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, channel_on_user_connection_change } from "../consts/channel_names"; import { GameMove } from "../models/GameMove"; import { GameCrashManager } from "./GameCrashManager"; import { MatchMaker } from "../matchmaker/MatchMaker"; import { UserConnectionInfo } from "../models/UserConnectionInfo"; 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(); this.listenUserConnectionChange(); } 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.getGameByUser(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.getGameByUser(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) { } 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(game.id, game); this.gameStore.setGameByUser(userKey1, game); this.gameStore.setGameByUser(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); this.sendUserConnectionInfo(game, game.player1Id); this.sendUserConnectionInfo(game, game.player2Id); } public sendUserConnectionInfo(game: MancalaGame, playerId: string, isOnline?: boolean) { //todo: reimplement when watch game feature added const _isOnline = isOnline === undefined ? this.rtmt.isClientOnline(playerId) : isOnline; const otherUser = game.player1Id === playerId ? game.player2Id : game.player1Id; const userConnectionInfo: UserConnectionInfo = { userId: playerId, isOnline: _isOnline }; this.rtmt.sendMessage(otherUser, channel_on_user_connection_change, userConnectionInfo); } public deleteGame(game: MancalaGame) { if (game) { this.gameStore.removeGameByPlayer(game.player1Id); this.gameStore.removeGameByPlayer(game.player2Id); } } private listenUserConnectionChange() { this.rtmt.listenOnClientConnectionChange((clientId: string, isOnline: boolean) => { const game = this.gameStore.getGameByUser(clientId); if (game) { this.sendUserConnectionInfo(game, clientId, isOnline); if (isOnline) { const otherUser = game.player1Id === clientId ? game.player2Id : game.player1Id; this.sendUserConnectionInfo(game, otherUser); } } }); } }