cocos2d-cli 1.4.0 → 1.5.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.
Files changed (45) hide show
  1. package/README.md +142 -0
  2. package/bin/cocos2d-cli.js +21 -12
  3. package/package.json +1 -1
  4. package/src/commands/add-component.js +77 -85
  5. package/src/commands/add.js +116 -212
  6. package/src/commands/create-scene.js +128 -109
  7. package/src/commands/get.js +113 -18
  8. package/src/commands/prefab-create.js +43 -139
  9. package/src/commands/remove-component.js +111 -0
  10. package/src/commands/remove.js +59 -122
  11. package/src/commands/set.js +121 -36
  12. package/src/commands/tree.js +3 -8
  13. package/src/lib/cc/CCButton.js +122 -0
  14. package/src/lib/cc/CCCamera.js +93 -0
  15. package/src/lib/cc/CCCanvas.js +64 -0
  16. package/src/lib/cc/CCColor.js +32 -0
  17. package/src/lib/cc/CCComponent.js +60 -0
  18. package/src/lib/cc/CCLabel.js +109 -0
  19. package/src/lib/cc/CCNode.js +242 -0
  20. package/src/lib/cc/CCObject.js +23 -0
  21. package/src/lib/cc/CCPrefab.js +242 -0
  22. package/src/lib/cc/CCRect.js +32 -0
  23. package/src/lib/cc/CCScene.js +42 -0
  24. package/src/lib/cc/CCSceneAsset.js +271 -0
  25. package/src/lib/cc/CCSize.js +26 -0
  26. package/src/lib/cc/CCSprite.js +82 -0
  27. package/src/lib/cc/CCTrs.js +74 -0
  28. package/src/lib/cc/CCVec2.js +26 -0
  29. package/src/lib/cc/CCVec3.js +29 -0
  30. package/src/lib/cc/CCWidget.js +98 -0
  31. package/src/lib/cc/index.js +40 -0
  32. package/src/lib/fire-utils.js +1 -1
  33. package/src/lib/json-parser.js +166 -0
  34. package/src/lib/node-utils.js +64 -28
  35. package/src/lib/templates.js +31 -194
  36. package/src/lib/utils.js +63 -0
  37. package/src/lib/components/button.js +0 -137
  38. package/src/lib/components/camera.js +0 -107
  39. package/src/lib/components/canvas.js +0 -89
  40. package/src/lib/components/index.js +0 -157
  41. package/src/lib/components/label.js +0 -120
  42. package/src/lib/components/layout.js +0 -110
  43. package/src/lib/components/particle-system.js +0 -160
  44. package/src/lib/components/sprite.js +0 -98
  45. package/src/lib/components/widget.js +0 -122
@@ -1,272 +1,176 @@
1
1
  /**
2
- * add 命令 - 添加节点(支持场景和预制体)
2
+ * add 命令 - 添加节点
3
3
  */
4
4
 
5
- const { loadScene, saveScene, buildMaps, refreshEditor, isPrefab, generateFileId, getPrefabRootIndex } = require('../lib/fire-utils');
6
- const { parseOptions, outputError, outputSuccess } = require('../lib/utils');
7
- const { createNodeData } = require('../lib/node-utils');
8
- const { createComponent } = require('../lib/components');
5
+ const path = require('path');
6
+ const fs = require('fs');
7
+ const { CCNode, CCSceneAsset, CCPrefab, CCCanvas, CCWidget, CCSprite, CCLabel, CCButton } = require('../lib/cc');
8
+ const { buildTree } = require('../lib/node-utils');
9
+ const { loadScriptMap, isPrefab } = require('../lib/fire-utils');
10
+ const { generateCompressedUUID } = require('../lib/utils');
9
11
 
10
12
  /**
11
- * 获取根节点 PrefabInfo 的索引
13
+ * 解析命令行选项
12
14
  */
