Room & Game Management
Relevant source files
The following files were used as context for generating this wiki page:
Room and Game Management in Dreamcats provides the infrastructure for creating, joining, and maintaining the authoritative state of multiplayer and local card games. The system utilizes Convex as a real-time backend to synchronize game states across clients, manage player presence, and enforce game rules through server-side mutations.
The scope of this system covers the lifecycle of a "Room"—from initial creation in a lobby to the execution of game rounds and final match recording. It supports multiple game modes, including online multiplayer, local hotseat, and solo play against AI agents.
Data Architecture & Schema
The system is built on a relational-style schema within Convex. The primary entities are Rooms, Players, and Games, which are linked by a unique roomId.
Core Database Tables
| Table | Purpose | Key Fields |
|---|---|---|
rooms | Tracks metadata for a game session. | roomId, hostId, status, mode |
players | Tracks individual participants within a specific room. | roomId, playerId, userId, seat, score |
games | Holds the authoritative state snapshot and versioning for a match. | roomId, state, version, idempotencyKey |
presence | Maintains real-time connectivity status for players. | roomId, playerId, status, lastPing |
matches | Archive of completed games for history and statistics. | roomId, winnerPlayerId, winningScore, mode |
Sources: convex/schema.ts:7-143, convex/rooms.ts:7-160
Entity Relationship Diagram
The following diagram illustrates how rooms and game states are related through the roomId identifier.
Sources: convex/schema.ts:7-143
Room Lifecycle Management
Room Creation and Joining
Rooms are created with a human-readable code. When a room is initialized, the system automatically inserts a host player record and seeds a "game snapshot shell" in the games table.
createRoom: Initializes the room metadata, adds the host atseat 0, and creates the initial game state withgamePhase: "lobby".joinRoom: Adds a new player to an existing room. It calculates the next available incremental seat (e.g., 0, 1, 2) and updates the player'slastSeenAttimestamp.
Sources: convex/rooms.ts:6-103, convex/tests/rooms-and-games.test.ts:85-116
Presence and Connectivity
To handle real-time synchronization, the system implements a heartbeat mechanism. Clients call updatePlayerPresence every 10 seconds to maintain an "online" status. If a user refreshes or disconnects, the userPreferences table stores an activeRoomId and activePlayerId to facilitate session rejoining.
Sources: convex/rooms.ts:133-160, convex/userPreferences.ts:182-209, src/state/useGame.ts:145-173
Game Execution & State Transitions
The games table stores an authoritative room state snapshot as an any type, allowing for flexible card game logic while maintaining a single source of truth.
The Action Flow
Game logic is driven by the performAction mutation. This function serves as the central dispatcher for all gameplay moves (drawing, swapping, peeking).
Idempotency and Versioning
To prevent double-application of moves (e.g., drawing two cards due to a network retry), the system uses:
- Idempotency Keys: A unique string (often a UUID) generated by the client and checked by the server before processing an action.
- Monotonic Versioning: The
versionfield in thegamestable increases with every write to prevent stale writes from overwriting the current state.
Sources: convex/schema.ts:39, convex/actions.ts:24-38, src/state/useGame.ts:26-31
Game Phases & Rules Enforcement
The system manages transition between distinct phases, ensuring players can only perform actions valid for the current state.
| Phase | Description | Key Actions |
|---|---|---|
lobby | Initial state where players wait for the host to start. | START_NEW_ROUND |
peeking | Initial round phase where players view 2 of their cards. | PEEK_CARD, FINISH_PEEKING |
playing | Main turn-based gameplay. | DRAW_FROM_DECK, DRAW_FROM_DISCARD, CALL_POBUDKA |
holding_card | Player has drawn a card and must decide what to do. | SWAP_HELD_CARD, DISCARD_HELD_CARD, USE_SPECIAL_ACTION |
round_end | Points are tallied; cards are revealed. | START_NEW_ROUND, RETURN_TO_LOBBY |
Sources: convex/actions.ts:175-380, convex/tests/rooms-and-games.test.ts:33-44
Special Action Handling
When a "Special Card" is drawn from the deck, the phase shifts to specific action states like action_peek_1 or action_swap_2_select_1. These states restrict the next possible moves to the requirements of that power, such as selecting a target player's card.
Sources: convex/actions.ts:305-350, convex/tests/actions-flow.test.ts:153-200
Match Finalization and Statistics
When a player reaches 100 points, the game_over phase is triggered. The system then performs several side effects:
- Winner Calculation: Identifies the player with the lowest score.
- Match Archive: Inserts a record into the
matchestable. - User Stats Update: Patches the
userStatstable for authenticated users, incrementinggamesPlayed,gamesWon, and updating theirbestScore(lowest total).
Sources: convex/actions.ts:55-139, convex/schema.ts:117-143
Summary
Room & Game Management provides a robust, stateful environment for Dreamcats. By combining Convex's real-time document store with strict server-side validation and idempotency checks, the system ensures that game rules are followed regardless of client-side latency or connectivity issues. The architecture supports a seamless transition from social lobby interactions to competitive, turn-based card gameplay.