2026-02-10 00:38:38 +08:00
|
|
|
|
# Cocos Creator 插件开发注意事项
|
|
|
|
|
|
|
|
|
|
|
|
## 1. 资源与预制体管理
|
|
|
|
|
|
|
|
|
|
|
|
### 1.1 禁止手动干预 `.meta` 文件
|
2026-02-12 22:55:08 +08:00
|
|
|
|
|
|
|
|
|
|
- **问题**:手动使用 `manage_asset` 创建或修改以 `.meta` 结尾的文件会导致编辑器报错(如 `Invalid assetpath, must not use .meta as suffix`)。
|
|
|
|
|
|
- **原因**:Cocos Creator 资源数据库会自动识别新资源并生成对应的 `.meta` 文件。外部强行介入会破坏资源索引一致性。
|
|
|
|
|
|
- **最佳实践**:始终使用高级资源工具(如 `prefab_management`)来处理资源,让编辑器自行管理 `.meta` 文件。
|
2026-02-10 00:38:38 +08:00
|
|
|
|
|
|
|
|
|
|
### 1.2 预制体的正确创建流程
|
2026-02-12 22:55:08 +08:00
|
|
|
|
|
2026-02-28 23:07:04 +08:00
|
|
|
|
- **推荐工具**:使用 `prefab_management` 的 `create` 操作,或 `create_prefab` 工具。
|
2026-02-12 22:55:08 +08:00
|
|
|
|
- **核心逻辑**:该工具会同步处理节点的序列化、db 路径映射以及资源刷新(Refresh),确保预制体及其配套的 `.meta` 文件原子化生成。
|
2026-02-28 23:07:04 +08:00
|
|
|
|
- **⚠️ IPC 签名要点**:底层使用的 `scene:create-prefab` 消息有严格的参数格式要求:
|
|
|
|
|
|
1. 必须使用 `Editor.Ipc.sendToPanel("scene", ...)` 而非 `sendToMain`(该消息由 Scene 面板渲染进程处理)。
|
|
|
|
|
|
2. 节点 ID 必须包裹在**数组**中:`[nodeId]`。
|
|
|
|
|
|
3. 第二个参数必须是 **db:// 目录路径**(如 `db://assets`),而非完整文件路径。
|
|
|
|
|
|
4. 预制体文件名取决于节点名称,因此创建前需先通过 `scene:set-property` 重命名节点。
|
2026-02-10 00:38:38 +08:00
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
|
|
## 2. 脚本属性(Inspector)关联
|
|
|
|
|
|
|
|
|
|
|
|
### 2.1 路径与 UUID 的区别
|
2026-02-12 22:55:08 +08:00
|
|
|
|
|
|
|
|
|
|
- **问题**:在 Inspector 面板中,脚本属性(如 `cc.Prefab` 或 `cc.Node`)若通过路径关联,经常会出现 "Type Error"。
|
|
|
|
|
|
- **原因**:编辑器 Inspector 期望获得的是引擎内部的对象引用。虽然 `db://` 路径可以指向文件,但在属性赋值层面,编辑器无法自动将字符串路径转换为对应的类实例。
|
|
|
|
|
|
- **最佳实践**:
|
2026-02-10 00:38:38 +08:00
|
|
|
|
1. 通过 `manage_asset -> get_info` 获取资源的 **UUID**。
|
|
|
|
|
|
2. 在调用 `manage_components -> update` 时,**优先使用 UUID** 进行赋值。
|
|
|
|
|
|
3. UUID 是底层唯一标识,能确保编辑器精准识别资源类型并正确完成引用链接。
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
|
|
## 3. 场景同步与编辑器状态
|
|
|
|
|
|
|
|
|
|
|
|
### 3.1 刷新与编译
|
2026-02-12 22:55:08 +08:00
|
|
|
|
|
|
|
|
|
|
- **注意事项**:创建新脚本后,必须调用 `manage_editor -> refresh_editor` 或等待几秒钟以触发编译。
|
|
|
|
|
|
- **风险**:在脚本编译完成前尝试将其作为组件添加到节点,会导致 `添加组件失败: Cannot read property 'constructor' of null` 或找不到脚本组件的问题。
|
2026-02-10 00:38:38 +08:00
|
|
|
|
|
|
|
|
|
|
### 3.2 节点删除 (IPC 协议)
|
2026-02-12 22:55:08 +08:00
|
|
|
|
|
|
|
|
|
|
- **正确协议**:应使用 `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` 并自动带上选中的节点。
|
2026-02-10 00:38:38 +08:00
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
|
|
## 4. MCP Bridge 源码补丁说明
|
|
|
|
|
|
|
|
|
|
|
|
### 4.1 属性解析增强 (Asset 序列化修复)
|
2026-02-12 22:55:08 +08:00
|
|
|
|
|
|
|
|
|
|
- **改进点**:在 `scene-script.js` 的 `applyProperties` 中通过 `cc.AssetLibrary.loadAsset` 解决了资源属性在 Inspector 报错 "Type Error" 的问题。
|
|
|
|
|
|
- **原理**:
|
|
|
|
|
|
- **问题根源**:在场景进程中直接将 UUID 字符串赋给资源属性(如 `comp.prefab = "uuid"`),会导致 `.fire` 文件将其保存为纯字符串而非对象格式。编辑器 Inspector 期望的是资源引用结构 `{ "__uuid__": "..." }`,类型不匹配产生 Type Error。
|
|
|
|
|
|
- **修复逻辑**:
|
2026-02-10 00:38:38 +08:00
|
|
|
|
1. **真实加载**:使用 `cc.AssetLibrary.loadAsset(uuid, callback)` 在场景进程中异步加载真实的资源实例。
|
|
|
|
|
|
2. **实例赋值**:在回调中将加载到的 `asset` 对象赋予组件(`component[key] = asset`),这确保了场景保存时能生成正确的序列化对象。
|
|
|
|
|
|
3. **UI 同步**:同步发送 IPC `scene:set-property`,使用 `{ uuid: value }` 格式通知编辑器面板更新 Inspector UI。
|
2026-02-12 22:55:08 +08:00
|
|
|
|
- **Node/Component**: 对于节点 or 组件引用,通过 `findNode` 查找实例并直接赋值实例对象,而非 UUID 字符串。
|
2026-02-10 00:38:38 +08:00
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
|
|
## 5. AI 操作安全守则 (Subject Validation Rule)
|
|
|
|
|
|
|
|
|
|
|
|
### 5.1 确定性优先
|
2026-02-12 22:55:08 +08:00
|
|
|
|
|
|
|
|
|
|
- **核心法则**:任何对节点、组件、属性的操作,都必须建立在 **“主体已确认存在”** 的基础上。
|
|
|
|
|
|
- **具体流程**:
|
2026-02-10 00:38:38 +08:00
|
|
|
|
1. **节点校验**:在操作前必须调用 `get_scene_hierarchy` 确认 `nodeId`。
|
|
|
|
|
|
2. **组件校验**:在 `update` 或 `remove` 前必须调用 `manage_components(action: 'get')` 确认目标组件存在。
|
|
|
|
|
|
3. **属性校验**:严禁猜测属性名。在 `update` 前,应通过读取脚本定义或 `get` 返回的现有属性列表来确定准确的属性名称。
|
2026-02-12 22:55:08 +08:00
|
|
|
|
- **禁止行为**:禁止基于假设进行盲目赋值或删除。如果发现对象不存在,应立即报错或尝试重建,而非继续尝试修改。
|
2026-02-10 00:38:38 +08:00
|
|
|
|
|
2026-02-25 11:11:21 +08:00
|
|
|
|
### 5.2 传参精准与别名容错
|
|
|
|
|
|
|
|
|
|
|
|
- **传参风险**:大语言模型在生成 JSON 时可能会出现操作类型字段名“幻觉”(例如在调用 `manage_components` 时将本应是 `action` 的参数写为含义相近的 `operation`)。
|
|
|
|
|
|
- **优化机制**:底层脚本 (`scene-script.js`) 已经全面引入参数别名回落机制(如 `action = action || operation`)。
|
|
|
|
|
|
- **提示开发**:尽管底层具备一定的容错率,在维护 MCP 工具说明书(Schema)时,仍应严格要求 AI 书写标准参数名,避免纵容产生更大的幻觉偏移。
|
|
|
|
|
|
|
2026-02-10 00:38:38 +08:00
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
|
|
## 6. 常见资源关键字
|
2026-02-12 22:55:08 +08:00
|
|
|
|
|
|
|
|
|
|
- **资产识别启发式**:当通过 `manage_components` 赋值时,如果属性名包含以下关键字,插件会尝试将其作为 UUID 资源处理:
|
|
|
|
|
|
`prefab`, `sprite`, `texture`, `material`, `skeleton`, `spine`, `atlas`, `font`, `audio`, `data`
|
|
|
|
|
|
- **建议**:如果资源未正确加载,请检查属性名是否包含以上关键字,或手动确认该 UUID 不属于任何节点。
|
2026-02-11 01:09:42 +08:00
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
|
|
## 7. 搜索工具 (search_project) 使用建议
|
2026-02-12 22:55:08 +08:00
|
|
|
|
|
|
|
|
|
|
- **性能建议**:尽量指定 `path` 参数缩小搜索范围(如 `db://assets/scripts`),避免全项目大面积搜索,尤其是在包含大量旧资源的 Library 目录(虽然插件已过滤)。
|
|
|
|
|
|
- **正则表达式**:在使用 `useRegex` 时,确保正则模式的语法正确。如果正则匹配失败,工具会返回详细的错误提示。
|
|
|
|
|
|
- **模式选择**:
|
|
|
|
|
|
- 查找具体逻辑代码:使用 `matchType: "content"`。
|
|
|
|
|
|
- 定位资源文件:使用 `matchType: "file_name"` 并配合 `extensions` 过滤。
|
|
|
|
|
|
- 重构目录结构前:使用 `matchType: "dir_name"` 检查目录名冲突。
|
2026-02-11 01:09:42 +08:00
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
|
|
## 8. Undo/Redo (撤销/重做) 使用指南
|
|
|
|
|
|
|
|
|
|
|
|
### 8.1 事务分组
|
2026-02-12 22:55:08 +08:00
|
|
|
|
|
|
|
|
|
|
- **背景**:连续执行多次修改(如同时移动并缩放)时,通常希望一次“撤销”能回滚所有更改。
|
|
|
|
|
|
- **最佳实践**:
|
2026-02-11 01:09:42 +08:00
|
|
|
|
1. 调用 `manage_undo(action: 'begin_group', description: '操作描述')`。
|
|
|
|
|
|
2. 执行多次修改(如调用 `update_node_transform`)。
|
|
|
|
|
|
3. 调用 `manage_undo(action: 'end_group')`。
|
2026-02-12 22:55:08 +08:00
|
|
|
|
- **注意**:`undo-record` 需要在 `begin_group` 时明确关联节点 ID,否则可能导致撤销栈无法精准匹配对象。
|
2026-02-11 01:09:42 +08:00
|
|
|
|
|
|
|
|
|
|
### 8.2 属性修改方式
|
2026-02-12 22:55:08 +08:00
|
|
|
|
|
|
|
|
|
|
- **核心规则**:在 `scene-script.js` 中严禁直接使用 `node.x = 100`。
|
|
|
|
|
|
- **正确做法**:必须通过 `Editor.Ipc.sendToPanel('scene', 'scene:set-property', ...)`。只有这样,修改才会被 Cocos Creator 的 UndoManager 捕获,从而支持撤销。
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
|
|
## 9. 并发安全与防卡死机制
|
|
|
|
|
|
|
|
|
|
|
|
### 9.1 指令队列 (CommandQueue)
|
|
|
|
|
|
|
|
|
|
|
|
- **背景**:AI 客户端可能在短时间内连续发送多个 MCP 请求(如 `delete-node` → `refresh_editor` → `search_project`),如果并发执行,`AssetDB.refresh()` 等异步重操作会与后续请求产生 I/O 和 IPC 通道冲突,导致编辑器主线程阻塞。
|
|
|
|
|
|
- **解决方案**:在 `/call-tool` HTTP 入口处引入 `enqueueCommand` 机制,将所有 MCP 工具调用**串行化**执行。前一个指令的回调完成后,才会出队并处理下一个指令。
|
|
|
|
|
|
- **注意事项**:
|
|
|
|
|
|
1. 队列在 `processNextCommand` 的 `catch` 块中有防死锁保护,即使某个指令抛出异常也不会永久阻塞后续指令。
|
|
|
|
|
|
2. `batchExecute` 内部也已从并行 `forEach` 改为串行链式执行。
|
|
|
|
|
|
3. 队列长度会在日志中显示(`REQ -> [toolName] (队列长度: N)`),可用于排查积压问题。
|
|
|
|
|
|
|
2026-02-12 23:36:21 +08:00
|
|
|
|
### 9.2 `refresh_editor` 路径要求
|
|
|
|
|
|
|
|
|
|
|
|
- **⚠️ 必须带路径**:在调用 `manage_editor` 的 `refresh_editor` 时,务必通过 `properties.path` 指定精确的文件或目录(如 `db://assets/scripts/Test.ts`)。严禁空参数进行全局刷新,在生产项目中会导致数分钟的编辑器卡死。
|
|
|
|
|
|
|
|
|
|
|
|
### 9.3 IPC 超时保护 (callSceneScriptWithTimeout)
|
2026-02-12 22:55:08 +08:00
|
|
|
|
|
|
|
|
|
|
- **背景**:`Editor.Scene.callSceneScript` 的回调依赖 Scene 面板响应 IPC 消息。如果主线程阻塞,Scene 面板无法处理消息,导致 callback 永远不返回,HTTP 连接堆积。
|
|
|
|
|
|
- **解决方案**:所有 `callSceneScript` 调用均通过 `callSceneScriptWithTimeout` 包装,默认 15 秒超时。超时后自动返回错误,释放 HTTP 连接和队列位置。
|
|
|
|
|
|
- **日志标识**:超时会记录 `[超时] callSceneScript "方法名" 超过 15000ms 未响应`。
|
2026-02-24 16:22:45 +08:00
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
|
|
## 10. Token 消耗与长数据保护防爆机制
|
|
|
|
|
|
|
|
|
|
|
|
### 10.1 `get_scene_hierarchy` 深度与层级限制
|
2026-02-25 11:11:21 +08:00
|
|
|
|
|
2026-02-24 16:22:45 +08:00
|
|
|
|
- **背景**:在一两千个节点的大型 UI 场景中,无限制地获取全场景树会瞬间消耗十万以上的 Token,导致 AI 丢失上下文甚至触发截断报错。
|
|
|
|
|
|
- **最佳实践**:
|
2026-02-25 11:11:21 +08:00
|
|
|
|
- **默认使用 `depth: 2`** (默认限制) 来逐步探查。
|
|
|
|
|
|
- **结合 `nodeId` 参数**:找到关键模块(例如 `Canvas/LoginPanel`)的 UUID 后,再单独向该 `nodeId` 请求下一层的结构,而非每次从根部拉取。
|
2026-02-24 16:22:45 +08:00
|
|
|
|
|
|
|
|
|
|
### 10.2 大对象与长数组截断
|
2026-02-25 11:11:21 +08:00
|
|
|
|
|
2026-02-24 16:22:45 +08:00
|
|
|
|
- **背景**:在读取某些特定组件数据(如多边形顶点坐标、Sprite 曲线数据或序列化的内联 Base64 图片)时,JSON 可能会异常庞大。
|
|
|
|
|
|
- **保护机制**:
|
2026-02-25 11:11:21 +08:00
|
|
|
|
- `scene-script.js` 内部在执行 `manage_components(get)` 序列化时,对于**长度超过 10 的 Array** 会强制截断,返回字面量字符串 `"[Array(X)]"`。
|
|
|
|
|
|
- 对于**长度大于 200 的长字符串**,也会强制缩略并追加 `...[Truncated, total length: X]`。
|
2026-02-24 16:22:45 +08:00
|
|
|
|
- **应对策略**:如果 AI 看到截断提示,这意味着此处为海量无语义数据,**请勿**尝试盲目通过 `update` 覆盖或还原被截断的字段,极易导致源数据被破坏。请仅修改自己能够完全看清的轻量级属性(如 `name`, `x`, `scale` 等)。
|
2026-03-01 00:32:59 +08:00
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
|
|
## 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 UUID,`find_references` 均能正确返回所有引用位置。
|