UE5 增量 Cook
UE 版本 5.5.4
添加了之后的 log 如下
![image-20250815202658904]()
这部分 log 比较重要
cs 中
![image-20250818120051662]()
![image-20250818120010488]()
即 -iterativecooking
等同于 -iterate
数据结构
1. FAssetPackageData
![image-20250815213552276]()
![image-20250815213619730]()
简单来说根据 GetPackageSavedHash()
判断包是否修改
根据 DiskSize
判断包修改的状态
-
状态
![image-20250815213816678]()
-
包类型分类:
- 包分为 已 Cook,未 Cook,占位包 (NeverCookPlaceholder)和 脚本包 Script
- 每种类型有
Identical
相同, Modified
修改 和 Removed
删除 状态。
2. ICookedPackageWriter
2. FCookSavePackageContext 烘焙保存包上下文
对一个给定的平台,传递给 SavePackage 的上下文数据。
![image-20250818142743787]()
实际上就是存储了
函数逻辑
1. LoadBeginCookIterativeFlags
![image-20250815202936321]()
![image-20250815202855644]()
![image-20250815202805085]()
这里的 CookWorkerRequests
是在 COTFS 的 Intialize
函数中初始化的
![image-20250815204603008]()
这个函数的目的也只是遍历传进来的 FBeginCookContext
,设置其中的 PlatformContext
的 相关 flag,如不是 FullBuild
,允许 IterativeResults
等,以及
bPopulateMemoryResultsFromDiskResults
是否允许从磁盘的结果填充记忆结果。
2. PopulateCookedPackages
StartCookByTheBook
中 LoadBeginCookIterativeFlags
结束之后,走到 BeginCookSandbox
中
![image-20250815205226180]()
这里会根据 LoadBeginCookIterativeFlags
中指定的 bPopulateMemoryResultsFromDiskResults
执行后续逻辑,添加目标平台,执行 PopulateCookedPackages
![image-20250815205342465]()
这是进行差异化判断的核心函数
![image-20250815204801832]()
![image-20250815214139990]()
ComputePackageDifferences
是另一个核心函数
3. ComputePackageDifferences
这个函数很长,但是逻辑是比较清晰的
前面先调用
![image-20250815214717880]()
根据 FAssetPackageData
中的 Hash 值直接判断是否发生变化
![image-20250815214912756]()
如果没有变化,就根据 DiskSize
进行状态的变更,添加到 OutDifference.Packages 数组中,记录状态
这里用 Mermaid 画一个流程图
graph TDA[Start ComputePackageDifferences] --> B[Initialize: Reserve OutDifference.Packages]B --> C[Loop through Current State's Packages]C --> D{Is Package in Previous State?}D -->|No| E[Skip: New Package, No Action]D -->|Yes| F[Check if Package is Unchanged]F -->|Yes| G{Is DiskSize < 0?}G -->|Yes| H{Is NeverCookPlaceholder?}H -->|Yes| I[Add to Packages: IdenticalNeverCookPlaceholder]H -->|No| J[Add to Packages: IdenticalUncooked]G -->|No| K{Is Script Package?}K -->|Yes| L[Add to Packages: IdenticalScript]K -->|No| M[Add to Packages: IdenticalCooked]F -->|No| N{Is DiskSize < 0?}N -->|Yes| O{Is NeverCookPlaceholder?}O -->|Yes| P[Add to Packages: ModifiedNeverCookPlaceholder]O -->|No| Q[Add to Packages: ModifiedUncooked]N -->|No| R{Is Script Package?}R -->|Yes| S[Add to Packages: ModifiedScript]R -->|No| T[Add to Packages: ModifiedCooked]E --> U[Loop through Previous State's Packages]U --> V{Is Package in Current State?}V -->|Yes| W[No Action: Already Processed]V -->|No| X{Is Generated Package?}X -->|Yes| Y{Is Generator in Current State?}Y -->|No| Z[Add to Packages: RemovedCooked]Y -->|Yes| AA[Add to GeneratorPackages]X -->|No| AB{Is DiskSize < 0?}AB -->|Yes| AC{Is NeverCookPlaceholder?}AC -->|Yes| AD[Add to Packages: RemovedNeverCookPlaceholder]AC -->|No| AE[Add to Packages: RemovedUncooked]AB -->|No| AF{Is Script Package?}AF -->|Yes| AG[Add to Packages: RemovedScript]AF -->|No| AH[Add to Packages: RemovedCooked]W --> AI[Loop through GeneratorPackages]AI --> AJ{Is Generator RemovedCooked?}AJ -->|Yes| AK[Mark All Generated Packages as RemovedCooked]AJ -->|No| AL[Keep GeneratorPackages Entry]AK --> AM{Check Options.bRecurseModifications?}AL --> AMAM -->|No| AN[End]AM -->|Yes| AO[Collect Modified Packages to VisitStack]AO --> AP[Loop through VisitStack]AP --> AQ{Stack Empty?}AQ -->|Yes| ANAQ -->|No| AR[Pop Package from VisitStack]AR --> AS[Get Referencers: Hard and Build Dependencies]AS --> AT[Loop through Referencers]AT --> AU{Is External Actor Package?}AU -->|Yes| AV{Refers to Modified Package's Map?}AV -->|Yes| AW[Skip Referencer]AV -->|No| AX{Already Visited?}AU -->|No| AXAX -->|Yes| AY[Skip Referencer]AX -->|No| AZ{Is Referencer in Packages?}AZ -->|No| BA[Skip Referencer]AZ -->|Yes| BB[Convert Identical to Modified]BB --> BC[Add Referencer to VisitStack]BC --> ATAW --> ATAY --> ATBA --> AT