Fix CRITICAL player seat loss on WebSocket reconnect (stable playerId + seat grace)
A player who dropped briefly got a fresh server playerId on auto-reconnect and silently lost their seat: the UI still showed 'granted' but every HP/condition/spell patch and dice roll was rejected server-side. Now: - The client persists a stable playerId (localStorage) and sends it on join. - The server reuses that id when it isn't already live on another connection (so a second tab/peer can't hijack an active seat), and on reconnect re-binds the seat to the new socket and re-sends seatGranted — control is restored seamlessly. - Seats survive a disconnect for a 5-minute grace window (marked, not deleted); sweep() evicts seats whose holder never returns. Adds 3 server tests (reconnect reclaim, grace eviction, anti-hijack). 4 files: join message gains optional playerId; server dispatch, RoomHub, and wsSync client. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
+1
-1
@@ -195,7 +195,7 @@ export function buildServer() {
|
||||
const m = parsed.data;
|
||||
switch (m.t) {
|
||||
case 'host': hub.host(sender, m.password, m.resume); break;
|
||||
case 'join': hub.join(sender, m.joinCode, m.password); break;
|
||||
case 'join': hub.join(sender, m.joinCode, m.password, m.playerId); break;
|
||||
case 'state': hub.state(sender, m.gmSecret, m.snapshot); break;
|
||||
case 'image': hub.image(sender, m.gmSecret, m.id, m.dataUrl); break;
|
||||
case 'requestImage': hub.requestImage(sender, m.id); break;
|
||||
|
||||
Reference in New Issue
Block a user