Skip to content
Snippets Groups Projects
game.service.ts 7.56 KiB
Newer Older
import { Injectable, HttpException, HttpStatus } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository, Not } from 'typeorm';
L4168's avatar
L4168 committed
import {
  GameEntity,
  Game_PersonEntity,
  ObjectivePointEntity,
  ObjectivePoint_HistoryEntity,
} from './game.entity';
import { GameDTO, FlagboxEventDTO, GameStateDTO } from './game.dto';
L4168's avatar
L4168 committed
import { PersonEntity } from '../user/user.entity';
Samuli Virtapohja's avatar
Samuli Virtapohja committed
import { FactionEntity } from '../faction/faction.entity';
L4168's avatar
L4168 committed
import { NotificationGateway } from '../notifications/notifications.gateway';

@Injectable()
export class GameService {
  constructor(
    @InjectRepository(GameEntity)
    private gameRepository: Repository<GameEntity>,
    @InjectRepository(FactionEntity)
    private factionRepository: Repository<FactionEntity>,
L4168's avatar
L4168 committed
    @InjectRepository(Game_PersonEntity)
    private game_PersonRepository: Repository<Game_PersonEntity>,
L4168's avatar
L4168 committed
    @InjectRepository(ObjectivePointEntity)
    private objectivePointRepository: Repository<ObjectivePointEntity>,
    @InjectRepository(ObjectivePoint_HistoryEntity)
    private objectivePoint_HistoryRepository: Repository<
      ObjectivePoint_HistoryEntity
    >,
    private notificationGateway: NotificationGateway,
  ) {}

  // create a new game
Samuli Virtapohja's avatar
Samuli Virtapohja committed
  async createNewGame(personId: PersonEntity, gameData: GameDTO) {
L4168's avatar
L4168 committed
    // checks if a game with the same name exists already
    if (await this.gameRepository.findOne({ name: gameData.name })) {
L4168's avatar
L4168 committed
      throw new HttpException('Game already exists', HttpStatus.BAD_REQUEST);
L4168's avatar
L4168 committed
    // else add the game to the database
    const game = await this.gameRepository.create(gameData);
    game.state = 'CREATED';
L4168's avatar
L4168 committed
    await this.gameRepository.insert(game);
    // add gamePerson with role admin to the game
L4168's avatar
L4168 committed
    const gamePerson = await this.game_PersonRepository.create({
      game: game,
      person: personId,
      role: 'admin',
L4168's avatar
L4168 committed
    });
    await this.game_PersonRepository.insert(gamePerson);
    return {
L4168's avatar
L4168 committed
      code: 201,
L4168's avatar
L4168 committed
      message: 'New game added',
    };
  }

  // edit already created game
L4168's avatar
L4168 committed
  async editGame(id, gameData: GameDTO) {
L4168's avatar
L4168 committed
    // checks if a game with the same name exists already
    if (
      await this.gameRepository.findOne({ name: gameData.name, id: Not(id) })
    ) {
L4168's avatar
L4168 committed
      throw new HttpException(
        'Game with the same name already exists',
        HttpStatus.BAD_REQUEST,
      );
L4168's avatar
L4168 committed
    }
L4168's avatar
L4168 committed
    // 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
L4168's avatar
L4168 committed
    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);
L4168's avatar
L4168 committed
    const gameId = await this.gameRepository.save(updatedGame);
    // iterate factions if any were added
L4168's avatar
L4168 committed
    if (gameData.factions) {
L4168's avatar
L4168 committed
      const factionIds = gameData.factions.map(({ factionId }) => factionId);
      // delete all existing factions that are not in submitted data
L4168's avatar
L4168 committed
      factions.map(async faction => {
        if (!factionIds.includes(faction.factionId)) {
L4168's avatar
L4168 committed
          await this.factionRepository.delete(faction);
L4168's avatar
L4168 committed
        }
Samuli Virtapohja's avatar
Samuli Virtapohja committed
      });
      // create / update factions present in the submitted data
L4168's avatar
L4168 committed
      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
L4168's avatar
L4168 committed
      await this.factionRepository.delete({ game: id });
L4168's avatar
L4168 committed
    }

    // 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);
L4168's avatar
L4168 committed
        }
L4168's avatar
L4168 committed
      });
      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 });
Samuli Virtapohja's avatar
Samuli Virtapohja committed
    }
L4168's avatar
L4168 committed

    // TO DO: ADD FLAGBOX LOCATION TO MAPDRAWING ENTITY

    return {
L4168's avatar
L4168 committed
      code: 200,
L4168's avatar
L4168 committed
      message: 'Game updated',
    };
L4168's avatar
L4168 committed
  }
  async updateGameStatus(game: GameStateDTO) {
L4168's avatar
L4168 committed
    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);
L4168's avatar
L4168 committed
  async listFactions(game: GameEntity) {
    return this.factionRepository.find({ game });
  }

L4072's avatar
L4072 committed
  async deleteGame(id) {
    // TODO: Delete factions from Faction table associated with the deleted game
L4072's avatar
L4072 committed
    await this.gameRepository.delete({ id });
    return {
L4168's avatar
L4168 committed
      code: 200,
      message: 'Game deleted',
    };
  }

L4168's avatar
L4168 committed
  // returns name and id of each game
  async listGames() {
L4168's avatar
L4168 committed
    const games = await this.gameRepository.find();
    return games.map(game => {
      return game.gameObject();
    });
L4168's avatar
L4168 committed

  // returns information about a game identified by id
  async returnGameInfo(id: string) {
    const game = await this.gameRepository.findOne({
      where: { id: id },
L4168's avatar
L4168 committed
      relations: ['factions', 'objective_points'],
    // sort factions by their name
    game.factions.sort(function(a, b) {
      return a['factionName'].localeCompare(b['factionName']);
    });
L4168's avatar
L4168 committed
    return game;
  }
L4168's avatar
L4168 committed

  // 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
L4168's avatar
L4168 committed
    const factionRef = await this.factionRepository.find({ game: gameId });
L4168's avatar
L4168 committed
    // 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,
L4168's avatar
L4168 committed
    });
    await this.objectivePoint_HistoryRepository.insert(eventUpdate);
    // send flagbox event to flagbox subscribers
    this.notificationGateway.server.emit('flagbox', 'event update');
L4168's avatar
L4168 committed
    return {
      code: 201,
      message: 'OK',
    };
L4168's avatar
L4168 committed
  }