fix: periodic player count refresh via probe shard connection
Some Jackbox games (e.g. Trivia Murder Party 2) do not send client/connected events to shard connections and lack textDescriptions, leaving the player count stuck at 0 if the shard connects before players join. Fix by opening a lightweight probe shard every 20s to read the fresh here map. Also fix bc:room entity lookup in handleWelcome and a WebSocket close handler race condition. Made-with: Cursor
This commit is contained in:
@@ -135,6 +135,32 @@ describe('EcastShardClient', () => {
|
||||
expect(client.lobbyState).toBe('CanStart');
|
||||
expect(client.gameStarted).toBe(false);
|
||||
});
|
||||
|
||||
test('parses bc:room entity when room key is absent', () => {
|
||||
const client = new EcastShardClient({
|
||||
sessionId: 1, gameId: 5, roomCode: 'TEST', maxPlayers: 8, onEvent: () => {}
|
||||
});
|
||||
|
||||
client.handleWelcome({
|
||||
id: 5,
|
||||
secret: 'xyz-789',
|
||||
reconnect: false,
|
||||
entities: {
|
||||
'bc:room': ['object', { key: 'bc:room', val: { state: 'Lobby', lobbyState: 'CanStart', gameCanStart: true, gameIsStarting: false, gameFinished: false }, version: 0, from: 1 }, { locked: false }],
|
||||
audience: ['crdt/pn-counter', [], { locked: false }],
|
||||
},
|
||||
here: {
|
||||
'1': { id: 1, roles: { host: {} } },
|
||||
'3': { id: 3, roles: { player: { name: 'HÂM' } } },
|
||||
'4': { id: 4, roles: { player: { name: 'FGHFGHY' } } },
|
||||
}
|
||||
});
|
||||
|
||||
expect(client.playerCount).toBe(2);
|
||||
expect(client.playerNames).toEqual(['HÂM', 'FGHFGHY']);
|
||||
expect(client.gameState).toBe('Lobby');
|
||||
expect(client.lobbyState).toBe('CanStart');
|
||||
});
|
||||
});
|
||||
|
||||
describe('handleEntityUpdate', () => {
|
||||
@@ -424,12 +450,17 @@ describe('EcastShardClient', () => {
|
||||
beforeEach(() => jest.useFakeTimers());
|
||||
afterEach(() => jest.useRealTimers());
|
||||
|
||||
test('broadcasts game.status every 20 seconds', () => {
|
||||
function stubRefresh(client) {
|
||||
client._refreshPlayerCount = () => Promise.resolve();
|
||||
}
|
||||
|
||||
test('broadcasts game.status every 20 seconds', async () => {
|
||||
const events = [];
|
||||
const client = new EcastShardClient({
|
||||
sessionId: 1, gameId: 5, roomCode: 'TEST', maxPlayers: 8,
|
||||
onEvent: (type, data) => events.push({ type, data }),
|
||||
});
|
||||
stubRefresh(client);
|
||||
client.playerCount = 2;
|
||||
client.playerNames = ['A', 'B'];
|
||||
client.gameState = 'Lobby';
|
||||
@@ -437,43 +468,50 @@ describe('EcastShardClient', () => {
|
||||
client.startStatusBroadcast();
|
||||
|
||||
jest.advanceTimersByTime(20000);
|
||||
await Promise.resolve();
|
||||
expect(events).toHaveLength(1);
|
||||
expect(events[0].type).toBe('game.status');
|
||||
expect(events[0].data.monitoring).toBe(true);
|
||||
|
||||
jest.advanceTimersByTime(20000);
|
||||
await Promise.resolve();
|
||||
expect(events).toHaveLength(2);
|
||||
|
||||
client.stopStatusBroadcast();
|
||||
|
||||
jest.advanceTimersByTime(40000);
|
||||
await Promise.resolve();
|
||||
expect(events).toHaveLength(2);
|
||||
});
|
||||
|
||||
test('disconnect stops the status broadcast', () => {
|
||||
test('disconnect stops the status broadcast', async () => {
|
||||
const events = [];
|
||||
const client = new EcastShardClient({
|
||||
sessionId: 1, gameId: 5, roomCode: 'TEST', maxPlayers: 8,
|
||||
onEvent: (type, data) => events.push({ type, data }),
|
||||
});
|
||||
stubRefresh(client);
|
||||
|
||||
client.startStatusBroadcast();
|
||||
|
||||
jest.advanceTimersByTime(20000);
|
||||
await Promise.resolve();
|
||||
expect(events).toHaveLength(1);
|
||||
|
||||
client.disconnect();
|
||||
|
||||
jest.advanceTimersByTime(40000);
|
||||
await Promise.resolve();
|
||||
expect(events).toHaveLength(1);
|
||||
});
|
||||
|
||||
test('handleWelcome starts status broadcast', () => {
|
||||
test('handleWelcome starts status broadcast', async () => {
|
||||
const events = [];
|
||||
const client = new EcastShardClient({
|
||||
sessionId: 1, gameId: 5, roomCode: 'TEST', maxPlayers: 8,
|
||||
onEvent: (type, data) => events.push({ type, data }),
|
||||
});
|
||||
stubRefresh(client);
|
||||
|
||||
client.handleWelcome({
|
||||
id: 7,
|
||||
@@ -484,6 +522,7 @@ describe('EcastShardClient', () => {
|
||||
});
|
||||
|
||||
jest.advanceTimersByTime(20000);
|
||||
await Promise.resolve();
|
||||
const statusEvents = events.filter(e => e.type === 'game.status');
|
||||
expect(statusEvents).toHaveLength(1);
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user