Files
mcp-bridge/docs/注意事项.md
火焰库拉 a618497028 新增 find_references 引用查找工具及 Texture2D 子资源自动解析
- 新增 find-references IPC 处理函数,递归遍历场景节点组件属性查找引用

- 新增 UUID 格式自动规范化(压缩/解压格式全量匹配)

- 新增 Texture2D -> SpriteFrame 子资源 UUID 自动解析

- 更新 UPDATE_LOG.md、注意事项.md、README.md 文档
2026-03-01 00:32:59 +08:00

12 KiB
Raw Blame History

Cocos Creator 插件开发注意事项

1. 资源与预制体管理

1.1 禁止手动干预 .meta 文件

  • 问题:手动使用 manage_asset 创建或修改以 .meta 结尾的文件会导致编辑器报错(如 Invalid assetpath, must not use .meta as suffix)。
  • 原因Cocos Creator 资源数据库会自动识别新资源并生成对应的 .meta 文件。外部强行介入会破坏资源索引一致性。
  • 最佳实践:始终使用高级资源工具(如 prefab_management)来处理资源,让编辑器自行管理 .meta 文件。

1.2 预制体的正确创建流程

  • 推荐工具:使用 prefab_managementcreate 操作,或 create_prefab 工具。
  • 核心逻辑该工具会同步处理节点的序列化、db 路径映射以及资源刷新Refresh确保预制体及其配套的 .meta 文件原子化生成。
  • ⚠️ IPC 签名要点:底层使用的 scene:create-prefab 消息有严格的参数格式要求:
    1. 必须使用 Editor.Ipc.sendToPanel("scene", ...) 而非 sendToMain(该消息由 Scene 面板渲染进程处理)。
    2. 节点 ID 必须包裹在数组中:[nodeId]
    3. 第二个参数必须是 db:// 目录路径(如 db://assets),而非完整文件路径。
    4. 预制体文件名取决于节点名称,因此创建前需先通过 scene:set-property 重命名节点。

2. 脚本属性Inspector关联

2.1 路径与 UUID 的区别

  • 问题:在 Inspector 面板中,脚本属性(如 cc.Prefabcc.Node)若通过路径关联,经常会出现 "Type Error"。
  • 原因:编辑器 Inspector 期望获得的是引擎内部的对象引用。虽然 db:// 路径可以指向文件,但在属性赋值层面,编辑器无法自动将字符串路径转换为对应的类实例。
  • 最佳实践
    1. 通过 manage_asset -> get_info 获取资源的 UUID
    2. 在调用 manage_components -> update 时,优先使用 UUID 进行赋值。
    3. UUID 是底层唯一标识,能确保编辑器精准识别资源类型并正确完成引用链接。

3. 场景同步与编辑器状态

3.1 刷新与编译

  • 注意事项:创建新脚本后,必须调用 manage_editor -> refresh_editor 或等待几秒钟以触发编译。
  • 风险:在脚本编译完成前尝试将其作为组件添加到节点,会导致 添加组件失败: Cannot read property 'constructor' of null 或找不到脚本组件的问题。

3.2 节点删除 (IPC 协议)

  • 正确协议:应使用 Editor.Ipc.sendToMain('scene:delete-nodes', uuid_or_array)
  • 注意:不要误用 scene:delete-selected,因为它在某些版本的编辑器底层不接受参数或行为不一致。
  • 技巧:在 mcp-bridge 中,调用 execute_menu_item("delete-node:NODE_UUID") 会走场景脚本的直连删除,而 execute_menu_item("Delete") 则会走主进程的 scene:delete-nodes 并自动带上选中的节点。

4. MCP Bridge 源码补丁说明

4.1 属性解析增强 (Asset 序列化修复)

  • 改进点:在 scene-script.jsapplyProperties 中通过 cc.AssetLibrary.loadAsset 解决了资源属性在 Inspector 报错 "Type Error" 的问题。
  • 原理
    • 问题根源:在场景进程中直接将 UUID 字符串赋给资源属性(如 comp.prefab = "uuid"),会导致 .fire 文件将其保存为纯字符串而非对象格式。编辑器 Inspector 期望的是资源引用结构 { "__uuid__": "..." },类型不匹配产生 Type Error。
    • 修复逻辑
      1. 真实加载:使用 cc.AssetLibrary.loadAsset(uuid, callback) 在场景进程中异步加载真实的资源实例。
      2. 实例赋值:在回调中将加载到的 asset 对象赋予组件(component[key] = asset),这确保了场景保存时能生成正确的序列化对象。
      3. UI 同步:同步发送 IPC scene:set-property,使用 { uuid: value } 格式通知编辑器面板更新 Inspector UI。
    • Node/Component: 对于节点 or 组件引用,通过 findNode 查找实例并直接赋值实例对象,而非 UUID 字符串。

