From 68ae8ac333f6599911f06fce40deafac0eacd288 Mon Sep 17 00:00:00 2001 From: LuckyLaszlo Date: Thu, 5 Jan 2023 20:18:59 +0100 Subject: [PATCH] bugfix with countdown() on early pong.destroy call + svelte reactivity with forfeit button + little matchmaking changes + Wip audio rework --- .../game_back/src/server/class/GameSession.ts | 15 +++---- .../game_back/src/server/wsServer.ts | 21 +++++++-- srcs/requirements/nestjs/api_back/.env | 22 --------- .../api_front/src/pages/game/Game.svelte | 45 ++++++++++++------- .../src/pages/game/GameSpectator.svelte | 39 ++-------------- .../api_front/src/pages/game/client/audio.ts | 12 ++--- .../src/pages/game/client/class/GameArea.ts | 1 + .../api_front/src/pages/game/client/init.ts | 29 ++++++++---- .../api_front/src/pages/game/client/pong.ts | 10 +++-- .../api_front/src/pages/game/client/utils.ts | 27 +++++++---- .../api_front/src/pages/game/client/ws.ts | 10 +++-- 11 files changed, 117 insertions(+), 114 deletions(-) delete mode 100644 srcs/requirements/nestjs/api_back/.env 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 24988b86..4a4446ac 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 @@ -250,10 +250,10 @@ export class GameSession { } } - private async _matchEnd(winner: en.PlayerSide, forfeit_flag: boolean = false) + private async _matchEnd(winner: en.PlayerSide, forfeitFlag: boolean = false) { this.matchEnded = true; - const eventEnd = new ev.EventMatchEnd(winner, forfeit_flag); + const eventEnd = new ev.EventMatchEnd(winner, forfeitFlag); this.playersMap.forEach( (client) => { client.socket.send(JSON.stringify(eventEnd)); }); @@ -261,19 +261,18 @@ 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; console.log("================================= MATCH ENDED"); - if (forfeit_flag) { + if (forfeitFlag) { if (winner === en.PlayerSide.left) { - gc.scoreLeft = 3 - gc.scoreRight = 0 + gc.scoreLeft = 3; + gc.scoreRight = 0; } else { - gc.scoreLeft = 0 - gc.scoreRight = 3 + gc.scoreLeft = 0; + gc.scoreRight = 3; } } 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 99fc6597..d3bab3d2 100644 --- a/srcs/requirements/game_server/game_back/src/server/wsServer.ts +++ b/srcs/requirements/game_server/game_back/src/server/wsServer.ts @@ -150,10 +150,10 @@ function publicMatchmaking(player: ClientPlayer) { const minPlayersNumber = 2; const maxPlayersNumber = 2; - matchmakingMap.set(player.id, player); const matchOptions = player.matchOptions; const compatiblePlayers: ClientPlayer[] = []; + compatiblePlayers.push(player); for (const [id, client] of matchmakingMap) { if (client.matchOptions === matchOptions) @@ -165,12 +165,27 @@ function publicMatchmaking(player: ClientPlayer) } } + // TODO: Replace with this code to disable the possibility to play against self +/* for (const [id, client] of matchmakingMap) + { + if (client.matchOptions === matchOptions && client.username !== player.username) + { + compatiblePlayers.push(client); + if (compatiblePlayers.length === maxPlayersNumber) { + break; + } + } + } */ + if (compatiblePlayers.length >= minPlayersNumber) { compatiblePlayers.forEach((client) => { matchmakingMap.delete(client.id); }); createGameSession(compatiblePlayers, matchOptions); } + else { + matchmakingMap.set(player.id, player); + } } @@ -178,11 +193,11 @@ function privateMatchmaking(player: ClientPlayer) { const minPlayersNumber = 2; const maxPlayersNumber = 2; - privateMatchmakingMap.set(player.id, player); const matchOptions = player.matchOptions; const token = player.token; const compatiblePlayers: ClientPlayer[] = []; + compatiblePlayers.push(player); for (const [id, client] of privateMatchmakingMap) { if (client.token === token) @@ -202,6 +217,7 @@ function privateMatchmaking(player: ClientPlayer) } else { + privateMatchmakingMap.set(player.id, player); setTimeout(async function abortMatch() { if (!player.gameSession) { @@ -226,7 +242,6 @@ function privateMatchmaking(player: ClientPlayer) function createGameSession(playersArr: ClientPlayer[], matchOptions: en.MatchOptions) { - // const id = c.gameSessionIdPLACEHOLDER; // Force ID, TESTING SPECTATOR const id = uuidv4(); const gameSession = new GameSession(id, matchOptions); gameSessionsMap.set(id, gameSession); diff --git a/srcs/requirements/nestjs/api_back/.env b/srcs/requirements/nestjs/api_back/.env deleted file mode 100644 index ed44998b..00000000 --- a/srcs/requirements/nestjs/api_back/.env +++ /dev/null @@ -1,22 +0,0 @@ -NODE_ENV=development -POSTGRES_HOST=postgresql -POSTGRES_PORT=5432 -POSTGRES_USERNAME=postgres -POSTGRES_PASSWORD=9pKpKEgiamxwk5P7Ggsz -POSTGRES_DATABASE=transcendance_db - -# OAUTH2 42 API -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=248cdc831110eec8796d7c1edbf79835 -# JWT -JWT_SECRET=442d774798979fcc14a4a2b6b7535902 -# Misc -PORT=3000 -#Redis -REDIS_HOST=redis -REDIS_PORT=6379 -REDIS_PASSWORD=1a5e04138b91b3d683c708e4689454c2 -#2fa -TWO_FACTOR_AUTHENTICATION_APP_NAME=Transcendance 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 94fd84df..89200706 100644 --- a/srcs/requirements/svelte/api_front/src/pages/game/Game.svelte +++ b/srcs/requirements/svelte/api_front/src/pages/game/Game.svelte @@ -30,9 +30,10 @@ let isThereAnyInvitation = false; let invitations = []; - let waitingMessage = "Please wait..." + let waitingMessage = "Please wait..."; let errorMessageWhenAttemptingToGetATicket = ""; - let idOfIntevalCheckTerminationOfTheMatch; + let watchGameStateInterval; + const watchGameStateIntervalRate = 142; onMount( async() => { user = await fetch(`http://${process.env.WEBSITE_HOST}:${process.env.WEBSITE_PORT}/api/v2/user`) @@ -43,7 +44,7 @@ }) onDestroy( async() => { - clearInterval(idOfIntevalCheckTerminationOfTheMatch); + clearInterval(watchGameStateInterval); pong.destroy(); }) @@ -84,7 +85,7 @@ } else if (token) { - idOfIntevalCheckTerminationOfTheMatch = setInterval(matchTermitation, 1000); + watchGameStateInterval = setInterval(watchGameState, watchGameStateIntervalRate); // options.isInvitedPerson = false // ??? pong.init(options, gameAreaId, token); hiddenGame = false; @@ -101,7 +102,7 @@ console.log(invitation) if (invitation.token) { - idOfIntevalCheckTerminationOfTheMatch = setInterval(matchTermitation, 1000); + watchGameStateInterval = setInterval(watchGameState, watchGameStateIntervalRate); options.playerOneUsername = invitation.playerOneUsername; options.playerTwoUsername = invitation.playerTwoUsername; options.isSomeoneIsInvited = true; @@ -112,23 +113,28 @@ } } - const matchTermitation = () => { - console.log("Ping matchTermitation") - if (gameState.matchAbort || gameState.matchEnded) + const watchGameState = () => { + console.log("watchGameState") + if (gameState) { // trigger Svelte reactivity + gameState.matchStarted = gameState.matchStarted; + gameState.matchEnded = gameState.matchEnded; + gameState.matchAborted = gameState.matchAborted; + } + if (gameState.matchAborted || gameState.matchEnded) { - clearInterval(idOfIntevalCheckTerminationOfTheMatch); - console.log("matchTermitation was called") + clearInterval(watchGameStateInterval); + console.log("watchGameState, end") showWaitPage = false - gameState.matchAbort ? + gameState.matchAborted ? errorMessageWhenAttemptingToGetATicket = "The match has been aborted" : errorMessageWhenAttemptingToGetATicket = "The match is finished !" - gameState.matchAbort ? showError = true : showMatchEnded = true; + gameState.matchAborted ? showError = true : showMatchEnded = true; setTimeout(() => { resetPage(); errorMessageWhenAttemptingToGetATicket = ""; isThereAnyInvitation = false; invitations = []; // ??? - console.log("matchTermitation : setTimeout") + console.log("watchGameState : setTimeout") }, 5000); } } @@ -183,6 +189,7 @@ } function leaveMatch() { + clearInterval(watchGameStateInterval); resetPage(); }; @@ -221,9 +228,15 @@ {#if !hiddenGame} -
- -
+ {#if !hiddenGame && gameState.matchStarted && !gameState.matchEnded} +
+ +
+ {:else if !hiddenGame && !gameState.matchStarted} +
+ +
+ {/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 1ed3186e..5365ff0e 100644 --- a/srcs/requirements/svelte/api_front/src/pages/game/GameSpectator.svelte +++ b/srcs/requirements/svelte/api_front/src/pages/game/GameSpectator.svelte @@ -8,7 +8,6 @@ import * as pongSpectator from "./client/pongSpectator"; import { gameState } from "./client/ws"; - import { gameSessionIdPLACEHOLDER } from "./shared_js/constants"; //user's stuff let user; @@ -17,32 +16,6 @@ //Game's stuff client side only const gameAreaId = "game_area"; let sound = "off"; - // const dummyMatchList = [ - // { - // 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, - // playerOneUsername: "bertand", - // playerTwoUsername: "cassandre", - // }, - // { - // gameSessionId: "id3452", - // matchOptions: pongSpectator.MatchOptions.multiBalls, - // playerOneUsername: "madeleine", - // playerTwoUsername: "jack", - // }, - // ]; let matchList = []; //html boolean for pages @@ -55,14 +28,12 @@ .then( x => x.json() ); allUsers = await fetch(`http://${process.env.WEBSITE_HOST}:${process.env.WEBSITE_PORT}/api/v2/user/all`) .then( x => x.json() ); - // WIP: fetch for match list here const responseForMatchList = await fetch(`http://${process.env.WEBSITE_HOST}:${process.env.WEBSITE_PORT}/api/v2/game/match/all`) const jsonForMatchList = await responseForMatchList.json(); matchList = jsonForMatchList; - console.log("matchList"); - if (matchList.length <= 0) + if (matchList.length <= 0) { hiddenMatchList = true; - console.log(matchList); + } }) onDestroy( async() => { @@ -81,13 +52,11 @@ async function resetPage() { hiddenGame = true; pongSpectator.destroy(); - // WIP: fetch for match list here matchList = await fetch(`http://${process.env.WEBSITE_HOST}:${process.env.WEBSITE_PORT}/api/v2/game/match/all`) .then( x => x.json() ); - console.log("matchList"); - if (matchList.length <= 0) + if (matchList.length <= 0) { hiddenMatchList = true; - console.log(matchList); + } }; 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 a3754446..49cc0482 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 @@ -2,11 +2,8 @@ import * as c from "./constants.js" // export const soundPongArr: HTMLAudioElement[] = []; -export const soundPongArr: HTMLAudioElement[] = [ - new Audio("http://" + process.env.WEBSITE_HOST + ":" + process.env.WEBSITE_PORT + "/sound/pong/"+1+".ogg"), - new Audio("http://" + process.env.WEBSITE_HOST + ":" + process.env.WEBSITE_PORT + "/sound/pong/"+2+".ogg") -]; -export const soundRoblox = new Audio("http://" + process.env.WEBSITE_HOST + ":" + process.env.WEBSITE_PORT + "/sound/roblox-oof.ogg"); +export const soundPongArr: HTMLAudioElement[] = []; +export let soundRoblox: HTMLAudioElement; export function initAudio(sound: string) { @@ -18,10 +15,15 @@ export function initAudio(sound: string) muteFlag = true; } + soundPongArr.length = 0; + soundPongArr.push(new Audio("http://" + process.env.WEBSITE_HOST + ":" + process.env.WEBSITE_PORT + "/sound/pong/"+1+".ogg")); + soundPongArr.push(new Audio("http://" + process.env.WEBSITE_HOST + ":" + process.env.WEBSITE_PORT + "/sound/pong/"+2+".ogg")); soundPongArr.forEach((value) => { value.volume = c.soundRobloxVolume; value.muted = muteFlag; }); + + soundRoblox = new Audio("http://" + process.env.WEBSITE_HOST + ":" + process.env.WEBSITE_PORT + "/sound/roblox-oof.ogg"); soundRoblox.volume = c.soundRobloxVolume; soundRoblox.muted = muteFlag; } diff --git a/srcs/requirements/svelte/api_front/src/pages/game/client/class/GameArea.ts b/srcs/requirements/svelte/api_front/src/pages/game/client/class/GameArea.ts index 9b90d4e5..833fd9c6 100644 --- a/srcs/requirements/svelte/api_front/src/pages/game/client/class/GameArea.ts +++ b/srcs/requirements/svelte/api_front/src/pages/game/client/class/GameArea.ts @@ -6,6 +6,7 @@ export class GameArea { handleInputInterval: number = 0; gameLoopInterval: number = 0; drawLoopInterval: number = 0; + timeoutArr: number[] = []; canvas: HTMLCanvasElement; ctx: CanvasRenderingContext2D; constructor(canvas_id: string) { 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 76051ef6..863ebdbd 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 @@ -34,15 +34,28 @@ export function initBase(matchOptions: en.MatchOptions, sound: string, gameAreaI export function destroyBase() { - if (pong) - { - clearInterval(pong.handleInputInterval); - clearInterval(pong.gameLoopInterval); - clearInterval(pong.drawLoopInterval); - setPong(null); - } - if (socket && socket.OPEN) { + if (socket && (socket.OPEN || socket.CONNECTING)) { socket.close(); } + if (pong) + { + pong.timeoutArr.forEach((value) => { + clearTimeout(value); + }); + pong.timeoutArr = []; + + clearInterval(pong.handleInputInterval); + pong.handleInputInterval = null; + + clearInterval(pong.gameLoopInterval); + pong.gameLoopInterval = null; + + clearInterval(pong.drawLoopInterval); + pong.drawLoopInterval = null; + + setPong(null); + } + setGc(null); + setMatchOptions(null); 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 39de4995..7667a322 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 @@ -4,7 +4,7 @@ import { handleInput } from "./handleInput.js"; import { gameLoop } from "./gameLoop.js" import { drawLoop } from "./draw.js"; import { countdown } from "./utils.js"; -import { initWebSocket } from "./ws.js"; +import { gameState, initWebSocket } from "./ws.js"; import type { InitOptions } from "./class/InitOptions.js"; export { InitOptions } from "./class/InitOptions.js"; import { initBase, destroyBase, computeMatchOptions } from "./init.js"; @@ -47,11 +47,12 @@ export function destroy() function start() { gc.text1.pos.assign(c.w*0.5, c.h*0.75); - countdown(c.matchStartDelay/1000, (count: number) => { + const countdownArr = countdown(c.matchStartDelay, 1000, (count: number) => { gc.text1.clear(); - gc.text1.text = `${count}`; + gc.text1.text = `${count/1000}`; gc.text1.update(); }, start_after_countdown); + pong.timeoutArr = pong.timeoutArr.concat(countdownArr); } function start_after_countdown() @@ -66,11 +67,12 @@ function start_after_countdown() abortControllerKeyup = new AbortController(); window.addEventListener( 'keyup', - (e) => { pong.deleteKey(e.key);}, + (e) => { pong.deleteKey(e.key); }, {signal: abortControllerKeyup.signal} ); resume(); + gameState.matchStarted = true; } function resume() diff --git a/srcs/requirements/svelte/api_front/src/pages/game/client/utils.ts b/srcs/requirements/svelte/api_front/src/pages/game/client/utils.ts index ff45234d..daa2393e 100644 --- a/srcs/requirements/svelte/api_front/src/pages/game/client/utils.ts +++ b/srcs/requirements/svelte/api_front/src/pages/game/client/utils.ts @@ -1,16 +1,25 @@ export * from "../shared_js/utils.js" -export function countdown(count: number, callback?: (count: number) => void, endCallback?: () => void) +export function countdown(count: number, step: number, callback: (count: number) => void, endCallback?: () => void) : number[] { - console.log("countdown ", count); - if (count > 0) { - if (callback) { + const timeoutArr: number[] = []; + + if (endCallback) { + timeoutArr.push( window.setTimeout(endCallback, count) ); + } + + let reverseCount = 0; + while (count > 0) + { + timeoutArr.push( window.setTimeout((count: number) => { + console.log("countdown ", count); callback(count); - } - setTimeout(countdown, 1000, --count, callback, endCallback); - } - else if (endCallback) { - endCallback(); + }, reverseCount, count) + ); + count -= step; + reverseCount += step; } + + return timeoutArr; } 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 95222dc7..99c17dd9 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 @@ -11,13 +11,15 @@ import { sleep } from "./utils.js"; import { Vector, VectorInteger } from "../shared_js/class/Vector.js"; export const gameState = { + matchStarted: false, matchEnded: false, - matchAbort: false + matchAborted: false } export function resetGameState() { + gameState.matchStarted = false; gameState.matchEnded = false; - gameState.matchAbort = false; + gameState.matchAborted = false; } class ClientInfo { @@ -36,7 +38,7 @@ class ClientInfoSpectator { } const wsUrl = "ws://" + process.env.WEBSITE_HOST + ":" + process.env.WEBSITE_PORT + "/pong"; -export let socket: WebSocket; /* TODO: A way to still use "const" not "let" ? */ +export let socket: WebSocket; export const clientInfo = new ClientInfo(); export const clientInfoSpectator = new ClientInfoSpectator(); // WIP, could refactor this @@ -104,7 +106,7 @@ function preMatchListener(this: WebSocket, event: MessageEvent) startFunction(); break; case en.EventTypes.matchAbort: - gameState.matchAbort = true; + gameState.matchAborted = true; socket.removeEventListener("message", preMatchListener); msg.matchAbort(); break;