This commit is contained in:
Jose Conde 2024-07-16 19:21:35 +02:00
parent 97b490c058
commit 2b54efb604
10 changed files with 73 additions and 47 deletions

View File

@ -219,7 +219,9 @@ export class DominoesGame extends EventEmitter {
isTied: this.gameTied, isTied: this.gameTied,
winner: this.winner?.getState(true), winner: this.winner?.getState(true),
score: this.players.map(player => ({id: player.id, name: player.name, score: player.score})), score: this.players.map(player => ({id: player.id, name: player.name, score: player.score})),
players: this.players.map(player => player.getState(true)) players: this.players.map(player => player.getState(true)),
board: this.board.tiles.map(tile => tile.getState(true)),
boneyard: this.board.boneyard.map(tile => tile.getState(true)),
} }
this.emit('game-over', summary); this.emit('game-over', summary);
} }

View File

@ -6,10 +6,11 @@ import { getRandomSeed, uuid, wait, whileNot } from "../common/utilities";
import { MatchSessionState } from "./dto/MatchSessionState"; import { MatchSessionState } from "./dto/MatchSessionState";
import { PlayerNotificationService } from '../server/services/PlayerNotificationService'; import { PlayerNotificationService } from '../server/services/PlayerNotificationService';
import seedrandom, { PRNG } from "seedrandom"; import seedrandom, { PRNG } from "seedrandom";
import { NetworkPlayer } from "./entities/player/NetworkPlayer";
import { PlayerHuman } from "./entities/player/PlayerHuman"; import { PlayerHuman } from "./entities/player/PlayerHuman";
import { GameSummary } from "./dto/GameSummary"; import { GameSummary } from "./dto/GameSummary";
import { PlayerMove } from "./entities/PlayerMove"; import { PlayerMove } from "./entities/PlayerMove";
import { SessionService } from "../server/services/SessionService";
import { Score } from "../server/db/interfaces";
export class MatchSession { export class MatchSession {
@ -23,6 +24,7 @@ export class MatchSession {
private winnerIndex: number | null = null; private winnerIndex: number | null = null;
private clientsReady: string[] = []; private clientsReady: string[] = [];
private gameSummaries: GameSummary[] = []; private gameSummaries: GameSummary[] = [];
private sessionService: SessionService = new SessionService();
id: string; id: string;
matchInProgress: boolean = false; matchInProgress: boolean = false;
@ -148,22 +150,26 @@ export class MatchSession {
this.setScores(gameSummary || undefined); this.setScores(gameSummary || undefined);
this.checkMatchWinner(); this.checkMatchWinner();
this.resetPlayers(); this.resetPlayers();
if (!this.matchInProgress) { try {
this.status = 'end' if (!this.matchInProgress) {
this.notificationService.sendEventToPlayers('server:match-finished', this.players, { this.status = 'end'
lastGame: gameSummary, this.notificationService.sendEventToPlayers('server:match-finished', this.players, {
sessionState: this.getState(true), lastGame: gameSummary,
}); sessionState: this.getState(true),
} else { });
this.status = 'waiting' } else {
// await this.playerNotificationManager.notifyMatchState(this); this.status = 'waiting'
this.notificationService.sendEventToPlayers('server:game-finished', this.players, { // await this.playerNotificationManager.notifyMatchState(this);
lastGame: gameSummary, this.notificationService.sendEventToPlayers('server:game-finished', this.players, {
sessionState: this.getState(true) lastGame: gameSummary,
}); sessionState: this.getState(true)
this.waitingForPlayers = true; });
this.startGame(); this.waitingForPlayers = true;
} this.startGame();
}
} finally {
this.sessionService.updateSession(this);
}
} }
private startGame() { private startGame() {
@ -327,11 +333,11 @@ export class MatchSession {
}; };
} }
getScoreBoardState() { getScoreBoardState(): Score[] {
return Array.from(this.scoreboard).map(([name, score]) => { return Array.from(this.scoreboard).map(([name, score]) => {
const player = this.players.find(player => player.name === name); const player = this.players.find(player => player.name === name);
const id = player?.id || name; const id = player?.id || name;
return { id, name, score }; return { id, name, score } as Score;
}); });
} }
} }

View File

