Compare commits

...

4 Commits

8 changed files with 208 additions and 116 deletions

7
.gitattributes vendored Normal file
View File

@@ -0,0 +1,7 @@
* text=auto eol=lf
*.png binary
*.jpg binary
*.jpeg binary
*.gif binary
*.ico binary

32
dist/scene.js vendored

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -141,6 +141,7 @@
"scene": {
"script": "./dist/scene.js",
"methods": [
"executeScript",
"createNewScene",
"addComponentToNode",
"removeComponentFromNode",

View File

@@ -2,6 +2,30 @@ import { join } from 'path';
module.paths.push(join(Editor.App.path, 'node_modules'));
export const methods: { [key: string]: (...any: any) => any } = {
/**
* Execute arbitrary JavaScript in the scene process.
* `cc` is available in scope; the value of the last expression is returned
* (compatible with `(function(){ ... })();` IIFE scripts).
*/
executeScript(script: string) {
try {
const cc = require('cc');
const body = String(script).trim().replace(/;+\s*$/, '');
let fn: Function;
try {
fn = new Function('cc', 'return (' + body + '\n);');
} catch (_e) {
fn = new Function('cc', script);
}
const result = fn(cc);
let data: any = result;
try { JSON.stringify(result); } catch (_) { data = String(result); }
return { success: true, data: { result: data } };
} catch (error: any) {
return { success: false, error: error.message };
}
},
/**
* Create a new scene
*/

View File

@@ -255,17 +255,11 @@ export class DebugTools implements ToolExecutor {
private async executeScript(script: string): Promise<ToolResponse> {
return new Promise((resolve) => {
Editor.Message.request('scene', 'execute-scene-script', {
name: 'console',
method: 'eval',
name: 'cocos-mcp-server',
method: 'executeScript',
args: [script]
}).then((result: any) => {
resolve({
success: true,
data: {
result: result,
message: 'Script executed successfully'
}
});
resolve(result);
}).catch((err: Error) => {
resolve({ success: false, error: err.message });
});
@@ -274,52 +268,69 @@ export class DebugTools implements ToolExecutor {
private async getNodeTree(rootUuid?: string, maxDepth: number = 10): Promise<ToolResponse> {
return new Promise((resolve) => {
const buildTree = async (nodeUuid: string, depth: number = 0): Promise<any> => {
const mapTree = (node: any, depth: number = 0): any => {
if (depth >= maxDepth) {
return { truncated: true };
}
try {
const nodeData = await Editor.Message.request('scene', 'query-node', nodeUuid);
const tree = {
uuid: nodeData.uuid,
name: nodeData.name,
active: nodeData.active,
components: (nodeData as any).components ? (nodeData as any).components.map((c: any) => c.__type__) : [],
childCount: nodeData.children ? nodeData.children.length : 0,
children: [] as any[]
};
if (nodeData.children && nodeData.children.length > 0) {
for (const childId of nodeData.children) {
const childTree = await buildTree(childId, depth + 1);
tree.children.push(childTree);
}
}
return tree;
} catch (err: any) {
return { error: err.message };
if (!node) {
return null;
}
const children = Array.isArray(node.children) ? node.children : [];
return {
uuid: node.uuid,
name: node.name,
active: node.active,
components: Array.isArray(node.components)
? node.components.map((c: any) => c.__type__ || c.type || c.cid).filter((x: any) => x)
: [],
childCount: children.length,
children: children.map((c: any) => mapTree(c, depth + 1))
};
};
if (rootUuid) {
buildTree(rootUuid).then(tree => {
resolve({ success: true, data: tree });
});
} else {
Editor.Message.request('scene', 'query-hierarchy').then(async (hierarchy: any) => {
const trees = [];
for (const rootNode of hierarchy.children) {
const tree = await buildTree(rootNode.uuid);
trees.push(tree);
const findInTree = (node: any, uuid: string): any => {
if (!node) {
return null;
}
if (node.uuid === uuid) {
return node;
}
const children = Array.isArray(node.children) ? node.children : [];
for (const child of children) {
const found = findInTree(child, uuid);
if (found) {
return found;
}
}
return null;
};
// 'query-hierarchy' 在 3.8.x 不存在,统一使用已验证可用的 'query-node-tree'
Editor.Message.request('scene', 'query-node-tree').then((tree: any) => {
if (rootUuid) {
const roots = Array.isArray(tree) ? tree : [tree];
let target: any = null;
for (const root of roots) {
target = findInTree(root, rootUuid);
if (target) {
break;
}
}
if (!target) {
resolve({ success: false, error: `Node not found: ${rootUuid}` });
return;
}
resolve({ success: true, data: mapTree(target, 0) });
} else {
const roots = Array.isArray(tree)
? tree
: (tree && Array.isArray(tree.children) ? tree.children : (tree ? [tree] : []));
const trees = roots.map((root: any) => mapTree(root, 0));
resolve({ success: true, data: trees });
}).catch((err: Error) => {
resolve({ success: false, error: err.message });
});
}
}
}).catch((err: Error) => {
resolve({ success: false, error: err.message });
});
});
}
@@ -365,8 +376,11 @@ export class DebugTools implements ToolExecutor {
// Check for performance issues
if (options.checkPerformance) {
const hierarchy = await Editor.Message.request('scene', 'query-hierarchy');
const nodeCount = this.countNodes(hierarchy.children);
const hierarchy: any = await Editor.Message.request('scene', 'query-node-tree');
const roots = Array.isArray(hierarchy)
? hierarchy
: (hierarchy && Array.isArray(hierarchy.children) ? hierarchy.children : []);
const nodeCount = this.countNodes(roots);
if (nodeCount > 1000) {
issues.push({

View File

@@ -233,20 +233,20 @@ export class PrefabTools implements ToolExecutor {
private async loadPrefab(prefabPath: string): Promise<ToolResponse> {
return new Promise((resolve) => {
Editor.Message.request('asset-db', 'query-asset-info', prefabPath).then((assetInfo: any) => {
if (!assetInfo) {
let assetInfo: any = null;
Editor.Message.request('asset-db', 'query-asset-info', prefabPath).then((info: any) => {
if (!info) {
throw new Error('Prefab not found');
}
return Editor.Message.request('scene', 'load-asset', {
uuid: assetInfo.uuid
});
}).then((prefabData: any) => {
assetInfo = info;
return Editor.Message.request('scene', 'open-scene', info.uuid);
}).then(() => {
resolve({
success: true,
data: {
uuid: prefabData.uuid,
name: prefabData.name,
uuid: assetInfo.uuid,
name: assetInfo.name,
message: 'Prefab loaded successfully'
}
});