Skip to content
3 changes: 3 additions & 0 deletions src/core/configuration/Config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { Colord } from "colord";
import { JWK } from "jose";
import {
Game,
GameType,
Gold,
Player,
PlayerInfo,
Expand All @@ -27,6 +28,8 @@ export interface ServerConfig {
turnstileSiteKey(): string;
turnstileSecretKey(): string;
turnIntervalMs(): number;
spawnPhaseTicks(gameType: GameType): number;
spawnPhaseSeconds(gameType: GameType): number;
gameCreationRate(): number;
numWorkers(): number;
workerIndex(gameID: GameID): number;
Expand Down
11 changes: 10 additions & 1 deletion src/core/configuration/DefaultConfig.ts
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,15 @@ export abstract class DefaultServerConfig implements ServerConfig {
turnIntervalMs(): number {
return 100;
}
ticksPerSecond(): number {
return 1000 / this.turnIntervalMs();
}
spawnPhaseTicks(gameType: GameType): number {
return gameType === GameType.Singleplayer ? 100 : 300;
}
spawnPhaseSeconds(gameType: GameType): number {
return this.spawnPhaseTicks(gameType) / this.ticksPerSecond();
}
gameCreationRate(): number {
return 60 * 1000;
}
Expand Down Expand Up @@ -542,7 +551,7 @@ export class DefaultConfig implements Config {
return 3;
}
numSpawnPhaseTurns(): number {
return this._gameConfig.gameType === GameType.Singleplayer ? 100 : 300;
return this._serverConfig.spawnPhaseTicks(this._gameConfig.gameType);
}
numBots(): number {
return this.bots();
Expand Down
22 changes: 19 additions & 3 deletions src/server/GamePreviewBuilder.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { z } from "zod";
import { ServerConfig } from "../core/configuration/Config";
import { GameMode, GameType } from "../core/game/Game";
import { GameInfo } from "../core/Schemas";
import { GameMode } from "../core/game/Game";

export const PlayerInfoSchema = z.object({
clientID: z.string().optional(),
Expand Down Expand Up @@ -132,6 +133,7 @@ export function buildPreview(
workerPath: string,
lobby: GameInfo | null,
publicInfo: ExternalGameInfo | null,
serverConfig: ServerConfig,
): PreviewMeta {
const isFinished = !!publicInfo?.info?.end;
const isPrivate = lobby?.gameConfig?.gameType === "Private";
Expand Down Expand Up @@ -178,6 +180,19 @@ export function buildPreview(

const winner = parseWinner(publicInfo?.info?.winner, players);
const duration = publicInfo?.info?.duration;
const gameType = lobby?.gameConfig?.gameType ?? config.gameType;
const adjustedDuration =
typeof duration === "number"
? Math.max(
0,
duration -
serverConfig.spawnPhaseSeconds(
gameType === GameType.Singleplayer
? GameType.Singleplayer
: GameType.Public,
),
)
: undefined;

// Normalize map name to match filesystem (lowercase, no spaces or special chars)
const normalizedMap = map ? map.toLowerCase().replace(/[\s.()]+/g, "") : null;
Expand All @@ -187,7 +202,6 @@ export function buildPreview(
: null;
const image = mapThumbnail ?? `${origin}/images/GameplayScreenshot.png`;

const gameType = lobby?.gameConfig?.gameType ?? config.gameType;
const gameTypeLabel = gameType ? ` (${gameType})` : "";

const title = isFinished
Expand All @@ -210,7 +224,9 @@ export function buildPreview(
const detailParts: string[] = [];
const playerCountLabel = `${activePlayers} ${activePlayers === 1 ? "player" : "players"}`;
detailParts.push(playerCountLabel);
if (duration !== undefined) detailParts.push(`${formatDuration(duration)}`);
if (adjustedDuration !== undefined) {
detailParts.push(`${formatDuration(adjustedDuration)}`);
}
if (matchTimestamp !== undefined) {
const dateTime = formatDateTimeParts(matchTimestamp);
detailParts.push(`${dateTime.date}`);
Expand Down
1 change: 1 addition & 0 deletions src/server/GamePreviewRoute.ts
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,7 @@ export function registerGamePreviewRoute(opts: {
config.workerPath(gameID),
lobby,
publicInfo,
config,
);

// Always serve HTML with meta tags for /game/:id route
Expand Down
10 changes: 8 additions & 2 deletions tests/util/TestServerConfig.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { JWK } from "jose";
import { GameEnv, ServerConfig } from "../../src/core/configuration/Config";
import { PublicGameModifiers } from "../../src/core/game/Game";
import { GameType, PublicGameModifiers } from "../../src/core/game/Game";
import { GameID } from "../../src/core/Schemas";

export class TestServerConfig implements ServerConfig {
Expand Down Expand Up @@ -44,7 +44,13 @@ export class TestServerConfig implements ServerConfig {
throw new Error("Method not implemented.");
}
turnIntervalMs(): number {
throw new Error("Method not implemented.");
return 100;
}
spawnPhaseTicks(gameType: GameType): number {
return gameType === GameType.Singleplayer ? 100 : 300;
}
spawnPhaseSeconds(gameType: GameType): number {
return this.spawnPhaseTicks(gameType) / (1000 / this.turnIntervalMs());
}
gameCreationRate(): number {
throw new Error("Method not implemented.");
Expand Down
Loading