美文网首页
18 UE5 UObject的序列化和存取

18 UE5 UObject的序列化和存取

作者: 游戏开发程序员 | 来源:发表于2024-03-16 10:53 被阅读0次

主要内容

  • UObject的序列化和反序列化
  • UPackage的保存与加载
  • CDO:ClassDefaultObject,UClass的成员变量,表示此UObject的默认对象。
  • 序列化:把RUNTIME运行时的内存对象,通过计算算法 存入/ 取出 为二进制内存.
  • 存档: 把序列化的一段内存 存/取 到磁盘文件上
  • 持久化: 把序列化的一段内存 存/取 到数据库上的操作.

UObject的序列化

  • 主要功能:把数据结构或对象状态转换为可存取的格式(比如二进制)
  • Serialize()方法:负责对整个类里面的「某些信息」做序列化。
  • 其中UPROPERTY()宏标记的属性,一般都是会被序列化的。
  • 将序列化的「二进制」数据以.uasset后缀的文件保存起来
  • LoadObject可以重新将uasset文件反序列化成UObject
image.png

FArchive介绍

  • UE使用访问者模式,让FArchive做访问者,来访问实现了Serialize(FArchive& Ar)的被访问者。
  • 大多数存储使用此类型:TArray<uint8> Buffer / TArray<uint8>& Bytes
  • FArchive 通过重载 << 来实现对 UObject 中数据的访问
  • 技巧:使用了友元friend,谁实现都可以
  • 比如int作为被访问者:FArchive& operator<<(FArchive& Ar, int& Value)
int Num = 1;
FArchive Archive ;
Archive<<Num;

FArchive主要的类

  • FArchive系列类有:文件系统、内存统计、UAssert对象存取,网络IO等。
  • FLinkerLoad和FLinkerSave :public FLinker, public FArchiveUObject(存取uasset,package,UObject)
  • FArchiveFile Reader/Write Generic : public FArchive(文件系统相关)
  • FArchiveCountMem : public FArchiveUObject(统计内存使用功能类)
  • struct FBitReader 和 FBitWriter: public FBitArchive(字节流写入和读取IO)

UObject::Serialize( FArchive& Ar )

UClass *ObjClass = GetClass();
UObject* LoadOuter = GetOuter();
FName LoadName = GetFName();

if (ObjClass != UClass::StaticClass())
{
    SerializeScriptProperties(Ar);
}

 // 添加GUID
FLazyObjectPtr::PossiblySerializeObjectGuid(this, Ar);

// 内存统计(with proper alignment to match C++)
SIZE_T Size = GetClass()->GetStructureSize();
Ar.CountBytes( Size, Size );
  • 虚幻引擎序列化每个继承自 CLass 的类的默认值(即序列化CDO),然后序列化对象与类默认对象的差异。这样就节约了大量的子类对象序列化后的存储空间。

