[wip] wip routes for paused games

This commit is contained in:
bgoulard 2026-01-09 15:21:10 +01:00 committed by Maix0
parent 2195207297
commit 9f9eea9525
4 changed files with 135 additions and 3 deletions

View file

@ -132,7 +132,7 @@ export class Pong {
public sendSig : boolean = false;
public ready_checks: [boolean, boolean] = [false, false];
public game_creation : number = Date.now();
public rdy_timer : number = Date.now(); // init rdy timer from class creation start
public score: [number, number] = [0, 0];
public local: boolean = false;
@ -282,7 +282,7 @@ export class Pong {
if (this.score[LEFT] >= 5) return 'left';
if (this.score[RIGHT] >= 5) return 'right';
if (this.local !== true && this.game_creation !== -1 && Date.now() - this.game_creation > Pong.CONCEDED_TIMEOUT * 10 && (!this.ready_checks[0] || !this.ready_checks[1])) {
if (this.local !== true && this.rdy_timer !== -1 && Date.now() - this.rdy_timer > Pong.CONCEDED_TIMEOUT * 10 && (!this.ready_checks[0] || !this.ready_checks[1])) {
if (!this.ready_checks[0] && !this.ready_checks[1]) return (randomInt(1) == 1 ? 'left' : 'right');
if (!this.ready_checks[0]) return ('right');
if (!this.ready_checks[1]) return ('left');

View file

@ -0,0 +1,48 @@
import { isNullish, MakeStaticResponse, typeResponse } from "@shared/utils";
import { FastifyPluginAsync } from "fastify";
import { Static, Type } from "typebox";
import { State } from "../state";
import { UserId } from "@shared/database/mixin/user";
// need: pongPausedParam -> uid1 uid2
// resp -> game_uid | ?error
//
// q - why does 'type PongHistoryResponse = MakeStaticResponse<typeof PongHistoryResponse>' why makestatic response?
// required to game create -> uid1+2
const CreatePausedGameParam = Type.Object({
user1: Type.String({ description: '\'id\' | <userid>' }),
user2: Type.String({ description: '\'id\' | <userid>' }),
});
type CreatePausedGameParam = Static<typeof CreatePausedGameParam>;
const CreatePausedGameResponse = {
'200': typeResponse('success', 'createPausedGame.success', {
gameId: Type.String({ description: 'gameId' }),
}),
'404': typeResponse('failure', 'createPausedGame.generic.fail')
}
type CreatePausedGameResponse = MakeStaticResponse<typeof CreatePausedGameResponse>;
const route: FastifyPluginAsync = async (fastify): Promise<void> => {
fastify.post<{ Body: CreatePausedGameParam }>(
'/createPausedGame',
{
schema: {
body: CreatePausedGameParam,
response: CreatePausedGameResponse,
operationId: 'pongCreatePauseGame',
},
},
async function (req, res) {
let resp = State.newPausedGame(req.body.user1 as UserId, req.body.user2 as UserId);
if (isNullish(resp)) { return (res.makeResponse(404, 'failure', 'createPausedGame.generic.fail')) }
// else
return (res.makeResponse(200, 'success', 'createPausedGame.success'));
}
)
};
export default route;

View file

@ -0,0 +1,39 @@
import { MakeStaticResponse, typeResponse } from "@shared/utils";
import { FastifyPluginAsync } from "fastify";
import Type, { Static } from "typebox";
import { State } from "../state";
import { PongGameId } from "@shared/database/mixin/pong";
const startPausedGameParam = Type.Object({
gameId: Type.String({ description: '\'id\' | <gameid>' }),
});
type startPausedGameParam = Static<typeof startPausedGameParam>;
const startPausedGameResponse = {
'200': typeResponse('success', 'startPausedGame.success', {}),
'404': typeResponse('failure', 'startPausedGame.no_such_game')
}
type startPausedGameResponse = MakeStaticResponse<typeof startPausedGameResponse>;
const route: FastifyPluginAsync = async (fastify): Promise<void> => {
fastify.post<{ Body: startPausedGameParam }>(
'/startPausedGame',
{
schema: {
body: startPausedGameParam,
response: startPausedGameResponse,
operationId: 'pongstartPauseGame',
},
},
async function (req, res) {
let resp = State.startPausedGame(req.body.gameId as PongGameId);
if (resp !== true) { return (res.makeResponse(404, 'failure', 'startPausedGame.generic.fail')) }
// else
return (res.makeResponse(200, 'success', 'startPausedGame.success'));
}
)
};
export default route;

View file

@ -103,6 +103,52 @@ class StateI {
this.tournament.start();
}
public newPausedGame(suid1 : string, suid2 : string) : GameId | undefined {
if (!this.users.has(suid1 as UserId) || !this.users.has(suid2 as UserId))
return (undefined);
const uid1 : UserId = suid1 as UserId;
const uid2 : UserId = suid2 as UserId;
const g = new Pong(uid1, uid2);
g.rdy_timer = -1;
const gameId = newUUID() as unknown as GameId;
this.games.set(gameId, g);
return (gameId);
}
public startPausedGame(g_id: PongGameId) : boolean {
let game : Pong | undefined;
if (!this.games.has(g_id) || (game = this.games.get(g_id)) === undefined) { return (false); }
game.rdy_timer = Date.now();
let id1 = game.userLeft;
let id2 = game.userRight;
if (!this.users.has(id1) || !this.users.has(id2)) { return (false); }
let usr1 = this.users.get(id1);
let usr2 = this.users.get(id2);
if (isNullish(usr1) || isNullish(usr2)) { return (false); }
const iState: GameUpdate = StateI.getGameUpdateData(g_id, game);
usr1.socket.emit('newGame', iState); usr1.currentGame = g_id;
usr2.socket.emit('newGame', iState); usr2.currentGame = g_id;
game.gameUpdate = setInterval(() => {
game.tick();
if (game.sendSig === false && game.ready_checks[0] === true && game.ready_checks[1] === true) {
usr1.socket.emit('rdyEnd');
usr2.socket.emit('rdyEnd');
game.sendSig = true;
}
if (game.ready_checks[0] === true && game.ready_checks[1] === true) {
this.gameUpdate(g_id, usr1.socket);
this.gameUpdate(g_id, usr2.socket);
}
if (game.checkWinner() !== null) {this.cleanupGame(g_id, game); }
}, 1000 / StateI.UPDATE_INTERVAL_FRAMES);
return (true);
}
private queuerFunction(): void {
const values = Array.from(this.queue.values());
shuffle(values);
@ -308,7 +354,6 @@ class StateI {
}
}
private enqueueUser(socket: SSocket): void {
if (!this.users.has(socket.authUser.id)) return;