UE5.7 解析:Incremental Cooking决策逻辑

前言

在 Unreal Engine 的 Cook Pipeline 中,UCookOnTheFlyServer::LoadBeginCookIncrementalFlagsLocal 负责在 Cook 任务启动初期,依据命令行参数、配置文件以及当前平台的状态,决定本次构建应当执行 Incremental Cook(增量构建) 还是 Full Cook(全量构建)

一、 参数解析

在进入具体平台的处理逻辑之前,系统首先需要确定“全局构建目的”。这一阶段的核心变量为 bForceRecook,其值的确定遵循“配置默认值 -> 命令行覆盖”的优先级链条。

1. 默认策略初始化

系统首先通过 bDefaultIncremental 变量确立默认行为。

  • 非 Legacy 模式(主要路径):通过读取 GEditorIni 配置文件中的 [CookSettings] CookIncrementalDefaultIncremental 字段决定。若未配置,默认值为 true
  • Legacy 模式:依据 ECookInitializationFlags::LegacyIterative 标志位判定。
1
bool bForceRecook = !bDefaultIncremental;

2. 命令行参数的覆盖逻辑

命令行参数具有最高优先级,可直接修正 bForceRecook 的状态:

  • 强制启用增量
    • 参数:-CookIncremental-CookIncremental=true
    • 效果:bForceRecook = false
    • 注意:在 Legacy 模式下,若存在 LegacyIterative flag,亦会将此值置为 false。
  • 强制全量构建
    • 参数:-fullcook-forcerecook-forcerecook=true
    • 效果:bForceRecook = true
  • DiffOnly 特殊模式
    • 参数:-DIFFONLY
    • 效果:设置 bIsDiffOnly = true。此模式独立于常规增量逻辑,旨在进行差异比对而不修改磁盘上的资产。

至此,变量 bIncrementalOrLegacyIterative 被计算得出,它代表了本次构建的理论目的

1
const bool bIncrementalOrLegacyIterative = !bForceRecook && (!bLegacyBuildDependencies || ...);

二、 平台有效性验证

确定全局目的后,函数进入 BeginContext.PlatformContexts 循环,针对每一目标平台进行独立判断。增量构建是否被允许(bIncrementalOrLegacyIterativeAllowed),取决于Sandbox 状态Settings Hash的一致性。

1. DiffOnly 模式

bIsDiffOnly 为真,逻辑将直接跳过常规判定:

  • 结果bFullBuild = false,但 bAllowIncrementalResults = false
  • 行为:系统将保留磁盘上的旧包,但仅将本次 Cook 结果写入内存用于比对,不会更新本地缓存。

2. 常规模式

若非 DiffOnly 模式,系统将通过以下两层检查来决定 bIncrementalOrLegacyIterativeAllowed 的最终值。

A. 初始化阶段的强制清理

当平台 Sandbox 尚未初始化 (!PlatformData->bIsSandboxInitialized) 且 全局目的为非增量 (!bIncrementalOrLegacyIterative) 时,系统将强制执行全量清理。

  • 代码逻辑
1
2
3
4
5
if (!bIncrementalOrLegacyIterative && !PlatformData->bIsSandboxInitialized)
{
// 打印 FULL COOK 日志,提示由于 Default.ini设置 或 命令行参数 导致的全量清理
bIncrementalOrLegacyIterativeAllowed = false;
}
  • 日志特征
    • 若因配置导致:FULL COOK: Incremental Cooks are disabled by default in Editor.ini...
    • 若因参数导致:FULL COOK: -forcerecook=true (or an equivalent) was specified.

B. 配置一致性检查

即便全局目的允许增量,或 Sandbox 已初始化,系统仍需验证构建环境的一致性。系统会遍历所有 CookArtifact,加载上一次构建保存的配置与当前计算出的配置 (Current.Settings) 进行比对。

  • 代码逻辑
