57 lines
3.3 KiB
Markdown
57 lines
3.3 KiB
Markdown
# Multiplayer rooms
|
|
|
|
Open a published map, select **Multiplayer**, enter your player name, and choose
|
|
a limit from 2 to 16 players, including yourself. Create the room and copy its
|
|
invite link. Friends open that link, enter a name, and join. The owner starts
|
|
the match once at least two players are present and can remove players from
|
|
the lobby.
|
|
|
|
Everyone plays the same five randomly selected locations with the selected
|
|
difficulty. A round starts when active players have loaded its images, with a
|
|
30-second loading grace period. The timer and scoring run in PostgreSQL;
|
|
refreshing the page restores the same player, guess, and deadline. Guesses and
|
|
scores are revealed when everyone submits or the timer expires. Missing guesses
|
|
score zero. The owner can advance from the round standings, or the next round
|
|
starts automatically after 20 seconds. The final table ranks total points;
|
|
equal totals share a place.
|
|
|
|
Players join without an account. A separate HttpOnly cookie identifies each
|
|
browser, and the room link acts as the invitation. Only the server can access
|
|
the room tables and functions. Clients receive the current round's signed
|
|
images and completed results, never future locations or other players' guesses
|
|
before a round closes. Leaving the lobby frees a place; leaving during a match
|
|
retains the player's results and scores their remaining rounds as zero. If the
|
|
owner leaves, ownership transfers to another remaining player.
|
|
|
|
Room state refreshes every two seconds, or every five seconds in a hidden tab.
|
|
Unfinished rooms expire after 24 hours. Multiplayer results are separate from
|
|
the solo leaderboard.
|
|
|
|
Room chat is available to current players in the lobby, during rounds, and at
|
|
the final standings. Open **Chat** to send a plain-text message of up to 500
|
|
characters. A badge shows unread messages while it is collapsed. Messages
|
|
refresh every two seconds and the latest 100 are restored after a refresh.
|
|
Sending chat does not lock the guess controls or change the round clock.
|
|
Removed players, players who left, and invite visitors cannot read or send
|
|
messages. Closed rooms and rooms older than 24 hours cannot use chat.
|
|
Retries are deduplicated; each player can send at most one new message per
|
|
second and 30 per minute. Player names come from the room identity.
|
|
|
|
## Database and verification
|
|
|
|
Apply `supabase/migrations/20261007071259_multiplayer_rooms.sql` to a new database
|
|
before deploying the web update. It has already been applied to MineGeo's
|
|
configured Supabase project. Deployments continue through `npm run deploy`
|
|
without a Git-provider connection.
|
|
Chat additionally requires `supabase/migrations/20261007155622_multiplayer_chat.sql`.
|
|
|
|
- `npm test`: validation and existing regression checks.
|
|
- `npm run test:multiplayer`: isolated PostgreSQL state, permission, and scoring
|
|
checks, using the existing `.data/sql-verification` PGlite installation.
|
|
- `node scripts/test-multiplayer-http.mjs <site-origin>`: real API and Storage
|
|
verification, including five-round rankings and concurrent last-slot joins.
|
|
Requires local Supabase configuration; creates and removes its own test rooms.
|
|
- `node scripts/test-multiplayer-browser.mjs <site-origin>`: desktop and mobile
|
|
invite, reconnect, map interaction, and five-round standings checks. Requires
|
|
Playwright Chromium; removes its own test room and saves screenshots locally.
|