ET UnityBridge 实战指南:用命令行让 AI 操作 Unity Editor 的全链路解析
2026/9/16 16:02:04 网站建设 项目流程

ET UnityBridge 实战指南:用命令行让 AI 操作 Unity Editor 的全链路解析

【免费下载链接】ETUnity3D Client And C# Server Framework项目地址: https://gitcode.com/GitHub_Trending/et/ET

导读

UnityBridge 是 ET 框架中连接「AI / 命令行工具」与「Unity Editor」的本地文件桥接模块:它由一个纯 .NET 命令行程序(ET.UnityBridge.dll)和驻留在 Unity Editor 中的文件宿主组成,让 Agent 无需点击 GUI 即可查询 Unity 编译/PlayMode 状态、操作资源与场景、执行编译热重载、运行 Editor 测试。本文以 SKILL.md 为骨架,结合 CLI 参考、AI 操作参考 及源码实现,完整讲解桥接原理、命令发现、任务路由、deferred 命令等待与错误排查,读完即可在 ET 工程中驱动 AI 安全、省 Token 地操作 Unity。

UnityBridge 是什么:一个纯命令行的 Unity 操作入口

UnityBridge 是 ET 的「Unity 本地文件桥接包」(位于 Packages/cn.etetet.unitybridge),由三部分构成(见 AGENTS.md):

目录作用
DotNet~纯命令行程序ET.UnityBridge(CLI 入口)
Scripts/EditorUnity Editor 侧的文件宿主、命令处理器与分发逻辑
Scripts/Model/Share桥接命令、错误码、路径与文件存储协议

它的核心价值在于:AI 通过一行dotnet命令即可操作 Unity Editor,覆盖资源、场景、选择集、GameObject、Transform、Inspector、Prefab、菜单、截图、GameView、Editor 测试等场景,以及Compile/Refresh/RegenProject/EnterPlay/ExitPlay/Reload等会跨越 Unity 状态变化的命令,并可直接排查桥接返回的Error/Message

桥接工作原理:文件即协议

UnityBridge 不依赖网络端口,而是以本地目录作为请求/响应的「信箱」,其路径解析与文件协议实现在 UnityBridgeStorage.cs:

  • 桥接根目录解析优先级:显式--root参数 > 环境变量ET_UNITY_BRIDGE_ROOT> 默认Temp/UnityBridge(见UnityBridgePathHelper.ResolveRoot)。
  • 目录结构requests/(待处理请求)、processing/(正在处理)、responses/(已写回的响应)、deadletter/(解析失败的死信)、state/idempotency/(幂等响应缓存)、state/pending-command.json(deferred 命令持久化状态)。
  • 写入方式UnityBridgeFileStore.WriteTextAtomic采用「先写.tmp再改名」的原子替换,避免半写文件被对端读到。

Editor 侧宿主UnityBridgeEditorHost(UnityBridgeEditorHost.cs)以[InitializeOnLoad]挂载到EditorApplication.update,每 0.2 秒轮询一次requests/目录,取出请求 → 反序列化为命令 → 交给UnityBridgeEditorDispatcher分发 → 写回响应。因此整个链路是:CLI 写请求文件 → Editor 轮询处理 → CLI 读到响应文件

何时使用与何时不要加载

SKILL 文档明确划定了适用范围,Agent 需要据此决定是否加载本技能:

应该使用:查询宿主是否在线、Unity 是否在编译、PlayMode 状态、CodeMode、Unity 版本;让 AI 操作 Unity Editor 的各类资源/场景/对象;执行Compile/Refresh/RegenProject/EnterPlay/ExitPlay/Reload等跨状态命令;排查桥接返回的Error/Message

不要加载:只是普通 C# 编译(应走et-build)、只是读写 Excel 或导出 Luban、只是纯代码结构分析(不需要 Unity 参与)、只是要解释命令协议而不实际操作 Unity(此时应只读 proto 或 handler,不要启动 UnityBridge)。

快速上手:最小流程

1. 确认 CLI 可执行

CLI 入口为:

