cocos2d-cli 1.0.4 → 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,12 +1,129 @@
1
1
  /**
2
- * get 命令 - 获取节点信息
2
+ * get 命令 - 获取节点信息
3
+ * 返回与编辑器 Inspector 面板一致的所有属性
3
4
  */
4
5
 
5
6
  const { loadScene, buildMaps, findNodeIndex } = require('../lib/fire-utils');
6
7
 
8
+ /**
9
+ * 将 _color 对象转为 #RRGGBB 字符串
10
+ */
11
+ function colorToHex(color) {
12
+ if (!color) return '#ffffff';
13
+ const r = (color.r || 0).toString(16).padStart(2, '0');
14
+ const g = (color.g || 0).toString(16).padStart(2, '0');
15
+ const b = (color.b || 0).toString(16).padStart(2, '0');
16
+ return `#${r}${g}${b}`;
17
+ }
18
+
19
+ /**
20
+ * 提取组件的关键属性(对应 Inspector 面板显示)
21
+ */
22
+ function extractComponentProps(comp) {
23
+ if (!comp) return null;
24
+ const type = comp.__type__;
25
+
26
+ // 只在 disabled 时才输出 enabled 字段
27
+ const base = comp._enabled ? { type } : { type, enabled: false };
28
+
29
+ // 清理对象中的 __type__ 字段
30
+ const clean = (obj) => {
31
+ if (!obj || typeof obj !== 'object') return obj;
32
+ if (Array.isArray(obj)) return obj.map(clean);
33
+ const result = {};
34
+ for (const [k, v] of Object.entries(obj)) {
35
+ if (k === '__type__') continue;
36
+ result[k] = typeof v === 'object' ? clean(v) : v;
37
+ }
38
+ return result;
39
+ };
40
+
41
+ switch (type) {
42
+ case 'cc.Sprite':
43
+ return {
44
+ ...base,
45
+ spriteFrame: comp._spriteFrame?.__uuid__ || null,
46
+ sizeMode: ['CUSTOM', 'TRIMMED', 'RAW'][comp._sizeMode] || comp._sizeMode,
47
+ spriteType: ['SIMPLE', 'SLICED', 'TILED', 'FILLED', 'MESH'][comp._type] || comp._type,
48
+ trim: comp._isTrimmedMode
49
+ };
50
+ case 'cc.Label':
51
+ return {
52
+ ...base,
53
+ string: comp._string,
54
+ fontSize: comp._fontSize,
55
+ lineHeight: comp._lineHeight,
56
+ horizontalAlign: ['LEFT', 'CENTER', 'RIGHT'][comp._N$horizontalAlign] || comp._N$horizontalAlign,
57
+ verticalAlign: ['TOP', 'CENTER', 'BOTTOM'][comp._N$verticalAlign] || comp._N$verticalAlign,
58
+ overflow: ['NONE', 'CLAMP', 'SHRINK', 'RESIZE_HEIGHT'][comp._N$overflow] || comp._N$overflow,
59
+ fontFamily: comp._N$fontFamily,
60
+ enableWrapText: comp._enableWrapText
61
+ };
62
+ case 'cc.Button':
63
+ return {
64
+ ...base,
65
+ interactable: comp._N$interactable,
66
+ transition: ['NONE', 'COLOR', 'SPRITE', 'SCALE'][comp._N$transition] || comp._N$transition,
67
+ zoomScale: comp.zoomScale,
68
+ duration: comp.duration
69
+ };
70
+ case 'cc.Widget':
71
+ return {
72
+ ...base,
73
+ alignMode: ['ONCE', 'ON_WINDOW_RESIZE', 'ALWAYS'][comp.alignMode] || comp.alignMode,
74
+ left: comp._left,
75
+ right: comp._right,
76
+ top: comp._top,
77
+ bottom: comp._bottom
78
+ };
79
+ case 'cc.Layout':
80
+ return {
81
+ ...base,
82
+ layoutType: ['NONE', 'HORIZONTAL', 'VERTICAL', 'GRID'][comp._N$layoutType] || comp._N$layoutType,
83
+ spacingX: comp._N$spacingX,
84
+ spacingY: comp._N$spacingY,
85
+ paddingLeft: comp._N$paddingLeft,
86
+ paddingRight: comp._N$paddingRight,
87
+ paddingTop: comp._N$paddingTop,
88
+ paddingBottom: comp._N$paddingBottom
89
+ };
90
+ case 'cc.Canvas':
91
+ return {
92
+ ...base,
93
+ designResolution: clean(comp._designResolution),
94
+ fitWidth: comp._fitWidth,
95
+ fitHeight: comp._fitHeight
96
+ };
97
+ case 'cc.Camera':
98
+ return {
99
+ ...base,
100
+ depth: comp._depth,
101
+ zoomRatio: comp._zoomRatio,
102
+ ortho: comp._ortho,
103
+ cullingMask: comp._cullingMask
104
+ };
105
+ case 'cc.ParticleSystem':
106
+ return {
107
+ ...base,
108
+ playOnLoad: comp.playOnLoad,
109
+ totalParticles: comp.totalParticles,
110
+ duration: comp.duration
111
+ };
112
+ default:
113
+ // 未知组件:返回去掉内部字段的原始属性
114
+ const result = { ...base };
115
+ for (const key of Object.keys(comp)) {
116
+ if (!key.startsWith('_') && key !== '__type__') {
117
+ result[key] = comp[key];
118
+ }
119
+ }
120
+ return result;
121
+ }
122
+ }
123
+
7
124
  function run(args) {
8
125
  if (args.length < 2) {
9
- console.log(JSON.stringify({ error: '用法: cocos2.4 get <场景文件路径> <节点索引|名称>' }));
126
+ console.log(JSON.stringify({ error: '用法: cocos2.4 get <场景.fire | 预制体.prefab> <节点索引|名称>' }));
10
127
  return;
11
128
  }
12
129
 
@@ -30,21 +147,41 @@ function run(args) {
30
147
  console.log(JSON.stringify({ error: `节点不存在: ${nodeRef}` }));
31
148
  return;
32
149
  }
33
-
34
- // 返回节点信息
150
+
151
+ // 从 _trs 数组解析变换属性
152
+ // 格式: [x, y, z, qx, qy, qz, qw, scaleX, scaleY, scaleZ]
153
+ const trs = node._trs?.array || [0,0,0, 0,0,0,1, 1,1,1];
154
+
155
+ // 组件详细信息
156
+ const components = (node._components || []).map(ref => {
157
+ const comp = data[ref.__id__];
158
+ return extractComponentProps(comp);
159
+ });
160
+
161
+ // 子节点名称
162
+ const children = (node._children || []).map(ref => data[ref.__id__]?._name || '(unknown)');
163
+
35
164
  const info = indexMap[idx] || {};
36
- console.log(JSON.stringify({
37
- success: true,
38
- index: idx,
39
- ...info,
40
- node: {
41
- active: node._active,
42
- position: node._trs?.array?.slice(0, 2) || [0, 0],
43
- size: node._contentSize || { width: 0, height: 0 },
44
- children: node._children?.map(c => c.__id__) || [],
45
- components: node._components?.map(c => c.__id__) || []
46
- }
47
- }, null, 2));
165
+
166
+ // 精简 JSON 输出
167
+ const result = {
168
+ name: info.name,
169
+ active: node._active,
170
+ position: { x: trs[0], y: trs[1] },
171
+ rotation: node._eulerAngles?.z ?? 0,
172
+ scale: { x: trs[7], y: trs[8] },
173
+ anchor: { x: node._anchorPoint?.x ?? 0.5, y: node._anchorPoint?.y ?? 0.5 },
174
+ size: { w: node._contentSize?.width ?? 0, h: node._contentSize?.height ?? 0 },
175
+ color: colorToHex(node._color),
176
+ opacity: node._opacity ?? 255,
177
+ group: node._groupIndex ?? 0
178
+ };
179
+
180
+ if (children.length > 0) result.children = children;
181
+ if (components.length > 0) result.components = components;
182
+
183
+ console.log(JSON.stringify(result));
184
+
48
185
  } catch (err) {
49
186
  console.log(JSON.stringify({ error: err.message }));
50
187
  }
