Use SharedArrayBuffer tile state and ring buffer for worker updates

- Share GameMapImpl tile state between worker and main via SharedArrayBuffer
- Add SAB-backed tile update ring buffer to stream tile changes instead of postMessage payloads
- Wire shared state/ring through WorkerClient, Worker.worker, GameRunner, and ClientGameRunner
- Update GameView to skip updateTile when shared state is enabled and consume tile refs from the ring
This commit is contained in:
scamiv
2025-12-11 17:17:54 +01:00
parent 05181d7479
commit 314d8ef25a
8 changed files with 75 additions and 9 deletions
+13 -3
View File
@@ -479,6 +479,7 @@ export class GameView implements GameMap {
private _cosmetics: Map<string, PlayerCosmetics> = new Map();
private _map: GameMap;
private readonly usesSharedTileState: boolean;
constructor(
public worker: WorkerClient,
@@ -487,8 +488,10 @@ export class GameView implements GameMap {
private _myClientID: ClientID,
private _gameID: GameID,
private humans: Player[],
usesSharedTileState: boolean = false,
) {
this._map = this._mapData.gameMap;
this.usesSharedTileState = usesSharedTileState;
this.lastUpdate = null;
this.unitGrid = new UnitGrid(this._map);
this._cosmetics = new Map(
@@ -517,9 +520,16 @@ export class GameView implements GameMap {
this.lastUpdate = gu;
this.updatedTiles = [];
this.lastUpdate.packedTileUpdates.forEach((tu) => {
this.updatedTiles.push(this.updateTile(tu));
});
if (this.usesSharedTileState) {
this.lastUpdate.packedTileUpdates.forEach((tu) => {
const tileRef = Number(tu >> 16n);
this.updatedTiles.push(tileRef);
});
} else {
this.lastUpdate.packedTileUpdates.forEach((tu) => {
this.updatedTiles.push(this.updateTile(tu));
});
}
if (gu.updates === null) {
throw new Error("lastUpdate.updates not initialized");