mirror of
https://github.com/openfrontio/OpenFrontIO.git
synced 2026-06-21 14:41:35 +00:00
275fd0dccc
## Description: This is a refactor to simplify config handling. Replaces the per-environment DevConfig/PreprodConfig/ProdConfig class hierarchy with two static classes: ClientEnv (browser main thread, reads from window.BOOTSTRAP_CONFIG) and ServerEnv (Node server, reads from process.env). The four config classes are deleted, the abstract DefaultServerConfig is gone, and DefaultConfig is renamed to Config. The values that flow server → client (gameEnv, numWorkers, turnstileSiteKey, jwtAudience, instanceId) used to be baked into the hardcoded per-env classes. They're now real env vars on the server, embedded into a single window.BOOTSTRAP_CONFIG object in index.html at request time (alongside the existing gitCommit/assetManifest/cdnBase globals, which moved into the same object), and read back by ClientEnv on the client. The dev defaults previously hidden inside DevServerConfig are now explicit in start:server-dev (NUM_WORKERS=2, TURNSTILE_SITE_KEY=1x..., JWT_AUDIENCE=localhost, etc.) and in vite.config.ts's html plugin inject.data. Production deploys plumb NUM_WORKERS and TURNSTILE_SITE_KEY through deploy.yml (GitHub vars) into the remote env file; JWT_AUDIENCE is derived from DOMAIN in deploy.sh. The dynamic /api/instance endpoint is gone — INSTANCE_ID rides along in BOOTSTRAP_CONFIG now. ServerEnv is the only thing server code touches; ClientEnv is browser-only. The two classes have intentional overlap (env, numWorkers, jwtIssuer, gameCreationRate, workerIndex, etc.) since they derive identical logic from different sources — there's a TODO in each to consolidate via a shared helper later. The game-logic Config no longer stores a ServerConfig/ClientEnv reference and its serverConfig() getter is gone; the one caller (MultiTabModal) now reads ClientEnv.env() directly. Worker init no longer carries server-config values since nothing in the worker actually reads them. ## Please complete the following: - [x] I have added screenshots for all UI updates - [x] I process any text displayed to the user through translateText() and I've added it to the en.json file - [x] I have added relevant tests to the test directory - [x] I confirm I have thoroughly tested these changes and take full responsibility for any bugs introduced ## Please put your Discord username so you can be contacted if a bug or regression is found: evan
174 lines
4.2 KiB
TypeScript
174 lines
4.2 KiB
TypeScript
// Minimal test maps for pathfinding unit tests
|
|
|
|
import {
|
|
Difficulty,
|
|
Game,
|
|
GameMapSize,
|
|
GameMapType,
|
|
GameMode,
|
|
GameType,
|
|
} from "../../../src/core/game/Game";
|
|
import { createGame as createGameImpl } from "../../../src/core/game/GameImpl";
|
|
import { GameMapImpl } from "../../../src/core/game/GameMap";
|
|
import { UserSettings } from "../../../src/core/game/UserSettings";
|
|
import { GameConfig } from "../../../src/core/Schemas";
|
|
import { TestConfig } from "../../util/TestConfig";
|
|
|
|
export const W = "W"; // Water
|
|
export const L = "L"; // Land
|
|
|
|
// Terrain encoding
|
|
const WATER_BIT = 0x20;
|
|
const LAND_BIT = 0x80;
|
|
const SHORELINE_BIT = 6;
|
|
|
|
export type TestMapData = {
|
|
width: number;
|
|
height: number;
|
|
grid: string[];
|
|
};
|
|
|
|
// Compute shoreline bit for tiles adjacent to opposite terrain
|
|
function computeShoreline(
|
|
terrain: Uint8Array,
|
|
width: number,
|
|
height: number,
|
|
): void {
|
|
for (let y = 0; y < height; y++) {
|
|
for (let x = 0; x < width; x++) {
|
|
const idx = y * width + x;
|
|
const isLand = (terrain[idx] & LAND_BIT) !== 0;
|
|
const neighbors = [
|
|
[x - 1, y],
|
|
[x + 1, y],
|
|
[x, y - 1],
|
|
[x, y + 1],
|
|
];
|
|
|
|
for (const [nx, ny] of neighbors) {
|
|
if (nx < 0 || nx >= width || ny < 0 || ny >= height) continue;
|
|
const neighborIsLand = (terrain[ny * width + nx] & LAND_BIT) !== 0;
|
|
if (isLand !== neighborIsLand) {
|
|
terrain[idx] |= 1 << SHORELINE_BIT;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// 5x5 simple island
|
|
export function createIslandMap(): TestMapData {
|
|
// prettier-ignore
|
|
const grid = [
|
|
W, W, W, W, W,
|
|
W, L, L, L, W,
|
|
W, L, L, L, W,
|
|
W, L, L, L, W,
|
|
W, W, W, W, W,
|
|
];
|
|
return { width: 5, height: 5, grid };
|
|
}
|
|
|
|
// Create Game from test map data (computes shoreline bits)
|
|
export function createGame(data: TestMapData): Game {
|
|
const { width, height, grid } = data;
|
|
|
|
// Convert string grid to terrain bytes
|
|
const terrain = new Uint8Array(width * height);
|
|
let numLand = 0;
|
|
|
|
for (let i = 0; i < grid.length; i++) {
|
|
if (grid[i] === L) {
|
|
terrain[i] = LAND_BIT;
|
|
numLand++;
|
|
} else {
|
|
terrain[i] = WATER_BIT;
|
|
}
|
|
}
|
|
|
|
computeShoreline(terrain, width, height);
|
|
|
|
const gameMap = new GameMapImpl(width, height, terrain, numLand);
|
|
|
|
// Create miniMap (2x2→1, water if ANY water)
|
|
const miniWidth = Math.ceil(width / 2);
|
|
const miniHeight = Math.ceil(height / 2);
|
|
const miniTerrain = new Uint8Array(miniWidth * miniHeight);
|
|
let miniNumLand = 0;
|
|
|
|
for (let my = 0; my < miniHeight; my++) {
|
|
for (let mx = 0; mx < miniWidth; mx++) {
|
|
const mIdx = my * miniWidth + mx;
|
|
let hasWater = false;
|
|
|
|
for (let dy = 0; dy < 2; dy++) {
|
|
for (let dx = 0; dx < 2; dx++) {
|
|
const x = mx * 2 + dx;
|
|
const y = my * 2 + dy;
|
|
if (x < width && y < height && !(terrain[y * width + x] & LAND_BIT)) {
|
|
hasWater = true;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (hasWater) {
|
|
miniTerrain[mIdx] = WATER_BIT;
|
|
} else {
|
|
miniTerrain[mIdx] = LAND_BIT;
|
|
miniNumLand++;
|
|
}
|
|
}
|
|
}
|
|
|
|
computeShoreline(miniTerrain, miniWidth, miniHeight);
|
|
|
|
const miniGameMap = new GameMapImpl(
|
|
miniWidth,
|
|
miniHeight,
|
|
miniTerrain,
|
|
miniNumLand,
|
|
);
|
|
|
|
const gameConfig: GameConfig = {
|
|
gameMap: GameMapType.Asia,
|
|
gameMapSize: GameMapSize.Normal,
|
|
gameMode: GameMode.FFA,
|
|
gameType: GameType.Singleplayer,
|
|
difficulty: Difficulty.Medium,
|
|
nations: "default",
|
|
donateGold: false,
|
|
donateTroops: false,
|
|
bots: 0,
|
|
infiniteGold: false,
|
|
infiniteTroops: false,
|
|
instantBuild: false,
|
|
disableNavMesh: false,
|
|
randomSpawn: false,
|
|
};
|
|
const config = new TestConfig(gameConfig, new UserSettings(), false);
|
|
|
|
return createGameImpl([], [], gameMap, miniGameMap, config);
|
|
}
|
|
|
|
// Create GameMapImpl from test map data (for map-only tests)
|
|
export function createGameMap(data: TestMapData): GameMapImpl {
|
|
const { width, height, grid } = data;
|
|
|
|
const terrain = new Uint8Array(width * height);
|
|
let numLand = 0;
|
|
|
|
for (let i = 0; i < grid.length; i++) {
|
|
if (grid[i] === L) {
|
|
terrain[i] = LAND_BIT;
|
|
numLand++;
|
|
} else {
|
|
terrain[i] = WATER_BIT;
|
|
}
|
|
}
|
|
|
|
computeShoreline(terrain, width, height);
|
|
|
|
return new GameMapImpl(width, height, terrain, numLand);
|
|
}
|