1
2
3
4
5
6
7
Artifact->CompareSettings(Context);
if (Context.IsRequestFullRecook())
{
// 关键路径:配置变更导致增量失效
bIncrementalOrLegacyIterativeAllowed = false;
break; // 只要有一个 Artifact 要求全量,则整体回退
}
  • 日志特征
    • FULL COOK: ... settings have changed and all previously cooked packages are invalidated.
    • 此日志表明 -CookIncremental 虽然已指定,但由于 Global Settings 或 Artifact Settings 变更,增量被否决。

三、 最终确认

经过上述判定,PlatformData 的关键标志位将被最终赋值,这将直接指导后续 Cook 流程的行为。

1. 判定结果为 Allowed

bIncrementalOrLegacyIterativeAllowed == true 时:

  • bFullBuild = false
  • bAllowIncrementalResults = true:允许复用旧结果。
  • bPopulateMemoryResultsFromDiskResults:若内存无结果,则允许从磁盘回填。
  • 日志INCREMENTAL COOK: ... settings are still valid.

2. 判定结果为 Not Allowed

bIncrementalOrLegacyIterativeAllowed == false 时:

  • bFullBuild = true
  • bAllowIncrementalResults = false
  • bClearMemoryResults = true:清理内存中的旧记录。
  • 日志:参见上文的 FULL COOK 日志。

3. 安全约定检查

最终把结论写回 PlatformData

1
2
3
4
PlatformData->bFullBuild = PlatformContext.bFullBuild;
PlatformData->bAllowIncrementalResults = PlatformContext.bAllowIncrementalResults;
PlatformData->bLegacyIterativeSharedBuild = PlatformContext.bLegacyIterativeSharedBuild;
PlatformData->bWorkerOnSharedSandbox = PlatformContext.bWorkerOnSharedSandbox;

后续 cook 流程会依据 PlatformData 的这些字段采取行为。

在函数末尾,存在一个关键的断言。若当前运行模式bFullBuildAllowed == false,但逻辑判定必须进行全量构建PlatformData->bFullBuild == true,系统将触发致命错误并中止进程,而非擅自执行清理。

1
2
3
4
if (PlatformData->bFullBuild && !bFullBuildAllowed)
{
UE_LOG(LogCook, Fatal, TEXT("...Aborting the cook."));
}

四、 总结

增量构建并非仅由命令行参数决定,而是一个多因素共同作用的动态决策过程:

  1. 命令行与 Ini 配置 决定了初始的构建目的。
  2. Sandbox 初始化状态 决定了冷启动时的清理策略。
  3. Artifact Settings 对比 构成了增量有效性的最后检查。

A. “增量”成功生效(即 bAllowIncrementalResults=true)必须满足所有条件:

  1. 不能是 -DiffOnly(DiffOnly 强制 bAllowIncrementalResults=false)。
  2. 对该平台,不能落入“初始化时强制全量清理”分支:
    • 也就是不能同时满足:!bIncrementalOrLegacyIterative && !bIsSandboxInitialized
    • 实操上:平台首次初始化时,必须处于 incremental/iterative 大前提为真,否则必 full。
  3. 设置对比不能要求全量:
    • 任一 CookArtifact 的 CompareSettings() 触发 Context.IsRequestFullRecook(),则必然 full。
  4. 如果处于某些 validate/diff 契约模式导致 !bFullBuildAllowed,则还必须保证最终不被判成 full,否则直接 fatal。

B. “全量”的典型触发条件:

  1. 显式 forcerecook/fullcook,且平台 sandbox 尚未初始化。
  2. 新系统下 Editor.ini 配置 CookIncrementalDefaultIncremental=false,且没有用命令行显式把它改回允许增量(例如 -CookIncremental-forcerecook=false),并且平台 sandbox 尚未初始化。
  3. legacy 模式下未设置 LegacyIterative flag(常见就是没带 -legacyiterative),且平台 sandbox 尚未初始化。
  4. 设置变化触发 RequestFullRecook:无论是否请求增量,只要触发就 full(并打印 settings changed 的 FULL COOK 日志)。

UE5.7 解析:Incremental Cooking决策逻辑
http://muchenhen.com/posts/46195/
作者
木尘痕
发布于
2026年1月12日
许可协议