解决UE4不能动态存储UObject指针问题

解决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));
		}
	}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值