/** Run inside the Creator Game View through MCP. Synthetic state; no login or business packets. */ export async function verifyLobbyMenuPreview() { const engine=await globalThis.System.import('cc'); const modules=Array.from(globalThis.System.entries()).map(([,module])=>module); const exported=name=>{const module=modules.find(m=>m[name]);if(!module)throw Error(`Missing preview export ${name}`);return module[name];}; const LobbyPanel=exported('LobbyPanel'),createRemoteConfig=exported('createRemoteConfig'); const resolveLobbyPolicy=exported('resolveLobbyPolicy'),resolveLobbyMenuConfig=exported('resolveLobbyMenuConfig'); const service=engine.director.getScene().getChildByName('PlatformServices'); const owner=service.getComponent('PlatformStartup'),assets=service.getComponent('LobbyAssets'); owner.unsubscribe?.();owner.runtime?.stop();owner.panel?.dispose();owner.panel=null; await new Promise((resolve,reject)=>engine.director.loadScene('PlatformLobby',error=>error?reject(error):resolve())); const canvas=engine.director.getScene().getChildByName('Canvas'); const popup=new engine.Node('MenuVerificationPopup');popup.parent=canvas;popup.layer=canvas.layer; popup.addComponent(engine.UITransform).setContentSize(1600,720); const player={playerid:7,nickname:'菜单接线验证',avatar:'',sex:0,bean:123456789,roomcard:1234,taskstate:1,advanced:0,score:9,sign:'验证账号',ip:'127.0.0.1'}; const state={app:{phase:'logged-in'},room:{kind:'outside'},players:{selfPlayerId:7,entities:{7:player}}}; const actions=[],tips=[],checks=[]; const assert=(condition,message)=>{if(!condition)throw Error(message);checks.push(message);}; const config=owner.config; const make=(data,context={versionState:0,launchMode:0})=>{ const remote=createRemoteConfig({gameNoticeShow:-1,...data},config.identity); const panel=new LobbyPanel(canvas,popup,assets,config,resolveLobbyPolicy(remote),state,text=>tips.push(text), ()=>actions.push('logout'),()=>({errorCode:1}),()=>actions.push('url'),resolveLobbyMenuConfig(remote),context,action=>actions.push(action),()=>{},(name,data)=>owner.callNative(name,data),{request:()=>actions.push('vip-query'),join:()=>actions.push('vip-join'),describe:()=> '测试玩法'}); popup.setSiblingIndex(canvas.children.length-1); return panel; }; const click=(panel,id)=>panel.menuNodes.get(id).emit(engine.Button.EventType.CLICK); let panel=make({rankList:1,cdKey:2,hideTaskBtn:1,miniPro:1,hideRoomCard:2}); assert(!panel.menuNodes.get(17).activeInHierarchy&&!panel.taskTip.activeInHierarchy,'hidden task also hides child red dot'); assert(!panel.menuNodes.get(14).activeInHierarchy,'miniPro hides share'); assert(!panel.menuNodes.get(10).active&& !panel.menuNodes.get(3161).active,'hideRoomCard hides purchase and number'); assert(panel.menuNodes.get(3264).active&&panel.menuNodes.get(3233).active,'cdKey and rank are visible'); assert(!panel.menuNodes.get(3256).active,'phone binding stays hidden'); click(panel,17);click(panel,14);click(panel,10); assert(actions.length===0,'hidden buttons cannot dispatch events'); click(panel,3264);assert(actions.at(-1)==='cdkey','cdkey dispatches named business event'); click(panel,7);assert(panel.modalKind==='settings','settings button opens existing prefab'); const before=actions.length;click(panel,3264);assert(actions.length===before,'modal blocks underlying menu'); panel.close();click(panel,9);assert(panel.modalKind==='profile','avatar opens existing profile prefab'); panel.close();click(panel,12);assert(panel.modalKind==='join','join button opens existing join prefab');panel.close(); click(panel,3120);assert(panel.noticeMenu.getChildByPath('group-95').active,'more button opens tray'); assert(panel.menuNodes.get(604).active&&!panel.menuNodes.get(235).active,'tray applies rank and miniPro policy'); const trayBackground=panel.menuNodes.get(3121),trayUI=trayBackground.getComponent(engine.UITransform); assert(trayBackground.position.x-trayUI.width*trayUI.anchorX===200-640,'tray resize preserves source left edge'); click(panel,5);assert(panel.modalKind==='notice','tray notice opens existing notice prefab');panel.close(); panel.render({...state,app:{phase:'reconnecting'}});const count=actions.length;click(panel,3264); assert(actions.length===count,'reconnecting blocks menu action'); panel.dispose(); panel=make({agentmode:1,androidPay:1,rankList:1,cdKey:2}); assert(panel.menuNodes.get(10).active&&panel.menuNodes.get(509).active,'androidPay restores both purchase buttons'); assert(panel.taskTip.activeInHierarchy&&panel.taskTip===panel.menuNodes.get(17).getChildByName('Tip'),'red dot is the authored Tip child'); const badge=panel.taskTip; panel.render({...state,players:{...state.players,entities:{7:{...player,taskstate:0}}}}); assert(!badge.active,'taskstate clears badge');panel.render(state); assert(panel.taskTip===badge&&badge.active,'rerender reuses the authored Tip sprite'); for(const id of [10,286,287,3161]){click(panel,id);assert(actions.at(-1)==='buy-roomcard',`roomcard hit region ${id}`);} for(const id of [508,509,496,3162]){click(panel,id);assert(actions.at(-1)==='buy-bean',`bean hit region ${id}`);} assert(tips.length===0,`existing actions run without errors: ${tips.join(';')}`); panel.dispose(); panel=make({cdKey:2},{versionState:1,launchMode:0}); assert(!panel.menuNodes.get(3233).active&&!panel.menuNodes.get(14).active,'review mode hides rank and share'); assert(panel.menuNodes.get(3264).active,'cdKey applies after review branch');panel.dispose(); panel=make({agentmode:1,androidPay:1,rankList:1,cdKey:2}); click(panel,14);assert(panel.modalKind==='share','share UI opens without a native host'); panel.modal.getChildByPath('group-11/Spirit72').emit(engine.Button.EventType.CLICK); assert(panel.modal===null,'share close restores lobby'); click(panel,679);assert(panel.modalKind==='vip-rooms'&&!panel.menu.active,'VIP entry shows its page and hides main menu'); panel.modal.getChildByPath('group-103/Spirit3182').emit(engine.Button.EventType.CLICK); assert(panel.modal===null&&panel.menu.active,'VIP close restores main menu'); globalThis.__lobbyMenuVerification={panel,checks,actions,tips,synthetic:true}; await new Promise(resolve=>setTimeout(resolve,200)); return {synthetic:true,scene:engine.director.getScene().name,checks:checks.length,failures:tips, canvas:canvas.getComponent(engine.UITransform).contentSize,actions}; }