mirror of
https://github.com/openfrontio/OpenFrontIO.git
synced 2026-06-21 11:30:43 +00:00
a8ec56b5a4
- Added TimelineController to manage timeline events and state. - Introduced TimelinePanel for user interaction with the timeline. - Implemented LruCache for efficient storage of timeline records. - Enhanced Transport and GameRenderer to support timeline features. - Updated various layers to respond to timeline events, ensuring synchronization with game state. - Added support for seeking and jumping within the timeline, improving user experience during gameplay. This commit lays the groundwork for a more interactive and responsive timeline feature in the game client.
117 lines
3.2 KiB
TypeScript
117 lines
3.2 KiB
TypeScript
import { describe, expect, it } from "vitest";
|
|
import type { Config } from "../src/core/configuration/Config";
|
|
import { UnitType } from "../src/core/game/Game";
|
|
import { GameMapImpl } from "../src/core/game/GameMap";
|
|
import {
|
|
GameUpdateType,
|
|
type GameUpdateViewData,
|
|
} from "../src/core/game/GameUpdates";
|
|
import { GameView } from "../src/core/game/GameView";
|
|
import type { TerrainMapData } from "../src/core/game/TerrainMapLoader";
|
|
import type { WorkerClient } from "../src/core/worker/WorkerClient";
|
|
|
|
function createEmptyGameUpdates() {
|
|
const updates: any = {};
|
|
for (const v of Object.values(GameUpdateType)) {
|
|
if (typeof v === "number") {
|
|
updates[v] = [];
|
|
}
|
|
}
|
|
return updates;
|
|
}
|
|
|
|
function createMinimalGameView(): GameView {
|
|
const w = 4;
|
|
const h = 3;
|
|
const terrain = new Uint8Array(w * h).fill(1 << 7); // land
|
|
const gameMap = new GameMapImpl(w, h, terrain, w * h);
|
|
const mapData: TerrainMapData = {
|
|
nations: [],
|
|
gameMap,
|
|
miniGameMap: gameMap,
|
|
};
|
|
|
|
return new GameView(
|
|
{} as unknown as WorkerClient,
|
|
{} as unknown as Config,
|
|
mapData,
|
|
"client1" as any,
|
|
"me",
|
|
"game1" as any,
|
|
[],
|
|
);
|
|
}
|
|
|
|
describe("GameView checkpoints", () => {
|
|
it("roundtrips a checkpoint (map, units, railroads, toDelete)", () => {
|
|
const view1 = createMinimalGameView();
|
|
|
|
const tileA = view1.ref(0, 0);
|
|
const tileB = view1.ref(1, 0);
|
|
const ownerA = 7;
|
|
const hasFallout = true;
|
|
const defenseBonus = true;
|
|
|
|
const stateA = ownerA;
|
|
const stateB =
|
|
3 /* owner */ | (hasFallout ? 1 << 13 : 0) | (defenseBonus ? 1 << 14 : 0);
|
|
|
|
const packedTileUpdates = new BigUint64Array([
|
|
(BigInt(tileA) << 16n) | BigInt(stateA),
|
|
(BigInt(tileB) << 16n) | BigInt(stateB),
|
|
]);
|
|
|
|
const updates = createEmptyGameUpdates();
|
|
updates[GameUpdateType.Unit].push({
|
|
type: GameUpdateType.Unit,
|
|
unitType: UnitType.City,
|
|
troops: 10,
|
|
id: 42,
|
|
ownerID: 1,
|
|
pos: tileA,
|
|
lastPos: tileA,
|
|
isActive: false,
|
|
reachedTarget: false,
|
|
retreating: false,
|
|
targetable: false,
|
|
markedForDeletion: false,
|
|
missileTimerQueue: [],
|
|
level: 1,
|
|
hasTrainStation: false,
|
|
});
|
|
updates[GameUpdateType.RailroadConstructionEvent].push({
|
|
type: GameUpdateType.RailroadConstructionEvent,
|
|
id: 99,
|
|
tiles: [tileA, tileB],
|
|
});
|
|
|
|
const gu: GameUpdateViewData = {
|
|
tick: 1,
|
|
packedTileUpdates,
|
|
updates,
|
|
playerNameViewData: {},
|
|
};
|
|
|
|
view1.update(gu);
|
|
const cp1 = view1.exportCheckpoint();
|
|
|
|
const view2 = createMinimalGameView();
|
|
view2.importCheckpoint(cp1);
|
|
const cp2 = view2.exportCheckpoint();
|
|
|
|
expect(view2.ticks()).toBe(1);
|
|
expect(view2.ownerID(tileA)).toBe(ownerA);
|
|
expect(view2.hasFallout(tileB)).toBe(true);
|
|
expect(((cp2.mapState[tileB] >> 14) & 1) === 1).toBe(true);
|
|
|
|
expect(cp2.toDeleteUnitIds).toEqual(cp1.toDeleteUnitIds);
|
|
expect(cp2.railroads).toEqual(cp1.railroads);
|
|
expect(Array.from(cp2.mapState)).toEqual(Array.from(cp1.mapState));
|
|
expect(cp2.numTilesWithFallout).toBe(cp1.numTilesWithFallout);
|
|
|
|
const unit = view2.unit(42);
|
|
expect(unit).toBeDefined();
|
|
expect(unit?.isActive()).toBe(false);
|
|
});
|
|
});
|