Skip to content

Commit

Permalink
feat: player connection status (#44)
Browse files Browse the repository at this point in the history
* add player joined team event

* update  GamePlayer model

* add GameRunner player events
  • Loading branch information
garrappachc authored Jan 3, 2020
1 parent fd733df commit f6f613a
Show file tree
Hide file tree
Showing 5 changed files with 65 additions and 5 deletions.
26 changes: 25 additions & 1 deletion src/games/game-runner.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,10 @@ const makeGame = () => ({
map: 'cp_badlands',
state: 'launching',
save: () => null,
slots: [
{ playerId: 'FAKE_PLAYER_ID_1', connectionStatus: 'offline' },
{ playerId: 'FAKE_PLAYER_ID_2', connectionStatus: 'joining' },
]
});

const makeGameServer = () => ({
Expand Down Expand Up @@ -38,7 +42,9 @@ class ServerConfiguratorServiceStub {
cleanupServer(gameServer: any) { return null; }
}

class PlayersServiceStub { }
class PlayersServiceStub {
findBySteamId(steamId: string) { return { id: 'FAKE_PLAYER_ID_1' }; }
}

describe('GameRunner', () => {
let gameRunner: GameRunner;
Expand Down Expand Up @@ -184,6 +190,24 @@ describe('GameRunner', () => {
});
});

describe('#onPlayerJoining()', () => {
it('should update player connection status and emit event', async done => {
gameRunner.gameUpdated.subscribe(done);
gameRunner.game = makeGame() as any;
await gameRunner.onPlayerJoining('some steam id');
expect(gameRunner.game.slots.find(s => s.playerId === 'FAKE_PLAYER_ID_1').connectionStatus).toEqual('joining');
});
});

describe('#onPlayerConnected()', () => {
it('should update player connection status and emit event', async done => {
gameRunner.gameUpdated.subscribe(done);
gameRunner.game = makeGame() as any;
await gameRunner.onPlayerConnected('some steam id');
expect(gameRunner.game.slots.find(s => s.playerId === 'FAKE_PLAYER_ID_1').connectionStatus).toEqual('connected');
});
});

describe('#onMatchStarted()', () => {
it('should change state and emit event', async done => {
gameRunner.game = makeGame() as any;
Expand Down
20 changes: 20 additions & 0 deletions src/games/game-runner.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import { Logger } from '@nestjs/common';
import { GamesService } from './services/games.service';
import { PlayersService } from '@/players/services/players.service';
import { Environment } from '@/environment/environment';
import { PlayerConnectionStatus } from './models/player-connection-status';

export class GameRunner {

Expand Down Expand Up @@ -97,14 +98,22 @@ export class GameRunner {
await this.gameServersService.releaseServer(this.gameServer.id);
}

async onPlayerJoining(steamId: string) {
const player = await this.playersService.findBySteamId(steamId);
this.logger.verbose(`${player.name} is joining the server`);
await this.setPlayerConnectionStatus(player.id, 'joining');
}

async onPlayerConnected(steamId: string) {
const player = await this.playersService.findBySteamId(steamId);
this.logger.verbose(`${player.name} connected`);
await this.setPlayerConnectionStatus(player.id, 'connected');
}

async onPlayerDisconnected(steamId: string) {
const player = await this.playersService.findBySteamId(steamId);
this.logger.verbose(`${player.name} disconnected`);
await this.setPlayerConnectionStatus(player.id, 'offline');
}

async onMatchStarted() {
Expand Down Expand Up @@ -157,4 +166,15 @@ export class GameRunner {
this._gameUpdated.next();
}

private async setPlayerConnectionStatus(playerId: string, connectionStatus: PlayerConnectionStatus) {
const slot = this.game.slots.find(s => s.playerId === playerId);
if (slot) {
slot.connectionStatus = connectionStatus;
await this.game.save();
this._gameUpdated.next();
} else {
this.logger.warn(`player ${playerId} does not belong in this game`);
}
}

}
12 changes: 8 additions & 4 deletions src/games/models/game-player.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,19 @@
import { prop } from '@typegoose/typegoose';
import { PlayerConnectionStatus } from './player-connection-status';

export class GamePlayer {
@prop({ required: true })
public playerId!: string;
playerId!: string;

@prop({ required: true })
public teamId!: string;
teamId!: string;

@prop({ required: true })
public gameClass: string;
gameClass: string;

@prop({ default: 'active' })
public status: 'active' | 'waiting for substitute' | 'replaced';
status: 'active' | 'waiting for substitute' | 'replaced';

@prop({ default: 'offline' })
connectionStatus: PlayerConnectionStatus;
}
1 change: 1 addition & 0 deletions src/games/models/player-connection-status.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export type PlayerConnectionStatus = 'offline' | 'joining' | 'connected';
11 changes: 11 additions & 0 deletions src/games/services/game-event-listener.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,17 @@ const gameEvents: GameEvent[] = [
name: 'player connected',
// https://regex101.com/r/uyPW8m/4
regex: /^(\d{2}\/\d{2}\/\d{4})\s-\s(\d{2}:\d{2}:\d{2}):\s\"(.+)\<(\d+)\>\<(\[.[^\]]+\])\>\<\>"\sconnected,\saddress\s\"(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}:\d{1,5})"$/,
handle: (gameRunner, matches) => {
const steamId = new SteamID(matches[5]);
if (steamId.isValid()) {
gameRunner.onPlayerJoining(steamId.getSteamID64());
}
},
},
{
name: 'player joined team',
// https://regex101.com/r/yzX9zG/1
regex: /^(\d{2}\/\d{2}\/\d{4})\s-\s(\d{2}:\d{2}:\d{2}):\s\"(.+)\<(\d+)\>\<(\[.[^\]]+\])\>\<(.+)\>"\sjoined\steam\s\"(.+)\"/,
handle: (gameRunner, matches) => {
const steamId = new SteamID(matches[5]);
if (steamId.isValid()) {
Expand Down

0 comments on commit f6f613a

Please sign in to comment.