Files
youle_cocos/cocoscreator_projects/YouleNexus/assets/games/template/template-game.ts
T
joywayer 35216f75e7 feat: integrate room framework and isolated subgame bundles
Complete room UI and protocol integration, move game definitions and resources behind bundle entries, publish authoritative version XML, and document single-game builds. Include all current resource changes and experiment artifacts.
2026-09-09 03:13:18 +08:00

40 lines
3.1 KiB
TypeScript

import type {GameRoomProjection,GameRoomProjectionSource} from '../../framework/sdk/contracts/game-room-projection.ts';
import type {GameEntry,GameHost,GameModule,PlatformGameSnapshot} from '../../framework/sdk/contracts/index.ts';
import {TemplateRoomRules} from './template-room-rules.ts';
import type {PlatformToGameEvent} from '../../framework/sdk/contracts/platform-events.ts';
import {requireRoomCapabilities,type RoomCapabilities} from '../../framework/sdk/contracts/index.ts';
export interface TemplateRoomActions {prepare():void;exit():void;}
export interface TemplateRoomPresentation {render(snapshot:PlatformGameSnapshot,actions:TemplateRoomActions,projection?:GameRoomProjection|null):void;close():void;}
/** Template hooks are intentionally empty, matching 02_SubGame_Input.js. No gameplay is inferred. */
export function createTemplateGame(gameId:string|number,identity:Pick<GameEntry,'key'|'route'>){
let active:TemplateModule|null=null;
class TemplateModule implements GameModule {
private capabilities:RoomCapabilities|null=null;
readonly roomProjection:GameRoomProjectionSource|null=null;
private unsubscribeProjection:(()=>void)|null=null;
private unsubscribe:(()=>void)|null=null;
private view:TemplateRoomPresentation|null=null;
restored:unknown=null;
attach(host:GameHost):void{
if(this.capabilities||active)throw Error('Template module already attached');
this.capabilities=requireRoomCapabilities(host);active=this;this.unsubscribe=this.capabilities.room.subscribe(()=>this.render());
this.unsubscribeProjection=this.roomProjection?.subscribe(()=>this.render())??null;
}
mount(view:TemplateRoomPresentation):void{this.view?.close();this.view=view;this.render();}
private requireCapabilities():RoomCapabilities{if(!this.capabilities)throw Error('Template room session disposed');return this.capabilities;}
private render():void{this.view?.render(this.requireCapabilities().room.getSnapshot(),{prepare:()=>this.requireCapabilities().room.prepare(),exit:()=>this.requireCapabilities().room.requestExit()},this.roomProjection?.getSnapshot()??null);}
handlePlatformEvent(event:PlatformToGameEvent):void{
if(event.type==='room.dissolution-confirmed')throw Error('模板游戏解散结算界面尚未接入');
this.render();
}
handleGameMessage():void{/* Original template _ReceiveData hook is empty. */}
restore(deskinfo:unknown):void{this.requireCapabilities();this.restored=deskinfo;}
dispose():void{this.unsubscribeProjection?.();this.unsubscribeProjection=null;this.unsubscribe?.();this.unsubscribe=null;this.view?.close();this.view=null;this.capabilities=null;this.restored=null;if(active===this)active=null;}
}
const rules=new TemplateRoomRules();
const entry:GameEntry={key:identity.key,gameId,route:identity.route,resolveSeatCount:roomtype=>rules.seatCount(roomtype),createModule:()=>new TemplateModule()};
return {entry,mount(view:TemplateRoomPresentation){if(!active)throw Error('Template room not attached');active.mount(view);},
get roomProjection(){return active?.roomProjection??null;},
get restoredSnapshot():unknown{return active?.restored;}};
}