adds leave game feature

This commit is contained in:
pb-coding 2023-09-25 12:43:45 +02:00
parent cca7d045e4
commit 456b0c2b1e
3 changed files with 79 additions and 9 deletions

View file

@ -2,6 +2,8 @@ import { Socket } from "socket.io";
import { io } from "../server"; import { io } from "../server";
import { Game } from "./game"; import { Game } from "./game";
import { allGames } from "./game";
export const handleJoinSession = (socket: Socket, sessionId: string) => { export const handleJoinSession = (socket: Socket, sessionId: string) => {
socket.join(sessionId); socket.join(sessionId);
console.log("User joined session:", 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); 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 = ( export const handleNewGame = (
socket: Socket, socket: Socket,
gameDetails: { sessionId: string } gameDetails: { sessionId: string }
@ -25,9 +41,24 @@ export const handleNewGame = (
if (players && players.size > 1) { if (players && players.size > 1) {
const game = new Game(socket, sessionId, players); const game = new Game(socket, sessionId, players);
game.sendObfuscatedGameUpdate(); allGames.push(game);
console.log(`New Game created with ${game.playerCount} players!`);
game.gameLoop();
} else { } else {
// TODO: error handling & send message to client // TODO: error handling & send message to client
console.log("Not enough players to start a game"); 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);
});
};

View file

@ -3,6 +3,7 @@ import { CardStack } from "./card";
import { Card, ObfuscatedCardStack } from "./card"; import { Card, ObfuscatedCardStack } from "./card";
import { Socket } from "socket.io"; import { Socket } from "socket.io";
import { io } from "../server"; import { io } from "../server";
import { all } from "axios";
type PlayerSocketSet = Set<string>; type PlayerSocketSet = Set<string>;
@ -31,6 +32,8 @@ export type ObfuscatedGame = {
round: number; round: number;
}; };
export const allGames: Game[] = [];
const gamePhase = { const gamePhase = {
newRound: "new round", newRound: "new round",
revealTwoCards: "reveal two cards", revealTwoCards: "reveal two cards",
@ -65,9 +68,6 @@ export class Game {
this.discardPile = [this.cardStack.cards.pop()!]; this.discardPile = [this.cardStack.cards.pop()!];
this.phase = gamePhase.revealTwoCards; this.phase = gamePhase.revealTwoCards;
this.round = 1; this.round = 1;
console.log(`New Game created with ${this.playerCount} players!`);
this.gameLoop();
} }
initializePlayers( initializePlayers(
@ -114,6 +114,7 @@ export class Game {
async gameLoop() { async gameLoop() {
console.log("Game started!"); console.log("Game started!");
this.sendObfuscatedGameUpdate();
while (this.phase !== gamePhase.gameEnded) { while (this.phase !== gamePhase.gameEnded) {
this.checkForFullRevealedCards(); this.checkForFullRevealedCards();
switch (this.phase) { switch (this.phase) {
@ -142,7 +143,8 @@ export class Game {
await this.nextRound(); await this.nextRound();
break; break;
default: 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); io.to(this.sessionId).emit("game-update", obfuscatedGame);
} }
sendNullGameUpdate() {
io.to(this.sessionId).emit("game-update", null);
}
updatePlayerRoundPoints() { updatePlayerRoundPoints() {
this.players.forEach((player) => { this.players.forEach((player) => {
const revealedCardValuesSum = player.getRevealedCardsValueSum(); 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() { revealAllCards() {
this.players.forEach((player) => { this.players.forEach((player) => {
player.knownCardPositions = player.knownCardPositions.map( player.knownCardPositions = player.knownCardPositions.map(

View file

@ -12,7 +12,12 @@ import cors from "cors";
import corsOptions from "./config/corsOptions"; import corsOptions from "./config/corsOptions";
import cookieParser from "cookie-parser"; import cookieParser from "cookie-parser";
import rootRouter from "./routes/root"; import rootRouter from "./routes/root";
import { handleJoinSession, handleNewGame } from "./game/events"; import {
handleJoinSession,
handleLeaveSession,
handleNewGame,
handleDisconnect,
} from "./game/events";
import dotenv from "dotenv"; import dotenv from "dotenv";
dotenv.config(); dotenv.config();
@ -33,14 +38,18 @@ io.on("connection", (socket: Socket) => {
handleJoinSession(socket, sessionId) 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 }) => socket.on("new-game", (gameDetails: { sessionId: string }) =>
// TODO: get sessionId from socket instead of passing it from client
handleNewGame(socket, gameDetails) handleNewGame(socket, gameDetails)
); );
socket.on("disconnect", () => { socket.on("disconnect", () => {
console.log("A user disconnected:", socket.id); handleDisconnect(socket);
// TODO: remove players from session and delete game object
io;
}); });
}); });