feature: spectator

This commit is contained in:
Halit Aksoy 2022-09-02 00:33:50 +03:00
parent 7a88eb4f54
commit e249896309
2 changed files with 61 additions and 19 deletions

View File

@ -9,3 +9,5 @@ export const channel_on_game_user_leave = "on_game_user_leave"
export const channel_ping = "ping" export const channel_ping = "ping"
export const channel_pong = "pong" export const channel_pong = "pong"
export const channel_on_user_connection_change = "channel_on_user_connection_change" export const channel_on_user_connection_change = "channel_on_user_connection_change"
export const channel_listen_game_events = "channel_listen_game_events"
export const channel_unlisten_game_events = "channel_unlisten_game_events"

View File

@ -5,12 +5,14 @@ import { generateKey } from "../util/key_factory";
import { import {
channel_game_move, channel_game_move,
channel_leave_game, channel_leave_game,
channel_listen_game_events,
channel_new_game, channel_new_game,
channel_on_game_crashed, channel_on_game_crashed,
channel_on_game_start, channel_on_game_start,
channel_on_game_update, channel_on_game_update,
channel_on_game_user_leave, channel_on_game_user_leave,
channel_on_user_connection_change channel_on_user_connection_change,
channel_unlisten_game_events
} from "../consts/channel_names"; } from "../consts/channel_names";
import { GameMove } from "../models/GameMove"; import { GameMove } from "../models/GameMove";
import { GameCrashManager } from "./GameCrashManager"; import { GameCrashManager } from "./GameCrashManager";
@ -47,6 +49,14 @@ export class GameManager {
this.rtmt.listenMessage(channel_leave_game, (userKey: string, message: Object) => { this.rtmt.listenMessage(channel_leave_game, (userKey: string, message: Object) => {
this.onPlayerLeave(userKey) this.onPlayerLeave(userKey)
}); });
this.rtmt.listenMessage(channel_listen_game_events, (userKey: string, message: Object) => {
this.addSpectator(userKey, message as string);
});
this.rtmt.listenMessage(channel_unlisten_game_events, (userKey: string, message: Object) => {
this.removeSpectator(userKey, message as string);
});
} }
private onGameMove(userKey: string, gameMove: GameMove) { private onGameMove(userKey: string, gameMove: GameMove) {
@ -55,10 +65,9 @@ export class GameManager {
try { try {
game.mancalaGame.moveByPlayerPit(userKey, gameMove.index); game.mancalaGame.moveByPlayerPit(userKey, gameMove.index);
game.gameUsersConnectionInfo = this.getGameUsersConnectionInfo(game); game.gameUsersConnectionInfo = this.getGameUsersConnectionInfo(game);
this.rtmt.sendMessage(game.mancalaGame.player1Id, channel_on_game_update, game); this.sendMessageToPlayersAndSpectators(game, channel_on_game_update, game);
this.rtmt.sendMessage(game.mancalaGame.player2Id, channel_on_game_update, game);
if (game.mancalaGame.state == "ended") { if (game.mancalaGame.state == "ended") {
this.deleteGame(game); this.onGameEnd(game);
} }
} catch (err: any) { } catch (err: any) {
this.onGameError(game, err) this.onGameError(game, err)
@ -72,19 +81,54 @@ export class GameManager {
console.error(error); console.error(error);
const crashFileName = GameCrashManager.logGameCrash(error, game); const crashFileName = GameCrashManager.logGameCrash(error, game);
console.info(`Game crash saved to file : ${crashFileName}`); console.info(`Game crash saved to file : ${crashFileName}`);
this.rtmt.sendMessage(game.mancalaGame.player1Id, channel_on_game_crashed, error); this.sendMessageToPlayersAndSpectators(game, channel_on_game_crashed, error);
this.rtmt.sendMessage(game.mancalaGame.player2Id, channel_on_game_crashed, error);
} }
private onPlayerLeave(userKey: string) { private onPlayerLeave(userKey: string) {
const game = this.gameStore.getGameByUser(userKey); const game = this.gameStore.getGameByUser(userKey);
if (game) { if (game) {
this.deleteGame(game); this.deleteGame(game);
this.rtmt.sendMessage(game.mancalaGame.player1Id, channel_on_game_user_leave, userKey); this.sendMessageToPlayersAndSpectators(game, channel_on_game_user_leave, userKey)
this.rtmt.sendMessage(game.mancalaGame.player2Id, channel_on_game_user_leave, userKey);
} }
} }
private addSpectator(userId: string, gameId: string) {
const game = this.gameStore.get(gameId);
if (game) {
const isUserPlayer = this.checkUserIdisPlayer(game, userId);
const isAlreadySpectator = game.spectatorIds.find((value) => value === userId);
if (!isAlreadySpectator && !isUserPlayer) {
game.spectatorIds.push(userId);
}
}
}
private removeSpectator(userId: string, gameId: string) {
const game = this.gameStore.get(gameId);
if (game) {
const userIdIndex = game.spectatorIds.findIndex((value) => value === userId);
if (userIdIndex >= 0) {
game.spectatorIds.splice(userIdIndex, 1);
}
}
}
private checkUserIdisPlayer(game: Game, userId: string): boolean {
return game.mancalaGame.player1Id === userId || game.mancalaGame.player2Id === userId;
}
private sendMessageToPlayersAndSpectators(game: Game, channel: string, message: Object) {
const sendMessage = (userId: string) => this.rtmt.sendMessage(userId, channel, message);
sendMessage(game.mancalaGame.player1Id);
sendMessage(game.mancalaGame.player2Id);
game.spectatorIds.forEach((spectatorId) => sendMessage(spectatorId));
}
private onGameEnd(game: Game) {
this.deleteGame(game);
game.spectatorIds = [];
}
private listenOnPlayersPaired() { private listenOnPlayersPaired() {
this.matchMaker.listenOnPlayersPaired((player1Id: string, player2Id: string) => { this.matchMaker.listenOnPlayersPaired((player1Id: string, player2Id: string) => {
const game = this.createMancalaGame(player1Id, player2Id); const game = this.createMancalaGame(player1Id, player2Id);
@ -103,6 +147,7 @@ export class GameManager {
id: mancalaGame.id, id: mancalaGame.id,
mancalaGame, mancalaGame,
gameUsersConnectionInfo: this.getGameUsersConnectionInfoFromUsers(mancalaGame.player1Id, mancalaGame.player2Id), gameUsersConnectionInfo: this.getGameUsersConnectionInfoFromUsers(mancalaGame.player1Id, mancalaGame.player2Id),
spectatorIds: []
}; };
this.gameStore.set(game.id, game); this.gameStore.set(game.id, game);
@ -125,21 +170,14 @@ export class GameManager {
} }
public startGame(game: Game) { public startGame(game: Game) {
const mancalaGame = game.mancalaGame; this.sendMessageToPlayersAndSpectators(game, channel_on_game_start, game);
this.rtmt.sendMessage(mancalaGame.player1Id, channel_on_game_start, game);
this.rtmt.sendMessage(mancalaGame.player2Id, channel_on_game_start, game);
this.sendUserConnectionInfo(game); this.sendUserConnectionInfo(game);
this.sendUserConnectionInfo(game); this.sendUserConnectionInfo(game);
} }
public sendUserConnectionInfo(game: Game) { public sendUserConnectionInfo(game: Game) {
const user1 = game.mancalaGame.player1Id;
const user2 = game.mancalaGame.player2Id;
const gameUsersConnectionInfo = this.getGameUsersConnectionInfo(game); const gameUsersConnectionInfo = this.getGameUsersConnectionInfo(game);
this.sendMessageToPlayersAndSpectators(game, channel_on_user_connection_change, gameUsersConnectionInfo);
//todo: reimplement when watch game feature added
this.rtmt.sendMessage(user1, channel_on_user_connection_change, gameUsersConnectionInfo);
this.rtmt.sendMessage(user2, channel_on_user_connection_change, gameUsersConnectionInfo);
} }
public deleteGame(game: Game) { public deleteGame(game: Game) {
@ -153,6 +191,8 @@ export class GameManager {
this.rtmt.listenOnClientConnectionChange((clientId: string, isOnline: boolean) => { this.rtmt.listenOnClientConnectionChange((clientId: string, isOnline: boolean) => {
const game = this.gameStore.getGameByUser(clientId); const game = this.gameStore.getGameByUser(clientId);
if (game) this.sendUserConnectionInfo(game); if (game) this.sendUserConnectionInfo(game);
const speactatingGameIds = this.gameStore.getSpeactatingGameIdsByUser(clientId);
speactatingGameIds.forEach((gameId) => this.removeSpectator(clientId, gameId));
}); });
} }
} }