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
This commit is contained in:
LuckyLaszlo
2023-01-01 22:13:22 +01:00
parent 941b0ea7ea
commit eae5b70194
21 changed files with 233 additions and 186 deletions

4
.gitignore vendored
View File

@@ -53,3 +53,7 @@ lerna-debug.log*
!.vscode/tasks.json
!.vscode/launch.json
!.vscode/extensions.json
.env
memo.txt

View File

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

View File

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

View File

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

View File

@@ -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<WebSocket>({host: "0.0.0.0", port: wsPort, path: "/pong"});
@@ -23,12 +22,12 @@ const matchmakingMap: Map<string, ClientPlayer> = new Map; // socket.id/ClientPl
const privateMatchmakingMap: Map<string, ClientPlayer> = new Map; // socket.id/ClientPlayer (duplicates with clientsMap)
const gameSessionsMap: Map<string, GameSession> = 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 = <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 = <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));
}

View File

@@ -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()
export const gameSessionIdPLACEHOLDER = "match-id-test-42"; // TESTING SPECTATOR PLACEHOLDER
// for testing, force gameSession.id in wsServer.ts->createGameSession()

View File

@@ -19,6 +19,7 @@ export enum EventTypes {
// Client
clientAnnounce,
clientPlayerReady,
clientSpectatorReady,
clientInput,
}

View File

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

View File

@@ -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}
<div id="game_option">
<form on:submit|preventDefault={() => initGame()}>
<div id="div_game">
<button id="pong_button" on:click={showInvitation}>Show invitations</button>
<fieldset>
<legend>game options</legend>
<div>
<input type="checkbox" id="multi_balls" name="multi_balls" bind:checked={options.multi_balls}>
<label for="multi_balls">Multiples balls</label>
</div>
<div>
<input type="checkbox" id="moving_walls" name="moving_walls" bind:checked={options.moving_walls}>
<label for="moving_walls">Moving walls</label>
</div>
<div>
<p>sound :</p>
<input type="radio" id="sound_on" name="sound_selector" bind:group={options.sound} value="on">
<label for="sound_on">on</label>
<input type="radio" id="sound_off" name="sound_selector" bind:group={options.sound} value="off">
<label for="sound_off">off</label>
</div>
<div>
<input type="checkbox" id="isSomeoneIsInvited" bind:checked={options.isSomeoneIsInvited}>
<label for="moving_walls">Invite a friend</label>
</div>
{#if options.isSomeoneIsInvited === true}
<select bind:value={options.playerTwoUsername}>
{#each allUsers as user }
<option value={user.username}>{user.username}</option>
{/each}
</select>
{/if}
<div>
<button id="pong_button">PLAY</button>
</div>
</fieldset>
</div>
</form>
<div id="div_game">
<button id="pong_button" on:click={showInvitation}>Show invitations</button>
<fieldset>
<legend>game options</legend>
<div>
<input type="checkbox" id="multi_balls" name="multi_balls" bind:checked={options.multi_balls}>
<label for="multi_balls">Multiples balls</label>
</div>
<div>
<input type="checkbox" id="moving_walls" name="moving_walls" bind:checked={options.moving_walls}>
<label for="moving_walls">Moving walls</label>
</div>
<div>
<p>sound :</p>
<input type="radio" id="sound_on" name="sound_selector" bind:group={options.sound} value="on">
<label for="sound_on">on</label>
<input type="radio" id="sound_off" name="sound_selector" bind:group={options.sound} value="off">
<label for="sound_off">off</label>
</div>
<div>
<input type="checkbox" id="isSomeoneIsInvited" bind:checked={options.isSomeoneIsInvited}>
<label for="moving_walls">Invite a friend</label>
</div>
{#if options.isSomeoneIsInvited === true}
<select bind:value={options.playerTwoUsername}>
{#each allUsers as user }
<option value={user.username}>{user.username}</option>
{/each}
</select>
{/if}
<div>
<button id="pong_button" on:click={initGame}>PLAY</button>
</div>
</fieldset>
</div>
</div>
{/if}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -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()
export const gameSessionIdPLACEHOLDER = "match-id-test-42"; // TESTING SPECTATOR PLACEHOLDER
// for testing, force gameSession.id in wsServer.ts->createGameSession()

View File

@@ -19,6 +19,7 @@ export enum EventTypes {
// Client
clientAnnounce,
clientPlayerReady,
clientSpectatorReady,
clientInput,
}