Unity 工具链修复实录:让 AI Agent 直接驱动 Unity 编辑器编译与测试

封面图

项目:Unity 2022.3 模拟经营游戏
环境:macOS / Unity 2022.3.51f1c1 / Unity Pipeline(com.unity.pipeline 兼容分支)


一、背景:为什么需要这套工具链

在做 ChaRestaurant 这个 Unity 2D 模拟经营游戏时,我们引入了 Unity Pipeline(Unity 官方的 com.unity.pipeline 包)——它能在 Unity Editor 内部跑一个 HTTP 服务器,让外部程序(CLI、CI、AI Agent)远程驱动编辑器:触发编译、跑测试、改场景、查日志、控制 Play Mode。

理想的工作流是:

AI Agent / CI 脚本
    │  HTTP 请求
    ▼
Unity Editor (内置 Pipeline HTTP 服务器, 端口 7800)
    ├── 触发 recompile → 返回编译结果
    ├── 运行单元测试 → 返回测试报告
    ├── 读写场景/资源/组件
    └── 控制 Play Mode / 截图 / 查日志

这套工具链能让 AI Agent(如 Claude / Codex / 自研 Agent)直接驱动 Unity 编辑器,实现"改代码 → 自动编译 → 跑测试 → 拿结果"的闭环自动化。

但问题是:这套工具链一开始根本没有配置成功。


二、问题诊断:为什么"没配置成功"

拿到任务后,我按顺序排查了 6 个环节,发现了整整 6 个问题:

问题 1:unity CLI 根本没安装

检查 which unitycommand not found。官方文档说通过 Unity CDN 安装:

curl -fsSL https://public-cdn.cloud.unity3d.com/hub/prod/cli/install.sh | UNITY_CLI_CHANNEL=beta bash

安装后得到 unity CLI v0.1.0-beta.3。

问题 2:com.pipeline.unity2022 包严重不完整

仓库里 Packages/com.pipeline.unity2022/ 只有 3 个文件(完整包应有 582 个):

com.pipeline.unity2022/
├── Runtime/Common/BasePipelineServer.cs      ← 唯一的核心文件
├── Runtime/Unity.Pipeline.asmdef
└── Tests/Editor/ServerLifecycle/PipelineServerTests.cs

BasePipelineServer.cs 里引用了 Unity.Pipeline.ModelsUnity.Pipeline.CommandsUnity.Pipeline.SecurityUnity.Pipeline.Threading 等命名空间——全部不存在,代码根本编译不过。

问题 3:manifest.json 从未引用 pipeline 包

Packages/manifest.json 里根本没有 com.pipeline.unity2022 / com.unity.pipeline 的依赖项,Unity 压根不会加载它们。

问题 4:fork 依赖的 Roslyn 在项目里不存在

fork 的 asmdef 声明了 precompiledReferences 指向 Microsoft.CodeAnalysis*.dll 等 Roslyn DLL,但项目 Assets 里一个都没有

问题 5:asmdef 引用了未安装的 InputSystem

fork 的 asmdef 引用 Unity.InputSystem,但项目 manifest 里没有这个包。

问题 6:官方源码有 Unity 6 专属 API

从官方 0.3.1-exp.1 拉下来的源码里,用到了 PhysicsMaterial(Unity 6 才有的类型,2022.3 叫 PhysicMaterial)和 Material.rawRenderQueue(Unity 6 属性,2022.3 只有 renderQueue)。


三、修复过程:六步走

第一步:找到完整源码

仓库里的 fork 是基于 Unity 官方内部包 com.unity.pipeline(版本 0.3.1-exp.1)做的 2022.3 兼容适配。我从 Unity 官方包注册表下载了原始 tarball:

https://download.packages.unity.com/com.unity.pipeline/-/com.unity.pipeline-0.3.1-exp.1.tgz

