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:
@@ -0,0 +1,83 @@
|
||||
import {test} from 'node:test';
|
||||
import assert from 'node:assert/strict';
|
||||
import {fileURLToPath} from 'node:url';
|
||||
import {loadRoomAssetInventory,loadRoomAssetDefinitions,validateRoomAssets,compressUuid,parseRoomAssetDefinitions} from '../../scripts/lib/room-assets.mjs';
|
||||
|
||||
const assetsDir=fileURLToPath(new URL('../../YouleNexus/assets/',import.meta.url));
|
||||
const inventory=()=>loadRoomAssetInventory(assetsDir);
|
||||
const definitions=loadRoomAssetDefinitions(fileURLToPath(new URL('../../YouleNexus/assets/games',import.meta.url)));
|
||||
const template=definitions.find(definition=>definition.key==='Game_Surface_3');
|
||||
const erqiwang=definitions.find(definition=>definition.key==='erqiwang');
|
||||
const original=inventory();
|
||||
const copy=()=>structuredClone(original);
|
||||
const erqiwangPath=erqiwang.resources.createRoom;
|
||||
const uuidOf=name=>original.scripts.find(script=>script.name===name).uuid;
|
||||
|
||||
test('static definition extraction reads the authoritative object without executing game factories',()=>{
|
||||
const declarations=Object.fromEntries(definitions.map(definition=>[definition.key,definition]));
|
||||
const text=`throw Error('must never execute'); export const GAME_DEFINITIONS=${JSON.stringify(declarations)} as const satisfies Record<string, GameDefinition>;`;
|
||||
assert.deepEqual(parseRoomAssetDefinitions(text),definitions);
|
||||
assert.throws(()=>parseRoomAssetDefinitions(text.replace('"key":"erqiwang"','"key":"another-game"')),/registration erqiwang differs/);
|
||||
assert.throws(()=>parseRoomAssetDefinitions(text.replace('"createPageClass":"ErqiwangCreateRoomView"','"createPageClass":getClassName()')),/createPageClass must be a nonempty string literal/);
|
||||
});
|
||||
|
||||
test('script UUID compression agrees with an actual serialized component and inherited page metadata',()=>{
|
||||
const script=original.scripts.find(script=>script.name==='ErqiwangCreateRoomView');
|
||||
assert.ok(script.contracts.includes('CreateRoomPage'));
|
||||
assert.ok(original.assets.find(asset=>asset.path===erqiwangPath).objects.some(object=>object.__type__===compressUuid(script.uuid)));
|
||||
});
|
||||
test('current template and erqiwang assets have unique pages and matching composition references',()=>{
|
||||
assert.deepEqual(validateRoomAssets(original,definitions),[]);
|
||||
});
|
||||
test('duplicate template component on erqiwang prefab is rejected',()=>{
|
||||
const data=copy();
|
||||
const prefab=data.assets.find(asset=>asset.path===erqiwangPath);
|
||||
prefab.objects.push({__type__:compressUuid(uuidOf('TemplateCreateRoomView')),node:{__id__:1}});
|
||||
assert.match(validateRoomAssets(data,definitions).join('\n'),/exactly one CreateRoomPage.*found 2/);
|
||||
});
|
||||
test('wrong game page and missing page are rejected',()=>{
|
||||
const data=copy();
|
||||
const page=data.assets.find(asset=>asset.path===erqiwangPath).objects.find(object=>object.__type__===compressUuid(uuidOf('ErqiwangCreateRoomView')));
|
||||
page.__type__=compressUuid(uuidOf('TemplateCreateRoomView'));
|
||||
assert.match(validateRoomAssets(data,definitions).join('\n'),/expected ErqiwangCreateRoomView.*TemplateCreateRoomView/);
|
||||
page.__type__='cc.Component';
|
||||
assert.match(validateRoomAssets(data,definitions).join('\n'),/exactly one CreateRoomPage.*found 0/);
|
||||
});
|
||||
test('serialized composition cannot retain private prefab references',()=>{
|
||||
const data=copy();
|
||||
const composition=data.assets.flatMap(asset=>asset.objects).find(object=>object.gameKey==='erqiwang');
|
||||
composition.createRoom={__uuid__:data.assets.find(asset=>asset.path===template.resources.createRoom).uuid};
|
||||
assert.match(validateRoomAssets(data,definitions).join('\n'),/createRoom.*must not be a serialized/);
|
||||
composition.room={__uuid__:'00000000-0000-0000-0000-000000000000'};
|
||||
assert.match(validateRoomAssets(data,definitions).join('\n'),/room.*must not be a serialized/);
|
||||
});
|
||||
test('unknown configured game, unresolved script and duplicate room views are rejected',()=>{
|
||||
const data=copy();
|
||||
const composition=data.assets.flatMap(asset=>asset.objects).find(object=>object.gameKey==='erqiwang');
|
||||
composition.gameKey='missing-game';
|
||||
const room=data.assets.find(asset=>asset.path===erqiwang.resources.room);
|
||||
room.objects.push({__type__:compressUuid(uuidOf('TemplateRoomView')),node:{__id__:1}});
|
||||
data.assets.find(asset=>asset.path===erqiwangPath).objects.push({__type__:compressUuid('00000000-0000-0000-0000-000000000001'),node:{__id__:1}});
|
||||
const errors=validateRoomAssets(data,definitions).join('\n');
|
||||
assert.match(errors,/unknown game missing-game/);
|
||||
assert.match(errors,/unresolved script/);
|
||||
assert.match(errors,/exactly one room view.*found 2/);
|
||||
});
|
||||
|
||||
test('inheritance resolves the erqiwang room view through its shared public base',()=>{
|
||||
const script=original.scripts.find(script=>script.name==='ErqiwangRoomView');
|
||||
assert.ok(script.contracts.includes('CommonRoomViewBase'));
|
||||
});
|
||||
test('component on a child node cannot satisfy the platform root lookup',()=>{
|
||||
const data=copy();
|
||||
const page=data.assets.find(asset=>asset.path===erqiwangPath).objects.find(object=>object.__type__===compressUuid(uuidOf('ErqiwangCreateRoomView')));
|
||||
page.node={__id__:2};
|
||||
assert.match(validateRoomAssets(data,definitions).join('\n'),/must be attached to prefab root/);
|
||||
});
|
||||
test('an orphan component record cannot satisfy the platform root lookup',()=>{
|
||||
const data=copy();
|
||||
const prefab=data.assets.find(asset=>asset.path===erqiwangPath);
|
||||
const pageIndex=prefab.objects.findIndex(object=>object.__type__===compressUuid(uuidOf('ErqiwangCreateRoomView')));
|
||||
prefab.objects[prefab.objects[0].data.__id__]._components=prefab.objects[prefab.objects[0].data.__id__]._components.filter(reference=>reference.__id__!==pageIndex);
|
||||
assert.match(validateRoomAssets(data,definitions).join('\n'),/not attached in the root component list/);
|
||||
});
|
||||
Reference in New Issue
Block a user