dotnet ./Bin/ET.UnityBridge.dll
  • 默认桥接根目录:优先读取环境变量ET_UNITY_BRIDGE_ROOT;未设置时默认Temp/UnityBridge;也可用--root <路径>显式指定。
  • Bin/ET.UnityBridge.dll尚不存在,先用et-build编译确认工具是否生成。构建产物路径由 ET.UnityBridge.csproj 的OutputPath决定(Debug/Release 均输出到仓库根的Bin目录),目标框架为net10.0

2. 发送第一个 Ping

dotnet ./Bin/ET.UnityBridge.dll '{"_t":"Ping"}'
dotnet ./Bin/ET.UnityBridge.dll '{"_t":"Ping"}' --root "Temp/UnityBridge"

Ping用来判断 UnityBridge 宿主是否在线、获取响应时间,以及读取IsCompiling/IsPlaying/IsPlayingOrWillChangePlaymode/CodeMode/UnityVersion。对应的处理器实现在 UnityBridgePingHandler.cs,其中IsCompiling/IsPlaying/IsPlayingOrWillChangePlaymode直接取自EditorApplicationUnityVersion取自Application.unityVersion

3. 需要命令列表时查询 HostState

dotnet ./Bin/ET.UnityBridge.dll '{"_t":"HostState"}'

HostStatePing信息的基础上额外返回AvailableCommands(由 UnityBridgeQueryHostStateHandler.cs 通过UnityBridgeEditorDispatcher.GetAvailableCommandTypes()汇总),因此按任务选择最小命令执行,失败时先看Error/Message,再读对应 handler。

命令发现:不要整包读,先 HostState 再 rg

省 Token 的关键是「按需发现命令」:

  1. 先用HostState看当前可用命令;
  2. 需要字段格式时用rg只查对应 proto 小片段:
rg -n "^message .*Request|^message (Ping|HostState|Compile|Refresh|RegenProject|EnterPlay|ExitPlay|Reload)\b" ./Packages/cn.etetet.unitybridge/Proto
  1. 需要行为细节时再查 handler:
rg -n "class UnityBridge.*Handler|AUnityBridgeDeferredHandler" ./Packages/cn.etetet.unitybridge/Scripts/Editor/Share

协议定义集中在 UnityBridge_C_11100.proto(基础命令与对象/资产/场景消息)与同目录的UnityBridge_C_11400.proto(其余命令族)。例如Ping/PingResponse的结构(ErrorMessageTimeIsCompilingIsPlayingCodeModeUnityVersion等字段)与HostStateResponse.AvailableCommandsUnityTestRunResponse.Matched/Passed/FailedAssetFindResponse.TotalFound/Returned等,均可从 proto 中直接确认。

任务路由:先读状态,再执行动作

来自 et-unitybridge-ai-ops.md 的完整任务路由表,是 AI 操作 Unity 的「地图」:

目标优先命令族常见前置
状态/连通性Ping,HostState,EditorGetStateRequest
编译/刷新Compile,Refresh,RegenProject,AssetRefreshRequest,AssetImportRequestIsCompiling == false
PlayMode/热重载EnterPlay,ExitPlay,Reload,EditorPauseRequest检查IsPlaying/IsPlayingOrWillChangePlaymode
资源AssetSearchRequest,AssetFindRequest,AssetLoadRequest,AssetReadTextRequest,AssetGetPathRequest先限定 filter/path/count
场景SceneGetHierarchyRequest,SceneGetActiveRequest,SceneLoadRequest,SceneSaveRequest,SceneNewRequest写操作前确认当前场景
选择集SelectionGetRequest,SelectionSetRequest,SelectionAddRequest,SelectionRemoveRequest,SelectionClearRequest先读当前 selection
对象/TransformGameObject*Request,Transform*RequestFind/GetInfo/Get
InspectorInspectorGet*Request,InspectorSet*Request,InspectorAddComponentRequest,InspectorRemoveComponentRequest先读组件和属性名
PrefabPrefabInstantiateRequest,PrefabSaveRequest,PrefabApplyRequest,PrefabGet*Request,PrefabUnpackRequest先确认 asset path / instance
截图/GameViewScreenshotCaptureRequest,GameView*Request先读分辨率
测试UnityTestRunRequest用精确正则
批量BatchExecuteRequest先单步验证

以资源查询为例,先小范围查、不要全项目大结果:

dotnet ./Bin/ET.UnityBridge.dll '{"_t":"AssetFindRequest","Filter":"t:Prefab","MaxResults":10}'

