5.6 KiB
Raw Blame History

MatchedSerializers

  • 功能描述: 指定类支持文本结构序列化
  • 引擎模块: Serialization
  • 元数据类型: bool
  • 作用机制: 在ClassFlags中增加CLASS_MatchedSerializers在Meta中添加MatchedSerializers
  • 常用程度: 0

该标识符只允许在NoExportTypes.h中使用属于是引擎自用的内部标识符。

基本上大部分的类都拥有该标记除了自身不导出的类一般包括NoExportTypes.h定义的除非手动加上MatchedSerializers比如UObject或者靠DECLARE_CLASS_INTRINSIC直接在源码里定义的元数据。

因此实际上大部分的类都拥有该标记。因为在UHT中只要不是NoExport的就会自动的加上这个标记。

// Force the MatchedSerializers on for anything being exported
if (!ClassExportFlags.HasAnyFlags(UhtClassExportFlags.NoExport))
{
			ClassFlags |= EClassFlags.MatchedSerializers;
}

结构化序列化器:

如果一个类支持文本格式则StructuredArchive的结构的意思是会把类里的字段树形展开来序列化展示出来从而方便人类理解。而如果不支持文本格式则会把所有的字段值压进一个二进制buffer里Data字段这也是runtime时候用的方式。

测试代码:


UCLASS(Blueprintable, BlueprintType,editinlinenew)
class INSIDER_API UMyClass_MatchedSerializersSub :public UObject
{
public:
	GENERATED_BODY()
public:
	UPROPERTY(EditAnywhere, BlueprintReadWrite)
	int32 MyInt_Default = 123;
};

UCLASS(Blueprintable, BlueprintType)
class INSIDER_API UMyClass_MatchedSerializersTestAsset:public UDataAsset
{
public:
	GENERATED_BODY()
public:
	UPROPERTY(EditAnywhere, BlueprintReadWrite)
	int32 MyInt_Default = 123;
	UPROPERTY(EditAnywhere, BlueprintReadWrite,Instanced)
	UMyClass_MatchedSerializersSub* SubObject;

	UPROPERTY(EditAnywhere, BlueprintReadWrite)
	UStruct* MyStructType;

	UPROPERTY(EditAnywhere, BlueprintReadWrite)
	UClass* MyClassType;

	UPROPERTY(EditAnywhere, BlueprintReadWrite)
	UEnum* MyEnumType;
};

void UMyClass_MatchedSerializers_Test::ApplyClassFlag()
{
	UMyClass_MatchedSerializersTestAsset::StaticClass()->ClassFlags |= CLASS_MatchedSerializers;
	UMyClass_MatchedSerializersSub::StaticClass()->ClassFlags |= CLASS_MatchedSerializers;
}

void UMyClass_MatchedSerializers_Test::RemoveClassFlag()
{
	UMyClass_MatchedSerializersTestAsset::StaticClass()->ClassFlags &= ~CLASS_MatchedSerializers;
	UMyClass_MatchedSerializersSub::StaticClass()->ClassFlags &= ~CLASS_MatchedSerializers;
}

在编辑器中创建测试数据Asset

Untitled

然后在Editor选项里打开TextAssetFormatSupport(UEditorExperimentalSettings::bTextAssetFormatSupport)

Untitled

然后在资产上就出现3个菜单支持把资产导出为文本。

Untitled

ExportToTextFormat会在蓝图资产的同目录生成一个.utxt的文件格式为json。通过动态的增删CLASS_MatchedSerializers这个标记来对比这个标记产生的差异

Untitled

可以发现序列化出来的内容有明显的差异不带有CLASS_MatchedSerializers标记的产生的右侧结果把所有的字段值压进一个二进制buffer里Data字段

内部机制原理:

CLASS_MatchedSerializers这个标记在UClass::IsSafeToSerializeToStructuredArchives中被使用标明采用结构序列化器。是否支持文本导入导出只在编辑器情况下使用。

在发生作用的只有SavePackage2.cpp和LinkerLoad.cpp因此是只发生在保存UPackage的时候作为子类对象。所以不能用简单的内存里Archive序列化来进行测试。

bool UClass::IsSafeToSerializeToStructuredArchives(UClass* InClass)
{
	while (InClass)
	{
		if (!InClass->HasAnyClassFlags(CLASS_MatchedSerializers))
		{
			return false;
		}
		InClass = InClass->GetSuperClass();
	}
	return true;
}

//LinkerLoad.cpp
bool bClassSupportsTextFormat = UClass::IsSafeToSerializeToStructuredArchives(Object->GetClass());
if (IsTextFormat())//如果Ar序列化是文本格式
{
			FStructuredArchiveSlot ExportSlot = GetExportSlot(Export.ThisIndex);

			if (bClassSupportsTextFormat) //如果类本身支持文本格式
			{
				Object->GetClass()->SerializeDefaultObject(Object, ExportSlot);
			}
			else
			{
				FStructuredArchiveChildReader ChildReader(ExportSlot);
				FArchiveUObjectFromStructuredArchive Adapter(ChildReader.GetRoot());
				Object->GetClass()->SerializeDefaultObject(Object, Adapter.GetArchive());
			}
}

//SavePackage2.cpp
#if WITH_EDITOR
			bool bSupportsText = UClass::IsSafeToSerializeToStructuredArchives(Export.Object->GetClass());
#else
			bool bSupportsText = false;
#endif

if (bSupportsText)
{
				Export.Object->GetClass()->SerializeDefaultObject(Export.Object, ExportSlot);
}
else
{
				FArchiveUObjectFromStructuredArchive Adapter(ExportSlot);
				Export.Object->GetClass()->SerializeDefaultObject(Export.Object, Adapter.GetArchive());
				Adapter.Close();
}

文本格式只在编辑器环境下生效。

可以从源码看到如果类本身支持文本格式序列化则在Ar是文本格式的时候直接可以序列化采用默认的SerializeTaggedProperties。否则得采用FArchiveUObjectFromStructuredArchive 来适配一下把对象指针转换为object path+ int32 Index的组合。

在引擎中打印出所有包含或不包含CLASS_MatchedSerializers的类发现UStruct继承链下面的类开始包含但是UClass却不包含而上面UField的类则不包含比如各种Property。类列表见Doc下txt文件。