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.
This commit is contained in:
2026-09-09 03:13:18 +08:00
parent a7ec8aa6a7
commit 35216f75e7
1028 changed files with 835556 additions and 21415 deletions
@@ -0,0 +1,28 @@
'use strict';
// Shared by Cocos runtime and the build extension: one parser for the native contract.
const {DOMParser}=require('@xmldom/xmldom');
function parseVersionManifest(xml){
const fail=message=>{throw Error('version.xml: '+message);};
if(typeof xml!=='string'||!xml.trim())fail('empty document');
if(/<!DOCTYPE|<!ENTITY/i.test(xml))fail('DTD and entity declarations are unsupported');
let doc;
try {doc=new DOMParser({onError:(_level,message)=>fail(message)}).parseFromString(xml,'text/xml');}
catch(error){fail(error.message);}
const root=doc.documentElement;
if(!root||root.tagName!=='game'||root.namespaceURI)fail('expected game root');
const fields={};
for(let child=root.firstChild;child;child=child.nextSibling){
if(child.nodeType===3&&!child.nodeValue.trim()||child.nodeType===8)continue;
if(child.nodeType!==1||!['agent','game','channel','version'].includes(child.tagName)||child.namespaceURI)fail('unexpected child');
if(fields[child.tagName])fail('duplicate '+child.tagName);
fields[child.tagName]=child;
for(let nested=child.firstChild;nested;nested=nested.nextSibling){if(nested.nodeType!==3||nested.nodeValue.trim())fail('unexpected nested content');}
}
const attr=(tag,name)=>{const node=fields[tag];if(!node)fail('missing '+tag);const value=node.getAttribute(name);if(value===null||!value.trim())fail('missing '+tag+'@'+name);return value;};
const code=attr('version','value');
if(!/^\d+$/.test(code)||!Number.isSafeInteger(Number(code)))fail('version@value must be a nonnegative safe integer');
return Object.freeze({agentid:attr('agent','id'),agentName:attr('agent','name'),
gameid:attr('game','id'),gameName:attr('game','name'),channelid:attr('channel','id'),channelName:attr('channel','name'),
versionCode:Number(code),version:attr('version','name')});
}
exports.parseVersionManifest=parseVersionManifest;