Unreal Engine 5.2 .uasset文件格式分析

     以下内容只包含UE5的5.2版本,不包含兼容性内容,不同版本可能会有所不同。

提示:

    N  :通常代表数组个数

    ?  :代表不确定,比如字符串的长度。

    *  : 乘积

    Type Name : Size : 此说明并非定义位域,是在说明此处的数据类型、名称以及空间占用,空间单位为字节。

基础类型序列化

       这里对基础类型的序列化进行简单描述,后续的段落中,可能会引用此段落的信息。

类型

细节

参考代码

FString

字符串序列化有一定的特殊性:

基于字符串自身是否以Unicode保存,其占用的大小并不一致。如若全是Ansi字符,则其大小为:

Int32 Num : 4 +

Num * sizeof(ANSICHAR)

Num包含字符串终止符’\0’

 

如果是Unicode保存,则将字符个数以负数保存。然后输出UTF16字符串。

Int32 -Num : 4 + Num * sizeof(UTF16CHAR),同样包含终止符

 

String.cpp

FArchive& operator<<( FArchive& Ar, FString& A )

FName

序列化时会输出两个Int32,其内容为Name数组中的索引+FName的Number属性。

大小为8

可以根据这个索引在NameMap中找到具体值

LinkerSave.cpp

FArchive& FLinkerSave::operator<<( FName& InName )

 

FGuid

4个Int32,大小为16

 

TArray<T>

以Num(int32)开头,后面接所有数组元素自身的序列化数据。

 

FCustomVersion

Int32 NumElements : 4

[

  {

FGuid Key : 16,

Int32 Version: 4

  }

]

以数组个数开头,接着是指定个数的 FCustomVersion,其为20个字节。

这些版本是对于这个资产中某一类数据的版本号标记。

参考:Source/Runtime/Core/Public/UObject/xxxObjectVersion.h

CustomVersion.cpp

FArchive& operator<<(FArchive& Ar, FCustomVersion& Version)

void operator<<(FStructuredArchive::FSlot Slot, FCustomVersion& Version)

FEngineVersion

一个输出5个字段:

UInt16 Major : 2

UInt16 Minor : 2

UInt16 Patch : 2

UInt32 ChangeList : 4

FString Branch : 4 + ?

 

因此总大小为14 + ? 至少14个字节。

 

EngineVersion.cpp

void operator<<(FStructuredArchive::FSlot Slot, FEngineVersion &Version)

FCompressedChunk

FCompressThunk输出4个字段:

Int32 UncompressedOffset : 4

Int32 UncompressedSize : 4

Int32 CompressedOffset : 4

Int32 CompressedSize : 4

Linker.cpp

FArchive& operator<<(FArchive& Ar,FCompressedChunk& Chunk)

FGenerationInfo

两个字段:

Int32 ExportCount : 4

Int32 NameCount : 4

Linker.cpp

void FGenerationInfo::Serialize(FArchive& Ar, const struct FPackageFileSummary& Summary)

FNameEntryId

以FNameEntrySerialized对象的形式保存。输出三个信息:

FString Str : 4 + ?

UInt16 NonCasePreservingHash : 2  // 读取时忽略

UInt16 CasePreservingHash : 2 // 读取时忽略

所以总大小为:8 + ?

UnrealNames.cpp

void FNameEntry::Write( FArchive& Ar ) const

FArchive& operator<<(FArchive& Ar, FNameEntrySerialized& E)

 

FSoftObjectPath

软引用对象在保序列化时根据应用场景不同而不同,当处于文件头时,直接输出两个属性:

FTopLevelAssetPath AssetPath;

FString SubPathString;

 

FTopLevelAssetPath又由两个FName组成:

FName PackageName : 8;

FName AssetName : 8;

 

所以一个软引用的大小为:16 + 4 + ?

TopLevelAssetPath.h

friend FArchive& operator<<(FArchive& Ar, FTopLevelAssetPath& Path)

 

LinkerSave.cpp

FArchive& FLinkerSave::operator<<(FSoftObjectPath& SoftObjectPath)

 

SoftObjectPath.cpp

void FSoftObjectPath::SerializePath(FArchive& Ar)

 

FTextSourceSiteContext

FString KeyName : 4 + ?

FString SiteDescription : 4 + ?

Bool IsEditorOnly : 4

Bool IsOptional : 4

FLocMetadataObject InfoMetaData : 4 + ?

FLocMetadataObject KeyMetaData : 4 + ?

 

GatherableTextData.cpp

