Files
youle_cocos/cocoscreator_projects/scripts/convert-ui.mjs
T
joywayerandClaude Opus 5 416a51e422 feat(ui-migration): 转换 CLI 与全量产出
55 界面 / 991 节点 → 中间描述; 439 图 → 1306 张散图落入 atlas-* 目录。
产出前先跑重组校验; 每次转换清空产出目录(中间描述 + 各 atlas-{bucket})保证幂等。
bucket 未定的层告警并落入 atlas-unassigned(7 层/162 图/285 帧), 不静默归入 common。
10 条 FrameIndex 越界警告(已知源数据遗留问题)随产出落盘为 warnings.json。
散图已用 cocos-mcp-server 刷新导入, 1306 个 .meta 由编辑器生成并入库。

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-28 01:49:51 +08:00

94 lines
3.9 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/usr/bin/env node
import { readFileSync, writeFileSync, mkdirSync, rmSync, existsSync, copyFileSync } from 'node:fs';
import { join } from 'node:path';
import { pathToFileURL } from 'node:url';
import { ROOT, HOST_PROJECT, frameworkUiDirOf } from './lib/paths.mjs';
import { loadSource } from './ui-migration/gameabc-source.mjs';
import { imageBuckets } from './ui-migration/buckets.mjs';
import { convertAll } from './ui-migration/convert.mjs';
import { splitSheet } from './ui-migration/frame-io.mjs';
import { frameNames } from './ui-migration/frames.mjs';
// 与 verify-frames.mjs 一致:相对 ROOT 推导,不硬编码绝对路径。
const DEFAULT_SOURCE = join(ROOT, '..', 'projects', 'Game_Surface_3');
/**
* 全量转换:产出中间描述 + 切好的散图。
* 幂等:每次先清空产出目录(spec §4.4),避免残留帧文件混进图集。
* 清空对象包括中间描述目录,以及本次实际会写入的每个 atlas-{bucket} 目录
* (按 bucket 惰性清空一次,防止在同一次运行中被同 bucket 的后续图片覆盖式清掉)。
*/
export function runConvert(opts = {}) {
const projectDir = opts.projectDir ?? DEFAULT_SOURCE;
const intermediateDir = opts.intermediateDir ?? join(ROOT, 'ui-migration', 'intermediate');
const uiDir = opts.uiDir ?? frameworkUiDirOf(HOST_PROJECT);
const source = loadSource(join(projectDir, 'output'));
const bucketMap = imageBuckets(source);
const { layers, manifest, warnings } = convertAll(source);
// 1) 中间描述
rmSync(intermediateDir, { recursive: true, force: true });
mkdirSync(intermediateDir, { recursive: true });
writeFileSync(join(intermediateDir, 'manifest.json'), `${JSON.stringify(manifest, null, 2)}\n`);
writeFileSync(join(intermediateDir, 'warnings.json'), `${JSON.stringify(warnings, null, 2)}\n`);
for (const doc of layers) {
const entry = manifest.layers.find((l) => l.layerId === doc.layerId);
writeFileSync(join(intermediateDir, entry.file), `${JSON.stringify(doc, null, 2)}\n`);
}
// 2) 散图:多帧图切分,单帧图直拷
let frameCount = 0;
const cleanedBuckets = new Set();
for (const image of source.images.values()) {
const bucket = bucketMap.get(image.id) ?? 'unassigned';
const outDir = join(uiDir, `atlas-${bucket}`);
if (!cleanedBuckets.has(bucket)) {
rmSync(outDir, { recursive: true, force: true });
mkdirSync(outDir, { recursive: true });
cleanedBuckets.add(bucket);
}
const src = join(projectDir, 'assets', 'bmp', image.bmp);
if (!existsSync(src)) {
throw new Error(`图片文件不存在: ${src}(图 id=${image.id})`);
}
if (image.frame_all <= 1) {
copyFileSync(src, join(outDir, image.bmp));
frameCount++;
continue;
}
const names = frameNames(image);
splitSheet(readFileSync(src), image).forEach((buf, i) => {
writeFileSync(join(outDir, names[i]), buf);
frameCount++;
});
}
const unassigned = layers.filter((l) => l.bucket === 'unassigned').map((l) => l.name);
return {
layerCount: layers.length,
nodeCount: layers.reduce((s, l) => s + l.nodes.length, 0),
imageCount: source.images.size,
frameCount,
unassigned,
warningCount: warnings.length,
};
}
if (process.argv[1] && import.meta.url === pathToFileURL(process.argv[1]).href) {
const r = runConvert();
console.log(`界面 ${r.layerCount} 个 / 节点 ${r.nodeCount} 个`);
console.log(`图片 ${r.imageCount} 张 → 散图 ${r.frameCount} 张`);
if (r.unassigned.length) {
console.warn(`\n⚠️ ${r.unassigned.length} 个层的 bucket 未定,资源已落入 atlas-unassigned,需人工归位:`);
for (const n of r.unassigned) console.warn(` ${n}`);
}
if (r.warningCount > 0) {
console.warn(
`\n⚠️ ${r.warningCount} 条已知的源数据遗留问题(FrameIndex 超出图帧数,已回退为帧 1),`
+ '详情见 ui-migration/intermediate/warnings.json',
);
}
}