mcpField
S
scenario-unity-pipeline-automation

scenario-unity-pipeline-automation

github.com/scenario-labs开发1.2k251 次安装1 天前更新
代码仓库

关于 scenario-unity-pipeline-automation

scenario-unity-pipeline-automation 面向 Unity 工具和构建工程师,帮助建立可重复的内容流水线。内容涵盖确定性导入、序列化编辑、Addressables 打包、测试门禁和从干净检出运行 CI,并通过计数与重跑检查验证稳定性。

主要功能

  1. 01确定性资源导入规则
  2. 02序列化资源与预制件编辑
  3. 03Addressables 分组与内容构建
  4. 04构建前测试与发布门禁
  5. 05玩家构建冒烟测试
  6. 06CI 流水线生成

适用场景

  1. 01自动处理批量导入的 FBX 资源
  2. 02按加载条件构建内容包
  3. 03通过内容测试把关玩家版本发布
  4. 04从干净的 CI 检出运行构建

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/scenario-labs/skills --skill scenario-unity-pipeline-automation

安装后在 Claude Code 中输入/scenario-unity-pipeline-automation确认已加载。

包含的文件

除 SKILL.md 外,安装时一起下载的参考资料和脚本。

references/
critique.md
expert-notes.md
gui-paths.md
procedures.md
sources.md
scripts/
ut_pipeline.py
scripts/AgentKit/Pipeline/
AddressablesJobs.cs
ArtDropJobs.cs
EditorEditJobs.cs
PipelineBuild.cs
PipelineChecks.cs
PipelineRules.cs
PropImportPostprocessor.cs
scripts/AgentKit/Pipeline/Tests/
PipelineContentTests.cs
scripts/AgentKit/PipelineCli/
AgentKit.PipelineCli.asmdef
PipelineCliCommands.cs
scripts/Runtime/
AgentAddressablesSmoke.cs
scripts/templates/PipelineAsmdef/Editor/
Game.Pipeline.Editor.asmdef
TextureRuleAudit.cs
scripts/templates/PipelineAsmdef/Tests/
Game.Pipeline.Tests.asmdef
TextureRuleTests.cs

详细介绍

Unity 流水线自动化(工具与构建工程师)

这里的专家级水平意味着:流水线在每台机器、每次运行中都能产出相同结果;导入时应用规则,通过序列化进行编辑,按加载时机打包内容,用测试把关构建,并由 CI 从干净的检出版本运行构建。原则是:不重复手动操作,不凭空信任任何结果,必须有数量统计、测试或帧作为依据;再次运行时不应产生任何变化。如果此处提到的同级技能不在你可用的技能中,请让用户安装它(npx skills add scenario-labs/skills --skill <name>);在无人值守的情况下,根据工具架构继续操作并指出这一缺口。

必备背景: scenario-unity-expert(通道、作业协议、审查循环、6.3 陷阱)。 导入其工具包;此技能新增 scripts/ut_pipeline.py 和 scripts/AgentKit/Pipeline/。

状态(2026-09-24,盲测评分重构后): 所有流程都已在这台 Mac 上使用 Unity 6000.3.21f1 针对一批 200 个 FBX 的 Blender 导出文件运行:tests/code/unity-pipeline-automation/(结果位于 archive/tests/unity-pipeline-automation/live_results.jsonl)。

