修复UE4的一个Cook稳定性bug

问题

最近在做热更补丁的时候遇到一个问题,就是保持资源不变的情况下,连续两次 Cook,部分资源的 Cook 结果不一致,具体体现在某个字节会随机地在 0x00 与 0x04 之间取值,如图

diff.png

这个 Cook 不稳定的问题会导致做热更补丁包的时候,会将一些没有变化的资源文件也打进包中,导致冗余

分析

通过调试 Cook 序列化过程,最终定位到这个变化的字节是在序列化 FPropertyPropertyFlags 时候写入的,如图

serialize.png

也就是在连续两次 Cook 的时候,写入的 PropertyFlags 值不一致。对比两次写入的值 0x0000000400080004 和 0x0004000400080004,差异在 CPF_UObjectWrapper 这个标志位。

继续调试,发现这个标志位是在创建 FProperty 的时候根据 FEdGraphPinType 里的 bIsUObjectWrapper 的值来设置的,而 bIsUObjectWrapper 这个属性只在默认构造函数里进行了初始化,而其他的带参构造函数里都没有初始化,导致创建 FEdGraphPinType 对象的时候 bIsUObjectWrapper 会随机地取 truefalse,进而导致会随机地给 FProperty 对象随机设置 CPF_UObjectWrapper 标志位,然后序列化的时候就不一致了

initialize1.png

initialize2.png

修复

修复的方法很简单,就是在 FEdGraphPinType 类的所有构造函数和 ResetToDefaults 函数中正确初始化 bIsUObjectWrapper

后来在准备提交 PR 的时候发现官方已经在 4.27 中修复了这个问题,其他版本的还是需要自己修复一下,提交信息如图

fix.png

调试 Cook Tips

  • 调试具体资源的Cook时,如果项目大资源多,可以先通过 DirectoriesToNeverCook 配置将一些资源屏蔽
  • 通过 -FullLoadAndSave 命令行将 Cook 过程的异步 Load/Save 转换成同步过程,方便调试
  • 通过 -DIFFONLY 命令行可以调试前后两次 Cook 的差异信息