bugfix with countdown() on early pong.destroy call

+ svelte reactivity with forfeit button
+ little matchmaking changes
+ Wip audio rework
This commit is contained in:
LuckyLaszlo
2023-01-05 20:18:59 +01:00
parent b35082148c
commit 68ae8ac333
11 changed files with 117 additions and 114 deletions

View File

@@ -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",

View File

@@ -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);

View File

@@ -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

View File

@@ -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}

View File

@@ -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>

View File

@@ -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;
}

View File

@@ -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) {

View File

@@ -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();
}

View File

@@ -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()

View File

@@ -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;
}

View File

@@ -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;