Skip to content

Commit 0ea671c

Browse files
committed
wip
1 parent 4ac9a64 commit 0ea671c

20 files changed

+317
-191
lines changed

src/app.module.ts

+3-1
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ import { CrimeController } from 'rest/crime/crime.controller';
2727
import configuration from 'util/configuration';
2828
import { ConfigModule, ConfigService } from '@nestjs/config';
2929
import { TypeOrmModuleOptions } from '@nestjs/typeorm/dist/interfaces/typeorm-options.interface';
30+
import { RmqController } from 'rmq.controller';
3031

3132
@Module({
3233
imports: [
@@ -75,7 +76,7 @@ import { TypeOrmModuleOptions } from '@nestjs/typeorm/dist/interfaces/typeorm-op
7576
password: config.get<string>('rabbitmq.password'),
7677
},
7778
],
78-
queue: config.get<string>('rabbitmq.queue'),
79+
queue: config.get<string>('rabbitmq.gameserver_commands'),
7980
queueOptions: {
8081
durable: true,
8182
},
@@ -106,6 +107,7 @@ import { TypeOrmModuleOptions } from '@nestjs/typeorm/dist/interfaces/typeorm-op
106107
],
107108
controllers: [
108109
CoreController,
110+
RmqController,
109111
QueryController,
110112
MatchController,
111113
PlayerController,

src/core.controller.ts

-22
Original file line numberDiff line numberDiff line change
@@ -5,17 +5,13 @@ import { Constructor, EventBus } from '@nestjs/cqrs';
55
import { GameServerNotStartedEvent, GameServerStartedEvent } from 'gateway/events/game-server-started.event';
66
import { GameServerStoppedEvent } from 'gateway/events/game-server-stopped.event';
77
import { GameServerDiscoveredEvent } from 'gateway/events/game-server-discovered.event';
8-
import { GameResultsEvent } from 'gateway/events/gs/game-results.event';
98
import { PlayerBanHammeredEvent } from 'gateway/events/bans/player-ban-hammered.event';
109
import { ServerSessionSyncEvent } from 'gateway/events/gs/server-session-sync.event';
11-
import { PlayerNotLoadedEvent } from 'gateway/events/bans/player-not-loaded.event';
1210
import { PlayerDeclinedGameEvent } from 'gateway/events/mm/player-declined-game.event';
1311
import { TournamentGameReadyEvent } from 'gateway/events/tournament/tournament-game-ready.event';
1412
import { LiveMatchUpdateEvent } from 'gateway/events/gs/live-match-update.event';
1513
import { StartFakeMatchEvent } from 'gateway/events/start-fake-match.event';
1614
import { ServerStatusEvent } from 'gateway/events/gs/server-status.event';
17-
import { MatchFailedEvent } from 'gateway/events/match-failed.event';
18-
import { PlayerAbandonedEvent } from 'gateway/events/bans/player-abandoned.event';
1915
import { LobbyReadyEvent } from 'gateway/events/lobby-ready.event';
2016
import { ConfigService } from '@nestjs/config';
2117
import { SrcdsServerStartedEvent } from 'gateway/events/srcds-server-started.event';
@@ -80,11 +76,6 @@ export class CoreController {
8076
this.event(GameServerDiscoveredEvent, data);
8177
}
8278

83-
@EventPattern(GameResultsEvent.name)
84-
async GameResultsEvent(data: GameResultsEvent) {
85-
this.event(GameResultsEvent, data);
86-
}
87-
8879
@EventPattern(PlayerBanHammeredEvent.name)
8980
async PlayerBanHammeredEvent(data: PlayerBanHammeredEvent) {
9081
this.event(PlayerBanHammeredEvent, data);
@@ -95,15 +86,7 @@ export class CoreController {
9586
this.event(PlayerDeclinedGameEvent, data);
9687
}
9788

98-
@EventPattern(PlayerNotLoadedEvent.name)
99-
async PlayerNotLoadedEvent(data: PlayerNotLoadedEvent) {
100-
this.event(PlayerNotLoadedEvent, data);
101-
}
10289

103-
@EventPattern(PlayerAbandonedEvent.name)
104-
async PlayerAbandonedEvent(data: PlayerAbandonedEvent) {
105-
this.event(PlayerAbandonedEvent, data);
106-
}
10790

10891
@EventPattern(LiveMatchUpdateEvent.name)
10992
async LiveMatchUpdateEvent(data: LiveMatchUpdateEvent) {
@@ -120,11 +103,6 @@ export class CoreController {
120103
this.event(ServerStatusEvent, data);
121104
}
122105

123-
@EventPattern(MatchFailedEvent.name)
124-
async MatchFailedEvent(data: MatchFailedEvent) {
125-
this.event(MatchFailedEvent, data);
126-
}
127-
128106
@EventPattern(PlayerConnectedEvent.name)
129107
async PlayerConnectedEvent(data: PlayerConnectedEvent) {
130108
this.event(PlayerConnectedEvent, data);
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
import { GameResultsEvent } from 'gateway/events/gs/game-results.event';
2+
3+
export class SaveGameResultsCommand {
4+
constructor(
5+
public readonly event: GameResultsEvent
6+
) {
7+
}
8+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,139 @@
1+
import { CommandHandler, EventBus, ICommandHandler } from '@nestjs/cqrs';
2+
import { Logger } from '@nestjs/common';
3+
import { SaveGameResultsCommand } from 'gameserver/command/SaveGameResults/save-game-results.command';
4+
import { MatchmakingMode } from 'gateway/shared-types/matchmaking-mode';
5+
import FinishedMatchEntity from 'gameserver/model/finished-match.entity';
6+
import PlayerInMatchEntity from 'gameserver/model/player-in-match.entity';
7+
import { MatchRecordedEvent } from 'gameserver/event/match-recorded.event';
8+
import { GameSessionFinishedEvent } from 'gateway/events/game-session-finished.event';
9+
import { InjectRepository } from '@nestjs/typeorm';
10+
import { DataSource, Repository } from 'typeorm';
11+
import { GameServerSessionEntity } from 'gameserver/model/game-server-session.entity';
12+
13+
@CommandHandler(SaveGameResultsCommand)
14+
export class SaveGameResultsHandler
15+
implements ICommandHandler<SaveGameResultsCommand>
16+
{
17+
private readonly logger = new Logger(SaveGameResultsHandler.name);
18+
19+
constructor(
20+
@InjectRepository(FinishedMatchEntity)
21+
private readonly finishedMatchRepository: Repository<FinishedMatchEntity>,
22+
@InjectRepository(PlayerInMatchEntity)
23+
private readonly playerInMatchRepository: Repository<PlayerInMatchEntity>,
24+
@InjectRepository(GameServerSessionEntity)
25+
private readonly gameServerSessionModelRepository: Repository<GameServerSessionEntity>,
26+
private readonly ebus: EventBus,
27+
private readonly datasource: DataSource,
28+
) {}
29+
30+
async execute({ event }: SaveGameResultsCommand) {
31+
const existingRecordedMatch = await this.finishedMatchRepository.exists({
32+
where: {
33+
id: event.matchId,
34+
},
35+
});
36+
37+
if (existingRecordedMatch) {
38+
this.logger.warn("Tried to save already existing match", {
39+
match_id: event.matchId
40+
});
41+
return;
42+
}
43+
44+
let modeOverride =
45+
(event.type === MatchmakingMode.UNRANKED ||
46+
event.type === MatchmakingMode.RANKED) &&
47+
event.players.length !== 10
48+
? MatchmakingMode.BOTS
49+
: event.type;
50+
51+
const m = await this.datasource.transaction<FinishedMatchEntity>(
52+
async (entityManager) => {
53+
const m = new FinishedMatchEntity(
54+
event.matchId,
55+
event.winner,
56+
new Date(event.timestamp * 1000).toISOString(),
57+
event.gameMode,
58+
modeOverride,
59+
event.duration,
60+
event.server,
61+
);
62+
63+
m.externalMatchId = event.externalMatchId;
64+
65+
await entityManager.save(m);
66+
67+
const pims = event.players.map((t) => {
68+
const pim = new PlayerInMatchEntity();
69+
70+
pim.match = m;
71+
// kda
72+
pim.kills = t.kills;
73+
pim.deaths = t.deaths;
74+
pim.assists = t.assists;
75+
76+
// creeps
77+
pim.denies = t.denies;
78+
pim.last_hits = t.last_hits;
79+
80+
// pm
81+
pim.gpm = t.gpm;
82+
pim.xpm = t.xpm;
83+
pim.hero_damage = t.heroDamage;
84+
pim.hero_healing = t.heroHealing;
85+
pim.tower_damage = t.towerDamage;
86+
87+
pim.abandoned = t.abandoned;
88+
pim.gold = t.networth;
89+
90+
pim.item0 = t.item0;
91+
pim.item1 = t.item1;
92+
pim.item2 = t.item2;
93+
pim.item3 = t.item3;
94+
pim.item4 = t.item4;
95+
pim.item5 = t.item5;
96+
97+
pim.level = t.level;
98+
pim.playerId = t.steam_id;
99+
pim.team = t.team;
100+
pim.hero = t.hero;
101+
return pim;
102+
});
103+
104+
await entityManager.save(pims);
105+
106+
return m;
107+
},
108+
);
109+
110+
await this.ebus.publish(
111+
new MatchRecordedEvent(
112+
event.matchId,
113+
event.winner,
114+
event.duration,
115+
m.matchmaking_mode,
116+
m.game_mode,
117+
event.timestamp,
118+
event.server,
119+
event.players,
120+
),
121+
);
122+
123+
const runningSession = await this.gameServerSessionModelRepository.findOne({
124+
where: {
125+
url: event.server,
126+
},
127+
});
128+
if (runningSession) {
129+
await this.gameServerSessionModelRepository.delete(runningSession.url);
130+
this.ebus.publish(
131+
new GameSessionFinishedEvent(
132+
runningSession.url,
133+
runningSession.matchId,
134+
runningSession.matchInfoJson,
135+
),
136+
);
137+
}
138+
}
139+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
import { MatchFailedEvent } from 'gateway/events/match-failed.event';
2+
3+
export class SaveMatchFailedCommand {
4+
constructor(
5+
public readonly event: MatchFailedEvent
6+
) {
7+
}
8+
}

src/gameserver/event-handler/match-failed.handler.ts src/gameserver/command/SaveMatchFailed/save-match-failed.handler.ts

+12-10
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,17 @@
1-
import { EventBus, EventsHandler, IEventHandler } from '@nestjs/cqrs';
2-
import { MatchFailedEvent } from 'gateway/events/match-failed.event';
3-
import { PlayerCrimeLogEntity } from 'gameserver/model/player-crime-log.entity';
1+
import { CommandHandler, EventBus, ICommandHandler } from '@nestjs/cqrs';
2+
import { Logger } from '@nestjs/common';
3+
import { SaveMatchFailedCommand } from 'gameserver/command/SaveMatchFailed/save-match-failed.command';
44
import { InjectRepository } from '@nestjs/typeorm';
5+
import { PlayerCrimeLogEntity } from 'gameserver/model/player-crime-log.entity';
56
import { Repository } from 'typeorm';
6-
import { PlayerNotLoadedEvent } from 'gateway/events/bans/player-not-loaded.event';
7-
import { Logger } from '@nestjs/common';
87
import { MatchEntity } from 'gameserver/model/match.entity';
8+
import { PlayerNotLoadedEvent } from 'gameserver/event/player-not-loaded.event';
99

10-
@EventsHandler(MatchFailedEvent)
11-
export class MatchFailedHandler implements IEventHandler<MatchFailedEvent> {
12-
private logger = new Logger(MatchFailedHandler.name);
10+
@CommandHandler(SaveMatchFailedCommand)
11+
export class SaveMatchFailedHandler
12+
implements ICommandHandler<SaveMatchFailedCommand>
13+
{
14+
private logger = new Logger(SaveMatchFailedHandler.name);
1315

1416
constructor(
1517
@InjectRepository(PlayerCrimeLogEntity)
@@ -21,12 +23,12 @@ export class MatchFailedHandler implements IEventHandler<MatchFailedEvent> {
2123
private readonly ebus: EventBus,
2224
) {}
2325

24-
async handle(event: MatchFailedEvent) {
26+
async execute({ event }: SaveMatchFailedCommand) {
2527
const match = await this.matchEntityRepository.findOne({
2628
where: { id: event.matchId },
2729
});
2830
if (!match) {
29-
this.logger.warn('MatchFailedEvent on non-existing match');
31+
this.logger.warn('MatchFailedEvent on non-existing match', { match_id: event.matchId });
3032
return;
3133
}
3234
//
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
import { PlayerAbandonedEvent } from 'gateway/events/bans/player-abandoned.event';
2+
3+
export class SavePlayerAbandonCommand {
4+
constructor(
5+
public readonly event: PlayerAbandonedEvent
6+
) {
7+
}
8+
}

src/gameserver/event-handler/player-abandoned.handler.ts src/gameserver/command/SavePlayerAbandon/save-player-abandon.handler.ts

+10-9
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,25 @@
1-
import { EventBus, EventsHandler, IEventHandler } from '@nestjs/cqrs';
2-
import { PlayerAbandonedEvent } from 'gateway/events/bans/player-abandoned.event';
1+
import { CommandHandler, EventBus, ICommandHandler } from '@nestjs/cqrs';
2+
import { Logger } from '@nestjs/common';
3+
import { SavePlayerAbandonCommand } from 'gameserver/command/SavePlayerAbandon/save-player-abandon.command';
34
import { PlayerCrimeLogEntity } from 'gameserver/model/player-crime-log.entity';
45
import { BanReason } from 'gateway/shared-types/ban';
5-
import { CrimeLogCreatedEvent } from 'gameserver/event/crime-log-created.event';
66
import { InjectRepository } from '@nestjs/typeorm';
77
import { Repository } from 'typeorm';
8-
import { Logger } from '@nestjs/common';
8+
import { CrimeLogCreatedEvent } from 'gameserver/event/crime-log-created.event';
99

10-
@EventsHandler(PlayerAbandonedEvent)
11-
export class PlayerAbandonedHandler
12-
implements IEventHandler<PlayerAbandonedEvent>
10+
@CommandHandler(SavePlayerAbandonCommand)
11+
export class SavePlayerAbandonHandler
12+
implements ICommandHandler<SavePlayerAbandonCommand>
1313
{
14-
private logger = new Logger(PlayerAbandonedHandler.name);
14+
private readonly logger = new Logger(SavePlayerAbandonHandler.name);
1515

1616
constructor(
1717
@InjectRepository(PlayerCrimeLogEntity)
1818
private readonly playerCrimeLogEntityRepository: Repository<PlayerCrimeLogEntity>,
1919
private readonly ebus: EventBus,
2020
) {}
2121

22-
async handle(event: PlayerAbandonedEvent) {
22+
async execute({ event }: SavePlayerAbandonCommand) {
2323
// Let them abandon ffs
2424
this.logger.log("PlayerAbandonEvent", { index: event.abandonIndex });
2525
if (event.abandonIndex > 0) {
@@ -31,6 +31,7 @@ export class PlayerAbandonedHandler
3131
event.playerId.value,
3232
BanReason.ABANDON,
3333
event.mode,
34+
event.matchId
3435
);
3536

3637
await this.playerCrimeLogEntityRepository.save(crime);

0 commit comments

Comments
 (0)