立场(专家观点差异)

  1. 导入规则是在导入时运行的代码,必须保证确定性并加以验证。 在 OnPreprocess* 中设置选项,每次代码变更都递增 GetVersion(),先声明配置再读取 (context.DependsOnSourceAsset),不使用时钟、不依赖字典顺序、不在回调中写入资源 (6.3 Manual;Javier Abud Chavez,S2P9n5U9xVw [00:04:35]、[00:19:29])。验证方式:在信任共享缓存或 CI 前运行 -consistencyCheck(Manual)。观察结果:23.5 秒检查了 12,184 个资源;随机像素探测纹理被标记,受管理的 593 个文件中有 0 个被标记。递增版本号或新增后处理器,会重新导入该导入器类型的所有资源,包括程序包(1,513 个纹理)。
  2. 只有通过序列化修改了确切的对象,编辑才算生效。 在变更前,对被修改的组件记录 Undo(Freya Holmér,pZ45O2hg_30 [03:01:01])。观察结果:执行 Undo.RecordObject(go) 后移动对象,操作无法撤销;执行 RecordObject(go.transform) 则可以。直接写入预制件实例会在下次预制件更新时还原;ScriptableObject 若未调用 SetDirty,则不会保存。
  3. 每个阶段只进行一次 AssetDatabase 批处理,并测量耗时。 使用 try/finally 包裹 StartAssetEditing / StopAssetEditing(Abud Chavez [00:30:21]),并在其中调用 SaveAndReimport / ImportAsset。使用 AssetDatabase 计数器统计,不要依赖日志(Abud Chavez [00:26:44])。观察结果:对 195 个 FBX 执行两轮重映射,逐个处理耗时 19.0 秒,批量处理耗时 5.1 秒。
  4. 按加载条件而非文件夹打包 Addressables,并保持顺序稳定。 在完全相同条件下所需的资源应放在同一组;多个组共用的依赖项应显式放置(Olle Axelsson,Valheim,Fzu2Das_1FU [00:23:08])。未分配的共享依赖项会被复制到每个 Bundle 中 [00:18:44];观察发现,其中包括 URP 的 Lit.shader。按序号顺序分配(6.3 Manual,Addressables 确定性):2.9.1 保存时会按 GUID 对组和条目排序,但标签表会保留插入顺序。
  5. 释放不等于卸载,引用也会触发加载。 当 Bundle 的引用计数降至零时,内存才会释放(Addressables 2.9 手册);引用 Addressable 内容的构建场景会在加载场景时加载这些内容,并再次从 Bundle 加载(Code Monkey,C6i_JiRoIfk [00:03:32];Axelsson [00:24:49])。为其设置门控;在播放器中测量卸载情况。
  6. 在启动时固定平台,并确保每个阶段的平台一致,同时发布构建时使用的内容。 在批处理作业中切换目标无效(Manual;Thom Hopper,BlVsi2cSJ88 [00:27:18]);构建目标是导入依赖项(Abud Chavez [00:15:49])。观察结果:一个阶段在 Android 上重新导入了 1,717 个资源,耗时 52 秒;切换回去后复用了缓存产物(60 次导入)。Addressables 的默认设置会在每次播放器构建中重新构建所有内容。
  7. 测试是发布门槛。 将内容规则编写为参数化的 Edit Mode 测试,每个资源对应一个用例(Warnecke 和 Fine,wTiF2D0_vKA [00:24:28]),并在预构建回调中同步运行,记录通过信息 [00:31:43]。除非使用 LogAssert.Expect 预期了日志,否则任何错误日志都会导致测试失败(Manual);观察发现,这也包括测试中重新导入所记录的导入错误。使用 -runTests 时绝不要加 -quit。
  8. 发布构建应来自干净的代码树,不启用调试定义,并保留溯源信息(文档摘要检查清单;Hopper,配置定义)。优先使用范围明确的命名工具,而非通用执行(git-amend,VPjo-M6mPkE [00:03:54];Unity,DgNrgZeJOxQ [00:07:41])。

首先确定

  • 交付内容约定: DCC 和导出设置、每个类别的文件夹、后缀、单位。默认值:Blender “FBX All” + “Apply Transform”,_BaseColor/_Normal,并用 manifest.csv 记录额外标签。
  • 加载条件: 按集合(关卡、生物群系)加载,还是逐个加载?默认值:标签, key_by="label";流式加载使用 key_by="root"。
  • 目标和预算: 平台(每次流水线运行使用一个 -buildTarget)、每个平台的纹理上限、顶点预算、每个标签的资源包预算。默认值:桌面端 1024 px,移动端 512 px,5,000 个顶点。
  • 内容更新: 发布后是否有远程内容?按平台、按发布版本归档 addressables_content_state.bin。
  • 渠道和 CI: 用户是否在该项目中打开了编辑器(ut_live.channel(P))?是否有 Git 仓库?是否有 Accelerator?许可证:Personal(仅需登录 Hub)或付费席位。

