Commit Graph

551 Commits

Author SHA1 Message Date
FloPinguin 05c4a67e17 Exclude extreme modifiers on Four Islands 🏝️ (#3593)
## Description:

I saw multiple occasions of 3h long four islands team games because of
the 2x gold multiplier. For example
[here](https://www.reddit.com/r/Openfront/comments/1sca6g4/endless_game/).
People just get too many SAMs.
Without the extreme gold amount, team games on four islands are actually
fun.

This PR excludes `goldMultiplier` and `startingGold25M` from special
game modifiers when the map is FourIslands.

## 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
2026-04-05 12:33:59 -07:00
scamiv 31203138bc fix: extend derived asset rewriting for web manifests to BMFont XML (#3591)
## Description:
The new hashed public asset pipeline treated `manifest.json` as a
derived asset, but BMFont XML files were still copied as raw files.

That broke bitmap fonts in production:
- the XML was loaded through the hashed asset manifest
- the XML still referenced an unhashed `file="...png"` page
- Pixi resolved that relative to the hashed XML URL
- the unhashed page file did not exist under `/_assets/...`

This PR extends the derived asset rewriting model to BMFont XML so font
page references are rewritten before hashing and emission.

## What changed

- Refactored the public asset build pipeline to distinguish:
  - raw assets hashed from source bytes
  - derived assets hashed from rewritten content
- Replaced the `manifest.json` one-off special case with a small
derived-asset registry
- Added BMFont XML derived-asset handling for `fonts/**/*.xml`
- Rewrote `<page file="...">` entries to hashed relative page paths
- Moved `_assets/asset-manifest.mjs` emission to the end of the Vite
asset sync step

Added regression coverage for:
- rewritten web manifest hashing
- BMFont XML page rewrite
- nested relative BMFont page paths
- hard failure on missing derived asset references


## Please complete the following:

- [ ] I have added screenshots for all UI updates
- [ ] I process any text displayed to the user through translateText()
and I've added it to the en.json file
- [ ] I have added relevant tests to the test directory
- [ ] 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:

DISCORD_USERNAME
2026-04-05 12:26:50 -07:00
Patrick Plays Badly 4ad172a8a0 Update MapPlaylist.ts Dyslexdria (#3579)
add map dyslexdria to map rotation


## Description:
I forgot to add dyslexdria to the map rotation and must atone for my
mistakes

## 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-04-04 12:45:31 -07:00
evanpelle b88c3a3bdd Merge branch 'v30' 2026-04-01 20:03:39 -07:00
evanpelle 6ca5cb9701 Revert "Add multiple funny maps april fools day (#3538)"
This reverts commit a7d9652886.
2026-04-01 20:03:33 -07:00
evanpelle ff7f459825 Revert "Add Map - Dyslexdria - April Fools (#3413)"
This reverts commit 2bf96db464.
2026-04-01 20:02:37 -07:00
evanpelle 85f09c1c98 Revert "Make april fool maps have the same name as normal maps (#3555)"
This reverts commit 38be51a2d6.
2026-04-01 20:02:16 -07:00
evanpelle dfbd17ecff Revert "Add multiple funny maps april fools day (#3538)"
This reverts commit bfb8a9447c.
2026-04-01 19:41:45 -07:00
Patrick Plays Badly 4c8754bd81 Add Map - Dyslexdria - April Fools (#3413)
Re-submission, previous request was not branched properly.

Add custom map Dyslexdria. Based off of large_world_map_recolor.tif and
rivers from the XL World map. Map is intended for long term use.
Suggesting that map be used as an April Fools gag by replacing thumbnail
and title with 'World' during first run.

<img width="995" height="721" alt="dyslexdria screenshot"
src="https://github.com/user-attachments/assets/8826839f-b4e0-431d-af9c-0b0e43dc601d"
/>

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

- Build log, screen shots, and test videos.
https://discord.com/channels/1284581928254701718/1456890656147374080

PlaysBadly

---------

Co-authored-by: Duwibi <86431918+Duwibi@users.noreply.github.com>
Co-authored-by: VariableVince <24507472+VariableVince@users.noreply.github.com>
2026-03-31 20:07:59 -07:00
Patrick Plays Badly bfb8a9447c Add multiple funny maps april fools day (#3538)
Requesting that these 4 maps be added temporarily for the April Fools
holiday. Included are:
- A wider version of the Amazon River to allow for larger ships.
- An edit of The Box with more varied terrain.
- A modification to The World which optimizes play for mobile users.
- A custom remix to Antarctica which re-adds ice to the map.
All maps are edits of existing work. All maps have been added as their
own individual map files rather than edits to existing files for ease of
management.

<img width="912" height="1067" alt="temp"
src="https://github.com/user-attachments/assets/089ef59f-8bdf-4c86-b479-620b8c220c3a"
/>
https://discord.com/channels/1284581928254701718/1483786939332169830

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

PlaysBadly
2026-03-31 20:01:40 -07:00
RickD004 38be51a2d6 Make april fool maps have the same name as normal maps (#3555)
## Description:

Make the april fool maps have the same name as the normal maps, in order
to make the prank better.

NOTE: In order for this to work, it re-adds the normal maps into
rotation. These normal maps have been given a lower rotation however.

In custom matches the maps will appear with the april fools names.

This change will be reverted after April Fools.

Check this for proof of it working: 

https://canary.discord.com/channels/1359946986937258015/1450487807242932336/1488682300924231882

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

DISCORD_USERNAME
2026-03-31 18:43:03 -07:00
Patrick Plays Badly 2bf96db464 Add Map - Dyslexdria - April Fools (#3413)
Re-submission, previous request was not branched properly.


## Description:

Add custom map Dyslexdria. Based off of large_world_map_recolor.tif and
rivers from the XL World map. Map is intended for long term use.
Suggesting that map be used as an April Fools gag by replacing thumbnail
and title with 'World' during first run.

<img width="995" height="721" alt="dyslexdria screenshot"
src="https://github.com/user-attachments/assets/8826839f-b4e0-431d-af9c-0b0e43dc601d"
/>

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


## Following:

- Build log, screen shots, and test videos.
https://discord.com/channels/1284581928254701718/1456890656147374080


## Discord username:

PlaysBadly

---------

Co-authored-by: Duwibi <86431918+Duwibi@users.noreply.github.com>
Co-authored-by: VariableVince <24507472+VariableVince@users.noreply.github.com>
2026-03-31 17:50:23 -07:00
Patrick Plays Badly a7d9652886 Add multiple funny maps april fools day (#3538)
## Description:
Requesting that these 4 maps be added temporarily for the April Fools
holiday. Included are:
- A wider version of the Amazon River to allow for larger ships.
- An edit of The Box with more varied terrain.
- A modification to The World which optimizes play for mobile users.
- A custom remix to Antarctica which re-adds ice to the map.
All maps are edits of existing work. All maps have been added as their
own individual map files rather than edits to existing files for ease of
management.

<img width="912" height="1067" alt="temp"
src="https://github.com/user-attachments/assets/089ef59f-8bdf-4c86-b479-620b8c220c3a"
/>
https://discord.com/channels/1284581928254701718/1483786939332169830

- [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-03-31 12:37:34 -07:00
VariableVince 74b5affa75 Chore(deps): Migrate Express 4 > 5 (#3549)
## Description:

Update from Express 4.22 > 5.2.1. And @types/express 4.17 > 5.0.6.

### CodeQL errors unjustified: Please dismiss the unjustified [CodeQL
scanning
results](https://github.com/openfrontio/OpenFrontIO/security/code-scanning?query=pr%3A3549+tool%3ACodeQL+is%3Aopen)
for playground/server.ts: they were flagged for this PR but i didn't
touch those specific parts of the file. More importantly: it is a test
server, created by Mole/ @Aareksio. I made requests to dismiss the
alerts but don't have the permissions to actually dismiss them myself

Version 5 was the first major upgrade in 10 years when it was released
in Sept 2024. 5.21 is from Dec 2025 so v5 teething problems should be
over by now. Many of its dependencies also updated by some major
versions. So it seems a worthy update but that is for you to decide. v4
will be EOL when v6 arrives, however that could be a year from now still
maybe.

- Migration:
-- Updated package.json, ran `npm install "express@5"` and `npm install
"@types/express@5.0.6"`.
-- Used https://expressjs.com/en/guide/migrating-5.html
-- Ran the codemods from the migration guide `npx codemod@latest
@expressjs/v5-migration-recipe`.
-- Checked manually.
-- Checked again with help of Gemini 3.1 Pro based on same guide.
-- Master.ts: use `*splat` instead of `*`, tested and going to
non-existing URL lands back on index.html like it should.
-- Worker.ts: MIME type _webp_ is now supported natively so remove added
config.
-- playground/server.ts: fix type error after upgrading types/express
for `name` in `req.params`. And `app.listen` handles user provided
callback on error, use that. The latter may not be not needed per se.
-- While v5 does this now "When an error is thrown in an async function
or a rejected promise is awaited inside an async function, those errors
will be passed to the error handler as if calling next(err).", choose to
leave our try/catch'es be. Since we use specific errors, probably easier
for consistency in log searches and user reporting.

- About performance: 
-- While [Express 5 seems a bit slower than
4](https://www.repoflow.io/blog/express-4-vs-express-5-benchmark-node-18-24),
it is not by much especially on Node24 which we're on. Also there's a
working group dedicated to improving Express performance, albeit they
expect v6/7 to benefit from that more than v5 will.
-- While there are faster alternatives in benchmarks, [in real-world
usage Express still holds up as one of the best and even beats most
'faster'
alternatives](https://medium.com/deno-the-complete-reference/node-js-the-fastest-web-framework-in-2025-static-file-server-case-1df462ad38cd).

## 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
2026-03-31 12:35:40 -07:00
evanpelle 35be401312 send x-api-key in requests to bypass bot detection 2026-03-30 20:57:13 -07:00
RickD004 6fa9bf692b Add Mediterranean map (#3523)
## Description:

Adds Mediterranean sea map, from Iberia to Asia. Map contains ancient
Roman Empire provinces and its rivals as Nations.
This map was requested by the dev.

elevation data from Opentopography

<img width="2850" height="1450" alt="image"
src="https://github.com/user-attachments/assets/6aa5ba12-f4f7-414d-a712-b90323f1d796"
/>
<img width="590" height="304" alt="Captura de pantalla 2026-03-27
010038"
src="https://github.com/user-attachments/assets/efd1deea-bd88-4ae2-92a0-47a6626a0c0f"
/>
<img width="585" height="302" alt="Captura de pantalla 2026-03-27
005758"
src="https://github.com/user-attachments/assets/a127696e-fe34-424c-a88d-b86b99a5f414"
/>



## 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-03-30 13:49:53 -07:00
RickD004 217a2c4548 Adds Milky Way Map (#3519)
## Description:

Adds Milky Way galaxy map based on real reconstruction by NASA. Star
density simulated as terrain. Best played in Dark Mode.

Also adds credits to JPL NASA

<img width="532" height="533" alt="Captura de pantalla 2026-03-26
142938"
src="https://github.com/user-attachments/assets/87bb19bb-4e2d-4383-a3e9-6e14b714b84c"
/>

## 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-03-26 19:18:30 -07:00
evanpelle 7fdda33fb9 Merge branch 'v30' 2026-03-25 13:34:34 -07:00
FloPinguin 0dc522413e Close private lobby when host leaves 🚪 (#3503)
## Description:

When the host of a private lobby disconnects before the game starts, the
lobby is now closed:

- **Server:** Detects host disconnection via `creatorPersistentID`
match, kicks all remaining clients with a `host_left` reason, and marks
the game as ended so it's cleaned up by the game manager and can no
longer be joined.
- **Client:** Participants receive an `alert()` saying "The host has
left the lobby." and their JoinLobbyModal is closed automatically via
the `leave-lobby` event.
- **Phase logic:** `phase()` now returns `Finished` for ended private
lobbies that haven't started, preventing the game from lingering in
`Lobby` state.

## 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
2026-03-24 13:00:20 -07:00
FloPinguin cf0cf14a1f Add new public game modifiers 🙂 (#3500)
## Description:

Adds 5 new public game modifiers to the Special game mode modifier pool:

- **Ports Disabled** - disables port construction, focus on factories
- **Nukes Disabled** - disables atom bombs, hydrogen bombs, MIRVs,
missile silos and SAM launchers
- **SAMs Disabled** - disables SAM launchers (thats funny, you cant
protect against nukes, have to space out your stuff) (mutually exclusive
with nukes disabled)
- **1M Starting Gold** - gives all players 1M starting gold (was
requested by people, new chill tier alongside existing 5M and 25M)
- **4min Peace Time** - grants 4 minutes of PVP spawn immunity

All `PublicGameModifiers` boolean fields are now optional - inactive
modifiers are omitted from game JSON instead of being serialized as
`false` (stop bloating the JSON size)

I think we have enough modifiers now :) Good variety

## 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
2026-03-24 12:57:08 -07:00
Ryan 6e67c2bf0d visibleAt (#3497)
## Description:

 needs prereq of https://github.com/openfrontio/infra/pull/272

## 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-03-24 12:53:32 -07:00
Evan 39ad547c04 support for unlockable flags (#3479)
## Description:

Add support for purchasable/gated flags.

* Create a new "Store" modal that renders both skins & flags
* move all store related logic out of TerritoryPatternsModal
* use nation:code for existing nation flags & flag:key for gated flags
* check if user has the appropriate flags before purchasing

## 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-03-23 17:09:18 -07:00
evanpelle 426806299f bugfix: map was not compact size in compact gamemode 2026-03-23 14:01:10 -07:00
evanpelle 527931255b bugfix: map was not compact size in compact gamemode 2026-03-23 14:00:47 -07:00
FloPinguin 043d8d4f22 Remove modifiers from normal FFA/Team games (And increase chance of gold multiplier for special games, decrease random spawn) 🎲 (#3471)
Normal (FFA and Team) public games no longer roll random modifiers.
Special games remain fully unaffected and continue to use random
modifiers as before.

I also increased the gold multiplier ticket count in the special
modifier pool from 1 to 4 because of player feedback.

Edit: And because I saw complaints of too much random spawn I decreased
the chance of it.

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

regression is found:

FloPinguin
2026-03-23 13:59:34 -07:00
evanpelle 0b88ec0b7a max of 3 modifiers for special (4 was confusing to me) 2026-03-23 13:58:49 -07:00
evanpelle 6fac264b7f make 1 in every 3 games compact 2026-03-23 13:58:49 -07:00
FloPinguin 8f4e6c2e2a Remove modifiers from normal FFA/Team games (And increase chance of gold multiplier for special games, decrease random spawn) 🎲 (#3471)
Normal (FFA and Team) public games no longer roll random modifiers.
Special games remain fully unaffected and continue to use random
modifiers as before.

I also increased the gold multiplier ticket count in the special
modifier pool from 1 to 4 because of player feedback.

Edit: And because I saw complaints of too much random spawn I decreased
the chance of it.

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

regression is found:

FloPinguin
2026-03-23 13:54:29 -07:00
scamiv 05e2bc9f0a Improve cacheability with content-hashed public assets and a cacheable app shell (#3494)
## Description:

This reworks asset delivery and cacheability across the app and moves
non-bundled public resources onto immutable, content-hashed URLs.

Vite bundle outputs continue to live under `/assets/**` and remain
content-hashed by Vite. Public resources that were previously fetched
from stable paths in `resources/` now go through a custom hashed
namespace under `/_assets/**`, backed by a generated asset manifest that
is available to the server, browser, and worker runtime.

In parallel, the root app shell is now cacheable shared HTML instead of
request-time `no-store` HTML. Dynamic and live routes remain explicitly
uncached.

## Why
- Improve browser and Cloudflare cacheability for static assets.
- Remove query-string and release-version cache busting for
runtime-fetched assets.
- Allow unchanged public assets to keep the same URL across releases.
- Reduce avoidable work on `/` by serving a shared app shell instead of
rendering HTML on every request.
- Make cache behavior explicit instead of relying on mixed framework
defaults and file-extension heuristics.

## What Changed

### 1. Content-hashed public asset pipeline
- Added a build-time public asset manifest and hashing pipeline for
non-Vite resources.
- Production now emits hashed public assets under `/_assets/**`.
- Added runtime manifest loading for Node so server-rendered paths
resolve against built hashed files instead of rebuilding from source at
runtime.
- Emitted the runtime asset manifest as an ESM module for server
consumption.

Result:
- `/assets/**` = Vite-managed hashed bundle outputs
- `/_assets/**` = custom content-hashed public resources

### 2. Runtime asset URL migration
- Added a shared `assetUrl(...)` resolution path.
- Migrated runtime references away from query-string versioning and
stable source paths.
- Updated browser, worker, and server-side rendering paths to resolve
through the asset manifest.
- Moved map manifests, map binaries, thumbnails, sprites, sounds, fonts,
flags, icons, screenshots, and other runtime-fetched resources onto
hashed URLs.

### 3. Map and preview fixes
- Fixed directory and per-file map asset resolution so map manifest and
binary fetches resolve to the correct hashed URLs.
- Updated preview metadata and map thumbnail paths to use the hashed
asset namespace.
- Fixed runtime manifest loading in prod after deployment.

### 4. Explicit cache policies
- Added explicit immutable cache headers for:
  - `/assets/**`
  - `/_assets/**`
  - worker-prefixed equivalents under `/wN/...`
- Added explicit `no-store` headers for live and dynamic APIs.
- Removed the old `/api/env` bootstrap request and baked `gameEnv` into
the HTML bootstrap instead.

### 5. Cacheable root app shell
- Refactored the root HTML path to serve a shared app shell with:
- `Cache-Control: public, max-age=0, s-maxage=300,
stale-while-revalidate=86400`
- `/` and the SPA fallback now serve shared cacheable HTML instead of
request-time `no-store` rendering.
- `/game/:id` remains dynamic and `no-store`, but now reuses the shared
shell before injecting preview tags.

### 6. Matchmaking instance handling
- Because the app shell is now cacheable, `INSTANCE_ID` was removed from
shared HTML.
- Added `/api/instance` as a temporary `no-store` runtime lookup used
only by matchmaking.
- This preserves correctness with the current random-per-boot
`INSTANCE_ID` model while keeping `/` cacheable, but it is not the
intended long-term design.

## Behavior Changes

### Asset URL contract
Production URLs for non-Vite public resources now change from stable
paths such as:
- `/maps/...`
- `/images/...`
- `/manifest.json`

to content-hashed paths under:
- `/_assets/...`

Examples:
- `/_assets/maps/<map>/manifest.<hash>.json`
- `/_assets/images/Favicon.<hash>.svg`

### Bootstrap/config
- `/api/env` is removed.
- `gameEnv` is now bootstrapped from HTML.

### HTML caching
- `/` and the SPA fallback are now cacheable shared HTML.
- `/game/:id` remains dynamic.

## Cache Matrix After This Branch
- `/_assets/**`: `public, max-age=31536000, immutable`
- `/assets/**`: `public, max-age=31536000, immutable`
- live `/api/**`: explicit `no-store`
- `/api/health`: explicit `no-store`
- `/api/instance`: explicit `no-store`
- `/game/:id`: explicit `no-store`
- `/` and SPA fallback: `public, max-age=0, s-maxage=300,
stale-while-revalidate=86400`

## Notes / Tradeoffs
- `/api/instance` is a temporary compromise. It exists because
`INSTANCE_ID` is currently random per boot, which is not safe to embed
into cacheable shared HTML.
- The current matchmaking flow still asks the client to provide
`instance_id` during `matchmaking/join`. That is functional, but it is
the wrong ownership boundary: instance selection should be handled by
the matchmaking service, not by the browser.
- The cleaner end-state would be:
- make `matchmaking/join` stop requiring `instance_id` from the client,
and let the matchmaking service select a healthy instance from worker
check-ins
- This branch makes the origin behavior edge-cache-friendly, but
Cloudflare still needs matching cache rules if HTML itself should be
cached at the edge.

## Validation
Verified during development with:
- `npx tsc --noEmit`
- `node node_modules\\vite\\bin\\vite.js build`
- `node node_modules\\vitest\\vitest.mjs run
tests/server/RenderHtml.test.ts tests/server/NoStoreHeaders.test.ts
tests/server/StaticAssetCache.test.ts
tests/core/configuration/ConfigLoader.test.ts`

Additional targeted tests added:
- `tests/AssetUrls.test.ts`
- `tests/core/game/FetchGameMapLoader.test.ts`
- `tests/core/configuration/ConfigLoader.test.ts`
- `tests/server/NoStoreHeaders.test.ts`
- `tests/server/StaticAssetCache.test.ts`
- `tests/server/RenderHtml.test.ts`

## Known Existing Warnings
The production build still reports pre-existing warnings that are not
addressed by this branch:
- inconsistent JSON import attributes for `resources/countries.json`
- inconsistent JSON import attributes for `resources/QuickChat.json`
- large chunk warnings from Vite

## Rollout Notes
- Cache rules should treat `/_assets/**` and `/assets/**` as immutable.
- Cloudflare will still classify HTML as dynamic after deploy unless
matching edge cache rules are configured for it.

## Follow-ups
- Remove `/api/instance` by changing `matchmaking/join` so the server
selects the target instance, or by making `INSTANCE_ID` deploy-stable if
the current contract must remain.


## Please complete the following:

- [ ] I have added screenshots for all UI updates
- [ ] I process any text displayed to the user through translateText()
and I've added it to the en.json file
- [ ] I have added relevant tests to the test directory
- [ ] 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:

DISCORD_USERNAME
2026-03-23 11:36:52 -07:00
FloPinguin bf09b9c9be Improve JoinLobbyModal (#3482)
## Description:

Perviously, JoinLobbyModal did not show settings like "Infinite gold" or
"Instant Build" or changed tribe count.
Now it does. Only if the setting differs from the default. I tested a
lot of scenarios, I also thought of the public game modifiers.
And we show a small map image now.

Public game with lots of modifiers:

<img width="780" height="758" alt="Screenshot 2026-03-21 011805"
src="https://github.com/user-attachments/assets/9d3fcaa9-3a50-42b2-a351-ac737ef18230"
/>

A private game with lots of custom settings:

<img width="776" height="530" alt="Screenshot 2026-03-21 011940"
src="https://github.com/user-attachments/assets/8f9a3809-844d-4f24-8f92-46c4ce480f8c"
/>

A private game with disabled units:

<img width="786" height="562" alt="Screenshot 2026-03-21 012134"
src="https://github.com/user-attachments/assets/61058329-1d86-4667-a945-7819b89cbf41"
/>

Regular public FFA (No modifiers):

<img width="780" height="372" alt="Screenshot 2026-03-21 012228"
src="https://github.com/user-attachments/assets/abdc42f0-8f2c-40c1-8719-76c648a12bae"
/>

This PR also includes a fix for UsernameInput:

<img width="910" height="647" alt="Screenshot 2026-03-20 222021"
src="https://github.com/user-attachments/assets/e1922395-9dfc-4b32-b987-e2dbff9af917"
/>

This PR also fixes the default private lobby difficulty in GameManager

## 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
2026-03-20 20:43:35 -07:00
evanpelle e14f1e8cea max of 3 modifiers for special (4 was confusing to me) 2026-03-19 21:16:38 -07:00
evanpelle c5706613e4 make 1 in every 3 games compact 2026-03-19 21:07:34 -07:00
FloPinguin 1220a331ba Remove modifiers from normal FFA/Team games (And increase chance of gold multiplier for special games, decrease random spawn) 🎲 (#3471)
## Description:

Normal (FFA and Team) public games no longer roll random modifiers.
Special games remain fully unaffected and continue to use random
modifiers as before.

I also increased the gold multiplier ticket count in the special
modifier pool from 1 to 4 because of player feedback.

Edit: And because I saw complaints of too much random spawn I decreased
the chance of it.

## 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
2026-03-19 14:50:07 -07:00
FloPinguin 4eb570fb8b Remove modifiers from normal FFA/Team games (And increase chance of gold multiplier for special games, decrease random spawn) 🎲 (#3471)
## Description:

Normal (FFA and Team) public games no longer roll random modifiers.
Special games remain fully unaffected and continue to use random
modifiers as before.

I also increased the gold multiplier ticket count in the special
modifier pool from 1 to 4 because of player feedback.

Edit: And because I saw complaints of too much random spawn I decreased
the chance of it.

## 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
2026-03-19 14:48:17 -07:00
evanpelle 6b9603d445 Merge branch 'v30' 2026-03-18 19:29:42 -07:00
FloPinguin 5b0b9dfd31 Increase spawn immunity from 30s to 45s for 5M starting gold maps 🛡️ (#3457)
## Description:

Increases the spawn immunity duration from 30s to 45s for maps with 5M
starting gold.

The previous 30s was too short - 45s gives players 15s longer than it
takes to build a SAM, allowing them to establish basic defenses before
becoming vulnerable.

## 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
2026-03-17 15:57:15 -07:00
FloPinguin afdb04ae5d Increase spawn immunity from 30s to 45s for 5M starting gold maps 🛡️ (#3457)
## Description:

Increases the spawn immunity duration from 30s to 45s for maps with 5M
starting gold.

The previous 30s was too short - 45s gives players 15s longer than it
takes to build a SAM, allowing them to establish basic defenses before
becoming vulnerable.

## 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
2026-03-17 15:56:52 -07:00
Ryan 1049b7e7dc Clan System Part 1 (#3276)
## Description:

Properly split out clantags and usernames, a clantag should not be part
of a username.

<img width="285" height="286" alt="image"
src="https://github.com/user-attachments/assets/8ac56e82-b12c-4fc0-9774-e445252a6e61"
/>

https://api.openfront.dev/game/ojkqZFb2


<img width="296" height="596" alt="image"
src="https://github.com/user-attachments/assets/85152f80-c111-4f87-b85b-8516c9c6137b"
/>


https://api.openfront.dev/game/MF32BkVc


requires;
https://github.com/openfrontio/infra/pull/264

## 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-03-17 15:55:47 -07:00
Evan dd2c239aa1 Have Worker rate limit ws messages (#3449)
## Description:

Prevent client from spamming ws messages before joining a game server.

## 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-03-16 20:45:05 -07:00
Evan 5e7317a818 Update socket rate limiting (#3447)
## Description:

On replays, there can be a burst of traffic from hashes, so instead just
have a 2MB limit per client for the entire game. Also the winner message
can be 100s of kb on a large game with many players, so now we don't
need to put a special case for that.

## 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-03-16 20:26:56 -07:00
evanpelle 194a288ce1 reduce ws max size to 1 mb 2026-03-16 20:13:14 -07:00
FloPinguin 71e5faf4ec Rebalance HvN (#3433)
## Description:

For the next v30 fix version

<img width="868" height="364" alt="imaege"
src="https://github.com/user-attachments/assets/520a999c-67e7-4c57-8651-895ad9eeb73a"
/>

HvN balancing for the revamped difficulty steps of v30 sadly doesn't
really work out...
In medium difficulty games humans nearly always win (boring)
In hard difficulty games humans usually lose
It was intended differently...

So lets get rid of medium difficulty HvN, always use hard difficulty and
disable the donation-capability for public game nations.
That will tune the human winrate towards a middle ground at about 65% I
think. Which should be nice.
Easier than in v29 (was frustrating sometimes) but not as easy as it's
now.

We can only test this in prod lol

## 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
2026-03-16 12:25:43 -07:00
FloPinguin aa59dd23be Rebalance HvN (#3433)
## Description:

For the next v30 fix version

<img width="868" height="364" alt="imaege"
src="https://github.com/user-attachments/assets/520a999c-67e7-4c57-8651-895ad9eeb73a"
/>

HvN balancing for the revamped difficulty steps of v30 sadly doesn't
really work out...
In medium difficulty games humans nearly always win (boring)
In hard difficulty games humans usually lose
It was intended differently...

So lets get rid of medium difficulty HvN, always use hard difficulty and
disable the donation-capability for public game nations.
That will tune the human winrate towards a middle ground at about 65% I
think. Which should be nice.
Easier than in v29 (was frustrating sometimes) but not as easy as it's
now.

We can only test this in prod lol

## 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
2026-03-15 21:28:40 -07:00
evanpelle 3919f17e8b Revert "Rearrange homepage game boxes & tune special modifier probabilities 🎲 (#3420)"
This reverts commit ea4355f03a.
2026-03-14 19:29:57 -07:00
evanpelle c8ed6b0e70 Merge branch 'v30' 2026-03-14 19:28:38 -07:00
evanpelle f6167d2d94 allow 3 send winner msgs, in case a client reconnects 2026-03-14 11:30:12 -07:00
Josh Harris 3273931950 Fix public lobby timer stuck due to IPC race condition 2026-03-14 06:02:57 +00:00
Evan 5fb7f75f3d Server-side WebSocket message rate limiting & size enforcement (#3424)
## Description:

* Adds ClientMsgRateLimiter — a per-client token-bucket rate limiter
that gates all incoming WebSocket messages. Returns "ok", "limit"
(drop), or "kick" based on the violation type.

* Intent messages are capped at 500 bytes each (they are stored in turn
history for the game duration, so oversized intents
accumulate in server RAM). Violations kick the client.

* Winner messages bypass the byte rate limit (they include stats for all
players and can be 100s of KB) but are strictly capped at one per client
— a second winner message kicks the client.

* All other messages go through the standard per-second (10/s) and
per-minute (150/min) rate limits. Violations drop the message; byte
budget exhaustion kicks the client.

* WebSocket maxPayload set to 2 MB on game workers.
Invalid (unparseable) messages now immediately kick the client rather
than being silently dropped.
Unit tests added for all rate limiting behaviors.

## 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-03-13 21:15:10 -07:00
evanpelle 9721aae9ab Kill and restart workers when IPC send fails
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-13 19:10:27 -07:00
evanpelle e596b998f8 terminate lobby ws on request 2026-03-13 18:55:59 -07:00