Skip to content

Instantly share code, notes, and snippets.

@redxdev
Created January 17, 2022 20:13
Show Gist options
  • Save redxdev/eef7050fafcd23b82bb8d2c6e6d5bf98 to your computer and use it in GitHub Desktop.
Save redxdev/eef7050fafcd23b82bb8d2c6e6d5bf98 to your computer and use it in GitHub Desktop.
Editor functions that allow exporting save games to json and then importing them again. Meant to be used in an editor module that depends on Json and JsonUtilities. Use it from an editor utility widget.
#include "SaveGameEditorUtilities.h"
#include "GameFramework/SaveGame.h"
#include "DesktopPlatformModule.h"
#include "JsonObjectConverter.h"
#include "Kismet/GameplayStatics.h"
#include "Logging/MessageLog.h"
#include "Misc/FileHelper.h"
#define LOCTEXT_NAMESPACE "SaveGameEditorUtilities"
bool USaveGameEditorUtilities::ExportSaveGameToJsonFile(const FString& SlotName, int32 UserIndex)
{
if (!UGameplayStatics::DoesSaveGameExist(SlotName, UserIndex))
{
FMessageLog("EditorErrors").Error(FText::Format(LOCTEXT("SaveGameDoesNotExit", "Save game '{0}' does not exist, cannot export save game"), FText::FromString(SlotName)));
FMessageLog("EditorErrors").Notify(LOCTEXT("ExportFailNotification", "Failed to export save game"));
return false;
}
USaveGame* SaveGame = UGameplayStatics::LoadGameFromSlot(SlotName, UserIndex);
if (!SaveGame)
{
FMessageLog("EditorErrors").Error(FText::Format(LOCTEXT("SaveGameFailedToLoad", "Save game '{0}' failed to load, cannot export save game"), FText::FromString(SlotName)));
FMessageLog("EditorErrors").Notify(LOCTEXT("ExportFailNotification", "Failed to export save game"));
return false;
}
IDesktopPlatform* DesktopPlatform = FDesktopPlatformModule::Get();
if (!DesktopPlatform)
{
FMessageLog("EditorErrors").Error(LOCTEXT("ExportBadDesktopPlatform", "Unable to retrieve IDesktopPlatform, cannot export save game"));
FMessageLog("EditorErrors").Notify(LOCTEXT("ExportFailNotification", "Failed to export save game"));
return false;
}
TSharedPtr<SWindow> ParentWindow = FSlateApplication::Get().GetActiveTopLevelWindow();
void* ParentWindowHandle = (ParentWindow.IsValid() && ParentWindow->GetNativeWindow().IsValid())
? ParentWindow->GetNativeWindow()->GetOSWindowHandle()
: nullptr;
TArray<FString> SelectedFiles;
bool Result = DesktopPlatform->SaveFileDialog(
ParentWindowHandle,
TEXT("Export Save Game"),
FPaths::ProjectDir(),
FString::Printf(TEXT("%s.json"), SlotName),
TEXT("JSON Files|*.json"),
EFileDialogFlags::None,
SelectedFiles);
if (!Result || SelectedFiles.Num() == 0)
{
return false;
}
FString JsonString;
if (!ExportSaveGameToJson(SaveGame, JsonString))
{
FMessageLog("EditorErrors").Error(LOCTEXT("ExportSaveFailedJson", "Failed to export save, json error"));
FMessageLog("EditorErrors").Notify(LOCTEXT("ExportFailNotification", "Failed to export save game"));
}
if (!FFileHelper::SaveStringToFile(JsonString, *SelectedFiles[0]))
{
FMessageLog("EditorErrors").Error(FText::Format(LOCTEXT("ExportSaveFailed", "Failed to export save to '{0}'"), FText::FromString(SelectedFiles[0])));
FMessageLog("EditorErrors").Notify(LOCTEXT("ExportFailNotification", "Failed to export save game"));
return false;
}
return true;
}
bool USaveGameEditorUtilities::ImportSaveGameFromJsonFile(const FString& SlotName, int32 UserIndex)
{
IDesktopPlatform* DesktopPlatform = FDesktopPlatformModule::Get();
if (!DesktopPlatform)
{
FMessageLog("EditorErrors").Error(LOCTEXT("ImportBadDesktopPlatform", "Unable to retrieve IDesktopPlatform, cannot import save game"));
FMessageLog("EditorErrors").Notify(LOCTEXT("ImportFailNotification", "Failed to import save game"));
return false;
}
TSharedPtr<SWindow> ParentWindow = FSlateApplication::Get().GetActiveTopLevelWindow();
void* ParentWindowHandle = (ParentWindow.IsValid() && ParentWindow->GetNativeWindow().IsValid())
? ParentWindow->GetNativeWindow()->GetOSWindowHandle()
: nullptr;
TArray<FString> SelectedFiles;
bool Result = DesktopPlatform->OpenFileDialog(
ParentWindowHandle,
TEXT("Import Save Game"),
FPaths::ProjectDir(),
TEXT(""),
TEXT("JSON Files|*.json"),
EFileDialogFlags::None,
SelectedFiles);
if (!Result || SelectedFiles.Num() == 0)
{
return false;
}
FString JsonString;
if (!FFileHelper::LoadFileToString(JsonString, *SelectedFiles[0]))
{
FMessageLog("EditorErrors").Error(FText::Format(LOCTEXT("ImportFileFailed", "Failed to import save from '{0}'"), FText::FromString(SelectedFiles[0])));
FMessageLog("EditorErrors").Notify(LOCTEXT("ImportFailNotification", "Failed to import save game"));
return false;
}
USaveGame* SaveGame = ImportSaveGameFromJson(JsonString);
if (!SaveGame)
{
FMessageLog("EditorErrors").Error(FText::Format(LOCTEXT("ImportSaveFileFailed", "Failed to import save from '{0}', possible parse error"), FText::FromString(SelectedFiles[0])));
FMessageLog("EditorErrors").Notify(LOCTEXT("ImportFailNotification", "Failed to import save game"));
return false;
}
if (!UGameplayStatics::SaveGameToSlot(SaveGame, SlotName, UserIndex))
{
FMessageLog("EditorErrors").Error(FText::Format(LOCTEXT("UnableToSaveImport", "Failed to save imported save game to slot '{0}'"), FText::FromString(SlotName)));
FMessageLog("EditorErrors").Notify(LOCTEXT("ImportFailNotification", "Failed to import save game"));
return false;
}
return true;
}
bool USaveGameEditorUtilities::ExportSaveGameToJson(USaveGame* Save, FString& OutJsonString)
{
if (!IsValid(Save))
{
return false;
}
FExportedSaveGame Export;
Export.SaveGame = Save;
return FJsonObjectConverter::UStructToJsonObjectString(Export, OutJsonString);
}
USaveGame* USaveGameEditorUtilities::ImportSaveGameFromJson(const FString& JsonString)
{
FExportedSaveGame Import;
if (!FJsonObjectConverter::JsonObjectStringToUStruct(JsonString, &Import, 0, 0))
{
return nullptr;
}
return Import.SaveGame;
}
#undef LOCTEXT_NAMESPACE
#pragma once
#include "CoreMinimal.h"
#include "SaveGameEditorUtilities.generated.h"
class USaveGame;
USTRUCT()
struct FExportedSaveGame
{
GENERATED_BODY()
FExportedSaveGame()
{
SaveGame = nullptr;
}
UPROPERTY(Instanced)
USaveGame* SaveGame;
};
UCLASS()
class MYGAMEEDITOR_API USaveGameEditorUtilities : public UBlueprintFunctionLibrary
{
GENERATED_BODY()
public:
UFUNCTION(BlueprintCallable, Category = "Game|SaveData|Editor")
static bool ExportSaveGameToJsonFile(const FString& SlotName, int32 UserIndex);
UFUNCTION(BlueprintCallable, Category = "Game|SaveData|Editor")
static bool ImportSaveGameFromJsonFile(const FString& SlotName, int32 UserIndex);
static bool ExportSaveGameToJson(USaveGame* Save, FString& OutJsonString);
static USaveGame* ImportSaveGameFromJson(const FString& JsonString);
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment