feat(scripts): resolveSpriteFrameUuid - ImgResID → SpriteFrame 真 UUID

This commit is contained in:
2026-09-02 08:23:46 +08:00
parent 712206fba0
commit 2e2a6b0025
2 changed files with 103 additions and 1 deletions
@@ -0,0 +1,21 @@
import { test } from 'node:test';
import assert from 'node:assert/strict';
import { resolveSpriteFrameUuid } from '../../scripts/legacy-layer-to-cocos-prefab.mjs';
// 数据源权威: gameabc_Image.json id=20 -> bmp="00020.png" 位于 atlas-login/,
// 该 .meta 的 subMetas.f9941.uuid 为 e36acab8-e623-4bfb-af05-3c6fd2fddfb4@f9941
// (SpriteFrame 真 UUID, 含 sub-asset 后缀).
test('resolveSpriteFrameUuid("20") 返回 atlas-login/00020.png 的 SpriteFrame 真 UUID', () => {
const uuid = resolveSpriteFrameUuid('20');
assert.equal(uuid, 'e36acab8-e623-4bfb-af05-3c6fd2fddfb4@f9941');
assert.match(uuid, /@f9941$/, '必须含 SpriteFrame sub-asset 后缀 @f9941');
});
test('未知 imgResId → throw(不静默兜底)', () => {
// 数据源权威唯一、下游不兜底: ImgResID 不在 gameabc_Image.json 时必须显式报错.
assert.throws(
() => resolveSpriteFrameUuid('99999999'),
/ImgResID .* not in gameabc_Image\.json/
);
});
@@ -1,4 +1,4 @@
import { readFileSync } from 'node:fs'; import { readFileSync, readdirSync, existsSync, statSync } from 'node:fs';
import { dirname, join } from 'node:path'; import { dirname, join } from 'node:path';
import { fileURLToPath } from 'node:url'; import { fileURLToPath } from 'node:url';
import { DOMParser } from '@xmldom/xmldom'; import { DOMParser } from '@xmldom/xmldom';
@@ -176,3 +176,84 @@ export function mapSpiritTypeToComponent(type) {
} }
return entry.component; return entry.component;
} }
// ImgResID (XML) → SpriteFrame 真 UUID. 数据源: fixtures/gameabc_Image.json + YouleNexus
// `atlas-*` 目录下的 .meta (含 subMetas.f9941.uuid). 下游不兜底: imgResId 不存在 / 对应
// bmp 不在任何 `atlas-*` 下 / .meta 缺 f9941 → 全部 throw.
const IMAGE_MAP_PATH = join(
__dirname,
'../framework-tests/legacy-layer-migration/fixtures/gameabc_Image.json'
);
let _imageMap = null;
function loadImageMap() {
if (!_imageMap) _imageMap = JSON.parse(readFileSync(IMAGE_MAP_PATH, 'utf8'));
return _imageMap;
}
const ATLAS_ROOT = join(
__dirname,
'../YouleNexus/assets/framework/ui'
);
let _bmpToMetaPath = null;
function loadBmpToMetaPath() {
if (_bmpToMetaPath) return _bmpToMetaPath;
const map = new Map();
if (existsSync(ATLAS_ROOT)) {
for (const entry of readdirSync(ATLAS_ROOT)) {
if (!entry.startsWith('atlas-')) continue;
const dir = join(ATLAS_ROOT, entry);
if (!statSync(dir).isDirectory()) continue;
for (const file of readdirSync(dir)) {
if (!file.endsWith('.png.meta')) continue;
const bmpName = file.replace(/\.meta$/, '');
// 同一 bmp 出现在多个 atlas 时, 取首次发现 (字典序);
// YouleNexus 实际数据中无重复, 此为防御性 fallback.
if (!map.has(bmpName)) map.set(bmpName, join(dir, file));
}
}
}
_bmpToMetaPath = map;
return map;
}
/**
* 将 XML 中的 ImgResID 字符串解析为 SpriteFrame 真 UUID (含 @f9941 sub-asset 后缀).
*
* 流程: gameabc_Image.json[id].bmp → `atlas-*`/<bmp>.meta → subMetas.f9941.uuid.
*
* 数据源权威唯一、下游不兜底:
* - imgResId 不在 gameabc_Image.json → throw
* - 对应 bmp 不在任何 `atlas-*` 下 → throw
* - .meta 缺 subMetas.f9941 → throw (说明该资源未走 sprite-frame 导入)
*
* @param {string} imgResId - XML ImgResID 字符串 (如 "20", "21", "25")
* @returns {string} SpriteFrame 真 UUID, 形如 "<uuid>@f9941"
*/
export function resolveSpriteFrameUuid(imgResId) {
const imageMap = loadImageMap();
const list = imageMap.ImageFileList;
if (!Array.isArray(list)) {
throw new Error('gameabc_Image.json missing ImageFileList array');
}
const entry = list.find(e => e && e.id != null && (e.id === Number(imgResId) || String(e.id) === imgResId));
if (!entry || !entry.bmp) {
const known = list.filter(e => e && e.id != null).slice(0, 5).map(e => e.id).join(', ');
throw new Error(`ImgResID "${imgResId}" not in gameabc_Image.json (known ids sample: ${known}...)`);
}
const bmpName = entry.bmp;
const bmpToMeta = loadBmpToMetaPath();
const metaPath = bmpToMeta.get(bmpName);
if (!metaPath) {
throw new Error(`bmp "${bmpName}" (ImgResID ${imgResId}) not found under 'atlas-*' in ${ATLAS_ROOT}`);
}
const meta = JSON.parse(readFileSync(metaPath, 'utf8'));
const spriteFrame = meta.subMetas && meta.subMetas.f9941;
if (!spriteFrame || !spriteFrame.uuid) {
throw new Error(`${bmpName}.meta missing subMetas.f9941.uuid (importer not sprite-frame?)`);
}
return spriteFrame.uuid;
}