Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions src/client/AccountModal.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import {
UserMeResponse,
} from "../core/ApiSchemas";
import { assetUrl } from "../core/AssetUrls";
import { getServerConfigFromClient } from "../core/configuration/ConfigLoader";
import { getRuntimeClientServerConfig } from "../core/configuration/ConfigLoader";
import { fetchPlayerById, getUserMe } from "./Api";
import { discordLogin, logOut, sendMagicLink } from "./Auth";
import "./components/baseComponents/stats/DiscordUserHeader";
Expand Down Expand Up @@ -217,7 +217,7 @@ export class AccountModal extends BaseModal {

private async viewGame(gameId: string): Promise<void> {
this.close();
const config = await getServerConfigFromClient();
const config = await getRuntimeClientServerConfig();
const encodedGameId = encodeURIComponent(gameId);
const newUrl = `/${config.workerPath(gameId)}/game/${encodedGameId}`;

Expand Down
4 changes: 2 additions & 2 deletions src/client/ClientGameRunner.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import {
} from "../core/Schemas";
import { createPartialGameRecord, findClosestBy, replacer } from "../core/Util";
import { ServerConfig } from "../core/configuration/Config";
import { getConfig } from "../core/configuration/ConfigLoader";
import { getGameLogicConfig } from "../core/configuration/ConfigLoader";
import { BuildableUnit, Structures, UnitType } from "../core/game/Game";
import { TileRef } from "../core/game/GameMap";
import { GameMapLoader } from "../core/game/GameMapLoader";
Expand Down Expand Up @@ -214,7 +214,7 @@ async function createClientGame(
if (lobbyConfig.gameStartInfo === undefined) {
throw new Error("missing gameStartInfo");
}
const config = await getConfig(
const config = await getGameLogicConfig(
lobbyConfig.gameStartInfo.config,
userSettings,
lobbyConfig.gameRecord !== undefined,
Expand Down
4 changes: 2 additions & 2 deletions src/client/GameModeSelector.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { html, LitElement, nothing, type TemplateResult } from "lit";
import { customElement, state } from "lit/decorators.js";
import { getServerConfigFromClient } from "src/core/configuration/ConfigLoader";
import { getRuntimeClientServerConfig } from "src/core/configuration/ConfigLoader";
Copy link
Contributor

@coderabbitai coderabbitai bot Mar 24, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Inconsistent import path style.

This file uses src/core/configuration/ConfigLoader (absolute-style path), while other client files in this PR use relative paths like ../core/configuration/ConfigLoader. This inconsistency could cause issues depending on bundler configuration.

🔧 Suggested fix
-import { getRuntimeClientServerConfig } from "src/core/configuration/ConfigLoader";
+import { getRuntimeClientServerConfig } from "../core/configuration/ConfigLoader";
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/client/GameModeSelector.ts` at line 3, The import in GameModeSelector.ts
uses an absolute path; change the import of getRuntimeClientServerConfig to the
same relative style used elsewhere (e.g., import from
../core/configuration/ConfigLoader) so it matches other client files and avoids
bundler path issues—update the import statement that references
getRuntimeClientServerConfig accordingly.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

good spot, but out of scope for this

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@scamiv, understood — happy to leave it for a later cleanup pass. Would you like me to open a follow-up issue to track the import path style inconsistency in src/client/GameModeSelector.ts?


🧠 Learnings used
Learnt from: FloPinguin
Repo: openfrontio/OpenFrontIO PR: 3349
File: src/client/HostLobbyModal.ts:649-660
Timestamp: 2026-03-04T20:14:53.404Z
Learning: In `src/client/HostLobbyModal.ts`, `putGameConfig()` dispatches the entire game config object as a full replacement via `CustomEvent("update-game-config")` on every call (not a partial merge). Fields set to `undefined` in the config (e.g. `startingGold`, `goldMultiplier`, `maxTimerValue`) correctly signal "not set / cleared" to the server. There is no stale-value risk when these fields are `undefined`.

Learnt from: Aotumuri
Repo: openfrontio/OpenFrontIO PR: 786
File: src/core/Util.ts:4-4
Timestamp: 2025-06-07T13:15:55.439Z
Learning: In the OpenFrontIO codebase, JSON files should be imported using standard import syntax without import attributes, as the TypeScript configuration supports resolveJsonModule and the codebase already uses this pattern successfully in files like src/client/Cosmetic.ts.

Learnt from: Foorack
Repo: openfrontio/OpenFrontIO PR: 2141
File: src/client/ClientGameRunner.ts:228-234
Timestamp: 2025-10-08T17:14:49.369Z
Learning: In `ClientGameRunner.ts`, the `myPlayer` field is always set when `shouldPreventWindowClose()` is called, so the null check in that method is sufficient without needing to fetch it again from `gameView.playerByClientID()`.

Learnt from: ryanbarlow97
Repo: openfrontio/OpenFrontIO PR: 3298
File: src/server/Worker.ts:359-372
Timestamp: 2026-02-28T21:54:43.932Z
Learning: In src/server/Worker.ts, there are two distinct reconnect paths: (1) explicit "rejoin" messages (clientMsg.type === "rejoin") are sent during mid-game reconnects and don't contain a username field per the ClientRejoinMessage schema; (2) implicit reconnects via "join" messages (clientMsg.type === "join") from existing clients handle page refreshes in pre-game and do contain username. Only the implicit path should pass newUsername to gm.rejoinClient because the explicit rejoin message doesn't have that field.

Learnt from: ryanbarlow97
Repo: openfrontio/OpenFrontIO PR: 2975
File: src/client/JoinPublicLobbyModal.ts:39-54
Timestamp: 2026-01-31T21:39:22.022Z
Learning: In src/client/JoinPublicLobbyModal.ts, the msUntilStart value received from lobby_info messages is a fixed timestamp (not a duration) set when the lobby is created on the server (this.createdAt + this.config.gameCreationRate()). It does not update on each broadcast. The client must subtract Date.now() to convert it to a relative duration before using it with countdown timers.

Learnt from: ryanbarlow97
Repo: openfrontio/OpenFrontIO PR: 2975
File: src/client/JoinLobbyModal.ts:482-493
Timestamp: 2026-01-31T21:28:44.679Z
Learning: In src/client/JoinLobbyModal.ts, the msUntilStart value received from lobby_info messages is a duration in milliseconds (not a fixed timestamp). The client adds Date.now() to convert it to an absolute timestamp for storage in lobbyStartAt, then subtracts Date.now() when displaying the countdown to get the remaining seconds.

Learnt from: VariableVince
Repo: openfrontio/OpenFrontIO PR: 1110
File: src/client/Main.ts:293-295
Timestamp: 2025-06-09T02:20:43.637Z
Learning: In src/client/Main.ts, during game start in the handleJoinLobby callback, UI elements are hidden using direct DOM manipulation with classList.add("hidden") for consistency. This includes modals, buttons, and error divs. The codebase follows this pattern rather than using component APIs for hiding elements during game transitions.

Learnt from: ryanbarlow97
Repo: openfrontio/OpenFrontIO PR: 2740
File: src/client/HostLobbyModal.ts:821-821
Timestamp: 2026-01-02T18:11:15.132Z
Learning: In src/client/HostLobbyModal.ts, the `?s=xxxxx` URL suffix in lobby URLs is purely for cache-busting embed previews on platforms like Discord, WhatsApp, and x.com. The suffix value is ignored by the join logic (any value works), so regenerating it on config changes via `updateUrlWithSuffix()` doesn't break existing shared URLs - it only forces platforms to re-fetch updated preview metadata.

Learnt from: FloPinguin
Repo: openfrontio/OpenFrontIO PR: 2689
File: src/client/PublicLobby.ts:245-245
Timestamp: 2025-12-26T22:21:21.904Z
Learning: In public lobbies with HumansVsNations mode in src/client/PublicLobby.ts, maxPlayers represents only human player slots (already halved in DefaultConfig.ts). The nation NPCs are added automatically server-side and don't count toward maxPlayers. Therefore, getTeamSize correctly returns maxPlayers directly for HumansVsNations to display the proper team size (e.g., maxPlayers=5 yields "5 Humans vs 5 Nations").

Learnt from: scottanderson
Repo: openfrontio/OpenFrontIO PR: 1752
File: src/core/game/Game.ts:750-752
Timestamp: 2025-08-12T00:31:50.144Z
Learning: In the OpenFrontIO codebase, changes to the PlayerInteraction interface (like adding canDonateGold and canDonateTroops flags) do not require corresponding updates to src/core/Schemas.ts or server serialization code.

Learnt from: andrewNiziolek
Repo: openfrontio/OpenFrontIO PR: 1007
File: resources/lang/de.json:115-115
Timestamp: 2025-06-02T14:27:37.609Z
Learning: For OpenFrontIO project: When localization keys are renamed in language JSON files, the maintainers separate technical changes from translation content updates. They wait for community translators to update the actual translation values rather than attempting to translate in the same PR. This allows technical changes to proceed while ensuring accurate translations from native speakers.

Learnt from: FloPinguin
Repo: openfrontio/OpenFrontIO PR: 2874
File: src/server/MapLandTiles.ts:7-11
Timestamp: 2026-01-12T21:37:01.156Z
Learning: In this repository's OpenFrontIO deployment, inter-service HTTP calls to the master should target http://localhost:3000 (master at port 3000) as the canonical address. Apply this as the standard for all server-side TypeScript code that communicates with the master. Avoid hardcoding non-master URLs; centralize the master address (e.g., via config or env) when possible, and ensure internal service communication uses localhost:3000 in this architecture.

Learnt from: FloPinguin
Repo: openfrontio/OpenFrontIO PR: 2887
File: src/core/execution/NukeExecution.ts:118-122
Timestamp: 2026-01-13T20:16:05.535Z
Learning: In code paths that return a Player-like object, prefer returning a union type (Player | TerraNullius) instead of undefined. When a function may fail to find a player, return TerraNullius for the 'not found' case and a Player for valid IDs, and check .isPlayer() (or equivalent) directly on the result instead of guarding with undefined or optional chaining. This should be enforced in Game, GameImpl, and GameView (and similar accessors) to avoid undefined checks and simplify null-safety handling.

Learnt from: evanpelle
Repo: openfrontio/OpenFrontIO PR: 3114
File: src/client/graphics/layers/AttacksDisplay.ts:64-77
Timestamp: 2026-02-10T05:02:28.715Z
Learning: In the OpenFrontIO codebase, GameUpdateType maps always have an array value for each key (never undefined). When iterating, you can safely use: for (const event of updates[GameUpdateType.X]) without optional chaining or guards. Treat updates as a Record<GameUpdateType, any[]> and rely on its guaranteed array values. If you modify the type, ensure the guarantee remains (e.g., initialize missing keys to []) to preserve safe iteration.

Learnt from: wozniakpl
Repo: openfrontio/OpenFrontIO PR: 3317
File: src/client/InputHandler.ts:344-350
Timestamp: 2026-03-07T11:35:24.071Z
Learning: Ensure ghost preservation logic for special units (AtomBomb and HydrogenBomb) is implemented via shouldPreserveGhostAfterBuild(unitType) and that ghost removal is conditional on !shouldPreserveGhostAfterBuild(unitType) within createStructure. Confirm that both mouse (MouseUpEvent) and keyboard (ConfirmGhostStructureEvent) confirmation paths go through requestConfirmStructure → createStructure, and that Enter/NumpadEnter confirmations do not break the locked-nuke multi-placement since the ghost should be preserved by design. Add tests to cover shouldPreserveGhostAfterBuild returning true for AtomBomb/HydrogenBomb and verify that ghost removal only occurs for other units. Applies to files in the repository OpenFrontIO (src/client/InputHandler.ts and src/client/graphics/layers/StructureIconsLayer.ts).

import {
Duos,
GameMapType,
Expand Down Expand Up @@ -58,7 +58,7 @@ export class GameModeSelector extends LitElement {
connectedCallback() {
super.connectedCallback();
this.lobbySocket.start();
getServerConfigFromClient().then((config) => {
getRuntimeClientServerConfig().then((config) => {
this.defaultLobbyTime = config.gameCreationRate() / 1000;
});
}
Expand Down
8 changes: 4 additions & 4 deletions src/client/HostLobbyModal.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { html } from "lit";
import { customElement, property, state } from "lit/decorators.js";
import { translateText } from "../client/Utils";
import { getServerConfigFromClient } from "../core/configuration/ConfigLoader";
import { getRuntimeClientServerConfig } from "../core/configuration/ConfigLoader";
import { EventBus } from "../core/EventBus";
import {
Difficulty,
Expand Down Expand Up @@ -113,7 +113,7 @@ export class HostLobbyModal extends BaseModal {
return link;
}
}
const config = await getServerConfigFromClient();
const config = await getRuntimeClientServerConfig();
return `${window.location.origin}/${config.workerPath(this.lobbyId)}/game/${this.lobbyId}?lobby&s=${encodeURIComponent(this.lobbyUrlSuffix)}`;
}

Expand Down Expand Up @@ -823,7 +823,7 @@ export class HostLobbyModal extends BaseModal {
// If the modal closes as part of starting the game, do not leave the lobby
this.leaveLobbyOnClose = false;

const config = await getServerConfigFromClient();
const config = await getRuntimeClientServerConfig();
const response = await fetch(
`${window.location.origin}/${config.workerPath(this.lobbyId)}/api/start_game/${this.lobbyId}`,
{
Expand Down Expand Up @@ -871,7 +871,7 @@ export class HostLobbyModal extends BaseModal {
}

async function createLobby(gameID: string): Promise<GameInfo> {
const config = await getServerConfigFromClient();
const config = await getRuntimeClientServerConfig();
// Send JWT token for creator identification - server extracts persistentID from it
// persistentID should never be exposed to other clients
const token = await getPlayToken();
Expand Down
4 changes: 2 additions & 2 deletions src/client/JoinLobbyModal.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ import {
LobbyInfoEvent,
PublicGameInfo,
} from "../core/Schemas";
import { getServerConfigFromClient } from "../core/configuration/ConfigLoader";
import { getRuntimeClientServerConfig } from "../core/configuration/ConfigLoader";
import {
Difficulty,
GameMapSize,
Expand Down Expand Up @@ -897,7 +897,7 @@ export class JoinLobbyModal extends BaseModal {
}

private async checkActiveLobby(lobbyId: string): Promise<boolean> {
const config = await getServerConfigFromClient();
const config = await getRuntimeClientServerConfig();
const url = `/${config.workerPath(lobbyId)}/api/game/${lobbyId}/exists`;

const response = await fetch(url, {
Expand Down
4 changes: 2 additions & 2 deletions src/client/LobbySocket.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { getServerConfigFromClient } from "../core/configuration/ConfigLoader";
import { getRuntimeClientServerConfig } from "../core/configuration/ConfigLoader";
import { PublicGames, PublicGamesSchema } from "../core/Schemas";

interface LobbySocketOptions {
Expand Down Expand Up @@ -35,7 +35,7 @@ export class PublicLobbySocket {
this.stopped = false;
this.wsConnectionAttempts = 0;
// Get config to determine number of workers, then pick a random one
const config = await getServerConfigFromClient();
const config = await getRuntimeClientServerConfig();
this.workerPath = getRandomWorkerPath(config.numWorkers());
this.connectWebSocket();
}
Expand Down
10 changes: 5 additions & 5 deletions src/client/Main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import {
PublicGameInfo,
} from "../core/Schemas";
import { GameEnv } from "../core/configuration/Config";
import { getServerConfigFromClient } from "../core/configuration/ConfigLoader";
import { getRuntimeClientServerConfig } from "../core/configuration/ConfigLoader";
import { GameType } from "../core/game/Game";
import { UserSettings } from "../core/game/UserSettings";
import "./AccountModal";
Expand Down Expand Up @@ -749,7 +749,7 @@ class Client {
if (lobby.source === "public") {
this.joinModal?.open(lobby.gameID, lobby.publicLobbyInfo);
}
const config = await getServerConfigFromClient();
const config = await getRuntimeClientServerConfig();
// Only update URL immediately for private lobbies, not public ones
if (lobby.source !== "public") {
this.updateJoinUrlForShare(lobby.gameID, config);
Expand Down Expand Up @@ -857,7 +857,7 @@ class Client {

private updateJoinUrlForShare(
lobbyId: string,
config: Awaited<ReturnType<typeof getServerConfigFromClient>>,
config: Awaited<ReturnType<typeof getRuntimeClientServerConfig>>,
) {
const lobbyIdHidden = !this.userSettings.lobbyIdVisibility();
const targetUrl = lobbyIdHidden
Expand Down Expand Up @@ -930,7 +930,7 @@ class Client {
private async getTurnstileToken(
lobby: JoinLobbyEvent,
): Promise<string | null> {
const config = await getServerConfigFromClient();
const config = await getRuntimeClientServerConfig();
if (
config.env() === GameEnv.Dev ||
lobby.gameStartInfo?.config.gameType === GameType.Singleplayer
Expand Down Expand Up @@ -1008,7 +1008,7 @@ async function getTurnstileToken(): Promise<{
throw new Error("Failed to load Turnstile script");
}

const config = await getServerConfigFromClient();
const config = await getRuntimeClientServerConfig();
const widgetId = window.turnstile.render("#turnstile-container", {
sitekey: config.turnstileSiteKey(),
size: "normal",
Expand Down
6 changes: 3 additions & 3 deletions src/client/Matchmaking.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { html, LitElement } from "lit";
import { customElement, state } from "lit/decorators.js";
import { UserMeResponse } from "../core/ApiSchemas";
import { getServerConfigFromClient } from "../core/configuration/ConfigLoader";
import { getRuntimeClientServerConfig } from "../core/configuration/ConfigLoader";
import { getUserMe, hasLinkedAccount } from "./Api";
import { getPlayToken } from "./Auth";
import { BaseModal } from "./components/BaseModal";
Expand Down Expand Up @@ -87,7 +87,7 @@ export class MatchmakingModal extends BaseModal {
}

private async connect() {
const config = await getServerConfigFromClient();
const config = await getRuntimeClientServerConfig();
const instanceId = await MatchmakingModal.getInstanceId();

this.socket = new WebSocket(
Expand Down Expand Up @@ -210,7 +210,7 @@ export class MatchmakingModal extends BaseModal {
if (this.gameID === null) {
return;
}
const config = await getServerConfigFromClient();
const config = await getRuntimeClientServerConfig();
const url = `/${config.workerPath(this.gameID)}/api/game/${this.gameID}/exists`;

const response = await fetch(url, {
Expand Down
4 changes: 2 additions & 2 deletions src/client/components/CopyButton.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { LitElement, html } from "lit";
import { customElement, property, state } from "lit/decorators.js";
import { getServerConfigFromClient } from "../../core/configuration/ConfigLoader";
import { getRuntimeClientServerConfig } from "../../core/configuration/ConfigLoader";
import { UserSettings } from "../../core/game/UserSettings";
import { crazyGamesSDK } from "../CrazyGamesSDK";
import { copyToClipboard, translateText } from "../Utils";
Expand Down Expand Up @@ -66,7 +66,7 @@ export class CopyButton extends LitElement {
}

private async buildCopyUrl(): Promise<string> {
const config = await getServerConfigFromClient();
const config = await getRuntimeClientServerConfig();
let url = `${window.location.origin}/${config.workerPath(this.lobbyId)}/game/${this.lobbyId}`;
if (this.includeLobbyQuery) {
url += `?lobby&s=${encodeURIComponent(this.lobbySuffix)}`;
Expand Down
4 changes: 2 additions & 2 deletions src/core/GameRunner.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { placeName } from "../client/graphics/NameBoxCalculator";
import { getConfig } from "./configuration/ConfigLoader";
import { getGameLogicConfig } from "./configuration/ConfigLoader";
import { Executor } from "./execution/ExecutionManager";
import { RecomputeRailClusterExecution } from "./execution/RecomputeRailClusterExecution";
import { WinCheckExecution } from "./execution/WinCheckExecution";
Expand Down Expand Up @@ -35,7 +35,7 @@ export async function createGameRunner(
mapLoader: GameMapLoader,
callBack: (gu: GameUpdateViewData | ErrorUpdate) => void,
): Promise<GameRunner> {
const config = await getConfig(gameStart.config, null);
const config = await getGameLogicConfig(gameStart.config, null);
const gameMap = await loadGameMap(
gameStart.config.gameMap,
gameStart.config.gameMapSize,
Expand Down
91 changes: 69 additions & 22 deletions src/core/configuration/ConfigLoader.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,18 @@
import { UserSettings } from "../game/UserSettings";
import { GameConfig } from "../Schemas";
import { Config, GameEnv, ServerConfig } from "./Config";
import { Config, ServerConfig } from "./Config";
import { DefaultConfig } from "./DefaultConfig";
import { DevConfig, DevServerConfig } from "./DevConfig";
import { Env } from "./Env";
import { preprodConfig } from "./PreprodConfig";
import { prodConfig } from "./ProdConfig";

export let cachedSC: ServerConfig | null = null;
export enum GameLogicEnv {
Dev = "dev",
Default = "default",
}

export let cachedRuntimeClientServerConfig: ServerConfig | null = null;

declare global {
interface Window {
Expand All @@ -17,35 +22,77 @@ declare global {
}
}

export async function getConfig(
export async function getGameLogicConfig(
gameConfig: GameConfig,
userSettings: UserSettings | null,
isReplay: boolean = false,
): Promise<Config> {
const sc = await getServerConfigFromClient();
switch (sc.env()) {
case GameEnv.Dev:
return new DevConfig(sc, gameConfig, userSettings, isReplay);
case GameEnv.Preprod:
case GameEnv.Prod:
console.log("using prod config");
return new DefaultConfig(sc, gameConfig, userSettings, isReplay);
const gameLogicEnv = getBuildTimeGameLogicEnv();
const serverConfig = getServerConfigForGameLogicEnv(gameLogicEnv);

switch (gameLogicEnv) {
case GameLogicEnv.Dev:
return new DevConfig(serverConfig, gameConfig, userSettings, isReplay);
case GameLogicEnv.Default:
return new DefaultConfig(
serverConfig,
gameConfig,
userSettings,
isReplay,
);
default:
throw Error(`unsupported game logic environment: ${gameLogicEnv}`);
}
}

export function getBuildTimeGameLogicEnv(): GameLogicEnv {
const bundledGameEnv = process.env.GAME_ENV;

switch (bundledGameEnv) {
case "dev":
return GameLogicEnv.Dev;
case "staging":
case "prod":
return GameLogicEnv.Default;
case undefined:
throw new Error("Missing bundled game logic env");
default:
throw Error(`unsupported bundled game logic env: ${bundledGameEnv}`);
}
}

export function getServerConfigForGameLogicEnv(
gameLogicEnv: GameLogicEnv,
): ServerConfig {
switch (gameLogicEnv) {
case GameLogicEnv.Dev:
return new DevServerConfig();
case GameLogicEnv.Default:
console.log("using default game logic config");
return prodConfig;
default:
throw Error(`unsupported server configuration: ${Env.GAME_ENV}`);
throw Error(`unsupported game logic environment: ${gameLogicEnv}`);
}
}
export async function getServerConfigFromClient(): Promise<ServerConfig> {
if (cachedSC) {
return cachedSC;

export async function getRuntimeClientServerConfig(): Promise<ServerConfig> {
if (cachedRuntimeClientServerConfig) {
return cachedRuntimeClientServerConfig;
}

if (typeof window === "undefined") {
throw new Error(
"Runtime client server config is only available on the browser main thread",
);
}

const bootstrapGameEnv = window.BOOTSTRAP_CONFIG?.gameEnv;
if (!bootstrapGameEnv) {
throw new Error("Missing bootstrap server config");
const runtimeClientEnv = window.BOOTSTRAP_CONFIG?.gameEnv;
if (!runtimeClientEnv) {
throw new Error("Missing runtime client server config");
}

cachedSC = getServerConfig(bootstrapGameEnv);
return cachedSC;
cachedRuntimeClientServerConfig = getServerConfig(runtimeClientEnv);
return cachedRuntimeClientServerConfig;
}
export function getServerConfigFromServer(): ServerConfig {
const gameEnv = Env.GAME_ENV;
Expand All @@ -67,6 +114,6 @@ export function getServerConfig(gameEnv: string) {
}
}

export function clearCachedServerConfig(): void {
cachedSC = null;
export function clearCachedRuntimeClientServerConfig(): void {
cachedRuntimeClientServerConfig = null;
}
Loading
Loading