5. AI 操作安全守则 (Subject Validation Rule)

5.1 确定性优先

  • 核心法则:任何对节点、组件、属性的操作,都必须建立在 “主体已确认存在” 的基础上。
  • 具体流程
    1. 节点校验:在操作前必须调用 get_scene_hierarchy 确认 nodeId
    2. 组件校验:在 updateremove 前必须调用 manage_components(action: 'get') 确认目标组件存在。
    3. 属性校验:严禁猜测属性名。在 update 前,应通过读取脚本定义或 get 返回的现有属性列表来确定准确的属性名称。
  • 禁止行为:禁止基于假设进行盲目赋值或删除。如果发现对象不存在,应立即报错或尝试重建,而非继续尝试修改。

5.2 传参精准与别名容错

  • 传参风险:大语言模型在生成 JSON 时可能会出现操作类型字段名“幻觉”(例如在调用 manage_components 时将本应是 action 的参数写为含义相近的 operation)。
  • 优化机制:底层脚本 (scene-script.js) 已经全面引入参数别名回落机制(如 action = action || operation)。
  • 提示开发:尽管底层具备一定的容错率,在维护 MCP 工具说明书Schema仍应严格要求 AI 书写标准参数名,避免纵容产生更大的幻觉偏移。

6. 常见资源关键字

  • 资产识别启发式:当通过 manage_components 赋值时,如果属性名包含以下关键字,插件会尝试将其作为 UUID 资源处理: prefab, sprite, texture, material, skeleton, spine, atlas, font, audio, data
  • 建议:如果资源未正确加载,请检查属性名是否包含以上关键字,或手动确认该 UUID 不属于任何节点。

