Commit Graph

3758 Commits

Author SHA1 Message Date
scamiv d0be9e26d5 Extend staging deployment lifetime 2026-05-26 21:59:30 +02:00
scamiv 07da3a3e3d Fix WebGPU settings accessors 2026-05-26 20:39:43 +02:00
scamiv 9456d991a0 Update terrain shader parameters
- Modified terrain shader parameters in GroundTruthData for better rendering.
- Added new user-configurable settings for water effects in TerrainShaderRegistry.
- Enhanced terrain compute shaders to incorporate water depth and blur adjustments.
- Refactored shader logic to improve water color blending and depth calculations
2026-05-26 20:23:20 +02:00
scamiv 63ab3b995f Update WebGPUDebugOverlay section title and adjust terrain shader default values
- Changed section title from "Shaders" to "Terrain" in WebGPUDebugOverlay.
- Updated default values for various terrain shader parameters to improve rendering quality, including noise strength, blend width, lighting strength, and cavity strength.
2026-05-26 20:23:20 +02:00
scamiv c9ea04abac Add improved terrain compute shaders with lite and heavy variants
- Add terrain-compute-improved-lite.wgsl and terrain-compute-improved-heavy.wgsl
- Create TerrainShaderRegistry.ts for shader management
- Refactor TerrainComputePass to support dynamic shader switching
- Update TerritoryRenderer, TerritoryLayer, and GroundTruthData for new shader integration
- Enhance WebGPUDebugOverlay with additional debugging capabilities
2026-05-26 20:23:20 +02:00
scamiv fd87b0e3f8 adjusted defaults 2026-05-26 20:23:19 +02:00
scamiv 962d4cabd4 add temporal smoothing for territory rendering
Add user-selectable temporal smoothing pipeline to create smooth visual
transitions between simulation ticks (~10Hz) and display frames (~60Hz).

Pre-render smoothing provides sharp tile dissolve transitions using compute
shaders, while post-render smoothing blends frames for fluid animation.
Includes tick timing with exponential moving averages for stable temporal
parameters.

New Components:
- TerritoryPreSmoothingRegistry & TerritoryPostSmoothingRegistry for mode selection
- VisualStateSmoothingPass compute shader for pre-render dissolve effects
- TemporalResolvePass render shader for post-render temporal compositing
- Enhanced GroundTruthData with temporal uniforms and history textures

Performance: No full-map per-frame compute, single fullscreen post-render pass.
Compatible with all territory shaders (classic, retro, future variants).

Files: 12 files changed, 1357 insertions(+), 8 deletions(-)
2026-05-26 20:23:19 +02:00
scamiv 6330c865ea Add WebGPU Debug Overlay to prod index.html
- Included <webgpu-debug-overlay> component in the main layout
2026-05-26 20:23:19 +02:00
scamiv d82c33863f Add WebGPU Debug Overlay and Shader Management
- Introduced WebGPUComputeMetricsEvent to track compute timing.
- Added WebGPUDebugOverlay component for displaying WebGPU performance metrics.
- Refactored TerritoryLayer to utilize new shader management for territory rendering.
- Updated shaders to support new parameters for enhanced visual effects.
- Removed deprecated territory border mode settings from UserSettingModal and SettingsModal.
- Enhanced GroundTruthData to manage new textures for owner indices and relations.
- Improved shader parameter handling in TerritoryRenderer and related classes.

This commit enhances the WebGPU rendering pipeline, providing better performance insights and visual fidelity through improved shader management and debugging capabilities.
2026-05-26 20:23:19 +02:00
scamiv 29e74af95f fix border mode selection 2026-05-26 20:21:59 +02:00
scamiv 06eb82b1cf border test 9000 2026-05-26 20:21:58 +02:00
scamiv 99e7d36464 Switched loadShader() to a Vite-bundled static shader map using import.meta.glob(..., { as: "raw", eager: true }) 2026-05-26 20:17:52 +02:00
scamiv 97603f7a1a replace defended epoch stamping with defended-strength field
Store defended influence in defendedStrengthTexture and sample it in territory render shader
Recompute defended strength on tick for state-updated tiles and for post-change dirty tiles, with full-map fallback when diffs are large
Pack defense posts by owner on GPU (owner offsets + posts buffer)
Remove old defended clear/update passes and epoch-based params
2026-05-26 20:17:52 +02:00
scamiv 655bb211e1 simplify defended territory rendering logic
Replace epoch-based defended texture tracking with hard-clear approach for
improved reliability and performance. Remove complex dirty state tracking
and epoch incrementing logic in favor of direct hard clears before rebuilds.