@ -1,10 +1,13 @@
import { PlayerDto } from "./PlayerDto"; import { Score } from "../../server/db/interfaces";
import { PlayerDto, TileDto } from "./PlayerDto";
export interface GameSummary { export interface GameSummary {
gameId: string; gameId: string;
isBlocked: boolean; isBlocked: boolean;
isTied: boolean; isTied: boolean;
winner: PlayerDto; winner: PlayerDto;
score: { id: string, name: string; score: number; }[], score: Score[],
players?: PlayerDto[]; players?: PlayerDto[];
board: TileDto[]
boneyard: TileDto[]
} }

View File

@ -1,3 +1,4 @@
import { Score } from "../../server/db/interfaces";
import { GameSummary } from "./GameSummary"; import { GameSummary } from "./GameSummary";
import { PlayerDto } from "./PlayerDto"; import { PlayerDto } from "./PlayerDto";
@ -15,7 +16,7 @@ export interface MatchSessionState {
maxPlayers: number; maxPlayers: number;
numPlayers: number; numPlayers: number;
waitingSeconds: number; waitingSeconds: number;
scoreboard: { id: string, name: string; score: number; }[]; scoreboard: Score[];
matchWinner: PlayerDto | null; matchWinner: PlayerDto | null;
matchInProgress: boolean; matchInProgress: boolean;
playersReady: number, playersReady: number,

View File

@ -13,4 +13,5 @@ export interface PlayerDto {
hand?: TileDto[]; hand?: TileDto[];
teamedWith?: PlayerDto | null; teamedWith?: PlayerDto | null;
ready: boolean; ready: boolean;
isHuman: boolean;
} }

View File

@ -7,6 +7,7 @@ import { EventEmitter } from "stream";
import { PlayerInteractionInterface } from "../../PlayerInteractionInterface"; import { PlayerInteractionInterface } from "../../PlayerInteractionInterface";
import { uuid } from "../../../common/utilities"; import { uuid } from "../../../common/utilities";
import { PlayerDto, TileDto } from "../../dto/PlayerDto"; import { PlayerDto, TileDto } from "../../dto/PlayerDto";
import { PlayerHuman } from "./PlayerHuman";
export abstract class AbstractPlayer extends EventEmitter implements PlayerInterface { export abstract class AbstractPlayer extends EventEmitter implements PlayerInterface {
hand: Tile[] = []; hand: Tile[] = [];
@ -59,6 +60,7 @@ export abstract class AbstractPlayer extends EventEmitter implements PlayerInter
hand: this.hand.map(tile => tile.getState(showPips)), hand: this.hand.map(tile => tile.getState(showPips)),
teamedWith: this.teamedWith?.getState(showPips) ?? null, teamedWith: this.teamedWith?.getState(showPips) ?? null,
ready: this.ready, ready: this.ready,
isHuman: this instanceof PlayerHuman
}; };
} }
} }

View File

