diff --git a/src/game/GameManager.ts b/src/game/GameManager.ts new file mode 100644 index 0000000..a604419 --- /dev/null +++ b/src/game/GameManager.ts @@ -0,0 +1,119 @@ +import { CommonMancalaGame, MancalaGame } from "mancala.js"; +import { RTMT } from "../rtmt/rtmt"; +import { GameStore } from "./gamestore/GameStore"; +import { generateKey } from "../util/key_factory"; +import { + channel_game_move, + channel_leave_game, + channel_new_game, + channel_on_game_crashed, + channel_on_game_start, + channel_on_game_update, + channel_on_game_user_leave +} from "../consts/channel_names"; +import { GameMove } from "../models/GameMove"; +import { GameCrashManager } from "./GameCrashManager"; +import { MatchMaker } from "../matchmaker/MatchMaker"; + +export class GameManager { + gameStore: GameStore; + rtmt: RTMT; + matchMaker: MatchMaker; + + constructor(params: { gameStore: GameStore, rtmt: RTMT, matchMaker: MatchMaker }) { + this.gameStore = params.gameStore; + this.rtmt = params.rtmt; + this.matchMaker = params.matchMaker; + this.initialize(); + } + + private initialize() { + this.listenOnPlayersPaired(); + this.listenRtmtMessages(); + } + + private listenRtmtMessages() { + this.rtmt.listenMessage(channel_new_game, (userKey: string, message: Object) => { + this.matchMaker.join(userKey); + }); + + this.rtmt.listenMessage(channel_game_move, (userKey: string, message: Object) => { + this.onGameMove(userKey, message as GameMove); + }); + + this.rtmt.listenMessage(channel_leave_game, (userKey: string, message: Object) => { + this.onPlayerLeave(userKey) + }); + } + + private onGameMove(userKey: string, gameMove: GameMove) { + const game = this.gameStore.get(userKey); + if (game) { + try { + game.moveByPlayerPit(userKey, gameMove.index); + this.rtmt.sendMessage(game.player1Id, channel_on_game_update, game); + this.rtmt.sendMessage(game.player2Id, channel_on_game_update, game); + if (game.state == "ended") { + this.deleteGame(game); + } + } catch (err: any) { + this.onGameError(game, err) + } + } else { + console.log("Game not found!"); + } + } + + private onGameError(game: MancalaGame, error: any) { + console.error(error); + const crashFileName = GameCrashManager.logGameCrash(error, game); + console.info(`Game crash saved to file : ${crashFileName}`); + this.rtmt.sendMessage(game.player1Id, channel_on_game_crashed, error); + this.rtmt.sendMessage(game.player2Id, channel_on_game_crashed, error); + } + + private onPlayerLeave(userKey: string) { + const game = this.gameStore.get(userKey); + if (game) { + this.deleteGame(game); + this.rtmt.sendMessage(game.player1Id, channel_on_game_user_leave, userKey); + this.rtmt.sendMessage(game.player2Id, channel_on_game_user_leave, userKey); + } + } + + private listenOnPlayersPaired() { + this.matchMaker.listenOnPlayersPaired((player1Id: string, player2Id: string) => { + const game = this.createMancalaGame(player1Id, player2Id); + this.startGame(game); + }); + } + + public fireOnPlayerConnected(playerId: string) { + const game = this.gameStore.get(playerId); + if (game) { + this.rtmt.sendMessage(playerId, channel_on_game_update, game); + } + } + + public createMancalaGame(userKey1: string, userKey2: string) { + const game = new CommonMancalaGame(generateKey(), userKey1, userKey2); + const random = Math.random(); + game.turnPlayerId = random > 0.5 ? userKey1 : userKey2; + + this.gameStore.set(userKey1, game); + this.gameStore.set(userKey2, game); + return game; + } + + public startGame(game: MancalaGame) { + this.rtmt.sendMessage(game.player1Id, channel_on_game_start, game); + this.rtmt.sendMessage(game.player2Id, channel_on_game_start, game); + } + + public deleteGame(game: MancalaGame) { + if (game) { + this.gameStore.remove(game.player1Id); + this.gameStore.remove(game.player2Id); + } + } +} \ No newline at end of file