cocos2d-cli 1.0.5 → 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.
- package/bin/cocos-cli.js +33 -16
- package/data/prefab-template.json +72 -0
- package/data/scene-template.json +241 -0
- package/package.json +1 -1
- package/src/commands/add.js +222 -97
- package/src/commands/create-scene.js +494 -0
- package/src/commands/get.js +1 -1
- package/src/commands/prefab-create.js +49 -0
- package/src/commands/set.js +1 -1
- package/src/commands/tree.js +16 -7
- package/src/lib/components.js +2 -2
- package/src/lib/fire-utils.js +195 -36
package/src/commands/add.js
CHANGED
|
@@ -1,14 +1,38 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* add 命令 -
|
|
3
|
-
*
|
|
2
|
+
* add 命令 - 添加节点(支持场景和预制体)
|
|
3
|
+
*
|
|
4
|
+
* 预制体正确结构(深度优先遍历):
|
|
5
|
+
* 节点 → 子节点(递归) → 组件 → PrefabInfo
|
|
6
|
+
*
|
|
7
|
+
* 示例:
|
|
8
|
+
* [1] Node (根) _prefab -> [最后]
|
|
9
|
+
* [2] Node (子1) _prefab -> [6]
|
|
10
|
+
* [3] Node (孙) _prefab -> [5]
|
|
11
|
+
* [4] Component (孙的组件)
|
|
12
|
+
* [5] PrefabInfo (孙的)
|
|
13
|
+
* [6] Component (子1的组件)
|
|
14
|
+
* [7] PrefabInfo (子1的)
|
|
15
|
+
* [8] PrefabInfo (根的,在最后)
|
|
4
16
|
*/
|
|
5
17
|
|
|
6
|
-
const { loadScene, saveScene, buildMaps,
|
|
18
|
+
const { loadScene, saveScene, buildMaps, refreshEditor, isPrefab, generateFileId } = require('../lib/fire-utils');
|
|
7
19
|
const { Components, createNodeData } = require('../lib/components');
|
|
8
20
|
|
|
9
21
|
/**
|
|
10
|
-
*
|
|
11
|
-
|
|
22
|
+
* 获取根节点 PrefabInfo 的索引(预制体最后一个元素)
|
|
23
|
+
*/
|
|
24
|
+
function getRootPrefabInfoIndex(data) {
|
|
25
|
+
for (let i = data.length - 1; i >= 0; i--) {
|
|
26
|
+
if (data[i].__type__ === 'cc.PrefabInfo') {
|
|
27
|
+
const rootRef = data[i].root?.__id__;
|
|
28
|
+
if (rootRef === 1) return i;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
return data.length - 1;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* 获取节点子树的结束索引(子节点 → 组件 → PrefabInfo)
|
|
12
36
|
*/
|
|
13
37
|
function getSubtreeEndIndex(data, nodeIndex) {
|
|
14
38
|
const node = data[nodeIndex];
|
|
@@ -24,33 +48,35 @@ function getSubtreeEndIndex(data, nodeIndex) {
|
|
|
24
48
|
}
|
|
25
49
|
}
|
|
26
50
|
|
|
27
|
-
//
|
|
51
|
+
// 处理组件
|
|
28
52
|
if (node._components) {
|
|
29
53
|
for (const compRef of node._components) {
|
|
30
54
|
lastIndex = Math.max(lastIndex, compRef.__id__);
|
|
31
55
|
}
|
|
32
56
|
}
|
|
33
57
|
|
|
58
|
+
// PrefabInfo 在最后(根节点的除外,它在整个数组最后)
|
|
59
|
+
if (node._prefab && nodeIndex !== 1) {
|
|
60
|
+
lastIndex = Math.max(lastIndex, node._prefab.__id__);
|
|
61
|
+
}
|
|
62
|
+
|
|
34
63
|
return lastIndex;
|
|
35
64
|
}
|
|
36
65
|
|
|
37
66
|
/**
|
|
38
|
-
* 重建所有 __id__
|
|
39
|
-
* 返回新旧索引的映射表
|
|
67
|
+
* 重建所有 __id__ 引用
|
|
40
68
|
*/
|
|
41
|
-
function
|
|
69
|
+
function rebuildReferences(data, insertIndex, count) {
|
|
42
70
|
const indexMap = {};
|
|
43
71
|
|
|
44
|
-
// 构建映射:旧索引 -> 新索引
|
|
45
72
|
for (let oldIndex = 0; oldIndex < data.length; oldIndex++) {
|
|
46
73
|
if (oldIndex < insertIndex) {
|
|
47
74
|
indexMap[oldIndex] = oldIndex;
|
|
48
75
|
} else {
|
|
49
|
-
indexMap[oldIndex] = oldIndex +
|
|
76
|
+
indexMap[oldIndex] = oldIndex + count;
|
|
50
77
|
}
|
|
51
78
|
}
|
|
52
79
|
|
|
53
|
-
// 更新所有 __id__ 引用
|
|
54
80
|
function updateRef(obj) {
|
|
55
81
|
if (!obj || typeof obj !== 'object') return;
|
|
56
82
|
|
|
@@ -75,11 +101,11 @@ function rebuildReferencesForInsert(data, insertIndex) {
|
|
|
75
101
|
|
|
76
102
|
function run(args) {
|
|
77
103
|
if (args.length < 3) {
|
|
78
|
-
console.log(JSON.stringify({ error: '用法: cocos2.4 add
|
|
104
|
+
console.log(JSON.stringify({ error: '用法: cocos2.4 add <场景.fire | 预制体.prefab> <父节点索引> <节点名称> [选项]' }));
|
|
79
105
|
return;
|
|
80
106
|
}
|
|
81
107
|
|
|
82
|
-
const
|
|
108
|
+
const filePath = args[0];
|
|
83
109
|
const parentRef = args[1];
|
|
84
110
|
const nodeName = args[2];
|
|
85
111
|
|
|
@@ -95,20 +121,21 @@ function run(args) {
|
|
|
95
121
|
else if (key === 'height') options.height = parseFloat(value) || 0;
|
|
96
122
|
else if (key === 'at') options.at = parseInt(value);
|
|
97
123
|
else if (key === 'active') options.active = value !== 'false';
|
|
124
|
+
else if (key === 'color') options.color = value;
|
|
125
|
+
else if (key === 'fontSize') options.fontSize = parseInt(value) || 40;
|
|
126
|
+
else if (key === 'string') options.string = value || '';
|
|
98
127
|
}
|
|
99
128
|
});
|
|
100
129
|
|
|
101
130
|
try {
|
|
102
|
-
const data = loadScene(
|
|
103
|
-
const {
|
|
131
|
+
const data = loadScene(filePath);
|
|
132
|
+
const { prefab } = buildMaps(data);
|
|
104
133
|
|
|
105
|
-
// 父节点必须使用数字索引
|
|
106
134
|
if (!/^\d+$/.test(parentRef)) {
|
|
107
135
|
console.log(JSON.stringify({ error: '父节点必须使用数字索引,请先用 tree 命令查看节点索引' }));
|
|
108
136
|
return;
|
|
109
137
|
}
|
|
110
138
|
|
|
111
|
-
// 查找父节点
|
|
112
139
|
const parentIndex = parseInt(parentRef);
|
|
113
140
|
|
|
114
141
|
if (parentIndex < 0 || parentIndex >= data.length || !data[parentIndex]) {
|
|
@@ -117,115 +144,213 @@ function run(args) {
|
|
|
117
144
|
}
|
|
118
145
|
|
|
119
146
|
const parentNode = data[parentIndex];
|
|
147
|
+
const isRootChild = prefab && parentIndex === 1;
|
|
120
148
|
|
|
121
|
-
//
|
|
122
|
-
// 按照 _children 顺序,找到应该插入的位置
|
|
149
|
+
// 确定插入位置:紧跟父节点之后(在父节点的子节点/组件/PrefabInfo之前)
|
|
123
150
|
let insertIndex;
|
|
151
|
+
|
|
124
152
|
if (!parentNode._children || parentNode._children.length === 0) {
|
|
125
|
-
//
|
|
153
|
+
// 父节点还没有子节点,插入到父节点之后
|
|
126
154
|
insertIndex = parentIndex + 1;
|
|
127
155
|
} else {
|
|
128
|
-
//
|
|
156
|
+
// 父节点已有子节点,根据 --at 参数确定位置
|
|
129
157
|
const targetPosition = options.at >= 0 ? options.at : parentNode._children.length;
|
|
130
158
|
|
|
131
159
|
if (targetPosition === 0) {
|
|
132
|
-
//
|
|
133
|
-
insertIndex =
|
|
160
|
+
// 插入到第一个子节点之前
|
|
161
|
+
insertIndex = parentNode._children[0].__id__;
|
|
134
162
|
} else if (targetPosition >= parentNode._children.length) {
|
|
135
|
-
//
|
|
163
|
+
// 插入到最后一个子节点之后
|
|
136
164
|
const lastChildRef = parentNode._children[parentNode._children.length - 1];
|
|
137
165
|
insertIndex = getSubtreeEndIndex(data, lastChildRef.__id__) + 1;
|
|
138
166
|
} else {
|
|
139
|
-
//
|
|
140
|
-
|
|
141
|
-
insertIndex = getSubtreeEndIndex(data, beforeChildRef.__id__) + 1;
|
|
167
|
+
// 插入到中间
|
|
168
|
+
insertIndex = parentNode._children[targetPosition].__id__;
|
|
142
169
|
}
|
|
143
170
|
}
|
|
144
171
|
|
|
145
|
-
|
|
146
|
-
const newNode = createNodeData(nodeName, parentIndex, options);
|
|
147
|
-
|
|
148
|
-
// 在正确位置插入新节点
|
|
149
|
-
data.splice(insertIndex, 0, newNode);
|
|
150
|
-
|
|
151
|
-
// 重建索引引用(因为插入了新元素,后续索引都+1)
|
|
152
|
-
const insertIndexMap = rebuildReferencesForInsert(data, insertIndex);
|
|
172
|
+
let newNodeIndex;
|
|
153
173
|
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
174
|
+
if (prefab) {
|
|
175
|
+
// 预制体模式
|
|
176
|
+
// 找到根节点的 PrefabInfo
|
|
177
|
+
const rootPrefabInfoOldIdx = getRootPrefabInfoIndex(data);
|
|
178
|
+
const rootPrefabInfo = data[rootPrefabInfoOldIdx];
|
|
179
|
+
|
|
180
|
+
// 创建节点
|
|
181
|
+
const nodeData = {
|
|
182
|
+
"__type__": "cc.Node",
|
|
183
|
+
"_name": nodeName,
|
|
184
|
+
"_objFlags": 0,
|
|
185
|
+
"_parent": { "__id__": parentIndex },
|
|
186
|
+
"_children": [],
|
|
187
|
+
"_active": options.active !== false,
|
|
188
|
+
"_components": [],
|
|
189
|
+
"_prefab": null,
|
|
190
|
+
"_opacity": 255,
|
|
191
|
+
"_color": parseColor(options.color) || { "__type__": "cc.Color", "r": 255, "g": 255, "b": 255, "a": 255 },
|
|
192
|
+
"_contentSize": { "__type__": "cc.Size", "width": options.width || 0, "height": options.height || 0 },
|
|
193
|
+
"_anchorPoint": { "__type__": "cc.Vec2", "x": 0.5, "y": 0.5 },
|
|
194
|
+
"_trs": { "__type__": "TypedArray", "ctor": "Float64Array", "array": [options.x || 0, options.y || 0, 0, 0, 0, 0, 1, 1, 1, 1] },
|
|
195
|
+
"_eulerAngles": { "__type__": "cc.Vec3", "x": 0, "y": 0, "z": 0 },
|
|
196
|
+
"_skewX": 0,
|
|
197
|
+
"_skewY": 0,
|
|
198
|
+
"_is3DNode": false,
|
|
199
|
+
"_groupIndex": 0,
|
|
200
|
+
"groupIndex": 0,
|
|
201
|
+
"_id": ""
|
|
202
|
+
};
|
|
203
|
+
|
|
204
|
+
// 创建组件(如果有)
|
|
205
|
+
let compData = null;
|
|
206
|
+
if (options.type) {
|
|
207
|
+
compData = Components[options.type]?.(insertIndex);
|
|
208
|
+
// 修改组件属性
|
|
209
|
+
if (compData) {
|
|
210
|
+
if (options.type === 'label') {
|
|
211
|
+
if (options.fontSize) {
|
|
212
|
+
compData._fontSize = options.fontSize;
|
|
213
|
+
compData._lineHeight = options.fontSize;
|
|
214
|
+
}
|
|
215
|
+
if (options.string) {
|
|
216
|
+
compData._string = options.string;
|
|
217
|
+
compData._N$string = options.string;
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
// 创建 PrefabInfo
|
|
224
|
+
const prefabInfo = {
|
|
225
|
+
"__type__": "cc.PrefabInfo",
|
|
226
|
+
"root": { "__id__": 1 },
|
|
227
|
+
"asset": { "__id__": 0 },
|
|
228
|
+
"fileId": generateFileId(),
|
|
229
|
+
"sync": false
|
|
230
|
+
};
|
|
231
|
+
|
|
232
|
+
// 构建要插入的元素:节点 → 组件 → PrefabInfo
|
|
233
|
+
const itemsToInsert = [nodeData];
|
|
234
|
+
if (compData) itemsToInsert.push(compData);
|
|
235
|
+
itemsToInsert.push(prefabInfo);
|
|
236
|
+
|
|
237
|
+
// 如果是根节点的子节点,先移除根 PrefabInfo
|
|
238
|
+
if (isRootChild) {
|
|
239
|
+
// 如果插入位置在根 PrefabInfo 之后,需要调整
|
|
240
|
+
if (insertIndex > rootPrefabInfoOldIdx) {
|
|
241
|
+
insertIndex--;
|
|
242
|
+
}
|
|
243
|
+
data.splice(rootPrefabInfoOldIdx, 1);
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
// 插入元素
|
|
247
|
+
for (let i = 0; i < itemsToInsert.length; i++) {
|
|
248
|
+
data.splice(insertIndex + i, 0, itemsToInsert[i]);
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
// 重建引用
|
|
252
|
+
rebuildReferences(data, insertIndex, itemsToInsert.length);
|
|
253
|
+
|
|
254
|
+
newNodeIndex = insertIndex;
|
|
255
|
+
|
|
256
|
+
// 设置引用
|
|
165
257
|
if (compData) {
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
258
|
+
compData.node = { "__id__": newNodeIndex };
|
|
259
|
+
nodeData._components.push({ "__id__": newNodeIndex + 1 });
|
|
260
|
+
nodeData._prefab = { "__id__": newNodeIndex + 2 };
|
|
261
|
+
} else {
|
|
262
|
+
nodeData._prefab = { "__id__": newNodeIndex + 1 };
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
// 如果是根节点的子节点,把根 PrefabInfo 添加到最后
|
|
266
|
+
if (isRootChild) {
|
|
267
|
+
data.push(rootPrefabInfo);
|
|
268
|
+
data[1]._prefab = { "__id__": data.length - 1 };
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
} else {
|
|
272
|
+
// 场景模式:节点 + 组件
|
|
273
|
+
const newNode = createNodeData(nodeName, parentIndex, options);
|
|
274
|
+
|
|
275
|
+
if (options.color) {
|
|
276
|
+
const color = parseColor(options.color);
|
|
277
|
+
if (color) newNode._color = color;
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
const itemsToInsert = [newNode];
|
|
281
|
+
|
|
282
|
+
let compData = null;
|
|
283
|
+
if (options.type) {
|
|
284
|
+
compData = Components[options.type]?.(insertIndex);
|
|
285
|
+
// 修改组件属性
|
|
286
|
+
if (compData) {
|
|
287
|
+
if (options.type === 'label') {
|
|
288
|
+
if (options.fontSize) {
|
|
289
|
+
compData._fontSize = options.fontSize;
|
|
290
|
+
compData._lineHeight = options.fontSize;
|
|
291
|
+
}
|
|
292
|
+
if (options.string) {
|
|
293
|
+
compData._string = options.string;
|
|
294
|
+
compData._N$string = options.string;
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
if (compData) itemsToInsert.push(compData);
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
for (let i = 0; i < itemsToInsert.length; i++) {
|
|
302
|
+
data.splice(insertIndex + i, 0, itemsToInsert[i]);
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
rebuildReferences(data, insertIndex, itemsToInsert.length);
|
|
306
|
+
|
|
307
|
+
newNodeIndex = insertIndex;
|
|
308
|
+
|
|
309
|
+
if (compData) {
|
|
310
|
+
compData.node = { "__id__": newNodeIndex };
|
|
311
|
+
newNode._components.push({ "__id__": newNodeIndex + 1 });
|
|
175
312
|
}
|
|
176
313
|
}
|
|
177
314
|
|
|
178
315
|
// 更新父节点的 _children
|
|
179
316
|
if (!parentNode._children) parentNode._children = [];
|
|
180
|
-
|
|
181
317
|
const insertPosition = options.at >= 0 ? options.at : parentNode._children.length;
|
|
182
318
|
parentNode._children.splice(insertPosition, 0, { "__id__": newNodeIndex });
|
|
183
319
|
|
|
184
|
-
//
|
|
185
|
-
saveScene(
|
|
320
|
+
// 保存文件
|
|
321
|
+
saveScene(filePath, data);
|
|
186
322
|
|
|
187
|
-
//
|
|
188
|
-
refreshEditor(
|
|
323
|
+
// 触发编辑器刷新
|
|
324
|
+
refreshEditor(filePath);
|
|
189
325
|
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
let result = prefix + (isRoot ? '' : active + ' ') + nodeName + ' #' + nodeIndex;
|
|
198
|
-
|
|
199
|
-
// 添加组件信息
|
|
200
|
-
if (node._components && node._components.length > 0) {
|
|
201
|
-
const comps = node._components.map(c => {
|
|
202
|
-
const comp = data[c.__id__];
|
|
203
|
-
if (!comp) return `? #${c.__id__}`;
|
|
204
|
-
return `${comp.__type__.replace('cc.', '')} #${c.__id__}`;
|
|
205
|
-
}).join(', ');
|
|
206
|
-
result += ` (${comps})`;
|
|
207
|
-
}
|
|
208
|
-
|
|
209
|
-
result += '\n';
|
|
210
|
-
|
|
211
|
-
// 处理子节点
|
|
212
|
-
if (node._children && node._children.length > 0) {
|
|
213
|
-
node._children.forEach((childRef, idx) => {
|
|
214
|
-
const childIsLast = idx === node._children.length - 1;
|
|
215
|
-
const childPrefix = prefix + (isRoot ? '' : (isLast ? ' ' : '│ '));
|
|
216
|
-
result += buildTree(childRef.__id__, childPrefix, childIsLast, false);
|
|
217
|
-
});
|
|
218
|
-
}
|
|
219
|
-
|
|
220
|
-
return result;
|
|
221
|
-
}
|
|
326
|
+
console.log(JSON.stringify({
|
|
327
|
+
success: true,
|
|
328
|
+
nodeIndex: newNodeIndex,
|
|
329
|
+
name: nodeName,
|
|
330
|
+
parent: parentRef,
|
|
331
|
+
type: prefab ? 'prefab' : 'scene'
|
|
332
|
+
}));
|
|
222
333
|
|
|
223
|
-
const treeStr = buildTree(1);
|
|
224
|
-
|
|
225
|
-
console.log(treeStr);
|
|
226
334
|
} catch (err) {
|
|
227
335
|
console.log(JSON.stringify({ error: err.message }));
|
|
228
336
|
}
|
|
229
337
|
}
|
|
230
338
|
|
|
231
|
-
|
|
339
|
+
function parseColor(colorStr) {
|
|
340
|
+
if (!colorStr) return null;
|
|
341
|
+
let color = colorStr;
|
|
342
|
+
if (typeof color === 'string') {
|
|
343
|
+
if (color.startsWith('#')) color = color.slice(1);
|
|
344
|
+
if (color.length === 6) {
|
|
345
|
+
const r = parseInt(color.slice(0, 2), 16);
|
|
346
|
+
const g = parseInt(color.slice(2, 4), 16);
|
|
347
|
+
const b = parseInt(color.slice(4, 6), 16);
|
|
348
|
+
if (!isNaN(r) && !isNaN(g) && !isNaN(b)) {
|
|
349
|
+
return { "__type__": "cc.Color", r, g, b, a: 255 };
|
|
350
|
+
}
|
|
351
|
+
}
|
|
352
|
+
}
|
|
353
|
+
return null;
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
module.exports = { run };
|