Newer
Older
PixelPaintWar / apps / server / src / domains / game / application / services / GameSessionService.ts
import { config } from "@repo/shared";
import { GameLoop, type TickData } from "../../GameLoop";
import { Player } from "../../entities/Player.js";
import { MapStore } from "../../states/MapStore";
import { logEvent } from "@server/logging/logEvent";

export class GameSessionService {
  private mapStores: Map<string, MapStore>;
  private gameLoops: Map<string, GameLoop>;
  private roomStartTimes: Map<string, number>;

  constructor(private players: Map<string, Player>) {
    this.mapStores = new Map();
    this.gameLoops = new Map();
    this.roomStartTimes = new Map();
  }

  public getRoomStartTime(roomId: string): number | undefined {
    return this.roomStartTimes.get(roomId);
  }

  public startGameLoop(
    roomId: string,
    playerIds: string[],
    onTick: (data: TickData) => void,
    onGameEnd: () => void
  ) {
    if (this.gameLoops.has(roomId)) {
      logEvent("GameSessionService", {
        event: "START_GAME_LOOP",
        result: "ignored_already_running",
        roomId,
      });
      return;
    }

    const tickRate = config.GAME_CONFIG.PLAYER_POSITION_UPDATE_MS;
    this.roomStartTimes.set(roomId, Date.now());
    const mapStore = this.mapStores.get(roomId) ?? new MapStore();
    this.mapStores.set(roomId, mapStore);

    const loop = new GameLoop(
      roomId,
      tickRate,
      playerIds,
      this.players,
      mapStore,
      onTick,
      () => {
        this.roomStartTimes.delete(roomId);
        this.gameLoops.delete(roomId);
        this.mapStores.delete(roomId);
        onGameEnd();
      }
    );

    loop.start();
    this.gameLoops.set(roomId, loop);
    logEvent("GameSessionService", {
      event: "START_GAME_LOOP",
      result: "started",
      roomId,
      playerCount: playerIds.length,
    });
  }
}