void operator<<(FStructuredArchive::FSlot Slot, FTextSourceSiteContext& This)

 

 

FLocMetadataObject

Int32 ValueCount : 4

TMap< FString, TSharedPtr<FLocMetadataValue> > Values : ?

 

InternationalizationMetadata.cpp

void SerializeLocMetadataValue(FStructuredArchive::FSlot Slot, TSharedPtr<FLocMetadataValue>& Value)

 

FTextSourceData

FString SourceString : 4 + ?

FLocMetadataObject SourceStringMetaData : ?

GatherableTextData.cpp

void operator<<(FStructuredArchive::FSlot Slot, FTextSourceData& This)

 

FGatherableTextData

FString NamespaceName : 4 + ?

FTextSourceData SourceData : 8 + ?

TArray<FTextSourceSiteContext> SourceSiteContexts : 4 + ?

GatherableTextData.cpp

void operator<<(FStructuredArchive::FSlot Slot, FGatherableTextData& This)

 

 

FObjectImport

FName ClassPackage : 8

FName ClassName : 8

FPackageIndex OuterIndex : 4

FName ObjectName : 8

FName PackageName : 8 (EditorOnly)

Bool bImportOptional : 4

总大小 40 (Editor) 32(Runtime)

 

ObjectResource.cpp

void operator<<(FStructuredArchive::FSlot Slot, FObjectImport& I)

 

FObjectExport

FPackageIndex ClassIndex : 4

FPackageIndex SuperIndex : 4

FPackageIndex TemplateIndex : 4

FPackageIndex OuterIndex : 4

FName ObjectName : 8

UInt32 ObjectFlags : 4

Int64 SerialSize : 8

Int64 SerialOffset : 8

Bool bForcedExport : 4

Bool bNotForClient : 4

Bool bNotForServer : 4

Bool bIsInheritedInstance : 4

UInt32 PackageFlags : 4

Bool bNotAlwaysLoadedForEditorGame : 4

Bool bIsAsset : 4

Bool bGeneratePublicHash : 4

Int32 FirstExportDependency : 4

Int32 SerializationBeforeSerializationDependencies : 4

Int32 CreateBeforeSerializationDependencies : 4

Int32 SerializationBeforeCreateDependencies : 4

Int32 CreateBeforeCreateDependencies : 4

 

总大小: 96

 

ObjectResource.cpp

void operator<<(FStructuredArchive::FSlot Slot, FObjectExport& E)

FObjectThumbnail

Int32 ImageWidth : 4

Int32 ImageHeight : 4

TArray<UInt8> CompressedImageData : 4 + ?

ObjectThumbnail.cpp

void FObjectThumbnail::Serialize(FStructuredArchive::FSlot Slot)

 

FPropertyTag

FName Name : 8

FName Type : 8

Int32 Size : 4

Int32 ArrayIndex : 4

TagType == Struct:

FName StructName : 8

FGuid StructGuid : 16

TagType == Bool:

UInt8 BoolVal : 1

TagType == Byte or Enum:

FName EnumName : 8

TagType == Array or Set:

FName InnerType : 8

TagType == Map:

FName InnerType : 8

Fname ValueType : 8

 

UInt8 HasPropertyGuid : 1

HasPropertyGrid == 1:

    FGuid PropertyGruid : 16

   

总大小:25 + ?

PropertyTag.cpp

void operator<<(FStructuredArchive::FSlot Slot, FPropertyTag& Tag)

FLookupTableEntry

FIoHash Identifier : 20

Int64 OffsetInFile : 8

UInt64 CompressedSize : 8

UInt64 RawSize : 8

总大小:44 + ?

 

FPackageTrailer::FHeader

UInt64 Tag : 8

Int32 Version : 4

UInt32 HeaderLength : 4

UInt64 PayloadsDataLength : 8

Int32 NumPayloads : 4

TArray<FLookupTableEntry> PayloadLookupTable : (44+?)*NumPayloads

 

总大小:28 + (44+?)*NumPayloads

 

FPackageTrailer::FFooter

UInt64 FooterTag : 8

UInt64 TrailerLength : 8

UInt32 PackageTag : 4

总大小:20

FooterTag = 0x29BFCA045138DE76

#define PACKAGE_FILE_TAG            0x9E2A83C1

 

 

文件头

       文件头部分也分成多个部分,概要部分保存了版本信息以及各种区块的偏移值。保存Package时,会先输出一个不完整的文件头用于占位,在完成所有序列化后,会重新刷新文件头中的数据。

概要

       类型:FPackageFileSummary

       相关代码:

