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 |
|
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· winform 绘制太阳,地球,月球 运作规律
· AI与.NET技术实操系列(五):向量存储与相似性搜索在 .NET 中的实现
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)