bugfix with countdown() on early pong.destroy call
+ svelte reactivity with forfeit button + little matchmaking changes + Wip audio rework
This commit is contained in:
@@ -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",
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
|
||||
@@ -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 @@
|
||||
<canvas id={gameAreaId}/>
|
||||
</div>
|
||||
{#if !hiddenGame}
|
||||
<div id="div_game">
|
||||
<button id="pong_button" on:click={leaveMatch}>forfeit</button>
|
||||
</div>
|
||||
{#if !hiddenGame && gameState.matchStarted && !gameState.matchEnded}
|
||||
<div id="div_game">
|
||||
<button id="pong_button" on:click={leaveMatch}>forfeit</button>
|
||||
</div>
|
||||
{:else if !hiddenGame && !gameState.matchStarted}
|
||||
<div id="div_game">
|
||||
<button id="pong_button" on:click={leaveMatch}>leave matchmaking</button>
|
||||
</div>
|
||||
{/if}
|
||||
{/if}
|
||||
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
};
|
||||
|
||||
</script>
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user