cocos2d-cli 1.0.3

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.
@@ -0,0 +1,53 @@
1
+ /**
2
+ * get 命令 - 获取节点信息
3
+ */
4
+
5
+ const { loadScene, buildMaps, findNodeIndex } = require('../lib/fire-utils');
6
+
7
+ function run(args) {
8
+ if (args.length < 2) {
9
+ console.log(JSON.stringify({ error: '用法: cocos2.4 get <场景文件路径> <节点索引|名称>' }));
10
+ return;
11
+ }
12
+
13
+ const scenePath = args[0];
14
+ const nodeRef = args[1];
15
+
16
+ try {
17
+ const data = loadScene(scenePath);
18
+ const { indexMap } = buildMaps(data);
19
+
20
+ // 查找节点
21
+ const idx = findNodeIndex(data, indexMap, nodeRef);
22
+
23
+ if (idx === null || idx < 0 || idx >= data.length) {
24
+ console.log(JSON.stringify({ error: `无效的节点索引: ${nodeRef}` }));
25
+ return;
26
+ }
27
+
28
+ const node = data[idx];
29
+ if (!node) {
30
+ console.log(JSON.stringify({ error: `节点不存在: ${nodeRef}` }));
31
+ return;
32
+ }
33
+
34
+ // 返回节点信息
35
+ 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));
48
+ } catch (err) {
49
+ console.log(JSON.stringify({ error: err.message }));
50
+ }
51
+ }
52
+
53
+ module.exports = { run };
@@ -0,0 +1,63 @@
1
+ /**
2
+ * remove-component 命令 - 删除节点上的组件
3
+ */
4
+
5
+ const { loadScene, saveScene } = require('../lib/fire-utils');
6
+
7
+ function run(args) {
8
+ if (args.length < 2) {
9
+ console.log('用法: cocos2.4 remove-component <场景文件路径> <组件索引>');
10
+ return;
11
+ }
12
+
13
+ const scenePath = args[0];
14
+ const compIndex = parseInt(args[1]);
15
+
16
+ if (isNaN(compIndex)) {
17
+ console.log('错误: 组件索引必须是数字');
18
+ return;
19
+ }
20
+
21
+ try {
22
+ const data = loadScene(scenePath);
23
+
24
+ // 检查组件数据是否存在
25
+ const compData = data[compIndex];
26
+ if (!compData) {
27
+ console.log(`错误: 组件索引 ${compIndex} 不存在`);
28
+ return;
29
+ }
30
+
31
+ const compType = compData.__type__;
32
+ const nodeId = compData.node?.__id__;
33
+
34
+ if (nodeId === undefined) {
35
+ console.log(`错误: 组件 ${compIndex} 没有关联的节点`);
36
+ return;
37
+ }
38
+
39
+ const node = data[nodeId];
40
+ if (!node) {
41
+ console.log(`错误: 组件关联的节点 ${nodeId} 不存在`);
42
+ return;
43
+ }
44
+
45
+ // 从节点的 _components 中移除引用
46
+ if (node._components) {
47
+ node._components = node._components.filter(c => c.__id__ !== compIndex);
48
+ }
49
+
50
+ // 从数组中删除组件(设为 null,保持索引)
51
+ data[compIndex] = null;
52
+
53
+ // 保存场景
54
+ saveScene(scenePath, data);
55
+
56
+ console.log(`已删除组件: ${compType} (索引: ${compIndex})`);
57
+ console.log(`从节点: ${node._name || '(unnamed)'} (索引: ${nodeId})`);
58
+ } catch (err) {
59
+ console.log(`错误: ${err.message}`);
60
+ }
61
+ }
62
+
63
+ module.exports = { run };
@@ -0,0 +1,163 @@
1
+ /**
2
+ * remove 命令 - 删除节点或组件
3
+ */
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
+ }
69
+
70
+ function run(args) {
71
+ if (args.length < 2) {
72
+ console.log('用法: cocos2.4 remove <场景文件路径> <索引>');
73
+ return;
74
+ }
75
+
76
+ const scenePath = args[0];
77
+
78
+ // 安装 CLI Helper 插件(如果不存在)
79
+ installPlugin(scenePath);
80
+
81
+ const index = parseInt(args[1]);
82
+
83
+ if (isNaN(index)) {
84
+ console.log('错误: 索引必须是数字');
85
+ return;
86
+ }
87
+
88
+ try {
89
+ let data = loadScene(scenePath);
90
+ const scriptMap = loadScriptMap(scenePath);
91
+
92
+ // 检查索引是否存在
93
+ if (!data[index]) {
94
+ console.log(`错误: 索引 ${index} 不存在`);
95
+ return;
96
+ }
97
+
98
+ const item = data[index];
99
+ const itemType = item.__type__;
100
+
101
+ // 判断是节点还是组件
102
+ const isNode = itemType === 'cc.Node' || itemType === 'cc.Scene' || item._name !== undefined;
103
+ const isComponent = item.node !== undefined;
104
+
105
+ if (isNode && index <= 1) {
106
+ console.log('错误: 不能删除根节点');
107
+ return;
108
+ }
109
+
110
+ if (isComponent) {
111
+ // 删除组件
112
+ const nodeId = item.node.__id__;
113
+ const node = data[nodeId];
114
+
115
+ if (node && node._components) {
116
+ node._components = node._components.filter(c => c.__id__ !== index);
117
+ }
118
+
119
+ // 真正从数组中删除组件并重建引用
120
+ const indicesToDelete = new Set([index]);
121
+ rebuildReferences(data, indicesToDelete);
122
+ data.splice(index, 1);
123
+
124
+ } else {
125
+ // 删除节点
126
+ // 收集所有需要删除的索引
127
+ const indicesToDelete = collectNodeAndChildren(data, index);
128
+
129
+ // 从父节点的 _children 中移除引用
130
+ if (item._parent) {
131
+ const parentIndex = item._parent.__id__;
132
+ const parent = data[parentIndex];
133
+ if (parent && parent._children) {
134
+ parent._children = parent._children.filter(c => c.__id__ !== index);
135
+ }
136
+ }
137
+
138
+ // 重建引用
139
+ rebuildReferences(data, indicesToDelete);
140
+
141
+ // 删除元素
142
+ const sortedIndices = Array.from(indicesToDelete).sort((a, b) => b - a);
143
+ for (const idx of sortedIndices) {
144
+ data.splice(idx, 1);
145
+ }
146
+ }
147
+
148
+ // 保存场景
149
+ saveScene(scenePath, data);
150
+
151
+ // 触发编辑器刷新
152
+ refreshEditor(scenePath);
153
+
154
+ // 重新加载并显示最新树
155
+ data = loadScene(scenePath);
156
+ console.log(buildTree(data, scriptMap, 1));
157
+
158
+ } catch (err) {
159
+ console.log(`错误: ${err.message}`);
160
+ }
161
+ }
162
+
163
+ module.exports = { run };
@@ -0,0 +1,163 @@
1
+ /**
2
+ * set 命令 - 修改节点属性
3
+ */
4
+
5
+ const { loadScene, saveScene, buildMaps, findNodeIndex, refreshEditor } = require('../lib/fire-utils');
6
+
7
+ // 解析颜色
8
+ function parseColor(colorStr) {
9
+ if (!colorStr) return null;
10
+ let color = colorStr;
11
+ if (typeof color === 'string') {
12
+ if (color.startsWith('#')) color = color.slice(1);
13
+ if (color.length === 6) {
14
+ const r = parseInt(color.slice(0, 2), 16);
15
+ const g = parseInt(color.slice(2, 4), 16);
16
+ const b = parseInt(color.slice(4, 6), 16);
17
+ if (!isNaN(r) && !isNaN(g) && !isNaN(b)) {
18
+ return { "__type__": "cc.Color", r, g, b, a: 255 };
19
+ }
20
+ }
21
+ }
22
+ return null;
23
+ }
24
+
25
+ function run(args) {
26
+ if (args.length < 2) {
27
+ console.log(JSON.stringify({ error: '用法: cocos2.4 set <场景文件路径> <节点索引|名称> [选项]' }));
28
+ return;
29
+ }
30
+
31
+ const scenePath = args[0];
32
+ const nodeRef = args[1];
33
+
34
+ // 解析选项
35
+ const options = {};
36
+ args.slice(2).forEach(arg => {
37
+ if (arg.startsWith('--')) {
38
+ const [key, value] = arg.substring(2).split('=');
39
+ options[key] = value;
40
+ }
41
+ });
42
+
43
+ try {
44
+ const data = loadScene(scenePath);
45
+ const { indexMap } = buildMaps(data);
46
+
47
+ // 查找节点
48
+ const nodeIndex = findNodeIndex(data, indexMap, nodeRef);
49
+
50
+ if (nodeIndex === null || !data[nodeIndex]) {
51
+ console.log(JSON.stringify({ error: `找不到节点: ${nodeRef}` }));
52
+ return;
53
+ }
54
+
55
+ const node = data[nodeIndex];
56
+ const changes = {};
57
+
58
+ // 修改名称
59
+ if (options.name !== undefined) {
60
+ const oldName = node._name;
61
+ node._name = options.name;
62
+ changes.name = { from: oldName, to: options.name };
63
+ }
64
+
65
+ // 修改激活状态
66
+ if (options.active !== undefined) {
67
+ const oldActive = node._active;
68
+ node._active = options.active !== 'false';
69
+ changes.active = { from: oldActive, to: node._active };
70
+ }
71
+
72
+ // 修改位置
73
+ if (options.x !== undefined || options.y !== undefined) {
74
+ if (!node._trs) {
75
+ node._trs = { "__type__": "TypedArray", "ctor": "Float64Array", "array": [0, 0, 0, 0, 0, 0, 1, 1, 1, 1] };
76
+ }
77
+ const oldX = node._trs.array[0];
78
+ const oldY = node._trs.array[1];
79
+ if (options.x !== undefined) node._trs.array[0] = parseFloat(options.x);
80
+ 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
+ }
83
+
84
+ // 修改大小
85
+ if (options.width !== undefined || options.height !== undefined) {
86
+ if (!node._contentSize) {
87
+ node._contentSize = { "__type__": "cc.Size", width: 0, height: 0 };
88
+ }
89
+ const oldW = node._contentSize.width;
90
+ const oldH = node._contentSize.height;
91
+ if (options.width !== undefined) node._contentSize.width = parseFloat(options.width);
92
+ 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
+ }
95
+
96
+ // 修改锚点
97
+ if (options.anchorX !== undefined || options.anchorY !== undefined) {
98
+ if (!node._anchorPoint) {
99
+ node._anchorPoint = { "__type__": "cc.Vec2", x: 0.5, y: 0.5 };
100
+ }
101
+ const oldX = node._anchorPoint.x;
102
+ const oldY = node._anchorPoint.y;
103
+ if (options.anchorX !== undefined) node._anchorPoint.x = parseFloat(options.anchorX);
104
+ if (options.anchorY !== undefined) node._anchorPoint.y = parseFloat(options.anchorY);
105
+ changes.anchor = { from: [oldX, oldY], to: [node._anchorPoint.x, node._anchorPoint.y] };
106
+ }
107
+
108
+ // 修改透明度
109
+ if (options.opacity !== undefined) {
110
+ const oldOpacity = node._opacity;
111
+ node._opacity = Math.max(0, Math.min(255, parseInt(options.opacity)));
112
+ changes.opacity = { from: oldOpacity, to: node._opacity };
113
+ }
114
+
115
+ // 修改颜色
116
+ if (options.color !== undefined) {
117
+ const color = parseColor(options.color);
118
+ if (color) {
119
+ node._color = color;
120
+ changes.color = { to: options.color };
121
+ }
122
+ }
123
+
124
+ // 修改旋转角度
125
+ if (options.rotation !== undefined) {
126
+ if (!node._eulerAngles) {
127
+ node._eulerAngles = { "__type__": "cc.Vec3", x: 0, y: 0, z: 0 };
128
+ }
129
+ const oldRotation = node._eulerAngles.z;
130
+ node._eulerAngles.z = parseFloat(options.rotation);
131
+ changes.rotation = { from: oldRotation, to: node._eulerAngles.z };
132
+ }
133
+
134
+ // 修改缩放
135
+ if (options.scaleX !== undefined || options.scaleY !== undefined) {
136
+ if (!node._trs) {
137
+ node._trs = { "__type__": "TypedArray", "ctor": "Float64Array", "array": [0, 0, 0, 0, 0, 0, 1, 1, 1, 1] };
138
+ }
139
+ const oldScaleX = node._trs.array[7];
140
+ const oldScaleY = node._trs.array[8];
141
+ if (options.scaleX !== undefined) node._trs.array[7] = parseFloat(options.scaleX);
142
+ 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
+ }
145
+
146
+ // 保存场景
147
+ saveScene(scenePath, data);
148
+
149
+ // 触发编辑器刷新(传入场景路径以重新打开场景)
150
+ refreshEditor(scenePath);
151
+
152
+ console.log(JSON.stringify({
153
+ success: true,
154
+ index: nodeIndex,
155
+ name: node._name,
156
+ changes
157
+ }, null, 2));
158
+ } catch (err) {
159
+ console.log(JSON.stringify({ error: err.message }));
160
+ }
161
+ }
162
+
163
+ module.exports = { run };
@@ -0,0 +1,92 @@
1
+ /**
2
+ * tree 命令 - 查看节点树
3
+ */
4
+
5
+ const { loadScene, buildMaps } = 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
+ function run(args) {
22
+ const scenePath = args[0];
23
+
24
+ if (!scenePath) {
25
+ console.log(JSON.stringify({ error: '用法: cocos2.4 tree <场景文件路径>' }));
26
+ return;
27
+ }
28
+
29
+ try {
30
+ const data = loadScene(scenePath);
31
+ const { indexMap } = buildMaps(data);
32
+ const scriptMap = loadScriptMap(scenePath);
33
+ const uuidRegex = /^[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}$/i;
34
+
35
+ // 构建树形结构输出
36
+ function buildTree(nodeIndex, prefix = '', isLast = true, isRoot = true) {
37
+ const node = data[nodeIndex];
38
+ if (!node) return '';
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;
83
+ }
84
+
85
+ const treeStr = buildTree(1);
86
+ console.log(treeStr);
87
+ } catch (err) {
88
+ console.log(`Error: ${err.message}`);
89
+ }
90
+ }
91
+
92
+ module.exports = { run };