@ -8,8 +8,8 @@ export class GameController extends BaseController {
public async createMatch(req: Request, res: Response) { public async createMatch(req: Request, res: Response) {
try { try {
const { user, body } = req; const { user, body } = req;
const { sessionName, seed } = body; const { sessionName, seed, options } = body;
const sessionId = await this.sessionService.createSession(user, sessionName, seed); const sessionId = await this.sessionService.createSession(user, sessionName, seed, options);
res.status(201).json({ sessionId }); res.status(201).json({ sessionId });
} catch (error) { } catch (error) {
this.handleError(res, error); this.handleError(res, error);
@ -39,7 +39,7 @@ export class GameController extends BaseController {
public async getMatch(req: Request, res: Response) { public async getMatch(req: Request, res: Response) {
try { try {
const { sessionId } = req.params; const { sessionId } = req.params;
const session = this.sessionService.getSession(sessionId) const session = await this.sessionService.getSession(sessionId)
res.status(200).json(session); res.status(200).json(session);
} catch (error) { } catch (error) {
this.handleError(res, error); this.handleError(res, error);

View File

@ -1,20 +1,23 @@
import { MatchSession } from "../../game/MatchSession"; import { MatchSession } from "../../game/MatchSession";
import { DbMatchSession } from "./interfaces"; import { DbMatchSession } from "./interfaces";
export function matchSessionAdapter(session: MatchSession) : DbMatchSession { export function matchSessionAdapter(session: MatchSession, showPips: boolean = false) : DbMatchSession {
const state = session.getState(showPips);
return { return {
id: session.id, id: state.id,
name: session.name || '', name: state.name || '',
creator: session.creator.id, creator: state.creator,
players: session.players.map(player => player.id), players: state.players,
seed: session.seed, seed: state.seed,
mode: session.mode, mode: state.mode,
pointsToWin: session.pointsToWin, pointsToWin: state.pointsToWin,
maxPlayers: session.maxPlayers, maxPlayers: state.maxPlayers,
numPlayers: session.numPlayers, numPlayers: state.numPlayers,
scoreboard: Array.from(session.scoreboard.entries()).map(([player, score]) => ({ player, score })), scoreboard: state.scoreboard,
matchWinner: session.matchWinner ? session.matchWinner.id : null, matchWinner: state.matchWinner,
status: session.status status: state.status,
matchInProgress: state.matchInProgress,
gameSummaries: state.gameSummaries,
} }
} }

View File

@ -1,3 +1,6 @@
import { GameSummary } from "../../game/dto/GameSummary";
import { PlayerDto } from "../../game/dto/PlayerDto";
export interface Entity { export interface Entity {
createdAt?: number; createdAt?: number;
modifiedAt?: number; modifiedAt?: number;
@ -10,7 +13,8 @@ export interface EntityMongo extends Entity {
} }
export interface Score { export interface Score {
player: string; id: string;
name: string;
score: number; score: number;
} }
@ -45,15 +49,17 @@ export interface DbMatchSession extends EntityMongo {
id: string; id: string;
name: string; name: string;
creator: string; creator: string;
players: string[]; players: PlayerDto[];
seed: string; seed: string;
mode: string; mode: string;
pointsToWin: number; pointsToWin: number;
maxPlayers: number; maxPlayers: number;
numPlayers: number; numPlayers: number;
scoreboard: Score[]; scoreboard: Score[];
matchWinner: string | null; matchWinner: PlayerDto | null;
status: string; status: string;
matchInProgress: boolean;
gameSummaries: GameSummary[];
} }
export interface DbUser extends EntityMongo { export interface DbUser extends EntityMongo {

View File

@ -10,7 +10,6 @@ import { MatchSessionMongoManager } from "../db/mongo/MatchSessionMongoManager";
import { SessionManager } from "../managers/SessionManager"; import { SessionManager } from "../managers/SessionManager";
import { ServiceBase } from "./ServiceBase"; import { ServiceBase } from "./ServiceBase";
import { SocketIoService } from "./SocketIoService"; import { SocketIoService } from "./SocketIoService";
import toObjectId from "../db/mongo/common/mongoUtils";
export class SessionService extends ServiceBase{ export class SessionService extends ServiceBase{
private dbManager: MatchSessionMongoManager = new MatchSessionMongoManager(); private dbManager: MatchSessionMongoManager = new MatchSessionMongoManager();
@ -20,7 +19,7 @@ export class SessionService extends ServiceBase{
super() super()
} }
public async createSession(user: any, sessionName: string, seed: string ): Promise<string> { public async createSession(user: any, sessionName: string, seed: string, options: any ): Promise<string> {
let socketClient; let socketClient;
try { try {
socketClient = await whileNotUndefined(() => SocketIoService.getClient(user._id)); socketClient = await whileNotUndefined(() => SocketIoService.getClient(user._id));
@ -29,6 +28,7 @@ export class SessionService extends ServiceBase{
} }
const player = new NetworkPlayer(user._id, user.username, socketClient.socketId); const player = new NetworkPlayer(user._id, user.username, socketClient.socketId);
const session = new MatchSession(player, sessionName, seed); const session = new MatchSession(player, sessionName, seed);
session.pointsToWin = options.pointsToWin;
const dbSessionId = await this.dbManager.create(matchSessionAdapter(session)); const dbSessionId = await this.dbManager.create(matchSessionAdapter(session));
if (dbSessionId === undefined) { if (dbSessionId === undefined) {
throw new SessionCreationError(); throw new SessionCreationError();
@ -82,7 +82,9 @@ export class SessionService extends ServiceBase{
return this.dbManager.update(session); return this.dbManager.update(session);
} }
// public updateSession(session: MatchSession): any { public updateSession(session: MatchSession): any {
// this.dbManager.replaceOne({id: session.id}, matchSessionAdapter(session)); const entity = matchSessionAdapter(session);
// } entity._id = session.id
this.dbManager.update(entity);
}
} }