import { Injectable, HttpException, HttpStatus } from '@nestjs/common'; import { InjectRepository } from '@nestjs/typeorm'; import { Repository, Not } from 'typeorm'; import { GameEntity, Game_PersonEntity, ObjectivePointEntity, ObjectivePoint_HistoryEntity, } from './game.entity'; import { GameDTO, FlagboxEventDTO, GameStateDTO } from './game.dto'; import { PersonEntity } from '../user/user.entity'; import { FactionEntity } from '../faction/faction.entity'; import { NotificationGateway } from '../notifications/notifications.gateway'; @Injectable() export class GameService { constructor( @InjectRepository(GameEntity) private gameRepository: Repository<GameEntity>, @InjectRepository(FactionEntity) private factionRepository: Repository<FactionEntity>, @InjectRepository(Game_PersonEntity) private game_PersonRepository: Repository<Game_PersonEntity>, @InjectRepository(ObjectivePointEntity) private objectivePointRepository: Repository<ObjectivePointEntity>, @InjectRepository(ObjectivePoint_HistoryEntity) private objectivePoint_HistoryRepository: Repository< ObjectivePoint_HistoryEntity >, private notificationGateway: NotificationGateway, ) {} // create a new game async createNewGame(personId: PersonEntity, gameData: GameDTO) { // checks if a game with the same name exists already if (await this.gameRepository.findOne({ name: gameData.name })) { throw new HttpException('Game already exists', HttpStatus.BAD_REQUEST); } // else add the game to the database const game = await this.gameRepository.create(gameData); game.state = 'CREATED'; await this.gameRepository.insert(game); // add gamePerson with role admin to the game const gamePerson = await this.game_PersonRepository.create({ game: game, person: personId, role: 'admin', }); await this.game_PersonRepository.insert(gamePerson); return { code: 201, message: 'New game added', }; } // edit already created game async editGame(id, gameData: GameDTO) { // checks if a game with the same name exists already if ( await this.gameRepository.findOne({ name: gameData.name, id: Not(id) }) ) { throw new HttpException( 'Game with the same name already exists', HttpStatus.BAD_REQUEST, ); } // check for duplicate names in gameData const factionNames = gameData.factions.map( ({ factionName }) => factionName, ); const flagboxNodeIds = gameData.objective_points.map( ({ objectivePointDescription }) => objectivePointDescription, ); if ( new Set(factionNames).size !== factionNames.length || new Set(flagboxNodeIds).size !== flagboxNodeIds.length ) { throw new HttpException( 'No duplicate names allowed!', HttpStatus.BAD_REQUEST, ); } // get factions that have been added previously let factions = await this.factionRepository.find({ game: id }); // get flagboxes that have been added previously let flagboxes = await this.objectivePointRepository.find({ game: id, }); // update game entry in db const updatedGame = await this.gameRepository.create(gameData); const gameId = await this.gameRepository.save(updatedGame); // iterate factions if any were added if (gameData.factions) { const factionIds = gameData.factions.map(({ factionId }) => factionId); // delete all existing factions that are not in submitted data factions.map(async faction => { if (!factionIds.includes(faction.factionId)) { await this.factionRepository.delete(faction); } }); // create / update factions present in the submitted data gameData.factions.map(async faction => { let name = await this.factionRepository.create({ ...faction, game: gameId, }); await this.factionRepository.save(name); }); } else { // if no factions are present in data, delete all factions associated with the game await this.factionRepository.delete({ game: id }); } // insert the flagboxes to db if (gameData.objective_points) { const flagboxIds = gameData.objective_points.map( ({ objectivePointId }) => objectivePointId, ); flagboxes.map(async flagbox => { if (!flagboxIds.includes(flagbox.objectivePointDescription)) { await this.objectivePointRepository.delete(flagbox); } }); gameData.objective_points.map(async flagbox => { let newFlagbox = await this.objectivePointRepository.create({ ...flagbox, game: gameId, }); await this.objectivePointRepository.save(newFlagbox); }); } else { await this.objectivePointRepository.delete({ game: id }); } // TO DO: ADD FLAGBOX LOCATION TO MAPDRAWING ENTITY return { code: 200, message: 'Game updated', }; } async updateGameStatus(game: GameStateDTO) { const updatedGame = await this.gameRepository.findOne({ id: game.id }); if (updatedGame) { updatedGame.state = game.state; await this.gameRepository.save(updatedGame); // notify players about game state change this.notificationGateway.server.emit(game.id, 'event update'); return { code: 200, message: 'State was updated', }; } throw new HttpException("Game doesn't exist", HttpStatus.BAD_REQUEST); } async listFactions(game: GameEntity) { return this.factionRepository.find({ game }); } async deleteGame(id) { // TODO: Delete factions from Faction table associated with the deleted game await this.gameRepository.delete({ id }); return { code: 200, message: 'Game deleted', }; } // returns name and id of each game async listGames() { const games = await this.gameRepository.find(); return games.map(game => { return game.gameObject(); }); } // returns information about a game identified by id async returnGameInfo(id: string) { const game = await this.gameRepository.findOne({ where: { id: id }, relations: ['factions', 'objective_points'], }); // sort factions by their name game.factions.sort(function(a, b) { return a['factionName'].localeCompare(b['factionName']); }); return game; } // returns flagbox settings async flagboxQuery(gameId) { const game = await this.gameRepository.findOne({ id: gameId }); return game.nodesettings; } // add events to history and send updates with socket async flagboxEvent(gameId, data: FlagboxEventDTO) { // get all the factions associated with the game const factionRef = await this.factionRepository.find({ game: gameId }); // get reference to the objective const objectiveRef = await this.objectivePointRepository.findOne({ where: { objectivePointDescription: data.node_id, game: gameId }, }); data.oP_HistoryTimestamp = new Date(Date.now()).toLocaleString(); const eventUpdate = await this.objectivePoint_HistoryRepository.create({ oP_HistoryTimestamp: data.oP_HistoryTimestamp, action: data.action, // -1 as 0 means null capture: data.capture !== 0 ? factionRef[data.capture - 1] : null, owner: data.owner !== 0 ? factionRef[data.owner - 1] : null, objective_point: objectiveRef.objectivePointId, }); await this.objectivePoint_HistoryRepository.insert(eventUpdate); // send flagbox event to flagbox subscribers this.notificationGateway.server.emit('flagbox', 'event update'); return { code: 201, message: 'OK', }; } }