@@ -0,0 +1,49 @@
1
+ /**
2
+ * prefab-create 命令 - 创建新预制体文件
3
+ */
4
+
5
+ const { saveScene, createPrefab } = require('../lib/fire-utils');
6
+ const fs = require('fs');
7
+ const path = require('path');
8
+
9
+ function run(args) {
10
+ if (args.length < 2) {
11
+ console.log(JSON.stringify({ error: '用法: cocos2.4 prefab-create <预制体路径> <根节点名称>' }));
12
+ return;
13
+ }
14
+
15
+ const prefabPath = args[0];
16
+ const rootName = args[1] || 'RootNode';
17
+
18
+ try {
19
+ // 检查文件是否已存在
20
+ if (fs.existsSync(prefabPath)) {
21
+ console.log(JSON.stringify({ error: `文件已存在: ${prefabPath}` }));
22
+ return;
23
+ }
24
+
25
+ // 确保目录存在
26
+ const dir = path.dirname(prefabPath);
27
+ if (!fs.existsSync(dir)) {
28
+ fs.mkdirSync(dir, { recursive: true });
29
+ }
30
+
31
+ // 创建预制体数据
32
+ const data = createPrefab(rootName);
33
+
34
+ // 保存文件
35
+ saveScene(prefabPath, data);
36
+
37
+ console.log(JSON.stringify({
38
+ success: true,
39
+ path: prefabPath,
40
+ rootName: rootName,
41
+ message: `预制体创建成功: ${rootName}`
42
+ }));
43
+
44
+ } catch (err) {
45
+ console.log(JSON.stringify({ error: err.message }));
46
+ }
47
+ }
48
+
49
+ module.exports = { run };
@@ -2,96 +2,31 @@
2
2
  * remove 命令 - 删除节点或组件
