feedback5 WX: the 39 summon models no web dump carries come from the local client (extract.py TOKEN_SPINES) and are drawn instead of the avatar diamond when data/local-assets.json lists them
- tools/local-extract/extract.py TOKEN_SPINES (`--only spine/token`): each token's battle prefab in the battle token packs (pkgrps/btl_pfb_tokens_*.ab; the Windows build has all 39, the iOS build lacks btl_pfb_tokens_0), the skeleton of its Front (or only) Spine renderer, written to public/assets/local/spine/token/<id>/ like the enemy models (sized pma atlas, premultiplied pages; the newer RGBA pages keep their own alpha). The enemy writer is shared (write_spine; the two enemy models re-extract byte for byte). The skinpack job of 乌尔比安's block is gone: it extracted nothing, and that token draws no model in the game (nor do 圣聆初雪's, 酒神's, 贝洛内's and 予愿安洁莉娜's hidden tokens: no Spine renderer, no avatar in either install). - tools/assets/local-token-spines.json (committed, `fetch-assets --local-spines`) → data/assets.json tokens[id].spineLocal for 35 自选 summons, 凯瑟琳's 爬行号·防护单元 and 凛御银灰's three 风雪之眼; the manifest is the same with or without the extraction (JSON diff: only the 39 spineLocal entries and the hash). spine.mjs LOCAL_SPINE_ROLES maps clips the resolver cannot read (电弧's 戴乌 C_Skill1_*, 酒神's 本能的召唤 Loop / End, 白铁's platforms End, 战术锚点 on its Default pose) [ASSUMED where named]. - assets.js spineEntry: a token resolves its spineLocal like an enemy (no web model behind it: the diamond stays when it is not listed or fails to load). Scale as the web tokens (UNIT.modelScale). - setup reports an extraction without the summon models; docs: ASSETS.md "Token models from the local client", DEPLOY.md §6, DESIGN §13 (design/client.md), README. - Tests: test/local-token-models.test.js (new), test/local-extract.test.js (job table, prefab walk, alpha merge), test/assets.test.js (the local token models load like the client does), test/package.test.js (the full zip ships them), test/static-local-art.test.js. Golden unchanged.
This commit is contained in:
1 parent
83d76e507d
commit
575333137c
17 files changed
+2738
-111
No files matched your search
+12
-2
@@ -6,7 +6,7 @@
|
||||
// that ends up on disk wins (later alts are fallbacks: other URLs for the
|
||||
// same file, or other sounds of the same bank);
|
||||
// { model: '<key>' } a Spine model (skel + atlas + page PNGs) from plan.models;
|
||||
// literal(value) a value emitted as it is (no files: enemies[id].spineLocal).
|
||||
// literal(value) a value emitted as it is (no files: enemies[id] / tokens[id].spineLocal).
|
||||
// Inputs are the research JSONs (docs/research/03, 05, 07), the official
|
||||
// audio_data.json and Ark-Models' models_data.json.
|
||||
//
|
||||
@@ -305,6 +305,9 @@ export function collectEnemyIds({ assets07, enemies05, maps05, ops03 }) {
|
||||
* @param {Record<string, import('./spine.mjs').LocalSpineMeta>} [p.localEnemySpines] metadata of the enemy models the
|
||||
* local client has (the committed tools/assets/local-enemy-spines.json, never the disk): each planned enemy listed
|
||||
* gets `spineLocal` = { group: 'spine/enemy/<id>', ...meta } beside its web `spine`
|
||||
* @param {Record<string, import('./spine.mjs').LocalSpineMeta>} [p.localTokenSpines] the same for the token (summon)
|
||||
* models (tools/assets/local-token-spines.json): each planned token listed gets `spineLocal` = { group:
|
||||
* 'spine/token/<id>', ...meta } beside its web `spine`, if any (most have none: the client drew the avatar)
|
||||
* @param {Record<string, any>} [p.extraOperators] charId → { subProfessionId, nationId, skills: [{ index, skillId, iconId }] }
|
||||
* of characters research 07 does not list (the 自选 owned-6★ picks, data/backups.json `units`): planned like the pool
|
||||
* operators from patternOperator
|
||||
@@ -314,7 +317,8 @@ export function collectEnemyIds({ assets07, enemies05, maps05, ops03 }) {
|
||||
*/
|
||||
export function buildPlan({ assets07, ops03, enemies05, maps05, audio, modelsData, charword = null, voiceLang = 'cn',
|
||||
voiceSlots = VOICE_BATTLE_SLOTS,
|
||||
extraEnemyIds = [], extraTokenIds = [], extraHandbook = {}, localEnemySpines = {}, extraOperators = {}, moduleTypes = [] }) {
|
||||
extraEnemyIds = [], extraTokenIds = [], extraHandbook = {}, localEnemySpines = {}, localTokenSpines = {}, extraOperators = {},
|
||||
moduleTypes = [] }) {
|
||||
const notes = [];
|
||||
/** @type {Map<string, any>} */
|
||||
const models = new Map();
|
||||
@@ -417,6 +421,12 @@ export function buildPlan({ assets07, ops03, enemies05, maps05, audio, modelsDat
|
||||
if (model) entry.spineVariant = v;
|
||||
}
|
||||
entry.spine = model;
|
||||
// the official model from the local client, drawn instead of the avatar (or of `spine`) when extracted (optional)
|
||||
const loc = localTokenSpines && Object.hasOwn(localTokenSpines, id) ? localTokenSpines[id] : null;
|
||||
if (loc && typeof loc === 'object') {
|
||||
entry.spineLocal = literal({ group: `spine/token/${id}`, ...loc });
|
||||
notes.push(`${id}: official Spine from the local client when extracted (spineLocal)`);
|
||||
}
|
||||
tokens[id] = entry;
|
||||
const { roles: u, mix } = unitSounds(audio, pickUnitSfx(audio.unitBanks.get(id)));
|
||||
if (mix) u.mix = mix;
|
||||
|
||||
Reference in new issue
Block a user