feat(platform): expose restricted game host and commands

This commit is contained in:
2026-09-05 07:25:21 +08:00
parent a383c0330e
commit 30547f6a54
5 changed files with 940 additions and 15 deletions
@@ -1,10 +1,16 @@
import assert from 'node:assert/strict';
import { readFileSync } from 'node:fs';
import { test } from 'node:test';
import type { RuntimeConfig } from '../../YouleNexus/assets/framework/config/runtime-config.ts';
import type { OutboundEnvelope } from '../../YouleNexus/assets/framework/core/types/envelope.ts';
import { createGameHostAdapter } from '../../YouleNexus/assets/framework/platform/game-host-adapter.ts';
import { PlatformCommands } from '../../YouleNexus/assets/framework/platform/commands.ts';
import { PlatformStore } from '../../YouleNexus/assets/framework/platform/stores/platform-store.ts';
import { parseLoginResponse } from '../../YouleNexus/assets/framework/protocol/contracts/index.ts';
import type {
GameEntry,
GameHost,
GameModule,
PlatformGameSnapshot,
} from '../../YouleNexus/assets/framework/sdk/contracts/index.ts';
import {
assertGameContract,
@@ -29,13 +35,26 @@ test('assertGameContract runs the reusable isolated session conformance suite',
assert.doesNotThrow(() => assertGameContract(
entry,
makeConformanceHost(() => { invalidations++; }, restoredDeskinfo),
makeConformanceHost(entry, () => { invalidations++; }, restoredDeskinfo),
));
assert.equal(invalidations, 2);
assert.equal(restoredDeskinfo.length, 0);
assert.ok(nextModuleId >= 2);
});
const RUNTIME_CONFIG: RuntimeConfig = Object.freeze({
mode: 'release',
isDebugger: false,
identity: Object.freeze({
agentid: 'fixture-agent', channelid: 'fixture-channel', gameid: '41',
marketid: 'fixture-market', version: 41,
}),
servers: Object.freeze(['ws://fixture']),
source: 'remote',
gameserver: 'https://fixture/config',
rawConfig: Object.freeze({ data: Object.freeze({ urlserver: 'fixture' }) }),
});
function makeModule(id: number, onRestore: (deskinfo: unknown) => void): GameModule {
let host: GameHost | undefined;
let restored: unknown;
@@ -77,25 +96,29 @@ function deskinfoFor(cycle: number): { readonly cycle: number } {
}
function makeConformanceHost(
entry: GameEntry,
onInvalidate: () => void,
restoredDeskinfo: unknown[],
): () => GameContractHost {
return () => {
const snapshot: PlatformGameSnapshot = {
connection: { phase: 'connected' },
self: { playerId: 1, seat: 0 },
room: { roomcode: 'fixture', roomtype: [], stage: 0, needprepare: 0, infinite: 0 },
seats: [],
};
const login = JSON.parse(readFileSync(
new URL('../fixtures/contracts/player-login-room.json', import.meta.url),
'utf8',
)) as { data: Record<string, unknown> };
login.data.roomtype = [4];
login.data.isbattle = 0;
const store = new PlatformStore();
store.applyLoginSuccess(parseLoginResponse(login.data));
const sent: OutboundEnvelope[] = [];
const send = { send: (envelope: OutboundEnvelope) => { sent.push(envelope); } };
const commands = new PlatformCommands({ runtimeConfig: RUNTIME_CONFIG, store, send });
const lease = createGameHostAdapter({ gameEntry: entry, store, commands, send });
return {
host: {
seat: { toView: (seat) => seat, toServer: (seat) => seat },
getSnapshot: () => snapshot,
subscribe: () => () => {},
sendGameMessage: () => {},
execute: () => {},
host: lease.host,
invalidate() {
lease.invalidate();
onInvalidate();
},
invalidate: onInvalidate,
assertRestored(deskinfo) {
assert.equal(restoredDeskinfo.shift(), deskinfo);
},