diff --git a/client/src/PlayerList.tsx b/client/src/PlayerList.tsx index 47b73b7..ec24127 100644 --- a/client/src/PlayerList.tsx +++ b/client/src/PlayerList.tsx @@ -163,97 +163,100 @@ const PlayerList: React.FC = () => { > - {players?.map((player) => ( - - - - -
{player.name ? player.name : player.session_id}
- {player.protected && ( -
- 🔒 -
- )} - {player.bot_instance_id && ( -
- 🤖 -
- )} + {players?.map((player) => { + const peerObj = peers[player.session_id] || peers[player.name]; + return ( + + + + +
{player.name ? player.name : player.session_id}
+ {player.protected && ( +
+ 🔒 +
+ )} + {player.bot_instance_id && ( +
+ 🤖 +
+ )} +
+ {player.name && !player.live &&
}
- {player.name && !player.live &&
} -
- {player.name && player.live && peers[player.session_id] && (player.local || player.has_media !== false) ? ( - <> - + {player.name && player.live && peerObj && (player.local || player.has_media !== false) ? ( + <> + - {/* If this is the local player and they haven't picked a color, show a picker */} - {player.local && player.color === "unassigned" && ( -
-
Pick your color:
-
- {["orange", "red", "white", "blue"].map((c) => ( - { - if (!sendJsonMessage) return; - sendJsonMessage({ type: "set", field: "color", value: c[0].toUpperCase() }); - }} - > - - - ))} + {/* If this is the local player and they haven't picked a color, show a picker */} + {player.local && player.color === "unassigned" && ( +
+
Pick your color:
+
+ {["orange", "red", "white", "blue"].map((c) => ( + { + if (!sendJsonMessage) return; + sendJsonMessage({ type: "set", field: "color", value: c[0].toUpperCase() }); + }} + > + + + ))} +
-
- )} - - ) : player.name && player.live && player.has_media === false ? ( -
- 💬 Chat Only -
- ) : ( - - )} - - ))} + )} + + ) : player.name && player.live && player.has_media === false ? ( +
+ 💬 Chat Only +
+ ) : ( + + )} + + ); + })} diff --git a/server/routes/games.ts b/server/routes/games.ts index ddabf0a..9b7b381 100755 --- a/server/routes/games.ts +++ b/server/routes/games.ts @@ -1222,13 +1222,13 @@ const setPlayerName = (game: Game, session: Session, name: string): string | und message = `${name} has rejoined the lobby.`; } session.name = name; - if (session.ws && game.id in audio && session.id in audio[game.id]) { - webrtcPart(audio[game.id], session); + if (session.ws && game.id in audio && session.id in audio[game.id]!) { + webrtcPart(audio[game.id]!, session); } } else { - message = `${session.name} has changed their name to ${name}.`; + message = `${session.name} hs changed their name to ${name}.`; if (session.ws && game.id in audio) { - webrtcPart(audio[game.id], session); + webrtcPart(audio[game.id]!, session); } } } @@ -1245,7 +1245,7 @@ const setPlayerName = (game: Game, session: Session, name: string): string | und } if (session.ws && session.hasAudio) { - webrtcJoin(audio[game.id], session); + webrtcJoin(audio[game.id]!, session); } console.log(`${info}: ${message}`); addChatMessage(game, null, message); @@ -3726,7 +3726,7 @@ router.ws("/ws/:id", async (ws, req) => { /* ignore logging errors */ } if (!(gameId in audio)) { - audio[gameId] = {}; /* List of peer sockets using session.id as index. */ + audio[gameId] = {}; /* List of peer sockets using session.id as index. */ console.log(`${short}: Game ${gameId} - New Game Audio`); } else { console.log(`${short}: Game ${gameId} - Already has Audio`); @@ -3822,7 +3822,7 @@ router.ws("/ws/:id", async (ws, req) => { /* Cleanup any voice channels */ if (gameId in audio) { try { - webrtcPart(audio[gameId], session); + webrtcPart(audio[gameId]!, session); } catch (e) { console.warn(`${short}: Error during part():`, e); } @@ -3932,7 +3932,7 @@ router.ws("/ws/:id", async (ws, req) => { // Clean up peer from audio registry before replacing WebSocket if (gameId in audio) { try { - webrtcPart(audio[gameId], session); + webrtcPart(audio[gameId]!, session); console.log(`${short}: Cleaned up peer ${session.name} from audio registry during reconnection`); } catch (e) { console.warn(`${short}: Error cleaning up peer during reconnection:`, e); @@ -3968,11 +3968,11 @@ router.ws("/ws/:id", async (ws, req) => { // Accept either legacy `config`, newer `data`, or flat payloads where // the client sent fields at the top level (normalizeIncoming will // populate `data` with the parsed object in that case). - webrtcJoin(audio[gameId], session); + webrtcJoin(audio[gameId]!, session); break; case "part": - webrtcPart(audio[gameId], session); + webrtcPart(audio[gameId]!, session); break; case "relayICECandidate": diff --git a/server/routes/webrtc-signaling.ts b/server/routes/webrtc-signaling.ts index ef72dbb..3fab2aa 100644 --- a/server/routes/webrtc-signaling.ts +++ b/server/routes/webrtc-signaling.ts @@ -10,7 +10,13 @@ import { Session } from "./games/types"; -export const audio: Record = {}; +interface Peer { + ws: any; + name: string; +} + +/* Map of session => peer_id => peer */ +export const audio: Record> = {}; // Default send helper used when caller doesn't provide a safeSend implementation. const defaultSend = (targetOrSession: any, message: any): boolean => { @@ -29,7 +35,7 @@ const defaultSend = (targetOrSession: any, message: any): boolean => { } }; -export const join = (peers: any, session: any): void => { +export const join = (peers: Record, session: Session): void => { const send = defaultSend; const ws = session.ws; @@ -45,18 +51,19 @@ export const join = (peers: any, session: any): void => { console.log(`${session.short}: <- join - ${session.name}`); + const peer = peers[session.id]; // Use session.id as the canonical peer key - if (session.id in peers) { + if (peer) { console.log(`${session.short}:${session.id} - Already joined to Audio, updating WebSocket reference.`); try { - const prev = peers[session.id] && peers[session.id].ws; + const prev = peer.ws; if (prev && prev._pingInterval) { clearInterval(prev._pingInterval); } } catch (e) { /* ignore */ } - peers[session.id].ws = ws; + peer.ws = ws; send(ws, { type: "join_status", @@ -72,7 +79,7 @@ export const join = (peers: any, session: any): void => { type: "addPeer", data: { peer_id: peerId, - peer_name: peers[peerId].name || peerId, + peer_name: peers[peerId]!.name, should_create_offer: true, }, }); @@ -82,7 +89,7 @@ export const join = (peers: any, session: any): void => { for (const peerId in peers) { if (peerId === session.id) continue; - send(peers[peerId].ws, { + send(peers[peerId]!.ws, { type: "addPeer", data: { peer_id: session.id, @@ -97,7 +104,7 @@ export const join = (peers: any, session: any): void => { for (let peerId in peers) { // notify existing peers about the new client - send(peers[peerId].ws, { + send(peers[peerId]!.ws, { type: "addPeer", data: { peer_id: session.id, @@ -111,7 +118,7 @@ export const join = (peers: any, session: any): void => { type: "addPeer", data: { peer_id: peerId, - peer_name: peers[peerId].name || peerId, + peer_name: peers[peerId]!.name || peerId, should_create_offer: true, }, }); @@ -130,7 +137,7 @@ export const join = (peers: any, session: any): void => { }); }; -export const part = (peers: any, session: any): void => { +export const part = (peers: Record, session: Session): void => { const ws = session.ws; const send = defaultSend; @@ -151,7 +158,7 @@ export const part = (peers: any, session: any): void => { delete peers[session.id]; for (let peerId in peers) { - send(peers[peerId].ws, { + send(peers[peerId]!.ws, { type: "removePeer", data: { peer_id: session.id, @@ -162,7 +169,7 @@ export const part = (peers: any, session: any): void => { type: "removePeer", data: { peer_id: peerId, - peer_name: peers[peerId].name || peerId, + peer_name: peers[peerId]!.name || peerId, }, }); } @@ -195,8 +202,8 @@ export const handleRelayICECandidate = (gameId: string, cfg: any, session: Sessi }, }); - if (peer_id in audio[gameId]) { - const target = audio[gameId][peer_id] as any; + if (peer_id in audio[gameId]!) { + const target = audio[gameId]![peer_id] as any; if (!target || !target.ws) { console.warn(`${session.id}:${gameId} relayICECandidate - target ${peer_id} has no ws`); } else if (!send(target.ws, message)) { @@ -236,8 +243,8 @@ export const handleRelaySessionDescription = (gameId: string, cfg: any, session: session_description, }, }); - if (peer_id in audio[gameId]) { - const target = audio[gameId][peer_id] as any; + if (peer_id in audio[gameId]!) { + const target = audio[gameId]![peer_id] as any; if (!target || !target.ws) { console.warn(`${session.id}:${gameId} relaySessionDescription - target ${peer_id} has no ws`); } else if (!send(target.ws, message)) {