mirror of
https://github.com/openfrontio/OpenFrontIO.git
synced 2026-07-18 21:43:06 +00:00
crit fix: indian subcontinent map crash (#4479)
Resolves #4401 NOTE: While this PR is an improvment, the Indian subcontinent crash IS NOT caused by >253 water components, as the map only has ~15 water components. ## Description: Fixes a critical browser tab crash ("Aw, Snap! Something went wrong") when loading the game on the new Indian Subcontinent map (or any map with >= 253 water components) in Solo Mode. ### Technical Cause: 1. When a map contains >= 253 disconnected water components, the array mapping tiles to component IDs is dynamically promoted from a Uint8Array to a Uint16Array. 2. This promotion upgrades the land sentinel LAND_MARKER from 0xff (255) to LAND_MARKER_WIDE (0xffff / 65535). 3. The BFS local search filter in AStarWaterHierarchical had a hardcoded sentinel check: (t: TileRef) => this.graph.getComponentId(t) !== LAND_MARKER (evaluating against 255). 4. On promoted maps, land tiles (65535) matched this check as water. The local BFS then traversed the entire landmass of the map, resulting in CPU exhaustion and memory/stack overflows that crashed the rendering process. ### Solution: Changed the hardcoded sentinel check to query the map's terrain directly via this.map.isWater(t). This makes the check immune to any component ID promotions or sentinel representation upgrades. Verified that the existing water pathfinding test suite passes successfully. ## Please complete the following: - [ ] I have added screenshots for all UI updates (N/A) - [ ] I process any text displayed to the user through translateText() and I've added it to the en.json file (N/A) - [x] I have added relevant tests to the test directory (Existing tests in tests/core/pathfinding/PathFinding.Water.test.ts cover water pathfinding behavior and run successfully) ## Please put your Discord username so you can be contacted if a bug or regression is found: blontd6
This commit is contained in:
@@ -12,6 +12,7 @@ import { createGame, L, W } from "./_fixtures";
|
||||
describe("PathFinding.Water", () => {
|
||||
let game: Game;
|
||||
let worldGame: Game;
|
||||
let giantWorldGame: Game;
|
||||
|
||||
function createPathFinder(g: Game = game): SteppingPathFinder<TileRef> {
|
||||
return PathFinding.Water(g);
|
||||
@@ -20,6 +21,7 @@ describe("PathFinding.Water", () => {
|
||||
beforeAll(async () => {
|
||||
game = await setup("ocean_and_land");
|
||||
worldGame = await setup("world", { disableNavMesh: false });
|
||||
giantWorldGame = await setup("giantworldmap", { disableNavMesh: false });
|
||||
});
|
||||
|
||||
describe("findPath", () => {
|
||||
@@ -274,4 +276,23 @@ describe("PathFinding.Water", () => {
|
||||
expect(path).not.toBeNull();
|
||||
});
|
||||
});
|
||||
|
||||
describe("Giant World Map routes", () => {
|
||||
it("routes correctly in promoted components", () => {
|
||||
const pathFinder = createPathFinder(giantWorldGame);
|
||||
const map = giantWorldGame.map();
|
||||
|
||||
// Coordinates inside Component 459 in map4x (promoted)
|
||||
const from = map.ref(2616, 452);
|
||||
const to = map.ref(2676, 474);
|
||||
|
||||
expect(map.isWater(from)).toBe(true);
|
||||
expect(map.isWater(to)).toBe(true);
|
||||
|
||||
const path = pathFinder.findPath(from, to);
|
||||
expect(path).not.toBeNull();
|
||||
expect(path![0]).toBe(from);
|
||||
expect(path![path!.length - 1]).toBe(to);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user