解决UE4不能动态存储UObject指针问题
最近项目解决存档过大问题,问题原因是同一个基类,多个子类,但存档数据是放在一个结构体里面,导致有很多子类不需要用到字段也会保存,为解决这个问题,采用动态指针保存的方式,根据具体的子类保存对应的数据字段即可
1.Serialize数据
需要存储的数据类
UCLASS()
class UTestData : public UObject
{
GENERATED_BODY()
public:
UPROPERTY()
FString str;
UPROPERTY()
TArray<FVector> vec;
};
UCLASS()
class UTestSubData : public UTestData
{
GENERATED_BODY()
public:
UPROPERTY()
float fv;
UPROPERTY()
int32 iv;
};
SaveGame类定义UTestData指针数组,重写Uobject类Serialize方法
/**
*
*/
UCLASS()
class THIRDPERSON_API UMySaveGame : public USaveGame
{
GENERATED_BODY()
UMySaveGame();
virtual void Serialize(FArchive& Ar) override;
public:
UPROPERTY()
TArray<UTestData*> data;
};
UMySaveGame实现
template<class T>
void CustomSerialize(FArchive& Ar, TArray<T*>& serializeData)
{
if (Ar.IsSaving())
{
if (serializeData.Num())
{
for (int i = 0; i < serializeData.Num(); i++)
{
const auto& d = serializeData[i];
FName name = FName(*d->GetClass()->GetPathName());
Ar << name;
d->Serialize(Ar);
bool isEnd = (i == serializeData.Num() - 1);
Ar << isEnd;
}
}
}
if (Ar.IsLoading())
{
serializeData.Empty();
while (!Ar.AtEnd())
{
FName className;
Ar << className;
FString ss = className.ToString();
UClass* SaveGameClass = FindObject<UClass>(ANY_PACKAGE, *className.ToString());
if (SaveGameClass == nullptr)
{
SaveGameClass = LoadObject<UClass>(nullptr, *className.ToString());
}
// If we have a class, try and load it.
if (SaveGameClass != nullptr)
{
T* Testd = NewObject<T>(GetTransientPackage(), SaveGameClass);
Testd->Serialize(Ar);
serializeData.Add(Testd);
}
bool bEnd;
Ar << bEnd;
if (bEnd) break;
}
}
}
void UMySaveGame::Serialize(FArchive& Ar)
{
Super::Serialize(Ar);
//为了兼容老存档
/*if (Ar.IsSaving())
{
Ar << CurrentClientVersion;
}
if (Ar.IsLoading())
{
if (Ar.AtEnd()) return;
Ar << CurrentArchiveVersion;
}*/
CustomSerialize(Ar,data);
}
如何有多种基类,只需多调用几次CustomSerialize(Ar,data1);CustomSerialize(Ar,data2);即可。
2.存档压缩
//存数据
if (mSaveGame)
{
TArray<uint8> ObjectBytes;
UGameplayStatics::SaveGameToMemory(mSaveGame, ObjectBytes);
// Compress File
//tmp compressed data array
TArray<uint8> CompressedData;
FArchiveSaveCompressedProxy Compressor = FArchiveSaveCompressedProxy(CompressedData, NAME_Zlib, ECompressionFlags::COMPRESS_ZLIB);
//Send entire binary array/archive to compressor
Compressor << ObjectBytes;
//send archive serialized data to binary array
Compressor.Flush();
//test size
FString str = FString::Printf(TEXT("--- befor Compresse:%d, after Compresse:%d"), ObjectBytes.Num(), CompressedData.Num());
UE_LOG(LogTemp, Warning, TEXT("====%s"), *str);
UGameplayStatics::SaveDataToSlot(CompressedData, TEXT("test"), 0);
}
//读数据
if (UGameplayStatics::DoesSaveGameExist(TEXT("test"), 0))
{
//mSaveGame = Cast<UMySaveGame>(UGameplayStatics::LoadGameFromSlot(TEXT("test"), 0));
TArray<uint8> ObjectBytes;
if (UGameplayStatics::LoadDataFromSlot(ObjectBytes, TEXT("test"), 0))
{
// Decompress File
FArchiveLoadCompressedProxy Decompressor = FArchiveLoadCompressedProxy(ObjectBytes, NAME_Zlib, ECompressionFlags::COMPRESS_ZLIB);
//Decompression Error?
if (Decompressor.GetError())
{
FString str = FString::Printf(TEXT("--- FArchiveLoadCompressedProxy>> ERROR : File Was Not Compressed"));
//GEngine->AddOnScreenDebugMessage(0, 5.0f, FColor::Green, str);
return;
}
TArray<uint8> CompressedData;
Decompressor << CompressedData;
mSaveGame = Cast<UMySaveGame>(UGameplayStatics::LoadGameFromMemory(CompressedData));
}
}