AssetFindRequestFilter(如t:Prefab)、SearchInFoldersMaxResultsFormat字段定义见 proto,其路径归一化与返回逻辑可查UnityBridgeAssetFindHandler.cs。场景对象操作则先读层级:

dotnet ./Bin/ET.UnityBridge.dll '{"_t":"SceneGetHierarchyRequest","Depth":2,"IncludeInactive":false}'

写操作后用GameObjectGetInfoRequestTransformGetRequest验证,不要只相信命令成功。改 Inspector 时先读组件与属性名,再使用 set 命令,不要猜测SerializedProperty路径:

dotnet ./Bin/ET.UnityBridge.dll '{"_t":"InspectorGetComponentsRequest","Path":"<HierarchyPath>"}'

常用命令与传输参数

来自 et-unitybridge-cli.md 的常用命令一览:

dotnet ./Bin/ET.UnityBridge.dll '{"_t":"Ping"}' dotnet ./Bin/ET.UnityBridge.dll '{"_t":"HostState"}' dotnet ./Bin/ET.UnityBridge.dll '{"_t":"Compile"}' dotnet ./Bin/ET.UnityBridge.dll '{"_t":"Refresh"}' dotnet ./Bin/ET.UnityBridge.dll '{"_t":"RegenProject"}' dotnet ./Bin/ET.UnityBridge.dll '{"_t":"EnterPlay"}' dotnet ./Bin/ET.UnityBridge.dll '{"_t":"ExitPlay"}' dotnet ./Bin/ET.UnityBridge.dll '{"_t":"Reload"}'

支持的传输参数(由 Program.cs 中的TransportOptions解析):

参数说明默认值
--root <路径>显式指定桥接根目录环境变量ET_UNITY_BRIDGE_ROOT,否则Temp/UnityBridge
--waitMs <毫秒>CLI 等待最终响应的最大时长15000DefaultWaitMs
--timeoutMs <毫秒>请求在 Editor 侧的超时(<=0时按命令类型取默认)0,由宿主按命令回退
--idempotencyKey <字符串>幂等键,重复请求命中缓存直接返回上次响应未提供时自动生成 GUID

其中--timeoutMs的「按命令回退」逻辑在 UnityBridgeEditorHost.cs 的ResolveTimeoutMs中:Compile为 180000ms,Refresh/RegenProject/EnterPlay/ExitPlay为 60000ms,其余命令为 10000ms。CLI 侧还内置了 deferred 自动延长机制:未显式指定--waitMs时,若检测到pending-command.json中存在本请求的 RpcId,等待期限会自动延长至DefaultDeferredWaitMs = 185000,确保Compile等长耗时命令能拿到最终响应。

带完整参数的示例:

dotnet ./Bin/ET.UnityBridge.dll '{"_t":"HostState"}' --root "Temp/UnityBridge" --waitMs 15000 --timeoutMs 10000 --idempotencyKey "host-state-check"

deferred 命令:必须等到最终响应

CompileRefreshRegenProjectEnterPlayExitPlayAssetImportRequestAssetRefreshRequest等是deferred(延迟)命令——它们会先返回「请求已接收」,真正的工作在 Unity 主循环中分帧完成。因此必须等待最终响应,不要看到请求已接收就结束

其底层机制在 AUnityBridgeDeferredHandler.cs:deferred handler 在首次执行时抛出UnityBridgeDeferredStartedException并返回 deferred 响应;Editor 侧通过UnityBridgeDeferredRuntime.TryPumpEditorApplication.update中持续恢复执行(Run(command, UnityBridgeDeferredContext.CreateResume(startedAt))),直到产出最终响应或抛出UnityBridgeCommandStateException(此时返回对应错误码)。以Refresh为例,UnityBridgeRefreshHandler.cs 会等条件满足后执行AssetDatabase.Refresh(ImportAssetOptions.ForceUpdate)deferred.Started<RefreshResponse>()

推荐的执行顺序:

  • 编译前:HostState -> Compile
  • 刷新前:HostState -> Refresh
  • 重建工程文件:HostState -> RegenProject
  • 进播放前:确认IsCompiling == falseIsPlayingOrWillChangePlaymode == false,再EnterPlay
  • 热重载前:确认IsPlaying == true,再Reload
  • 退播放前:HostState -> ExitPlay

