diff --git a/src/games/controllers/games.lobby.controller.ts b/src/games/controllers/games.lobby.controller.ts index 3106c57..cd8bf9f 100644 --- a/src/games/controllers/games.lobby.controller.ts +++ b/src/games/controllers/games.lobby.controller.ts @@ -152,7 +152,7 @@ export class LobbyController { HttpStatus.FORBIDDEN, ); } - this.lobbyService.start(game); + await this.lobbyService.start(game); return; } @@ -178,6 +178,20 @@ export class LobbyController { HttpStatus.BAD_REQUEST, ); } - return this.lobbyService.joinGame(game, session.user); + return await this.lobbyService.joinGame(game, session.user); + } + + @Post(':id/leave') + @ApiOperation({ summary: "Leave a game that hasn't already started" }) + @UseGuards(AuthGuard) + async leave( + @Param('id') id: string, + @Session() session: Record, + @Param('id', GamePipe) game: Document & Game, + ) { + if (game.started) { + throw new HttpException('Game already started', HttpStatus.BAD_REQUEST); + } + return await this.lobbyService.leaveGame(game, session.user); } } diff --git a/src/games/services/games.lobby.service.ts b/src/games/services/games.lobby.service.ts index 4d3dc31..099bde0 100644 --- a/src/games/services/games.lobby.service.ts +++ b/src/games/services/games.lobby.service.ts @@ -6,6 +6,7 @@ import mongoose, { Document, Model } from 'mongoose'; import { ReadContainerDto, ReadGameDto, + ReadPlayerDto, ReadTeamDto, } from '../dto/read-games.dto'; import { User } from 'src/users/schemas/user.entity'; @@ -15,6 +16,7 @@ import { StartingDeckDto, UpdateGameDto } from '../dto/update-game.dto'; import { EventEmitter2 } from '@nestjs/event-emitter'; import { GameService } from './games.service'; import { WithTransaction } from '../utils'; +import { platform } from 'os'; @Injectable() export class LobbyService { @@ -72,6 +74,46 @@ export class LobbyService { return 'true!'; } + @WithTransaction + async leaveGame( + game: Document & Game, + user: User, + session?: mongoose.mongo.ClientSession, + ) { + const team = game.teams.find((t) => + t.players.find((p) => p.user._id.equals(user._id)), + ); + if (team == undefined) { + throw new HttpException('User not in game', HttpStatus.FORBIDDEN); + } + if (game.owner._id.equals(user._id)) { + throw new HttpException( + 'You cannot leave a game you own', + HttpStatus.FORBIDDEN, + ); + } + const index = team.players.findIndex((p) => p.user._id.equals(user._id)); + const player = team.players[index]; + team.players.splice(index, 1); + this.eventEmitter.emit('sse.lobby', { + type: 'leaveGame', + player: new ReadPlayerDto(player), + game: game._id.toHexString(), + }); + this.eventEmitter.emit('sse.game.' + game._id.toHexString(), { + type: 'leaveGame', + player: new ReadPlayerDto(player), + }); + if (team.players.length == 0) { + const teamIndex = game.teams.indexOf(team); + game.teams.splice(teamIndex, 1); + } + + await game.save({ session }); + + return 'true!'; + } + async findAll(): Promise { const games = await this.gameModel.find().exec(); return await Promise.all(