From eae5b70194c0b948b281cab71a696e3d2710d576 Mon Sep 17 00:00:00 2001 From: LuckyLaszlo Date: Sun, 1 Jan 2023 22:13:22 +0100 Subject: [PATCH] GameSpectator nearly done (missing fetch matchlist from Nest) + matchEnded/matchAbort proper reset (replace setTimeout) + abort window.addEventListener('keydown/keyup', ...) + refactoring Game.svelte and others + fix $POSTGRES_PASSWORD in make_env.sh + Wip bug audio --- .gitignore | 4 + make_env.sh | 5 +- srcs/.env | 13 -- .../game_back/src/server/class/GameSession.ts | 11 +- .../game_back/src/server/wsServer.ts | 55 +++++-- .../game_back/src/shared_js/constants.ts | 4 +- .../game_back/src/shared_js/enums.ts | 1 + srcs/requirements/nestjs/api_back/.env | 13 -- .../api_front/src/pages/game/Game.svelte | 142 +++++++----------- .../src/pages/game/GameSpectator.svelte | 21 ++- .../api_front/src/pages/game/client/audio.ts | 19 ++- .../pages/game/client/class/InitOptions.ts | 9 ++ .../src/pages/game/client/gameLoop.ts | 3 +- .../api_front/src/pages/game/client/global.ts | 11 +- .../src/pages/game/client/handleInput.ts | 6 +- .../api_front/src/pages/game/client/init.ts | 13 +- .../api_front/src/pages/game/client/pong.ts | 48 ++++-- .../src/pages/game/client/pongSpectator.ts | 10 +- .../api_front/src/pages/game/client/ws.ts | 26 ++-- .../src/pages/game/shared_js/constants.ts | 4 +- .../src/pages/game/shared_js/enums.ts | 1 + 21 files changed, 233 insertions(+), 186 deletions(-) delete mode 100644 srcs/.env delete mode 100644 srcs/requirements/nestjs/api_back/.env diff --git a/.gitignore b/.gitignore index 140fa633..96b0e159 100644 --- a/.gitignore +++ b/.gitignore @@ -53,3 +53,7 @@ lerna-debug.log* !.vscode/tasks.json !.vscode/launch.json !.vscode/extensions.json + +.env + +memo.txt diff --git a/make_env.sh b/make_env.sh index 55da918f..8cff3621 100644 --- a/make_env.sh +++ b/make_env.sh @@ -33,7 +33,8 @@ read -p "Enter the name of the host like \"localhost\" : " PROJECT_HOST echo "WEBSITE_HOST=$PROJECT_HOST" >> "$ENV_FILE_DOCKER" echo "WEBSITE_PORT=8080" >> "$ENV_FILE_DOCKER" echo "POSTGRES_USER=postgres" >> "$ENV_FILE_DOCKER" -echo "POSTGRES_PASSWORD=$(openssl rand -base64 32)" >> "$ENV_FILE_DOCKER" +POSTGRES_PASSWORD=$(openssl rand -base64 32) +echo "POSTGRES_PASSWORD=$POSTGRES_PASSWORD" >> "$ENV_FILE_DOCKER" echo "POSTGRES_DB=transcendance_db" >> "$ENV_FILE_DOCKER" echo "POSTGRES_HOST=postgresql" >> "$ENV_FILE_DOCKER" echo "POSTGRES_PORT=5432" >> "$ENV_FILE_DOCKER" @@ -56,7 +57,7 @@ fi echo "WEBSITE_HOST=$PROJECT_HOST" >> "$ENV_FILE_NESTJS" echo "WEBSITE_PORT=8080" >> "$ENV_FILE_NESTJS" echo "POSTGRES_USER=postgres" >> "$ENV_FILE_NESTJS" -echo "POSTGRES_PASSWORD=$POSTGRES_PASSSWORD" >> "$ENV_FILE_NESTJS" +echo "POSTGRES_PASSWORD=$POSTGRES_PASSWORD" >> "$ENV_FILE_NESTJS" echo "POSTGRES_DB=transcendance_db" >> "$ENV_FILE_NESTJS" echo "POSTGRES_HOST=postgresql" >> "$ENV_FILE_NESTJS" echo "POSTGRES_PORT=5432" >> "$ENV_FILE_NESTJS" diff --git a/srcs/.env b/srcs/.env deleted file mode 100644 index c63e1cc3..00000000 --- a/srcs/.env +++ /dev/null @@ -1,13 +0,0 @@ -NODE_ENV=development -WEBSITE_HOST=transcendance -POSTGRES_USER=postgres -POSTGRES_PASSWORD=unPCFsMxZwwCguGFMTmKgCySt6o5uX76QsKyabKS89I= -POSTGRES_DB=transcendance_db -POSTGRES_HOST=postgresql -POSTGRES_PORT=5432 -REDIS_HOST=redis -REDIS_PORT=6379 -REDIS_PASSWORD=yiCFcBSrFv7DXVBmydtwL9unzNA2MjbB70XspflHHPc= -REDIS_HOST=redis -REDIS_PORT=6379 -REDIS_PASSWORD= diff --git a/srcs/requirements/game_server/game_back/src/server/class/GameSession.ts b/srcs/requirements/game_server/game_back/src/server/class/GameSession.ts index 287c1c02..e31ce997 100644 --- a/srcs/requirements/game_server/game_back/src/server/class/GameSession.ts +++ b/srcs/requirements/game_server/game_back/src/server/class/GameSession.ts @@ -154,11 +154,12 @@ export class GameSession { else if (ball.pos.x < 0 - ball.width) { ++gc.scoreRight; } + const scoreUpdate = new ev.EventScoreUpdate(gc.scoreLeft, gc.scoreRight); this.playersMap.forEach( (client) => { - client.socket.send(JSON.stringify(new ev.EventScoreUpdate(gc.scoreLeft, gc.scoreRight))); + client.socket.send(JSON.stringify(scoreUpdate)); }); this.spectatorsMap.forEach( (client) => { - client.socket.send(JSON.stringify(new ev.EventScoreUpdate(gc.scoreLeft, gc.scoreRight))); + client.socket.send(JSON.stringify(scoreUpdate)); }); } private _playersUpdate(s: GameSession) { @@ -167,9 +168,9 @@ export class GameSession { s.lastStateSnapshot.lastInputId = client.lastInputId; client.socket.send(JSON.stringify(s.lastStateSnapshot)); }); + s.lastStateSnapshot.lastInputId = 0; } private _spectatorsUpdate(s: GameSession) { - s.lastStateSnapshot.lastInputId = 0; s.spectatorsMap.forEach( (client) => { client.socket.send(JSON.stringify(s.lastStateSnapshot)); }); @@ -251,8 +252,7 @@ export class GameSession { private async _matchEnd(winner: en.PlayerSide, forfeit_flag: boolean = false) { this.matchEnded = true; - let eventEnd: ev.EventMatchEnd; - eventEnd = new ev.EventMatchEnd(winner, forfeit_flag); + const eventEnd = new ev.EventMatchEnd(winner, forfeit_flag); this.playersMap.forEach( (client) => { client.socket.send(JSON.stringify(eventEnd)); }); @@ -260,6 +260,7 @@ export class GameSession { client.socket.send(JSON.stringify(eventEnd)); }); + // TODO: mettre à jour la route pour gerer les forfaits (actuellement le plus haut score gagne par defaut) const gc = this.components; await fetch(c.addressBackEnd + "/game/gameserver/updategame", { diff --git a/srcs/requirements/game_server/game_back/src/server/wsServer.ts b/srcs/requirements/game_server/game_back/src/server/wsServer.ts index 8b3226bb..01d0941c 100644 --- a/srcs/requirements/game_server/game_back/src/server/wsServer.ts +++ b/srcs/requirements/game_server/game_back/src/server/wsServer.ts @@ -14,7 +14,6 @@ import * as c from "./constants.js" import { Client, ClientPlayer, ClientSpectator } from "./class/Client.js" import { GameSession } from "./class/GameSession.js" import { shortId } from "./utils.js"; -import { gameSessionIdPLACEHOLDER } from "./constants.js"; const wsPort = 8042; export const wsServer = new WebSocketServer({host: "0.0.0.0", port: wsPort, path: "/pong"}); @@ -23,12 +22,12 @@ const matchmakingMap: Map = new Map; // socket.id/ClientPl const privateMatchmakingMap: Map = new Map; // socket.id/ClientPlayer (duplicates with clientsMap) const gameSessionsMap: Map = new Map; // GameSession.id(url)/GameSession -wsServer.on("connection", connectionListener); -wsServer.on("error", errorListener); -wsServer.on("close", closeListener); +wsServer.on("connection", serverConnectionListener); +wsServer.on("error", serverErrorListener); +wsServer.on("close", serverCloseListener); -function connectionListener(socket: WebSocket, request: IncomingMessage) +function serverConnectionListener(socket: WebSocket, request: IncomingMessage) { const id = uuidv4(); const client = new Client(socket, id); @@ -40,7 +39,11 @@ function connectionListener(socket: WebSocket, request: IncomingMessage) console.log(`client ${shortId(client.id)} is alive`); }); - socket.on("error", function errorPrint(this: WebSocket, err: Error) { + socket.on("close", function removeClient() { + clientTerminate(client); + }); + + socket.on("error", function errorLog(this: WebSocket, err: Error) { console.log(`error socket ${shortId(this.id)}:`); console.log(`${err.name}: ${err.message}`); if (err.stack) { @@ -48,7 +51,7 @@ function connectionListener(socket: WebSocket, request: IncomingMessage) } }); - socket.on("message", function log(data: string) { + socket.on("message", function messageLog(data: string) { try { const event: ev.ClientEvent = JSON.parse(data); if (event.type === en.EventTypes.clientInput) { @@ -69,13 +72,11 @@ async function clientAnnounceListener(this: WebSocket, data: string) const msg : ev.ClientAnnounce = JSON.parse(data); if (msg.type === en.EventTypes.clientAnnounce) { - // TODO: reconnection with msg.clientId ? - // "/pong" to play, "/pong?ID_OF_A_GAMESESSION" to spectate (or something like that) + // BONUS: reconnection with msg.clientId ? if (msg.role === en.ClientRole.player) { const announce: ev.ClientAnnouncePlayer = msg; - // WIP nest, fetch token validation const body = { playerOneUsername: announce.username, playerTwoUsername: "", @@ -96,7 +97,7 @@ async function clientAnnounceListener(this: WebSocket, data: string) }); if (!response.ok) { - this.send(JSON.stringify( new ev.EventError((await response.json()).message))); + this.send(JSON.stringify( new ev.EventError((await response.json()).message) )); clientTerminate(clientsMap.get(this.id)); return; } @@ -122,13 +123,14 @@ async function clientAnnounceListener(this: WebSocket, data: string) const announce: ev.ClientAnnounceSpectator = msg; const gameSession = gameSessionsMap.get(announce.gameSessionId); if (!gameSession) { - this.send(JSON.stringify( new ev.EventError("invalid gameSessionId"))); + this.send(JSON.stringify( new ev.EventError("invalid gameSessionId") )); clientTerminate(clientsMap.get(this.id)); return; } const spectator = clientsMap.get(this.id) as ClientSpectator; spectator.gameSession = gameSession; gameSession.spectatorsMap.set(spectator.id, spectator); + spectator.socket.once("message", spectatorReadyConfirmationListener); this.send(JSON.stringify( new ev.ServerEvent(en.EventTypes.matchStart) )); } } @@ -224,7 +226,7 @@ function privateMatchmaking(player: ClientPlayer) function createGameSession(playersArr: ClientPlayer[], matchOptions: en.MatchOptions) { - // const id = gameSessionIdPLACEHOLDER; // Force ID, TESTING SPECTATOR + // const id = c.gameSessionIdPLACEHOLDER; // Force ID, TESTING SPECTATOR const id = uuidv4(); const gameSession = new GameSession(id, matchOptions); gameSessionsMap.set(id, gameSession); @@ -274,7 +276,6 @@ async function playerReadyConfirmationListener(this: WebSocket, data: string) gameSession.unreadyPlayersMap.delete(this.id); if (gameSession.unreadyPlayersMap.size === 0) { - // WIP nest , send gameSession.id const gameSessionPlayersIterator = gameSession.playersMap.values(); const body = { gameServerIdOfTheMatch : gameSession.id, @@ -341,6 +342,28 @@ export function clientInputListener(this: WebSocket, data: string) } } +function spectatorReadyConfirmationListener(this: WebSocket, data: string) +{ + try { + const msg : ev.ClientEvent = JSON.parse(data); + if (msg.type === en.EventTypes.clientSpectatorReady) + { + const client = clientsMap.get(this.id); + const gameSession = client.gameSession; + const scoreUpdate = new ev.EventScoreUpdate(gameSession.components.scoreLeft, gameSession.components.scoreRight); + this.send(JSON.stringify(scoreUpdate)); + } + else { + console.log("Invalid spectatorReadyConfirmation"); + } + return; + } + catch (e) { + console.log("Invalid JSON (spectatorReadyConfirmationListener)"); + } + this.once("message", spectatorReadyConfirmationListener); +} + //////////// //////////// @@ -390,13 +413,13 @@ export function clientTerminate(client: Client) } -function closeListener() +function serverCloseListener() { clearInterval(pingInterval); } -function errorListener(error: Error) +function serverErrorListener(error: Error) { console.log("Error: " + JSON.stringify(error)); } diff --git a/srcs/requirements/game_server/game_back/src/shared_js/constants.ts b/srcs/requirements/game_server/game_back/src/shared_js/constants.ts index 44c282c2..18713ae4 100644 --- a/srcs/requirements/game_server/game_back/src/shared_js/constants.ts +++ b/srcs/requirements/game_server/game_back/src/shared_js/constants.ts @@ -26,5 +26,5 @@ export const movingWallPosMax = Math.floor(w*0.12); export const movingWallSpeed = Math.floor(w*0.08); -export const gameSessionIdPLACEHOLDER = "42"; // TESTING SPECTATOR PLACEHOLDER -// for testing, force gameSession.id in wsServer.ts->matchmaking() \ No newline at end of file +export const gameSessionIdPLACEHOLDER = "match-id-test-42"; // TESTING SPECTATOR PLACEHOLDER +// for testing, force gameSession.id in wsServer.ts->createGameSession() diff --git a/srcs/requirements/game_server/game_back/src/shared_js/enums.ts b/srcs/requirements/game_server/game_back/src/shared_js/enums.ts index b86571e5..6d54e139 100644 --- a/srcs/requirements/game_server/game_back/src/shared_js/enums.ts +++ b/srcs/requirements/game_server/game_back/src/shared_js/enums.ts @@ -19,6 +19,7 @@ export enum EventTypes { // Client clientAnnounce, clientPlayerReady, + clientSpectatorReady, clientInput, } diff --git a/srcs/requirements/nestjs/api_back/.env b/srcs/requirements/nestjs/api_back/.env deleted file mode 100644 index e1dc7bcd..00000000 --- a/srcs/requirements/nestjs/api_back/.env +++ /dev/null @@ -1,13 +0,0 @@ -NODE_ENV=development -POSTGRES_USER=postgres -POSTGRES_PASSWORD= -POSTGRES_DB=transcendance_db -POSTGRES_HOST=postgresql -POSTGRES_PORT=5432 -FORTYTWO_CLIENT_ID=u-s4t2ud-49dc7b539bcfe1acb48b928b2b281671c99fc5bfab1faca57a536ab7e0075500 -FORTYTWO_CLIENT_SECRET=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 -FORTYTWO_CALLBACK_URL=http://transcendance:8080/api/v2/auth/redirect -COOKIE_SECRET=JsqrZopdOb3zuAkZd+8xDkPHOhEMmbz4eAlJ+liEo0U= -PORT=3000 -TWO_FACTOR_AUTHENTICATION_APP_NAME=Transcendance -TICKET_FOR_PLAYING_GAME_SECRET=5MkACVi80PE+7XGrG3Tij3+BE3RJk0h0v7NI0uFJswg= diff --git a/srcs/requirements/svelte/api_front/src/pages/game/Game.svelte b/srcs/requirements/svelte/api_front/src/pages/game/Game.svelte index 8d57ae2c..7dfd1b08 100644 --- a/srcs/requirements/svelte/api_front/src/pages/game/Game.svelte +++ b/srcs/requirements/svelte/api_front/src/pages/game/Game.svelte @@ -5,9 +5,7 @@ import { fade, fly } from 'svelte/transition'; import * as pong from "./client/pong"; - - // Pour Chérif: variables indiquant l'état du match - import { matchEnded, matchAbort } from "./client/ws"; + import { gameState } from "./client/ws"; //user's stuff let user; @@ -44,28 +42,14 @@ }) onDestroy( async() => { - options.playerOneUsername = user.username; - showError = false; - showMatchEnded = false; - optionsAreNotSet = true - options.playerTwoUsername = ""; - options.isSomeoneIsInvited = false; - options.isInvitedPerson = false; - options.moving_walls = false; - options.multi_balls = false; - errorMessageWhenAttemptingToGetATicket = ""; - hiddenGame = true; - isThereAnyInvitation = false; - invitations = []; - pong.destroy(); clearInterval(idOfIntevalCheckTerminationOfTheMatch); + pong.destroy(); }) const initGame = async() => { optionsAreNotSet = false; showWaitPage = true; - idOfIntevalCheckTerminationOfTheMatch = setInterval(matchTermitation, 1000); const matchOptions = pong.computeMatchOptions(options); const responseWhenGrantToken = fetch("http://transcendance:8080/api/v2/game/ticket", { @@ -87,39 +71,35 @@ { console.log(responseInjson) console.log("On refuse le ticket"); - clearInterval(idOfIntevalCheckTerminationOfTheMatch); errorMessageWhenAttemptingToGetATicket = responseInjson.message; showError = true; - options.playerTwoUsername = ""; + options.reset(); options.playerOneUsername = user.username; - options.isSomeoneIsInvited = false; - options.isInvitedPerson = false; - options.moving_walls = false; - options.multi_balls = false; setTimeout(() => { - showError = false; - showWaitPage = false optionsAreNotSet = true - + showError = false; + // showWaitPage = false // ??? }, 5000); } else if (token) { - options.isInvitedPerson = false + idOfIntevalCheckTerminationOfTheMatch = setInterval(matchTermitation, 1000); + // options.isInvitedPerson = false // ??? pong.init(options, gameAreaId, token); hiddenGame = false; } + // TODO: Un "else" peut-être ? Si pas de token on fait un truc ? } const initGameForInvitedPlayer = async(invitation : any) => { - idOfIntevalCheckTerminationOfTheMatch = setInterval(matchTermitation, 1000); optionsAreNotSet = false showWaitPage = true console.log("invitation : ") console.log(invitation) if (invitation.token) { + idOfIntevalCheckTerminationOfTheMatch = setInterval(matchTermitation, 1000); options.playerOneUsername = invitation.playerOneUsername; options.playerTwoUsername = invitation.playerTwoUsername; options.isSomeoneIsInvited = true; @@ -132,32 +112,20 @@ const matchTermitation = () => { console.log("Ping matchTermitation") - if (matchAbort || matchEnded) + if (gameState.matchAbort || gameState.matchEnded) { clearInterval(idOfIntevalCheckTerminationOfTheMatch); console.log("matchTermitation was called") showWaitPage = false - matchAbort ? + gameState.matchAbort ? errorMessageWhenAttemptingToGetATicket = "The match has been aborted" : errorMessageWhenAttemptingToGetATicket = "The match is finished !" - matchAbort ? showError = true : showMatchEnded = true; + gameState.matchAbort ? showError = true : showMatchEnded = true; setTimeout(() => { - hiddenGame = true; - showError = false; - showMatchEnded = false; - optionsAreNotSet = true - options.playerTwoUsername = ""; - options.playerOneUsername = user.username; - options.isSomeoneIsInvited = false; - options.isInvitedPerson = false; - options.moving_walls = false; - options.multi_balls = false; + resetPage(); errorMessageWhenAttemptingToGetATicket = ""; - options.playerTwoUsername = ""; - hiddenGame = true; isThereAnyInvitation = false; - invitations = []; - pong.destroy(); + invitations = []; // ??? console.log("matchTermitation : setTimeout") }, 5000); } @@ -213,7 +181,16 @@ } function leaveMatch() { + resetPage(); + }; + + function resetPage() { hiddenGame = true; + optionsAreNotSet = true + showError = false; + showMatchEnded = false; + options.reset(); + options.playerOneUsername = user.username; pong.destroy(); }; @@ -262,44 +239,41 @@ {#if optionsAreNotSet} {#if showGameOption === true}
-
initGame()}> -
- -
- game options -
- - -
-
- - -
-
-

sound :

- - - - -
-
- - -
- {#if options.isSomeoneIsInvited === true} - - {/if} -
- -
-
-
- -
+
+ +
+ game options +
+ + +
+
+ + +
+
+

sound :

+ + + + +
+
+ + +
+ {#if options.isSomeoneIsInvited === true} + + {/if} +
+ +
+
+
{/if} diff --git a/srcs/requirements/svelte/api_front/src/pages/game/GameSpectator.svelte b/srcs/requirements/svelte/api_front/src/pages/game/GameSpectator.svelte index eeafa43b..9278ec53 100644 --- a/srcs/requirements/svelte/api_front/src/pages/game/GameSpectator.svelte +++ b/srcs/requirements/svelte/api_front/src/pages/game/GameSpectator.svelte @@ -6,9 +6,8 @@ import { fade, fly } from 'svelte/transition'; import * as pongSpectator from "./client/pongSpectator"; - - // Pour Chérif: variables indiquant l'état du match - import { matchEnded, matchAbort } from "./client/ws"; + import { gameState } from "./client/ws"; + import { gameSessionIdPLACEHOLDER } from "./shared_js/constants"; //user's stuff let user; @@ -19,11 +18,17 @@ let sound = "off"; const dummyMatchList = [ { - gameSessionId: "id2445", + gameSessionId: gameSessionIdPLACEHOLDER, matchOptions: pongSpectator.MatchOptions.noOption, playerOneUsername: "toto", playerTwoUsername: "bruno", }, + { + gameSessionId: gameSessionIdPLACEHOLDER, + matchOptions: pongSpectator.MatchOptions.multiBalls, + playerOneUsername: "pl1", + playerTwoUsername: "pl2", + }, { gameSessionId: "id6543", matchOptions: pongSpectator.MatchOptions.movingWalls | pongSpectator.MatchOptions.multiBalls, @@ -55,14 +60,20 @@ pongSpectator.destroy(); }) - const initGameSpectator = async(gameSessionId: string, matchOptions: pongSpectator.MatchOptions) => { + async function initGameSpectator(gameSessionId: string, matchOptions: pongSpectator.MatchOptions) { pongSpectator.init(matchOptions, sound, gameAreaId, gameSessionId); hiddenGame = false; }; function leaveMatch() { + resetPage(); + }; + + function resetPage() { hiddenGame = true; pongSpectator.destroy(); + // WIP: fetch for match list here + matchList = dummyMatchList; }; diff --git a/srcs/requirements/svelte/api_front/src/pages/game/client/audio.ts b/srcs/requirements/svelte/api_front/src/pages/game/client/audio.ts index 07b846d2..eedc08a6 100644 --- a/srcs/requirements/svelte/api_front/src/pages/game/client/audio.ts +++ b/srcs/requirements/svelte/api_front/src/pages/game/client/audio.ts @@ -1,21 +1,32 @@ import * as c from "./constants.js" -export const soundPongArr: HTMLAudioElement[] = []; +// export const soundPongArr: HTMLAudioElement[] = []; +export const soundPongArr: HTMLAudioElement[] = [ + new Audio("http://transcendance:8080/sound/pong/"+1+".ogg"), + new Audio("http://transcendance:8080/sound/pong/"+2+".ogg") +]; export const soundRoblox = new Audio("http://transcendance:8080/sound/roblox-oof.ogg"); export function initAudio(sound: string) { - let muteFlag = true; + let muteFlag: boolean; if (sound === "on") { muteFlag = false; } + else { + muteFlag = true; + } - for (let i = 0; i <= 32; i++) { +/* for (let i = 0; i <= 32; i++) { soundPongArr.push(new Audio("http://transcendance:8080/sound/pong/"+i+".ogg")); soundPongArr[i].volume = c.soundPongVolume; soundPongArr[i].muted = muteFlag; - } + } */ + soundPongArr.forEach((value) => { + value.volume = c.soundRobloxVolume; + value.muted = muteFlag; + }); soundRoblox.volume = c.soundRobloxVolume; soundRoblox.muted = muteFlag; } diff --git a/srcs/requirements/svelte/api_front/src/pages/game/client/class/InitOptions.ts b/srcs/requirements/svelte/api_front/src/pages/game/client/class/InitOptions.ts index acefe9c8..d09c0597 100644 --- a/srcs/requirements/svelte/api_front/src/pages/game/client/class/InitOptions.ts +++ b/srcs/requirements/svelte/api_front/src/pages/game/client/class/InitOptions.ts @@ -7,4 +7,13 @@ export class InitOptions { isInvitedPerson = false; playerOneUsername = ""; playerTwoUsername = ""; + reset() { + this.sound = "off"; + this.multi_balls = false; + this.moving_walls = false; + this.isSomeoneIsInvited = false; + this.isInvitedPerson = false; + this.playerOneUsername = ""; + this.playerTwoUsername = ""; + } } diff --git a/srcs/requirements/svelte/api_front/src/pages/game/client/gameLoop.ts b/srcs/requirements/svelte/api_front/src/pages/game/client/gameLoop.ts index 2ba91739..9d3f4a1b 100644 --- a/srcs/requirements/svelte/api_front/src/pages/game/client/gameLoop.ts +++ b/srcs/requirements/svelte/api_front/src/pages/game/client/gameLoop.ts @@ -1,7 +1,8 @@ import * as c from "./constants.js"; import * as en from "../shared_js/enums.js" -import { gc, matchOptions, clientInfo, clientInfoSpectator} from "./global.js"; +import { gc, matchOptions } from "./global.js"; +import { clientInfo, clientInfoSpectator} from "./ws.js"; import { wallsMovements } from "../shared_js/wallsMovement.js"; import type { RacketClient } from "./class/RectangleClient.js"; import type { VectorInteger } from "../shared_js/class/Vector.js"; diff --git a/srcs/requirements/svelte/api_front/src/pages/game/client/global.ts b/srcs/requirements/svelte/api_front/src/pages/game/client/global.ts index 146803aa..6a00813a 100644 --- a/srcs/requirements/svelte/api_front/src/pages/game/client/global.ts +++ b/srcs/requirements/svelte/api_front/src/pages/game/client/global.ts @@ -3,27 +3,24 @@ import * as en from "../shared_js/enums.js"; import type { GameArea } from "./class/GameArea.js"; import type { GameComponentsClient } from "./class/GameComponentsClient.js"; -// export {pong, gc, matchOptions} from "./pong.js" -export {socket, clientInfo, clientInfoSpectator} from "./ws.js" - export let pong: GameArea; export let gc: GameComponentsClient; export let matchOptions: en.MatchOptions = en.MatchOptions.noOption; -export function initPong(value: GameArea) { +export function setPong(value: GameArea) { pong = value; } -export function initGc(value: GameComponentsClient) { +export function setGc(value: GameComponentsClient) { gc = value; } -export function initMatchOptions(value: en.MatchOptions) { +export function setMatchOptions(value: en.MatchOptions) { matchOptions = value; } export let startFunction: () => void; -export function initStartFunction(value: () => void) { +export function setStartFunction(value: () => void) { startFunction = value; } diff --git a/srcs/requirements/svelte/api_front/src/pages/game/client/handleInput.ts b/srcs/requirements/svelte/api_front/src/pages/game/client/handleInput.ts index 78a2af47..0798fc38 100644 --- a/srcs/requirements/svelte/api_front/src/pages/game/client/handleInput.ts +++ b/srcs/requirements/svelte/api_front/src/pages/game/client/handleInput.ts @@ -1,10 +1,10 @@ -import { pong, gc, socket, clientInfo } from "./global.js" +import { pong, gc } from "./global.js" +import { socket, clientInfo, gameState } from "./ws.js" import * as ev from "../shared_js/class/Event.js" import * as en from "../shared_js/enums.js" import { InputHistory } from "./class/InputHistory.js" import * as c from "./constants.js"; -import { matchEnded } from "./ws.js"; export let gridDisplay = false; @@ -44,7 +44,7 @@ export function handleInput() playerMovements(delta_time, keys); } - if (!matchEnded) { + if (!gameState.matchEnded) { socket.send(JSON.stringify(inputState)); } // setTimeout(testInputDelay, 100); diff --git a/srcs/requirements/svelte/api_front/src/pages/game/client/init.ts b/srcs/requirements/svelte/api_front/src/pages/game/client/init.ts index ab832e93..76051ef6 100644 --- a/srcs/requirements/svelte/api_front/src/pages/game/client/init.ts +++ b/srcs/requirements/svelte/api_front/src/pages/game/client/init.ts @@ -3,12 +3,12 @@ import * as c from "./constants.js" import * as en from "../shared_js/enums.js" import { GameArea } from "./class/GameArea.js"; import { GameComponentsClient } from "./class/GameComponentsClient.js"; -import { socket } from "./ws.js"; +import { socket, resetGameState } from "./ws.js"; import { initAudio } from "./audio.js"; import type { InitOptions } from "./class/InitOptions.js"; import { pong } from "./global.js" -import { initPong, initGc, initMatchOptions } from "./global.js" +import { setPong, setGc, setMatchOptions } from "./global.js" export function computeMatchOptions(options: InitOptions) { @@ -26,10 +26,10 @@ export function computeMatchOptions(options: InitOptions) export function initBase(matchOptions: en.MatchOptions, sound: string, gameAreaId: string) { - initMatchOptions(matchOptions); initAudio(sound); - initPong(new GameArea(gameAreaId)); - initGc(new GameComponentsClient(matchOptions, pong.ctx)); + setMatchOptions(matchOptions); + setPong(new GameArea(gameAreaId)); + setGc(new GameComponentsClient(matchOptions, pong.ctx)); } export function destroyBase() @@ -39,9 +39,10 @@ export function destroyBase() clearInterval(pong.handleInputInterval); clearInterval(pong.gameLoopInterval); clearInterval(pong.drawLoopInterval); - initPong(null); + setPong(null); } if (socket && socket.OPEN) { socket.close(); } + resetGameState(); } diff --git a/srcs/requirements/svelte/api_front/src/pages/game/client/pong.ts b/srcs/requirements/svelte/api_front/src/pages/game/client/pong.ts index cf15df25..39de4995 100644 --- a/srcs/requirements/svelte/api_front/src/pages/game/client/pong.ts +++ b/srcs/requirements/svelte/api_front/src/pages/game/client/pong.ts @@ -12,15 +12,17 @@ export { computeMatchOptions } from "./init.js"; /* TODO: A way to delay the init of variables, but still use "const" not "let" ? */ import { pong, gc } from "./global.js" -import { initStartFunction } from "./global.js" +import { setStartFunction } from "./global.js" +let abortControllerKeydown: AbortController; +let abortControllerKeyup: AbortController; export function init(options: InitOptions, gameAreaId: string, token: string) { const matchOptions = computeMatchOptions(options); initBase(matchOptions, options.sound, gameAreaId); - initStartFunction(start); + setStartFunction(start); if (options.isSomeoneIsInvited) { initWebSocket(matchOptions, token, options.playerOneUsername, true, options.playerTwoUsername, options.isInvitedPerson); } @@ -32,6 +34,14 @@ export function init(options: InitOptions, gameAreaId: string, token: string) export function destroy() { destroyBase(); + if (abortControllerKeydown) { + abortControllerKeydown.abort(); + abortControllerKeydown = null; + } + if (abortControllerKeyup) { + abortControllerKeyup.abort(); + abortControllerKeyup = null; + } } function start() @@ -41,20 +51,40 @@ function start() gc.text1.clear(); gc.text1.text = `${count}`; gc.text1.update(); - }, resume); + }, start_after_countdown); +} + +function start_after_countdown() +{ + abortControllerKeydown = new AbortController(); + window.addEventListener( + 'keydown', + (e) => { pong.addKey(e.key); }, + {signal: abortControllerKeydown.signal} + ); + + abortControllerKeyup = new AbortController(); + window.addEventListener( + 'keyup', + (e) => { pong.deleteKey(e.key);}, + {signal: abortControllerKeyup.signal} + ); + + resume(); } function resume() { gc.text1.text = ""; - window.addEventListener('keydown', function (e) { - pong.addKey(e.key); - }); - window.addEventListener('keyup', function (e) { - pong.deleteKey(e.key); - }); pong.handleInputInterval = window.setInterval(handleInput, c.handleInputIntervalMS); // pong.handleInputInterval = window.setInterval(sendLoop, c.sendLoopIntervalMS); pong.gameLoopInterval = window.setInterval(gameLoop, c.gameLoopIntervalMS); pong.drawLoopInterval = window.setInterval(drawLoop, c.drawLoopIntervalMS); } + +function pause() // unused +{ + clearInterval(pong.handleInputInterval); + clearInterval(pong.gameLoopInterval); + clearInterval(pong.drawLoopInterval); +} diff --git a/srcs/requirements/svelte/api_front/src/pages/game/client/pongSpectator.ts b/srcs/requirements/svelte/api_front/src/pages/game/client/pongSpectator.ts index 6c2c963c..0b2fbeea 100644 --- a/srcs/requirements/svelte/api_front/src/pages/game/client/pongSpectator.ts +++ b/srcs/requirements/svelte/api_front/src/pages/game/client/pongSpectator.ts @@ -10,14 +10,14 @@ export { MatchOptions } from "../shared_js/enums.js" /* TODO: A way to delay the init of variables, but still use "const" not "let" ? */ import { pong, gc } from "./global.js" -import { initStartFunction } from "./global.js" +import { setStartFunction } from "./global.js" export function init(matchOptions: en.MatchOptions, sound: string, gameAreaId: string, gameSessionId: string) { initBase(matchOptions, sound, gameAreaId); - initStartFunction(start); + setStartFunction(start); initWebSocketSpectator(gameSessionId); } @@ -36,3 +36,9 @@ function resume() pong.gameLoopInterval = window.setInterval(gameLoopSpectator, c.gameLoopIntervalMS); pong.drawLoopInterval = window.setInterval(drawLoop, c.drawLoopIntervalMS); } + +function pause() // unused +{ + clearInterval(pong.gameLoopInterval); + clearInterval(pong.drawLoopInterval); +} diff --git a/srcs/requirements/svelte/api_front/src/pages/game/client/ws.ts b/srcs/requirements/svelte/api_front/src/pages/game/client/ws.ts index 6f33f98d..fdd867f4 100644 --- a/srcs/requirements/svelte/api_front/src/pages/game/client/ws.ts +++ b/srcs/requirements/svelte/api_front/src/pages/game/client/ws.ts @@ -10,8 +10,15 @@ import { soundRoblox } from "./audio.js" import { sleep } from "./utils.js"; import { Vector, VectorInteger } from "../shared_js/class/Vector.js"; -export let matchEnded = false; -export let matchAbort = false; +export const gameState = { + matchEnded: false, + matchAbort: false +} + +export function resetGameState() { + gameState.matchEnded = false; + gameState.matchAbort = false; +} class ClientInfo { id = ""; @@ -57,7 +64,6 @@ function logListener(this: WebSocket, event: MessageEvent) { } function errorListener(this: WebSocket, event: MessageEvent) { - console.log("errorListener"); const data: ev.ServerEvent = JSON.parse(event.data); if (data.type === en.EventTypes.error) { console.log("actual Error"); @@ -98,12 +104,9 @@ function preMatchListener(this: WebSocket, event: MessageEvent) startFunction(); break; case en.EventTypes.matchAbort: - matchAbort = true; + gameState.matchAbort = true; socket.removeEventListener("message", preMatchListener); msg.matchAbort(); - setTimeout(() => { - matchAbort = false; - }, 1000); break; } } @@ -204,7 +207,7 @@ function scoreUpdate(data: ev.EventScoreUpdate) function matchEnd(data: ev.EventMatchEnd) { - matchEnded = true; + gameState.matchEnded = true; socket.close(); if (data.winner === clientInfo.side) { msg.win(); @@ -215,9 +218,6 @@ function matchEnd(data: ev.EventMatchEnd) else { msg.lose(); } - setTimeout(() => { - matchEnded = false; - }, 1000); } /* Spectator */ @@ -229,6 +229,7 @@ export function initWebSocketSpectator(gameSessionId: string) socket.send(JSON.stringify( new ev.ClientAnnounceSpectator(gameSessionId) )); }); // socket.addEventListener("message", logListener); // for testing purpose + socket.addEventListener("message", errorListener); socket.addEventListener("message", preMatchListenerSpectator); clientInfoSpectator.playerLeftNextPos = new VectorInteger(gc.playerLeft.pos.x, gc.playerLeft.pos.y); @@ -243,6 +244,7 @@ export function preMatchListenerSpectator(this: WebSocket, event: MessageEvent) { socket.removeEventListener("message", preMatchListenerSpectator); socket.addEventListener("message", inGameListenerSpectator); + socket.send(JSON.stringify( new ev.ClientEvent(en.EventTypes.clientSpectatorReady) )); startFunction(); } } @@ -318,7 +320,7 @@ function scoreUpdateSpectator(data: ev.EventScoreUpdate) function matchEndSpectator(data: ev.EventMatchEnd) { console.log("matchEndSpectator"); - matchEnded = true; + gameState.matchEnded = true; socket.close(); // WIP /* msg.win(); diff --git a/srcs/requirements/svelte/api_front/src/pages/game/shared_js/constants.ts b/srcs/requirements/svelte/api_front/src/pages/game/shared_js/constants.ts index 44c282c2..18713ae4 100644 --- a/srcs/requirements/svelte/api_front/src/pages/game/shared_js/constants.ts +++ b/srcs/requirements/svelte/api_front/src/pages/game/shared_js/constants.ts @@ -26,5 +26,5 @@ export const movingWallPosMax = Math.floor(w*0.12); export const movingWallSpeed = Math.floor(w*0.08); -export const gameSessionIdPLACEHOLDER = "42"; // TESTING SPECTATOR PLACEHOLDER -// for testing, force gameSession.id in wsServer.ts->matchmaking() \ No newline at end of file +export const gameSessionIdPLACEHOLDER = "match-id-test-42"; // TESTING SPECTATOR PLACEHOLDER +// for testing, force gameSession.id in wsServer.ts->createGameSession() diff --git a/srcs/requirements/svelte/api_front/src/pages/game/shared_js/enums.ts b/srcs/requirements/svelte/api_front/src/pages/game/shared_js/enums.ts index b86571e5..6d54e139 100644 --- a/srcs/requirements/svelte/api_front/src/pages/game/shared_js/enums.ts +++ b/srcs/requirements/svelte/api_front/src/pages/game/shared_js/enums.ts @@ -19,6 +19,7 @@ export enum EventTypes { // Client clientAnnounce, clientPlayerReady, + clientSpectatorReady, clientInput, }