serveur de jeu - work in progress

This commit is contained in:
batche
2022-12-14 10:45:10 +01:00
parent 6ca35ccaa7
commit f1f94cb9bc
125 changed files with 3947 additions and 719 deletions

View File

@@ -0,0 +1,212 @@
import * as en from "../../shared_js/enums.js";
import * as ev from "../../shared_js/class/Event.js";
import * as c from "../constants.js";
import { GameComponentsServer } from "./GameComponentsServer.js";
import { clientInputListener } from "../wsServer.js";
import { random } from "../utils.js";
import { wallsMovements } from "../../shared_js/wallsMovement.js";
/*
multiples methods of GameSession have parameter "s: GameSession".
its used with calls to setTimeout(),
because "this" is not equal to the GameSession but to "this: Timeout"
*/
export class GameSession {
constructor(id, matchOptions) {
this.playersMap = new Map();
this.unreadyPlayersMap = new Map();
this.spectatorsMap = new Map();
this.gameLoopInterval = 0;
this.playersUpdateInterval = 0;
this.spectatorsUpdateInterval = 0;
this.matchEnded = false;
this.id = id;
this.matchOptions = matchOptions;
this.components = new GameComponentsServer(this.matchOptions);
}
start() {
const gc = this.components;
setTimeout(this.resume, c.matchStartDelay, this);
let timeout = c.matchStartDelay + c.newRoundDelay;
gc.ballsArr.forEach((ball) => {
setTimeout(this._newRound, timeout, this, ball);
timeout += c.newRoundDelay * 0.5;
});
}
resume(s) {
s.playersMap.forEach((client) => {
client.socket.on("message", clientInputListener);
});
s.actual_time = Date.now();
s.gameLoopInterval = setInterval(s._gameLoop, c.serverGameLoopIntervalMS, s);
s.playersUpdateInterval = setInterval(s._playersUpdate, c.playersUpdateIntervalMS, s);
s.spectatorsUpdateInterval = setInterval(s._spectatorsUpdate, c.spectatorsUpdateIntervalMS, s);
}
pause(s) {
s.playersMap.forEach((client) => {
client.socket.off("message", clientInputListener);
});
clearInterval(s.gameLoopInterval);
clearInterval(s.playersUpdateInterval);
clearInterval(s.spectatorsUpdateInterval);
}
instantInputDebug(client) {
this._handleInput(c.fixedDeltaTime, client);
}
_handleInput(delta, client) {
// if (client.inputBuffer === null) {return;}
const gc = this.components;
const input = client.inputBuffer.input;
if (input === en.InputEnum.up) {
client.racket.dir.y = -1;
}
else if (input === en.InputEnum.down) {
client.racket.dir.y = 1;
}
if (input !== en.InputEnum.noInput) {
client.racket.moveAndCollide(delta, [gc.wallTop, gc.wallBottom]);
}
client.lastInputId = client.inputBuffer.id;
// client.inputBuffer = null;
}
_gameLoop(s) {
/* s.last_time = s.actual_time;
s.actual_time = Date.now();
s.delta_time = (s.actual_time - s.last_time) / 1000; */
s.delta_time = c.fixedDeltaTime;
// WIP, replaced by instantInputDebug() to prevent desynchro
/* s.playersMap.forEach( (client) => {
s._handleInput(s.delta_time, client);
}); */
const gc = s.components;
gc.ballsArr.forEach((ball) => {
s._ballMovement(s.delta_time, ball);
});
if (s.matchOptions & en.MatchOptions.movingWalls) {
wallsMovements(s.delta_time, gc);
}
}
_ballMovement(delta, ball) {
const gc = this.components;
if (ball.ballInPlay) {
ball.moveAndBounce(delta, [gc.wallTop, gc.wallBottom, gc.playerLeft, gc.playerRight]);
if (ball.pos.x > c.w
|| ball.pos.x < 0 - ball.width) {
ball.ballInPlay = false;
if (this.matchEnded) {
return;
}
this._scoreUpdate(ball);
setTimeout(this._newRound, c.newRoundDelay, this, ball);
}
}
}
_scoreUpdate(ball) {
const gc = this.components;
if (ball.pos.x > c.w) {
++gc.scoreLeft;
}
else if (ball.pos.x < 0 - ball.width) {
++gc.scoreRight;
}
this.playersMap.forEach((client) => {
client.socket.send(JSON.stringify(new ev.EventScoreUpdate(gc.scoreLeft, gc.scoreRight)));
});
this.spectatorsMap.forEach((client) => {
client.socket.send(JSON.stringify(new ev.EventScoreUpdate(gc.scoreLeft, gc.scoreRight)));
});
}
_playersUpdate(s) {
const gameState = s._gameStateSnapshot();
s.playersMap.forEach((client) => {
gameState.lastInputId = client.lastInputId;
client.socket.send(JSON.stringify(gameState));
});
}
_spectatorsUpdate(s) {
const gameState = s._gameStateSnapshot();
s.spectatorsMap.forEach((client) => {
client.socket.send(JSON.stringify(gameState));
});
}
_gameStateSnapshot() {
const gc = this.components;
const snapshot = new ev.EventGameUpdate();
snapshot.playerLeft.y = gc.playerLeft.pos.y;
snapshot.playerRight.y = gc.playerRight.pos.y;
gc.ballsArr.forEach((ball) => {
snapshot.ballsArr.push({
x: ball.pos.x,
y: ball.pos.y,
dirX: ball.dir.x,
dirY: ball.dir.y,
speed: ball.speed
});
});
if (this.matchOptions & en.MatchOptions.movingWalls) {
snapshot.wallTop.y = gc.wallTop.pos.y;
snapshot.wallBottom.y = gc.wallBottom.pos.y;
}
return (snapshot);
}
_newRound(s, ball) {
if (s._checkDisconnexions()) {
return;
}
// https://fr.wikipedia.org/wiki/Tennis_de_table#Nombre_de_manches
const gc = s.components;
const minScore = 11; // can be changed for testing
if (gc.scoreLeft >= minScore || gc.scoreRight >= minScore) {
if (Math.abs(gc.scoreLeft - gc.scoreRight) >= 2) {
s._matchEnd(s);
return;
}
}
ball.pos.x = c.w_mid;
ball.pos.y = random(c.h * 0.3, c.h * 0.7);
ball.speed = ball.baseSpeed;
ball.ballInPlay = true;
}
_checkDisconnexions() {
if (this.playersMap.size !== 2) {
this.matchEnded = true;
if (this.playersMap.size != 0) {
const gc = this.components;
const luckyWinner = this.playersMap.values().next().value;
let eventEnd;
if (luckyWinner.racket === gc.playerLeft) {
eventEnd = new ev.EventMatchEnd(en.PlayerSide.left, true);
console.log("Player Left WIN (by forfeit)");
}
else {
eventEnd = new ev.EventMatchEnd(en.PlayerSide.right, true);
console.log("Player Right WIN (by forfeit)");
}
luckyWinner.socket.send(JSON.stringify(eventEnd));
this.spectatorsMap.forEach((client) => {
client.socket.send(JSON.stringify(eventEnd));
});
}
return true;
}
return false;
}
_matchEnd(s) {
s.matchEnded = true;
const gc = s.components;
let eventEnd;
if (gc.scoreLeft > gc.scoreRight) {
eventEnd = new ev.EventMatchEnd(en.PlayerSide.left);
console.log("Player Left WIN");
}
else {
eventEnd = new ev.EventMatchEnd(en.PlayerSide.right);
console.log("Player Right WIN");
}
s.playersMap.forEach((client) => {
client.socket.send(JSON.stringify(eventEnd));
});
s.spectatorsMap.forEach((client) => {
client.socket.send(JSON.stringify(eventEnd));
});
}
}