cocos2d-cli 1.6.4 → 1.6.5
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/cocos2d-cli.js +152 -152
- package/data/script_map.json +25 -25
- package/package.json +33 -33
- package/src/commands/add-component.js +112 -112
- package/src/commands/add.js +177 -177
- package/src/commands/build.js +78 -78
- package/src/commands/create-scene.js +181 -181
- package/src/commands/get.js +108 -108
- package/src/commands/prefab-create.js +110 -110
- package/src/commands/remove-component.js +110 -110
- package/src/commands/remove.js +99 -99
- package/src/commands/screenshot.js +108 -108
- package/src/commands/set-component.js +119 -119
- package/src/commands/set.js +107 -107
- package/src/commands/tree.js +28 -28
- package/src/lib/cc/CCButton.js +122 -122
- package/src/lib/cc/CCCamera.js +93 -93
- package/src/lib/cc/CCCanvas.js +54 -54
- package/src/lib/cc/CCColor.js +32 -32
- package/src/lib/cc/CCComponent.js +60 -60
- package/src/lib/cc/CCLabel.js +146 -146
- package/src/lib/cc/CCNode.js +255 -255
- package/src/lib/cc/CCObject.js +23 -23
- package/src/lib/cc/CCPrefab.js +242 -242
- package/src/lib/cc/CCRect.js +32 -32
- package/src/lib/cc/CCRichText.js +44 -44
- package/src/lib/cc/CCScene.js +42 -42
- package/src/lib/cc/CCSceneAsset.js +302 -302
- package/src/lib/cc/CCSize.js +26 -26
- package/src/lib/cc/CCSprite.js +94 -94
- package/src/lib/cc/CCTrs.js +74 -74
- package/src/lib/cc/CCVec2.js +26 -26
- package/src/lib/cc/CCVec3.js +29 -29
- package/src/lib/cc/CCWidget.js +98 -98
- package/src/lib/cc/index.js +42 -42
- package/src/lib/fire-utils.js +373 -373
- package/src/lib/json-parser.js +185 -185
- package/src/lib/node-utils.js +395 -395
- package/src/lib/screenshot/index.html +29 -29
- package/src/lib/screenshot-core.js +285 -286
- package/src/lib/templates.js +49 -49
- package/src/lib/utils.js +202 -202
package/src/lib/fire-utils.js
CHANGED
|
@@ -1,374 +1,374 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Fire/Prefab 文件工具模块
|
|
3
|
-
* 提供场景/预制体文件的读写和编辑器交互功能
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
const fs = require('fs');
|
|
7
|
-
const path = require('path');
|
|
8
|
-
const crypto = require('crypto');
|
|
9
|
-
|
|
10
|
-
/**
|
|
11
|
-
* 检测是否为预制体文件
|
|
12
|
-
*/
|
|
13
|
-
function isPrefab(data) {
|
|
14
|
-
return data[0]?.__type__ === 'cc.Prefab';
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
/**
|
|
18
|
-
* 加载场景/预制体文件
|
|
19
|
-
*/
|
|
20
|
-
function loadScene(scenePath) {
|
|
21
|
-
if (!fs.existsSync(scenePath)) {
|
|
22
|
-
throw new Error(`文件不存在: ${scenePath}`);
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
const content = fs.readFileSync(scenePath, 'utf8');
|
|
26
|
-
return JSON.parse(content);
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
/**
|
|
30
|
-
* 保存场景/预制体文件
|
|
31
|
-
*/
|
|
32
|
-
function saveScene(scenePath, data) {
|
|
33
|
-
fs.writeFileSync(scenePath, JSON.stringify(data, null, 2), 'utf8');
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
/**
|
|
37
|
-
* 构建 ID 和索引映射
|
|
38
|
-
*/
|
|
39
|
-
function buildMaps(data) {
|
|
40
|
-
const idMap = {};
|
|
41
|
-
const indexMap = {};
|
|
42
|
-
const prefab = isPrefab(data);
|
|
43
|
-
|
|
44
|
-
function traverse(nodeIndex, parentPath = '') {
|
|
45
|
-
const node = data[nodeIndex];
|
|
46
|
-
if (!node) return;
|
|
47
|
-
|
|
48
|
-
if (!node.__type__?.startsWith('cc.Node') && node.__type__ !== 'cc.Scene') {
|
|
49
|
-
return;
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
const nodeId = node._id;
|
|
53
|
-
if (nodeId) {
|
|
54
|
-
idMap[nodeId] = nodeIndex;
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
const nodeName = node._name || '(unnamed)';
|
|
58
|
-
const nodePath = parentPath ? `${parentPath}/${nodeName}` : nodeName;
|
|
59
|
-
|
|
60
|
-
indexMap[nodeIndex] = {
|
|
61
|
-
_id: nodeId,
|
|
62
|
-
name: nodeName,
|
|
63
|
-
path: nodePath,
|
|
64
|
-
type: node.__type__
|
|
65
|
-
};
|
|
66
|
-
|
|
67
|
-
if (node._children) {
|
|
68
|
-
node._children.forEach(childRef => {
|
|
69
|
-
traverse(childRef.__id__, nodePath);
|
|
70
|
-
});
|
|
71
|
-
}
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
traverse(1);
|
|
75
|
-
|
|
76
|
-
return { idMap, indexMap, prefab };
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
/**
|
|
80
|
-
* 查找节点索引
|
|
81
|
-
*/
|
|
82
|
-
function findNodeIndex(data, indexMap, nodeRef) {
|
|
83
|
-
if (/^\d+$/.test(nodeRef)) {
|
|
84
|
-
return parseInt(nodeRef);
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
for (const [idx, info] of Object.entries(indexMap)) {
|
|
88
|
-
if (info.name === nodeRef || info.path === nodeRef || info.path.endsWith('/' + nodeRef)) {
|
|
89
|
-
return parseInt(idx);
|
|
90
|
-
}
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
return null;
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
/**
|
|
97
|
-
* 重建所有 __id__ 引用
|
|
98
|
-
*/
|
|
99
|
-
function rebuildReferences(data, deletedIndices) {
|
|
100
|
-
const indexMap = {};
|
|
101
|
-
let newIndex = 0;
|
|
102
|
-
for (let oldIndex = 0; oldIndex < data.length; oldIndex++) {
|
|
103
|
-
if (!deletedIndices.has(oldIndex)) {
|
|
104
|
-
indexMap[oldIndex] = newIndex;
|
|
105
|
-
newIndex++;
|
|
106
|
-
}
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
function updateRef(obj) {
|
|
110
|
-
if (!obj || typeof obj !== 'object') return;
|
|
111
|
-
|
|
112
|
-
if (obj.__id__ !== undefined) {
|
|
113
|
-
const oldId = obj.__id__;
|
|
114
|
-
if (indexMap[oldId] !== undefined) {
|
|
115
|
-
obj.__id__ = indexMap[oldId];
|
|
116
|
-
}
|
|
117
|
-
} else {
|
|
118
|
-
for (const key of Object.keys(obj)) {
|
|
119
|
-
updateRef(obj[key]);
|
|
120
|
-
}
|
|
121
|
-
}
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
for (const item of data) {
|
|
125
|
-
updateRef(item);
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
return indexMap;
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
/**
|
|
132
|
-
* 检查 CLI Helper 插件状态
|
|
133
|
-
*/
|
|
134
|
-
function checkPluginStatus() {
|
|
135
|
-
const http = require('http');
|
|
136
|
-
|
|
137
|
-
return new Promise((resolve) => {
|
|
138
|
-
const req = http.request({
|
|
139
|
-
hostname: 'localhost',
|
|
140
|
-
port: 7455,
|
|
141
|
-
path: '/status',
|
|
142
|
-
method: 'GET'
|
|
143
|
-
}, (res) => {
|
|
144
|
-
let data = '';
|
|
145
|
-
res.on('data', chunk => data += chunk);
|
|
146
|
-
res.on('end', () => {
|
|
147
|
-
try {
|
|
148
|
-
resolve(JSON.parse(data));
|
|
149
|
-
} catch (e) {
|
|
150
|
-
resolve(null);
|
|
151
|
-
}
|
|
152
|
-
});
|
|
153
|
-
});
|
|
154
|
-
|
|
155
|
-
req.on('error', () => resolve(null));
|
|
156
|
-
req.setTimeout(3000, () => { req.destroy(); resolve(null); });
|
|
157
|
-
req.end();
|
|
158
|
-
});
|
|
159
|
-
}
|
|
160
|
-
|
|
161
|
-
/**
|
|
162
|
-
* 触发编辑器刷新
|
|
163
|
-
*/
|
|
164
|
-
function refreshEditor(scenePath) {
|
|
165
|
-
if (!scenePath) return;
|
|
166
|
-
|
|
167
|
-
const http = require('http');
|
|
168
|
-
|
|
169
|
-
const assetsPath = path.dirname(scenePath);
|
|
170
|
-
const projectPath = path.dirname(assetsPath);
|
|
171
|
-
const relativePath = path.relative(projectPath, scenePath).replace(/\\/g, '/');
|
|
172
|
-
const targetSceneUrl = 'db://' + relativePath.replace(/^assets\//, 'assets/');
|
|
173
|
-
|
|
174
|
-
const getCurrentScene = () => {
|
|
175
|
-
return new Promise((resolve) => {
|
|
176
|
-
const req = http.request({
|
|
177
|
-
hostname: 'localhost',
|
|
178
|
-
port: 7455,
|
|
179
|
-
path: '/current-scene',
|
|
180
|
-
method: 'GET'
|
|
181
|
-
}, (res) => {
|
|
182
|
-
let data = '';
|
|
183
|
-
res.on('data', chunk => data += chunk);
|
|
184
|
-
res.on('end', () => {
|
|
185
|
-
try {
|
|
186
|
-
resolve(JSON.parse(data).sceneUrl || null);
|
|
187
|
-
} catch (e) {
|
|
188
|
-
resolve(null);
|
|
189
|
-
}
|
|
190
|
-
});
|
|
191
|
-
});
|
|
192
|
-
req.on('error', () => resolve(null));
|
|
193
|
-
req.setTimeout(3000, () => { req.destroy(); resolve(null); });
|
|
194
|
-
req.end();
|
|
195
|
-
});
|
|
196
|
-
};
|
|
197
|
-
|
|
198
|
-
const sendRefreshRequest = (sceneUrl) => {
|
|
199
|
-
const postData = sceneUrl ? JSON.stringify({ sceneUrl }) : '';
|
|
200
|
-
const req = http.request({
|
|
201
|
-
hostname: 'localhost',
|
|
202
|
-
port: 7455,
|
|
203
|
-
path: '/refresh',
|
|
204
|
-
method: 'POST',
|
|
205
|
-
headers: {
|
|
206
|
-
'Content-Type': 'application/json',
|
|
207
|
-
'Content-Length': Buffer.byteLength(postData)
|
|
208
|
-
}
|
|
209
|
-
}, () => {});
|
|
210
|
-
req.on('error', () => {});
|
|
211
|
-
if (postData) req.write(postData);
|
|
212
|
-
req.end();
|
|
213
|
-
};
|
|
214
|
-
|
|
215
|
-
getCurrentScene().then(currentSceneUrl => {
|
|
216
|
-
sendRefreshRequest(currentSceneUrl === targetSceneUrl ? targetSceneUrl : null);
|
|
217
|
-
});
|
|
218
|
-
}
|
|
219
|
-
|
|
220
|
-
/**
|
|
221
|
-
* 安装 CLI Helper 插件
|
|
222
|
-
*/
|
|
223
|
-
function installPlugin(scenePath) {
|
|
224
|
-
try {
|
|
225
|
-
const assetsPath = path.dirname(scenePath);
|
|
226
|
-
const projectPath = path.dirname(assetsPath);
|
|
227
|
-
const packagesPath = path.join(projectPath, 'packages');
|
|
228
|
-
const pluginPath = path.join(packagesPath, 'cocos2d-cli-helper');
|
|
229
|
-
|
|
230
|
-
if (fs.existsSync(pluginPath)) return true;
|
|
231
|
-
|
|
232
|
-
if (!fs.existsSync(packagesPath)) {
|
|
233
|
-
fs.mkdirSync(packagesPath, { recursive: true });
|
|
234
|
-
}
|
|
235
|
-
|
|
236
|
-
const cliPluginPath = path.join(__dirname, '..', '..', 'editor-plugin');
|
|
237
|
-
|
|
238
|
-
if (!fs.existsSync(cliPluginPath)) return false;
|
|
239
|
-
|
|
240
|
-
fs.cpSync(cliPluginPath, pluginPath, { recursive: true });
|
|
241
|
-
return true;
|
|
242
|
-
} catch (e) {
|
|
243
|
-
return false;
|
|
244
|
-
}
|
|
245
|
-
}
|
|
246
|
-
|
|
247
|
-
/**
|
|
248
|
-
* 加载脚本映射
|
|
249
|
-
*/
|
|
250
|
-
function loadScriptMap(scenePath) {
|
|
251
|
-
const projectPath = path.dirname(path.dirname(scenePath));
|
|
252
|
-
const mapPath = path.join(projectPath, 'data', 'script_map.json');
|
|
253
|
-
try {
|
|
254
|
-
if (fs.existsSync(mapPath)) {
|
|
255
|
-
return JSON.parse(fs.readFileSync(mapPath, 'utf-8'));
|
|
256
|
-
}
|
|
257
|
-
} catch (e) {}
|
|
258
|
-
return {};
|
|
259
|
-
}
|
|
260
|
-
|
|
261
|
-
/**
|
|
262
|
-
* 生成 fileId(用于 PrefabInfo)
|
|
263
|
-
*/
|
|
264
|
-
function generateFileId() {
|
|
265
|
-
const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
|
|
266
|
-
let result = '';
|
|
267
|
-
for (let i = 0; i < 22; i++) {
|
|
268
|
-
result += chars.charAt(Math.floor(Math.random() * chars.length));
|
|
269
|
-
}
|
|
270
|
-
return result;
|
|
271
|
-
}
|
|
272
|
-
|
|
273
|
-
/**
|
|
274
|
-
* 获取预制体根节点索引
|
|
275
|
-
*/
|
|
276
|
-
function getPrefabRootIndex(data) {
|
|
277
|
-
if (!isPrefab(data)) return null;
|
|
278
|
-
return 1;
|
|
279
|
-
}
|
|
280
|
-
|
|
281
|
-
/**
|
|
282
|
-
* 生成 UUID
|
|
283
|
-
*/
|
|
284
|
-
function generateUUID() {
|
|
285
|
-
return crypto.randomUUID();
|
|
286
|
-
}
|
|
287
|
-
|
|
288
|
-
/**
|
|
289
|
-
* 生成预制体的 meta 对象
|
|
290
|
-
* @param {string} uuid - 可选的 UUID,不传则自动生成
|
|
291
|
-
* @returns {object}
|
|
292
|
-
*/
|
|
293
|
-
function createPrefabMeta(uuid) {
|
|
294
|
-
return {
|
|
295
|
-
ver: '1.3.2',
|
|
296
|
-
uuid: uuid || generateUUID(),
|
|
297
|
-
importer: 'prefab',
|
|
298
|
-
optimizationPolicy: 'AUTO',
|
|
299
|
-
asyncLoadAssets: false,
|
|
300
|
-
readonly: false,
|
|
301
|
-
subMetas: {}
|
|
302
|
-
};
|
|
303
|
-
}
|
|
304
|
-
|
|
305
|
-
/**
|
|
306
|
-
* 生成场景的 meta 对象
|
|
307
|
-
* @param {string} uuid - 可选的 UUID,不传则自动生成
|
|
308
|
-
* @returns {object}
|
|
309
|
-
*/
|
|
310
|
-
function createSceneMeta(uuid) {
|
|
311
|
-
return {
|
|
312
|
-
ver: '1.3.2',
|
|
313
|
-
uuid: uuid || generateUUID(),
|
|
314
|
-
importer: 'scene',
|
|
315
|
-
asyncLoadAssets: false,
|
|
316
|
-
autoReleaseAssets: false,
|
|
317
|
-
subMetas: {}
|
|
318
|
-
};
|
|
319
|
-
}
|
|
320
|
-
|
|
321
|
-
/**
|
|
322
|
-
* 保存 meta 文件
|
|
323
|
-
* @param {string} filePath - 资源文件路径(.prefab 或 .fire)
|
|
324
|
-
* @param {object} meta - meta 对象
|
|
325
|
-
*/
|
|
326
|
-
function saveMetaFile(filePath, meta) {
|
|
327
|
-
const metaPath = filePath + '.meta';
|
|
328
|
-
fs.writeFileSync(metaPath, JSON.stringify(meta, null, 2), 'utf8');
|
|
329
|
-
return metaPath;
|
|
330
|
-
}
|
|
331
|
-
|
|
332
|
-
/**
|
|
333
|
-
* 加载 meta 文件
|
|
334
|
-
* @param {string} filePath - 资源文件路径
|
|
335
|
-
* @returns {object|null}
|
|
336
|
-
*/
|
|
337
|
-
function loadMetaFile(filePath) {
|
|
338
|
-
const metaPath = filePath + '.meta';
|
|
339
|
-
try {
|
|
340
|
-
if (fs.existsSync(metaPath)) {
|
|
341
|
-
return JSON.parse(fs.readFileSync(metaPath, 'utf8'));
|
|
342
|
-
}
|
|
343
|
-
} catch (e) {}
|
|
344
|
-
return null;
|
|
345
|
-
}
|
|
346
|
-
|
|
347
|
-
module.exports = {
|
|
348
|
-
// 文件操作
|
|
349
|
-
loadScene,
|
|
350
|
-
saveScene,
|
|
351
|
-
isPrefab,
|
|
352
|
-
|
|
353
|
-
// 索引映射
|
|
354
|
-
buildMaps,
|
|
355
|
-
findNodeIndex,
|
|
356
|
-
rebuildReferences,
|
|
357
|
-
|
|
358
|
-
// 编辑器交互
|
|
359
|
-
refreshEditor,
|
|
360
|
-
installPlugin,
|
|
361
|
-
checkPluginStatus,
|
|
362
|
-
|
|
363
|
-
// Meta 文件管理
|
|
364
|
-
generateUUID,
|
|
365
|
-
createPrefabMeta,
|
|
366
|
-
createSceneMeta,
|
|
367
|
-
saveMetaFile,
|
|
368
|
-
loadMetaFile,
|
|
369
|
-
|
|
370
|
-
// 工具函数
|
|
371
|
-
loadScriptMap,
|
|
372
|
-
generateFileId,
|
|
373
|
-
getPrefabRootIndex
|
|
1
|
+
/**
|
|
2
|
+
* Fire/Prefab 文件工具模块
|
|
3
|
+
* 提供场景/预制体文件的读写和编辑器交互功能
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
const fs = require('fs');
|
|
7
|
+
const path = require('path');
|
|
8
|
+
const crypto = require('crypto');
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* 检测是否为预制体文件
|
|
12
|
+
*/
|
|
13
|
+
function isPrefab(data) {
|
|
14
|
+
return data[0]?.__type__ === 'cc.Prefab';
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* 加载场景/预制体文件
|
|
19
|
+
*/
|
|
20
|
+
function loadScene(scenePath) {
|
|
21
|
+
if (!fs.existsSync(scenePath)) {
|
|
22
|
+
throw new Error(`文件不存在: ${scenePath}`);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
const content = fs.readFileSync(scenePath, 'utf8');
|
|
26
|
+
return JSON.parse(content);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* 保存场景/预制体文件
|
|
31
|
+
*/
|
|
32
|
+
function saveScene(scenePath, data) {
|
|
33
|
+
fs.writeFileSync(scenePath, JSON.stringify(data, null, 2), 'utf8');
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* 构建 ID 和索引映射
|
|
38
|
+
*/
|
|
39
|
+
function buildMaps(data) {
|
|
40
|
+
const idMap = {};
|
|
41
|
+
const indexMap = {};
|
|
42
|
+
const prefab = isPrefab(data);
|
|
43
|
+
|
|
44
|
+
function traverse(nodeIndex, parentPath = '') {
|
|
45
|
+
const node = data[nodeIndex];
|
|
46
|
+
if (!node) return;
|
|
47
|
+
|
|
48
|
+
if (!node.__type__?.startsWith('cc.Node') && node.__type__ !== 'cc.Scene') {
|
|
49
|
+
return;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
const nodeId = node._id;
|
|
53
|
+
if (nodeId) {
|
|
54
|
+
idMap[nodeId] = nodeIndex;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
const nodeName = node._name || '(unnamed)';
|
|
58
|
+
const nodePath = parentPath ? `${parentPath}/${nodeName}` : nodeName;
|
|
59
|
+
|
|
60
|
+
indexMap[nodeIndex] = {
|
|
61
|
+
_id: nodeId,
|
|
62
|
+
name: nodeName,
|
|
63
|
+
path: nodePath,
|
|
64
|
+
type: node.__type__
|
|
65
|
+
};
|
|
66
|
+
|
|
67
|
+
if (node._children) {
|
|
68
|
+
node._children.forEach(childRef => {
|
|
69
|
+
traverse(childRef.__id__, nodePath);
|
|
70
|
+
});
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
traverse(1);
|
|
75
|
+
|
|
76
|
+
return { idMap, indexMap, prefab };
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* 查找节点索引
|
|
81
|
+
*/
|
|
82
|
+
function findNodeIndex(data, indexMap, nodeRef) {
|
|
83
|
+
if (/^\d+$/.test(nodeRef)) {
|
|
84
|
+
return parseInt(nodeRef);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
for (const [idx, info] of Object.entries(indexMap)) {
|
|
88
|
+
if (info.name === nodeRef || info.path === nodeRef || info.path.endsWith('/' + nodeRef)) {
|
|
89
|
+
return parseInt(idx);
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
return null;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* 重建所有 __id__ 引用
|
|
98
|
+
*/
|
|
99
|
+
function rebuildReferences(data, deletedIndices) {
|
|
100
|
+
const indexMap = {};
|
|
101
|
+
let newIndex = 0;
|
|
102
|
+
for (let oldIndex = 0; oldIndex < data.length; oldIndex++) {
|
|
103
|
+
if (!deletedIndices.has(oldIndex)) {
|
|
104
|
+
indexMap[oldIndex] = newIndex;
|
|
105
|
+
newIndex++;
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
function updateRef(obj) {
|
|
110
|
+
if (!obj || typeof obj !== 'object') return;
|
|
111
|
+
|
|
112
|
+
if (obj.__id__ !== undefined) {
|
|
113
|
+
const oldId = obj.__id__;
|
|
114
|
+
if (indexMap[oldId] !== undefined) {
|
|
115
|
+
obj.__id__ = indexMap[oldId];
|
|
116
|
+
}
|
|
117
|
+
} else {
|
|
118
|
+
for (const key of Object.keys(obj)) {
|
|
119
|
+
updateRef(obj[key]);
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
for (const item of data) {
|
|
125
|
+
updateRef(item);
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
return indexMap;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
/**
|
|
132
|
+
* 检查 CLI Helper 插件状态
|
|
133
|
+
*/
|
|
134
|
+
function checkPluginStatus() {
|
|
135
|
+
const http = require('http');
|
|
136
|
+
|
|
137
|
+
return new Promise((resolve) => {
|
|
138
|
+
const req = http.request({
|
|
139
|
+
hostname: 'localhost',
|
|
140
|
+
port: 7455,
|
|
141
|
+
path: '/status',
|
|
142
|
+
method: 'GET'
|
|
143
|
+
}, (res) => {
|
|
144
|
+
let data = '';
|
|
145
|
+
res.on('data', chunk => data += chunk);
|
|
146
|
+
res.on('end', () => {
|
|
147
|
+
try {
|
|
148
|
+
resolve(JSON.parse(data));
|
|
149
|
+
} catch (e) {
|
|
150
|
+
resolve(null);
|
|
151
|
+
}
|
|
152
|
+
});
|
|
153
|
+
});
|
|
154
|
+
|
|
155
|
+
req.on('error', () => resolve(null));
|
|
156
|
+
req.setTimeout(3000, () => { req.destroy(); resolve(null); });
|
|
157
|
+
req.end();
|
|
158
|
+
});
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
/**
|
|
162
|
+
* 触发编辑器刷新
|
|
163
|
+
*/
|
|
164
|
+
function refreshEditor(scenePath) {
|
|
165
|
+
if (!scenePath) return;
|
|
166
|
+
|
|
167
|
+
const http = require('http');
|
|
168
|
+
|
|
169
|
+
const assetsPath = path.dirname(scenePath);
|
|
170
|
+
const projectPath = path.dirname(assetsPath);
|
|
171
|
+
const relativePath = path.relative(projectPath, scenePath).replace(/\\/g, '/');
|
|
172
|
+
const targetSceneUrl = 'db://' + relativePath.replace(/^assets\//, 'assets/');
|
|
173
|
+
|
|
174
|
+
const getCurrentScene = () => {
|
|
175
|
+
return new Promise((resolve) => {
|
|
176
|
+
const req = http.request({
|
|
177
|
+
hostname: 'localhost',
|
|
178
|
+
port: 7455,
|
|
179
|
+
path: '/current-scene',
|
|
180
|
+
method: 'GET'
|
|
181
|
+
}, (res) => {
|
|
182
|
+
let data = '';
|
|
183
|
+
res.on('data', chunk => data += chunk);
|
|
184
|
+
res.on('end', () => {
|
|
185
|
+
try {
|
|
186
|
+
resolve(JSON.parse(data).sceneUrl || null);
|
|
187
|
+
} catch (e) {
|
|
188
|
+
resolve(null);
|
|
189
|
+
}
|
|
190
|
+
});
|
|
191
|
+
});
|
|
192
|
+
req.on('error', () => resolve(null));
|
|
193
|
+
req.setTimeout(3000, () => { req.destroy(); resolve(null); });
|
|
194
|
+
req.end();
|
|
195
|
+
});
|
|
196
|
+
};
|
|
197
|
+
|
|
198
|
+
const sendRefreshRequest = (sceneUrl) => {
|
|
199
|
+
const postData = sceneUrl ? JSON.stringify({ sceneUrl }) : '';
|
|
200
|
+
const req = http.request({
|
|
201
|
+
hostname: 'localhost',
|
|
202
|
+
port: 7455,
|
|
203
|
+
path: '/refresh',
|
|
204
|
+
method: 'POST',
|
|
205
|
+
headers: {
|
|
206
|
+
'Content-Type': 'application/json',
|
|
207
|
+
'Content-Length': Buffer.byteLength(postData)
|
|
208
|
+
}
|
|
209
|
+
}, () => {});
|
|
210
|
+
req.on('error', () => {});
|
|
211
|
+
if (postData) req.write(postData);
|
|
212
|
+
req.end();
|
|
213
|
+
};
|
|
214
|
+
|
|
215
|
+
getCurrentScene().then(currentSceneUrl => {
|
|
216
|
+
sendRefreshRequest(currentSceneUrl === targetSceneUrl ? targetSceneUrl : null);
|
|
217
|
+
});
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
/**
|
|
221
|
+
* 安装 CLI Helper 插件
|
|
222
|
+
*/
|
|
223
|
+
function installPlugin(scenePath) {
|
|
224
|
+
try {
|
|
225
|
+
const assetsPath = path.dirname(scenePath);
|
|
226
|
+
const projectPath = path.dirname(assetsPath);
|
|
227
|
+
const packagesPath = path.join(projectPath, 'packages');
|
|
228
|
+
const pluginPath = path.join(packagesPath, 'cocos2d-cli-helper');
|
|
229
|
+
|
|
230
|
+
if (fs.existsSync(pluginPath)) return true;
|
|
231
|
+
|
|
232
|
+
if (!fs.existsSync(packagesPath)) {
|
|
233
|
+
fs.mkdirSync(packagesPath, { recursive: true });
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
const cliPluginPath = path.join(__dirname, '..', '..', 'editor-plugin');
|
|
237
|
+
|
|
238
|
+
if (!fs.existsSync(cliPluginPath)) return false;
|
|
239
|
+
|
|
240
|
+
fs.cpSync(cliPluginPath, pluginPath, { recursive: true });
|
|
241
|
+
return true;
|
|
242
|
+
} catch (e) {
|
|
243
|
+
return false;
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
/**
|
|
248
|
+
* 加载脚本映射
|
|
249
|
+
*/
|
|
250
|
+
function loadScriptMap(scenePath) {
|
|
251
|
+
const projectPath = path.dirname(path.dirname(scenePath));
|
|
252
|
+
const mapPath = path.join(projectPath, 'data', 'script_map.json');
|
|
253
|
+
try {
|
|
254
|
+
if (fs.existsSync(mapPath)) {
|
|
255
|
+
return JSON.parse(fs.readFileSync(mapPath, 'utf-8'));
|
|
256
|
+
}
|
|
257
|
+
} catch (e) {}
|
|
258
|
+
return {};
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
/**
|
|
262
|
+
* 生成 fileId(用于 PrefabInfo)
|
|
263
|
+
*/
|
|
264
|
+
function generateFileId() {
|
|
265
|
+
const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
|
|
266
|
+
let result = '';
|
|
267
|
+
for (let i = 0; i < 22; i++) {
|
|
268
|
+
result += chars.charAt(Math.floor(Math.random() * chars.length));
|
|
269
|
+
}
|
|
270
|
+
return result;
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
/**
|
|
274
|
+
* 获取预制体根节点索引
|
|
275
|
+
*/
|
|
276
|
+
function getPrefabRootIndex(data) {
|
|
277
|
+
if (!isPrefab(data)) return null;
|
|
278
|
+
return 1;
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
/**
|
|
282
|
+
* 生成 UUID
|
|
283
|
+
*/
|
|
284
|
+
function generateUUID() {
|
|
285
|
+
return crypto.randomUUID();
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
/**
|
|
289
|
+
* 生成预制体的 meta 对象
|
|
290
|
+
* @param {string} uuid - 可选的 UUID,不传则自动生成
|
|
291
|
+
* @returns {object}
|
|
292
|
+
*/
|
|
293
|
+
function createPrefabMeta(uuid) {
|
|
294
|
+
return {
|
|
295
|
+
ver: '1.3.2',
|
|
296
|
+
uuid: uuid || generateUUID(),
|
|
297
|
+
importer: 'prefab',
|
|
298
|
+
optimizationPolicy: 'AUTO',
|
|
299
|
+
asyncLoadAssets: false,
|
|
300
|
+
readonly: false,
|
|
301
|
+
subMetas: {}
|
|
302
|
+
};
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
/**
|
|
306
|
+
* 生成场景的 meta 对象
|
|
307
|
+
* @param {string} uuid - 可选的 UUID,不传则自动生成
|
|
308
|
+
* @returns {object}
|
|
309
|
+
*/
|
|
310
|
+
function createSceneMeta(uuid) {
|
|
311
|
+
return {
|
|
312
|
+
ver: '1.3.2',
|
|
313
|
+
uuid: uuid || generateUUID(),
|
|
314
|
+
importer: 'scene',
|
|
315
|
+
asyncLoadAssets: false,
|
|
316
|
+
autoReleaseAssets: false,
|
|
317
|
+
subMetas: {}
|
|
318
|
+
};
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
/**
|
|
322
|
+
* 保存 meta 文件
|
|
323
|
+
* @param {string} filePath - 资源文件路径(.prefab 或 .fire)
|
|
324
|
+
* @param {object} meta - meta 对象
|
|
325
|
+
*/
|
|
326
|
+
function saveMetaFile(filePath, meta) {
|
|
327
|
+
const metaPath = filePath + '.meta';
|
|
328
|
+
fs.writeFileSync(metaPath, JSON.stringify(meta, null, 2), 'utf8');
|
|
329
|
+
return metaPath;
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
/**
|
|
333
|
+
* 加载 meta 文件
|
|
334
|
+
* @param {string} filePath - 资源文件路径
|
|
335
|
+
* @returns {object|null}
|
|
336
|
+
*/
|
|
337
|
+
function loadMetaFile(filePath) {
|
|
338
|
+
const metaPath = filePath + '.meta';
|
|
339
|
+
try {
|
|
340
|
+
if (fs.existsSync(metaPath)) {
|
|
341
|
+
return JSON.parse(fs.readFileSync(metaPath, 'utf8'));
|
|
342
|
+
}
|
|
343
|
+
} catch (e) {}
|
|
344
|
+
return null;
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
module.exports = {
|
|
348
|
+
// 文件操作
|
|
349
|
+
loadScene,
|
|
350
|
+
saveScene,
|
|
351
|
+
isPrefab,
|
|
352
|
+
|
|
353
|
+
// 索引映射
|
|
354
|
+
buildMaps,
|
|
355
|
+
findNodeIndex,
|
|
356
|
+
rebuildReferences,
|
|
357
|
+
|
|
358
|
+
// 编辑器交互
|
|
359
|
+
refreshEditor,
|
|
360
|
+
installPlugin,
|
|
361
|
+
checkPluginStatus,
|
|
362
|
+
|
|
363
|
+
// Meta 文件管理
|
|
364
|
+
generateUUID,
|
|
365
|
+
createPrefabMeta,
|
|
366
|
+
createSceneMeta,
|
|
367
|
+
saveMetaFile,
|
|
368
|
+
loadMetaFile,
|
|
369
|
+
|
|
370
|
+
// 工具函数
|
|
371
|
+
loadScriptMap,
|
|
372
|
+
generateFileId,
|
|
373
|
+
getPrefabRootIndex
|
|
374
374
|
};
|