Files
mcp-bridge/注意事项.md
火焰库拉 8df6f5a415 文档: 强化 AI 刷新性能警示
- 在 manage_editor 描述中加入⚠️警告,强制要求使用 path 避免全量刷新
- AI 安全守则更新为 4 条,包含禁止全局刷新要求
- 注意事项文档同步强化路径要求警示
2026-02-12 23:36:21 +08:00

131 lines
8.1 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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_management``create` 操作。
- **核心逻辑**该工具会同步处理节点的序列化、db 路径映射以及资源刷新Refresh确保预制体及其配套的 `.meta` 文件原子化生成。
---
## 2. 脚本属性Inspector关联
### 2.1 路径与 UUID 的区别
- **问题**:在 Inspector 面板中,脚本属性(如 `cc.Prefab``cc.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.js``applyProperties` 中通过 `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. **组件校验**:在 `update``remove` 前必须调用 `manage_components(action: 'get')` 确认目标组件存在。
3. **属性校验**:严禁猜测属性名。在 `update` 前,应通过读取脚本定义或 `get` 返回的现有属性列表来确定准确的属性名称。
- **禁止行为**:禁止基于假设进行盲目赋值或删除。如果发现对象不存在,应立即报错或尝试重建,而非继续尝试修改。
---
## 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-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)`),可用于排查积压问题。
### 9.2 `refresh_editor` 路径要求
- **⚠️ 必须带路径**:在调用 `manage_editor``refresh_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 未响应`