Files
mcp-bridge/scene-script.js

272 lines
7.4 KiB
JavaScript
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.
"use strict";
module.exports = {
"set-property": function (event, args) {
const { id, path, value } = args;
// 1. 获取节点
let node = cc.engine.getInstanceById(id);
if (node) {
// 2. 修改属性
if (path === "name") {
node.name = value;
} else {
node[path] = value;
}
// 3. 【解决报错的关键】告诉编辑器场景变脏了(需要保存)
// 在场景进程中,我们发送 IPC 给主进程
Editor.Ipc.sendToMain("scene:dirty");
// 4. 【额外补丁】通知层级管理器Hierarchy同步更新节点名称
// 否则你修改了名字,层级管理器可能还是显示旧名字
Editor.Ipc.sendToAll("scene:node-changed", {
uuid: id,
});
if (event.reply) {
event.reply(null, `Node ${id} updated to ${value}`);
}
} else {
if (event.reply) {
event.reply(new Error("Scene Script: Node not found " + id));
}
}
},
"get-hierarchy": function (event) {
const scene = cc.director.getScene();
function dumpNodes(node) {
// 【优化】跳过编辑器内部的私有节点,减少数据量
if (node.name.startsWith("Editor Scene") || node.name === "gizmoRoot") {
return null;
}
let nodeData = {
name: node.name,
uuid: node.uuid,
active: node.active,
position: { x: Math.round(node.x), y: Math.round(node.y) },
scale: { x: node.scaleX, y: node.scaleY },
size: { width: node.width, height: node.height },
// 记录组件类型,让 AI 知道这是个什么节点
components: node._components.map((c) => c.__typename),
children: [],
};
for (let i = 0; i < node.childrenCount; i++) {
let childData = dumpNodes(node.children[i]);
if (childData) nodeData.children.push(childData);
}
return nodeData;
}
const hierarchy = dumpNodes(scene);
if (event.reply) event.reply(null, hierarchy);
},
"update-node-transform": function (event, args) {
const { id, x, y, scaleX, scaleY, color } = args;
let node = cc.engine.getInstanceById(id);
if (node) {
if (x !== undefined) node.x = x;
if (y !== undefined) node.y = y;
if (scaleX !== undefined) node.scaleX = scaleX;
if (scaleY !== undefined) node.scaleY = scaleY;
if (color) {
// color 格式如 "#FF0000"
node.color = new cc.Color().fromHEX(color);
}
Editor.Ipc.sendToMain("scene:dirty");
Editor.Ipc.sendToAll("scene:node-changed", { uuid: id });
if (event.reply) event.reply(null, "Transform updated");
} else {
if (event.reply) event.reply(new Error("Node not found"));
}
},
"create-node": function (event, args) {
const { name, parentId, type } = args;
const scene = cc.director.getScene();
if (!scene || !cc.director.getRunningScene()) {
if (event.reply) event.reply(new Error("Scene not ready or loading."));
return;
}
let newNode = null;
// 特殊处理:如果是创建 Canvas自动设置好适配
if (type === "canvas" || name === "Canvas") {
newNode = new cc.Node("Canvas");
let canvas = newNode.addComponent(cc.Canvas);
newNode.addComponent(cc.Widget);
// 设置默认设计分辨率
canvas.designResolution = cc.size(960, 640);
canvas.fitHeight = true;
// 自动在 Canvas 下创建一个 Camera
let camNode = new cc.Node("Main Camera");
camNode.addComponent(cc.Camera);
camNode.parent = newNode;
} else if (type === "sprite") {
newNode = new cc.Node(name || "New Sprite");
newNode.addComponent(cc.Sprite);
} else if (type === "label") {
newNode = new cc.Node(name || "New Label");
let l = newNode.addComponent(cc.Label);
l.string = "New Label";
} else {
newNode = new cc.Node(name || "New Node");
}
// 设置层级
let parent = parentId ? cc.engine.getInstanceById(parentId) : scene;
if (parent) {
newNode.parent = parent;
// 【优化】通知主进程场景变脏
Editor.Ipc.sendToMain("scene:dirty");
// 【关键】使用 setTimeout 延迟通知 UI 刷新,让出主循环
setTimeout(() => {
Editor.Ipc.sendToAll("scene:node-created", {
uuid: newNode.uuid,
parentUuid: parent.uuid,
});
}, 10);
if (event.reply) event.reply(null, newNode.uuid);
}
},
"manage-components": function (event, args) {
const { nodeId, action, componentType, componentId, properties } = args;
let node = cc.engine.getInstanceById(nodeId);
if (!node) {
if (event.reply) event.reply(new Error("Node not found"));
return;
}
switch (action) {
case "add":
if (!componentType) {
if (event.reply) event.reply(new Error("Component type is required"));
return;
}
try {
// 解析组件类型
let compClass = null;
if (componentType.startsWith("cc.")) {
const className = componentType.replace("cc.", "");
compClass = cc[className];
} else {
// 尝试获取自定义组件
compClass = cc.js.getClassByName(componentType);
}
if (!compClass) {
if (event.reply) event.reply(new Error(`Component type not found: ${componentType}`));
return;
}
// 添加组件
const component = node.addComponent(compClass);
// 设置属性
if (properties) {
for (const [key, value] of Object.entries(properties)) {
if (component[key] !== undefined) {
component[key] = value;
}
}
}
Editor.Ipc.sendToMain("scene:dirty");
Editor.Ipc.sendToAll("scene:node-changed", { uuid: nodeId });
if (event.reply) event.reply(null, `Component ${componentType} added`);
} catch (err) {
if (event.reply) event.reply(new Error(`Failed to add component: ${err.message}`));
}
break;
case "remove":
if (!componentId) {
if (event.reply) event.reply(new Error("Component ID is required"));
return;
}
try {
// 查找并移除组件
const component = node.getComponentById(componentId);
if (component) {
node.removeComponent(component);
Editor.Ipc.sendToMain("scene:dirty");
Editor.Ipc.sendToAll("scene:node-changed", { uuid: nodeId });
if (event.reply) event.reply(null, "Component removed");
} else {
if (event.reply) event.reply(new Error("Component not found"));
}
} catch (err) {
if (event.reply) event.reply(new Error(`Failed to remove component: ${err.message}`));
}
break;
case "get":
try {
const components = node._components.map((c) => {
// 获取组件属性
const properties = {};
for (const key in c) {
if (typeof c[key] !== "function" &&
!key.startsWith("_") &&
c[key] !== undefined) {
try {
properties[key] = c[key];
} catch (e) {
// 忽略无法序列化的属性
}
}
}
return {
type: c.__typename,
uuid: c.uuid,
properties: properties
};
});
if (event.reply) event.reply(null, components);
} catch (err) {
if (event.reply) event.reply(new Error(`Failed to get components: ${err.message}`));
}
break;
default:
if (event.reply) event.reply(new Error(`Unknown component action: ${action}`));
break;
}
},
"get-component-properties": function (component) {
const properties = {};
// 遍历组件属性
for (const key in component) {
if (typeof component[key] !== "function" &&
!key.startsWith("_") &&
component[key] !== undefined) {
try {
properties[key] = component[key];
} catch (e) {
// 忽略无法序列化的属性
}
}
}
return properties;
},
};