추가해야할 모듈

.h
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);
#include "GameFramework/SaveGame.h"
#include "DesktopPlatformModule.h"
#include "JsonObjectConverter.h"
#include "Kismet/GameplayStatics.h"
#include "Logging/MessageLog.h"
#include "Misc/FileHelper.h"
#include "Widgets/SWindow.h"
#include "Dom/JsonObject.h"
#include "Framework/Application/SlateApplication.h"

#define LOCTEXT_NAMESPACE "ReseachBlueprintFunctionLibrary"

bool UReseachBlueprintFunctionLibrary::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;

	FString asd = SlotName;
	TArray<FString> SelectedFiles;
	bool Result = DesktopPlatform->SaveFileDialog(
		ParentWindowHandle,
		TEXT("Export Save Game"),
		FPaths::ProjectDir(),
		FString::Printf(TEXT("%s.json"), *asd),
		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 UReseachBlueprintFunctionLibrary::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 UReseachBlueprintFunctionLibrary::ExportSaveGameToJson(USaveGame* Save, FString& OutJsonString)
{
	if (!IsValid(Save))
	{
		return false;
	}

	FExportedSaveGame Export;
	Export.SaveGame = Save;

	return FJsonObjectConverter::UStructToJsonObjectString(Export, OutJsonString);
}

USaveGame* UReseachBlueprintFunctionLibrary::ImportSaveGameFromJson(const FString& JsonString)
{
	FExportedSaveGame Import;
	if (!FJsonObjectConverter::JsonObjectStringToUStruct(JsonString, &Import, 0, 0))
	{
		return nullptr;
	}

	return Import.SaveGame;
}

#undef LOCTEXT_NAMESPACE