对比后发现:fork 的 BasePipelineServer.cs 和官方源码几乎一致(只差 watchdog 心跳的几行改动),确认 fork 就是官方源码的轻量适配。

第二步:补全包结构

把官方源码的 Runtime/Editor/CodeGen/ 全部复制进 com.pipeline.unity2022/(共 309 个文件),并:

  1. 创建 package.json(fork 之前根本没有!):

    {
      "name": "com.pipeline.unity2022",
      "version": "0.3.1-exp.1.compat.2",
      "unity": "2022.3",
      "dependencies": {
        "com.unity.test-framework": "1.1.33",
        "com.unity.nuget.newtonsoft-json": "3.0.2",
        "com.unity.nuget.mono-cecil": "1.11.6",
        "...": "..."
      }
    }
    
  2. 移除 asmdef 的 Unity.InputSystem 引用——检查发现 RuntimeInputCommand.cs 的所有 InputSystem 调用都在 #if ENABLE_INPUT_SYSTEM 保护内,没有 InputSystem 包也能编译(运行时返回 Unavailable)。

  3. 修改 manifest.json,添加三个包:

    "com.pipeline.unity2022": "file:com.pipeline.unity2022",
    "com.unity.pipeline": "file:com.unity.pipeline",
    "com.unity.nuget.mono-cecil": "1.11.6"
    

第三步:硬碰硬解决 Roslyn 问题(最深的坑)

编译后报了一堆 error CS0246: The type or namespace name 'SyntaxNode' could not be found

排查发现编译命令里 Microsoft.CodeAnalysis*.dll 被 Unity 的 Bee 编译器静默过滤掉了——只保留了 Newtonsoft.Json.dllUnsafe.dll。查证后确认:Unity 2022.3 的 Bee 构建系统硬编码排除用户提供的 Microsoft.CodeAnalysis 程序集(为了和它自带的 Roslyn 4.3.1 编译器不冲突)。

试了 isExplicitlyReferenced: 1 标记也不行,彻底确认这是引擎级限制,无法绕过。

