Commit Graph

2789 Commits

Author SHA1 Message Date
scamiv a91e82b162 test 2025-12-05 14:45:01 +01:00
scamiv abe62e27da Add tick interpolation support to TerritoryLayer and WebGLRenderer
- Introduced tick management in TerritoryLayer with lastTickSeen, tickParity, and tickDurationMs properties.

- Updated tick method to handle tile updates based on the current tick and manage WebGL rendering timing.

- Enhanced TerritoryRendererStrategy interface with new methods for updating tile arrival and setting tick timing.

- Implemented arrival phase and tick parity handling in TerritoryWebGLRenderer, including texture updates for changed tiles.

- Improved shader logic to manage visibility of tiles based on tick progress and arrival phase.
2025-12-05 14:37:47 +01:00
scamiv 5ce27d28c9 Enhance shared tile ring initialization in Worker.worker.ts
- Updated the initialization logic to include a check for sharedDirtyBuffer alongside sharedTileRingHeader and sharedTileRingData, ensuring all necessary data is present before creating sharedTileRing views.
2025-12-04 16:42:13 +01:00
scamiv 0d1769fc92 Refactor GameImpl and GameView methods to remove unnecessary return statements
- Updated setOwnerID, setDefended, forEachTile, and setFallout methods in GameImpl and GameView to eliminate redundant return statements
2025-12-04 16:36:57 +01:00
scamiv 8752642e46 add comment to unused labelUpload method and clean up removeUnit ordering
- Move unitGrid.removeUnit() call to beginning of removeUnit method
  for cleaner code organization
2025-12-04 16:33:15 +01:00
scamiv 84bb2e0e65 Removed legacy border color texture and all related plumbing
In src/client/graphics/layers/TerritoryWebGLRenderer.ts:
- Deleted borderColorTexture, borderColorData, borderDirtyRows, borderNeedsFullUpload.
- Removed setBorderColor, clearBorderColor, markBorderDirty, and uploadBorderTexture, plus the extra profiling calls.
- Dropped the u_borderColor uniform from both the uniform map and the fragment shader.
- Removed all texture creation/binding/uniform setup for the old border color texture; only u_state, u_palette, and u_relations remain.

The WebGL renderer now relies solely on the palette + relations + state buffers for borders.
2025-12-04 03:20:10 +01:00
scamiv 84bcf6fb55 Removed old per-tile relation handling; relations are now handled via the u_relations texture in TerritoryWebGLRenderer 2025-12-04 02:57:06 +01:00
scamiv bbf768025e Refactor territory defense management in GameImpl and CanvasTerritoryRenderer
- Consolidated defended state logic for tiles into dedicated methods in GameImpl to improve clarity and maintainability.
- Updated CanvasTerritoryRenderer to utilize the new isDefended method for determining tile defense status.
- Removed redundant checks and streamlined the painting logic for territory tiles.
2025-12-04 00:46:38 +01:00
scamiv 8752d55817 Move relationship calculation (for borders) into the shader.
- GPU Relation Calculations: Moved border diplomatic relation logic from CPU buffer to WebGL shader, eliminating per-tile CPU computation
- Relation Matrix: Converted 1D relation array to 2D owner×other matrix for O(1) GPU lookups
- Palette Refresh: Batched palette refreshes to single call per update cycle

WebGL Shader Updates
- Added u_viewerId uniform and bitmask relation helper functions (isFriendly(), isEmbargo(), isSelf())
- Enhanced border detection with per-neighbor relation evaluation
Removed CPU-side relation state management