3
3
  */
4
4
 
5
- const { loadScene, saveScene, buildMaps, collectNodeAndChildren, rebuildReferences, refreshEditor, installPlugin } = require('../lib/fire-utils');
6
- const fs = require('fs');
7
- const path = require('path');
8
-
9
- // 加载脚本映射
10
- function loadScriptMap(scenePath) {
11
- const projectPath = path.dirname(path.dirname(scenePath));
12
- const mapPath = path.join(projectPath, 'data', 'script_map.json');
13
- try {
14
- if (fs.existsSync(mapPath)) {
15
- return JSON.parse(fs.readFileSync(mapPath, 'utf-8'));
16
- }
17
- } catch (e) {}
18
- return {};
19
- }
20
-
21
- // 构建树形结构
22
- function buildTree(data, scriptMap, nodeIndex, prefix = '', isLast = true, isRoot = true) {
23
- const node = data[nodeIndex];
24
- if (!node) return '';
25
-
26
- const nodeName = isRoot ? 'Root' : (node._name || '(unnamed)');
27
- const active = node._active !== false ? '●' : '○';
28
- const uuidRegex = /^[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}$/i;
29
-
30
- let result = prefix + (isRoot ? '' : active + ' ') + nodeName + ' #' + nodeIndex;
31
-
32
- // 添加组件信息
33
- if (node._components && node._components.length > 0) {
34
- const comps = node._components.map(c => {
35
- const comp = data[c.__id__];
36
- if (!comp) return `? #${c.__id__}`;
37
- const typeName = comp.__type__;
38
- let displayName;
39
- if (uuidRegex.test(typeName)) {
40
- const scriptInfo = scriptMap[typeName];
41
- if (scriptInfo && scriptInfo.name) {
42
- displayName = scriptInfo.name;
43
- } else {
44
- displayName = '⚠️MissingScript';
45
- }
46
- } else if (typeName === 'MissingScript') {
47
- displayName = '⚠️MissingScript';
48
- } else {
49
- displayName = typeName.replace('cc.', '');
50
- }
51
- return `${displayName} #${c.__id__}`;
52
- }).join(', ');
53
- result += ` (${comps})`;
54
- }
55
-
56
- result += '\n';
57
-
58
- // 处理子节点
59
- if (node._children && node._children.length > 0) {
60
- node._children.forEach((childRef, idx) => {
61
- const childIsLast = idx === node._children.length - 1;
62
- const childPrefix = prefix + (isRoot ? '' : (isLast ? ' ' : '│ '));
63
- result += buildTree(data, scriptMap, childRef.__id__, childPrefix, childIsLast, false);
64
- });
65
- }
66
-
67
- return result;
68
- }
5
+ const { loadScene, saveScene, collectNodeAndChildren, rebuildReferences, refreshEditor, loadScriptMap, buildTree } = require('../lib/fire-utils');
69
6
 
