ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

Unity MCP 中 refresh_unity 工具详解:资产库刷新、脚本编译与就绪等待机制

Unity MCP 中 refresh_unity 工具详解:资产库刷新、脚本编译与就绪等待机制 Unity MCP 中 refresh_unity 工具详解资产库刷新、脚本编译与就绪等待机制【免费下载链接】unity-mcpUnity MCP acts as a bridge between AI assistants and your Unity Editor. Give your LLM tools to manage assets, control scenes, edit scripts, and automate tasks within Unity.项目地址: https://gitcode.com/GitHub_Trending/un/unity-mcprefresh_unity是 Unity MCPMCPForUnity核心工具组core中负责**显式触发 Unity 资源导入Asset Database Refresh与脚本编译Script Compilation**的关键能力通常用于完成文件写入、资源落地、脚本编辑后的收尾动作。读完本文你将掌握该工具的完整参数语义、从 Python 服务端到 Unity 编辑器的底层调用链路、断连/重载场景下的容错恢复策略以及如何结合mcpforunity://editor/state资源做就绪等待从而在 AI 工作流中安全可靠地使用刷新能力。工具定位显式触发刷新与编译的副作用型工具Unity MCP 的绝大多数工具如manage_asset、manage_script只负责在编辑器中执行具体操作而refresh_unity专门承担事后同步职责请求 Unity 资产数据库重新导入并可选地触发一次脚本编译同时还可以阻塞等待编辑器恢复就绪状态。在 Unity 侧实现 的注释中它被明确标注为 side-effectful and should be treated as a tool具有副作用、应按工具对待并以[McpForUnityTool(refresh_unity, AutoRegister false)]声明——这意味着它不会在 Unity 端自动注册进工具列表而是由 Python 服务端在需要时通过 TCP 桥接显式下发refresh_unity命令。典型使用场景包括通过外部进程如 Agent、CI 或脚本向Assets/目录写入新资源后强制 Unity 重新导入修改脚本文件后请求CompilationPipeline触发一次显式编译在执行一系列变更后等待编辑器回到ready_for_tools状态再进行后续工具调用。参数详解mode / scope / compile / wait_for_ready根据 官方参考文档该文档由tools/generate_docs_reference.py从 Python 工具注册表自动生成工具的四个参数如下参数类型必填说明modeLiteral[if_dirty, force]否刷新模式仅在检测到变更时刷新或强制刷新scopeLiteral[assets, scripts, all]否刷新范围仅资产、仅脚本、全部compileLiteral[none, request]否是否请求编译不请求、请求一次编译wait_for_readybool否若为 true则等待mcpforunity://editor/state返回data.advice.ready_for_tools为 true各参数的默认值与底层语义从 服务端定义 可以看到实际默认值为modeif_dirty、scopeall、compilenone、wait_for_readyTrue。而 Unity 端处理 读取参数时的兜底默认值为modeif_dirty、scopeall、compilenone、wait_for_readyfalse——两者不一致意味着若客户端不传wait_for_ready服务端仍会自行执行一次防御性的就绪等待轮询详见下文服务端容错与恢复。modeif_dirty与force目前在实际执行上等价。Unity 侧代码注释明确指出 Best-effort semantics: if_dirty currently behaves like force unless future dirty signals are added即当前实现并未接入真正的脏标记信号两种模式都会触发刷新语义保留为向后兼容的扩展点。scopeassets执行AssetDatabase.Refresh(ForceUpdate | ForceSynchronousImport)scripts跳过重量级全量刷新For scripts, requesting compilation is usually the meaningful action把动作交给compile参数all先按上述逻辑处理若未触发刷新则补一次轻量级AssetDatabase.Refresh(ForceSynchronousImport)确保调用返回前刷新完成、避免 Unity 后台化时卡住。compilerequest时调用CompilationPipeline.RequestScriptCompilation()触发一次脚本编译与可能的 Domain Reload程序域重载。wait_for_ready控制是否等待编辑器就绪。等待逻辑在 Unity 端与 Python 端各有一层实现二者互为兜底。从服务端到编辑器的调用链路refresh_unity的完整执行链路分为 Python 服务端与 Unity 编辑器两端核心流程如下路由定位服务端通过get_unity_instance_from_context(ctx)从中间件状态中取出unity_instance由set_active_instance设置、UnityInstanceMiddleware注入确定命令要发往哪个 Unity 实例多实例场景支持。下发命令调用unity_transport.send_with_unity_instance(..., refresh_unity, params, retry_on_reloadFalse)。注意这里显式传入retry_on_reloadFalse——因为refresh_unity本身就会触发编译/重载若在重载时重试会引发多次重载代码注释引用 issue #577。Unity 端执行编辑器收到命令后在主线程执行刷新与编译见 RefreshUnity.HandleCommand。就绪等待若请求了等待Unity 端通过EditorApplication.update轮询EditorStateCache.GetActualIsCompiling()、EditorApplication.isUpdating、TestRunStatus.IsRunning、EditorApplication.isPlayingOrWillChangePlaymode四个条件全部满足才判定就绪Python 端则轮询mcpforunity://editor/state资源作为第二层保障。清理状态就绪恢复后服务端会调用external_changes_scanner.clear_dirty(inst)清除该实例的外部变更脏标记。调用关系示意MCP Client (LLM) │ tools/call refresh_unity ▼ Python Server: services/tools/refresh_unity.py │ TCP Bridge (send_with_unity_instance, retry_on_reloadFalse) ▼ Unity Editor: RefreshUnity.HandleCommand ├─ AssetDatabase.Refresh(...) ├─ CompilationPipeline.RequestScriptCompilation() └─ WaitForUnityReadyAsync (EditorApplication.update 轮询) ▼ 返回响应: refresh_triggered / compile_requested / resulting_state / hintUnity 端源码级行为细节测试运行时的安全保护进入处理逻辑前Unity 端会先检查TestRunStatus.IsRunning见 RefreshUnity.cs#L28-L35。若测试正在运行直接返回ErrorResponse(tests_running, { retry_after_ms 5000 })避免刷新/编译打断测试执行。刷新与编译的执行分支// MCPForUnity/Editor/Tools/RefreshUnity.cs节选 bool shouldRefresh mode is force or if_dirty; if (shouldRefresh) { if (scope scripts) { // 脚本范围跳过全量刷新编译才是关键动作 } else { AssetDatabase.Refresh(ImportAssetOptions.ForceUpdate | ImportAssetOptions.ForceSynchronousImport); refreshTriggered true; } } if (compile request) { CompilationPipeline.RequestScriptCompilation(); compileRequested true; } // scope all 且尚未刷新时补一次同步刷新 if (scope all !refreshTriggered) { AssetDatabase.Refresh(ImportAssetOptions.ForceSynchronousImport); refreshTriggered true; }关键点在于ForceSynchronousImport它保证刷新在命令返回前同步完成避免 Unity 后台化backgrounded时刷新被延迟导致调用方误判失败。Unity 6 的特殊处理Unity 端针对 Unity 6 及以上版本做了一处专门修复RefreshUnity.cs#L80-L89当compilerequest时跳过wait_for_ready等待。原因是 Unity 6 中EditorApplication.update轮询在 Domain Reload 后无法正确存活等待会引发无限编译循环。该场景下改为立即返回由客户端自行轮询editor_state。此行为仅通过#if UNITY_6000_0_OR_NEWER编译指令启用旧版本 Unity 保留原等待行为。等待就绪的实现WaitForUnityReadyAsync使用TaskCompletionSourcebool配合EditorApplication.update事件驱动而非阻塞式Thread.Sleep每个帧 tick 检查四个条件!EditorStateCache.GetActualIsCompiling()—— 使用真实编译中标记而非 Unity 的isCompiling避免误报源码注释引用 issue #549、#1276!EditorApplication.isUpdating—— 资产导入未在进行!TestRunStatus.IsRunning—— 测试未在运行!EditorApplication.isPlayingOrWillChangePlaymode—— 未处于播放模式切换。超时上限为DefaultWaitTimeoutSeconds 60秒超时抛出TimeoutException由外层转换为ErrorResponse(refresh_timeout_waiting_for_ready, ...)。返回结构与错误码成功后返回SuccessResponse(Refresh requested., ...)data字段如下字段说明refresh_triggered是否实际触发了资产刷新compile_requested是否请求了编译resulting_state返回瞬间的编辑器状态compiling/asset_import/idlehint后续操作指引如轮询 editor_state 直到 ready_for_tools可能的错误码包括tests_running测试运行中建议 5 秒后重试、refresh_failed: 异常信息、refresh_timeout_waiting_for_ready等待就绪超时、refresh_wait_failed: 异常信息。服务端容错与恢复把断连当作成功refresh_unity最大的工程难点在于触发编译会引发 Domain Reload导致 TCP 连接在命令执行中途断开。如果服务端把这种情况当作失败并让客户端重试就会造成多次重载。因此 refresh_unity.py 专门实现了断连恢复逻辑编译断连 预期成功当compilerequest且响应中出现connection closed/disconnected/abortedWinError 10053/timeout或reason reloading时服务端将其视为刷新已成功触发置recovered_from_disconnect True不再向客户端返回错误防止 Claude Code 等客户端盲目重试issue #577。可重试错误hint retry或could not connect时若wait_for_ready为 true 则进入等待循环否则原样返回。不可恢复错误与 Domain Reload 无关的连接错误直接返回原始错误响应。随后若wait_for_readyTrue服务端调用wait_for_editor_ready(ctx, timeout_s60.0)refresh_unity.py#L34-L61以 0.25 秒为间隔轮询editor_state.get_editor_state(ctx)直至data.advice.ready_for_tools为 true或 60 秒超时返回失败{timeout: True, wait_seconds: 60.0}。轮询期间任何读取异常都被吞掉继续轮询以对抗 Domain Reload 期间的瞬时连接错误。就绪恢复后还会执行最后一步清理调用external_changes_scanner.clear_dirty(inst)refresh_unity.py#L258-L264清除该实例的外部变更脏标记使后续工具能够干净地继续执行。该扫描器external_changes_scanner.py通过比较Assets/、ProjectSettings/、Packages/及Packages/manifest.json中file:本地依赖目录的最大 mtime 来感知外部变更。就绪判定标准editor_state 的 advice 机制wait_for_ready的判定依据来自mcpforunity://editor/state资源editor_state.py。服务端在组装状态快照时计算adviceready_for_toolsblocking_reasons为空时为 trueblocking_reasons可能包含compiling、domain_reload、running_tests、asset_refresh、stale_status状态超过 2 秒判定为过期recommended_retry_after_ms未就绪时为 500就绪时为 0。Python 端的wait_for_editor_ready使用_REAL_BLOCKING_REASONS {compiling, domain_reload, running_tests, asset_import}refresh_unity.py#L26过滤真正忙碌的原因——该集合与 EditorStateCache.cs 中activityPhase的取值running_tests、compiling、domain_reload、asset_import、playmode_transition、idle一一对应避免把stale_status这类陈旧状态误判为阻塞。典型调用示例以下为通过 MCP 客户端向服务端发起调用的 JSON-RPC 请求示例{ jsonrpc: 2.0, id: 1, method: tools/call, params: { name: refresh_unity, arguments: { mode: force, scope: all, compile: none, wait_for_ready: true } } }成功响应示例resulting_state为返回瞬间的编辑器状态{ success: true, message: Refresh requested., data: { refresh_triggered: true, compile_requested: false, resulting_state: idle, hint: Unity refresh completed; editor should be ready. } }若compilerequest且处于 Unity 6hint会提示客户端If Unity enters compilation/domain reload, poll the mcpforunity://editor/state resource until data.advice.ready_for_tools is true.推荐实践修改脚本后使用{compile: request, wait_for_ready: true}外部写入资源文件后使用{mode: force, scope: assets}需要等待编辑器的场景务必开启wait_for_ready并在 Unity 6 下做好客户端侧轮询兜底。测试验证与注册机制仓库为refresh_unity提供了两层集成测试test_refresh_unity_registration.py验证mcp_for_unity_tool装饰器正确注册了名为refresh_unity的工具red test 风格要求显式刷新工具存在。test_refresh_unity_retry_recovery.py模拟 Unity 断开连接且传输层返回hintretry的场景验证refresh_unity(wait_for_readyTrue)会轮询就绪、返回successTrue且data.recovered_from_disconnect True并清除了external_changes_scanner中的脏标记。工具注册走services.tools.__init__.py的register_all_tools自动发现机制任何位于tools/目录下、带mcp_for_unity_tool装饰器的模块都会被自动扫描注册Server/src/services/tools/init.py随后套上log_execution、telemetry_tool装饰器后注册进 FastMCP。总结refresh_unity是 Unity MCP 中连接变更操作与编辑器同步的收尾工具其工程价值体现在三层设计上语义分层mode刷不刷、scope刷什么、compile编不编、wait_for_ready等不等四个正交维度覆盖从轻量资源刷新到完整刷新编译等待就绪的全部需求容错设计把 Domain Reload 断连视为预期成功、禁止重载期重试、双端就绪等待互为兜底保证 AI 工作流不会因连接中断而误判失败或重复触发编译状态联动与mcpforunity://editor/state资源的advice.ready_for_tools机制深度耦合为客户端提供可轮询、可验证的编辑器就绪判定标准。理解这些细节后你便能在自己的 Unity MCP 自动化流程中准确编排资源导入、脚本编译与就绪等待避免常见的刷新后立刻操作导致失败或编译触发后反复重载等问题。【免费下载链接】unity-mcpUnity MCP acts as a bridge between AI assistants and your Unity Editor. Give your LLM tools to manage assets, control scenes, edit scripts, and automate tasks within Unity.项目地址: https://gitcode.com/GitHub_Trending/un/unity-mcp创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进