LinkerLoader.cpp : FLinkerLoad::ELinkerStatus FLinkerLoad::ProcessPackageSummary(TMap<TPair<FName, FPackageIndex>, FPackageIndex>* ObjectNameWithOuterToExportMap)

           SavePackage2.cpp : ESavePackageResult WritePackageHeader(FStructuredArchive::FRecord& StructuredArchiveRoot, FSaveContext& SaveContext)

           PackageFileSummary.cpp : void operator<<(FStructuredArchive::FSlot Slot, FPackageFileSummary& Sum)

   

名称

类型

大小

注解

Tag

Int32

4

文件标识

#define PACKAGE_FILE_TAG          0x9E2A83C1

#define PACKAGE_FILE_TAG_SWAPPED    0xC1832A9E

 

LegacyFileVersion

Int32

4

文件版本,当前默认0xFFFFFFF8(-8)

LegacyUE3Version

Int32

4

0x00000360

读取后不再使用

FileVersionUE4

Int32

4

0x0000020a

FileVersionUE5

Int32

4

0x000003f1

FileVersionLicenseeUE4

Int32

4

0x00000000

CustomVersions

TArray<FCustomVersion>

4 + 20 * N

FCustomVersion包含一个FGuid(16字节)作为Key,一个Int32(4字节)作为版本号

TotalHeaderSize

Int32

4

文件头总大小

PackageName

FString

4 + ?

包名称

字符串数据由字符串长度+字符串数据本身组成 包含字符串结束符

PackageFlags

UInt32

4

包标记位

Cooked标记即放在这个字段

NameCount

Int32

4

名字列表的个数

NameOffset

Int32

4

指向名字列表数据区块的偏移值

名字列表是TArray<FNameEntryId>

后续数据中的字符串都只保存这个列表的索引,这样当存在多个相同的字符串时,也只存在一份字符串实例

SoftObjectPathsCount

Int32

4

软引用个数

SoftObjectPathsOffset

Int32

4

软引用数据区块偏移

数据是TArray<FSoftObjectPath>

这以一个路径引用代替真实的对象引用,相当于是一种Lazy处理资源引用的方法,但是对于程序外观来说,与直接硬引用类似。

LocalizationId

FString

4 + ?

本地化标识

GatherableTextDataCount

Int32

4

本地化文本数据个数

GatherableTextDataOffset

Int32

4

本地化文本数据区块偏移

TArray<FGatherableTextData>

使用FText之类的属性时,会产生这个数据。

ExportCount

Int32

4

导出表数据个数

ExportOffset

Int32

4

导出表数据区块偏移

ImportCount

Int32

4

导入表数据个数

ImportOffset

Int32

4

导入表数据区块偏移

 

DependsOffset

Int32

4

依赖数据区块偏移

SoftPackageReferencesCount

Int32

4

 

SoftPackageReferencesOffset

Int32

4

 

SearchableNamesOffset

Int32

4

 

ThumbnailTableOffset

Int32

4

 

Guid

FGuid

16

 

PersistentGuid

FGuid

16

EditorOnly

GenerationCount

Int32

4

 

Generations

FGenerationInfo

8*GenerationCount

 

SavedByEngineVersion

FEngineVersion

14+ ?

 

CompatibleWithEngineVersion

FEngineVersion

14+ ?

 

CompressionFlags

UInt32

4

 

CompressedChunks

TArray<FCompressedChunk>

4 + 16 * N

 

PackageSource

UInt32

4

 

AdditionalPackagesToCook

TArray<FString>

4 + ? * N

Deprecated,新版本中为空

AssetRegistryDataOffset

Int32

4

 

BulkDataStartOffset

UInt64

8

 

WorldTileInfoDataOffset

Int32

4

 

ChunkIDs

TArray<Int32>

4 + 4 * N

 

PreloadDependencyCount

Int32

4

预加载依赖项数量,没有时为-1

PreloadDependencyOffset

Int32

4

预加载依赖项数据区块偏移,始终有值但仅当PreloadDependencyCount有效时才有意义,否则该位置为其它数据

NamesReferencedFromExportDataCount

Int32

4

 

PayloadTocOffset

Int64

8

指向文件尾

文件尾数据主要用于校验

DataResourceOffset

Int32

4

Cooking时才会输出的数据,在导出表后面。这是它的偏移值。

 

区块

       每个区块的大小都是不确定的,但是每个区块在概要数据中最终都会保存对应的偏移值,所以可以基于偏移值直接计算出某个区块的整体大小。

 

名称

类型

大小

注解

NameMap

