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>
This commit is contained in:
@@ -0,0 +1,93 @@
|
||||
#!/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',
|
||||
);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user