fix(scripts): final review Critical+Important fixes (Widget alignment, full readLayerXml, Label _string, atlas selection, hard-coded paths, exit code, dead code removal)
This commit is contained in:
@@ -65,6 +65,26 @@ export function readLayerXml(path) {
|
||||
h: getProp(propList, 'Height'),
|
||||
group: getProp(propList, 'BelongGroupID'),
|
||||
indexOfLayer: getProp(propList, 'IndexOfLayer'),
|
||||
text: getProp(propList, 'Text'),
|
||||
sizeCalcMode: getProp(propList, 'SizeCalcMode'),
|
||||
sizeParentID: getProp(propList, 'SizeParentID'),
|
||||
widthCalcMode: getProp(propList, 'WidthCalcMode'),
|
||||
heightCalcMode: getProp(propList, 'HeightCalcMode'),
|
||||
sizeRelaWidth: getProp(propList, 'SizeRelaWidth'),
|
||||
sizeRelaHeight: getProp(propList, 'SizeRelaHeight'),
|
||||
coordSelfPos: getProp(propList, 'CoordSelfPos'),
|
||||
coordRelaX: getProp(propList, 'CoordRelaX'),
|
||||
coordRelaY: getProp(propList, 'CoordRelaY'),
|
||||
coordParentID: getProp(propList, 'CoordParentID'),
|
||||
belongLayerID: getProp(propList, 'BelongLayerID'),
|
||||
fontSize: getProp(propList, 'FontSize'),
|
||||
fontColor: getProp(propList, 'FontColor'),
|
||||
alignHorz: getProp(propList, 'AlignHorz'),
|
||||
alignVert: getProp(propList, 'AlignVert'),
|
||||
fontBold: getProp(propList, 'FontBold'),
|
||||
wordWrap: getProp(propList, 'WordWrap'),
|
||||
lineSpace: getProp(propList, 'LineSpace'),
|
||||
rowSpace: getProp(propList, 'RowSpace'),
|
||||
};
|
||||
});
|
||||
|
||||
@@ -97,14 +117,31 @@ export function computeLpos(spirit) {
|
||||
/**
|
||||
* 计算 Spirit 的 contentSize (Cocos UI 节点尺寸).
|
||||
*
|
||||
* 数据源权威: SizeCalcMode 缺失视作 0 (直接读 Width/Height); 非 0 抛错,
|
||||
* 由上游显式决定是否逆向 gameabc.min.js (Task 5 范围, 本任务不支持).
|
||||
* 数据源权威: SizeCalcMode=0 直接读 Width/Height; SizeCalcMode=2 按
|
||||
* ImgResID 对应的 image natural size × SizeRela/10000; 其他未知模式显式报错.
|
||||
*
|
||||
* @param {{ w?: string, h?: string, sizeCalcMode?: string, id?: string, name?: string }} spirit
|
||||
* @returns {{ width: number, height: number }}
|
||||
*/
|
||||
export function computeContentSize(spirit) {
|
||||
export function computeContentSize(spirit, naturalSize = null) {
|
||||
const sizeCalcMode = parseInt(spirit.sizeCalcMode || '0', 10);
|
||||
if (sizeCalcMode === 1) {
|
||||
throw new Error(`SizeCalcMode=${sizeCalcMode} not yet supported for Spirit ${spirit.id} (${spirit.name}) - reverse gameabc.min.js first (Task 5)`);
|
||||
}
|
||||
if (sizeCalcMode === 2) {
|
||||
const imageNaturalSize = naturalSize || lookupImageNaturalSize(spirit.imgResID);
|
||||
const widthMode = parseInt(spirit.widthCalcMode || '0', 10);
|
||||
const heightMode = parseInt(spirit.heightCalcMode || '0', 10);
|
||||
const widthRatio = parseFloat(spirit.sizeRelaWidth);
|
||||
const heightRatio = parseFloat(spirit.sizeRelaHeight);
|
||||
if (!Number.isFinite(widthRatio) || !Number.isFinite(heightRatio)) {
|
||||
throw new Error(`Spirit ${spirit.id} (${spirit.name}) missing SizeRelaWidth/SizeRelaHeight for SizeCalcMode=2`);
|
||||
}
|
||||
return {
|
||||
width: widthMode === 1 ? imageNaturalSize.width * widthRatio / 10000 : parseFloat(spirit.w || '0'),
|
||||
height: heightMode === 1 ? imageNaturalSize.height * heightRatio / 10000 : parseFloat(spirit.h || '0'),
|
||||
};
|
||||
}
|
||||
if (sizeCalcMode !== 0) {
|
||||
throw new Error(`SizeCalcMode=${sizeCalcMode} not yet supported for Spirit ${spirit.id} (${spirit.name}) - reverse gameabc.min.js first (Task 5)`);
|
||||
}
|
||||
@@ -117,29 +154,47 @@ export function computeContentSize(spirit) {
|
||||
/**
|
||||
* 计算 Spirit 在其所属 group 内的 cc.Widget 锚定参数 (PoC 阶段 2 简化版).
|
||||
*
|
||||
* 数据源权威: 公式仅处理 Spirit.Y < 360 (上) vs > 360 (下) 与水平偏移, 完全基于
|
||||
* 已知字段 (x/y/w/h). SizeCalcMode / CoordRelaX / CoordRelaY 等逆向未出的字段
|
||||
* 暂不支持 — 由 buildSpiritBlock 调用方保证父 group 已经处理 SizeCalcMode ≠ 0.
|
||||
*
|
||||
* 简化规则:
|
||||
* _alignFlags = 16 | 8 # 16=水平居中, 8=垂直居中
|
||||
* _horizontalCenter = x + w/2 - 640 # 像素偏移, 1280 坐标系水平中心
|
||||
* _verticalCenter = 360 - (y + h/2) # Y-up 翻转 + 720 坐标系垂直中心
|
||||
* 数据源权威: 按节点尺寸与 name 几何规则区分 full-screen (45),
|
||||
* top-left (9), 以及 normal (16) 三种 Widget 对齐契约.
|
||||
*
|
||||
* @param {{ x?: string, y?: string, w?: string, h?: string }} spirit
|
||||
* @returns {object} cc.Widget 字段 (除 __type__/node/__prefab/_id 外)
|
||||
*/
|
||||
export function computeWidgetAlignment(spirit) {
|
||||
const x = parseFloat(spirit.x || '0');
|
||||
const y = parseFloat(spirit.y || '0');
|
||||
const w = parseFloat(spirit.w || '0');
|
||||
const h = parseFloat(spirit.h || '0');
|
||||
const name = String(spirit.name || '');
|
||||
const width = parseFloat(spirit.w || '0');
|
||||
const height = parseFloat(spirit.h || '0');
|
||||
const lpos = computeLpos(spirit);
|
||||
const isFullScreen = width === 1280 && height === 720;
|
||||
if (isFullScreen) {
|
||||
return {
|
||||
_alignFlags: 45,
|
||||
_target: null,
|
||||
_left: 0, _right: 0, _top: 0, _bottom: 0,
|
||||
_isAbsLeft: true, _isAbsRight: true, _isAbsTop: true, _isAbsBottom: true,
|
||||
_isAbsHorizontalCenter: true, _isAbsVerticalCenter: true,
|
||||
_originalWidth: 100, _originalHeight: 100,
|
||||
_alignMode: 2, _lockFlags: 0,
|
||||
};
|
||||
}
|
||||
|
||||
const isTopLeft = lpos.y > 0 && lpos.x < 0 || /背景|bg/i.test(name);
|
||||
if (isTopLeft) {
|
||||
return {
|
||||
_alignFlags: 9,
|
||||
_target: null,
|
||||
_left: lpos.x, _top: lpos.y,
|
||||
_isAbsLeft: true, _isAbsRight: true, _isAbsTop: true, _isAbsBottom: true,
|
||||
_isAbsHorizontalCenter: true, _isAbsVerticalCenter: true,
|
||||
_originalWidth: 0, _originalHeight: 0,
|
||||
_alignMode: 2, _lockFlags: 0,
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
_alignFlags: 16 | 8, // 水平居中 + 垂直居中
|
||||
_alignFlags: 16,
|
||||
_target: null,
|
||||
_left: 0, _right: 0, _top: 0, _bottom: 0,
|
||||
_horizontalCenter: x + w / 2 - 640, // 1280 体系半宽
|
||||
_verticalCenter: 360 - (y + h / 2), // Y-up + 720 体系半高
|
||||
_horizontalCenter: lpos.x, _verticalCenter: 0,
|
||||
_isAbsLeft: true, _isAbsRight: true, _isAbsTop: true, _isAbsBottom: true,
|
||||
_isAbsHorizontalCenter: true, _isAbsVerticalCenter: true,
|
||||
_originalWidth: 0, _originalHeight: 0,
|
||||
@@ -224,30 +279,106 @@ function loadImageMap() {
|
||||
return _imageMap;
|
||||
}
|
||||
|
||||
let _imageNaturalSizeMap = null;
|
||||
function loadImageNaturalSizeMap() {
|
||||
if (_imageNaturalSizeMap) return _imageNaturalSizeMap;
|
||||
const list = loadImageMap().ImageFileList;
|
||||
if (!Array.isArray(list)) {
|
||||
throw new Error('gameabc_Image.json missing ImageFileList array');
|
||||
}
|
||||
_imageNaturalSizeMap = new Map();
|
||||
for (const entry of list) {
|
||||
if (!entry || entry.id == null) continue;
|
||||
const width = Number(entry.w_all);
|
||||
const height = Number(entry.h_all);
|
||||
if (!Number.isFinite(width) || !Number.isFinite(height)) continue;
|
||||
_imageNaturalSizeMap.set(String(entry.id), { width, height });
|
||||
}
|
||||
return _imageNaturalSizeMap;
|
||||
}
|
||||
|
||||
function lookupImageNaturalSize(imgResId) {
|
||||
const key = String(imgResId);
|
||||
const naturalSize = loadImageNaturalSizeMap().get(key);
|
||||
if (!naturalSize) {
|
||||
throw new Error(`ImgResID "${imgResId}" missing natural size in gameabc_Image.json`);
|
||||
}
|
||||
return naturalSize;
|
||||
}
|
||||
|
||||
const ATLAS_ROOT = join(
|
||||
__dirname,
|
||||
'../YouleNexus/assets/framework/ui'
|
||||
);
|
||||
|
||||
let _bmpToMetaPath = null;
|
||||
function loadBmpToMetaPath() {
|
||||
if (_bmpToMetaPath) return _bmpToMetaPath;
|
||||
const ATLAS_BY_LAYER_NAME = [
|
||||
['MainScene_PlayerInfo', 'atlas-hall'],
|
||||
['BackHall', 'atlas-hall'],
|
||||
['Login', 'atlas-login'],
|
||||
['Notice', 'atlas-login'],
|
||||
['Protol', 'atlas-login'],
|
||||
['Loading', 'atlas-login'],
|
||||
['Kick', 'atlas-login'],
|
||||
['Reconnect', 'atlas-login'],
|
||||
['Setting', 'atlas-login'],
|
||||
['Tips', 'atlas-login'],
|
||||
['updateRoomCard', 'atlas-login'],
|
||||
['phoneInfo', 'atlas-login'],
|
||||
['recordLayer', 'atlas-login'],
|
||||
['MenuPlayerInfo', 'atlas-login'],
|
||||
];
|
||||
|
||||
export function selectAtlasForLayerName(layerName) {
|
||||
const normalizedName = String(layerName || '').toLowerCase();
|
||||
const match = ATLAS_BY_LAYER_NAME.find(([keyword]) => normalizedName.includes(keyword.toLowerCase()));
|
||||
return match ? match[1] : 'atlas-login';
|
||||
}
|
||||
|
||||
function listAtlasDirectories() {
|
||||
if (!existsSync(ATLAS_ROOT)) return [];
|
||||
return readdirSync(ATLAS_ROOT)
|
||||
.filter(entry => entry.startsWith('atlas-') && statSync(join(ATLAS_ROOT, entry)).isDirectory());
|
||||
}
|
||||
|
||||
const _bmpToMetaPath = new Map();
|
||||
function loadBmpToMetaPath(preferredAtlas = null) {
|
||||
const cacheKey = preferredAtlas || 'default';
|
||||
if (_bmpToMetaPath.has(cacheKey)) return _bmpToMetaPath.get(cacheKey);
|
||||
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));
|
||||
const directories = listAtlasDirectories();
|
||||
const orderedDirectories = [
|
||||
...(preferredAtlas ? [preferredAtlas] : []),
|
||||
...(preferredAtlas === 'atlas-login' || !preferredAtlas ? ['atlas-login'] : []),
|
||||
...directories.filter(entry => entry !== preferredAtlas && entry !== 'atlas-login'),
|
||||
];
|
||||
for (const entry of orderedDirectories) {
|
||||
const dir = join(ATLAS_ROOT, entry);
|
||||
for (const file of readdirSync(dir)) {
|
||||
if (!file.endsWith('.png.meta')) continue;
|
||||
const bmpName = file.replace(/\.meta$/, '');
|
||||
if (!map.has(bmpName)) map.set(bmpName, join(dir, file));
|
||||
}
|
||||
}
|
||||
|
||||
// Cocos imports multi-frame source BMPs as <bmp>_1.png, <bmp>_2.png, ...
|
||||
// Keep the first frame deterministic when a legacy image has no exact BMP basename.
|
||||
const imageMap = loadImageMap();
|
||||
const imageList = Array.isArray(imageMap.ImageFileList) ? imageMap.ImageFileList : [];
|
||||
for (const image of imageList) {
|
||||
if (!image?.bmp || map.has(image.bmp)) continue;
|
||||
const baseName = image.bmp.replace(/\.png$/i, '');
|
||||
const frameCount = Number.isInteger(Number(image.frame_all)) && Number(image.frame_all) > 0
|
||||
? Number(image.frame_all)
|
||||
: 1;
|
||||
for (let frame = 1; frame <= frameCount; frame += 1) {
|
||||
const frameName = `${baseName}_${frame}.png`;
|
||||
if (map.has(frameName)) {
|
||||
map.set(image.bmp, map.get(frameName));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
_bmpToMetaPath = map;
|
||||
_bmpToMetaPath.set(cacheKey, map);
|
||||
return map;
|
||||
}
|
||||
|
||||
@@ -262,9 +393,10 @@ function loadBmpToMetaPath() {
|
||||
* - .meta 缺 subMetas.f9941 → throw (说明该资源未走 sprite-frame 导入)
|
||||
*
|
||||
* @param {string} imgResId - XML ImgResID 字符串 (如 "20", "21", "25")
|
||||
* @param {string} [atlasDir] - 可选的 layer atlas 目录, 例如 atlas-login.
|
||||
* @returns {string} SpriteFrame 真 UUID, 形如 "<uuid>@f9941"
|
||||
*/
|
||||
export function resolveSpriteFrameUuid(imgResId) {
|
||||
export function resolveSpriteFrameUuid(imgResId, atlasDir = null) {
|
||||
const imageMap = loadImageMap();
|
||||
const list = imageMap.ImageFileList;
|
||||
if (!Array.isArray(list)) {
|
||||
@@ -277,7 +409,7 @@ export function resolveSpriteFrameUuid(imgResId) {
|
||||
}
|
||||
const bmpName = entry.bmp;
|
||||
|
||||
const bmpToMeta = loadBmpToMetaPath();
|
||||
const bmpToMeta = loadBmpToMetaPath(atlasDir);
|
||||
const metaPath = bmpToMeta.get(bmpName);
|
||||
if (!metaPath) {
|
||||
throw new Error(`bmp "${bmpName}" (ImgResID ${imgResId}) not found under 'atlas-*' in ${ATLAS_ROOT}`);
|
||||
@@ -376,7 +508,7 @@ function makeUiTransform(nodeId, compPrefabId, width, height) {
|
||||
};
|
||||
}
|
||||
|
||||
function makeWidget(nodeId, compPrefabId) {
|
||||
function makeWidget(nodeId, compPrefabId, originalWidth = 100, originalHeight = 100) {
|
||||
return {
|
||||
__type__: 'cc.Widget',
|
||||
_name: '',
|
||||
@@ -391,7 +523,7 @@ function makeWidget(nodeId, compPrefabId) {
|
||||
_horizontalCenter: 0, _verticalCenter: 0,
|
||||
_isAbsLeft: true, _isAbsRight: true, _isAbsTop: true, _isAbsBottom: true,
|
||||
_isAbsHorizontalCenter: true, _isAbsVerticalCenter: true,
|
||||
_originalWidth: 0, _originalHeight: 0,
|
||||
_originalWidth: originalWidth, _originalHeight: originalHeight,
|
||||
_alignMode: 2,
|
||||
_lockFlags: 0,
|
||||
_id: '',
|
||||
@@ -446,7 +578,13 @@ function makeSprite(nodeId, compPrefabId, spriteFrameUuid, type = 0) {
|
||||
};
|
||||
}
|
||||
|
||||
function makeLabel(nodeId, compPrefabId, text) {
|
||||
function makeLabel(nodeId, compPrefabId, spirit) {
|
||||
const fontSize = Number.isFinite(Number(spirit.fontSize)) ? Number(spirit.fontSize) : 40;
|
||||
const lineSpace = Number.isFinite(Number(spirit.lineSpace)) ? Number(spirit.lineSpace) : fontSize;
|
||||
const rowSpace = Number.isFinite(Number(spirit.rowSpace)) ? Number(spirit.rowSpace) : 0;
|
||||
const color = Number.isInteger(Number(spirit.fontColor)) ? Number(spirit.fontColor) : 0xffffff;
|
||||
const horizontalAlign = Number.isInteger(Number(spirit.alignHorz)) ? Number(spirit.alignHorz) : 1;
|
||||
const verticalAlign = Number.isInteger(Number(spirit.alignVert)) ? Number(spirit.alignVert) : 1;
|
||||
return {
|
||||
__type__: 'cc.Label',
|
||||
_name: '',
|
||||
@@ -458,20 +596,28 @@ function makeLabel(nodeId, compPrefabId, text) {
|
||||
_customMaterial: null,
|
||||
_srcBlendFactor: 2,
|
||||
_dstBlendFactor: 4,
|
||||
_color: { __type__: 'cc.Color', r: 255, g: 255, b: 255, a: 255 },
|
||||
_string: text || '',
|
||||
_horizontalAlign: 1,
|
||||
_verticalAlign: 1,
|
||||
_actualFontSize: 40,
|
||||
_fontSize: 40,
|
||||
_color: {
|
||||
__type__: 'cc.Color',
|
||||
r: (color >> 16) & 255,
|
||||
g: (color >> 8) & 255,
|
||||
b: color & 255,
|
||||
a: 255,
|
||||
},
|
||||
_string: spirit.text || spirit.name || '',
|
||||
_horizontalAlign: horizontalAlign,
|
||||
_verticalAlign: verticalAlign,
|
||||
_actualFontSize: fontSize,
|
||||
_fontSize: fontSize,
|
||||
_fontFamily: 'Arial',
|
||||
_lineHeight: 40,
|
||||
_lineHeight: lineSpace,
|
||||
_overflow: 0,
|
||||
_enableWrapText: true,
|
||||
_enableWrapText: spirit.wordWrap !== undefined && spirit.wordWrap !== '0',
|
||||
_font: null,
|
||||
_isSystemFontUsed: true,
|
||||
_spacingX: 0,
|
||||
_isItalic: false, _isBold: false, _isUnderline: false,
|
||||
_spacingX: rowSpace,
|
||||
_isItalic: false,
|
||||
_isBold: spirit.fontBold !== undefined && spirit.fontBold !== '0',
|
||||
_isUnderline: false,
|
||||
_underlineHeight: 2,
|
||||
_cacheMode: 0,
|
||||
_enableOutline: false,
|
||||
@@ -579,7 +725,7 @@ function makeEditBox(nodeId, compPrefabId, spriteFrameUuid, text) {
|
||||
* @param {{ layerId?: string, layerName: string, spirits: Array<{ id: string, name: string, type: string, imgResID: string, x: string, y: string, w: string, h: string, group: string, indexOfLayer: string }> }} layer
|
||||
* @returns {Array<object>} Cocos prefab JSON 数组
|
||||
*/
|
||||
export function emitPrefabJson(layer) {
|
||||
export function emitPrefabJson(layer, opts = {}) {
|
||||
if (!layer || !layer.layerName) {
|
||||
throw new Error('emitPrefabJson: layer.layerName is required');
|
||||
}
|
||||
@@ -588,11 +734,13 @@ export function emitPrefabJson(layer) {
|
||||
}
|
||||
|
||||
const out = [];
|
||||
const targetName = opts.targetName || layer.layerName;
|
||||
const atlasName = opts.atlasName || selectAtlasForLayerName(targetName);
|
||||
|
||||
// ── 1. cc.Prefab 头 ─────────────────────────────────────────────
|
||||
out.push({
|
||||
__type__: 'cc.Prefab',
|
||||
_name: layer.layerName,
|
||||
_name: targetName,
|
||||
_objFlags: 0,
|
||||
__editorExtras__: {},
|
||||
_native: '',
|
||||
@@ -602,7 +750,7 @@ export function emitPrefabJson(layer) {
|
||||
});
|
||||
|
||||
// ── 2. 根节点 cc.Node (id=1) ────────────────────────────────────
|
||||
const rootNode = makeNode(layer.layerName, null);
|
||||
const rootNode = makeNode(targetName, null);
|
||||
out.push(rootNode);
|
||||
const rootId = out.length - 1; // =1
|
||||
|
||||
@@ -628,7 +776,7 @@ export function emitPrefabJson(layer) {
|
||||
if (!spirit) {
|
||||
throw new Error(`emitPrefabJson: spirit id ${spiritId} referenced by ${gi.group.name} but not found in layer.spirits`);
|
||||
}
|
||||
const info = buildSpiritBlock(spirit, { __id__: gi.nodeId }, out, { parentIsGroup: true });
|
||||
const info = buildSpiritBlock(spirit, { __id__: gi.nodeId }, out, { parentIsGroup: true, atlasName });
|
||||
spiritInfo.set(spiritId, info);
|
||||
gi.node._children.push({ __id__: info.nodeId });
|
||||
}
|
||||
@@ -639,7 +787,7 @@ export function emitPrefabJson(layer) {
|
||||
if (!spirit) {
|
||||
throw new Error(`emitPrefabJson: root child spirit id ${spiritId} not found in layer.spirits`);
|
||||
}
|
||||
const info = buildSpiritBlock(spirit, { __id__: rootId }, out, { parentIsGroup: false });
|
||||
const info = buildSpiritBlock(spirit, { __id__: rootId }, out, { parentIsGroup: false, atlasName });
|
||||
spiritInfo.set(spiritId, info);
|
||||
rootNode._children.push({ __id__: info.nodeId });
|
||||
}
|
||||
@@ -669,7 +817,12 @@ export function emitPrefabJson(layer) {
|
||||
*/
|
||||
function buildSpiritBlock(spirit, parentRef, out, opts = { parentIsGroup: false }) {
|
||||
const lpos = computeLpos(spirit);
|
||||
const size = computeContentSize(spirit);
|
||||
const width = parseFloat(spirit.w || '0');
|
||||
const height = parseFloat(spirit.h || '0');
|
||||
const isFullScreen = width === 1280 && height === 720;
|
||||
const size = isFullScreen
|
||||
? { width: 1600, height: 720 }
|
||||
: computeContentSize(spirit);
|
||||
const componentName = mapSpiritTypeToComponent(spirit.type);
|
||||
|
||||
// 1. cc.Node (主组件 id=K+0)
|
||||
@@ -680,19 +833,18 @@ function buildSpiritBlock(spirit, parentRef, out, opts = { parentIsGroup: false
|
||||
|
||||
// 2. cc.UITransform (K+1)
|
||||
const uiCompInfo = makeCompPrefabInfo();
|
||||
out.push(uiCompInfo);
|
||||
const uiCompInfoId = out.length - 1;
|
||||
const uiTransform = makeUiTransform(nodeId, uiCompInfoId, size.width, size.height);
|
||||
const uiTransform = makeUiTransform(nodeId, out.length + 1, size.width, size.height);
|
||||
out.push(uiTransform);
|
||||
const uiId = out.length - 1;
|
||||
out.push(uiCompInfo);
|
||||
const uiCompInfoId = out.length - 1;
|
||||
|
||||
// 3. 主组件 (K+3) — CompPrefabInfo 先 push (K+2), 主组件 __prefab → 该 CompPrefabInfo
|
||||
// 3. 主组件 (K+3) — component 先 push, CompPrefabInfo follows it.
|
||||
const mainCompInfo = makeCompPrefabInfo();
|
||||
out.push(mainCompInfo);
|
||||
const mainCompInfoId = out.length - 1;
|
||||
const mainCompInfoId = out.length + 1;
|
||||
|
||||
const spriteFrameUuid = (spirit.type === '0' || spirit.type === '3' || spirit.type === '5')
|
||||
? resolveSpriteFrameUuid(spirit.imgResID)
|
||||
? resolveSpriteFrameUuid(spirit.imgResID, opts.atlasName)
|
||||
: null;
|
||||
|
||||
let mainComp;
|
||||
@@ -700,7 +852,7 @@ function buildSpiritBlock(spirit, parentRef, out, opts = { parentIsGroup: false
|
||||
const spriteType = spirit.type === '5' ? 1 : 0; // 5=SLICED, else SIMPLE
|
||||
mainComp = makeSprite(nodeId, mainCompInfoId, spriteFrameUuid, spriteType);
|
||||
} else if (componentName === 'cc.Label') {
|
||||
mainComp = makeLabel(nodeId, mainCompInfoId, spirit.name);
|
||||
mainComp = makeLabel(nodeId, mainCompInfoId, spirit);
|
||||
} else if (componentName === 'cc.ProgressBar') {
|
||||
mainComp = makeProgressBar(nodeId, mainCompInfoId, spriteFrameUuid);
|
||||
} else if (componentName === 'cc.EditBox') {
|
||||
@@ -712,18 +864,18 @@ function buildSpiritBlock(spirit, parentRef, out, opts = { parentIsGroup: false
|
||||
}
|
||||
out.push(mainComp);
|
||||
const mainCompId = out.length - 1;
|
||||
out.push(mainCompInfo);
|
||||
|
||||
// 4. cc.Widget (K+5) — CompPrefabInfo 先 push (K+4)
|
||||
// 4. cc.Widget (K+5) — component 先 push, CompPrefabInfo follows it.
|
||||
const widgetCompInfo = makeCompPrefabInfo();
|
||||
out.push(widgetCompInfo);
|
||||
const widgetCompInfoId = out.length - 1;
|
||||
// parentIsGroup 时走 computeWidgetAlignment (水平+垂直居中); Layer 根直挂时
|
||||
// 用默认 _alignFlags=45 (全屏铺满占位, 后续 PoC 阶段再细化).
|
||||
// parentIsGroup 时走 computeWidgetAlignment; Layer 根直挂时使用全屏 Widget.
|
||||
const widget = opts.parentIsGroup
|
||||
? makeSpiritWidget(nodeId, widgetCompInfoId, spirit)
|
||||
: makeWidget(nodeId, widgetCompInfoId);
|
||||
? makeSpiritWidget(nodeId, out.length + 1, spirit)
|
||||
: makeWidget(nodeId, out.length + 1);
|
||||
out.push(widget);
|
||||
const widgetId = out.length - 1;
|
||||
out.push(widgetCompInfo);
|
||||
const widgetCompInfoId = out.length - 1;
|
||||
|
||||
// 5. cc.PrefabInfo (K+7) — Node 的 _prefab 指向这里
|
||||
const prefabInfo = makePrefabInfo();
|
||||
@@ -744,19 +896,19 @@ function buildSpiritBlock(spirit, parentRef, out, opts = { parentIsGroup: false
|
||||
function appendNodeEnvelope(node, nodeId, out) {
|
||||
// 1. UITransform + CompPrefabInfo
|
||||
const uiCompInfo = makeCompPrefabInfo();
|
||||
out.push(uiCompInfo);
|
||||
const uiCompInfoId = out.length - 1;
|
||||
const uiTransform = makeUiTransform(nodeId, uiCompInfoId, DESIGN_WIDTH, DESIGN_HEIGHT);
|
||||
const uiTransform = makeUiTransform(nodeId, out.length + 1, DESIGN_WIDTH, DESIGN_HEIGHT);
|
||||
out.push(uiTransform);
|
||||
const uiId = out.length - 1;
|
||||
out.push(uiCompInfo);
|
||||
const uiCompInfoId = out.length - 1;
|
||||
|
||||
// 2. Widget + CompPrefabInfo
|
||||
const widgetCompInfo = makeCompPrefabInfo();
|
||||
out.push(widgetCompInfo);
|
||||
const widgetCompInfoId = out.length - 1;
|
||||
const widget = makeWidget(nodeId, widgetCompInfoId);
|
||||
const widget = makeWidget(nodeId, out.length + 1);
|
||||
out.push(widget);
|
||||
const widgetId = out.length - 1;
|
||||
out.push(widgetCompInfo);
|
||||
const widgetCompInfoId = out.length - 1;
|
||||
|
||||
// 3. PrefabInfo
|
||||
const prefabInfo = makePrefabInfo();
|
||||
|
||||
Reference in New Issue
Block a user