解决方案:裁剪 Roslyn 依赖。 由于 Roslyn 只服务于 eval(动态执行 C#)和热重载(hot reload)这两个功能,而它们与我们的核心需求(触发编译 + 跑测试)无关,所以:

  • 删除 7 个 Roslyn 依赖文件(RoslynCompilationService.csEvalCodeCompiler.csHotReloadCompiler.cs、4 个 HotReload 处理文件)
  • eval / eval_file / reload_file / reload_file_override / cleanup_hotreload 命令改为返回明确的 "Not Supported" 结果(而不是神秘报错)
  • 从 asmdef 的 precompiledReferences 移除所有 Roslyn DLL 引用

经验:兼容旧版本引擎时,与其硬啃 API 差异,不如评估"被砍的功能是否核心"。砍掉边缘功能、保留核心,是更务实的策略。

第四步:修复 Unity 6 API 兼容问题

  • PhysicsMaterial → 用反射辅助方法解析 PhysicMaterial(2022.3 的正确类型):
    private static Type PhysicsMaterialType() => typeof(PhysicMaterial);
    
  • Material.rawRenderQueue → 改用 Material.renderQueue(2022.3 的 getter 行为一致,-1 表示继承 shader 队列)。

第五步:清 Bee 编译缓存

删掉 Roslyn DLL 后,报 error CS0006: Metadata file '.../System.Runtime.CompilerServices.Unsafe.dll' could not be found——这是 Bee 构建系统的增量缓存还引用着已删除的文件。删除 Library/Bee/artifacts 下所有 Unity.Pipeline* 缓存文件后解决。

第六步:修复 CmdFailure 参数错误

重写命令时,HotReloadResponse.CmdFailure() 需要 3 个参数(error, errorDetails, executionTimeMs),我漏传了第 3 个。补上后编译通过。


四、过程中遇到的"环境坑"

坑 1:运行 18 小时的编辑器不响应文件变更

Unity Editor 已经连续运行了 18 小时(PID 21996),修改 manifest.json 后它完全没有反应——文件系统监听失效。Asset 文件触碰、AppleScript 激活、Hub CLI 都不行。

最后发现:用户手动点击编辑器窗口就能触发重新编译。所以整个调试过程变成了"我改文件 → 请用户点一下编辑器 → 看日志 → 继续改"的循环。

经验:长时间运行的 Unity Editor 会进入"深度空闲"状态,外部文件变更不触发刷新。改包、改 manifest 这类操作,最好先让编辑器"醒"过来(点击窗口或重启)。

坑 2:unity open . 会截断 Editor 日志

调试过程中尝试 unity open . 想触发刷新,结果它启动了一个短暂的新实例,~/Library/Logs/Unity/Editor.log 截断重写了。原编辑器的日志被转移到 Editor-prev.log

经验:运行中编辑器,别用 unity open 去"唤醒"它,会弄丢主日志。

坑 3:域重载期间服务器短暂不可用

触发 recompile 后,Unity 会做 Domain Reload,Pipeline 服务器会短暂断开(连接被重置)。这是正常现象——[InitializeOnLoad] 会在重载后自动重启服务器。轮询 recompile_status 时遇到连接失败,重试即可。


五、最终效果(实测数据)

修复完成后,工具链完全可用:

验证项 结果
Pipeline 服务器 监听 127.0.0.1:7800
实例描述文件 Library/Pipeline/.unity-pipeline-port(含认证 token)✅
注册命令数 140 个
recompile 触发编译 {"status":"compiling"}
recompile_status 轮询结果 {"status":"completed","failed":false,"errors":[]}
list_tests / run_tests 正常列出/运行测试 ✅
get_scene_hierarchy 返回完整场景层级树 ✅
get_performance_stats 返回 draw calls / 内存 / 帧时间 ✅
get_console_logs / console 返回控制台日志(含编译警告)✅
set_autotick 已启用(16ms 间隔),失焦也能持续运行 ✅
认证 Bearer token(存于描述文件,权限 600)✅

实际调用方式(因为 unity CLI 的 command 子命令官方还没发布,直接用 HTTP):

TOKEN=$(python3 -c "import json,sys; print(json.load(open(sys.argv[1]))['evalToken'])" "Library/Pipeline/.unity-pipeline-port")
BASE="http://127.0.0.1:7800"

# 触发编译
curl -X POST -H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" \
  -d '{"command":"recompile","parameters":{}}' "$BASE/api/exec"

# 查询编译结果
curl -X POST -H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" \
  -d '{"command":"recompile_status","parameters":{}}' "$BASE/api/exec"
# → {"status":"completed","failed":false,"errors":[]}

六、这套工具链能做什么(使用场景)

场景 1:AI Agent 自动开发闭环 ⭐ 核心场景

AI 修改 C# 代码 → 触发 recompile → 拿到编译错误 → 继续修改 → 编译通过 → 跑测试 → 修复失败用例

完全自主,无需人工介入编辑器。这也是我们引入它的初衷。

场景 2:CI/CD 自动化

  • 提交代码后自动触发 recompile + run_tests
  • 失败时自动抓取 get_console_logs 的错误详情
  • 自动截图(capture_game_view)作为构建产物
  • 自动构建(build / switch_build_target

场景 3:测试与验证

  • list_tests / run_tests(EditMode + PlayMode,支持 filter 精确跑单个用例)
  • test_status 异步轮询,cancel_tests 中止
  • 测试失败后自动获取堆栈和日志

场景 4:场景与资源批量操作

  • get_scene_hierarchy 查看完整场景结构
  • create_gameobjects 批量创建对象(支持 positions/rotations 数组)
  • find_assets / create_asset / move_asset / rename_asset 资产管线
  • set_component_properties / set_serialized_field 改组件属性
  • Prefab 全套:create_prefab / instantiate_prefab / apply_prefab_overrides / unpack_prefab

场景 5:远程诊断

  • get_performance_stats:draw calls、内存、帧时间
  • console / get_console_logs:实时控制台
  • editor_play / editor_stop / editor_pause:远程控制 Play Mode
  • screenshot / capture_game_view / capture_scene_view:远程截图

场景 6:构建与烘焙(异步任务)

  • bake_lighting / bake_navmesh / bake_occlusion_culling + 对应 *_status 轮询
  • build / build_status / switch_build_target

场景 7:项目设置管理

  • 8 大设置域读写:Audio / Graphics / Physics / Player / Quality / Time / Tags & Layers / Input
  • 全部支持 dry_run + confirm 安全门

七、安全机制

这套工具默认带安全防护(对 AI Agent 自动化尤其重要):

  • Bearer token 认证:所有请求必须带令牌,令牌存于 Library/Pipeline/.unity-pipeline-port(权限 600)
  • 仅限本机回环:只监听 127.0.0.1,外部网络无法访问
  • 双保险写操作:所有写/删命令支持 dry_run(先验证不执行)+ confirm(显式确认)
# 先 dry_run 验证(不实际执行)
-d '{"command":"delete_asset","parameters":{"asset":"Assets/Foo.mat","dry_run":true}}'
# 确认后再真删
-d '{"command":"delete_asset","parameters":{"asset":"Assets/Foo.mat","confirm":true}}'

八、已知限制(2022.3 专属)

由于 Unity 2022.3 的 Bee 编译器硬性排除 Microsoft.CodeAnalysis,以下功能不可用(返回明确的 "Not Supported",非报错):

命令 功能 原因
eval / eval_file 动态执行 C# 需要 Roslyn 编译
reload_file / reload_file_override 热重载 需要 Roslyn
cleanup_hotreload 清理热重载 DLL 需要 Roslyn

这些功能在 Unity 6(6000.0)上是完整可用的。如果团队需要 eval / 热重载,升级到 Unity 6 是唯一路径。


九、配套的 Skill 规范

为了让 AI Agent 能规范地使用这套工具链,我们还更新了仓库的 unity-pipeline Skill.agents/skills/.claude/skills/ 双份同步),内容包括:

  • 连接方式(token 读取、端口、HTTP 调用格式)
  • 140 个命令的分类索引
  • 核心工作流(编译循环、测试循环)
  • 安全规范(dry_run → confirm 门控、执行后读回验证)
  • 明确标注不可用功能,避免 Agent 误用

这样任何新会话的 AI Agent 加载 skill 后,就能立即按规范驱动 Unity,无需重新摸索。


十、总结

这次修复的核心收获:

  1. 工具链的价值:把 Unity Editor 变成"可编程的自动化节点",AI Agent / CI 可以直接驱动它,实现编译-测试-改资源-打包的全自动闭环。
  2. 版本兼容的务实策略:旧引擎适配时,评估"被砍功能是否核心",砍边缘保核心,比硬啃 API 差异更高效。
  3. 工程排坑经验:Bee 缓存要清、域重载期间服务器会断、长时间运行的编辑器需要"唤醒"、unity open 会截断日志——这些坑都能省下大量排查时间。
  4. 安全设计值得借鉴:token 认证 + 回环绑定 + dry_run/confirm 门控,是给外部 Agent 开放编辑器控制权的正确姿势。

如果你们的项目也在做"AI 辅助开发"或"Unity 自动化测试/构建",这套工具链值得一试。


(本文记录了 ChaRestaurant 项目的真实修复过程。技术栈:Unity 2022.3.51f1c1 / com.unity.pipeline 0.3.1-exp.1.compat.2 / macOS)

posted @ 2026-09-14 11:28  鑫鑫哥Adam  阅读(2)  评论(0)    收藏  举报