Files
youle_cocos/cocoscreator_projects/YouleNexus/assets/app/composition/SubgameAssets.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

62 lines
3.8 KiB
TypeScript

import {createBuildIdentity} from './build-identity.ts';
import {_decorator,Prefab,SceneAsset,Node,assetManager,AssetManager,TextAsset,js} from 'cc';
import versionManifestParser,{type VersionManifest} from './version-manifest.js';
import {GameComposition,type CommonRoomView} from '../../scripts/platform-login/GameComposition.ts';
import {getGameDefinition,gameBundleName,gameResourcePath,type SubgameEntry} from './game-definitions.ts';
import type {GameDefinition} from '../../framework/sdk/contracts/game-definition.ts';
const {ccclass,property}=_decorator;
/** App composition root: each game assigns its own pre-room page, room view and scene. */
@ccclass('SubgameAssets')
export class SubgameAssets extends GameComposition {
@property gameKey:string='';
private loaded:Readonly<{definition:GameDefinition;createRoom:Prefab;room:Prefab}>|null=null;
get createRoom(){return this.loaded?.createRoom??null;}
get room(){return this.loaded?.room??null;}
@property(SceneAsset) roomScene:SceneAsset|null=null;
private manifestValue:Readonly<VersionManifest>|null=null;
get versionManifest(){return this.manifestValue;}
get displayVersion(){if(!this.manifestValue)throw Error('version.xml has not been loaded');return this.manifestValue.version;}
async loadBuildIdentity(){
await this.loadGameAssets();
const key=this.gameKey,path=this.definition.config.versionResource;
if(path!==key+'/version')throw Error('Version resource does not match selected game: '+key);
const bundleName='version-'+key;
const bundle=await new Promise<AssetManager.Bundle>((resolve,reject)=>assetManager.loadBundle(bundleName,(error,result)=>{
if(error)reject(Error('Cannot load '+bundleName+': '+error.message));
else if(!result)reject(Error('Missing '+bundleName));else resolve(result);
}));
const asset=await new Promise<TextAsset>((resolve,reject)=>bundle.load(path,TextAsset,(error,result)=>{
if(error)reject(Error('Cannot load '+path+'.xml: '+error.message));
else if(!result)reject(Error('Missing '+path+'.xml'));else resolve(result);
}));
try {
if(this.gameKey!==key)throw Error('Game selection changed during version.xml load');
const manifest=versionManifestParser.parseVersionManifest(asset.text);
const identity=createBuildIdentity(manifest);
this.manifestValue=manifest;
return identity;
} finally {bundle.release(path,TextAsset);}
}
private async loadGameAssets(){
const key=this.gameKey;
if(this.loaded){if(this.loaded.definition.key!==key)throw Error('Game selection changed after loading');return;}
const bundle=await new Promise<AssetManager.Bundle>((resolve,reject)=>assetManager.loadBundle(gameBundleName(key),(error,result)=>{
if(error)reject(error);else if(!result)reject(Error('Missing game bundle: '+key));else resolve(result);
}));
const definition=getGameDefinition(key,name=>js.getClassByName(name) as unknown as SubgameEntry|null);
const load=(resource:string)=>new Promise<Prefab>((resolve,reject)=>bundle.load(gameResourcePath(definition.config.assetRoot,resource),Prefab,(error,result)=>{
if(error)reject(error);else if(!result)reject(Error('Missing game prefab: '+resource));else resolve(result);
}));
const [createRoom,room]=await Promise.all([load(definition.resources.createRoom),load(definition.resources.room)]);
if(this.gameKey!==key)throw Error('Game selection changed during asset load');
this.loaded={definition,createRoom,room};
}
get definition(){if(!this.loaded)throw Error('Subgame assets have not been loaded');return this.loaded.definition;}
resolveRoomView(root:Node):CommonRoomView {
const name=this.definition.roomViewClass;
const view=root.getComponent(name) as (CommonRoomView|null);
if(!view||typeof view.render!=='function'||typeof view.close!=='function'||typeof view.dissolutionReceived!=='function')throw Error(`Room prefab missing valid ${name}`);
return view;
}
}