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/lib/fire-utils.js
CHANGED
|
@@ -1,17 +1,24 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Fire 文件工具模块
|
|
3
|
-
* 提供直接读取和操作 .fire
|
|
2
|
+
* Fire/Prefab 文件工具模块
|
|
3
|
+
* 提供直接读取和操作 .fire 场景文件和 .prefab 预制体文件的功能
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
6
|
const fs = require('fs');
|
|
7
7
|
const path = require('path');
|
|
8
8
|
|
|
9
9
|
/**
|
|
10
|
-
*
|
|
10
|
+
* 检测是否为预制体文件
|
|
11
|
+
*/
|
|
12
|
+
function isPrefab(data) {
|
|
13
|
+
return data[0]?.__type__ === 'cc.Prefab';
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* 加载场景/预制体文件
|
|
11
18
|
*/
|
|
12
19
|
function loadScene(scenePath) {
|
|
13
20
|
if (!fs.existsSync(scenePath)) {
|
|
14
|
-
throw new Error(
|
|
21
|
+
throw new Error(`文件不存在: ${scenePath}`);
|
|
15
22
|
}
|
|
16
23
|
|
|
17
24
|
const content = fs.readFileSync(scenePath, 'utf8');
|
|
@@ -19,23 +26,29 @@ function loadScene(scenePath) {
|
|
|
19
26
|
}
|
|
20
27
|
|
|
21
28
|
/**
|
|
22
|
-
*
|
|
29
|
+
* 保存场景/预制体文件
|
|
23
30
|
*/
|
|
24
31
|
function saveScene(scenePath, data) {
|
|
25
32
|
fs.writeFileSync(scenePath, JSON.stringify(data, null, 2), 'utf8');
|
|
26
33
|
}
|
|
27
34
|
|
|
28
35
|
/**
|
|
29
|
-
* 构建 ID
|
|
36
|
+
* 构建 ID 和索引映射(自动适配场景和预制体)
|
|
30
37
|
*/
|
|
31
38
|
function buildMaps(data) {
|
|
32
39
|
const idMap = {}; // _id -> index
|
|
33
|
-
const indexMap = {}; // index -> { _id, name, path }
|
|
40
|
+
const indexMap = {}; // index -> { _id, name, path, type }
|
|
41
|
+
const prefab = isPrefab(data);
|
|
34
42
|
|
|
35
43
|
function traverse(nodeIndex, parentPath = '') {
|
|
36
44
|
const node = data[nodeIndex];
|
|
37
45
|
if (!node) return;
|
|
38
46
|
|
|
47
|
+
// 跳过非节点类型
|
|
48
|
+
if (!node.__type__?.startsWith('cc.Node') && node.__type__ !== 'cc.Scene') {
|
|
49
|
+
return;
|
|
50
|
+
}
|
|
51
|
+
|
|
39
52
|
const nodeId = node._id;
|
|
40
53
|
if (nodeId) {
|
|
41
54
|
idMap[nodeId] = nodeIndex;
|
|
@@ -59,12 +72,15 @@ function buildMaps(data) {
|
|
|
59
72
|
}
|
|
60
73
|
}
|
|
61
74
|
|
|
62
|
-
|
|
63
|
-
|
|
75
|
+
if (prefab) {
|
|
76
|
+
// 预制体:从索引 1(根节点)开始遍历
|
|
77
|
+
traverse(1);
|
|
78
|
+
} else {
|
|
79
|
+
// 场景:从索引 1(Scene)开始遍历
|
|
64
80
|
traverse(1);
|
|
65
81
|
}
|
|
66
82
|
|
|
67
|
-
return { idMap, indexMap };
|
|
83
|
+
return { idMap, indexMap, prefab };
|
|
68
84
|
}
|
|
69
85
|
|
|
70
86
|
/**
|
|
@@ -413,52 +429,190 @@ function loadScriptMap(scenePath) {
|
|
|
413
429
|
}
|
|
414
430
|
|
|
415
431
|
/**
|
|
416
|
-
*
|
|
432
|
+
* 构建节点树输出(自动适配场景和预制体)
|
|
417
433
|
*/
|
|
418
434
|
function buildTree(data, scriptMap, nodeIndex, prefix = '', isLast = true, isRoot = true) {
|
|
419
435
|
const node = data[nodeIndex];
|
|
420
436
|
if (!node) return '';
|
|
421
437
|
|
|
438
|
+
// 跳过 Scene 类型(场景根节点)
|
|
439
|
+
const isSceneRoot = node.__type__ === 'cc.Scene';
|
|
422
440
|
const nodeName = isRoot ? 'Root' : (node._name || '(unnamed)');
|
|
423
441
|
const active = node._active !== false ? '●' : '○';
|
|
424
442
|
const uuidRegex = /^[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}$/i;
|
|
425
443
|
|
|
426
|
-
let result =
|
|
427
|
-
|
|
428
|
-
// 添加组件信息
|
|
429
|
-
if (node._components && node._components.length > 0) {
|
|
430
|
-
const comps = node._components.map(c => {
|
|
431
|
-
const comp = data[c.__id__];
|
|
432
|
-
if (!comp) return `? #${c.__id__}`;
|
|
433
|
-
const typeName = comp.__type__;
|
|
434
|
-
let displayName;
|
|
435
|
-
if (uuidRegex.test(typeName)) {
|
|
436
|
-
const scriptInfo = scriptMap[typeName];
|
|
437
|
-
displayName = (scriptInfo && scriptInfo.name) ? scriptInfo.name : '⚠️MissingScript';
|
|
438
|
-
} else if (typeName === 'MissingScript') {
|
|
439
|
-
displayName = '⚠️MissingScript';
|
|
440
|
-
} else {
|
|
441
|
-
displayName = typeName.replace('cc.', '');
|
|
442
|
-
}
|
|
443
|
-
return `${displayName} #${c.__id__}`;
|
|
444
|
-
}).join(', ');
|
|
445
|
-
result += ` (${comps})`;
|
|
446
|
-
}
|
|
444
|
+
let result = '';
|
|
447
445
|
|
|
448
|
-
|
|
446
|
+
// 场景根节点特殊处理
|
|
447
|
+
if (isSceneRoot) {
|
|
448
|
+
result = prefix + '🎬 Scene\n';
|
|
449
|
+
} else {
|
|
450
|
+
result = prefix + (isRoot ? '' : active + ' ') + nodeName + ' #' + nodeIndex;
|
|
451
|
+
|
|
452
|
+
// 添加组件信息
|
|
453
|
+
if (node._components && node._components.length > 0) {
|
|
454
|
+
const comps = node._components.map(c => {
|
|
455
|
+
const comp = data[c.__id__];
|
|
456
|
+
if (!comp) return `? #${c.__id__}`;
|
|
457
|
+
const typeName = comp.__type__;
|
|
458
|
+
let displayName;
|
|
459
|
+
if (uuidRegex.test(typeName)) {
|
|
460
|
+
const scriptInfo = scriptMap[typeName];
|
|
461
|
+
displayName = (scriptInfo && scriptInfo.name) ? scriptInfo.name : '⚠️MissingScript';
|
|
462
|
+
} else if (typeName === 'MissingScript') {
|
|
463
|
+
displayName = '⚠️MissingScript';
|
|
464
|
+
} else {
|
|
465
|
+
displayName = typeName.replace('cc.', '');
|
|
466
|
+
}
|
|
467
|
+
return `${displayName} #${c.__id__}`;
|
|
468
|
+
}).join(', ');
|
|
469
|
+
result += ` (${comps})`;
|
|
470
|
+
}
|
|
471
|
+
|
|
472
|
+
result += '\n';
|
|
473
|
+
}
|
|
449
474
|
|
|
450
475
|
// 处理子节点
|
|
451
476
|
if (node._children && node._children.length > 0) {
|
|
452
477
|
node._children.forEach((childRef, idx) => {
|
|
453
478
|
const childIsLast = idx === node._children.length - 1;
|
|
454
|
-
const childPrefix = prefix + (isRoot ? '' : (isLast ? ' ' : '│ '));
|
|
455
|
-
result += buildTree(data, scriptMap, childRef.__id__, childPrefix, childIsLast,
|
|
479
|
+
const childPrefix = prefix + (isSceneRoot ? '' : (isRoot ? '' : (isLast ? ' ' : '│ ')));
|
|
480
|
+
result += buildTree(data, scriptMap, childRef.__id__, childPrefix, childIsLast, isSceneRoot);
|
|
456
481
|
});
|
|
457
482
|
}
|
|
458
483
|
|
|
459
484
|
return result;
|
|
460
485
|
}
|
|
461
486
|
|
|
487
|
+
/**
|
|
488
|
+
* 生成 fileId(用于 PrefabInfo)
|
|
489
|
+
*/
|
|
490
|
+
function generateFileId() {
|
|
491
|
+
const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
|
|
492
|
+
let result = '';
|
|
493
|
+
for (let i = 0; i < 22; i++) {
|
|
494
|
+
result += chars.charAt(Math.floor(Math.random() * chars.length));
|
|
495
|
+
}
|
|
496
|
+
return result;
|
|
497
|
+
}
|
|
498
|
+
|
|
499
|
+
/**
|
|
500
|
+
* 创建新预制体
|
|
501
|
+
* @param {string} name - 预制体名称
|
|
502
|
+
* @returns {Array} - 预制体数据
|
|
503
|
+
*
|
|
504
|
+
* 预制体结构说明:
|
|
505
|
+
* [0] cc.Prefab - 预制体元数据
|
|
506
|
+
* [1] cc.Node - 根节点,_prefab 指向最后一个 PrefabInfo
|
|
507
|
+
* [2] cc.PrefabInfo - 根节点的 PrefabInfo(在最后)
|
|
508
|
+
*
|
|
509
|
+
* 当添加子节点时,结构变为:
|
|
510
|
+
* [0] cc.Prefab
|
|
511
|
+
* [1] cc.Node (根) _prefab -> [N]
|
|
512
|
+
* [2] cc.Node (子1) _prefab -> [3]
|
|
513
|
+
* [3] cc.PrefabInfo (子1的)
|
|
514
|
+
* ...
|
|
515
|
+
* [N] cc.PrefabInfo (根节点的,在最后)
|
|
516
|
+
*/
|
|
517
|
+
function createPrefab(name) {
|
|
518
|
+
const fileId = generateFileId();
|
|
519
|
+
return [
|
|
520
|
+
{
|
|
521
|
+
"__type__": "cc.Prefab",
|
|
522
|
+
"_name": "",
|
|
523
|
+
"_objFlags": 0,
|
|
524
|
+
"_native": "",
|
|
525
|
+
"data": { "__id__": 1 },
|
|
526
|
+
"optimizationPolicy": 0,
|
|
527
|
+
"asyncLoadAssets": false,
|
|
528
|
+
"readonly": false
|
|
529
|
+
},
|
|
530
|
+
{
|
|
531
|
+
"__type__": "cc.Node",
|
|
532
|
+
"_name": name,
|
|
533
|
+
"_objFlags": 0,
|
|
534
|
+
"_parent": null,
|
|
535
|
+
"_children": [],
|
|
536
|
+
"_active": true,
|
|
537
|
+
"_components": [],
|
|
538
|
+
"_prefab": { "__id__": 2 }, // 指向最后的 PrefabInfo
|
|
539
|
+
"_opacity": 255,
|
|
540
|
+
"_color": { "__type__": "cc.Color", "r": 255, "g": 255, "b": 255, "a": 255 },
|
|
541
|
+
"_contentSize": { "__type__": "cc.Size", "width": 0, "height": 0 },
|
|
542
|
+
"_anchorPoint": { "__type__": "cc.Vec2", "x": 0.5, "y": 0.5 },
|
|
543
|
+
"_trs": { "__type__": "TypedArray", "ctor": "Float64Array", "array": [0, 0, 0, 0, 0, 0, 1, 1, 1, 1] },
|
|
544
|
+
"_eulerAngles": { "__type__": "cc.Vec3", "x": 0, "y": 0, "z": 0 },
|
|
545
|
+
"_skewX": 0,
|
|
546
|
+
"_skewY": 0,
|
|
547
|
+
"_is3DNode": false,
|
|
548
|
+
"_groupIndex": 0,
|
|
549
|
+
"groupIndex": 0,
|
|
550
|
+
"_id": ""
|
|
551
|
+
},
|
|
552
|
+
{
|
|
553
|
+
"__type__": "cc.PrefabInfo",
|
|
554
|
+
"root": { "__id__": 1 },
|
|
555
|
+
"asset": { "__id__": 0 },
|
|
556
|
+
"fileId": fileId,
|
|
557
|
+
"sync": false
|
|
558
|
+
}
|
|
559
|
+
];
|
|
560
|
+
}
|
|
561
|
+
|
|
562
|
+
/**
|
|
563
|
+
* 创建预制体节点数据(带 PrefabInfo)
|
|
564
|
+
* @param {string} name - 节点名称
|
|
565
|
+
* @param {number} parentId - 父节点索引
|
|
566
|
+
* @param {number} rootId - 预制体根节点索引
|
|
567
|
+
* @param {object} options - 可选参数
|
|
568
|
+
*/
|
|
569
|
+
function createPrefabNodeData(name, parentId, rootId, options = {}) {
|
|
570
|
+
const fileId = generateFileId();
|
|
571
|
+
const nodeIndex = -1; // 占位,插入时确定
|
|
572
|
+
const prefabInfoIndex = nodeIndex + 1; // PrefabInfo 紧跟节点
|
|
573
|
+
|
|
574
|
+
const nodeData = {
|
|
575
|
+
"__type__": "cc.Node",
|
|
576
|
+
"_name": name,
|
|
577
|
+
"_objFlags": 0,
|
|
578
|
+
"_parent": { "__id__": parentId },
|
|
579
|
+
"_children": [],
|
|
580
|
+
"_active": options.active !== false,
|
|
581
|
+
"_components": [],
|
|
582
|
+
"_prefab": { "__id__": prefabInfoIndex },
|
|
583
|
+
"_opacity": 255,
|
|
584
|
+
"_color": { "__type__": "cc.Color", "r": 255, "g": 255, "b": 255, "a": 255 },
|
|
585
|
+
"_contentSize": { "__type__": "cc.Size", "width": options.width || 0, "height": options.height || 0 },
|
|
586
|
+
"_anchorPoint": { "__type__": "cc.Vec2", "x": 0.5, "y": 0.5 },
|
|
587
|
+
"_trs": { "__type__": "TypedArray", "ctor": "Float64Array", "array": [options.x || 0, options.y || 0, 0, 0, 0, 0, 1, 1, 1, 1] },
|
|
588
|
+
"_eulerAngles": { "__type__": "cc.Vec3", "x": 0, "y": 0, "z": 0 },
|
|
589
|
+
"_skewX": 0,
|
|
590
|
+
"_skewY": 0,
|
|
591
|
+
"_is3DNode": false,
|
|
592
|
+
"_groupIndex": 0,
|
|
593
|
+
"groupIndex": 0,
|
|
594
|
+
"_id": ""
|
|
595
|
+
};
|
|
596
|
+
|
|
597
|
+
const prefabInfo = {
|
|
598
|
+
"__type__": "cc.PrefabInfo",
|
|
599
|
+
"root": { "__id__": rootId },
|
|
600
|
+
"asset": { "__id__": 0 },
|
|
601
|
+
"fileId": fileId,
|
|
602
|
+
"sync": false
|
|
603
|
+
};
|
|
604
|
+
|
|
605
|
+
return { nodeData, prefabInfo };
|
|
606
|
+
}
|
|
607
|
+
|
|
608
|
+
/**
|
|
609
|
+
* 获取预制体根节点索引
|
|
610
|
+
*/
|
|
611
|
+
function getPrefabRootIndex(data) {
|
|
612
|
+
if (!isPrefab(data)) return null;
|
|
613
|
+
return 1; // 预制体根节点固定在索引 1
|
|
614
|
+
}
|
|
615
|
+
|
|
462
616
|
module.exports = {
|
|
463
617
|
loadScene,
|
|
464
618
|
saveScene,
|
|
@@ -471,5 +625,10 @@ module.exports = {
|
|
|
471
625
|
installPlugin,
|
|
472
626
|
checkPluginStatus,
|
|
473
627
|
loadScriptMap,
|
|
474
|
-
buildTree
|
|
628
|
+
buildTree,
|
|
629
|
+
isPrefab,
|
|
630
|
+
createPrefab,
|
|
631
|
+
createPrefabNodeData,
|
|
632
|
+
getPrefabRootIndex,
|
|
633
|
+
generateFileId
|
|
475
634
|
};
|