实时等待的正确姿势:

  1. 先执行PingHostState
  2. IsCompiling == true,持续轮询直到编译结束;
  3. 再发Compile/EnterPlay/Reload/ExitPlay等正式命令;
  4. deferred 命令必须读取最终响应。

响应解读:Error 为 0 才是成功

  • Error == 0表示成功;非 0 表示失败,结合Message判断原因。
  • CompileResponse额外包含DurationMs(编译耗时)。
  • EnterPlayResponse/ExitPlayResponse额外包含IsPlaying
  • PingResponse额外包含TimeIsCompilingIsPlayingIsPlayingOrWillChangePlaymodeCodeModeUnityVersion
  • HostStateResponse额外包含AvailableCommands

向用户汇报时只总结ErrorMessage和关键字段,不要把完整 JSON 响应贴给用户。写操作后说明如何验证,必要时直接执行验证命令。

跑 Editor 测试

使用精确正则,避免全量跑:

dotnet ./Bin/ET.UnityBridge.dll '{"_t":"UnityTestRunRequest","Name":"^Unitybridge_DeferredHandlerRunContext_Test$"}'

判定:Error == 0Matched > 0Failed == 0。其实现见 UnityBridgeUnityTestRunHandler.cs:通过TestDispatcher按正则匹配ET.Core/ET.Loader/ET.Model/ET.ModelView/ET.Editor/ET.Hotfix/ET.HotfixView程序集中的测试用例并逐条执行,最终汇总Matched/Passed/Failed与总耗时。仓库中同名测试(如Unitybridge_DeferredHandlerRunContext_Test.cs)即用于验证 deferred 运行上下文。

常见错误与排查

CLI 与参考文档列出的高频错误及其含义:

  • wait unity bridge response timeout:Unity 未打开、项目未加载完、桥接根目录不一致,或 Editor 未处理请求。排查顺序:先检查 Unity 是否已打开项目、心跳文件是否存在、桥接根目录是否一致。
  • unity is compiling:Unity 正在编译,暂时不能开始新的延迟命令。先轮询Ping,等IsCompiling == false后重试。
  • unity already in playmode or changing playmode:不能再次执行EnterPlay
  • unity not in playmode:执行ExitPlayReload的前置条件不满足。
  • handler is missing:先HostState确认可用命令,再查 proto 名是否写错。
  • execute menu item failed:菜单路径不存在,或 Unity 当前状态不允许执行。

对应的错误码定义集中在 ErrorCode.cs:Success = 0,并区分TimeoutNotInPlayModeAlreadyInPlayModeCompilingHandlerFailInvalidCommandLine等,便于程序化处理。

省 Token 操作守则

SKILL 与两份参考文档反复强调的 AI 操作纪律,值得作为长期协作约定:

  • 不要完整读取所有 UnityBridge proto、handler 或AvailableCommands
  • 先用HostStaterg发现命令名,再只打开相关 proto 小片段和对应 handler;
  • 先执行最小读命令确认目标,再做写操作;批量操作前先验证 1 个样本(BatchExecuteRequest先单步验证);
  • 不要把完整 JSON 响应贴给用户,只总结ErrorMessage和关键字段;
  • 优先 UnityBridge 命令,不要用 GUI 点击 Unity Editor,除非命令缺失或用户明确要求;如果 UnityBridge 不可用,说明原因和下一步,不回退到 GUI 点击。

小结

UnityBridge 以「文件即协议」的本地桥接设计,为 ET 工程提供了稳定、可脚本化、对 AI 友好的 Unity 操作入口。掌握「HostState 发现命令 → 最小读命令确认 → deferred 命令等待最终响应 → 按 Error/Message 排查」这条主线,即可让 AI 在零 GUI 依赖的前提下完成从编译热重载到场景搭建、从 Inspector 调参到 Editor 测试的全流程自动化操作。进一步深入可阅读 SKILL.md、CLI 参考、AI 操作参考,以及 Proto 协议 和 Editor 宿主实现。

【免费下载链接】ETUnity3D Client And C# Server Framework项目地址: https://gitcode.com/GitHub_Trending/et/ET

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询