7. 搜索工具 (search_project) 使用建议

  • 性能建议:尽量指定 path 参数缩小搜索范围(如 db://assets/scripts),避免全项目大面积搜索,尤其是在包含大量旧资源的 Library 目录(虽然插件已过滤)。
  • 正则表达式:在使用 useRegex 时,确保正则模式的语法正确。如果正则匹配失败,工具会返回详细的错误提示。
  • 模式选择
    • 查找具体逻辑代码:使用 matchType: "content"
    • 定位资源文件:使用 matchType: "file_name" 并配合 extensions 过滤。
    • 重构目录结构前:使用 matchType: "dir_name" 检查目录名冲突。

8. Undo/Redo (撤销/重做) 使用指南

8.1 事务分组

  • 背景:连续执行多次修改(如同时移动并缩放)时,通常希望一次“撤销”能回滚所有更改。
  • 最佳实践
    1. 调用 manage_undo(action: 'begin_group', description: '操作描述')
    2. 执行多次修改(如调用 update_node_transform)。
    3. 调用 manage_undo(action: 'end_group')
  • 注意undo-record 需要在 begin_group 时明确关联节点 ID否则可能导致撤销栈无法精准匹配对象。

8.2 属性修改方式

  • 核心规则:在 scene-script.js 中严禁直接使用 node.x = 100
  • 正确做法:必须通过 Editor.Ipc.sendToPanel('scene', 'scene:set-property', ...)。只有这样,修改才会被 Cocos Creator 的 UndoManager 捕获,从而支持撤销。

9. 并发安全与防卡死机制

9.1 指令队列 (CommandQueue)

  • 背景AI 客户端可能在短时间内连续发送多个 MCP 请求(如 delete-noderefresh_editorsearch_project),如果并发执行,AssetDB.refresh() 等异步重操作会与后续请求产生 I/O 和 IPC 通道冲突,导致编辑器主线程阻塞。
  • 解决方案:在 /call-tool HTTP 入口处引入 enqueueCommand 机制,将所有 MCP 工具调用串行化执行。前一个指令的回调完成后,才会出队并处理下一个指令。
  • 注意事项
    1. 队列在 processNextCommandcatch 块中有防死锁保护,即使某个指令抛出异常也不会永久阻塞后续指令。
    2. batchExecute 内部也已从并行 forEach 改为串行链式执行。
    3. 队列长度会在日志中显示(REQ -> [toolName] (队列长度: N)),可用于排查积压问题。

9.2 refresh_editor 路径要求

  • ⚠️ 必须带路径:在调用 manage_editorrefresh_editor 时,务必通过 properties.path 指定精确的文件或目录(如 db://assets/scripts/Test.ts)。严禁空参数进行全局刷新,在生产项目中会导致数分钟的编辑器卡死。

9.3 IPC 超时保护 (callSceneScriptWithTimeout)

  • 背景Editor.Scene.callSceneScript 的回调依赖 Scene 面板响应 IPC 消息。如果主线程阻塞Scene 面板无法处理消息,导致 callback 永远不返回HTTP 连接堆积。
  • 解决方案:所有 callSceneScript 调用均通过 callSceneScriptWithTimeout 包装,默认 15 秒超时。超时后自动返回错误,释放 HTTP 连接和队列位置。
  • 日志标识:超时会记录 [超时] callSceneScript "方法名" 超过 15000ms 未响应

10. Token 消耗与长数据保护防爆机制

10.1 get_scene_hierarchy 深度与层级限制

  • 背景:在一两千个节点的大型 UI 场景中,无限制地获取全场景树会瞬间消耗十万以上的 Token导致 AI 丢失上下文甚至触发截断报错。
  • 最佳实践
    • 默认使用 depth: 2 (默认限制) 来逐步探查。
    • 结合 nodeId 参数:找到关键模块(例如 Canvas/LoginPanel)的 UUID 后,再单独向该 nodeId 请求下一层的结构,而非每次从根部拉取。

10.2 大对象与长数组截断

  • 背景在读取某些特定组件数据如多边形顶点坐标、Sprite 曲线数据或序列化的内联 Base64 图片JSON 可能会异常庞大。
  • 保护机制
    • scene-script.js 内部在执行 manage_components(get) 序列化时,对于长度超过 10 的 Array 会强制截断,返回字面量字符串 "[Array(X)]"
    • 对于长度大于 200 的长字符串,也会强制缩略并追加 ...[Truncated, total length: X]
  • 应对策略:如果 AI 看到截断提示,这意味着此处为海量无语义数据,请勿尝试盲目通过 update 覆盖或还原被截断的字段,极易导致源数据被破坏。请仅修改自己能够完全看清的轻量级属性(如 name, x, scale 等)。

11. 引用查找 (find_references) 与 UUID 自动解析

11.1 引用查找工具用途

  • 功能: find_references 工具可查找当前场景中所有引用了指定节点或资源的位置,返回引用所在节点、组件类型、属性名等详细信息。
  • 应用场景:
    • 删除节点或预制体前,检查是否有组件属性引用了它,防止脚本报错。
    • 替换资源(如更换 SpriteFrame快速定位所有使用了旧资源的组件。
    • 分析场景依赖关系,辅助重构。

11.2 UUID 格式差异与自动规范化

  • 背景: Cocos Creator 2.x 中 cc.Asset._uuid 使用 22 位压缩 UUID 格式,而 Editor.assetdb 返回标准 36 位带连字符 UUID同一资源的两种表示在字符串层面不相等。
  • 机制: find-references 处理函数通过 Editor.Utils.UuidUtils.compressUuid/decompressUuid 自动预计算所有格式变体,存入 targetVariants 数组进行全量匹配。无需人工关心 UUID 格式。

11.3 Texture2D 与 SpriteFrame 子资源解析

  • 问题: AI 传入图片 (Texture2D) 的 UUID 时,cc.Sprite.spriteFrame 实际引用的是该图片的子资源 SpriteFrame具有不同的 UUID导致直接查找返回空结果。
  • 解决方案: main.js 在调用 scene-script 前,自动读取目标 UUID 对应的 .meta 文件,提取 subMetas 中所有子资源 UUID作为 additionalIds 一并传递。scene-script 对这些额外 UUID 同样执行压缩/解压规范化后加入匹配列表。
  • 效果: 无论传入 Texture2D UUID 还是 SpriteFrame UUIDfind_references 均能正确返回所有引用位置。