// Fresh native inputs for equipment, augment grants and scoring; never reuse an older catalog. import * as e from './extract.mjs'; import * as s from './stages.mjs'; import {table_bindings} from './rounds.mjs'; import {text_rows} from './ui_names.mjs'; import {fixpoint} from './trait_effects.mjs'; export const TYPES=['GridFightRoleRecommendEquipConfigRow','GridFightSPSilverWolfChooseConfigRow', 'GridFightClaraEnhanceConfigRow','GridFightClaraLinkRelationConfigRow','GridFightPhanionUniqueTraitConfigRow', 'GridFightForgeConfigRow','GridFightSeasonExpScoreRow','GridFightScoreRewardConfigRow', 'GridFightDivisionStageRow','GridFightTraitElationTemplateConfigRow', 'GridFightBonfireHealConfigRow','GridFightBonfireEventRow','GridFightShopPriceConfigRow', 'GridFightFormationWaveConfigRow','GridFightStageLevelValueConfigRow','GridFightPenaltyRuleConfigRow', 'GridFightEnemyDifficultyLvConfigRow','GridFightBonusRuleConfigRow','GridFightBinaryNodeRuleConfigRow', 'GridFightLevelBaseValueConfigRow']; export function enrich(value,texts){ if(Array.isArray(value))return value.map(v=>enrich(v,texts)); if(!value||typeof value!=='object')return value; if('hash'in value&&'hash64'in value)return {text:texts[value.hash64]??'',text_id:value}; if('wire'in value)return {...value,value:fixpoint(value.wire)}; return Object.fromEntries(Object.entries(value).map(([k,v])=>[k,enrich(v,texts)])); } export function main(){ const a=e.cli(['client','dump','identity','literals','english','items','output']),ctx=s.extractionContext(a), literals=new Map(e.loadJSON(a.literals).map(r=>[Number(BigInt(r.Address)),r.Value])), texts=text_rows(e.fs.readFileSync(a.english)),raw=e.loadJSON(a.items),proofs=[]; for(const name of TYPES){ const [asset]=table_bindings(ctx.codec,literals,'RPG.GameCore.'+name), match=asset.match(/^BakedConfig\/ExcelOutput(GameCore)?\/(\w+)\.bytes$/); if(!match)e.fail('Unsupported native table path: '+asset); const [rows,proof]=s.table(ctx.assets,ctx.codec,name,match[1]??'',match[2]); if(ctx.codec.schema('RPG.GameCore.'+name).length!==ctx.codec.fields('RPG.GameCore.'+name).size)e.fail('Incomplete catalog schema: '+name); raw[name]=rows;proofs.push(proof);console.log(`${name}: ${rows.length} byte-exact rows`); } const tables=enrich(raw,texts),eq=new Map(tables.GridFightEquipConfigRow.map(r=>[r.ID,r])), seasons=Object.fromEntries([...new Set(raw.GridFightSeasonItemConfigRow.map(r=>r.SeasonID))].map(id=>[id,{ items:raw.GridFightSeasonItemConfigRow.filter(r=>r.SeasonID===id).map(r=>({id:r.ItemID,config_id:r.ConfigID,equipment:eq.get(r.ConfigID)??null,raw_link:r})) }])); s.publish(a,ctx,raw,proofs,{'catalog.json':{identity:ctx.identity,tables,seasons},'catalog.raw.json':raw},'catalog',{ textmap:{file:e.path.basename(a.english),sha256:e.sha256_file(a.english)},gameplay_verified:false }); } e.runMain(import.meta.url,main);