Gracefully handle reconnection when player disconnects from a game. Redirect players to game URL when they visit / without a gameId

This commit is contained in:
sepia 2025-07-23 21:47:15 -05:00
parent 9334ae12ce
commit 034a9d3909
2 changed files with 29 additions and 9 deletions

View File

@ -49,6 +49,7 @@ const app = new Elysia()
} }
let gameId = query.gameId as string | undefined; let gameId = query.gameId as string | undefined;
let gameIdInitialized = false;
if (gameId) { if (gameId) {
if (!wsHandler.hasGame(gameId)) { if (!wsHandler.hasGame(gameId)) {
wsHandler.createGame(gameId); wsHandler.createGame(gameId);
@ -56,9 +57,17 @@ const app = new Elysia()
} }
} else { } else {
gameId = wsHandler.createGame(); gameId = wsHandler.createGame();
gameIdInitialized = true;
console.log(`Created new game without specific ID: ${gameId}`); console.log(`Created new game without specific ID: ${gameId}`);
} }
if (gameIdInitialized) {
return new Response(null, {
status: 302,
headers: { Location: `/?gameId=${gameId}` },
});
}
const displayName = wsHandler.getPlayerName(playerId); const displayName = wsHandler.getPlayerName(playerId);
const htmlTemplate = await Bun.file('./index.html').text(); const htmlTemplate = await Bun.file('./index.html').text();

View File

@ -54,16 +54,26 @@ class GameServer {
public handleConnection(ws: WS) { public handleConnection(ws: WS) {
const { playerId } = ws.data.query; const { playerId } = ws.data.query;
if (this.connections.has(playerId)) {
const existingConn = this.connections.get(playerId)!;
existingConn.ws = ws; // Update with new WebSocket
console.log(
`Updated connection for player ${playerId} in game ${this.id}, replacing old WS.`,
);
} else {
const playerName = this.webSocketHandler.getPlayerName(playerId); // Retrieve name or use ID const playerName = this.webSocketHandler.getPlayerName(playerId); // Retrieve name or use ID
const conn = new PlayerConnection(playerId, playerName, ws); const conn = new PlayerConnection(playerId, playerName, ws);
this.connections.set(playerId, conn); this.connections.set(playerId, conn);
console.log(`Created connection with player ${conn.id} in game ${this.id}`); console.log(
`Created new connection with player ${conn.id} in game ${this.id}`,
);
if (!this.blackPlayerId) { if (!this.blackPlayerId) {
this.blackPlayerId = conn.id; this.blackPlayerId = conn.id;
} else if (!this.whitePlayerId) { } else if (!this.whitePlayerId) {
this.whitePlayerId = conn.id; this.whitePlayerId = conn.id;
} }
}
if (this.whitePlayerId && this.blackPlayerId) { if (this.whitePlayerId && this.blackPlayerId) {
this.gomoku.status = 'playing'; this.gomoku.status = 'playing';
} }
@ -76,6 +86,7 @@ class GameServer {
public handleDisconnect(ws: WS) { public handleDisconnect(ws: WS) {
const { playerId } = ws.data.query; const { playerId } = ws.data.query;
this.connections.delete(playerId); this.connections.delete(playerId);
this.broadcastTitle();
} }
public broadcastBoard() { public broadcastBoard() {
@ -734,7 +745,7 @@ export class WebSocketHandler {
game.handleDisconnect(ws); game.handleDisconnect(ws);
console.log(`${playerId} disconnected from game ${gameId}`); console.log(`${playerId} disconnected from game ${gameId}`);
if (game.connections.entries.length == 0) { if (game.connections.size == 0) {
this.games.delete(gameId); this.games.delete(gameId);
console.log(`Game ${gameId} has been deleted (empty).`); console.log(`Game ${gameId} has been deleted (empty).`);
} }