diff --git a/cocoscreator_projects/framework-tests/legacy-layer-migration/sprite-uuid-resolver.test.mjs b/cocoscreator_projects/framework-tests/legacy-layer-migration/sprite-uuid-resolver.test.mjs new file mode 100644 index 0000000..7fb87e3 --- /dev/null +++ b/cocoscreator_projects/framework-tests/legacy-layer-migration/sprite-uuid-resolver.test.mjs @@ -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/ + ); +}); diff --git a/cocoscreator_projects/scripts/legacy-layer-to-cocos-prefab.mjs b/cocoscreator_projects/scripts/legacy-layer-to-cocos-prefab.mjs index 1f6544b..2a39acb 100644 --- a/cocoscreator_projects/scripts/legacy-layer-to-cocos-prefab.mjs +++ b/cocoscreator_projects/scripts/legacy-layer-to-cocos-prefab.mjs @@ -1,4 +1,4 @@ -import { readFileSync } from 'node:fs'; +import { readFileSync, readdirSync, existsSync, statSync } from 'node:fs'; import { dirname, join } from 'node:path'; import { fileURLToPath } from 'node:url'; import { DOMParser } from '@xmldom/xmldom'; @@ -176,3 +176,84 @@ export function mapSpiritTypeToComponent(type) { } 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-*`/.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, 形如 "@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; +}