From 0803b71e81f07a8e7a6331126cae2ed94ddf4865 Mon Sep 17 00:00:00 2001 From: Ryan Barlow Date: Thu, 29 Jan 2026 21:15:02 +0000 Subject: [PATCH] update --- src/core/Schemas.ts | 29 ------------------------- src/core/configuration/Config.ts | 3 +++ src/core/configuration/DefaultConfig.ts | 16 ++++++++------ src/server/GamePreviewBuilder.ts | 14 +++++++++--- src/server/GamePreviewRoute.ts | 1 + tests/util/TestServerConfig.ts | 8 ++++++- 6 files changed, 31 insertions(+), 40 deletions(-) diff --git a/src/core/Schemas.ts b/src/core/Schemas.ts index 90a044256..9255156c1 100644 --- a/src/core/Schemas.ts +++ b/src/core/Schemas.ts @@ -89,35 +89,6 @@ export type UpdateGameConfigIntent = z.infer< export type Turn = z.infer; export type GameConfig = z.infer; -const TICKS_PER_SECOND = 10; -const SPAWN_PHASE_TICKS = { - singleplayer: 100, - multiplayer: 300, -} as const; - -export function spawnPhaseTurns( - configOrGameType: - | Pick - | GameType - | string - | undefined, -): number { - return (typeof configOrGameType === "object" - ? configOrGameType?.gameType - : configOrGameType) === GameType.Singleplayer - ? SPAWN_PHASE_TICKS.singleplayer - : SPAWN_PHASE_TICKS.multiplayer; -} - -export function spawnPhaseSeconds( - configOrGameType: - | Pick - | GameType - | string - | undefined, -): number { - return spawnPhaseTurns(configOrGameType) / TICKS_PER_SECOND; -} export type ClientMessage = | ClientSendWinnerMessage diff --git a/src/core/configuration/Config.ts b/src/core/configuration/Config.ts index ac1d9ee4a..2329360ef 100644 --- a/src/core/configuration/Config.ts +++ b/src/core/configuration/Config.ts @@ -2,6 +2,7 @@ import { Colord } from "colord"; import { JWK } from "jose"; import { Game, + GameType, Gold, Player, PlayerInfo, @@ -27,6 +28,8 @@ export interface ServerConfig { turnstileSiteKey(): string; turnstileSecretKey(): string; turnIntervalMs(): number; + ticksPerSecond(): number; + spawnPhaseTicks(gameType: GameType): number; gameCreationRate(): number; numWorkers(): number; workerIndex(gameID: GameID): number; diff --git a/src/core/configuration/DefaultConfig.ts b/src/core/configuration/DefaultConfig.ts index e20d9dfc1..f4eaf07d0 100644 --- a/src/core/configuration/DefaultConfig.ts +++ b/src/core/configuration/DefaultConfig.ts @@ -4,6 +4,7 @@ import { Difficulty, Game, GameMode, + GameType, Gold, Player, PlayerInfo, @@ -17,12 +18,7 @@ import { import { TileRef } from "../game/GameMap"; import { PlayerView } from "../game/GameView"; import { UserSettings } from "../game/UserSettings"; -import { - GameConfig, - GameID, - spawnPhaseTurns, - TeamCountConfig, -} from "../Schemas"; +import { GameConfig, GameID, TeamCountConfig } from "../Schemas"; import { NukeType } from "../StatsSchemas"; import { assertNever, sigmoid, simpleHash, within } from "../Util"; import { Config, GameEnv, NukeMagnitude, ServerConfig, Theme } from "./Config"; @@ -121,6 +117,12 @@ 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; + } gameCreationRate(): number { return 60 * 1000; } @@ -546,7 +548,7 @@ export class DefaultConfig implements Config { return 3; } numSpawnPhaseTurns(): number { - return spawnPhaseTurns(this._gameConfig); + return this._serverConfig.spawnPhaseTicks(this._gameConfig.gameType); } numBots(): number { return this.bots(); diff --git a/src/server/GamePreviewBuilder.ts b/src/server/GamePreviewBuilder.ts index 036fb8320..ed5cef77d 100644 --- a/src/server/GamePreviewBuilder.ts +++ b/src/server/GamePreviewBuilder.ts @@ -1,6 +1,7 @@ import { z } from "zod"; -import { GameInfo, spawnPhaseSeconds } from "../core/Schemas"; -import { GameMode } from "../core/game/Game"; +import { ServerConfig } from "../core/configuration/Config"; +import { GameMode, GameType } from "../core/game/Game"; +import { GameInfo } from "../core/Schemas"; export const PlayerInfoSchema = z.object({ clientID: z.string().optional(), @@ -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"; @@ -180,9 +182,15 @@ export function buildPreview( const winner = parseWinner(publicInfo?.info?.winner, players); const duration = publicInfo?.info?.duration; const gameType = lobby?.gameConfig?.gameType ?? config.gameType; + const spawnPhaseSeconds = + serverConfig.spawnPhaseTicks( + gameType === GameType.Singleplayer + ? GameType.Singleplayer + : GameType.Public, + ) / serverConfig.ticksPerSecond(); const adjustedDuration = typeof duration === "number" - ? Math.max(0, duration - spawnPhaseSeconds(gameType)) + ? Math.max(0, duration - spawnPhaseSeconds) : undefined; // Normalize map name to match filesystem (lowercase, no spaces or special chars) diff --git a/src/server/GamePreviewRoute.ts b/src/server/GamePreviewRoute.ts index 01837ff19..acd95c26a 100644 --- a/src/server/GamePreviewRoute.ts +++ b/src/server/GamePreviewRoute.ts @@ -102,6 +102,7 @@ export function registerGamePreviewRoute(opts: { config.workerPath(gameID), lobby, publicInfo, + config, ); // Always serve HTML with meta tags for /game/:id route diff --git a/tests/util/TestServerConfig.ts b/tests/util/TestServerConfig.ts index 94b625943..39263b11f 100644 --- a/tests/util/TestServerConfig.ts +++ b/tests/util/TestServerConfig.ts @@ -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 { @@ -46,6 +46,12 @@ export class TestServerConfig implements ServerConfig { turnIntervalMs(): number { throw new Error("Method not implemented."); } + ticksPerSecond(): number { + throw new Error("Method not implemented."); + } + spawnPhaseTicks(gameType: GameType): number { + throw new Error("Method not implemented."); + } gameCreationRate(): number { throw new Error("Method not implemented."); }