Unreal Instance Object Serialize Fail in SaveGame

.h

#pragma once

#include "CoreMinimal.h"
#include "GameFramework/SaveGame.h"
#include "Subsystems/GameInstanceSubsystem.h"
#include "InstancedSerializationSubsystem.generated.h"

UCLASS(DefaultToInstanced, EditInlineNew)
class UMyInstancedClass : public UObject
{
	GENERATED_BODY()

public:
	UPROPERTY(EditAnywhere, SaveGame, BlueprintReadWrite)
	FString MyString;

	UPROPERTY(EditAnywhere, SaveGame, BlueprintReadWrite)
	float MyFloat;
};

UCLASS()
class UMySaveGame : public USaveGame
{
	GENERATED_BODY()

public:
	// Runtime object rebuilt from persisted fields after loading.
	UPROPERTY(Transient, Instanced, EditAnywhere, BlueprintReadOnly)
	UMyInstancedClass* MyClass;
};

UCLASS()
class INSTANCEDSERIALIZ_API UInstancedSerializationSubsystem : public UGameInstanceSubsystem
{
	GENERATED_BODY()

public:
	virtual void Initialize(FSubsystemCollectionBase& Collection) override;

	UFUNCTION(BlueprintCallable)
	static UMySaveGame* LoadOrCreateArchiveBySaveGame();
};

.cpp

// Fill out your copyright notice in the Description page of Project Settings.


#include "InstancedSerializationSubsystem.h"

#include "Kismet/GameplayStatics.h"

void UInstancedSerializationSubsystem::Initialize(FSubsystemCollectionBase& Collection)
{
	Super::Initialize(Collection);
	//Step 1:Load Or Create 
	auto Loaded = UInstancedSerializationSubsystem::LoadOrCreateArchiveBySaveGame();
	if (!IsValid(Loaded->MyClass))
	{
		UE_LOG(LogTemp, Warning, TEXT("Failed to load MyClass from SaveGame!"));
	}

	//Setp 2 Write Data And Save
	if (IsValid(Loaded->MyClass))
	{
		Loaded->MyClass->MyString = TEXT("Hello, Unreal!");
		Loaded->MyClass->MyFloat = 6.28f;
		UGameplayStatics::SaveGameToSlot(Loaded, TEXT("MySaveSlot"), 0);
	}
}

UMySaveGame* UInstancedSerializationSubsystem::LoadOrCreateArchiveBySaveGame()
{
	UMySaveGame* SaveGame = Cast<UMySaveGame>(UGameplayStatics::LoadGameFromSlot(TEXT("MySaveSlot"), 0));
	if (!IsValid(SaveGame))
	{
		SaveGame = NewObject<UMySaveGame>(GetTransientPackage());
		SaveGame->MyClass = NewObject<UMyInstancedClass>(SaveGame);
		SaveGame->MyClass->MyString = TEXT("Hello, World!");
		SaveGame->MyClass->MyFloat = 3.14f;
	}

	return SaveGame;
}

Hi,

你好,这里的写法有几个问题:

  1. transient的property是不会被序列化下来的

  2. SaveGame序列化应该需要Property添加UPROPERTY(SaveGame)的标记。

  3. SaveGame本身是不支持Instanced的Class的序列化的,所以有两种改法

    • 直接使用常规的结构体,或者数据
    • 如果一定要使用Instanced的class,可以参考下面的写法
在SaveGame的类里添加 
UPROPERTY(SaveGame)
TArray<uint8> MyInstancedClassData;

然后在UInstancedSerializationSubsystem::Initializ里添加
FMemoryWriter Writer(SaveGame->MyInstancedClassData, true);
FObjectAndNameAsStringProxyArchive Ar(Writer, false);
Ar.ArIsSaveGame = true;
SaveGame->MyClass->Serialize(Ar); // 把instanced class写到这个Data里

然后在LoadOrCreate函数里添加
SaveGame->MyClass = NewObject<UMyInstancedClass>(SaveGame);
if (SaveGame->MyInstancedClassData.Num() > 0)
{
    FMemoryReader Reader(SaveGame->MyInstancedClassData, true);
    FObjectAndNameAsStringProxyArchive Ar(Reader, true);
    Ar.ArIsSaveGame = true;
    SaveGame->MyClass->Serialize(Ar);   // ← 从Data还原Instanced class
}