13
- function getRootPrefabInfoIndex(data) {
14
- for (let i = data.length - 1; i >= 0; i--) {
15
- if (data[i].__type__ === 'cc.PrefabInfo') {
16
- const rootRef = data[i].root?.__id__;
17
- if (rootRef === 1) return i;
15
+ function parseOptions(args, startIndex) {
16
+ const options = {};
17
+ for (let i = startIndex; i < args.length; i++) {
18
+ const arg = args[i];
19
+ if (arg.startsWith('--')) {
20
+ const eqIndex = arg.indexOf('=');
21
+ if (eqIndex > 0) {
22
+ const key = arg.substring(2, eqIndex);
23
+ let value = arg.substring(eqIndex + 1);
24
+ if (!isNaN(value) && value !== '') {
25
+ value = parseFloat(value);
26
+ }
27
+ options[key] = value;
28
+ }
18
29
  }
19
30
  }
20
- return data.length - 1;
31
+ return options;
21
32
  }
22
33
 
23
34
  /**
24
- * 获取节点子树的结束索引
35
+ * 创建组件
25
36
  */
26
- function getSubtreeEndIndex(data, nodeIndex) {
27
- const node = data[nodeIndex];
28
- if (!node) return nodeIndex;
29
-
30
- let lastIndex = nodeIndex;
31
-
32
- if (node._children) {
33
- for (const childRef of node._children) {
34
- const childEnd = getSubtreeEndIndex(data, childRef.__id__);
35
- lastIndex = Math.max(lastIndex, childEnd);
36
- }
37
- }
38
-
39
- if (node._components) {
40
- for (const compRef of node._components) {
41
- lastIndex = Math.max(lastIndex, compRef.__id__);
42
- }
43
- }
44
-
45
- if (node._prefab && nodeIndex !== 1) {
46
- lastIndex = Math.max(lastIndex, node._prefab.__id__);
37
+ function createComponent(type) {
38
+ switch (type.toLowerCase()) {
39
+ case 'canvas': return new CCCanvas();
40
+ case 'widget': return new CCWidget();
41
+ case 'sprite': return new CCSprite();
42
+ case 'label': return new CCLabel();
43
+ case 'button': return new CCButton();
44
+ default: return null;
47
45
  }
48
-
49
- return lastIndex;
50
46
  }
51
47
 
52
48
  /**
53
- * 重建所有 __id__ 引用
49
+ * 查找节点
54
50
  */
55
- function rebuildReferencesForInsert(data, insertIndex, count) {
56
- const indexMap = {};
51
+ function findNode(root, path) {
52
+ if (!path) return root;
57
53
 
58
- for (let oldIndex = 0; oldIndex < data.length; oldIndex++) {
59
- if (oldIndex < insertIndex) {
60
- indexMap[oldIndex] = oldIndex;
61
- } else {
62
- indexMap[oldIndex] = oldIndex + count;
63
- }
64
- }
54
+ const parts = path.split('/').filter(p => p);
55
+ if (parts.length === 0) return root;
65
56
 
66
- function updateRef(obj) {
67
- if (!obj || typeof obj !== 'object') return;
68
-
69
- if (obj.__id__ !== undefined) {
70
- const oldId = obj.__id__;
71
- if (indexMap[oldId] !== undefined) {
72
- obj.__id__ = indexMap[oldId];
73
- }
74
- } else {
75
- for (const key of Object.keys(obj)) {
76
- updateRef(obj[key]);
77
- }
78
- }
57
+ let current = root;
58
+
59
+ // 如果路径以根节点名称开始,跳过
60
+ if (parts[0] === root._name) {
61
+ parts.shift();
79
62
  }
80
63
 
81
- for (const item of data) {
82
- updateRef(item);
64
+ for (const part of parts) {
65
+ if (!current._children || current._children.length === 0) return null;
66
+ const found = current._children.find(c => c._name === part);
67
+ if (!found) return null;
68
+ current = found;
83
69
  }
84
70
 
85
- return indexMap;
71
+ return current;
86
72
  }
87
73
 
88
74
  function run(args) {
89
75
  if (args.length < 3) {
90
- outputError('用法: cocos2d-cli add <场景.fire | 预制体.prefab> <父节点索引> <节点名称> [选项]');
76
+ console.log(JSON.stringify({ error: '用法: cocos2d-cli add <场景.fire|预制体.prefab> <父节点路径> <节点名称> [--type=组件类型] [--x=N] [--y=N]' }));
91
77
  return;
92
78
  }
93
79
 
94
80
  const filePath = args[0];
95
- const parentRef = args[1];
81
+ const parentPath = args[1];
96
82
  const nodeName = args[2];
97
-
98
83
  const options = parseOptions(args, 3);
99
84
 
100
- // 转换数值类型
101
- if (options.x) options.x = parseFloat(options.x) || 0;
102
- if (options.y) options.y = parseFloat(options.y) || 0;
103
- if (options.width) options.width = parseFloat(options.width) || 0;
104
- if (options.height) options.height = parseFloat(options.height) || 0;
105
- if (options.at !== undefined) options.at = parseInt(options.at);
106
- if (options.active !== undefined) options.active = options.active !== 'false';
107
- if (options.fontSize) options.fontSize = parseInt(options.fontSize) || 40;
85
+ const ext = path.extname(filePath).toLowerCase();
108
86
 
109
87
  try {
110
- const data = loadScene(filePath);
111
- const { prefab } = buildMaps(data);
88
+ let root;
89
+ let asset;
90
+ const json = JSON.parse(fs.readFileSync(filePath, 'utf8'));
112
91
 
113
- if (!/^\d+$/.test(parentRef)) {
114
- outputError('父节点必须使用数字索引,请先用 tree 命令查看节点索引');
92
+ if (ext === '.fire') {
93
+ asset = CCSceneAsset.fromJSON(json);
94
+ root = asset._scene;
95
+ } else if (ext === '.prefab') {
96
+ asset = CCPrefab.fromJSON(json);
97
+ root = asset._root;
98
+ } else {
99
+ console.log(JSON.stringify({ error: '不支持的文件类型,仅支持 .fire 和 .prefab' }));
115
100
  return;
116
101
  }
117
102
 
118
- const parentIndex = parseInt(parentRef);
103
+ const parent = findNode(root, parentPath);
119
104
 
120
- if (parentIndex < 0 || parentIndex >= data.length || !data[parentIndex]) {
121
- outputError(`无效的节点索引: ${parentRef}`);
105
+ if (!parent) {
106
+ console.log(JSON.stringify({ error: `父节点不存在: ${parentPath}` }));
122
107
  return;
123
108
  }
124
109
 
125
- const parentNode = data[parentIndex];
126
- const isRootChild = prefab && parentIndex === 1;
127
-
128
- // 确定插入位置
129
- let insertIndex;
110
+ // 创建节点
111
+ const node = new CCNode(nodeName);
130
112
 
131
- if (!parentNode._children || parentNode._children.length === 0) {
132
- insertIndex = parentIndex + 1;
133
- } else {
134
- const targetPosition = options.at >= 0 ? options.at : parentNode._children.length;
135
-
136
- if (targetPosition === 0) {
137
- insertIndex = parentNode._children[0].__id__;
138
- } else if (targetPosition >= parentNode._children.length) {
139
- const lastChildRef = parentNode._children[parentNode._children.length - 1];
140
- insertIndex = getSubtreeEndIndex(data, lastChildRef.__id__) + 1;
141
- } else {
142
- insertIndex = parentNode._children[targetPosition].__id__;
143
- }
113
+ // 应用属性
114
+ if (options.x !== undefined) node._trs.array[0] = parseFloat(options.x);
115
+ if (options.y !== undefined) node._trs.array[1] = parseFloat(options.y);
116
+ if (options.width !== undefined) node._contentSize.width = parseFloat(options.width);
117
+ if (options.height !== undefined) node._contentSize.height = parseFloat(options.height);
118
+ if (options.scaleX !== undefined) node._trs.array[7] = parseFloat(options.scaleX);
119
+ if (options.scaleY !== undefined) node._trs.array[8] = parseFloat(options.scaleY);
120
+ if (options.rotation !== undefined) {
121
+ node._trs.array[5] = parseFloat(options.rotation) * Math.PI / 180;
122
+ node._eulerAngles.z = parseFloat(options.rotation);
123
+ }
124
+ if (options.active !== undefined) {
125
+ node._active = options.active !== 'false' && options.active !== false;
144
126
  }
145
127
 
146
- let newNodeIndex;
147
-
148
- if (prefab) {
149
- // 预制体模式
150
- const rootPrefabInfoOldIdx = getRootPrefabInfoIndex(data);
151
- const rootPrefabInfo = data[rootPrefabInfoOldIdx];
152
-
153
- // 创建节点
154
- const nodeData = createNodeData(nodeName, parentIndex, options);
155
-
156
- // 创建组件
157
- let compData = null;
158
- if (options.type) {
159
- compData = createComponent(options.type, insertIndex);
160
- if (compData) {
161
- if (options.type === 'label') {
162
- if (options.fontSize) {
163
- compData._fontSize = options.fontSize;
164
- compData._lineHeight = options.fontSize;
165
- }
166
- if (options.string) {
167
- compData._string = options.string;
168
- compData._N$string = options.string;
169
- }
128
+ // 添加组件
129
+ if (options.type) {
130
+ const comp = createComponent(options.type);
131
+ if (comp) {
132
+ comp.node = node;
133
+ node._components = [comp];
134
+
135
+ // 组件特殊属性
136
+ if (options.type.toLowerCase() === 'label') {
137
+ if (options.string) {
138
+ comp._string = options.string;
139
+ comp['_N$string'] = options.string;
170
140
  }
171
- }
172
- }
173
-
174
- // 创建 PrefabInfo
175
- const prefabInfo = {
176
- "__type__": "cc.PrefabInfo",
177
- "root": { "__id__": 1 },
178
- "asset": { "__id__": 0 },
179
- "fileId": generateFileId(),
180
- "sync": false
181
- };
182
-
183
- const itemsToInsert = [nodeData];
184
- if (compData) itemsToInsert.push(compData);
185
- itemsToInsert.push(prefabInfo);
186
-
187
- if (isRootChild) {
188
- if (insertIndex > rootPrefabInfoOldIdx) {
189
- insertIndex--;
190
- }
191
- data.splice(rootPrefabInfoOldIdx, 1);
192
- }
193
-
194
- for (let i = 0; i < itemsToInsert.length; i++) {
195
- data.splice(insertIndex + i, 0, itemsToInsert[i]);
196
- }
197
-
198
- rebuildReferencesForInsert(data, insertIndex, itemsToInsert.length);
199
-
200
- newNodeIndex = insertIndex;
201
-
202
- if (compData) {
203
- compData.node = { "__id__": newNodeIndex };
204
- nodeData._components.push({ "__id__": newNodeIndex + 1 });
205
- nodeData._prefab = { "__id__": newNodeIndex + 2 };
206
- } else {
207
- nodeData._prefab = { "__id__": newNodeIndex + 1 };
208
- }
209
-
210
- if (isRootChild) {
211
- data.push(rootPrefabInfo);
212
- data[1]._prefab = { "__id__": data.length - 1 };
213
- }
214
-
215
- } else {
216
- // 场景模式
217
- const newNode = createNodeData(nodeName, parentIndex, options);
218
-
219
- const itemsToInsert = [newNode];
220
-
221
- let compData = null;
222
- if (options.type) {
223
- compData = createComponent(options.type, insertIndex);
224
- if (compData) {
225
- if (options.type === 'label') {
226
- if (options.fontSize) {
227
- compData._fontSize = options.fontSize;
228
- compData._lineHeight = options.fontSize;
229
- }
230
- if (options.string) {
231
- compData._string = options.string;
232
- compData._N$string = options.string;
233
- }
141
+ if (options.fontSize) {
142
+ comp._fontSize = parseInt(options.fontSize);
143
+ comp._lineHeight = parseInt(options.fontSize);
234
144
  }
235
145
  }
236
- if (compData) itemsToInsert.push(compData);
237
- }
238
-
239
- for (let i = 0; i < itemsToInsert.length; i++) {
240
- data.splice(insertIndex + i, 0, itemsToInsert[i]);
241
- }
242
-
243
- rebuildReferencesForInsert(data, insertIndex, itemsToInsert.length);
244
-
245
- newNodeIndex = insertIndex;
246
-
247
- if (compData) {
248
- compData.node = { "__id__": newNodeIndex };
249
- newNode._components.push({ "__id__": newNodeIndex + 1 });
250
146
  }
251
147
  }
252
148
 
253
- // 更新父节点的 _children
254
- if (!parentNode._children) parentNode._children = [];
255
- const insertPosition = options.at >= 0 ? options.at : parentNode._children.length;
256
- parentNode._children.splice(insertPosition, 0, { "__id__": newNodeIndex });
149
+ // 添加节点到父节点
150
+ parent._children = parent._children || [];
151
+ parent._children.push(node);
152
+ node._parent = parent;
153
+
154
+ // 场景节点需要 _id,预制体需要 PrefabInfo
155
+ if (ext === '.fire') {
156
+ node._id = generateCompressedUUID();
157
+ } else if (ext === '.prefab') {
158
+ const { CCPrefabInfo } = require('../lib/cc');
159
+ node._prefab = new CCPrefabInfo();
160
+ }
257
161
 
258
- saveScene(filePath, data);
259
- refreshEditor(filePath);
162
+ // 保存
163
+ const data = asset.toJSON();
164
+ fs.writeFileSync(filePath, JSON.stringify(data, null, 2), 'utf8');
260
165
 
261
- outputSuccess({
262
- nodeIndex: newNodeIndex,
263
- name: nodeName,
264
- parent: parentRef,
265
- type: prefab ? 'prefab' : 'scene'
266
- });
166
+ // 输出节点树
167
+ const scriptMap = loadScriptMap(filePath);
168
+ const prefab = isPrefab(data);
169
+ const startIndex = prefab ? 0 : 1;
170
+ console.log(buildTree(data, scriptMap, startIndex).trim());
267
171
 
268
172
  } catch (err) {
269
- outputError(err.message);
173
+ console.log(JSON.stringify({ error: err.message }));
270
174
  }
271
175
  }
272
176