70
7
  function run(args) {
71
8
  if (args.length < 2) {
72
- console.log('用法: cocos2.4 remove <场景文件路径> <索引>');
9
+ console.log(JSON.stringify({ error: '用法: cocos2.4 remove <场景文件路径> <索引>' }));
73
10
  return;
74
11
  }
75
12
 
76
13
  const scenePath = args[0];
77
14
 
78
- // 安装 CLI Helper 插件(如果不存在)
79
- installPlugin(scenePath);
80
-
81
- const index = parseInt(args[1]);
82
-
83
- if (isNaN(index)) {
84
- console.log('错误: 索引必须是数字');
15
+ // 索引必须是数字
16
+ if (!/^\d+$/.test(args[1])) {
17
+ console.log(JSON.stringify({ error: '索引必须是数字,请先用 tree 命令查看节点索引' }));
85
18
  return;
86
19
  }
87
20
 
21
+ const index = parseInt(args[1]);
22
+
88
23
  try {
89
24
  let data = loadScene(scenePath);
90
25
  const scriptMap = loadScriptMap(scenePath);
91
26
 
92
27
  // 检查索引是否存在
93
28
  if (!data[index]) {
94
- console.log(`错误: 索引 ${index} 不存在`);
29
+ console.log(JSON.stringify({ error: `索引 ${index} 不存在` }));
95
30
  return;
96
31
  }
97
32
 
@@ -103,7 +38,7 @@ function run(args) {
103
38
  const isComponent = item.node !== undefined;
104
39
 
105
40
  if (isNode && index <= 1) {
106
- console.log('错误: 不能删除根节点');
41
+ console.log(JSON.stringify({ error: '不能删除根节点' }));
107
42
  return;
108
43
  }
109
44
 
@@ -156,8 +91,8 @@ function run(args) {
156
91
  console.log(buildTree(data, scriptMap, 1));
157
92
 
158
93
  } catch (err) {
159
- console.log(`错误: ${err.message}`);
94
+ console.log(JSON.stringify({ error: err.message }));
160
95
  }
161
96
  }
162
97
 
163
- module.exports = { run };
98
+ module.exports = { run };
@@ -1,9 +1,122 @@
1
1
  /**
2
- * set 命令 - 修改节点属性
2
+ * set 命令 - 修改节点属性
3
+ * 修改成功后返回节点最终状态(与 get 命令格式一致)
3
4
  */
4
5
 
5
6
  const { loadScene, saveScene, buildMaps, findNodeIndex, refreshEditor } = require('../lib/fire-utils');
6
7
 
8
+ /**
9
+ * 将 _color 对象转为 #RRGGBB 字符串
10
+ */
11
+ function colorToHex(color) {
12
+ if (!color) return '#ffffff';
13
+ const r = (color.r || 0).toString(16).padStart(2, '0');
14
+ const g = (color.g || 0).toString(16).padStart(2, '0');
15
+ const b = (color.b || 0).toString(16).padStart(2, '0');
16
+ return `#${r}${g}${b}`;
17
+ }
18
+
19
+ /**
20
+ * 提取组件的关键属性(对应 Inspector 面板显示)
21
+ */
22
+ function extractComponentProps(comp) {
23
+ if (!comp) return null;
24
+ const type = comp.__type__;
25
+ const base = comp._enabled ? { type } : { type, enabled: false };
26
+
27
+ const clean = (obj) => {
28
+ if (!obj || typeof obj !== 'object') return obj;
29
+ if (Array.isArray(obj)) return obj.map(clean);
30
+ const result = {};
31
+ for (const [k, v] of Object.entries(obj)) {
32
+ if (k === '__type__') continue;
33
+ result[k] = typeof v === 'object' ? clean(v) : v;
34
+ }
35
+ return result;
36
+ };
37
+
38
+ switch (type) {
39
+ case 'cc.Sprite':
40
+ return {
41
+ ...base,
42
+ spriteFrame: comp._spriteFrame?.__uuid__ || null,
43
+ sizeMode: ['CUSTOM', 'TRIMMED', 'RAW'][comp._sizeMode] || comp._sizeMode,
44
+ spriteType: ['SIMPLE', 'SLICED', 'TILED', 'FILLED', 'MESH'][comp._type] || comp._type,
45
+ trim: comp._isTrimmedMode
46
+ };
47
+ case 'cc.Label':
48
+ return {
49
+ ...base,
50
+ string: comp._string,
51
+ fontSize: comp._fontSize,
52
+ lineHeight: comp._lineHeight,
53
+ horizontalAlign: ['LEFT', 'CENTER', 'RIGHT'][comp._N$horizontalAlign] || comp._N$horizontalAlign,
54
+ verticalAlign: ['TOP', 'CENTER', 'BOTTOM'][comp._N$verticalAlign] || comp._N$verticalAlign,
55
+ overflow: ['NONE', 'CLAMP', 'SHRINK', 'RESIZE_HEIGHT'][comp._N$overflow] || comp._N$overflow,
56
+ fontFamily: comp._N$fontFamily,
57
+ enableWrapText: comp._enableWrapText
58
+ };
59
+ case 'cc.Button':
60
+ return {
61
+ ...base,
62
+ interactable: comp._N$interactable,
63
+ transition: ['NONE', 'COLOR', 'SPRITE', 'SCALE'][comp._N$transition] || comp._N$transition,
64
+ zoomScale: comp.zoomScale,
65
+ duration: comp.duration
66
+ };
67
+ case 'cc.Widget':
68
+ return {
69
+ ...base,
70
+ alignMode: ['ONCE', 'ON_WINDOW_RESIZE', 'ALWAYS'][comp.alignMode] || comp.alignMode,
71
+ left: comp._left,
72
+ right: comp._right,
73
+ top: comp._top,
74
+ bottom: comp._bottom
75
+ };
76
+ case 'cc.Layout':
77
+ return {
78
+ ...base,
79
+ layoutType: ['NONE', 'HORIZONTAL', 'VERTICAL', 'GRID'][comp._N$layoutType] || comp._N$layoutType,
80
+ spacingX: comp._N$spacingX,
81
+ spacingY: comp._N$spacingY,
82
+ paddingLeft: comp._N$paddingLeft,
83
+ paddingRight: comp._N$paddingRight,
84
+ paddingTop: comp._N$paddingTop,
85
+ paddingBottom: comp._N$paddingBottom
86
+ };
87
+ case 'cc.Canvas':
88
+ return {
89
+ ...base,
90
+ designResolution: clean(comp._designResolution),
91
+ fitWidth: comp._fitWidth,
92
+ fitHeight: comp._fitHeight
93
+ };
94
+ case 'cc.Camera':
95
+ return {
96
+ ...base,
97
+ depth: comp._depth,
98
+ zoomRatio: comp._zoomRatio,
99
+ ortho: comp._ortho,
100
+ cullingMask: comp._cullingMask
101
+ };
102
+ case 'cc.ParticleSystem':
103
+ return {
104
+ ...base,
105
+ playOnLoad: comp.playOnLoad,
106
+ totalParticles: comp.totalParticles,
107
+ duration: comp.duration
108
+ };
109
+ default:
110
+ const result = { ...base };
111
+ for (const key of Object.keys(comp)) {
112
+ if (!key.startsWith('_') && key !== '__type__') {
113
+ result[key] = comp[key];
114
+ }
115
+ }
116
+ return result;
117
+ }
118
+ }
119
+
7
120
  // 解析颜色
8
121
  function parseColor(colorStr) {
9
122
  if (!colorStr) return null;
@@ -22,9 +135,36 @@ function parseColor(colorStr) {
22
135
  return null;
23
136
  }
24
137
 
138
+ /**
139
+ * 获取节点的完整状态(与 get 命令一致)
140
+ */
141
+ function getNodeState(data, node, nodeIndex) {
142
+ const trs = node._trs?.array || [0,0,0, 0,0,0,1, 1,1,1];
143
+ const components = (node._components || []).map(ref => extractComponentProps(data[ref.__id__]));
144
+ const children = (node._children || []).map(ref => data[ref.__id__]?._name || '(unknown)');
145
+
146
+ const result = {
147
+ name: node._name,
148
+ active: node._active,
149
+ position: { x: trs[0], y: trs[1] },
150
+ rotation: node._eulerAngles?.z ?? 0,
151
+ scale: { x: trs[7], y: trs[8] },
152
+ anchor: { x: node._anchorPoint?.x ?? 0.5, y: node._anchorPoint?.y ?? 0.5 },
153
+ size: { w: node._contentSize?.width ?? 0, h: node._contentSize?.height ?? 0 },
154
+ color: colorToHex(node._color),
155
+ opacity: node._opacity ?? 255,
156
+ group: node._groupIndex ?? 0
157
+ };
158
+
159
+ if (children.length > 0) result.children = children;
160
+ if (components.length > 0) result.components = components;
161
+
162
+ return result;
163
+ }
164
+
25
165
  function run(args) {
26
166
  if (args.length < 2) {
27
- console.log(JSON.stringify({ error: '用法: cocos2.4 set <场景文件路径> <节点索引|名称> [选项]' }));
167
+ console.log(JSON.stringify({ error: '用法: cocos2.4 set <场景.fire | 预制体.prefab> <节点索引|名称> [选项]' }));
28
168
  return;
29
169
  }
30
170
 
@@ -53,20 +193,15 @@ function run(args) {
53
193
  }
54
194
 
55
195
  const node = data[nodeIndex];
56
- const changes = {};
57
196
 
58
197
  // 修改名称
59
198
  if (options.name !== undefined) {
60
- const oldName = node._name;
61
199
  node._name = options.name;
62
- changes.name = { from: oldName, to: options.name };
63
200
  }
64
201
 
65
202
  // 修改激活状态
66
203
  if (options.active !== undefined) {
67
- const oldActive = node._active;
68
204
  node._active = options.active !== 'false';
69
- changes.active = { from: oldActive, to: node._active };
70
205
  }
71
206
 
72
207
  // 修改位置
@@ -74,11 +209,8 @@ function run(args) {
74
209
  if (!node._trs) {
75
210
  node._trs = { "__type__": "TypedArray", "ctor": "Float64Array", "array": [0, 0, 0, 0, 0, 0, 1, 1, 1, 1] };
76
211
  }
77
- const oldX = node._trs.array[0];
78
- const oldY = node._trs.array[1];
79
212
  if (options.x !== undefined) node._trs.array[0] = parseFloat(options.x);
80
213
  if (options.y !== undefined) node._trs.array[1] = parseFloat(options.y);
81
- changes.position = { from: [oldX, oldY], to: [node._trs.array[0], node._trs.array[1]] };
82
214
  }
83
215
 
84
216
  // 修改大小
@@ -86,11 +218,8 @@ function run(args) {
86
218
  if (!node._contentSize) {
87
219
  node._contentSize = { "__type__": "cc.Size", width: 0, height: 0 };
88
220
  }
89
- const oldW = node._contentSize.width;
90
- const oldH = node._contentSize.height;
91
221
  if (options.width !== undefined) node._contentSize.width = parseFloat(options.width);
92
222
  if (options.height !== undefined) node._contentSize.height = parseFloat(options.height);
93
- changes.size = { from: { width: oldW, height: oldH }, to: { width: node._contentSize.width, height: node._contentSize.height } };
94
223
  }
95
224
 
96
225
  // 修改锚点
@@ -98,18 +227,13 @@ function run(args) {
98
227
  if (!node._anchorPoint) {
99
228
  node._anchorPoint = { "__type__": "cc.Vec2", x: 0.5, y: 0.5 };
100
229
  }
101
- const oldX = node._anchorPoint.x;
102
- const oldY = node._anchorPoint.y;
103
230
  if (options.anchorX !== undefined) node._anchorPoint.x = parseFloat(options.anchorX);
104
231
  if (options.anchorY !== undefined) node._anchorPoint.y = parseFloat(options.anchorY);
105
- changes.anchor = { from: [oldX, oldY], to: [node._anchorPoint.x, node._anchorPoint.y] };
106
232
  }
107
233
 
108
234
  // 修改透明度
109
235
  if (options.opacity !== undefined) {
110
- const oldOpacity = node._opacity;
111
236
  node._opacity = Math.max(0, Math.min(255, parseInt(options.opacity)));
112
- changes.opacity = { from: oldOpacity, to: node._opacity };
113
237
  }
114
238
 
115
239
  // 修改颜色
@@ -117,7 +241,6 @@ function run(args) {
117
241
  const color = parseColor(options.color);
118
242
  if (color) {
119
243
  node._color = color;
120
- changes.color = { to: options.color };
121
244
  }
122
245
  }
123
246
 
@@ -126,9 +249,7 @@ function run(args) {
126
249
  if (!node._eulerAngles) {
127
250
  node._eulerAngles = { "__type__": "cc.Vec3", x: 0, y: 0, z: 0 };
128
251
  }
129
- const oldRotation = node._eulerAngles.z;
130
252
  node._eulerAngles.z = parseFloat(options.rotation);
131
- changes.rotation = { from: oldRotation, to: node._eulerAngles.z };
132
253
  }
133
254
 
134
255
  // 修改缩放
@@ -136,25 +257,18 @@ function run(args) {
136
257
  if (!node._trs) {
137
258
  node._trs = { "__type__": "TypedArray", "ctor": "Float64Array", "array": [0, 0, 0, 0, 0, 0, 1, 1, 1, 1] };
138
259
  }
139
- const oldScaleX = node._trs.array[7];
140
- const oldScaleY = node._trs.array[8];
141
260
  if (options.scaleX !== undefined) node._trs.array[7] = parseFloat(options.scaleX);
142
261
  if (options.scaleY !== undefined) node._trs.array[8] = parseFloat(options.scaleY);
143
- changes.scale = { from: [oldScaleX, oldScaleY], to: [node._trs.array[7], node._trs.array[8]] };
144
262
  }
145
263
 
146
264
  // 保存场景
147
265
  saveScene(scenePath, data);
148
266
 
149
- // 触发编辑器刷新(传入场景路径以重新打开场景)
267
+ // 触发编辑器刷新
150
268
  refreshEditor(scenePath);
151
269
 
152
- console.log(JSON.stringify({
153
- success: true,
154
- index: nodeIndex,
155
- name: node._name,
156
- changes
157
- }, null, 2));
270
+ // 返回节点最终状态(与 get 命令格式一致)
271
+ console.log(JSON.stringify(getNodeState(data, node, nodeIndex)));
158
272
  } catch (err) {
159
273
  console.log(JSON.stringify({ error: err.message }));
160
274
  }