diff --git a/deep-sea-stories/packages/backend/src/game/room.ts b/deep-sea-stories/packages/backend/src/game/room.ts index 6f11be5..4c41de9 100644 --- a/deep-sea-stories/packages/backend/src/game/room.ts +++ b/deep-sea-stories/packages/backend/src/game/room.ts @@ -66,7 +66,8 @@ export class GameRoom { } async addPlayer(name: string): Promise<{ peer: Peer; peerToken: string }> { - if (this.players.size >= ROOM_PLAYERS_LIMIT) { + const roomPlayersCount = await this.getAndReconcilePlayersCount(); + if (roomPlayersCount >= ROOM_PLAYERS_LIMIT) { throw new GameRoomFullError(); } const { peer, peerToken } = await this.fishjamClient.createPeer( @@ -242,4 +243,50 @@ export class GameRoom { await new Promise((resolve) => setTimeout(resolve, 500)); return { agent, agentId: peer.id }; } + + private async getAndReconcilePlayersCount(): Promise { + try { + const room = await this.fishjamClient.getRoom(this.roomId); + const webrtcPlayers = room.peers.filter((peer) => peer.type === 'webrtc'); + this.reconcilePlayersCount(webrtcPlayers); + return webrtcPlayers.length; + } catch (e) { + console.error(`Error fetching room info for room ${this.roomId}:`, e); + return this.players.size; + } + } + + private async reconcilePlayersCount(webrtcPlayers: Peer[]) { + try { + if (webrtcPlayers.length === this.players.size) { + return; + } + console.warn( + `Discrepancy in player count for room ${this.roomId}: Fishjam reports ${webrtcPlayers.length}, local state has ${this.players.size}. This most probably means some peerDisconnected events were missed.`, + ); + const webrtcPeerIds = new Set(webrtcPlayers.map((p) => p.id)); + for (const localPeerId of this.players.keys()) { + if (!webrtcPeerIds.has(localPeerId)) { + console.log( + `Reconciling: removing peer ${localPeerId} from local state of room ${this.roomId}`, + ); + this.players.delete(localPeerId); + this.gameSession?.removePlayer(localPeerId); + } + } + for (const fishjamPeer of webrtcPlayers) { + if (!this.players.has(fishjamPeer.id)) { + await this.fishjamClient.deletePeer(this.roomId, fishjamPeer.id); + console.log( + `Reconciling: removing unknown peer ${fishjamPeer.id} from Fishjam room ${this.roomId}`, + ); + } + } + } catch (e) { + console.error( + `Error reconciling players count for room ${this.roomId}:`, + e, + ); + } + } }