通过UPackage保存UObject

  • 1 创建资源包:UPackage* Package = CreatePackage(*AssetPath);
  • 2 对象创建时,关联包 NewObject<UTestObject>(Package, FName(*ObjectName),
  • 3 Package->MarkPackageDirty();
  • 4 UPackage::SavePackage(Package, pObj......)
FString AssetPath = TEXT("/Game/TestObject");
// 全路径,MyGame/Content/MyObject.uasset
FString PackageFileName = FPackageName::LongPackageNameToFilename(AssetPath, FPackageName::GetAssetPackageExtension());
FString ObjectName = TEXT("Mike");
// 调用保存
bool bSaved = SaveToPackage(AssetPath, PackageFileName, ObjectName);
UE_LOG(TestLog, Display, TEXT("Save Package %s !"), bSaved?TEXT("Success"):TEXT("Failed"));

// 保存到package函数
bool SaveToPackage(const FString &AssetPath, const FString &PackageFileName, const FString &ObjectName)
{
    // 创建一个资源Package
    UPackage* Package = CreatePackage(*AssetPath);

    // 完全加载这个包
    Package->FullyLoad();

    // 创建对象
    UTestObject* pObj = NewObject<UTestObject>(Package, FName(*ObjectName), 
    EObjectFlags::RF_Public | EObjectFlags::RF_Standalone);

    // 设置对象属性
    pObj->CurPlayerName = ObjectName;
    pObj->CurPlayerAge = 18;

    // 标记脏数据
    Package->MarkPackageDirty();

    // 保存对象到uasset
    return UPackage::SavePackage(Package, pObj, 
    EObjectFlags::RF_Public | EObjectFlags::RF_Standalone, 
    *PackageFileName, GError, nullptr, true, true, SAVE_NoError);
}

通过UPackage加载UObject

  • LoadPackage 先加载包 FullyLoad
  • FindObject<UMyObject>(pPkg, TEXT("Mike")); // *ObjectName
  • 从包中寻找某名称的对象
// 加载package
UPackage* pPkg = LoadPackage(nullptr, *AssetPath, LOAD_None);
if(pPkg)
{
    pPkg->FullyLoad();
    auto info = pPkg->GetDetailedInfo(); 
    // 加载UObject上文中保存的名字ObjectName 
    UMyObject* FoundObj = FindObject<UMyObject>(pPkg, TEXT("Mike"));
    if(FoundObj)
    {
       auto _age = FoundObj->CurPlayerAge;
       FString _name = FoundObj->CurPlayerName;
    }
}

  • 一路跟踪,UE是从这里找来对象指针返回
image.png

Object序列化步骤

  1. 通过GetClass函数获取当前的类信息,通过GetOuter函数获取Outer。Outer指定当前UObject会作为哪一个对象的子对象进行序列化。
  2. 判断当前等待序列化的对象的类UClass的信息是否被载入,没有的话:
  3. 预载入当前类的信息;
  4. 预载入当前类的默认对象CDO的信息(ObjClass->GetDefaultObject())
  5. 载入名字
  6. 载入Outer
  7. 载入当前对象的类信息,保存于ObjClass对象中。
  8. 载入对象的所有脚本成员变量信息。这一步必须在类信息加载后,才会知道有哪些脚本成员变量需要加载。
  9. 调用SerializeScriptProperties,序列化在类中定义的对象属性。
  10. 调用FArchive.MarkScriptSerializationStart,标志脚本序列化数据开始;
  11. 调用SerializeTaggedProperties,序列化对象属性,并且加入tag;
  12. 调用FArchive.MarkScriptSerializationEnd,标志脚本序列化数据结束。

-可参考 直呼:UE 序列化介绍及源码解析

相关文章

  • UE4对象系统_UObject&UClass

    UObject UObject为对象系统的基类。类层次为: UObjectBase和UObjectBaseUtil...

  • 9.28学习总结

    今天讲了MFC中的文件的储存和读取,还开始讲了一些对象数组。 文件的存取分为字符文件存取和类对象序列化。 主要是在...

  • UE4之UObject介绍

    UObject UObject,它是所有引擎层面、游戏层面对象的基类。 UObjects 提供的功能 垃圾回收 引...

  • UObject

    CreateDefaultSubobject:创建一个子类实例,主要用于创建组件实例,而且只能在构造函数里调用。 ...

  • python数据分析与展示(数据存取)

    1.数据的csv文件存取 二维数组存取 np.savetxt(frame, array, fmt='%.18e',...

  • Python入门与进阶(10-18)

    10-18 序列化

  • 程序打包

    关于UE5打包问题[https://www.bilibili.com/read/cv11679358] UE5 P...

  • UObject的创建与销毁

    1、使用NewObject进行创建 2、使用ConditionalBeginDestroy()销毁UObject

  • pandas读写二进制文件

    python内置了以pickle序列化的方式存取二进制文件。pandas也提供了方便的方法通过pickle方式加载...

  • 存储器的存储方式

    存储器中数据常用的存取方式有顺序存取、直接存取、随机存取和相联存取等四种。(1)顺序存取:存储器的数据以记录的形式...

网友评论

      本文标题:18 UE5 UObject的序列化和存取

      本文链接:https://www.haomeiwen.com/subject/vghwzdtx.html