Skip to content

joinGame doesn't guard against players who are already in a game #2

@dennisthemenacing

Description

@dennisthemenacing

Bug

createGame correctly rejects a player who's already in a game:

// src/gameManager/index.ts
public createGame(playerId: string, color: Color): Game | undefined {
  const game = this.playerMap.get(playerId);
  if (game) return undefined; // Player already in a game
  ...
}

joinGame has no equivalent guard. A player who is already in a game can call joinGame with any open gameId, and the method will succeed.

What goes wrong

When this happens:

  1. playerMap for the joining player is overwritten to point to the new game.
  2. Their original game still exists in gameMap, with that player listed as a participant — but playerMap no longer references it.
  3. The other player in the original game is now stuck waiting for an opponent who has silently moved on.
  4. The orphaned game can only be reclaimed by CleaningService once it crosses the stale threshold (100 seconds by default).

Steps to reproduce

  1. Player A creates a game.
  2. Player B joins Player A's game — both are now in playerMap.
  3. Player B emits joinGame again with a different open gameId.

Player B is now in two gameMap entries; Player A's game is orphaned.

Fix

Add the same guard used in createGame:

public joinGame(playerId: string, gameId: string): Game | undefined {
  if (this.playerMap.get(playerId)) return undefined; // Player already in a game
  ...
}

One line, consistent with existing patterns.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions