// One-time conversion to editable Cocos 2.4 assets. Existing prefabs are never overwritten. const fs = require('node:fs'), path = require('node:path'), crypto = require('node:crypto'); const root = path.resolve(__dirname, '..'); const read = p => JSON.parse(fs.readFileSync(path.join(root, p), 'utf8')); const clone = v => JSON.parse(JSON.stringify(v)); const uuid = key => { const h = crypto.createHash('sha256').update('pass-prefab:' + 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, v) => fs.writeFileSync(path.join(root, p), JSON.stringify(v, null, 2) + '\n', {flag:'wx'}); const buy = read('assets/shop/prefab/buyActivate.prefab'), rewards = read('assets/publicUI/prefab/rewardNode.prefab'); const layout = read('assets/action_bundle/prefab/dailyQuests.prefab').find(v => v.__type__ === 'cc.Layout'); function copyTexture(from, name) { const to = 'assets/passCheck/img/settlement/' + name + '.png'; if (fs.existsSync(path.join(root, to))) return; const meta = read(from + '.meta'), frame = clone(Object.values(meta.subMetas)[0]); meta.uuid = uuid(to); frame.uuid = uuid(to + ':frame'); frame.rawTextureUuid = meta.uuid; meta.subMetas = {[name]:frame}; fs.copyFileSync(path.join(root, from), path.join(root, to), fs.constants.COPYFILE_EXCL); write(to + '.meta', meta); } copyTexture('assets/mini_program_benefits/texture/solid-white.png', 'modal_mask'); copyTexture('assets/coin_madness/texture/ui/ended_reward_bg.png', 'reward_card'); const frame = p => Object.values(read(p + '.meta').subMetas)[0]; const local = n => frame('assets/passCheck/img/settlement/' + n + '.png'); const lose = n => frame('assets/lose/texture/' + n + '.png'); const atlas = read('assets/shop/img2/shopUI.plist.meta').subMetas; function build(name, contents) { const file = 'assets/passCheck/prefab/' + name + '.prefab'; if (fs.existsSync(path.join(root, file))) { console.log('Preserved editor asset:', file); return; } const objects = [clone(buy[0])]; objects[0].data = {__id__:1}; const add = value => { objects.push(value); return objects.length - 1; }; function component(node, source) { const c = clone(source); c.node = {__id__:node}; c._id = ''; const id = add(c); objects[node]._components.push({__id__:id}); return c; } function node(parent, name, x=0, y=0, w=0, h=0, active=true) { const n = clone(buy[1]); n._name=name; n._parent=parent?{__id__:parent}:null; n._children=[]; n._components=[]; n._active=active; n._contentSize.width=w; n._contentSize.height=h; n._trs.array=[x,y,0,0,0,0,1,1,1,1]; const id=add(n); n._prefab={__id__:add({__type__:'cc.PrefabInfo',root:{__id__:1},asset:{__id__:0},fileId:uuid(file+':'+id),sync:false})}; if(parent)objects[parent]._children.push({__id__:id}); return id; } function image(parent, name, f, x=0, y=0, w=f.rawWidth, h=f.rawHeight, sliced=false) { const id=node(parent,name,x,y,w,h), sprite=component(id,buy[3]); sprite._spriteFrame={__uuid__:f.uuid}; sprite._type=sliced?1:0; return id; } const button = (parent,name,f,x,y,w,h) => {const id=image(parent,name,f,x,y,w,h);component(id,buy[16]);return id;}; function shade(parent,opacity) { const id=image(parent,'shade',local('modal_mask'),0,0,4000,4000); objects[id]._opacity=opacity; objects[id]._color={__type__:'cc.Color',r:0,g:0,b:0,a:255}; component(id,buy[4]); } function rewardRows(parent) { const holder=node(parent,'rewards'); for(let row=0;row<2;row++) { const count=row?2:3, rowNode=node(holder,row?'bottomRow':'topRow',0,-75-row*245,count*206+(count-1)*54,206); const l=component(rowNode,layout);l._layoutSize={__type__:'cc.Size',width:objects[rowNode]._contentSize.width,height:206}; l['_N$layoutType']=1;l['_N$paddingBottom']=0;l['_N$spacingX']=54;l['_N$spacingY']=0; for(let i=0;i{ shade(id,185); const panel=node(id,'panel',0,0,1080,1920); for(const mode of ['offer','empty','claim']) { const p=node(panel,mode,0,0,1080,1920,mode==='offer'),height=mode==='empty'?1080:1546,top=height/2; image(p,'background',frame('assets/passCheck/img/passCheckWindow.png'),0,0,938,height,true); image(p,'title',frame('assets/passCheck/img/tongpiaozi.png'),0,top-10,730,189); button(p,'closeButton',lose('close'),408,top-105,103,112); image(p,'copy',local(mode==='empty'?'copy_season_end_empty':mode==='offer'?'copy_buy_now':'copy_season_end_rewards'),0,mode==='empty'?-125:mode==='offer'?180:145); if(mode==='empty')continue; rewardRows(p); if(mode==='claim')button(p,'claimButton',local('btn_claim'),0,-530,400,137); else { const b=button(p,'buyButton',atlas['giftBtnBg.png'],0,-530,520,160); image(b,'price1',atlas['coin_1.png'],-67,5,38.4,60); image(b,'price8',atlas['coin_8.png'],-15,5,55.2,62.4); image(b,'priceYuan',atlas['coin_yuan.png'],49,5,63.6,58.8); image(p,'bestValue',local('badge_best_value'),-245,-470); } } const c=node(panel,'confirmation',0,0,2400,3000,false);shade(c,150); image(c,'background',lose('kuang_bottom'),0,-75,902,970,true); image(c,'header',lose('kuang_top'),0,450);image(c,'title',lose('fangqi'),25,460); image(c,'copy',local('copy_abandon_confirm'),0,160); button(c,'thinkAgainButton',lose('xiangxiang2'),0,-145,642,170); button(c,'abandonButton',lose('giveup'),0,-340,438,138); }); build('PassUnlock',({id,node,image,shade})=>{ shade(id,210);const panel=node(id,'content',0,0,1080,1920); for(const tier of ['vip','svip']) { const p=node(panel,tier,0,0,1080,1920,tier==='vip'); image(p,'badge',local(tier+'_badge'),0,470); // Tween the wrapper, not the artwork's editable position or scale. const animation=node(p,'cardAnimation',0,80); image(animation,'card',local(tier+'_card_art')); image(p,'copy',local('unlock_'+tier),0,-240); } });