MatchMaster/tools/import-battle-pass-art.cjs
2026-10-09 10:03:29 +08:00

49 lines
5.2 KiB
JavaScript

// Reproducible binary import and mechanical Cocos UUID replacement. Never overwrites user art.
const fs = require('node:fs'), path = require('node:path'), crypto = require('node:crypto');
const root = path.resolve(__dirname, '..');
const source = 'C:/Users/NK/Desktop/图片资源';
const uuid = key => { const h = crypto.createHash('sha256').update('battle-pass-halloween:' + key).digest('hex'); return `${h.slice(0,8)}-${h.slice(8,12)}-4${h.slice(13,16)}-a${h.slice(17,20)}-${h.slice(20,32)}`; };
const write = (p, value) => fs.writeFileSync(path.join(root, p), JSON.stringify(value, null, 2) + '\n');
function folder(p) {
if (fs.existsSync(path.join(root,p))) return;
folder(path.dirname(p)); fs.mkdirSync(path.join(root,p));
write(p+'.meta', {ver:'1.1.3',uuid:uuid(p),importer:'folder',isBundle:false,subMetas:{}});
}
function importPNG(from, to) {
folder(path.dirname(to));
if (!fs.existsSync(path.join(root,to))) fs.copyFileSync(from,path.join(root,to));
const b=fs.readFileSync(path.join(root,to)), w=b.readUInt32BE(16),h=b.readUInt32BE(20), name=path.basename(to,'.png');
const id=uuid(to), frame=uuid(to+':frame');
if(!fs.existsSync(path.join(root,to+'.meta'))) write(to+'.meta', {ver:'2.3.7',uuid:id,importer:'texture',type:'sprite',wrapMode:'clamp',filterMode:'bilinear',premultiplyAlpha:false,genMipmaps:false,packable:true,width:w,height:h,platformSettings:{},subMetas:{[name]:{ver:'1.0.6',uuid:frame,importer:'sprite-frame',rawTextureUuid:id,trimType:'none',trimThreshold:1,rotated:false,offsetX:0,offsetY:0,trimX:0,trimY:0,width:w,height:h,rawWidth:w,rawHeight:h,borderTop:0,borderBottom:0,borderLeft:0,borderRight:0,subMetas:{}}}});
return JSON.parse(fs.readFileSync(path.join(root,to+'.meta'))).subMetas[name].uuid;
}
const art={};
// This supplied JPG is the clean main-page background, not a composed screenshot.
const bgSource=path.join(source,'万圣节10月战令/万圣节通行证界面0928.jpg'),bgTarget=path.join(root,'assets/shop/img/passCheck/bg.jpg');
const hash=p=>crypto.createHash('sha256').update(fs.readFileSync(p)).digest('hex');
if(!['b816e5b36212150b1d33fc4aa27736111ec972cea28e968f7952b156df585575',hash(bgSource)].includes(hash(bgTarget)))throw Error('Main background changed outside this import; preserve it for manual review.');
fs.copyFileSync(bgSource,bgTarget);
art.btn_claim=importPNG(path.join(root,'assets/res/move/lingqu.png'),'assets/passCheck/img/settlement/btn_claim.png');
const map={'超值':'badge_best_value','文字':'copy_buy_now','结束字':'copy_season_end_empty','结束文字00':'copy_season_end_rewards','放弃文字':'copy_abandon_confirm','解锁01':'unlock_vip','解锁02':'unlock_svip','vip图':'vip_card_art','vip证':'vip_badge','贵宾卡02':'svip_card_art','豪华卡':'svip_badge'};
for(const [name,out] of Object.entries(map)) art[out]=importPNG(path.join(source,'万圣节通行证购买图更改0930',name+'.png'),'assets/passCheck/img/settlement/'+out+'.png');
const main={'进度条底':'progress_bg','南瓜00':'pumpkin_normal','南瓜01':'pumpkin_active','时间段':'time_bg','时钟':'clock','shujintdu':'progress_vertical','shujintdu00':'progress_vertical_active','yaoshi':'key'};
for(const [name,out] of Object.entries(main)) art[out]=importPNG(path.join(source,'万圣节10月战令',name+'.png'),'assets/passCheck/img/halloween/'+out+'.png');
for(const [from,to] of [['进度条上的数字01','digits_progress'],['南瓜上的数字02','digits_level_large'],['南瓜上显示数字','digits_level_small']]) {
for(let i=0;i<10;i++) importPNG(path.join(source,'万圣节10月战令',from,i+'.png'),`assets/passCheck/img/halloween/${to}/${i}.png`);
}
art.slash=importPNG(path.join(source,'万圣节10月战令/进度条上的数字01/斜杆.png'),'assets/passCheck/img/halloween/slash.png');
const replacements={'18d65e4a-9a87-4fdf-8fe5-e0334c8e6cd5':art.clock,'4a54bc22-a445-49f2-ab31-061dc1ba189e':art.progress_bg,'24adad9c-1a33-44bd-b471-d615817acdb1':art.key,'79c6af2e-9a84-462f-8d91-15a83ef1e068':art.progress_vertical,'1f8f8247-0c5c-44a6-95f5-81ebc95d40e9':art.progress_vertical_active,'8d1ce904-0216-4aae-95bd-fd451329ff66':art.pumpkin_active};
replacements['0ad127f3-5a65-4404-ad12-f7ad4225d956']=art.slash;
for(const file of ['assets/shop/prefab/passCheck.prefab','assets/shop/prefab/passCheckItemLv.prefab']) {
let raw=fs.readFileSync(path.join(root,file),'utf8');
for(const [from,to] of Object.entries(replacements)) raw=raw.replaceAll(from,to);
fs.writeFileSync(path.join(root,file),raw);
}
// Figure 5 only changes art references; purchase behavior is untouched.
const buy='assets/shop/prefab/buyActivate.prefab';
let raw=fs.readFileSync(path.join(root,buy),'utf8');
raw=raw.replaceAll('1bf393cb-7939-4226-b585-ccb706908c72',art.vip_badge).replaceAll('bc0b12da-552c-4cb9-8df6-1ab49a7ff900',art.svip_badge);
fs.writeFileSync(path.join(root,buy),raw);
for(const p of ['assets/Script/BattlePassSettlement.ts','assets/Script/BattlePassArt.ts','assets/Script/module/Config/BattlePassSettlementModel.ts']) if(!fs.existsSync(path.join(root,p+'.meta'))) write(p+'.meta',{ver:'1.1.0',uuid:uuid(p),importer:'typescript',isPlugin:false,loadPluginInWeb:true,loadPluginInNative:true,loadPluginInEditor:false,subMetas:{}});
console.log('Imported battle pass PNG assets and updated prefab art references.');