18 UE5 UObject的序列化和存取

2024-03-16  本文已影响0人  游戏开发程序员

主要内容

UObject的序列化

image.png

FArchive介绍

int Num = 1;
FArchive Archive ;
Archive<<Num;

FArchive主要的类

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 );

通过UPackage保存UObject

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

// 加载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;
    }
}

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 序列化介绍及源码解析

上一篇 下一篇

猜你喜欢

热点阅读