- **完全修复预制体创建功能**: 彻底解决了预制体创建时组件/节点/资源类型引用丢失的问题
- **正确的引用处理**: 实现了与手动创建预制体完全一致的引用格式
- **内部引用**: 预制体内部的节点和组件引用正确转换为 `{"__id__": x}` 格式
- **外部引用**: 预制体外部的节点和组件引用正确设置为 `null`
- **资源引用**: 预制体、纹理、精灵帧等资源引用完整保留UUID格式
This commit is contained in:
@@ -1,308 +0,0 @@
|
||||
import { PrefabTools } from '../tools/prefab-tools';
|
||||
|
||||
/**
|
||||
* 预制体实例化使用示例
|
||||
* 展示如何在实际项目中使用预制体工具
|
||||
*/
|
||||
export class PrefabInstantiationExample {
|
||||
private prefabTools: PrefabTools;
|
||||
|
||||
constructor() {
|
||||
this.prefabTools = new PrefabTools();
|
||||
}
|
||||
|
||||
/**
|
||||
* 示例1: 基本预制体实例化
|
||||
*/
|
||||
async basicInstantiationExample() {
|
||||
console.log('=== 基本预制体实例化示例 ===');
|
||||
|
||||
try {
|
||||
const result = await this.prefabTools.execute('instantiate_prefab', {
|
||||
prefabPath: 'db://assets/prefabs/Player.prefab',
|
||||
position: { x: 0, y: 0, z: 0 }
|
||||
});
|
||||
|
||||
if (result.success) {
|
||||
console.log('✅ 预制体实例化成功');
|
||||
console.log(`节点UUID: ${result.data.nodeUuid}`);
|
||||
console.log(`节点名称: ${result.data.name}`);
|
||||
console.log('使用的API: create-node with assetUuid');
|
||||
} else {
|
||||
console.log('❌ 预制体实例化失败');
|
||||
console.log(`错误: ${result.error}`);
|
||||
if (result.instruction) {
|
||||
console.log(`建议: ${result.instruction}`);
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('实例化过程中发生错误:', error);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 示例2: 在指定父节点下实例化预制体
|
||||
*/
|
||||
async instantiateWithParentExample() {
|
||||
console.log('=== 在父节点下实例化预制体示例 ===');
|
||||
|
||||
try {
|
||||
const result = await this.prefabTools.execute('instantiate_prefab', {
|
||||
prefabPath: 'db://assets/prefabs/Enemy.prefab',
|
||||
parentUuid: 'canvas-uuid-here',
|
||||
position: { x: 100, y: 200, z: 0 }
|
||||
});
|
||||
|
||||
if (result.success) {
|
||||
console.log('✅ 在父节点下实例化成功');
|
||||
console.log(`节点UUID: ${result.data.nodeUuid}`);
|
||||
} else {
|
||||
console.log('❌ 实例化失败');
|
||||
console.log(`错误: ${result.error}`);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('实例化过程中发生错误:', error);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 示例3: 批量实例化预制体
|
||||
*/
|
||||
async batchInstantiationExample() {
|
||||
console.log('=== 批量实例化预制体示例 ===');
|
||||
|
||||
const prefabPaths = [
|
||||
'db://assets/prefabs/Item1.prefab',
|
||||
'db://assets/prefabs/Item2.prefab',
|
||||
'db://assets/prefabs/Item3.prefab'
|
||||
];
|
||||
|
||||
const positions = [
|
||||
{ x: 0, y: 0, z: 0 },
|
||||
{ x: 100, y: 0, z: 0 },
|
||||
{ x: 200, y: 0, z: 0 }
|
||||
];
|
||||
|
||||
const results = [];
|
||||
|
||||
for (let i = 0; i < prefabPaths.length; i++) {
|
||||
try {
|
||||
const result = await this.prefabTools.execute('instantiate_prefab', {
|
||||
prefabPath: prefabPaths[i],
|
||||
position: positions[i]
|
||||
});
|
||||
|
||||
results.push({
|
||||
index: i,
|
||||
prefabPath: prefabPaths[i],
|
||||
success: result.success,
|
||||
data: result.data,
|
||||
error: result.error
|
||||
});
|
||||
|
||||
if (result.success) {
|
||||
console.log(`✅ 预制体 ${i + 1} 实例化成功`);
|
||||
} else {
|
||||
console.log(`❌ 预制体 ${i + 1} 实例化失败: ${result.error}`);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(`预制体 ${i + 1} 实例化时发生错误:`, error);
|
||||
results.push({
|
||||
index: i,
|
||||
prefabPath: prefabPaths[i],
|
||||
success: false,
|
||||
error: error instanceof Error ? error.message : String(error)
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
const successCount = results.filter(r => r.success).length;
|
||||
console.log(`批量实例化完成: ${successCount}/${results.length} 成功`);
|
||||
|
||||
return results;
|
||||
}
|
||||
|
||||
/**
|
||||
* 示例4: 错误处理和重试机制
|
||||
*/
|
||||
async instantiationWithRetryExample() {
|
||||
console.log('=== 带重试机制的实例化示例 ===');
|
||||
|
||||
const maxRetries = 3;
|
||||
let attempt = 0;
|
||||
|
||||
while (attempt < maxRetries) {
|
||||
try {
|
||||
const result = await this.prefabTools.execute('instantiate_prefab', {
|
||||
prefabPath: 'db://assets/prefabs/ComplexPrefab.prefab',
|
||||
position: { x: 0, y: 0, z: 0 }
|
||||
});
|
||||
|
||||
if (result.success) {
|
||||
console.log(`✅ 预制体实例化成功 (尝试 ${attempt + 1})`);
|
||||
return result;
|
||||
} else {
|
||||
console.log(`❌ 尝试 ${attempt + 1} 失败: ${result.error}`);
|
||||
attempt++;
|
||||
|
||||
if (attempt < maxRetries) {
|
||||
console.log(`等待 1 秒后重试...`);
|
||||
await this.delay(1000);
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(`尝试 ${attempt + 1} 时发生错误:`, error);
|
||||
attempt++;
|
||||
|
||||
if (attempt < maxRetries) {
|
||||
console.log(`等待 1 秒后重试...`);
|
||||
await this.delay(1000);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
console.log('❌ 所有重试都失败了');
|
||||
return { success: false, error: '达到最大重试次数' };
|
||||
}
|
||||
|
||||
/**
|
||||
* 示例5: 预制体实例化前的验证
|
||||
*/
|
||||
async instantiationWithValidationExample() {
|
||||
console.log('=== 带验证的实例化示例 ===');
|
||||
|
||||
const prefabPath = 'db://assets/prefabs/ValidatedPrefab.prefab';
|
||||
|
||||
try {
|
||||
// 首先验证预制体
|
||||
const validationResult = await this.prefabTools.execute('validate_prefab', {
|
||||
prefabPath: prefabPath
|
||||
});
|
||||
|
||||
if (validationResult.success && validationResult.data.isValid) {
|
||||
console.log('✅ 预制体验证通过');
|
||||
console.log(`节点数量: ${validationResult.data.nodeCount}`);
|
||||
console.log(`组件数量: ${validationResult.data.componentCount}`);
|
||||
|
||||
// 验证通过后实例化
|
||||
const instantiationResult = await this.prefabTools.execute('instantiate_prefab', {
|
||||
prefabPath: prefabPath,
|
||||
position: { x: 0, y: 0, z: 0 }
|
||||
});
|
||||
|
||||
if (instantiationResult.success) {
|
||||
console.log('✅ 预制体实例化成功');
|
||||
return instantiationResult;
|
||||
} else {
|
||||
console.log('❌ 预制体实例化失败:', instantiationResult.error);
|
||||
return instantiationResult;
|
||||
}
|
||||
} else {
|
||||
console.log('❌ 预制体验证失败');
|
||||
if (validationResult.data && validationResult.data.issues) {
|
||||
console.log('问题列表:');
|
||||
validationResult.data.issues.forEach((issue: string, index: number) => {
|
||||
console.log(` ${index + 1}. ${issue}`);
|
||||
});
|
||||
}
|
||||
return validationResult;
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('验证和实例化过程中发生错误:', error);
|
||||
return { success: false, error: error instanceof Error ? error.message : String(error) };
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 示例6: API参数构建示例
|
||||
*/
|
||||
demonstrateAPIParameters() {
|
||||
console.log('=== API参数构建示例 ===');
|
||||
|
||||
// 模拟从asset-db获取的预制体信息
|
||||
const assetInfo = {
|
||||
uuid: 'prefab-uuid-123',
|
||||
name: 'PlayerCharacter'
|
||||
};
|
||||
|
||||
// 基本实例化参数
|
||||
const basicOptions = {
|
||||
assetUuid: assetInfo.uuid,
|
||||
name: assetInfo.name
|
||||
};
|
||||
console.log('基本实例化参数:', JSON.stringify(basicOptions, null, 2));
|
||||
|
||||
// 带父节点的实例化参数
|
||||
const withParentOptions = {
|
||||
assetUuid: assetInfo.uuid,
|
||||
name: assetInfo.name,
|
||||
parent: 'canvas-uuid-456'
|
||||
};
|
||||
console.log('带父节点参数:', JSON.stringify(withParentOptions, null, 2));
|
||||
|
||||
// 带位置设置的实例化参数
|
||||
const withPositionOptions = {
|
||||
assetUuid: assetInfo.uuid,
|
||||
name: assetInfo.name,
|
||||
dump: {
|
||||
position: { x: 100, y: 200, z: 0 }
|
||||
}
|
||||
};
|
||||
console.log('带位置参数:', JSON.stringify(withPositionOptions, null, 2));
|
||||
|
||||
// 完整实例化参数
|
||||
const fullOptions = {
|
||||
assetUuid: assetInfo.uuid,
|
||||
name: assetInfo.name,
|
||||
parent: 'canvas-uuid-456',
|
||||
dump: {
|
||||
position: { x: 100, y: 200, z: 0 }
|
||||
},
|
||||
keepWorldTransform: false,
|
||||
unlinkPrefab: false
|
||||
};
|
||||
console.log('完整参数:', JSON.stringify(fullOptions, null, 2));
|
||||
|
||||
console.log('这些参数将传递给 Editor.Message.request("scene", "create-node", options)');
|
||||
}
|
||||
|
||||
/**
|
||||
* 延迟函数
|
||||
*/
|
||||
private delay(ms: number): Promise<void> {
|
||||
return new Promise(resolve => setTimeout(resolve, ms));
|
||||
}
|
||||
|
||||
/**
|
||||
* 运行所有示例
|
||||
*/
|
||||
async runAllExamples() {
|
||||
console.log('🚀 开始运行预制体实例化示例...\n');
|
||||
|
||||
await this.basicInstantiationExample();
|
||||
console.log('');
|
||||
|
||||
await this.instantiateWithParentExample();
|
||||
console.log('');
|
||||
|
||||
await this.batchInstantiationExample();
|
||||
console.log('');
|
||||
|
||||
await this.instantiationWithRetryExample();
|
||||
console.log('');
|
||||
|
||||
await this.instantiationWithValidationExample();
|
||||
console.log('');
|
||||
|
||||
this.demonstrateAPIParameters();
|
||||
console.log('');
|
||||
|
||||
console.log('🎉 所有示例运行完成!');
|
||||
}
|
||||
}
|
||||
|
||||
// 如果直接运行此文件
|
||||
if (typeof module !== 'undefined' && module.exports) {
|
||||
const example = new PrefabInstantiationExample();
|
||||
example.runAllExamples();
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,11 +1,13 @@
|
||||
import { ToolDefinition, ToolResponse, ToolExecutor, NodeInfo } from '../types';
|
||||
import { ComponentTools } from './component-tools';
|
||||
|
||||
export class NodeTools implements ToolExecutor {
|
||||
private componentTools = new ComponentTools();
|
||||
getTools(): ToolDefinition[] {
|
||||
return [
|
||||
{
|
||||
name: 'create_node',
|
||||
description: 'Create a new node in the scene. IMPORTANT: You should always provide parentUuid to specify where to create the node. If parentUuid is not provided, the node will be created at the scene root.',
|
||||
description: 'Create a new node in the scene. Supports creating empty nodes, nodes with components, or instantiating from assets (prefabs, etc.). IMPORTANT: You should always provide parentUuid to specify where to create the node.',
|
||||
inputSchema: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
@@ -27,6 +29,59 @@ export class NodeTools implements ToolExecutor {
|
||||
type: 'number',
|
||||
description: 'Sibling index for ordering (-1 means append at end)',
|
||||
default: -1
|
||||
},
|
||||
assetUuid: {
|
||||
type: 'string',
|
||||
description: 'Asset UUID to instantiate from (e.g., prefab UUID). When provided, creates a node instance from the asset instead of an empty node.'
|
||||
},
|
||||
assetPath: {
|
||||
type: 'string',
|
||||
description: 'Asset path to instantiate from (e.g., "db://assets/prefabs/MyPrefab.prefab"). Alternative to assetUuid.'
|
||||
},
|
||||
components: {
|
||||
type: 'array',
|
||||
items: { type: 'string' },
|
||||
description: 'Array of component type names to add to the new node (e.g., ["cc.Sprite", "cc.Button"])'
|
||||
},
|
||||
unlinkPrefab: {
|
||||
type: 'boolean',
|
||||
description: 'If true and creating from prefab, unlink from prefab to create a regular node',
|
||||
default: false
|
||||
},
|
||||
keepWorldTransform: {
|
||||
type: 'boolean',
|
||||
description: 'Whether to keep world transform when creating the node',
|
||||
default: false
|
||||
},
|
||||
initialTransform: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
position: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
x: { type: 'number' },
|
||||
y: { type: 'number' },
|
||||
z: { type: 'number' }
|
||||
}
|
||||
},
|
||||
rotation: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
x: { type: 'number' },
|
||||
y: { type: 'number' },
|
||||
z: { type: 'number' }
|
||||
}
|
||||
},
|
||||
scale: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
x: { type: 'number' },
|
||||
y: { type: 'number' },
|
||||
z: { type: 'number' }
|
||||
}
|
||||
}
|
||||
},
|
||||
description: 'Initial transform to apply to the created node'
|
||||
}
|
||||
},
|
||||
required: ['name']
|
||||
@@ -89,7 +144,7 @@ export class NodeTools implements ToolExecutor {
|
||||
},
|
||||
{
|
||||
name: 'set_node_property',
|
||||
description: 'Set node property value (prefer using set_node_transform for position/rotation/scale)',
|
||||
description: 'Set node property value (prefer using set_node_transform for active/layer/mobility/position/rotation/scale)',
|
||||
inputSchema: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
@@ -253,150 +308,190 @@ export class NodeTools implements ToolExecutor {
|
||||
|
||||
private async createNode(args: any): Promise<ToolResponse> {
|
||||
return new Promise(async (resolve) => {
|
||||
let targetParentUuid = args.parentUuid;
|
||||
|
||||
// 如果没有提供父节点UUID,获取场景根节点
|
||||
if (!targetParentUuid) {
|
||||
try {
|
||||
const sceneInfo = await Editor.Message.request('scene', 'query-node-tree');
|
||||
if (sceneInfo && typeof sceneInfo === 'object' && !Array.isArray(sceneInfo) && Object.prototype.hasOwnProperty.call(sceneInfo, 'uuid')) {
|
||||
targetParentUuid = (sceneInfo as any).uuid;
|
||||
console.log(`No parent specified, using scene root: ${targetParentUuid}`);
|
||||
} else if (Array.isArray(sceneInfo) && sceneInfo.length > 0 && sceneInfo[0].uuid) {
|
||||
// 如果返回的是数组,使用第一个元素(通常是场景根节点)
|
||||
targetParentUuid = sceneInfo[0].uuid;
|
||||
console.log(`No parent specified, using scene root: ${targetParentUuid}`);
|
||||
} else {
|
||||
// 备用方案:尝试获取当前场景
|
||||
const currentScene = await Editor.Message.request('scene', 'query-current-scene');
|
||||
if (currentScene && currentScene.uuid) {
|
||||
targetParentUuid = currentScene.uuid;
|
||||
try {
|
||||
let targetParentUuid = args.parentUuid;
|
||||
|
||||
// 如果没有提供父节点UUID,获取场景根节点
|
||||
if (!targetParentUuid) {
|
||||
try {
|
||||
const sceneInfo = await Editor.Message.request('scene', 'query-node-tree');
|
||||
if (sceneInfo && typeof sceneInfo === 'object' && !Array.isArray(sceneInfo) && Object.prototype.hasOwnProperty.call(sceneInfo, 'uuid')) {
|
||||
targetParentUuid = (sceneInfo as any).uuid;
|
||||
console.log(`No parent specified, using scene root: ${targetParentUuid}`);
|
||||
} else if (Array.isArray(sceneInfo) && sceneInfo.length > 0 && sceneInfo[0].uuid) {
|
||||
targetParentUuid = sceneInfo[0].uuid;
|
||||
console.log(`No parent specified, using scene root: ${targetParentUuid}`);
|
||||
} else {
|
||||
const currentScene = await Editor.Message.request('scene', 'query-current-scene');
|
||||
if (currentScene && currentScene.uuid) {
|
||||
targetParentUuid = currentScene.uuid;
|
||||
}
|
||||
}
|
||||
} catch (err) {
|
||||
console.warn('Failed to get scene root, will use default behavior');
|
||||
}
|
||||
} catch (err) {
|
||||
console.warn('Failed to get scene root, will use default behavior');
|
||||
}
|
||||
}
|
||||
|
||||
// 如果指定了父节点,先验证父节点是否存在
|
||||
if (targetParentUuid) {
|
||||
try {
|
||||
const parentNode = await Editor.Message.request('scene', 'query-node', targetParentUuid);
|
||||
if (!parentNode) {
|
||||
// 如果提供了assetPath,先解析为assetUuid
|
||||
let finalAssetUuid = args.assetUuid;
|
||||
if (args.assetPath && !finalAssetUuid) {
|
||||
try {
|
||||
const assetInfo = await Editor.Message.request('asset-db', 'query-asset-info', args.assetPath);
|
||||
if (assetInfo && assetInfo.uuid) {
|
||||
finalAssetUuid = assetInfo.uuid;
|
||||
console.log(`Asset path '${args.assetPath}' resolved to UUID: ${finalAssetUuid}`);
|
||||
} else {
|
||||
resolve({
|
||||
success: false,
|
||||
error: `Asset not found at path: ${args.assetPath}`
|
||||
});
|
||||
return;
|
||||
}
|
||||
} catch (err) {
|
||||
resolve({
|
||||
success: false,
|
||||
error: `Parent node with UUID '${targetParentUuid}' not found`
|
||||
error: `Failed to resolve asset path '${args.assetPath}': ${err}`
|
||||
});
|
||||
return;
|
||||
}
|
||||
} catch (err) {
|
||||
resolve({
|
||||
success: false,
|
||||
error: `Failed to verify parent node: ${err}`
|
||||
});
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
const nodeData: any = {
|
||||
name: args.name,
|
||||
type: args.nodeType || 'cc.Node'
|
||||
};
|
||||
|
||||
// 使用正确的create-node API参数结构
|
||||
if (targetParentUuid) {
|
||||
const createNodeOptions = {
|
||||
parent: targetParentUuid,
|
||||
name: args.name,
|
||||
components: args.nodeType && args.nodeType !== 'Node' ? [args.nodeType] : undefined
|
||||
// 构建create-node选项
|
||||
const createNodeOptions: any = {
|
||||
name: args.name
|
||||
};
|
||||
|
||||
Editor.Message.request('scene', 'create-node', createNodeOptions).then((nodeUuid: any) => {
|
||||
// 如果需要设置特定的兄弟索引,使用set-parent API
|
||||
// 添加延迟以避免内部状态竞争
|
||||
if (args.siblingIndex !== undefined && args.siblingIndex >= 0 && nodeUuid) {
|
||||
setTimeout(() => {
|
||||
Editor.Message.request('scene', 'set-parent', {
|
||||
parent: targetParentUuid,
|
||||
uuids: [nodeUuid],
|
||||
keepWorldTransform: false
|
||||
}).then(() => {
|
||||
resolve({
|
||||
success: true,
|
||||
data: {
|
||||
uuid: nodeUuid,
|
||||
name: args.name,
|
||||
parentUuid: targetParentUuid,
|
||||
message: args.parentUuid
|
||||
? `Node '${args.name}' created under specified parent`
|
||||
: `Node '${args.name}' created at scene root (no parent specified)`
|
||||
}
|
||||
});
|
||||
}).catch(() => {
|
||||
// 即使移动失败,节点已创建,返回成功但带警告
|
||||
resolve({
|
||||
success: true,
|
||||
data: {
|
||||
uuid: nodeUuid,
|
||||
name: args.name,
|
||||
message: `Node '${args.name}' created but may not be under intended parent`,
|
||||
warning: 'Failed to move node to specified parent'
|
||||
}
|
||||
});
|
||||
});
|
||||
}, 100); // 100ms延迟
|
||||
} else {
|
||||
// Get complete node info for verification
|
||||
this.getNodeInfo(nodeUuid).then((nodeInfo) => {
|
||||
resolve({
|
||||
success: true,
|
||||
data: {
|
||||
uuid: nodeUuid,
|
||||
name: args.name,
|
||||
message: `Node '${args.name}' created successfully`
|
||||
},
|
||||
verificationData: {
|
||||
nodeInfo: nodeInfo.data,
|
||||
creationDetails: {
|
||||
parentUuid: targetParentUuid,
|
||||
nodeType: args.nodeType || 'Node',
|
||||
timestamp: new Date().toISOString()
|
||||
}
|
||||
}
|
||||
});
|
||||
}).catch(() => {
|
||||
resolve({
|
||||
success: true,
|
||||
data: {
|
||||
uuid: nodeUuid,
|
||||
name: args.name,
|
||||
message: `Node '${args.name}' created successfully (verification failed)`
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// 设置父节点
|
||||
if (targetParentUuid) {
|
||||
createNodeOptions.parent = targetParentUuid;
|
||||
}
|
||||
|
||||
// 从资源实例化
|
||||
if (finalAssetUuid) {
|
||||
createNodeOptions.assetUuid = finalAssetUuid;
|
||||
if (args.unlinkPrefab) {
|
||||
createNodeOptions.unlinkPrefab = true;
|
||||
}
|
||||
}).catch((err: Error) => {
|
||||
resolve({ success: false, error: err.message });
|
||||
});
|
||||
} else {
|
||||
// 没有找到场景根节点,使用默认行为(创建在场景根节点)
|
||||
const createNodeOptions = {
|
||||
name: args.name,
|
||||
components: args.nodeType && args.nodeType !== 'Node' ? [args.nodeType] : undefined
|
||||
};
|
||||
|
||||
Editor.Message.request('scene', 'create-node', createNodeOptions).then((result: any) => {
|
||||
resolve({
|
||||
success: true,
|
||||
data: {
|
||||
uuid: result,
|
||||
name: args.name,
|
||||
message: `Node '${args.name}' created at default location (scene root not found)`,
|
||||
warning: 'Could not determine scene root, node created at default location'
|
||||
}
|
||||
|
||||
// 添加组件
|
||||
if (args.components && args.components.length > 0) {
|
||||
createNodeOptions.components = args.components;
|
||||
} else if (args.nodeType && args.nodeType !== 'Node' && !finalAssetUuid) {
|
||||
// 只有在不从资源实例化时才添加nodeType组件
|
||||
createNodeOptions.components = [args.nodeType];
|
||||
}
|
||||
|
||||
// 保持世界变换
|
||||
if (args.keepWorldTransform) {
|
||||
createNodeOptions.keepWorldTransform = true;
|
||||
}
|
||||
|
||||
// 不使用dump参数处理初始变换,创建后使用set_node_transform设置
|
||||
|
||||
console.log('Creating node with options:', createNodeOptions);
|
||||
|
||||
// 创建节点
|
||||
const nodeUuid = await Editor.Message.request('scene', 'create-node', createNodeOptions);
|
||||
const uuid = Array.isArray(nodeUuid) ? nodeUuid[0] : nodeUuid;
|
||||
|
||||
// 处理兄弟索引
|
||||
if (args.siblingIndex !== undefined && args.siblingIndex >= 0 && uuid && targetParentUuid) {
|
||||
try {
|
||||
await new Promise(resolve => setTimeout(resolve, 100)); // 等待内部状态更新
|
||||
await Editor.Message.request('scene', 'set-parent', {
|
||||
parent: targetParentUuid,
|
||||
uuids: [uuid],
|
||||
keepWorldTransform: args.keepWorldTransform || false
|
||||
});
|
||||
} catch (err) {
|
||||
console.warn('Failed to set sibling index:', err);
|
||||
}
|
||||
}
|
||||
|
||||
// 添加组件(如果提供的话)
|
||||
if (args.components && args.components.length > 0 && uuid) {
|
||||
try {
|
||||
await new Promise(resolve => setTimeout(resolve, 100)); // 等待节点创建完成
|
||||
for (const componentType of args.components) {
|
||||
try {
|
||||
const result = await this.componentTools.execute('add_component', {
|
||||
nodeUuid: uuid,
|
||||
componentType: componentType
|
||||
});
|
||||
if (result.success) {
|
||||
console.log(`Component ${componentType} added successfully`);
|
||||
} else {
|
||||
console.warn(`Failed to add component ${componentType}:`, result.error);
|
||||
}
|
||||
} catch (err) {
|
||||
console.warn(`Failed to add component ${componentType}:`, err);
|
||||
}
|
||||
}
|
||||
});
|
||||
}).catch((err: Error) => {
|
||||
resolve({ success: false, error: err.message });
|
||||
} catch (err) {
|
||||
console.warn('Failed to add components:', err);
|
||||
}
|
||||
}
|
||||
|
||||
// 设置初始变换(如果提供的话)
|
||||
if (args.initialTransform && uuid) {
|
||||
try {
|
||||
await new Promise(resolve => setTimeout(resolve, 150)); // 等待节点和组件创建完成
|
||||
await this.setNodeTransform({
|
||||
uuid: uuid,
|
||||
position: args.initialTransform.position,
|
||||
rotation: args.initialTransform.rotation,
|
||||
scale: args.initialTransform.scale
|
||||
});
|
||||
console.log('Initial transform applied successfully');
|
||||
} catch (err) {
|
||||
console.warn('Failed to set initial transform:', err);
|
||||
}
|
||||
}
|
||||
|
||||
// 获取创建后的节点信息进行验证
|
||||
let verificationData: any = null;
|
||||
try {
|
||||
const nodeInfo = await this.getNodeInfo(uuid);
|
||||
if (nodeInfo.success) {
|
||||
verificationData = {
|
||||
nodeInfo: nodeInfo.data,
|
||||
creationDetails: {
|
||||
parentUuid: targetParentUuid,
|
||||
nodeType: args.nodeType || 'Node',
|
||||
fromAsset: !!finalAssetUuid,
|
||||
assetUuid: finalAssetUuid,
|
||||
assetPath: args.assetPath,
|
||||
timestamp: new Date().toISOString()
|
||||
}
|
||||
};
|
||||
}
|
||||
} catch (err) {
|
||||
console.warn('Failed to get verification data:', err);
|
||||
}
|
||||
|
||||
const successMessage = finalAssetUuid
|
||||
? `Node '${args.name}' instantiated from asset successfully`
|
||||
: `Node '${args.name}' created successfully`;
|
||||
|
||||
resolve({
|
||||
success: true,
|
||||
data: {
|
||||
uuid: uuid,
|
||||
name: args.name,
|
||||
parentUuid: targetParentUuid,
|
||||
nodeType: args.nodeType || 'Node',
|
||||
fromAsset: !!finalAssetUuid,
|
||||
assetUuid: finalAssetUuid,
|
||||
message: successMessage
|
||||
},
|
||||
verificationData: verificationData
|
||||
});
|
||||
|
||||
} catch (err: any) {
|
||||
resolve({
|
||||
success: false,
|
||||
error: `Failed to create node: ${err.message}. Args: ${JSON.stringify(args)}`
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user