Changes:
- Remove wasDefensePostsDirty tracking from TerritoryRenderer
- Replace numUpdates > 0 checks with hasStateUpdates boolean
- Hard-clear defended texture before restamping instead of epoch management
- Mark DefendedUpdatePass as dirty when rebuilding defended state
- Rebuild bind group in DefendedUpdatePass when missing, not just on buffer change

This eliminates potential transient mismatches where defended rendering
disappeared between rebuilds and simplifies the update pipeline.
2026-05-26 20:17:52 +02:00
scamiv 44ffa96b64 refactor: optimize terrain color extraction in GroundTruthData
Replaced tile sampling for terrain colors with direct extraction from the theme object, significantly improving performance. Updated shore, water, shoreline water, plains, highland, and mountain color computations to utilize theme properties, eliminating the need for tile searches. This change enhances efficiency in terrain color management while maintaining visual fidelity.
2026-05-26 20:17:52 +02:00
scamiv 92ba5754d6 refactor: update workgroup size in compute shader and dispatch logic
Modified the workgroup size in the state-update compute shader from 1 to 64 for improved parallel processing. Adjusted the dispatch logic in StateUpdatePass to calculate the correct number of workgroups based on the new size, enhancing performance during state updates. Removed unnecessary terrain parameter upload in TerritoryRenderer to streamline resource management.
2026-05-26 20:17:52 +02:00
scamiv c26acbda3a refactor: optimize terrain recomputation in TerritoryRenderer
Updated the terrain recomputation logic to trigger asynchronously, improving performance by allowing rendering to continue without blocking. This change ensures that the terrain will be ready for the next frame, which may result in displaying stale terrain for one frame but enhances overall rendering efficiency.
2026-05-26 20:17:52 +02:00
scamiv d149ff48dd move terrain color computation to GPU compute shader 2026-05-26 20:17:52 +02:00
scamiv 7cdf1b8160 refactor: restructure WebGPU territory renderer into extensible pass-based architecture
Refactor the monolithic TerritoryWebGLRenderer into a modular, extensible
architecture that separates ground truth computation from rendering passes.
This change also includes related improvements to game state management and
hover information handling.

WebGPU Architecture Refactor:
- Extract all shaders to external .wgsl files (no inlined shaders)
- Separate ground truth data management (GroundTruthData) from rendering
- Create pass-based architecture with ComputePass and RenderPass interfaces
- Implement compute passes: StateUpdatePass, DefendedClearPass, DefendedUpdatePass
- Implement render pass: TerritoryRenderPass
- Add TerritoryRenderer orchestrator with dependency-based execution ordering
- Add WebGPUDevice for device initialization and management
- Add ShaderLoader utility for loading .wgsl files via Vite ?raw imports

Performance Optimizations:
- Dependency order computed once at init (topological sort)
- Early exit checks at orchestrator and pass levels
- Bind groups rebuilt when textures/buffers are recreated
- Zero per-frame allocations (reuse command encoders and staging buffers)

Architecture Benefits:
- Easy to extend with new compute/render passes (borders, temporal smoothing, etc.)
- Clear separation between tick-based compute and frame-based rendering
- All shaders in external files for better maintainability
- Ground truth data computed once and reused by all passes

Related Changes:
- Add defended tile state support to GameMap (isDefended/setDefended)
- Expose tileStateView() for direct GPU state access
- Extract hover info logic to HoverInfo utility
- Remove TerrainLayer (terrain now rendered by WebGPU territory pass)
- Update GameRenderer to use transparent overlay canvas
- Add viewOffset() method to TransformHandler

Files:
- Deleted: TerritoryWebGLRenderer.ts (1217 lines), TerrainLayer.ts (77 lines)
- Added: 17 new files in webgpu/ directory structure
- Updated: TerritoryLayer.ts, GameRenderer.ts, PlayerInfoOverlay.ts,
  GameMap.ts, GameView.ts, GameImpl.ts, TransformHandler.ts, vite-env.d.ts
