ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

UE4 Cook失败排查实战:从日志定位到依赖链与缓存修复

UE4 Cook失败排查实战:从日志定位到依赖链与缓存修复 1. Cook失败这种事为什么我劝你先冷静下来做UE4项目的人多少都在某个版本节点上栽过Cook这道坎。明明编辑器里跑得飞起PIE也正常一到打包就给你甩一脸错误日志而且往往是项目临交付或者要做QA构建的时候错误来得最密集。这篇我记录的是一次完整的Cook资源失败排查过程从崩溃开始到定位、拆解、逐个击破最后总结出一套可复用的处理流程。先说个基本认知UE4的Cook本质是把工程里的资产打包成目标平台可读取的中间格式再结合关卡、代码、Shader编译结果最终生成Pak包。这个环节里跑的是编辑器逻辑的子集所以Cook失败并不等于你的项目“坏了”更多时候是资源配置不合理、引用不规范、或者是构建环境出了一些隐藏问题。适合读这篇内容的人我猜是这些已经能正常启动UE4项目但一执行Build就报错日志看不懂发版前频繁被Cook错误打断每天盯着输出窗口怀疑人生想给团队整理一套查Cook报错的SOP但手头缺少一份系统性的排查链路参考如果你符合其中任何一条这篇记录应该能帮你少折腾一两天。这里面没有什么玄学所有报错背后都有对应的原因排查链路是固定的关键在于你有没有一套自己的方法。2. 先搞清楚Cook失败的本质再动手删资源2.1 编辑器里没事为什么Cook就炸了这是很多人问的第一个问题。UE4编辑器加载资源用的是开发态格式贴图是原图模型是原始网格蓝图有完整的节点图。Cook出来之后要落地到某个具体平台比如Windows、Android或iOS资源格式要转换、压缩、序列化Shader要在编译后编进资源包里蓝图节点要生成可执行的字节码。所以你会发现Cook失败的报错很多根本不是“资源缺失”而是Shader编译不过去某个材质在特定平台下编译出非法指令纹理格式不被目标平台支持比如Android上用了RGBA16F且没有Fallback蓝图字节码生成失败往往是某个节点在Cook阶段执行了EditorOnly逻辑资源引用链断裂Cook到一半某个引用关系找不到对应对象2.2 Cook失败的几种类型决定你该怎么查我习惯把Cook失败分成三类每一类的排查方式完全不一样。失败类型典型现象排查方向单个资产失败日志里明确指向某张贴图、某个模型、某个关卡优先在编辑器里单资产验证Cook依赖链失败报错对象是A但根因在BB是A引用的查引用关系打断依赖链环境性失败同一份代码别人机器能过你机器不能过查缓存、共享内存、磁盘剩余、路径深度第一类最简单直接在编辑器里对报错资产执行单独的Cook或重存基本能复现。第二类最隐蔽经常让你误判。第三类最气人因为代码和资源都没问题纯粹是环境问题。3. 从日志里挖出真正的元凶我的完整排查链路3.1 日志要看哪几行怎么看遇到Cook失败第一件事不是去翻Content目录而是先拿一份完整日志。Windows下UE4的Cook日志默认在项目目录/Saved/Logs/目录里文件名一般是烤制时的时间戳加Cook前缀。如果你在Build任务里跑了Cook那日志会嵌入整个构建日志里。我习惯用编辑器里的Output Log配合命令行同时跑因为Output Log有实时过滤而命令行日志保留了最原始的堆栈信息。拿到日志之后我只看三类东西Error级别的行这是直接告诉你什么失败了的。Warning配合Error附近的行很多失败是Warning触发出来的连锁反应。Cook命令的任务编号UE4的Cook日志会显示当前正在处理哪个包、第几个资产顺着这个编号往前翻能定位到是哪个批次崩的。3.2 一次真实崩溃的日志定位过程这次我遇到的情况日志最后几行是这个样子LogCook: Warning: Unable to find package for cooking CharacterBase requested by Map_Test01 LogCook: Error: Cook failed. LogCook: Display: 0 errors, 12 warnings.很多人看到这行就开始慌心想“CharacterBase是不是被删了”但注意看警告说的是“Unable to find package for cooking”意思是Cook系统在序列化某些对象的时候找不到CharacterBase这个包。这不代表它在磁盘上不存在而是它没有被加入这次Cook的依赖收集范围。我接下来执行了命令行Cook单跑UE4Editor-Cmd.exe 项目.uproject -runcook -targetplatformWindows -mapMap_Test01 -iterate -unversioned -log这里有几个参数解释一下-runcook是固定调用Cook命令-targetplatformWindows指定目标平台-iterate只补Cook有变动的资产别全量跑-unversioned不生成版本号附加信息调试更快-log强制输出完整日志单跑之后立刻复现输出的信息比合入Build的日志多了几十行最终锁定的SQLite报告里显示问题出在CharacterBase蓝图里挂了一个继承自ActorComponent的C类但这个类在目标平台下没有实现。3.3 日志看不懂时直接开时间戳UE4的Cook日志有个让人恼火的问题就是它的输出顺序不一定和实际执行顺序完全一致。尤其多线程Cook开启后默认开启了同一时间有多个资产在处理日志会交叉打印你根本排不出先后。这时候别硬看直接在命令行里加-logtimes它会在每行日志前打上[时间戳][帧号]格式的前缀用记事本打开后按时间排序整个逻辑链就清晰了。我这次排查花了很长时间后来发现有一张4096x4096的贴图在Android平台下压缩耗时远高于其他资产导致整个Cook进程看起来像卡死。如果不加这个参数你很难判断“慢”和“挂掉”的区别。4. 材质与贴图类失败最常见也最容易被误判4.1 Shader编译失败的一个隐蔽原因Cook过程中材质编译是重头戏。如果某个材质在编辑器里看起来一切正常但是Cook时Shader编译报错十有八九是材质表达式里用了某个平台不支持的节点或其组合方式不合理。我这次遇到的是Landscape图层材质里面用了一个World Position Offset节点去做顶点动画但目标平台是Android。这个节点本身在Android也能用问题是我在同一个材质里混用了Pixel Depth Offset和Vertex Color两个节点在移动端组合会产生不可预期的编译行为。排查方法是把一个复杂材质里的节点逐个禁用每次只保留一个变量然后重新Cook直到找出哪两个节点组合会报错。这个过程很枯燥但有效。4.2 纹理压缩失败的识别信号日志里如果出现Unable to compress texture ...之类的提示首先去检查纹理的压缩设置。UE4里长宽不是2的幂次时某些压缩格式比如BC7无法处理会回退到RGBA8在某些平台上是合法回退在另一些平台会直接报错。还有一点容易忽略贴图的Source纹理尺寸超过4096后Android的OpenGL ES 3.0部分驱动不支持4096的Cubemap或有最大纹理尺寸限制。日志里如果只显示某一帧纹理压缩失败但实际上Cook流程因为这个中断了可能就是这种。解决方式是在纹理导入设置里勾选“Power Of Two Mode”为PadToPowerOfTwo或设置MaxTextureSize为2048对性能影响很小但Cook稳定性大幅提升。4.3 UV错误引发的烘焙问题有些贴图类失败不是压缩的事而是模型UV超出0-1范围。Cook阶段虽然不会执行渲染但会把模型的静态光照贴图信息烘焙出来UV超出范围而且没设置Wrap模式时光照贴图通道会写入非预期数据最终反映为Cook报错。这种问题往往在编辑器里不提示只有Cook时才炸。处理方法是选中对应StaticMesh在Mesh Settings里检查UV Channel 1是否在0-1范围内配合UV Channel Editing工具修正。5. 依赖链断裂最让人头秃的一类Cook失败5.1 蓝图里的硬引用Cook收集不到的三种场景这次排查还连带修了两个依赖链问题都属于“编辑器里正常Cook时找不到对象”的典型。整理一下动态加载用字符串路径LoadObject或StaticLoadObject运行时传入的资源路径Cook收集器不一定能识别出来因为它默认通过硬引用关系收集资产。字符串路径属于软引用必须有对应的AssetRegistry扫描支撑。蓝图里通过变量暴露的对象引用被标记为Transient某些变量在Details面板中勾了Transient后Cook序列化时会被跳过但运行时又需要它于是出现“Cook成功但运行时崩溃”和严格意义上的Cook失败不同但排查思路类似。C里使用ConstructorHelpers::FObjectFinder引用的资源只存在于某个插件但插件未启用Cook收集器扫描依赖时插件未启用会导致整个包都不进入收集范围。5.2 用Reference Viewer批量排查依赖链排查依赖问题时我习惯优先用Content Browser的Reference Viewer在资源上右键 → Reference Viewer勾上“Show Soft References”和“Show Hard References”能直观看到资源间的引用图。但这东西有个局限它只展示编辑器已经加载进来的引用。如果你想在无UI环境下精确知道一个资产的引用链用命令行更靠谱UE4Editor-Cmd.exe 项目.uproject -runAssetRegistry -modequery -object/Game/Characters/CharacterBase -propertyDependencies这个命令会直接输出CharacterBase的所有依赖包路径拿它和你Cook失败时的报错路径做对比缺失的依赖项一目了然。比在编辑器里一个个点高效很多。5.3 修复依赖链之后的“假成功”坑修复完成后别忘了验证一下Cook是否真正通过。有些时候日志显示“0 errors”但Pak包是残缺的。我的验证方法是用命令行执行一次加载测试UE4Editor-Cmd.exe 项目.uproject -runLoadPackage -map/Game/Maps/Map_Test01 -log如果这个命令没有任何Error才说明依赖链真的补全了。否则哪怕Cook报告成功也只是把缺失的引用跳过了运行时大概率会崩。6. 构建机环境的隐性炸弹内存、路径、缓存与并发6.1 路径超长问题Win10下你防不胜防如果你的项目放在D:\GameProject\Client\Main\UE4\ProjectName\Content\...这种层级比较深的目录里Cook到一半很有可能突然报一堆“Cannot find file”或“Create directory failed”的错误。这不是文件丢了而是**Windows的MAX_PATH限制260个字符**撞上了UE4的Cook临时目录。UE4的Cook会往项目Saved目录写入大量中间文件路径一长就爆。解决方式很粗暴但有效把项目移到浅目录比如D:\UProj\你的项目名\或者开启Windows长路径支持注册表里设置LongPathsEnabled为1重启。两种方式我都在项目里用过前一种更稳妥因为即使你开启了长路径某些三方库底层还是调用的旧API照样会炸。6.2 缓存损坏同一个锅背了两次黑锅Cook缓存有多坑我觉得值得单独讲一下。UE4的Cook缓存分为两级一是Saved/Cooked目录的成品缓存二是Saved/DerivedDataCacheDDC的中间数据缓存。这次项目里我遇到的诡异现象是第一次Cook失败清理了资源后重新跑还是同样的错误而且错误路径指向一个已经不存在的资产。最后我把Saved/DerivedDataCache整个目录删了再Cook一次居然就过了。原因在于DDC里保留了旧的资产输出记录Cook系统在做增量更新时以为这些旧资产还是最新的就直接复用了缓存结果而那个缓存本身是坏的。这个坑非常隐蔽因为你修了资源、修了引用但DDC还在用失效数据。提示遇到“删了资产还在依赖它”的诡异Cook错误先删除Saved/DerivedDataCache目录再试一次成本极低不要一上来就动项目配置。6.3 并发Cook的线程数调整某些资源在Cook时有状态冲突特别是一些自定义C类里的静态变量如果多个线程同时访问同一个全局数据就会产生竞态条件表现出来的就是随机性很强的Cook失败——你重跑一次崩的资源都不一样。遇到这种情况先别急着改代码试试限制Cook线程数UE4Editor-Cmd.exe 项目.uproject -runcook -targetplatformWindows -CookWorkerCount1 -unversioned -log默认情况下UE4会按CPU核心数启动多个CookWorker。调成1以后很多因为并发导致的随机失败直接消失。如果你的项目是在验证阶段用单线程跑一次确认问题根因之后再有针对性地修复代码里的静态数据访问问题。7. 提升Cook效率减少无谓失败的三个习惯7.1 每次交互前先做一次无UI的Cook验证很多项目是美术、策划、程序共用一套工程。美术在编辑器里操作改了很多资源但他不知道某个改动会让Cook失败。如果等到正式构建时才暴露后端工程师就要在一个巨大日志里捞针。我自己的习惯是每天至少跑一次无UI的Cook验证命令就是前面提到的基础命令不需要打最终包只要Cook能出Pak或中间产物就算过。这套验证可以在本地跑也可以在构建机上定时跑。尽早发现问题排查成本最低。7.2 善用Cook命令的迭代模式平时开发中全量Cook非常浪费时间。除非你要出最终验证包否则我都用-iterate模式。它根据资源时间戳和DDC缓存来决定哪些资产需要重新Cook其余直接跳过。实测下来一个Asset中等的项目全量Cook可能要30分钟-iterate模式常常5分钟以内就完成了。用它的前提是确保你的工程版本的资源时间戳是准确的。如果某个环节统一修改了所有资源的时间戳比如从版本控制里批量checkout那-iterate会退化成全量Cook但即便如此也不会出错只是慢。7.3 给构建机设置独立的构建账户构建机和开发机应该分开这是一条相对更实用的建议。在开发机上跑Cook你背后还开着IDE、浏览器、通讯软件内存占用大了以后Cook会莫名资源不足然后报一些“Out of memory”或“Unable to allocate”的错误。构建机用独立账户跑构建任务时其他服务全停Cook的稳定性大幅提升。另外构建机上的杀毒软件和索引服务也建议把项目目录加入排除列表。我遇到过不少次Cook失败是因为某个dll或中间产物正在被杀毒软件扫描锁定导致文件写入失败。8. 个人体会Cook排障本质上是资源意识的较量Cook失败的排查没有太多捷径但如果你能做到下面三点大部分问题都能在半小时内定位拿到日志先分类型不盲猜善用命令行工具把问题缩小到最小复现范围遇到诡异情况先清DDC缓存再做其他尝试我自己的项目组从建立这份排查流程之后Cook失败的平均定位时间从一整天缩短到了两三个小时。现在新来的同事遇到打包报错第一反应不是去群里喊人而是自己拉日志、查类型、跑单测效率提升非常明显。最后再分享一个小工具吧UE4自带的命令行里有个-logtimes参数我前面提过一次这里再重复一遍是因为它真的救命。项目组的所有打包脚本里我都加了这一项出了问题直接把日志按时间轴展开谁先谁后一目了然。没有它我大概还会在那些交错的Cook日志里多挣扎很多次。
返回列表