工作流

  1. 预检。 ut_env.preflight(P);ut_pipeline.install(P)。编辑器已打开:通过 ut_live.call 或 [CliCommand] 工具执行相同任务。团队测试必须调用的流水线代码:项目自己的 Editor asmdef 和一个测试 asmdef(install_asmdef_template)。GATE:Echo 正常,编译错误为 0(一个错误就会中止所有批处理任务)。
  2. 离线扫描交付内容。 up.scan_drop(drop),规则相同,使用 JSON。GATE:每个拒收项都有原因;重复项的每个副本都拒收。
  3. 导入。 up.import_drop(P, drop, target=T):将更改的文件导入 <root>/<Category>/<Name>/,单次批处理,并进行审计。GATE:已接受数量 = 找到数量 - 拒收数量;审计错误均有说明;后处理器更改后,up.consistency_check(P, target=T) 不会在 Assets/ 下标记任何内容。
  4. 材质和预制件。 up.build_prefabs(P, target=T):每个道具使用 URP Lit 材质,根据 ShaderGUI.ValidateMaterial 设置关键字,在批处理中通过 SaveAndReimport 重新映射 FBX,在预览场景中构建 Prefab Variants,仅在值发生更改时保存。GATE:预制件数量 = 已接受数量 - 尺寸错误数;重新运行后重写文件数为 0(git status 干净)。
  5. 查看效果。 依次运行 EditorEditJobs.BuildLineup、启用 graphics=True 的 AgentCapture.CaptureViews、ut_review.review_capture,然后打开图集。GATE:没有洋红色、黑色或空白标记;道具直立、落地且比例正确。
  6. Addressables 组。 up.assign_addressables(P, "condition", target=T)。GATE:implicit_duplicates == 0;up.hard_references(P) 正常。
  7. 构建内容。 up.build_content(P, T):构建器索引 >= 0,执行 ClearCachedData + BuildCache.PurgeCache(false),设置 DoNotBuildWithPlayer,回读布局,并归档状态。GATE:重复资源数为 0,每个标签的字节数均在预算内。
  8. 测试。 ut_run.run_tests(P, "EditMode", categories="PipelinePreBuild", extra_args=["-buildTarget", up.cli_target(T)])。 GATE:失败数为 0,总数等于预期资源数。
  9. 构建 Player。 从已提交的模板复制配置文件(使用 template 调用 PipelineBuild.CreateBuildProfile),然后运行 ut_run.build(P, T, profile=...),或直接使用 -activeBuildProfile ... -executeMethod AgentKit.Pipeline.PipelineBuild.BuildFromCommandLine。 发布:使用 -agentRelease(门禁会拒绝调试定义),确保工作树干净,并运行 up.release_ready(repo, app)。 GATE:AGENT_GATE 正常,hard_references 为 0,BuildReport 状态为 Succeeded。
  10. 冒烟测试 Player。 up.player_smoke(app, label)。GATE:已加载资源数量等于清单数量;释放后资源包已卸载。
  11. CI。 up.write_ci(repo):生成 ci/pipeline.sh(每个阶段使用一个进程;每个阶段使用相同的 -buildTarget;设置 ACCELERATOR=、CONSISTENCY=1、RELEASE=1)和 GitHub Actions 文件。GATE:从不含 Library/ 的检出目录运行并通过;许可证通过 if: always() 归还;启用 Accelerator 时,日志中的 cache server= 计数大于 0。

数字

数值对比对象来源
5.6 到 6.7 s一次性复制并导入 593 个文件实测
19.0 s vs 5.1 s对 195 个 FBX 执行两轮重映射(SaveAndReimport),逐个执行 vs 一次性批量执行实测
11 到 12 s197 个材质、197 个 FBX 重映射、196 个 Prefab Variant,在编辑器中的耗时实测
1,717 次导入,52 s / 60 次导入首次在另一个平台启动 / 切换回来(已缓存的构件)实测
1,513 张纹理,17 s一个不执行任何操作的纹理后处理器的 GetVersion() 递增后重新导入实测
检查 12,184 项,23.5 s此项目的 -consistencyCheck(跳过 7,390 项;标记了 2 个 URP 着色器:基线包)实测
0 个文件第二次完整运行(导入、预制件、分组)所更改的文件实测
791 项测试,10 到 16 s针对 196 个预制件、396 张纹理、197 个模型的内容测试实测
13.5 / 12.9 / 4.8 MB最差的标签加载量,分类 / 隔离 / 条件布局(3 个生物群系)实测
5分类布局中的重复资源(2 张纹理、Lit.shader、2 个回退资源)实测
0 到 63 ms最后一次 Release 后仍加载的 AssetBundle(7 次玩家运行)实测
60 到 158 s / 5 到 23 s首次 macOS Mono 玩家构建 / 增量重建(共享机器);玩家包 127.4 MB实测
0.4 到 1.2 s vs 10 到 17 s同一任务通过常驻编辑器的桥接执行 vs 启动编辑器的批处理任务实测
4 GB为跨平台兼容性设定的每个 AssetBundle 上限Addressables 2.9 手册
30,000 个顶点FBX 预算警告示例Unity 教程,qZ5NmyoxKRk [00:03:55]
38%,约 110 MBValheim 通过流式加载减少的内存,随后通过减少已加载的 AssetBundle 进一步降低Axelsson [00:03:02], [00:30:41]
179 s / 486 s从没有 Library/ 的检出目录生成 ci/pipeline.sh(v0.2,空闲机器 / v0.1,有 6 到 8 个其他编辑器运行)实测
0 / 8 / 6unity test 退出码:通过 / 测试失败(绝不重试)/ 无结论(重试)unity-cli 技能