2026-05-26 20:17:51 +02:00
evanpelle aeb8d60224 don't show clan tab on crazy games v0.31.12 2026-05-12 07:49:02 -07:00
Evan ead2601623 Show bonus amount on currency packs (#3907)
## Description:

Show bonus amount on currency packs

- Add `bonusAmount` field to `PackSchema` (non-negative int)
- Render a rotated green corner ribbon (`+X FREE!`) on pack tiles when
`bonusAmount > 0`
- Add `cosmetics.free` translation key with `numFree` param

<img width="720" height="359" alt="Screenshot 2026-05-12 at 7 40 12 AM"
src="https://github.com/user-attachments/assets/3dd70fc4-c922-47f4-aee6-055047b58563"
/>

Describe the PR.

## 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
2026-05-12 07:44:44 -07:00
iamlewis 96e8f5cccd Update privacy policy and terms of service (#3897) v0.31.11 2026-05-11 12:58:28 +01:00
Patrick Plays Badly a3f695ee54 Update dyslexdria map (#3886)
## Description:
Small update to Dylexdria.
Iceland (island) moved for better game play.
Edits to nation locations and additional nations added.
Entire map shifted ~120 pixels for balance reasons. 


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

---------

Co-authored-by: Ricky G.P. <realtacoco@gmail.com>
v0.31.10
2026-05-08 14:48:29 -07:00
Ryan 7873bdbcb4 clan stats breakdown (#3869)
## Description:

improvements to clan ui. 
<img width="788" height="290" alt="image"
src="https://github.com/user-attachments/assets/736ca147-bff4-44d8-8180-7b80a85556fe"
/>
added "expand all" and new collapsible sections.


<img width="787" height="550" alt="image"
src="https://github.com/user-attachments/assets/deb2f813-854b-46a9-a767-52c4f749f30f"
/>

which changes to collapse all when expanded

also adds more info about team (d,t,q,2,3,4,5,6,7 team)

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

w.o.n
2026-05-06 16:10:27 -06:00
Ryan 9ab817cc89 [bugfix] fixes border around clans ui (#3873)
## Description:

fixes border around clans ui
<img width="67" height="705" alt="image"
src="https://github.com/user-attachments/assets/5ee35eb5-b406-4403-b9b4-324769faf061"
/>


also fixes weird padding:
<img width="134" height="244" alt="image"
src="https://github.com/user-attachments/assets/32a84074-afa6-4e9a-98f1-e45aabe4aa2a"
/>

what it should be:
<img width="140" height="206" alt="image"
src="https://github.com/user-attachments/assets/b72b480e-c972-4495-b9da-5c3b411bf590"
/>

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

w.o.n
2026-05-06 16:10:21 -06:00
evanpelle 8769e85576 run map generate to update map files 2026-05-06 14:44:39 -06:00
Alex Jurkiewicz 365402bbc7 perf(map-generator): major CPU and memory optimisations (#3860)
## Description:

Five performance improvements to the map generator, measured on three
maps of increasing size. End-to-end time on `world` improved ~15×, heap
allocations ~19×.

| Map | Before | After | Speedup |
|-----|--------|-------|---------|
| bosphorusstraits (~612K tiles) | 578ms / 594MB | 45ms / 134MB | 13× /
4.4× |
| world (~2M tiles) | 2333ms / 2128MB | 150ms / 553MB | 15× / 3.8× |
| giantworldmap (~8M tiles) | 10701ms / 9300MB | 635ms / 2509MB | 17× /
3.7× |

Changes (one commit each):
- **`--workers` flag**: bounds concurrent map processing to limit peak
memory
- **Flat `[]bool` visited sets**: replaced `map[string]bool` keyed by
`fmt.Sprintf` with flat `[]bool` indexed `x*height+y` — the dominant
cost
- **`neighborCoords` with stack buffer**: eliminates per-call slice
allocation for neighbour lookups
- **`Terrain` struct 24→16 bytes**: field reorder + `uint8` type for
`TerrainType`
- **Nil buffers early**: releases image/terrain arrays as soon as
they're no longer needed
- **BFS mark-visited on push**: each tile enters the queue once instead
of up to 4×, halving queue memory


also fixes a bug (according to Claude):

Here's the bug: createMiniMap downscales by averaging/sampling 2x2
blocks, copying field values across — including Ocean=true from the
parent scale. When a single connected ocean at 1x splits into multiple
disconnected bodies at 4x (because narrow water channels disappear when
you halve resolution), those smaller fragments still carry Ocean=true
from the carryover. The 4x processWater call picks the new largest
fragment and sets it to Ocean=true, but never clears the others — so
multiple disconnected bodies end up flagged as Ocean.

This PR's fix: before the new BFS pass, zero out every Ocean flag, so
only the truly-largest body at the current scale ends up marked.

It's incidental to the perf work but it's a real semantic change — the
on-disk .bin files will differ from main on any map where ocean splits
across downscaling. The PR doesn't mention it, which is why I flagged
it.

---------

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-05-06 14:39:59 -06:00
Evan 30caea0c40 Add loading spinner while waiting for public lobbies to load (#3867)
## Description:

Loading spinner:


https://github.com/user-attachments/assets/9033b707-7499-4a52-b0c6-d96d8f331ee3


## 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
2026-05-06 14:28:20 -06:00
Ryan a4c3d54217 [bugfix] add detailCache = null; (#3868)
## Description:

fixed issue when leaving and trying to rejoin a clan without a reload

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

w.o.n
2026-05-06 13:35:58 -06:00
evanpelle f9f46379f1 refine lobby/action card hover styles
Add a thinner hover ring for the ranked/create/join action buttons via a new --shadow-action-card-hover variable, apply the same ring to the flag and skin selectors, and split the solo button's hover scale to expand mostly vertically so it doesn't clip horizontally.
2026-05-06 13:02:51 -06:00
Patrick Plays Badly c128157c85 Update map LUNA (#3854)
## Description:

Corrected inbalance in Luna map between top and bottom. Now both sides
have about equal land tiles.
Testing and editing was done to help boat-pathing at least look normal
along bottom half.
Additional notch cut in orbit lines to take edge off boat-pathing. Now
obstacle is almost a straight line.
Filled in center orbits to help players push easier. It was reported to
be tedious previously.
'Top Secret Military Base' nation was renamed with only vowels blacked
out for easier reading of joke name.
'Monolith' nation was renamed with a special character that displays
like the actual Monolith.

<img width="829" height="1165" alt="l1"
src="https://github.com/user-attachments/assets/8cf10fbf-99c1-4ec8-ae0c-7066d1deae21"
/>

<img width="829" height="1165" alt="l2"
src="https://github.com/user-attachments/assets/828e2caf-60b3-4ac7-aa70-0f5b64fac643"
/>



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

## Discord username
PlaysBadly
2026-05-06 12:48:35 -06:00
Evan df84ee023e Refactor & standardize modal tabs (#3864)
## Description:

Refactors tab handling out of the individual modal components and into
the base o-modal component. Tabs are now declared by passing tabs,
activeTab, and onTabChange props, and a new named header slot pins
consumer-supplied content above the tabs. This standardizes the modal
tab look.

<img width="1089" height="290" alt="Screenshot 2026-05-06 at 12 17
33 PM"
src="https://github.com/user-attachments/assets/08d5a039-0aef-4aa7-b972-1e43b8723685"
/>

## 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
2026-05-06 12:47:11 -06:00
babyboucher 94bab78d24 Fix off by one error (#3827)
## Description:

Currently it is impossible to search for 2 letter clan tags (UN, FR,
EU), this is because of an off by one error present in the API

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

Babyboucher
2026-05-05 22:15:47 -06:00
Evan 7f9b63a24c Increase max intent size to 2kb (#3852)
## Description:

Raised MAX_INTENT_SIZE from 500 to 2000 bytes — the move_warship intent
could exceed the old limit and get rejected.
Removed the separate MAX_CONFIG_INTENT_SIZE (also 2000) and the
intentType branching, since both paths now share the same cap.
## Please complete the following:

- [ ] 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
2026-05-05 14:59:09 -06:00
Evan af5249655c Worker init (#3850)
## Description:

- Inline the game worker into the main bundle (`?worker&inline`) instead
of loading it from the CDN via a same-origin Blob trampoline.
- Some users were failing to load the worker — most likely a
cross-origin / CDN edge case the trampoline didn't paper over. Inlining
serves the worker as a same-origin Blob from the main bundle, bypassing
the cross-origin `new Worker(url)` restriction entirely.
- Removes `createGameWorker()`, the trampoline script, the
`trampoline_error` message type, and the `onTrampolineError` listener in
`initialize()`. The 60s init timeout backstop stays.
- `cdnBase` is still forwarded in the `init` message — that's for
in-worker asset fetches (maps, etc.), unrelated to loading the worker
module itself.

Tradeoff: the worker bundles all of `src/core`, so the main JS download
grows by that amount on every page load (including lobby/settings pages
that never start a game). Accepted because load reliability > bundle
size here.

## 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
v0.31.9
2026-05-05 13:22:58 -06:00
evanpelle ffbe48ad10 fix: catch punctuation-separated slurs in username censor
Re-add skipNonAlphabeticTransformer to both matcher chains so bypass
attempts like "n.i.g.g.e.r" are detected.
v0.31.8
2026-05-04 18:18:36 -06:00
Evan 08b9fd96e6 simplify attack overlay to reduce visual clutter (#3848)
## Description:

Simplifies the attacking-troops overlay: removes the soldier icon and
strength bar, dropping each label down to just the troop number in cyan
(outgoing) or red (incoming) with a soft dark text-shadow halo and no
background fill so territory borders show through cleanly. Also splits
the label into outer (transitioned position) and inner (instant scale)
divs so zoom changes no longer get smeared by the 0.25s cluster-move
transition, retunes the zoom→size curve, and skips incoming labels from
bot tribes to cut clutter.

<img width="374" height="307" alt="Screenshot 2026-05-04 at 5 53 17 PM"
src="https://github.com/user-attachments/assets/a7044221-06cc-4027-b19a-6ff4ca8f542a"
/>

## 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
2026-05-04 18:10:06 -06:00
evanpelle 83ff524529 increase woker init timeout to 60s 2026-05-04 18:00:16 -06:00
evanpelle 900d7f0bd0 Increase worker init timeout from 20s to 30s 2026-05-04 15:04:23 -06:00
Evan 94205426e7 Move turnstile check to api (#3845)
## Description

Re-enables Turnstile verification (was temporarily disabled in v31 to
diagnose intermittent `invalid-input-response` rejections) and moves the
verification call off the game servers.

Game servers no longer hold `TURNSTILE_SECRET_KEY` or hit
`challenges.cloudflare.com` directly. Instead they POST to
`${jwtIssuer}/turnstile` on the api-worker (authenticated with the
existing `apiKey`), which holds the secret and proxies to Cloudflare.
Shrinks blast radius and removes the secret from every game host + GH
Actions workflow.

Response from the api-worker is Zod-validated; null tokens short-circuit
to `rejected` locally.

## Please complete the following:

- [x] I have added screenshots for all UI updates (n/a — server only)
- [x] I process any text displayed to the user through translateText()
(n/a — no user-visible text)
- [ ] 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

## Discord:

evanpelle
v0.31.7
2026-05-04 12:53:02 -06:00
evanpelle 257fb9b38e temporarily disable turnstile v0.31.3 2026-05-03 18:50:59 -06:00
FloPinguin 3a24383e88 Fix map land tile lookup broken by asset URL migration 🗺️ (#3826)
## Description:

`MapLandTiles` was fetching map manifests via HTTP at
`http://localhost:3000/maps/<map>/manifest.json`. This stopped working
after PR #3494 moved all public assets from stable paths (e.g.
`/maps/...`) to content-hashed paths under `/_assets/...`. The master
server no longer serves `/maps/` -- requests fell through to the SPA
handler, returned `index.html`, failed JSON parsing, and silently fell
back to the default `1_000_000` land tile count.

With 1M tiles, `calculateMapPlayerCounts` produces `[50, 40, 25]`
instead of the real values (e.g. `[185, 140, 95]` for Alps), causing all
public lobbies to be capped at 25-50 players regardless of map.

Fixes this by reading map manifests directly from disk instead of via
HTTP:
- In production: resolves the source path through
`getRuntimeAssetManifest()` to the hashed file under `static/_assets/`,
then reads it with `fs.readFile`.
- In dev: falls back to `resources/maps/<name>/manifest.json` directly
(the Dockerfile removes `resources/maps` in production, so this branch
only runs locally).

Also adds an in-process cache so each map manifest is only read once per
server lifetime.

Verified that it works on
https://fix-map-land-tiles-asset-manifest.openfront.dev/ and locally.

## 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
v0.31.2
2026-05-03 14:31:00 -06:00
evanpelle ac679b68c5 update cache bust version to invalid bad response headers v0.31.1 2026-05-03 10:14:19 -06:00
evanpelle 5d6c48ebf2 Revert "Fix winner stats spoofing exploit"
This reverts commit 819edb21bb.
v0.31.0
2026-05-03 09:54:50 -06:00
FloPinguin 4cd6f50c03 Nations: Fix city farming + reactive defense posts + fix nuked territory capture 🛡️ (#3814)
## Description:

Would be very good to get these fixes last minute into v31.

- **Farming nations for cities is fixed**: Here you can see city farming
in action, vari farms Finland:
https://www.youtube.com/watch?v=J4J0ajlnSHs&t=137s - Lots of 125k gold
cities... Now nations will build defense posts instead of cities:

- **Nations now build defense posts reactively** instead of through the
normal structure build order. When a nation is under significant land
attack (incoming/own troops >= 35%), it places a defense post near the
attack front -- skipped on Easy, capped at 1 on Medium, and scaled by
the incoming troop ratio on Hard/Impossible. Posts spread along the
front. The old `defensePostValue()` placement path is removed.

- **Nations now capture nuked territory.**
`hasLandBorderWithTerraNullius()` was incorrectly filtering out tiles
with fallout, causing the `nuked` attack strategy to never dispatch a
attack. Big bug

.

- [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
v0.31.0-test
2026-05-03 09:33:44 -06:00
RickD004 482d1b8bff Fix Bosphorus map (#3823)
## Description:

QoL changes for the Bosphorus map.

The base image for the map had a little aliasing which resulted in some
rivers being cut off.

<img width="673" height="386" alt="image"
src="https://github.com/user-attachments/assets/b8ed181f-fbeb-4d6f-b7ab-a8b0ea300a22"
/>

All of the nations except istanbul also had absolutely nothing to do
with the region. For example, Varna is a city in Northeast bulgaria and
the aegean isles are also nowhere near. There was also a nation that did
not spawn because its coordinates were in the sea.

<img width="626" height="413" alt="image"
src="https://github.com/user-attachments/assets/a6537f79-3785-4316-8fd4-a99f55faff71"
/>

All of these poor designs are probably the result of the map being
resized, originally being a larger map. It probably explains why this is
the smallest map by land area (not counting Oceania)

Fixes:

- Fixed landlocked rivers and added More accurate bodies of water

- Complete remake of the nations. Nations are now far more accurately
placed districts of the region, and more evenly placed

<img width="664" height="407" alt="image"
src="https://github.com/user-attachments/assets/ff5a34fc-dea0-4a3d-b798-39d5711b91af"
/>

The data and gamestyle of this map should not change much, as the
landmasses remain in practice the same

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

tri.star1011
2026-05-03 09:32:27 -06:00
evanpelle 819edb21bb Fix winner stats spoofing exploit
Previously, winnerVotes was keyed only on winner, so a client could send the correct winner with spoofed allPlayersStats and have their vote count toward the majority. The key is now a SHA-256 hash of both winner and allPlayersStats together, so any stats divergence produces a distinct key that must independently reach majority.

When the winner is confirmed, the log now includes votesByKey — a summary of every distinct key, its vote count, and winner value — making stat manipulation visible in the logs.
v0.31.0-beta2
2026-05-02 13:47:19 -06:00
evanpelle bf74028200 Fix medal icon CORS errors by inlining SVG as data URI
CSS mask-image triggers a CORS fetch, which failed for the CDN-hosted medal SVG. Switched to a Vite ?raw import so the SVG is embedded as a data URI at build time — no network request, no CORS.

Also stripped the SVG of Inkscape metadata and replaced filter-based color inversion with a plain fill="white", shrinking it from 3,278 → 955 bytes (387 bytes gzipped).
2026-05-02 12:54:29 -06:00
evanpelle 22dbc4fbb8 meta: increase alt/current attackerTroopLoss to 60/40 v0.31.0-beta1 2026-05-02 09:44:34 -06:00
evanpelle ba57da35e2 Increase port build time to 5 seconds 2026-05-02 09:43:19 -06:00