refactor(platform): unify routing and session dispatch
This commit is contained in:
@@ -0,0 +1,111 @@
|
||||
import { readFileSync } from 'node:fs';
|
||||
import assert from 'node:assert/strict';
|
||||
import { test } from 'node:test';
|
||||
import type {
|
||||
GameEntry,
|
||||
GameHost,
|
||||
GameModule,
|
||||
PlatformGameSnapshot,
|
||||
PlatformToGameEvent,
|
||||
} from '../../YouleNexus/assets/framework/sdk/contracts/index.ts';
|
||||
import { GameSessionHost } from '../../YouleNexus/assets/framework/sdk/runtime/game-session-host.ts';
|
||||
import { RuntimeSession } from '../../YouleNexus/assets/framework/platform/runtime-session.ts';
|
||||
import { PlatformStore } from '../../YouleNexus/assets/framework/platform/stores/platform-store.ts';
|
||||
import { selectGameSnapshot } from '../../YouleNexus/assets/framework/platform/stores/selectors.ts';
|
||||
|
||||
function fixture(name: string): Record<string, unknown> {
|
||||
return JSON.parse(readFileSync(new URL(`../fixtures/contracts/${name}`, import.meta.url), 'utf8')).data;
|
||||
}
|
||||
|
||||
function makeSession() {
|
||||
const store = new PlatformStore();
|
||||
const log: string[] = [];
|
||||
const restored: unknown[] = [];
|
||||
const events: Array<{ event: PlatformToGameEvent; snapshot: PlatformGameSnapshot }> = [];
|
||||
let host: GameHost;
|
||||
const entry: GameEntry = {
|
||||
key: 'fixture',
|
||||
gameId: 41,
|
||||
route: 'fixture-game',
|
||||
resolveSeatCount: () => 4,
|
||||
createModule: (): GameModule => ({
|
||||
attach(attachedHost) {
|
||||
host = attachedHost;
|
||||
attachedHost.getSnapshot();
|
||||
log.push('attach');
|
||||
},
|
||||
handlePlatformEvent(event) {
|
||||
events.push({ event, snapshot: host.getSnapshot() });
|
||||
log.push(`event:${event.type}`);
|
||||
},
|
||||
handleGameMessage() {},
|
||||
restore(deskinfo) {
|
||||
restored.push(deskinfo);
|
||||
log.push('restore');
|
||||
},
|
||||
dispose() { log.push('dispose'); },
|
||||
}),
|
||||
};
|
||||
const gameSession = new GameSessionHost(entry);
|
||||
log.length = 0;
|
||||
const gameHost: GameHost = {
|
||||
seat: { toView: (seat) => seat, toServer: (seat) => seat },
|
||||
getSnapshot: () => selectGameSnapshot(store.getState()),
|
||||
subscribe: () => () => {},
|
||||
sendGameMessage() {},
|
||||
execute() {},
|
||||
};
|
||||
const session = new RuntimeSession({ store, gameSession, gameHost });
|
||||
return { store, gameSession, session, log, restored, events };
|
||||
}
|
||||
|
||||
test('RuntimeSession commits a room login before opening, publishing, and restoring deskinfo', () => {
|
||||
const setup = makeSession();
|
||||
const data = fixture('player-login-room.json');
|
||||
setup.store.subscribe(() => { setup.log.push('store'); });
|
||||
|
||||
setup.session.markLoginPending();
|
||||
setup.session.handleLogin(data);
|
||||
|
||||
assert.equal(setup.session.loginPending, false);
|
||||
assert.equal(setup.store.getState().room.kind, 'inside');
|
||||
assert.equal('deskinfo' in setup.store.getState().room, false);
|
||||
assert.equal(setup.restored.length, 1);
|
||||
assert.equal(setup.restored[0], data.deskinfo);
|
||||
assert.deepEqual(setup.log, ['store', 'attach', 'event:room.entered', 'restore']);
|
||||
assert.equal(setup.events[0]?.snapshot.room.roomcode, '100001');
|
||||
assert.equal(setup.events[0]?.event.type, 'room.entered');
|
||||
if (setup.events[0]?.event.type === 'room.entered') {
|
||||
assert.equal(setup.events[0].event.roomtype, setup.events[0].snapshot.room.roomtype);
|
||||
}
|
||||
});
|
||||
|
||||
test('RuntimeSession never treats isbattle as a restore signal without truthy deskinfo', () => {
|
||||
for (const deskinfo of [undefined, null, false, 0, '']) {
|
||||
const setup = makeSession();
|
||||
const data = fixture('player-login-room.json');
|
||||
if (deskinfo === undefined) delete data.deskinfo;
|
||||
else data.deskinfo = deskinfo;
|
||||
data.isbattle = 1;
|
||||
|
||||
setup.session.handleLogin(data);
|
||||
|
||||
assert.deepEqual(setup.restored, [], `deskinfo=${String(deskinfo)}`);
|
||||
assert.equal(setup.store.getState().room.kind, 'inside');
|
||||
}
|
||||
});
|
||||
|
||||
test('RuntimeSession self join commits, opens a fresh session, and restores the same snapshot once', () => {
|
||||
const setup = makeSession();
|
||||
setup.session.handleLogin(fixture('player-login-success.json'));
|
||||
setup.log.length = 0;
|
||||
const join = fixture('self-join-room.json');
|
||||
setup.store.subscribe(() => { setup.log.push('store'); });
|
||||
|
||||
setup.session.handleSelfJoin(join);
|
||||
|
||||
assert.equal(setup.store.getState().room.kind, 'inside');
|
||||
assert.equal(setup.restored.length, 1);
|
||||
assert.equal(setup.restored[0], join.deskinfo);
|
||||
assert.deepEqual(setup.log, ['store', 'attach', 'event:room.entered', 'restore']);
|
||||
});
|
||||
Reference in New Issue
Block a user