fix(prefab): 修复预制体编辑模式的保存与退出,使用原生 scene://edit-mode 接口替代无效的 IPC 广播,更新相关使用文档与安全规定
This commit is contained in:
18
.agent/workflows/architect.md
Normal file
18
.agent/workflows/architect.md
Normal file
@@ -0,0 +1,18 @@
|
||||
---
|
||||
description: Create a unified implementation plan.
|
||||
---
|
||||
|
||||
## User Input
|
||||
$ARGUMENTS
|
||||
|
||||
## Instructions
|
||||
|
||||
1. **Read**: Load the `spec.md` provided by the user.
|
||||
2. **Draft Plan**:
|
||||
* Create/Update **ONE file**: `specs/[feature_name]/plan.md`.
|
||||
* **Section 1: Architecture**: Briefly list changed files and data models.
|
||||
* **Section 2: Step-by-Step**: List the implementation steps (Todo list) directly in this file.
|
||||
3. **Format**:
|
||||
* Use checkboxes `- [ ]` for the steps so they are clickable.
|
||||
* Mark steps as `[Frontend]` or `[Backend]`.
|
||||
4. **Constraint**: Do NOT create `tasks.md`. Keep it all in `plan.md`.
|
||||
19
.agent/workflows/define.md
Normal file
19
.agent/workflows/define.md
Normal file
@@ -0,0 +1,19 @@
|
||||
---
|
||||
description: Create a single, rigorous feature spec.
|
||||
---
|
||||
|
||||
## User Input
|
||||
$ARGUMENTS
|
||||
|
||||
## Instructions
|
||||
|
||||
1. **Context**: Read `memory/constitution.md` and any attached images.
|
||||
2. **Draft Spec**:
|
||||
* Create/Update **ONE file only**: `specs/[feature_name]/spec.md`.
|
||||
* **Do NOT** create a checklist file.
|
||||
* **Do NOT** create a separate analysis file.
|
||||
3. **Content**:
|
||||
* Include "Visual Requirements" (from images).
|
||||
* Include "Functional Requirements".
|
||||
* Include "Edge Cases" directly in the spec as a section.
|
||||
4. **Output**: Show the `spec.md` artifact.
|
||||
13
.agent/workflows/execute.md
Normal file
13
.agent/workflows/execute.md
Normal file
@@ -0,0 +1,13 @@
|
||||
---
|
||||
description: Build the feature from the plan.
|
||||
---
|
||||
|
||||
## Instructions
|
||||
|
||||
1. **Read**: Open `specs/[feature_name]/plan.md`.
|
||||
2. **Execute**:
|
||||
* Look for the **Step-by-Step** section with checkboxes.
|
||||
* Execute the unchecked items `- [ ]`.
|
||||
3. **Vibe Check**:
|
||||
* After every 2-3 steps, verify the code visually.
|
||||
* Mark steps as `- [x]` in `plan.md` as you finish them.
|
||||
14
.agent/workflows/refactor.md
Normal file
14
.agent/workflows/refactor.md
Normal file
@@ -0,0 +1,14 @@
|
||||
---
|
||||
description: Clean up legacy code before feature work.
|
||||
---
|
||||
|
||||
## User Input
|
||||
|
||||
$ARGUMENTS
|
||||
|
||||
## Instructions
|
||||
|
||||
1. **Audit**: Scan the target directory `$ARGUMENTS`.
|
||||
2. **Constitution Check**: Compare against `/memory/constitution.md`.
|
||||
3. **Refactor**: Apply modern patterns (e.g., "Convert Promises to Async/Await") WITHOUT changing business logic.
|
||||
4. **Verify**: Run existing tests to ensure no regression.
|
||||
17
.agent/workflows/verify.md
Normal file
17
.agent/workflows/verify.md
Normal file
@@ -0,0 +1,17 @@
|
||||
---
|
||||
description: Visual and logic verification of the feature.
|
||||
---
|
||||
|
||||
## Antigravity QA Instructions
|
||||
|
||||
1. **Environment**: Spin up the app in the Integrated Terminal/Browser.
|
||||
2. **Visual Audit**:
|
||||
- Navigate to the new feature.
|
||||
- **TAKE SCREENSHOT**.
|
||||
- Compare screenshot to the `spec.md` requirements.
|
||||
- Report: "Match" or "Discrepancy".
|
||||
3. **Logic Audit**:
|
||||
- Run the "Happy Path" user journey.
|
||||
- Check console logs for errors.
|
||||
4. **Report**:
|
||||
- Generate a **Release Readiness Artifact**.
|
||||
@@ -133,11 +133,14 @@ Args: [你的项目所在盘符]:/[项目路径]/packages/mcp-bridge/src/mcp-pro
|
||||
- **参数**:
|
||||
- `url`: 场景资源路径,如 `db://assets/NewScene.fire`
|
||||
|
||||
### 7. open_prefab
|
||||
### 7. open_prefab / save_prefab / close_prefab
|
||||
|
||||
- **描述**: 在编辑器中打开指定的预制体文件进入编辑模式。这是一个异步操作,打开后请等待几秒。
|
||||
- **描述**: 预制体专用操作三部曲。
|
||||
- **参数**:
|
||||
- `url`: 预制体资源路径,如 `db://assets/prefabs/Test.prefab`
|
||||
- `open_prefab`: 需提供 `url` (如 `db://assets/prefabs/Test.prefab`), 将异步打开并进入编辑模式。
|
||||
- `save_prefab`: 无需参数,保存当前预制体。
|
||||
- `close_prefab`: 无需参数,彻底退出预制体编辑模式并返回原场景。
|
||||
- **重要提示**: 这三个工具操作会直接深入场景编辑器的底层并驱动真正的状态机(通过内部 `scene://edit-mode` 的真实模拟),行为与人类手动点击“保存”“退出”按钮100%一致。
|
||||
|
||||
### 8. create_node
|
||||
|
||||
|
||||
@@ -431,3 +431,17 @@ ps: 感谢 @亮仔😂 😁 🐔否? 提供的反馈以及操作日志
|
||||
|
||||
- **问题**: `get-hierarchy` 的 `dumpNodes` 递归遍历子节点时无数量限制,若某个节点下有数百个同级子节点,返回数据量巨大。
|
||||
- **修复**: 新增 `MAX_CHILDREN_PER_LEVEL = 50` 安全上限。每层最多返回 50 个子节点,超出部分在返回数据中通过 `childrenTruncated` 字段标注被截断的数量,帮助 AI 知悉还有更多子节点未列出。
|
||||
|
||||
---
|
||||
|
||||
## 预制体全生命周期编辑与状态流转修复 (2026-03-08)
|
||||
|
||||
### 1. `save_prefab` 与 `close_prefab` 原生化改造
|
||||
|
||||
- **问题**: AI 尝试从 `McpTestPrefab.prefab` 等文件中通过 `scene:save-prefab` 和 `scene:close-prefab` 保存并退出预制体模式时,报错找不到事件。分析源码发现,这些直觉上的 IPC 消息实际上并不存在,导致一旦用 `open_prefab` 进入隔离的编辑空间后,无法正确将修改落盘,且无法安全退出返回原大场景。
|
||||
- **修复**:
|
||||
1. **直接调用内部 API**: 完全废弃尝试通过常规 IPC 发送伪装指令的想法。在 `scene-script.js` 内部直接 `require("scene://edit-mode")`,获取到负责管理场景所有状态机(如大场景模式、预制体模式、动画编辑模式)的核心模块。
|
||||
2. **真实状态机驱动**:
|
||||
- 对于 `save_prefab`,直接调用无参的 `editMode.save()`。这100%等同于人工点击编辑器左上角的“保存”按钮。也因此**移除了多余的 `rootNodeId` 参数**限制。
|
||||
- 对于 `close_prefab`,直接调用 `editMode.pop()`。彻底将当前编辑的预制体上下文从堆栈中弹出,干净利落地回落回原始场景,并自动更新引擎各面板 (Inspector、层级管理器等) 状态。
|
||||
- **意义**: 到目前为止,涵盖**创建 (`create_prefab`) -> 打开 (`open_prefab`) -> 修改 -> (可选)保存 (`save_prefab`) -> 退出 (`close_prefab`)** 的完整大模型端到端自动化预制体流水线被彻底打通。没有任何妥协,一切就像是有一个看不见的高手坐在引擎主控面板前帮你点按按钮。
|
||||
|
||||
187
docs/prefab-ipc-messages.md
Normal file
187
docs/prefab-ipc-messages.md
Normal file
@@ -0,0 +1,187 @@
|
||||
# Prefab 相关的 IPC 消息总结
|
||||
|
||||
本文档总结了 Cocos Creator 编辑器中所有与 Prefab 相关的 `Editor.Ipc.sendTo*` 开头的 IPC 消息。
|
||||
|
||||
## 消息列表
|
||||
|
||||
| 序号 | IPC 消息调用 | 消息名称 | 参数 | 所在文件 | 说明 |
|
||||
| ---- | --------------------------------------------------------------------------------------------------- | ------------------------------ | ------------------------------------------------------------------ | ---------------------------------------------------------- | ------------------------------ |
|
||||
| 1 | `Editor.Ipc.sendToAll("scene:enter-prefab-edit-mode", e)` | scene:enter-prefab-edit-mode | `e` (prefab uuid) | `editor/builtin/assets/panel/component/node.js:277` | 进入 prefab 编辑模式 |
|
||||
| 2 | `Editor.Ipc.sendToPanel("scene", "scene:create-prefab", d, u)` | scene:create-prefab | `d` (uuid), `u` (path) | `editor/builtin/assets/panel/component/nodes.js:197` | 创建 prefab |
|
||||
| 3 | `Editor.Ipc.sendToPanel("scene", "scene:revert-prefab", this._vm.target.uuid)` | scene:revert-prefab | `this._vm.target.uuid` (node uuid) | `editor/builtin/inspector/panel/index.js:137` | 还原 prefab |
|
||||
| 4 | `Editor.Ipc.sendToPanel("scene", "scene:apply-prefab", this._vm.target.uuid)` | scene:apply-prefab | `this._vm.target.uuid` (node uuid) | `editor/builtin/inspector/panel/index.js:140` | 应用 prefab |
|
||||
| 5 | `Editor.Ipc.sendToPanel("scene", "scene:set-prefab-sync", this._vm.target.uuid)` | scene:set-prefab-sync | `this._vm.target.uuid` (node uuid) | `editor/builtin/inspector/panel/index.js:143` | 设置 prefab 同步 |
|
||||
| 6 | `Editor.Ipc.sendToPanel("node-library", "node-library:delete-prefab", e)` | node-library:delete-prefab | `e` (prefab info object) | `editor/builtin/node-library/core/menu.js:7` | 删除 prefab |
|
||||
| 7 | `Editor.Ipc.sendToPanel("node-library", "node-library:rename-prefab", e)` | node-library:rename-prefab | `e` (prefab info object) | `editor/builtin/node-library/core/menu.js:14` | 重命名 prefab |
|
||||
| 8 | `Editor.Ipc.sendToPanel("node-library", "node-library:set-prefab-icon", e)` | node-library:set-prefab-icon | `e` (prefab info object) | `editor/builtin/node-library/core/menu.js:21` | 设置 prefab 图标 |
|
||||
| 9 | `Editor.Ipc.sendToMain("node-library:popup-prefab-menu", e.x, e.y, { id: this.prefab.uuid })` | node-library:popup-prefab-menu | `e.x`, `e.y`, `{ id: this.prefab.uuid }` | `editor/builtin/node-library/panel/component/prefab.js:30` | 弹出 prefab 菜单 |
|
||||
| 10 | `Editor.Ipc.sendToPanel("scene", "scene:create-node-by-prefab", e, Editor.assetdb.urlToUuid(r), o)` | scene:create-node-by-prefab | `e` (name), `Editor.assetdb.urlToUuid(r)` (uuid), `o` (parentNode) | `editor/core/main-menu.js:6` | 通过 prefab 创建节点 |
|
||||
| 11 | `Editor.Ipc.sendToMain("scene:create-prefab", s, a, (e, t) => {...})` | scene:create-prefab | `s` (path), `a` (serialized data), callback | `editor/page/scene-utils/index.js:211` | 创建 prefab(带回调) |
|
||||
| 12 | `Editor.Ipc.sendToMain("scene:apply-prefab", i, n)` | scene:apply-prefab | `i` (uuid), `n` (serialized data) | `editor/page/scene-utils/index.js:225` | 应用 prefab 到资源 |
|
||||
| 13 | `Editor.Ipc.sendToAll("scene:enter-prefab-edit-mode", l.uuid)` | scene:enter-prefab-edit-mode | `l.uuid` (prefab uuid) | `editor/builtin/open-recent-items/main.js:28` | 从最近项目进入 prefab 编辑模式 |
|
||||
|
||||
## 按功能分类
|
||||
|
||||
### Prefab 编辑模式管理
|
||||
|
||||
- **scene:enter-prefab-edit-mode** - 进入 prefab 编辑模式
|
||||
|
||||
### Prefab 创建与保存
|
||||
|
||||
- **scene:create-prefab** - 创建 prefab 资源
|
||||
- **scene:apply-prefab** - 应用 prefab 修改到资源
|
||||
|
||||
### Prefab 实例操作
|
||||
|
||||
- **scene:revert-prefab** - 还原 prefab 实例
|
||||
- **scene:set-prefab-sync** - 设置 prefab 同步状态
|
||||
|
||||
### Node Library Prefab 管理
|
||||
|
||||
- **node-library:delete-prefab** - 删除用户 prefab
|
||||
- **node-library:rename-prefab** - 重命名用户 prefab
|
||||
- **node-library:set-prefab-icon** - 设置 prefab 图标
|
||||
- **node-library:popup-prefab-menu** - 弹出 prefab 右键菜单
|
||||
|
||||
### 节点创建
|
||||
|
||||
- **scene:create-node-by-prefab** - 从 prefab 创建节点
|
||||
|
||||
## 详细说明
|
||||
|
||||
### 1. Prefab 编辑模式管理
|
||||
|
||||
#### scene:enter-prefab-edit-mode
|
||||
|
||||
- **用途**: 打开 prefab 进行编辑
|
||||
- **参数**: prefab 资源的 uuid
|
||||
- **发送方式**: sendToAll
|
||||
- **处理**: 加载 prefab 资源并推入 prefab 编辑模式栈
|
||||
|
||||
> **重要提示**: `scene:save-prefab` 和 `scene:close-prefab` 以及 `scene:prefab-mode-changed` 等并不能用于主动保存或退出预制体模式。如果要在代码中真正模拟点击“保存”或“退出”预制体编辑模式,必须在运行于 `scene` 面板的脚本中获取内部的 `scene://edit-mode` 模块:
|
||||
>
|
||||
> ```javascript
|
||||
> const editMode = Editor.require("scene://edit-mode");
|
||||
> if (editMode && editMode.curMode().name === "prefab") {
|
||||
> editMode.save(); // 保存预制体
|
||||
> editMode.pop(); // 退出预制体编辑模式
|
||||
> }
|
||||
> ```
|
||||
|
||||
### 2. Prefab 创建与保存
|
||||
|
||||
#### scene:create-prefab
|
||||
|
||||
- **用途**: 将场景中的节点保存为 prefab 资源
|
||||
- **参数**:
|
||||
- path: prefab 保存路径
|
||||
- serializedData: 序列化后的 prefab 数据
|
||||
- callback: 回调函数 (error, uuid)
|
||||
- **发送方式**: sendToMain 或 sendToPanel
|
||||
- **处理**: 在 asset-db 中创建 prefab 文件
|
||||
|
||||
#### scene:apply-prefab
|
||||
|
||||
- **用途**: 将 prefab 实例的修改应用到 prefab 资源
|
||||
- **参数**:
|
||||
- uuid: prefab 资源 uuid
|
||||
- serializedData: 序列化后的 prefab 数据
|
||||
- **发送方式**: sendToMain 或 sendToPanel
|
||||
- **处理**: 保存 prefab 资源文件
|
||||
|
||||
### 3. Prefab 实例操作
|
||||
|
||||
#### scene:revert-prefab
|
||||
|
||||
- **用途**: 将 prefab 实例还原到 prefab 资源的状态
|
||||
- **参数**: 节点 uuid
|
||||
- **发送方式**: sendToPanel
|
||||
- **处理**: 重新实例化 prefab 资源并替换当前节点
|
||||
|
||||
#### scene:set-prefab-sync
|
||||
|
||||
- **用途**: 设置 prefab 实例的自动同步状态
|
||||
- **参数**: 节点 uuid
|
||||
- **发送方式**: sendToPanel
|
||||
- **处理**: 切换 prefab sync 属性
|
||||
|
||||
### 4. Node Library Prefab 管理
|
||||
|
||||
#### node-library:delete-prefab
|
||||
|
||||
- **用途**: 从 node library 删除用户 prefab
|
||||
- **参数**: prefab 信息对象 {id}
|
||||
- **发送方式**: sendToPanel
|
||||
- **处理**: 删除 prefab 文件和图标
|
||||
|
||||
#### node-library:rename-prefab
|
||||
|
||||
- **用途**: 重命名 node library 中的 prefab
|
||||
- **参数**: prefab 信息对象 {id}
|
||||
- **发送方式**: sendToPanel
|
||||
- **处理**: 触发重命名 UI 交互
|
||||
|
||||
#### node-library:set-prefab-icon
|
||||
|
||||
- **用途**: 设置 prefab 的自定义图标
|
||||
- **参数**: prefab 信息对象 {id}
|
||||
- **发送方式**: sendToPanel
|
||||
- **处理**: 打开文件选择对话框并保存图标
|
||||
|
||||
#### node-library:popup-prefab-menu
|
||||
|
||||
- **用途**: 在 prefab 上右键弹出上下文菜单
|
||||
- **参数**: x 坐标,y 坐标,prefab 信息对象 {id}
|
||||
- **发送方式**: sendToMain
|
||||
- **处理**: 显示右键菜单
|
||||
|
||||
### 5. 节点创建
|
||||
|
||||
#### scene:create-node-by-prefab
|
||||
|
||||
- **用途**: 从 prefab 资源创建节点实例
|
||||
- **参数**:
|
||||
- name: 节点名称
|
||||
- uuid: prefab 资源 uuid
|
||||
- parentNode: 父节点
|
||||
- **发送方式**: sendToPanel
|
||||
- **处理**: 实例化 prefab 并添加到场景中
|
||||
|
||||
## 使用示例
|
||||
|
||||
### 进入 Prefab 编辑模式
|
||||
|
||||
```javascript
|
||||
Editor.Ipc.sendToAll("scene:enter-prefab-edit-mode", prefabUuid);
|
||||
```
|
||||
|
||||
### 创建 Prefab
|
||||
|
||||
```javascript
|
||||
Editor.Ipc.sendToMain("scene:create-prefab", path, serializedData, (error, uuid) => {
|
||||
if (error) {
|
||||
Editor.error(error);
|
||||
return;
|
||||
}
|
||||
// prefab 创建成功,uuid 为新创建的 prefab uuid
|
||||
});
|
||||
```
|
||||
|
||||
### 应用 Prefab 修改
|
||||
|
||||
```javascript
|
||||
Editor.Ipc.sendToPanel("scene", "scene:apply-prefab", rootNodeUuid);
|
||||
```
|
||||
|
||||
### 还原 Prefab
|
||||
|
||||
```javascript
|
||||
Editor.Ipc.sendToPanel("scene", "scene:revert-prefab", nodeUuid);
|
||||
```
|
||||
|
||||
### 从代码创建 Prefab 节点
|
||||
|
||||
```javascript
|
||||
let parentNode = Editor.Selection.contexts("node")[0] || Editor.Selection.curActivate("node");
|
||||
Editor.Ipc.sendToPanel("scene", "scene:create-node-by-prefab", nodeName, prefabUuid, parentNode);
|
||||
```
|
||||
10
docs/注意事项.md
10
docs/注意事项.md
@@ -20,6 +20,16 @@
|
||||
5. 所有节点和组件的 `_id` 字段必须为空字符串(运行时由引擎分配)。
|
||||
6. 文件中不能包含 `cc.Scene` 对象。
|
||||
|
||||
### 1.3 预制体界面的打开与保存
|
||||
|
||||
- **推荐工具**:使用 `open_prefab`, `save_prefab`,和 `close_prefab` 工具。
|
||||
- **痛点**:直觉上 AI 可能会推断应该通过 `scene:save-prefab` 或 `scene:close-prefab` 这样的 IPC 指令来实现“保存”与“退出预制体视图”,但实际上这类消息在引擎内部并不存在。
|
||||
- **正规实现(封装在工具内)**:
|
||||
必须在负责渲染场景面板的渲染进程(Scene Process)中,直接 `require("scene://edit-mode")`,然后对当前的状态机进行控制。
|
||||
- 保存:`require("scene://edit-mode").save()`
|
||||
- 退出:`require("scene://edit-mode").pop()`
|
||||
这彻底解决了进入预制体模式后出不去,或者没法存盘的痛点。AI 在使用 `save_prefab` 和 `close_prefab` 工具时就是在触发这两行代码。
|
||||
|
||||
---
|
||||
|
||||
## 2. 脚本属性(Inspector)关联
|
||||
|
||||
22
memory/constitution.md
Normal file
22
memory/constitution.md
Normal file
@@ -0,0 +1,22 @@
|
||||
# Project Constitution
|
||||
|
||||
## Article I: The Artifact Mandate
|
||||
**Agents shall not perform work without a visible Artifact.**
|
||||
- Every planning step must produce a Markdown Artifact (Plan, Spec, or Checklist).
|
||||
- Never rely on "chat memory" alone. If it's important, write it to a file.
|
||||
|
||||
## Article II: Vision Verification
|
||||
**Trust but Verify (Visually).**
|
||||
- When implementing UI, the Agent MUST take a screenshot using the integrated Browser.
|
||||
- Compare the screenshot to the original requirement/mockup.
|
||||
- If pixels don't match, the task is incomplete.
|
||||
|
||||
## Article III: Agent Independence
|
||||
**Build for Parallelism.**
|
||||
- Tasks must be atomic.
|
||||
- Frontend agents should mock API responses if the Backend agent isn't finished.
|
||||
- Never block a thread waiting for another agent.
|
||||
|
||||
## Article IV: Code Health
|
||||
- **No Legacy Patterns**: Use modern syntax (e.g., React Hooks, ES6+, Python 3.12+).
|
||||
- **Self-Correction**: If a test fails, attempt to fix it *once* before asking the user.
|
||||
28
src/main.js
28
src/main.js
@@ -345,6 +345,16 @@ const getToolsList = () => {
|
||||
description: `保存当前场景的修改`,
|
||||
inputSchema: { type: "object", properties: {} },
|
||||
},
|
||||
{
|
||||
name: "save_prefab",
|
||||
description: `保存当前正在编辑的预制体的修改(仅在 open_prefab 进入预制体编辑模式后使用)`,
|
||||
inputSchema: { type: "object", properties: {} },
|
||||
},
|
||||
{
|
||||
name: "close_prefab",
|
||||
description: `退出预制体编辑模式,返回普通场景编辑状态`,
|
||||
inputSchema: { type: "object", properties: {} },
|
||||
},
|
||||
{
|
||||
name: "get_scene_hierarchy",
|
||||
description: `获取当前场景的节点树结构(包含 UUID、名称、子节点数)。若要查询节点组件详情等,请使用 manage_components。`,
|
||||
@@ -1238,6 +1248,24 @@ module.exports = {
|
||||
callback(null, "场景保存成功。");
|
||||
break;
|
||||
|
||||
case "save_prefab":
|
||||
isSceneBusy = true;
|
||||
addLog("info", "调用场景脚本保存预制体...");
|
||||
callSceneScriptWithTimeout("mcp-bridge", "save-prefab", {}, (err, res) => {
|
||||
isSceneBusy = false;
|
||||
callback(err, res);
|
||||
});
|
||||
break;
|
||||
|
||||
case "close_prefab":
|
||||
isSceneBusy = true;
|
||||
addLog("info", "调用场景脚本退出预制体模式...");
|
||||
callSceneScriptWithTimeout("mcp-bridge", "close-prefab", {}, (err, res) => {
|
||||
isSceneBusy = false;
|
||||
callback(err, res);
|
||||
});
|
||||
break;
|
||||
|
||||
case "get_scene_hierarchy":
|
||||
callSceneScriptWithTimeout("mcp-bridge", "get-hierarchy", args, callback);
|
||||
break;
|
||||
|
||||
@@ -610,6 +610,9 @@ module.exports = {
|
||||
} else {
|
||||
// 尝试获取自定义组件
|
||||
compClass = cc.js.getClassByName(componentType);
|
||||
if (!compClass && cc[componentType]) {
|
||||
compClass = cc[componentType];
|
||||
}
|
||||
}
|
||||
|
||||
if (!compClass) {
|
||||
@@ -647,14 +650,15 @@ module.exports = {
|
||||
break;
|
||||
|
||||
case "remove":
|
||||
if (!componentId) {
|
||||
if (event.reply) event.reply(new Error("必须提供组件 ID"));
|
||||
if (!componentId && !componentType) {
|
||||
if (event.reply) event.reply(new Error("必须提供组件 ID 或组件类型(componentType)"));
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
// 查找并移除组件
|
||||
let component = null;
|
||||
if (componentId) {
|
||||
if (node._components) {
|
||||
for (let i = 0; i < node._components.length; i++) {
|
||||
if (node._components[i].uuid === componentId) {
|
||||
@@ -663,6 +667,21 @@ module.exports = {
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (componentType) {
|
||||
let compClass = null;
|
||||
if (componentType.startsWith("cc.")) {
|
||||
const className = componentType.replace("cc.", "");
|
||||
compClass = cc[className];
|
||||
} else {
|
||||
compClass = cc.js.getClassByName(componentType);
|
||||
if (!compClass && cc[componentType]) {
|
||||
compClass = cc[componentType];
|
||||
}
|
||||
}
|
||||
if (compClass) {
|
||||
component = node.getComponent(compClass);
|
||||
}
|
||||
}
|
||||
|
||||
if (component) {
|
||||
node.removeComponent(component);
|
||||
@@ -679,9 +698,9 @@ module.exports = {
|
||||
|
||||
case "update":
|
||||
// 更新现有组件属性
|
||||
if (!componentType) {
|
||||
// 如果提供了 componentId,可以只用 componentId
|
||||
// 但 Cocos 2.4 uuid 获取组件比较麻烦,最好还是有 type 或者遍历
|
||||
if (!componentType && !componentId) {
|
||||
if (event.reply) event.reply(new Error("必须提供组件 ID 或组件类型"));
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
@@ -707,6 +726,9 @@ module.exports = {
|
||||
compClass = cc[className];
|
||||
} else {
|
||||
compClass = cc.js.getClassByName(componentType);
|
||||
if (!compClass && cc[componentType]) {
|
||||
compClass = cc[componentType];
|
||||
}
|
||||
}
|
||||
if (compClass) {
|
||||
targetComp = node.getComponent(compClass);
|
||||
@@ -1583,4 +1605,37 @@ module.exports = {
|
||||
if (event.reply) event.reply(new Error(`序列化节点失败: ${e.message}`));
|
||||
}
|
||||
},
|
||||
|
||||
"save-prefab": function (event, args) {
|
||||
try {
|
||||
const editMode = Editor.require("scene://edit-mode");
|
||||
if (editMode && editMode.curMode().name === "prefab") {
|
||||
editMode.save((err) => {
|
||||
if (err) {
|
||||
if (event.reply) event.reply(new Error(err.message || err));
|
||||
} else {
|
||||
if (event.reply) event.reply(null, "预制体保存成功");
|
||||
}
|
||||
});
|
||||
} else {
|
||||
if (event.reply) event.reply(new Error("当前不在预制体编辑模式中"));
|
||||
}
|
||||
} catch (e) {
|
||||
if (event.reply) event.reply(new Error("保存预制体发生异常: " + e.message));
|
||||
}
|
||||
},
|
||||
|
||||
"close-prefab": function (event, args) {
|
||||
try {
|
||||
const editMode = Editor.require("scene://edit-mode");
|
||||
if (editMode && editMode.curMode().name === "prefab") {
|
||||
editMode.pop();
|
||||
if (event.reply) event.reply(null, "已触发退出预制体编辑模式");
|
||||
} else {
|
||||
if (event.reply) event.reply(new Error("当前不在预制体编辑模式中"));
|
||||
}
|
||||
} catch (e) {
|
||||
if (event.reply) event.reply(new Error("退出预制体模式发生异常: " + e.message));
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
15
templates/spec.md
Normal file
15
templates/spec.md
Normal file
@@ -0,0 +1,15 @@
|
||||
# Feature: [Name]
|
||||
|
||||
## 1. Overview
|
||||
*What are we building and why?*
|
||||
|
||||
## 2. Visual Requirements (Vision)
|
||||
*Description of UI/UX derived from uploaded mockups.*
|
||||
- [ ] Component A
|
||||
- [ ] Layout B
|
||||
|
||||
## 3. Functional Requirements
|
||||
- [ ] User can...
|
||||
- [ ] System must...
|
||||
|
||||
## 4. Data Model
|
||||
15
templates/tasks.md
Normal file
15
templates/tasks.md
Normal file
@@ -0,0 +1,15 @@
|
||||
# Implementation Tasks
|
||||
|
||||
## 🔴 Parallel Group A: Backend
|
||||
- [ ] Define API Schema
|
||||
- [ ] Implement Database Migrations
|
||||
- [ ] Create API Endpoints
|
||||
|
||||
## 🔵 Parallel Group B: Frontend
|
||||
- [ ] Scaffold Components
|
||||
- [ ] Implement State Management
|
||||
- [ ] Connect to Mock API
|
||||
|
||||
## 🟢 Phase 2: Integration
|
||||
- [ ] Connect Frontend to Real Backend
|
||||
- [ ] E2E Tests
|
||||
Reference in New Issue
Block a user