(UE4.26)UE4的FArchive序列化入门

前言

序列化(Serialize) 和**反序列化(UnSerialize)**是程序领域常见的概念。对于这两个词汇我理解的是

序列化(Serialize) : 变量值(int, float, string 等基本类型, 或者ArrayMap ,或者更复杂的复合体)存储为一个文件(二进制流, 二进制文件, json, xml等格式)。

反序列化(UnSerialize): 读取文件来复原变量值。

UE4的序列化

FArchive简介

UE4的序列化一个比较核心类是FArchive, 这个类定义了对大部分基础变量类型的序列化和反序列化接口。这里得注意是FArchive的operator<<接口既包含了序列化,也包含了反序列化。判断是operator<< 此时运行的状态是序列化还是反序列化可以通过接口IsLoading(反序列化)IsSaving(序列化)。这些接口不一定有实际的实现, 很多实现是在FArchive子类里。

FArchive核心接口--void Serialize(void* V, int64 Length)

这个接口是大多数类型序列化的底层,主要是面向一段内存进行读/写FArchive.

我们自定义复杂类型的数据序列化时经常和这个接口打交道. 得注意的是Length 是内存byte 的个数。用法和FMemory::Copy类似。

UObject序列化

UObject的序列化也是通过**FArchive,**UObject被UProperty标记的变量会自动参与到序列化中。背后有一套管理机制,后续再深入篇在分析。

UObject序列化接口--void Serialize(FArchive& Ar)
复制代码
virtual void Serialize(FArchive& Ar);

保存和加载UObject对象都会触发Serialize, 对于UObject未被UProperty标记的变量,又需要存储到UObject的,可以Override这个接口来自定义

对复杂类型变量自定义序列化

对于部分复杂变量类型, FArchive接口和UE其他模块没有提供的。我们只能手动自定义序列化流程.

变量类型序列化也是分解为上门的基础序列化接口.

下面讲两个经典案例

案例一: 自定义Struct序列化
cpp 复制代码
struct TestStruct
{
    int a;
    float c;
}

FArchive Ar;
TestStruct test;

// 调用 FArchive& operator << (int& value)
Ar << test.a; 

// 调用 FArchive& operator << (float& value)
Ar << test.c;
案例二: TArray<int32>数组序列化

对于一个UObject里没有被UPROPERTY标记的TArray<int32>序列化。

cpp 复制代码
UCLASS()
class TESTARCH_API ATest : public AActor
{
	GENERATED_BODY()
	
public:	
	// Sets default values for this actor's properties
	ATest();
	
	UFUNCTION(CallInEditor)
	void TestWrite();

	UFUNCTION(CallInEditor)
	void TestPrint();

	TArray<int32> Data;
	
public:
	virtual void Serialize(FArchive& Ar) override;
};
cpp 复制代码
// Sets default values
ATest::ATest()
{
 	// Set this actor to call Tick() every frame.  You can turn this off to improve performance if you don't need it.
	PrimaryActorTick.bCanEverTick = true;
}

void ATest::TestWrite()
{
	Data.Empty();

	for(int32 Index = 0; Index < 10; Index++)
	{
		Data.Add(Index);
	}
}


void ATest::TestPrint()
{
	for(int32 Index = 0; Index < 10; Index++)
	{
		if(Data.IsValidIndex(Index))
		{
			UE_LOG(LogTemp, Error, TEXT("%d"), Data[Index]);
		}
	}
}
	

void ATest::Serialize(FArchive& Ar)
{
	Super::Serialize(Ar);

	// 反序列化(加载)
	if(Ar.IsLoading())
	{
		int32 Num = 0;
		Ar << Num;

		if(Num > 0)
		{
			Data.Init(0, Num);
			Ar.Serialize(Data.GetData(), sizeof(int32) * Num);
		}
	}
	// 序列化(保存)
	else
	{
		int32 Num = Data.Num();
		Ar << Num;
		
		if(Num > 0)
		{
			Ar.Serialize(Data.GetData(), sizeof(int32) * Num);
		}
	}
};

对于很多基础类型我们经常能轻易使用 " Operator << " 就同时处理了序列化和反序列化, 这是因为UE4 FArchive底层已经帮我们处理好两种情况下的逻辑,显得很简单。但是对于FArchive接口未覆盖的复杂类型, 需要我们手动实现相应接口时, 基本是需要分为序列化和反序列化两种情况来进行处理。

相关推荐
小江村儿的文杰3 天前
UE4安卓Gradle工程中的libUE4.so的生成原理
ue4
北冥没有鱼啊8 天前
UE5 射线折射
游戏·ue5·游戏引擎·ue4
Growthofnotes9 天前
UE4_Niagara基础实例—9、使用条带渲染器来制作闪电
ue4
Growthofnotes9 天前
UE4_Niagara基础实例—10、位置事件
ue4
directx3d_beginner9 天前
ue4 .usf抄写记录
ue4
 M͏⁠͏r.D14 天前
UE4 材质学习笔记13(格斯特纳波)
学习·ue4·材质
Growthofnotes14 天前
UE4_Niagara基础实例—8、生成网格体粒子并与角色产生交互
ue4
 M͏⁠͏r.D14 天前
UE4 材质学习笔记11(水波纹着色器/水深度着色器)
学习·ue4·材质
北冥没有鱼啊15 天前
ue5 扇形射线检测和鼠标拖拽物体
游戏·ue5·ue4·游戏开发·虚幻
 M͏⁠͏r.D17 天前
UE4 材质学习笔记12(水体反射和折射)
学习·ue4·材质