质量门禁

  • **可衡量:**信封 ok,无编译错误,每个阶段的 active_target 均相同;ImportDrop 计数;Assets/ 下的一致性检查通过;预制件数量;重新运行:复制数为 0,git status 无更改;implicit_duplicates 为 0,且 duplicated_assets 为 0;按标签统计 KB;无硬引用 Addressable 内容的构建场景;NUnit 失败数为 0,且总数符合预期;AGENT_GATE 为 ok;BuildReport 为 Succeeded;玩家冒烟测试计数;发布:工作树干净,来源记录 source.dirty 为 false,无禁止的定义;CI 脚本从干净检出运行,退出码为 0。
  • **视觉:**已打开排列图:没有洋红色;法线贴图着色正常;道具直立;枢轴位于地面;与 1.8 m 胶囊体相比,尺寸合理。

常见错误

错误表现修复
在 OnPostprocessTexture 中设置导入器选项;代码已更改,但未提升 GetVersion() 版本使用旧设置;不同机器结果不一致使用 OnPreprocess*;提升版本;使用 -consistencyCheck
在规则 JSON 中添加非导入器键所有受管控资源都会重新导入使用单独的文件(pipeline_checks.json)
移动对象前调用 Undo.RecordObject(gameObject)移动操作无法撤销记录 Transform
直接写入预制件实例或 ScriptableObject下次更新预制件时被还原/文件未更改使用 RecordPrefabInstancePropertyModifications/SetDirty
未使用 finally 的 StartAssetEditing;批处理之外对每个 FBX 调用 SaveAndReimport数据库冻结;重新映射速度慢 4 倍使用 try/finally;在批处理中重新导入
各阶段使用的 -buildTarget 不一致每个阶段都会重新导入纹理和着色器所有阶段(包括测试)使用相同目标
每个文件夹单独建组,却共享纹理每个包中都包含相同的纹理和着色器条件打包;检查构建布局
按文件顺序或 HashSet 顺序添加标签不同机器上的设置文件内容不一致使用序数排序
构建场景引用了一个 Addressable 预制件加载两次,绕过包在门禁中使用 HardReferences
构建内容后又执行默认玩家构建内容被重新构建,归档状态过时使用 DoNotBuildWithPlayer + 门禁
在批处理作业中调用 SetActiveBuildProfile;使用来自内部 API 的配置文件目标平台或定义过时;升级后失效使用 -activeBuildProfile;复制已提交的模板
测试重新导入的资源,其导入器会记录错误出现 "Unhandled log message",测试失败使用 LogAssert.Expect
测试位于 test asmdef 中,却调用 Assembly-CSharp-Editor 中的代码出现 CS0103,每个批处理作业都中止将管线代码放入单独的 Editor asmdef
使用 Accelerator 时调用 -quit,但未设置等待标记;服务器无法访问上传丢失;作业静默通过使用 -cacheServerWaitForUploadCompletion;检查 cache server=
从有未提交更改的工作树发布来源信息为 dirty: true,CLI 仍会构建保持工作树干净,设置 RELEASE=1,将 Addressables 的 link.xml 加入 gitignore
Blender 默认 FBX 导出根节点旋转 90 度,缩放比例为 100选择 FBX All + Apply Transform(scenario-blender-export)
按顺序解决重复名称错误资源会悄然胜出拒绝所有副本并询问
在作业中创建 Addressables 设置下一次运行时会重写设置文件在 GetSettings(true) 后设置这两种提供程序类型
使用 -quit 和 -runTests;--output-path 为相对路径没有 XML;构建输出位于项目之外省略 -quit;使用绝对路径

交接

  • 接收: 来自 scenario-blender-export、scenario-maya-expert、scenario-3d、scenario-textures 的 FBX、纹理及导出设置;来自 scenario-unity-architecture 的代码布局和 asmdefs;来自 scenario-unity-world-building 的道具加载分组信息。
  • 交付: 向 scenario-unity-performance 提供构建报告、资源包大小和各标签的加载情况;向 scenario-unity-mobile 提供纹理格式(此技能只设置尺寸上限)和签名构建;向 scenario-unity-web 提供 Web 构建(WebGL 上不使用 WaitForCompletion);向 scenario-unity-rendering-lighting 提供光照贴图 UV 需求;向负责人提供规则 JSON、道具清单、包络、NUnit 总数、布局 JSON、BuildReport、来源信息和联系表。

Unity 6.3 说明

  • Addressables 2.9.1 是此编辑器的默认版本(文件夹键和 await handle 属于 4.0);其后处理器会将任何导入的组资源采用到默认设置中。6.6 中,内容目录将取代 AssetBundle 构建。
  • IPreprocessBuildWithContext 也会在 AssetBundle 构建时触发:使用 BuildPipeline.isBuildingPlayer 进行筛选。
  • 6.5 之前没有公开的配置文件创建 API;AssetDatabase 计数器可通过 UnityEditor.Experimental.AssetDatabaseExperimental.counters 公开访问。
  • Unity CLI 处于 Beta 阶段;unity build 会在 macOS 上将来源清单写入 .app 内。个人许可证只能通过 Hub 登录激活。

参考资料

评论

支持 Markdown