TArray<FNameEntryId>

(8 + ?)*N

NameOffset、NameCount

字符串列表

 

SoftObjectPathList

TArray<FSoftObjectPath>

(20 + ?)*N

SoftObjectPathsOffset、

SoftObjectPathsCount

GatherableTextData

TArray<FGatherableTextData>

? * N

GatherableTextDataOffset、

GatherableTextDataCount

ImportMap

TArray<FObjectImport>

40 * N

ImportCount、ImportOffset

ExportMap

TArray<FObjectExport>

96 * N

ExportCount、ExportOffset

DependsMap

TArray<TArray<FPackageIndex>>

(4+4) * N

DependsOffset

DependsMap和ExportMap的大小必须是一模一样的,所以不再需要额外的DependsCount

SoftReferences

TArray<FName>

8 * N

SoftPackageReferencesOffset、SoftPackageReferencesCount

SearchableNames

TMap<FPackageIndex, TArray<FName>>

4 + (4 + (4+8*N1))*N2

SearchableNamesOffset

Thumbnails

TArray< FObjectFullNameAndThumbnail >

(12+?)*N + ((4+?)+(4+?)+4)*N

ThumbnailTableOffset

 

SavePackageUtilities.cpp

void SaveThumbnails(UPackage* InOuter, FLinkerSave* Linker, FStructuredArchive::FSlot Slot)

 

分两部分保存。

第一个循环保存TArray< FObjectThumbnail >;

第二个循环保存TArray< FObjectFullNameAndThumbnail>,其中每个FObjectFullNameAndThumbnail保存:

FString ObjectClassName : 4 + ?

FString ObjectPathWithoutPackageName : 4 + ?

Int32 FileOffset : 4

 

AssetRegistry

TArray<UObject::FAssetRegistryTag>

 

?

AssetRegistryDataOffset

SavePackageUtilities.cpp

UE::AssetRegistry::WritePackageData

 

WorldLevelInfo

FWorldTileInfo

?

WorldTileInfoDataOffset

SavePackageUtilities.cpp

void SaveWorldLevelInfo(UPackage* InOuter, FLinkerSave* Linker, FStructuredArchive::FRecord Record)

 

如果不存在这个数据,则WorldTileInfoDataOffset为0

PreloadDependencies

 

?

PreloadDependencyOffset、PreloadDependencyCount

 

CookedOnly

       文件头整体大小保存在TotalHeaderSize中。

 

对象数据

       即Exports。Exports保存的即是对象本身。数据来自TArray<FObjectExport>,FObjectExport中的Object为要保存的对象。其内部具体内容与格式,由Object自行决定。FObjectExport的字段SerialOffset、SerialSize保存在文件头中,可以用于定位每个Export对象的偏移和整体大小。

    序列化单个Object时,默认使用TaggedProperties序列化各个属性。当使用TaggedProperties序列化时,每个属性序列化之前都会与默认值进行比对,当属性值与默认值相同时,该属性会被忽略。每个属性在序列化之前,会输出FPropertyTag,这个Tag用于标记当前区块对应的是哪个属性。读取时,先读取Tag,再通过这个Tag的数据将接下来的内容与目标属性关联在一起。参考代码:

Class.cpp :

void UStruct::SerializeVersionedTaggedProperties(FStructuredArchive::FSlot Slot, uint8* Data, UStruct* DefaultsStruct, uint8* Defaults, const UObject* BreakRecursionIfFullyLoad) const

 

BulkData

       由BulkDataStartOffset定位位置。如果没有时,大小为0。

 

额外数据

名称

类型

大小

注解

AdditionalDataToAppend

TArray<AdditionalDataCallback>

0 or ?

允许通过回调添加自定义数据

SidecarDataToAppend

TArray<FSidecarStorageInfo>

0 or ?

提供给FEditorBulkData添加自定义数据

AdditionalFilesFromExports

TArray<FLargeMemoryWriter, TInlineAllocator<4>>

0 or ?

来自Export的自定义数据,Cookedonly

Tag

UInt32

4

一个终结Tag:

       #define PACKAGE_FILE_TAG          0x9E2A83C1

 

 

文件尾

       以PayloadTocOffset定位,这是最后一个区块。

名称

类型

大小

注解

Header

FPackageTrailer::FHeader

28 + (44+?)*NumPayloads

 

LocalEntries

FCompressedBuffer

? * N

 

Footer

FPackageTrailer::FFooter

20

 

posted @ 2023-08-09 21:08  bodong  阅读(1055)  评论(0编辑  收藏  举报