Commit Graph

535 Commits

Author SHA1 Message Date
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
evanpelle 2741e315e0 kick players when intents too large 2026-03-13 18:44:18 -07:00
evanpelle d4321ba81f add intent based rate limits 2026-03-13 18:32:29 -07:00
evanpelle add21ace42 Revert "Rearrange homepage game boxes & tune special modifier probabilities 🎲 (#3420)"
This reverts commit ea4355f03a.
2026-03-13 12:14:36 -07:00
FloPinguin ea4355f03a Rearrange homepage game boxes & tune special modifier probabilities 🎲 (#3420)
## Description:

**Homepage layout:** Reorder the game mode cards so FFA is the left
(large) box, Teams is the upper-right box, and Special Games is the
lower-right box. Mobile order updated to match (FFA → Teams → Special).

**Special game modifiers:**
- Adjusted modifier count roll to 40%/40%/15%/5% for 1/2/3/4 modifiers
(was 30%/40%/20%/10%) because having so many special games with 3/4
modifiers while we only have 8 modifiers in the pool is a bit dumb (from
the 8 modifiers two are mutually exclusive and 4 should be quite rare).
- Changed ticket counts in `SPECIAL_MODIFIER_POOL` so
isAlliancesDisabled and isHardNations are more rare.

## 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-13 11:55:03 -07:00
FloPinguin 2419f77f17 Rearrange homepage game boxes & tune special modifier probabilities 🎲 (#3420)
## Description:

**Homepage layout:** Reorder the game mode cards so FFA is the left
(large) box, Teams is the upper-right box, and Special Games is the
lower-right box. Mobile order updated to match (FFA → Teams → Special).

**Special game modifiers:**
- Adjusted modifier count roll to 40%/40%/15%/5% for 1/2/3/4 modifiers
(was 30%/40%/20%/10%) because having so many special games with 3/4
modifiers while we only have 8 modifiers in the pool is a bit dumb (from
the 8 modifiers two are mutually exclusive and 4 should be quite rare).
- Changed ticket counts in `SPECIAL_MODIFIER_POOL` so
isAlliancesDisabled and isHardNations are more rare.

## 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-13 11:54:39 -07:00
evanpelle 60e0ea6425 reduce lobby update rate from every 250ms => 500ms to reduce bandwidth 2026-03-12 16:22:03 -07:00
evanpelle ebe7f76cd3 fix: track max player count reached to correctly determine lobby phase, this is to prevent old lobbies reappearing when someone leaves before the game starts 2026-03-12 11:25:02 -07:00
evanpelle 4cfefdfb02 fix: don't report game as Lobby phase when players leave mid-game
After a player left, the server would fall back to Lobby phase if player
count dropped below the max — even if the game had already started.
Now checks hasStarted() before reporting Lobby phase.
2026-03-11 21:30:04 -07:00
evanpelle 2c13c41077 make world more frequent in public games 2026-03-11 14:38:13 -07:00
evanpelle fee625801d fix: track desynced clients as live set instead of accumulating count 2026-03-11 14:35:25 -07:00
FloPinguin 3838de1d30 Option to disable alliances + 2 new modifiers for variety 😄 (#3392)
## Description:

Rex had this idea: "It would be funny to have an option in private
lobbies to disable alliances."
I added it as an option.
Now people can choose to live in constant fear of their neighbors 😆 

Also added two new public game modifiers for variety (only for the
special rotation):
- Alliances disabled (low probability)
- x2 gold multiplier (low probability)

Would be nice to squeeze this into v30, last minute?

## 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-09 21:13:13 -07:00
evanpelle fdaeaf66d0 bugfix: invalid banned word caused PrivilegeRefresher to fail to load 2026-03-09 14:46:42 -07:00
RickD004 84ae5fc879 Adds Aegean map (#3384)
## Description:

Adds Aegean map, a map centered in the Aegean Sea and the aegean islands
between Greece and Turkey. Map has approx. 1M land tiles, size of
1600x2000.

Nations are named after Ancient Greece era city-states and tribes.
Elevation source from OpenTopography, already credited

<img width="1600" height="2000" alt="image"
src="https://github.com/user-attachments/assets/e4f52d6e-bba4-4641-9eac-31e3ddee354e"
/>
<img width="453" height="445" alt="Captura de pantalla 2026-03-08
141256"
src="https://github.com/user-attachments/assets/5d2bc8cf-1e54-461a-ae0f-9bb2dafc2db6"
/>

This has been a heavily requested map in the community, having
suggestions in the Discord, Subreddit and even in some videos (for
example i saw Ultimus Rex suggest an aegean map when asked what maps he
would like in his last stream)

The map is designed so that the greek and turkish main landmasses are
around 400,000 pixels in area, which combined account for around less or
equal to 80% of the map. This means players will have to cross the sea
to win, and to do so they will have to hop across the islands, which
means there will be heavy warship action, instead of having stalemates
like in most island maps where the gap between islands is too large and
players would rather bomb each other.

## 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-08 22:05:09 -07:00
RickD004 df62251d3a Add San Francisco map (#3373)
## Description:

Adds San Francisco bay map. 21 nations based on cities and towns of the
area. 1.8M land pixels , size of 2000x1700
Elevation data from Opentopography, already credited. 
Map frequency of 3, as to mirror New York map.

<img width="2000" height="1700" alt="image"
src="https://github.com/user-attachments/assets/dc80a2db-6233-4b50-8f07-bd21c23c8b53"
/>

## 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-07 20:51:59 -08:00
RickD004 6254cc0598 Add Arctic map (#3341)
## Description:

Adds Arctic map, a map centered about the Geographical North Pole using
an azimuthal equidistant projection. Features Cold War themed countries
and subdivisions as nations. Square map with 1.6M land tiles. Terrain
data from Opentopography and Arctic SDI real relief data

<img width="1830" height="1830" alt="image"
src="https://github.com/user-attachments/assets/0b8b1e42-f477-4ebf-a256-c07536db87d9"
/>

## 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-05 20:43:34 -08:00
FloPinguin 6154b779f5 Fix compact map playercount 🔧 (#3361)
## Description:

The recently improved `supportsCompactMapForTeams` only checked that
each team had ≥2 players but not that there were ≥2 teams. On very small
maps with compact + Duos (rare), this allowed lobbies with 1 team of 2,
which makes no sense (Wonder noticed that randomly while looking at the
homepage). Added a `numberOfTeams ≥ 2` check so the compact map modifier
isn't active when the player count can't sustain multiple teams.

The 125-player performance cap was also applied inside
`calculateMapPlayerCounts` before the compact 75% reduction, so a map
sized for 200 players would get capped to 125 then reduced to 31 instead
of the expected 50. Moved the cap (`MAX_PLAYER_COUNT`) to after the
compact reduction.

## 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-05 15:21:35 -08:00