diff --git a/src/client/ClientGameRunner.ts b/src/client/ClientGameRunner.ts index 941e07a46..0d45eb193 100644 --- a/src/client/ClientGameRunner.ts +++ b/src/client/ClientGameRunner.ts @@ -80,12 +80,14 @@ export function joinLobby( onPrestart(); } if (message.type == "start") { - // Trigger prestart for singleplayer games onPrestart(); consolex.log(`lobby: game started: ${JSON.stringify(message)}`); onJoin(); - // For multiplayer games, GameStartInfo is not known until game starts. lobbyConfig.gameStartInfo = message.gameStartInfo; + + // ✅ Add this line to ensure gameID is defined + lobbyConfig.gameID = message.gameStartInfo.gameID; + createClientGame( lobbyConfig, eventBus, diff --git a/src/client/Main.ts b/src/client/Main.ts index 5539e4058..5d50f265a 100644 --- a/src/client/Main.ts +++ b/src/client/Main.ts @@ -44,7 +44,7 @@ export interface JoinLobbyEvent { class Client { private gameStop: () => void; - + private homepageWS: WebSocket | null = null; private usernameInput: UsernameInput | null = null; private flagInput: FlagInput | null = null; private darkModeButton: DarkModeButton | null = null; @@ -222,11 +222,10 @@ class Client { } // Establish minimal WebSocket connection to track homepage view try { - const ws = new WebSocket(`ws://${location.host}/w0`); - - ws.onopen = () => { + this.homepageWS = new WebSocket(`ws://${location.host}/w0`); + this.homepageWS.onopen = () => { console.log("WebSocket opened: sending homepage_ping"); - ws.send(JSON.stringify({ type: "homepage_ping" })); + this.homepageWS?.send(JSON.stringify({ type: "homepage_ping" })); }; } catch (e) { console.warn("Failed to connect to homepage tracking WebSocket", e); @@ -243,6 +242,11 @@ class Client { private async handleJoinLobby(event: CustomEvent) { const lobby = event.detail as JoinLobbyEvent; consolex.log(`joining lobby ${lobby.gameID}`); + if (this.homepageWS) { + this.homepageWS.close(); + this.homepageWS = null; + } + if (this.gameStop != null) { consolex.log("joining lobby, stopping existing game"); this.gameStop(); @@ -320,6 +324,15 @@ class Client { this.gameStop(); this.gameStop = null; this.publicLobby.leaveLobby(); + + try { + const ws = new WebSocket(`ws://${location.host}/w0`); + ws.onopen = () => { + ws.send(JSON.stringify({ type: "homepage_ping" })); + }; + } catch (e) { + console.warn("Failed to reconnect to homepage tracking WebSocket", e); + } } } diff --git a/src/client/Transport.ts b/src/client/Transport.ts index a9ee93fe9..5112fcc8a 100644 --- a/src/client/Transport.ts +++ b/src/client/Transport.ts @@ -15,7 +15,6 @@ import { AllPlayersStats, ClientID, ClientIntentMessageSchema, - ClientJoinMessageSchema, ClientLogMessageSchema, ClientMessageSchema, ClientPingMessageSchema, @@ -329,18 +328,20 @@ export class Transport { } joinGame(numTurns: number) { + if (!this.lobbyConfig.gameID) { + throw new Error("gameID is missing in lobbyConfig. Cannot join game."); + } + this.sendMsg( - JSON.stringify( - ClientJoinMessageSchema.parse({ - type: "join", - gameID: this.lobbyConfig.gameID, - clientID: this.lobbyConfig.clientID, - lastTurn: numTurns, - persistentID: this.lobbyConfig.persistentID, - username: this.lobbyConfig.playerName, - flag: this.lobbyConfig.flag, - }), - ), + JSON.stringify({ + type: "join", + gameID: this.lobbyConfig.gameID, + clientID: this.lobbyConfig.clientID, + lastTurn: numTurns, + persistentID: this.lobbyConfig.persistentID, + username: this.lobbyConfig.playerName, + flag: this.lobbyConfig.flag, + }), ); } diff --git a/src/server/Worker.ts b/src/server/Worker.ts index 170dff2c3..facd926f5 100644 --- a/src/server/Worker.ts +++ b/src/server/Worker.ts @@ -271,9 +271,15 @@ export function startWorker() { sendHomepageCount(); return; } + log.info("FULL JOIN MSG:", clientMsg); - if (clientMsg.type == "join") { - // Verify this worker should handle this game + if ( + clientMsg.type === "join" && + typeof clientMsg.gameID === "string" && + typeof clientMsg.clientID === "string" && + typeof clientMsg.username === "string" && + typeof clientMsg.persistentID === "string" + ) { const expectedWorkerId = config.workerIndex(clientMsg.gameID); if (expectedWorkerId !== workerId) { log.warn( @@ -282,28 +288,39 @@ export function startWorker() { return; } - // Create client and add to game + log.info( + `Processing join for gameID: ${clientMsg.gameID}, clientID: ${clientMsg.clientID}`, + ); + const client = new Client( clientMsg.clientID, clientMsg.persistentID, ip, clientMsg.username, ws, - clientMsg.flag, + clientMsg.flag ?? "", // fallback if flag is missing ); + homepageClients.delete(ws); // Remove from homepage tracker + sendHomepageCount(); // Update count immediately - const wasFound = gm.addClient( - client, - clientMsg.gameID, - clientMsg.lastTurn, - ); + let wasFound = false; + try { + wasFound = gm.addClient( + client, + clientMsg.gameID, + clientMsg.lastTurn ?? 0, // default to 0 + ); + } catch (err) { + log.error("gm.addClient threw error:", err); + } if (!wasFound) { log.info( `game ${clientMsg.gameID} not found on worker ${workerId}`, ); - // Handle game not found case } + + return; } // Handle other message types