feat(mcp-bridge): 添加场景和节点创建功能

- 新增 getNewSceneTemplate 函数用于生成标准场景模板
- 实现 create_scene 工具用于在 assets 目录下创建新场景文件
- 实现 create_prefab 工具用于将节点保存为预制体资源
- 实现 open_scene 工具用于在编辑器中打开指定场景
- 实现 create_node 工具用于在当前场景中创建新节点
- 在 scene-script.js 中添加 create-node 处理逻辑
- 支持创建不同类型的节点(空节点、精灵、标签等)
- 添加 UUID 生成的多种兼容方案
```
This commit is contained in:
火焰库拉
2026-01-29 14:26:28 +08:00
parent 1af6f08c94
commit f901bcc38f
2 changed files with 225 additions and 4 deletions

178
main.js
View File

@@ -1,6 +1,44 @@
"use strict";
const http = require("http");
const path = require("path");
const getNewSceneTemplate = () => {
// 尝试获取 UUID 生成函数
let newId = "";
if (Editor.Utils && Editor.Utils.uuid) {
newId = Editor.Utils.uuid();
} else if (Editor.Utils && Editor.Utils.UuidUtils && Editor.Utils.UuidUtils.uuid) {
newId = Editor.Utils.UuidUtils.uuid();
} else {
// 兜底方案:如果找不到编辑器 API生成一个随机字符串
newId = Math.random().toString(36).substring(2, 15);
}
const sceneData = [
{
__type__: "cc.SceneAsset",
_name: "",
_objFlags: 0,
_native: "",
scene: { __id__: 1 },
},
{
__id__: 1,
__type__: "cc.Scene",
_name: "",
_objFlags: 0,
_parent: null,
_children: [],
_active: true,
_level: 0,
_components: [],
autoReleaseAssets: false,
_id: newId,
},
];
return JSON.stringify(sceneData);
};
module.exports = {
"scene-script": "scene-script.js",
@@ -44,8 +82,6 @@ module.exports = {
// 简易 MCP 桥接服务器
startMcpServer() {
const http = require("http");
this.server = http.createServer((req, res) => {
// 设置 CORS 方便调试
res.setHeader("Access-Control-Allow-Origin", "*");
@@ -110,9 +146,67 @@ module.exports = {
required: ["id"],
},
},
{
name: "create_scene",
description: "在 assets 目录下创建一个新的场景文件",
inputSchema: {
type: "object",
properties: {
sceneName: { type: "string", description: "场景名称" },
},
required: ["sceneName"],
},
},
{
name: "create_prefab",
description: "将场景中的某个节点保存为预制体资源",
inputSchema: {
type: "object",
properties: {
nodeId: { type: "string", description: "节点 UUID" },
prefabName: { type: "string", description: "预制体名称" },
},
required: ["nodeId", "prefabName"],
},
},
{
name: "open_scene",
description: "在编辑器中打开指定的场景文件",
inputSchema: {
type: "object",
properties: {
url: {
type: "string",
description: "场景资源路径,如 db://assets/NewScene.fire",
},
},
required: ["url"],
},
},
{
name: "create_node",
description: "在当前场景中创建一个新节点",
inputSchema: {
type: "object",
properties: {
name: { type: "string", description: "节点名称" },
parentId: {
type: "string",
description: "父节点 UUID (可选,不传则挂在场景根部)",
},
type: {
type: "string",
enum: ["empty", "sprite", "label"],
description: "节点预设类型",
},
},
required: ["name"],
},
},
];
res.end(JSON.stringify({ tools }));
} else if (req.url === "/call-tool" && req.method === "POST") {
return res.end(JSON.stringify({ tools }));
}
if (req.url === "/call-tool" && req.method === "POST") {
// 2. 执行工具逻辑
const { name, arguments: args } = JSON.parse(body);
@@ -168,6 +262,82 @@ module.exports = {
}),
);
});
} else if (name === "create_scene") {
const url = `db://assets/${args.sceneName}.fire`;
if (Editor.assetdb.exists(url)) {
return res.end(
JSON.stringify({
content: [{ type: "text", text: "Error: Scene already exists" }],
}),
);
}
// 生成标准场景内容
const sceneJson = getNewSceneTemplate();
Editor.assetdb.create(url, sceneJson, (err, results) => {
if (err) {
res.end(
JSON.stringify({
content: [{ type: "text", text: "Error creating scene: " + err }],
}),
);
} else {
res.end(
JSON.stringify({
content: [{ type: "text", text: `Standard Scene created at ${url}` }],
}),
);
}
});
} else if (name === "create_prefab") {
const url = `db://assets/${args.prefabName}.prefab`;
// 2.4.x 创建预制体的 IPC 消息
Editor.Ipc.sendToMain("scene:create-prefab", args.nodeId, url);
res.end(
JSON.stringify({
content: [
{ type: "text", text: `Command sent: Creating prefab '${args.prefabName}'` },
],
}),
);
} else if (name === "open_scene") {
const url = args.url;
// 1. 将 db:// 路径转换为 UUID
const uuid = Editor.assetdb.urlToUuid(url);
if (uuid) {
// 2. 发送核心 IPC 消息给主进程
// scene:open-by-uuid 是编辑器内置的场景打开逻辑
Editor.Ipc.sendToMain("scene:open-by-uuid", uuid);
res.end(
JSON.stringify({
content: [
{ type: "text", text: `Success: Opening scene ${url} (UUID: ${uuid})` },
],
}),
);
} else {
res.end(
JSON.stringify({
content: [
{ type: "text", text: `Error: Could not find asset with URL ${url}` },
],
}),
);
}
} else if (name === "create_node") {
// 转发给场景脚本处理
Editor.Scene.callSceneScript("mcp-bridge", "create-node", args, (err, result) => {
res.end(
JSON.stringify({
content: [
{ type: "text", text: err ? `Error: ${err}` : `Node created: ${result}` },
],
}),
);
});
}
} else {
res.statusCode = 404;