From 456b0c2b1e1babacca7976ccd9ada854fde709f6 Mon Sep 17 00:00:00 2001 From: pb-coding <71174645+pb-coding@users.noreply.github.com> Date: Mon, 25 Sep 2023 12:43:45 +0200 Subject: [PATCH] adds leave game feature --- src/game/events.ts | 33 ++++++++++++++++++++++++++++++++- src/game/game.ts | 38 ++++++++++++++++++++++++++++++++++---- src/server.ts | 17 +++++++++++++---- 3 files changed, 79 insertions(+), 9 deletions(-) diff --git a/src/game/events.ts b/src/game/events.ts index 464c972..3c300f3 100644 --- a/src/game/events.ts +++ b/src/game/events.ts @@ -2,6 +2,8 @@ import { Socket } from "socket.io"; import { io } from "../server"; import { Game } from "./game"; +import { allGames } from "./game"; + export const handleJoinSession = (socket: Socket, sessionId: string) => { socket.join(sessionId); console.log("User joined session:", sessionId); @@ -11,6 +13,20 @@ export const handleJoinSession = (socket: Socket, sessionId: string) => { io.to(sessionId).emit("clients-in-session", numberOfClients); }; +export const handleLeaveSession = (socket: Socket, sessionId: string) => { + socket.emit("game-update", null); + socket.leave(sessionId); + console.log("User left session:", sessionId); + + const numberOfClients = io.sockets.adapter.rooms.get(sessionId)?.size ?? 0; + console.log("Clients in room:", numberOfClients); + io.to(sessionId).emit("clients-in-session", numberOfClients); + + const relatedGame = allGames.find((game) => game.sessionId === sessionId); + if (!relatedGame) return; + relatedGame.checkForPlayerLeave(); +}; + export const handleNewGame = ( socket: Socket, gameDetails: { sessionId: string } @@ -25,9 +41,24 @@ export const handleNewGame = ( if (players && players.size > 1) { const game = new Game(socket, sessionId, players); - game.sendObfuscatedGameUpdate(); + allGames.push(game); + console.log(`New Game created with ${game.playerCount} players!`); + game.gameLoop(); } else { // TODO: error handling & send message to client console.log("Not enough players to start a game"); } }; + +export const handleDisconnect = (socket: Socket) => { + console.log("A user disconnected:", socket.id); + // TODO: update clients-in-room and delete game object + console.log("socket rooms", socket.rooms.size); + allGames.forEach((game) => { + game.checkForPlayerLeave(); + }); + const allSessions = io.sockets.adapter.rooms; + allSessions.forEach((socketIds, sessionName) => { + io.to(sessionName).emit("clients-in-session", socketIds.size); + }); +}; diff --git a/src/game/game.ts b/src/game/game.ts index 4db5ed0..2215613 100644 --- a/src/game/game.ts +++ b/src/game/game.ts @@ -3,6 +3,7 @@ import { CardStack } from "./card"; import { Card, ObfuscatedCardStack } from "./card"; import { Socket } from "socket.io"; import { io } from "../server"; +import { all } from "axios"; type PlayerSocketSet = Set; @@ -31,6 +32,8 @@ export type ObfuscatedGame = { round: number; }; +export const allGames: Game[] = []; + const gamePhase = { newRound: "new round", revealTwoCards: "reveal two cards", @@ -65,9 +68,6 @@ export class Game { this.discardPile = [this.cardStack.cards.pop()!]; this.phase = gamePhase.revealTwoCards; this.round = 1; - - console.log(`New Game created with ${this.playerCount} players!`); - this.gameLoop(); } initializePlayers( @@ -114,6 +114,7 @@ export class Game { async gameLoop() { console.log("Game started!"); + this.sendObfuscatedGameUpdate(); while (this.phase !== gamePhase.gameEnded) { this.checkForFullRevealedCards(); switch (this.phase) { @@ -142,7 +143,8 @@ export class Game { await this.nextRound(); break; default: - throw new Error(`Invalid game phase: ${this.phase}`); + console.log("\nGame Ended."); + break; } } } @@ -415,6 +417,10 @@ export class Game { io.to(this.sessionId).emit("game-update", obfuscatedGame); } + sendNullGameUpdate() { + io.to(this.sessionId).emit("game-update", null); + } + updatePlayerRoundPoints() { this.players.forEach((player) => { const revealedCardValuesSum = player.getRevealedCardsValueSum(); @@ -487,6 +493,30 @@ export class Game { } } + checkForPlayerLeave() { + const playersInSession = io.sockets.adapter.rooms.get(this.sessionId); + if (playersInSession?.size ?? 0 < this.playerCount) { + const playerThatLeftSession = this.players.filter( + (player) => !playersInSession?.has(player.socketId) + ); + console.log("players that left session", playerThatLeftSession); + if (playerThatLeftSession.length > 0) { + this.sendMessageToAllPlayers( + `${playerThatLeftSession.map( + (player) => player.name + " " + )} left the session!` + ); + this.phase = gamePhase.gameEnded; + this.sendNullGameUpdate(); + io.to(this.sessionId).emit( + "clients-in-session", + playersInSession?.size ?? 0 + ); + allGames.splice(allGames.indexOf(this), 1); + } + } + } + revealAllCards() { this.players.forEach((player) => { player.knownCardPositions = player.knownCardPositions.map( diff --git a/src/server.ts b/src/server.ts index 48ee502..cbe65e2 100644 --- a/src/server.ts +++ b/src/server.ts @@ -12,7 +12,12 @@ import cors from "cors"; import corsOptions from "./config/corsOptions"; import cookieParser from "cookie-parser"; import rootRouter from "./routes/root"; -import { handleJoinSession, handleNewGame } from "./game/events"; +import { + handleJoinSession, + handleLeaveSession, + handleNewGame, + handleDisconnect, +} from "./game/events"; import dotenv from "dotenv"; dotenv.config(); @@ -33,14 +38,18 @@ io.on("connection", (socket: Socket) => { handleJoinSession(socket, sessionId) ); + socket.on("leave-session", (sessionId: string) => { + // TODO: check if user is in that session before leaving + handleLeaveSession(socket, sessionId); + }); + socket.on("new-game", (gameDetails: { sessionId: string }) => + // TODO: get sessionId from socket instead of passing it from client handleNewGame(socket, gameDetails) ); socket.on("disconnect", () => { - console.log("A user disconnected:", socket.id); - // TODO: remove players from session and delete game object - io; + handleDisconnect(socket); }); });