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.
- package/bin/cocos-cli.js +39 -21
- package/data/prefab-template.json +72 -0
- package/data/scene-template.json +241 -0
- package/package.json +4 -6
- package/src/commands/add.js +230 -101
- package/src/commands/create-scene.js +494 -0
- package/src/commands/delete.js +16 -15
- package/src/commands/get.js +153 -16
- package/src/commands/prefab-create.js +49 -0
- package/src/commands/remove.js +11 -76
- package/src/commands/set.js +145 -31
- package/src/commands/tree.js +15 -74
- package/src/lib/components.js +2 -2
- package/src/lib/fire-utils.js +233 -11
package/src/commands/tree.js
CHANGED
|
@@ -1,91 +1,32 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* tree 命令 -
|
|
2
|
+
* tree 命令 - 查看节点树(支持场景和预制体)
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
|
-
const { loadScene,
|
|
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
|
-
}
|
|
5
|
+
const { loadScene, loadScriptMap, buildTree, isPrefab } = require('../lib/fire-utils');
|
|
20
6
|
|
|
21
7
|
function run(args) {
|
|
22
|
-
const
|
|
8
|
+
const filePath = args[0];
|
|
23
9
|
|
|
24
|
-
if (!
|
|
25
|
-
console.log(JSON.stringify({ error: '用法: cocos2.4 tree
|
|
10
|
+
if (!filePath) {
|
|
11
|
+
console.log(JSON.stringify({ error: '用法: cocos2.4 tree <场景.fire | 预制体.prefab>' }));
|
|
26
12
|
return;
|
|
27
13
|
}
|
|
28
14
|
|
|
29
15
|
try {
|
|
30
|
-
const data = loadScene(
|
|
31
|
-
const
|
|
32
|
-
const
|
|
33
|
-
const uuidRegex = /^[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}$/i;
|
|
16
|
+
const data = loadScene(filePath);
|
|
17
|
+
const scriptMap = loadScriptMap(filePath);
|
|
18
|
+
const prefab = isPrefab(data);
|
|
34
19
|
|
|
35
|
-
//
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
const nodeName = isRoot ? 'Root' : (node._name || '(unnamed)');
|
|
41
|
-
const active = node._active !== false ? '●' : '○';
|
|
42
|
-
const connector = isRoot ? '' : (isLast ? '└── ' : '├── ');
|
|
43
|
-
|
|
44
|
-
let result = prefix + (isRoot ? '' : active + ' ') + nodeName + ' #' + nodeIndex;
|
|
45
|
-
|
|
46
|
-
// 添加组件信息
|
|
47
|
-
if (node._components && node._components.length > 0) {
|
|
48
|
-
const comps = node._components.map(c => {
|
|
49
|
-
const comp = data[c.__id__];
|
|
50
|
-
if (!comp) return `? #${c.__id__}`;
|
|
51
|
-
const typeName = comp.__type__;
|
|
52
|
-
let displayName;
|
|
53
|
-
// 如果是 UUID,尝试从 scriptMap 查找类名
|
|
54
|
-
if (uuidRegex.test(typeName)) {
|
|
55
|
-
const scriptInfo = scriptMap[typeName];
|
|
56
|
-
if (scriptInfo && scriptInfo.name) {
|
|
57
|
-
displayName = scriptInfo.name;
|
|
58
|
-
} else {
|
|
59
|
-
displayName = '⚠️MissingScript';
|
|
60
|
-
}
|
|
61
|
-
} else if (typeName === 'MissingScript') {
|
|
62
|
-
displayName = '⚠️MissingScript';
|
|
63
|
-
} else {
|
|
64
|
-
displayName = typeName.replace('cc.', '');
|
|
65
|
-
}
|
|
66
|
-
return `${displayName} #${c.__id__}`;
|
|
67
|
-
}).join(', ');
|
|
68
|
-
result += ` (${comps})`;
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
result += '\n';
|
|
72
|
-
|
|
73
|
-
// 处理子节点
|
|
74
|
-
if (node._children && node._children.length > 0) {
|
|
75
|
-
node._children.forEach((childRef, idx) => {
|
|
76
|
-
const childIsLast = idx === node._children.length - 1;
|
|
77
|
-
const childPrefix = prefix + (isRoot ? '' : (isLast ? ' ' : '│ '));
|
|
78
|
-
result += buildTree(childRef.__id__, childPrefix, childIsLast, false);
|
|
79
|
-
});
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
return result;
|
|
20
|
+
// 输出文件类型
|
|
21
|
+
if (prefab) {
|
|
22
|
+
console.log(`📦 Prefab: ${data[1]._name || 'Root'}\n`);
|
|
23
|
+
} else {
|
|
24
|
+
console.log(`🎬 Scene\n`);
|
|
83
25
|
}
|
|
84
26
|
|
|
85
|
-
|
|
86
|
-
console.log(treeStr);
|
|
27
|
+
console.log(buildTree(data, scriptMap, 1));
|
|
87
28
|
} catch (err) {
|
|
88
|
-
console.log(
|
|
29
|
+
console.log(JSON.stringify({ error: err.message }));
|
|
89
30
|
}
|
|
90
31
|
}
|
|
91
32
|
|
package/src/lib/components.js
CHANGED
|
@@ -31,9 +31,9 @@ const Components = {
|
|
|
31
31
|
"_materials": [DEFAULT_MATERIAL],
|
|
32
32
|
"_srcBlendFactor": 770,
|
|
33
33
|
"_dstBlendFactor": 771,
|
|
34
|
-
"_spriteFrame":
|
|
34
|
+
"_spriteFrame": SPLASH_SPRITE_FRAME,
|
|
35
35
|
"_type": 0,
|
|
36
|
-
"_sizeMode":
|
|
36
|
+
"_sizeMode": 0,
|
|
37
37
|
"_fillType": 0,
|
|
38
38
|
"_fillCenter": { "__type__": "cc.Vec2", "x": 0, "y": 0 },
|
|
39
39
|
"_fillStart": 0,
|
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
|
/**
|
|
@@ -398,6 +414,205 @@ function installPlugin(scenePath) {
|
|
|
398
414
|
}
|
|
399
415
|
}
|
|
400
416
|
|
|
417
|
+
/**
|
|
418
|
+
* 加载脚本映射(用于显示自定义脚本组件名称)
|
|
419
|
+
*/
|
|
420
|
+
function loadScriptMap(scenePath) {
|
|
421
|
+
const projectPath = path.dirname(path.dirname(scenePath));
|
|
422
|
+
const mapPath = path.join(projectPath, 'data', 'script_map.json');
|
|
423
|
+
try {
|
|
424
|
+
if (fs.existsSync(mapPath)) {
|
|
425
|
+
return JSON.parse(fs.readFileSync(mapPath, 'utf-8'));
|
|
426
|
+
}
|
|
427
|
+
} catch (e) {}
|
|
428
|
+
return {};
|
|
429
|
+
}
|
|
430
|
+
|
|
431
|
+
/**
|
|
432
|
+
* 构建节点树输出(自动适配场景和预制体)
|
|
433
|
+
*/
|
|
434
|
+
function buildTree(data, scriptMap, nodeIndex, prefix = '', isLast = true, isRoot = true) {
|
|
435
|
+
const node = data[nodeIndex];
|
|
436
|
+
if (!node) return '';
|
|
437
|
+
|
|
438
|
+
// 跳过 Scene 类型(场景根节点)
|
|
439
|
+
const isSceneRoot = node.__type__ === 'cc.Scene';
|
|
440
|
+
const nodeName = isRoot ? 'Root' : (node._name || '(unnamed)');
|
|
441
|
+
const active = node._active !== false ? '●' : '○';
|
|
442
|
+
const uuidRegex = /^[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}$/i;
|
|
443
|
+
|
|
444
|
+
let result = '';
|
|
445
|
+
|
|
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
|
+
}
|
|
474
|
+
|
|
475
|
+
// 处理子节点
|
|
476
|
+
if (node._children && node._children.length > 0) {
|
|
477
|
+
node._children.forEach((childRef, idx) => {
|
|
478
|
+
const childIsLast = idx === node._children.length - 1;
|
|
479
|
+
const childPrefix = prefix + (isSceneRoot ? '' : (isRoot ? '' : (isLast ? ' ' : '│ ')));
|
|
480
|
+
result += buildTree(data, scriptMap, childRef.__id__, childPrefix, childIsLast, isSceneRoot);
|
|
481
|
+
});
|
|
482
|
+
}
|
|
483
|
+
|
|
484
|
+
return result;
|
|
485
|
+
}
|
|
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
|
+
|
|
401
616
|
module.exports = {
|
|
402
617
|
loadScene,
|
|
403
618
|
saveScene,
|
|
@@ -408,5 +623,12 @@ module.exports = {
|
|
|
408
623
|
reorderArrayToMatchChildren,
|
|
409
624
|
refreshEditor,
|
|
410
625
|
installPlugin,
|
|
411
|
-
checkPluginStatus
|
|
626
|
+
checkPluginStatus,
|
|
627
|
+
loadScriptMap,
|
|
628
|
+
buildTree,
|
|
629
|
+
isPrefab,
|
|
630
|
+
createPrefab,
|
|
631
|
+
createPrefabNodeData,
|
|
632
|
+
getPrefabRootIndex,
|
|
633
|
+
generateFileId
|
|
412
634
|
};
|