Files: TerritoryLayer.ts, TerritoryRenderers.ts, TerritoryWebGLRenderer.ts (+102/-39 lines)
2025-12-03 20:01:43 +01:00
scamiv 99b7c54c93 fix TerritoryWebGLRenderer premultiplied alpha 2025-12-03 18:05:57 +01:00
scamiv ad2a96cbbe Revert "test replayspeed"
This reverts commit 33ea33d4df.
2025-12-03 17:49:23 +01:00
scamiv 33ea33d4df test replayspeed 2025-11-29 12:25:07 +01:00
scamiv 95519ce5cc update comment 2025-11-28 20:52:22 +01:00
scamiv a15fcdf132 Update WebGL status message 2025-11-28 20:04:37 +01:00
scamiv ff4d8c9d6f Implement territory defense and relation management in GameMap and renderers; update WebGL shader 2025-11-28 19:20:32 +01:00
scamiv a9c1c408ca Update GameRenderer and TerritoryLayer for improved performance profiling; adjust minimum FPS and enhance layer profiling with new profileName method. Refactor rendering logic in Canvas and WebGL territory renderers . 2025-11-28 18:40:16 +01:00
scamiv 8077008ceb Refactor TerritoryLayer to use a strategy pattern for territory rendering; remove unused ToggleTerritoryWebGLDebugBordersEvent and BorderRenderer interface. Update imports and rendering logic to accommodate new CanvasTerritoryRenderer and WebglTerritoryRenderer classes. 2025-11-28 17:52:38 +01:00
scamiv fb30bf8f69 Remove unused HoverTargetResolver and TerritoryBorderWebGL files; update imports in PlayerInfoOverlay, TerritoryLayer, and other files to use new HoverTarget module. 2025-11-28 17:04:16 +01:00
scamiv 990b698845 fixes 2025-11-28 14:34:37 +01:00
scamiv a9a29614ea territory 2025-11-28 05:27:19 +01:00
scamiv aba4030b6d Merge branch 'sab' into webgl-territory-worker 2025-11-28 04:21:59 +01:00
FloPinguin ab53ee687f Alliance icon does no longer stretch/disappear 🖌️ (#2527)
Resolves #2521

## Description:

Small CSS fix so the new alliance icon does not stretch when there are
multiple icons.

## 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:

FloPinguin
2025-11-26 19:50:58 -08:00
FloPinguin 41deef9e96 Nations no longer send random boats to their bordering enemies 🚢 (#2526)
## Description:

Nations no longer send random boats to their bordering enemies.

Usually it looked a bit stupid when nations did that ("Why don't you
attack your bordering enemy directly?")

## 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:

FloPinguin
2025-11-26 19:42:50 -08:00
DevelopingTom c38c25ab1e Add factory & train emojis (#2522)
## Description:

Add 🏭 & 🚂 emojis, which is commonly requested. Also 3 other emojis to
fill the new emoji line: 🫴🙏

To be discussed: this adds a new line in the emoji list: is it too much?
Eventually we could use categories to filter the emojis.

<img width="199" height="465" alt="image"
src="https://github.com/user-attachments/assets/cb6a44e9-30cd-48f7-90ab-8a7c32dcd180"
/>

## 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:

IngloriousTom
2025-11-26 16:39:52 -08:00
CrackeRR11 8f53785a80 BUG FIX: Gold double deduction + Rmoval of UnitType.Construction (#2378)
## Description:

- Removed the temporary UnitType.Construction and embedded construction
state into real units via isUnderConstruction().
- Centralized non-structure spawning to perform a single validation
right before unit creation/launch.
- Updated UI layers to render construction state without relying on the
removed enum.
- Adjusted and created tests to match the new flow and to cover the
no-refundscenarios.

# Tests updated 
- tests/economy/ConstructionGold.test.ts: covers structure cost
deduction and income, tolerant of passive income; ensures no refunds
during construction.
- tests/nukes/HydrogenAndMirv.test.ts: accounts for single-check launch
flow; MIRV test targets a player-owned tile; ensures launch after
payment.
- tests/client/graphics/UILayer.test.ts: mocks now provide
isUnderConstruction and real type strings;

## 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:

CrackeRR1

---------

Co-authored-by: Evan <evanpelle@gmail.com>
2025-11-26 14:45:14 -08:00
VariableVince c341aafaf9 Fix: 'Mini Map' to 'Compact Map' for Private Lobby Modal (#2520)
## Description:

Fix for v27.

In commit
https://github.com/openfrontio/OpenFrontIO/commit/91ff1c0e538b80825fd4374b936763923905cb1d,
the name of Mini Map was changed to Compact Map. But it was only done
for the Single Player modal by mistake. This PR also changes it for the
Host Lobby Modal.

## 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:

tryout33
2025-11-26 21:09:52 +00:00
scamiv 1e3d2e10f3 overflows field now acts as a bool 2025-11-26 22:02:12 +01:00
scamiv 7e2784eee2 refactored loadTerrainMap to reuse the existing canUseSharedBuffers 2025-11-26 21:55:37 +01:00
scamiv 81b0d36c38 disable TerrainMapData cache for SAB path 2025-11-26 21:53:49 +01:00
scamiv c1bc4a7d1c removed console.log 2025-11-26 21:35:22 +01:00
scamiv 75a9465f5a Size SAB ring buffer by world tile count 2025-11-26 21:35:21 +01:00
scamiv 5a8c0b636d Use dirty flags to coalesce tile updates in SAB ring
- Extend SharedTileRing to include a shared dirtyFlags buffer alongside header and data
- Pass shared dirty buffer through WorkerClient/WorkerMessages and initialize views in Worker.worker
- In SAB mode, mark tiles dirty via Atomics.compareExchange before enqueuing to ensure each tile is queued at most once until processed
- On the main thread, clear dirty flags when draining the ring and build packedTileUpdates from distinct tile refs
- Keep non-SAB behaviour unchanged while reducing ring pressure and making overflows reflect true backlog, not duplicate updates
2025-11-26 21:35:21 +01:00
scamiv 02db840d3c Revert "dedup tileRef for tileUpdateSink(tileRef)"
This reverts commit 08a2ff906b.
2025-11-26 21:35:20 +01:00
scamiv 45971d3c36 dedup tileRef for tileUpdateSink(tileRef) 2025-11-26 21:35:19 +01:00
scamiv 40e7394e58 fix performance overlay 2025-11-26 21:35:18 +01:00
scamiv 8d72632f79 fix sab detection 2025-11-26 21:35:17 +01:00
scamiv 43774615f0 mergeGameUpdates fix batch.length === 0 return case 2025-11-26 21:35:16 +01:00
scamiv e4178d3dc6 add more stats to perf overlay 2025-11-26 21:35:16 +01:00
scamiv 1f655618ff Change the ring buffer to Uint32Array
Store only TileRef instead of packed tile+state values
2025-11-26 21:35:15 +01:00
scamiv 15531806fa 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
2025-11-26 21:35:14 +01:00
scamiv fa6d445f46 SAB+Atomics refactor
Added src/core/worker/SharedTileRing.ts, which defines a SharedArrayBuffer-backed ring buffer (SharedTileRingBuffers/SharedTileRingViews) and helpers pushTileUpdate (worker-side writer) and drainTileUpdates (main-thread reader) using Atomics.

Extended GameRunner (src/core/GameRunner.ts) with an optional tileUpdateSink?: (update: bigint) => void; when provided, tile updates are sent to the sink instead of being packed into GameUpdateViewData.packedTileUpdates (those become an empty BigUint64Array in this mode).

Extended the worker protocol (src/core/worker/WorkerMessages.ts) so the init message can optionally carry sharedTileRingHeader and sharedTileRingData (the two SABs for the ring).

Updated WorkerClient (src/core/worker/WorkerClient.ts) to accept optional SharedTileRingBuffers in its constructor and, during initialize(), include those SABs in the init message sent to Worker.worker.ts.

Updated the worker implementation (src/core/worker/Worker.worker.ts) to build sharedTileRing views from the SABs on "init" and pass a (update: bigint) => pushTileUpdate(...) sink into createGameRunner, so every tile update from the simulation goes into the shared ring instead of the message payload.

Updated the client side (src/client/ClientGameRunner.ts):
In createClientGame, when SharedArrayBuffer/Atomics are available and crossOriginIsolated is true, it allocates the ring (createSharedTileRingBuffers with capacity 262144), creates views, passes buffers into WorkerClient, and keeps the views in ClientGameRunner.
ClientGameRunner now has a tileRingViews field and, in mergeGameUpdates, if the ring is present it ignores gu.packedTileUpdates and instead drains up to MAX_TILE_UPDATES_PER_RENDER (100 000) tile updates from the SAB ring into combinedPackedTileUpdates before constructing the merged GameUpdateViewData passed to GameView.update.
If SABs are unavailable, it falls back to the original behaviour (packing gu.packedTileUpdates from messages), so the feature is opt-in and backward compatible.

Net effect: when the page is cross-origin isolated, the worker no longer sends per-tick BigUint64Array tile payloads via postMessage; it streams tile updates into a shared ring buffer, and the main thread pulls and applies them at its own pace while still batching non-tile updates and rendering exactly as before. If you’d like, I can next run the existing tests/build in your environment to sanity-check everything.
2025-11-26 21:35:13 +01:00
scamiv e74dbe64fa Add performance metrics for worker and render ticks
- Introduced new metrics in ClientGameRunner to track worker simulation ticks and render tick calls per second.
- Updated TickMetricsEvent to include these new metrics.
- Enhanced PerformanceOverlay to display worker and render ticks per second, improving performance monitoring capabilities.
- Adjusted minimum FPS in GameRenderer
2025-11-26 21:35:12 +01:00
scamiv 59ff42e52b Refactor rendering and throttle based on backlog
- Refactor rendering and metrics emission in ClientGameRunner to ensure updates occur only after all processing is complete
- Throttle renderGame() based on the current backlog
2025-11-26 21:35:11 +01:00
scamiv f0e05c66b8 add "ticks per render" metric 2025-11-26 21:35:10 +01:00
scamiv d501d0e2d9 remove redundant logic 2025-11-26 21:35:10 +01:00
scamiv 73f47fe997 ClientGameRunner: simplify catch-up loop with indexed queue
process updates in a single budgeted loop per RAF and render once
track queue head with pendingStart and compact to avoid array shifts
2025-11-26 21:35:09 +01:00
scamiv 5c99ef5092 Refactor slice budget calculation in ClientGameRunner to improve backlog handling. Introduced dynamic slice budget scaling based on backlog size, allowing for longer processing times when necessary while maintaining UI responsiveness. 2025-11-26 21:35:08 +01:00
scamiv 3cc6243bf4 Implemented time-sliced catch-up on the main thread to keep input responsive.
src/client/ClientGameRunner.ts now drains pending game updates in small chunks (max 100 updates or ~8ms per slice) via requestAnimationFrame, merging and rendering per slice, and only clears the processing flag when the queue is empty.
2025-11-26 21:35:08 +01:00
scamiv 8e0a42c513 Clean up previous implementations
removed:
- catchUpMode and its CATCH_UP_ENTER/EXIT thresholds in ClientGameRunner
- tick metrics fields and overlay UI for inCatchUpMode and beatsPerFrame
- leftover worker heartbeat plumbing (message type + WorkerClient.sendHeartbeat) that was no longer used after self-clocking

changed:
- backlog tracking: keep serverTurnHighWater / lastProcessedTick / backlogTurns, but simplify it to just compute backlog and a backlogGrowing flag instead of driving a dedicated catch-up mode
- frame skip: adaptRenderFrequency now only increases renderEveryN when backlog > 0 and still growing; when backlog is stable/shrinking or zero, it decays renderEveryN back toward 1
- render loop: uses the backlog-aware renderEveryN unconditionally (no catch-up flag), and resets skipping completely when backlog reaches 0
- metrics/overlay: TickMetricsEvent now carries backlogTurns and renderEveryN; the performance overlay displays backlog and current “render every N frames” but no longer mentions catch-up or heartbeats

Learnings during branch development leading to this

Once the worker self-clocks, a separate “catch-up mode” and beats-per-frame knob don’t add real control; they just complicate the model.
Backlog is still a valuable signal, but it’s more effective as a quantitative input (backlog size and whether it’s growing) than as a boolean mode toggle.
Frame skipping should be driven by actual backlog pressure plus frame cost: throttle only while backlog is growing and frames are heavy, and automatically relax back to full-rate rendering once the simulation catches up.
2025-11-26 21:35:07 +01:00
scamiv dcd5b550cf Worker now self-clocks; no heartbeats needed
GameRunner exposes pending work via a new hasPendingTurns() so the worker can check whether more ticks need to be processed.
Worker auto-runs ticks: as soon as it initializes or receives a new turn, it calls processPendingTurns() and loops executeNextTick() while hasPendingTurns() is true. No more "heartbeat" message type; the worker no longer depends on the main thread’s RAF loop to advance the simulation.
Client main thread simplified:
Removed CATCH_UP_HEARTBEATS_PER_FRAME, the heartbeat loop, and the lastBeatsPerFrame tracking.
keepWorkerAlive now just manages frame skipping + draining. When it decides to render (based on renderEveryN), it drains pendingUpdates, merges them, updates GameView, and runs renderer.tick().
Because rendering a batch always implies draining, we restored the invariant that every GameView.update is paired with a layer tick() (no more lost incremental updates).
MAX_RENDER_EVERY_N is now 5 to keep the queue from growing too large while the worker sprints.
2025-11-26 21:35:05 +01:00