fix: per-socket state with drawer-only wordChoices to prevent race on lobby→play nav

This commit is contained in:
PM
2026-05-04 15:32:03 +00:00
parent 4b98d07069
commit ce43e6f6aa
2 changed files with 24 additions and 2 deletions
+15 -1
View File
@@ -59,7 +59,8 @@ function makeRoom({ code, hostId, mode, settings }) {
};
}
function publicRoomState(room) {
function publicRoomState(room, viewerId) {
const isViewerDrawer = !!(viewerId && room.skribbl && room.skribbl.drawerId === viewerId);
return {
code: room.code,
hostId: room.hostId,
@@ -84,6 +85,19 @@ function publicRoomState(room) {
phase: room.skribbl.phase, // 'choosing' | 'drawing' | 'between'
endsAt: room.skribbl.endsAt,
solvedIds: [...(room.skribbl.solvedIds || [])],
// Drawer-only: surface current word choices in the snapshot so a
// late-mounted play page (after lobby→/play navigation) can render
// the pick modal even if the original skribbl:wordChoices event
// was emitted before the listener was attached.
wordChoices:
isViewerDrawer && room.skribbl.phase === "choosing"
? room.skribbl.wordChoices
: null,
// Drawer-only: reveal the actual word so they know what to draw.
word:
isViewerDrawer && room.skribbl.phase === "drawing"
? room.skribbl.word
: null,
}
: null,
gartic: room.gartic
+9 -1
View File
@@ -10,7 +10,15 @@ function escape(text) {
}
function broadcastState(io, room) {
io.to(room.code).emit("room:state", G.publicRoomState(room));
// Per-socket emission so we can include drawer-only data
// (wordChoices during choosing, secret word during drawing) in the
// snapshot of the right viewer without leaking it to others.
for (const player of room.players) {
if (!player.socketId) continue;
const sock = io.sockets.sockets.get(player.socketId);
if (!sock) continue;
sock.emit("room:state", G.publicRoomState(room, player.id));
}
}
function chatSystem(io, room, text) {