Commit Graph

636 Commits

Author SHA1 Message Date
Patrick Plays Badly b4058b5a58 Add map chopping block (#4143)
Resolves #4080

## Description:

Add Map Chopping Block
https://youtu.be/NpX73lHiKO8

Increased multiplier for 4 player team games and water nukes (plug in
center among other shortcuts). This map was made as a faster alternative
to Labyrinth. Map has been modified since last submission to be 'less
crazy'.

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

## Discord username:

PlaysBadly
2026-06-04 15:58:34 -07:00
Ryan 9c2ac05506 clantag part 1 (#4066)
If this PR fixes an issue, link it below. If not, delete these two
lines.
Resolves #(issue number)

## Description:

adds a check to see if you're in a clan or not. if not, checks to see if
the clan exists, if it does, warns the user, if it doesn't, lets them
use 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:

w.o.n
2026-06-03 14:25:55 -07:00
Evan 48609fa70a Reduce lobby broadcast bandwidth via counts-only deltas (#4116)
## Description:

- The lobby WebSocket broadcast (`/lobbies`) was re-sending the full
`PublicGames` snapshot — including each lobby's `gameConfig` — to every
connected client every 500ms. Almost nothing in that payload changes
tick-to-tick; only `numClients` moves.
- `WorkerLobbyService` now tracks the sorted set of `gameID`s it last
sent as a full snapshot. On each incoming broadcast it sends a `full`
only when that set changes; otherwise it sends a `counts` delta carrying
just `{gameID → numClients}`.
- This relies on the master-side coupling at
[MasterLobbyService.ts:140-159](src/server/MasterLobbyService.ts#L140-L159):
when master finds a lobby without `startsAt`, it both sets `startsAt`
AND schedules a fresh lobby on the same tick, so the gameID change
brings the `startsAt` (and `gameConfig`) along with it.
- New WS connections are primed with the worker's cached last `full` so
late joiners don't have to wait for the next structural change.
- `LobbySocket` parses the new discriminated union (`PublicLobbyMessage
= full | counts`), keeps the last full snapshot in memory, and merges
counts into it before invoking the existing callback. `GameModeSelector`
is unchanged.
- Master → worker IPC is unchanged — still sends the full snapshot every
500ms. The optimization only applies to the worker → WS-client boundary,
which is the fan-out point.

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

## Please put your Discord username so you can be contacted if a bug or
regression is found:

evan
2026-06-02 15:52:14 -07:00
RickD004 95377f0361 Adds map of Southeast Asia (#4105)
Resolves #4098

## Description:

Adds Southeast Asia map for v32. Very requested map. 31 default nations
(with an extra 31 named for HvN).

Map for intense warship and naval warfare with many, many islands. Also
adds flags of the region to be used by nations in the map. More info
specified in issue


https://github.com/user-attachments/assets/b4151db4-825a-4c1c-8bf8-7b760ae056d2

## 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-06-01 17:29:56 -07:00
RickD004 c049a81b86 Adds map of the Caribbean 🏴‍☠️ (#4067)
## Description:

Fixes #4069

Adds map of the Caribbean sea and its islands. Archipelago map with lots
of islands, lots of water and a lot of trade.

This map has multiple large landmasses of similar size to prevent
steamrolls (the largest islands and landmasses are around 30%), and
many, many small islands where players can survive and trade. Players
will have to island hop in order to win. 34 nations of Caribbean
countries and territories, with an extra 28 AdditionalNations for a
total of 62 nations for crowded HvN.

Heavy Island maps are very popular in the broader community and we dont
have one for v32, so i figured it would be nice to have a very requested
and popular world location

570k land tiles, fairly small for a map, would be right placed before
World (600k tiles). Also adds some flags of caribbean regions.


https://github.com/user-attachments/assets/9eae81ec-58eb-4594-89fd-2f95742f8b3a

Terrain source from OpenTopography, already credited. No modification to
the tests are needed for new maps added in Game.ts

## 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-29 19:23:21 -07:00
TKTK123456 9d4080fbe8 Adds onion map (#4057)
If this PR fixes an issue, link it below. If not, delete these two
lines.
Resolves #4055 

## Description:

Adds a 512*512 onion map with 3 nations (Leafer Confederation, Outer
Enclave and Inner Tribe)

<img width="128" height="128" alt="thumbnail"
src="https://github.com/user-attachments/assets/8d97d8dc-6286-4e79-a459-767c936d49ec"
/>


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

tktk1234567
2026-05-29 15:58:02 -07:00
RickD004 b043dc6c15 Team Maps Expansion: New team spawnzones for multiple maps (#4058)
## Description:

Lets give Teams and HvN gamemodes some attention. Adds team spawnzones
to the following maps, and boosts them to appear more frequently as this
gamemode:

- Straitofgibraltar - 2 teams
- Aegean - 2 teams
- Beringsea - 2 teams
- Beringstrait - 2 teams
- Bosphorusstraits - 2 teams
- Conakry - 2 teams
- Falklandislands - 2 teams
- Straitofhormuz - 2 teams
- Tradersdream - 2 teams
- Surrounded - 2 teams & 4 teams
- Pluto - 2 teams
- Gulf of St. Lawrence - 3 teams

These maps (especially the ones for 2 teams) are all very symmetrical
and would be nice gift for the playerbase, which enjoys these kind of
games like FourIslands4Teams and Baikal2Teams. This is also nice for
HvN, as it centralizes the players and gives them a better chance at
defeating the nations.

Screenshots of the maps with the new team spawnzones:


<img width="1320" height="486" alt="Captura de pantalla 2026-05-28
001558"
src="https://github.com/user-attachments/assets/e0b4bea6-d1b7-4793-a995-ec2a139a5af6"
/>
<img width="1177" height="528" alt="Captura de pantalla 2026-05-28
001913"
src="https://github.com/user-attachments/assets/28ec5bf8-3a02-4660-ba62-3edbcabeaf51"
/>
<img width="1147" height="531" alt="Captura de pantalla 2026-05-28
002032"
src="https://github.com/user-attachments/assets/b148f1ae-473a-4505-b0f4-ca8820fbbb55"
/>
<img width="1219" height="536" alt="Captura de pantalla 2026-05-28
002348"
src="https://github.com/user-attachments/assets/89af4d27-eadf-447c-9bde-d0dcfe1ff757"
/>
<img width="923" height="524" alt="Captura de pantalla 2026-05-28
002704"
src="https://github.com/user-attachments/assets/50ad1b11-1685-41fb-b14d-088a2f0db88b"
/>
<img width="1307" height="456" alt="Captura de pantalla 2026-05-28
002859"
src="https://github.com/user-attachments/assets/4ef18da9-336a-4698-8af0-2769467148b4"
/>
<img width="1219" height="548" alt="Captura de pantalla 2026-05-28
003134"
src="https://github.com/user-attachments/assets/d0a514bf-e6e6-43f6-89b7-2168bc395010"
/>
<img width="1200" height="538" alt="Captura de pantalla 2026-05-28
003449"
src="https://github.com/user-attachments/assets/c1672296-db4d-4baf-9992-4bb380fab4e9"
/>
<img width="1032" height="501" alt="Captura de pantalla 2026-05-28
003650"
src="https://github.com/user-attachments/assets/8dd5ee07-3ac3-4f03-a56e-31c01d612655"
/>
<img width="1074" height="525" alt="Captura de pantalla 2026-05-28
003951"
src="https://github.com/user-attachments/assets/e140706b-3f1c-4e09-b70c-efc3e6536c60"
/>
<img width="914" height="513" alt="Captura de pantalla 2026-05-28
004632"
src="https://github.com/user-attachments/assets/e0dd6820-62f4-48b6-8356-df20c0e6ed8f"
/>
<img width="988" height="509" alt="Captura de pantalla 2026-05-28
005518"
src="https://github.com/user-attachments/assets/0da95c41-1191-4de4-a3ce-873839c00605"
/>
<img width="986" height="514" alt="Captura de pantalla 2026-05-28
000505"
src="https://github.com/user-attachments/assets/4eb20c73-56ba-4f9f-90af-8a047aa399eb"
/>


## 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-28 15:34:26 -07:00
crunchybbb 2cb5244ad4 Adds Map of the Yellow Sea (#4026)
## Description:

"A high-stakes naval theater where empires clash over narrow corridors,
bottleneck straits, and heavily fortified shorelines."

Modeled to the exact strategic proportions of the classic Black Sea map,
Yellow Sea shifts the focus of global conflict to East Asia. The map is
defined by its massive central body of water, making naval dominance
absolutely essential for survival. However, unlike wide-open oceans,
control of the Yellow Sea is entirely dictated by its unique coastal
geography.
The Shandong And Liaoning Peninsulas are The definitive feature of the
map. Two massive, opposing peninsulas project deep into the sea, acting
as natural, heavily contestable daggers. They create tight naval choke
points in the central waters while forcing land-based players into
brutal, linear frontlines where every pixel of territory is bought with
blood.
The Continental Rim: A sprawling mainland coast wraps around the
northern and western edges of the map, offering expansive land routes
for players who prefer sweeping land invasions over amphibious assaults.

Scale Class: Medium

Gameplay Style: Naval/Land Hybrid, Tactical Choke Points, Frontline
Bottlenecks

Nations: 8
North Korea South Korea Liaoning Shandong Beijing Hebei Tianjin Jilin



description mostly generated by google gemini ai

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

<img width="1660" height="1266" alt="Screenshot 2026-05-24 220103"
src="https://github.com/user-attachments/assets/800c6732-677d-44f1-ba5c-c60da5f199e0"
/>


<img width="1500" height="1152" alt="yellow_sea2"
src="https://github.com/user-attachments/assets/9b3ba34a-3f9c-4485-9235-f953fd07be4c"
/>

Game play video https://youtu.be/IcRPTM0rHM0

---------

Co-authored-by: RickD004 <realtacoco@gmail.com>
2026-05-28 15:30:47 -07:00
Evan aa3959bffe feat: territory png based skins (#4006)
## Description:

Add image-based territory skins as a new cosmetic type, rendered
alongside the existing 1-bit patterns. Skins render a single PNG
centered on each player's spawn tile — opaque pixels show the skin
(multiplied by team color in team games, raw colors in FFA), transparent
pixels and tiles outside the image bounds fall through to the regular
player palette color.

**Cosmetic plumbing**
- `SkinSchema` in `CosmeticSchemas.ts`, optional `skins` map on
`CosmeticsSchema`
- `PlayerSkin`, `PlayerCosmetics.skin`, `PlayerCosmeticRefs.skinName` in
`Schemas.ts`
- Server-side resolution: `PrivilegeCheckerImpl.isSkinAllowed` (gated by
`skin:*` / `skin:<name>` flares)
- Client persistence: stored under `PATTERN_KEY` (`pattern:` and `skin:`
share one slot — they're mutually exclusive)
- `getPlayerCosmeticsRefs` only emits a `skinName` when cosmetics are
loaded, the skin exists in the catalog, and the user has the right flare
— otherwise drops the ref and clears storage

**Renderer**
- `SkinAtlasArray` — fixed `TEXTURE_2D_ARRAY`, 1024×1024 per layer,
exact layer count allocated once at game start from the locked-in player
set. No resize, no callbacks, no retained `HTMLImageElement`. Zero GPU
cost when no players have skins (1×1 placeholder).
- `skinLayerTex` (R8UI 4096×1) — per-player `layer + 1` (`0` = no skin)
- `skinAnchorTex` (RG16UI 4096×1) — per-player spawn tile, so the PNG
center anchors at each player's spawn (re-uploads when the player
re-picks during spawn phase)
- `WebGLFrameBuilder.syncPlayers` collects unique skin URLs on first
sync and calls `view.initSkinAtlas(urls)` once; `clearCaches()` resets
so seek/replay re-initializes
- `territory.frag.glsl`: skin branch is mutually exclusive with
patterns; bounds-checks UVs against `[0, 1]` so the image is a single
stamp, not tiled; alpha-blends against the player palette color so
transparent pixels and out-of-bounds tiles render as the regular player
color

**Hover highlight (global UX change, not skin-scoped)**
- Existing hover highlight changed from "brighten toward white" to
"saturation boost." Applies to all players regardless of
skin/pattern/flat-color — looks better across the board.

**UI**
- `CosmeticButton` renders skins as a single `<img>` (object-contain)
- `TerritoryPatternsModal` merges patterns + skins into one grid; single
"default" tile clears both
- Selecting a pattern clears the skin and vice versa (mutually
exclusive)
- `Store` pattern tab includes skin entries (purchasable, not-yet-owned)
- `PatternInput` lobby button previews the active skin when one is set

**Memory**
- 0 skin players → ~4 bytes (placeholder) + ~40 KB fixed per-player
tables
- 1 skin player → ~5.6 MB GPU
- 5 skin players → ~28 MB GPU
- 10 skin players → ~56 MB GPU

**Tests**
- `tests/Privilege.test.ts`: 13 new cases covering `isSkinAllowed`
(wildcard, exact-match, missing flare, missing skin, forged refs) and
`isAllowed` integration (allowed/forbidden paths, short-circuit when
invalid skin is paired with valid other cosmetics)

## 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
- [x] 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:

evan
2026-05-27 13:00:07 -07:00
Berk ddf63066fa fix(game): patch Desync DoS vulnerability with strict majority consensus (#3956)
Resolves #3959

## Description:

This PR fixes a Denial of Service (DoS) vulnerability in 1v1 matches
related to desync reporting. The `findOutOfSyncClients` logic previously
forced a game-ending desync if half or more players reported conflicting
hashes (`outOfSyncClients.length >= Math.floor(this.activeClients.length
/ 2)`). In a 1v1, this meant a single malicious player sending a bad
hash could trigger a global desync, crashing their opponent's game
session.

The logic has been corrected to require a **strict majority** (`>
Math.floor(this.activeClients.length / 2)`) to declare a lobby-wide
desync. In a 1v1 game, a single malicious actor will now simply be
flagged as the out-of-sync client and disconnected, allowing the honest
player to continue their session uninterrupted.

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

barfires

Co-authored-by: Josh Harris <josh@wickedsick.com>
2026-05-27 14:10:43 +00:00
Patrick Plays Badly 172113193f Add May Labyrinth (#4002)
## Description:

Labyrinth is a maze type map. My attempt at making a more chess style
board for play. Games with bots appear stable at over 45min average run
times. The map has been setup for team spawn zones for 2, 3, 4, 5, 6,
and 7 teams. Some of the team spawns for odd numbers are experimental
and I would like to see how they play out with live players. Additional
nation names included. There are other design factors like each of the
large squares being within the blast radius of a hydro; small islands
are within the blast radius of nukes.

This is meant as a slower playing game. My intentions are to get some
sort of literal rotation of the map in the future if easily implemented.
That way every time players load the game there would be some
randomization.

As an additional note one of my last edit to the map was the "+" shape
to the islands to allow train passage. Zooming out I can see now that
the pattern is squares and + through out. Did not fully intend on that,
but it felt like good vibes.


https://discord.com/channels/1284581928254701718/1293201128858587207/threads/1497062552784605316
https://www.youtube.com/watch?v=e8c-TylT4hs
https://www.youtube.com/watch?v=0-yqrfr3nv0


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

PlaysBadly

---------

Co-authored-by: RickD004 <realtacoco@gmail.com>
2026-05-26 19:25:43 -07:00
crunchybbb b086881a4e Add Korea Map (#3977)
## Description:

Add map of korean peninsula. Size 1092x2149
Nations: 35
based on provinces

## 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
crunchybbbbb @crunchybbbbb_59469


<img width="1092" height="2149" alt="Korea-2"
src="https://github.com/user-attachments/assets/874100e8-4a68-4f57-b2f7-49aa87b8194d"
/>

two teams nations war video https://www.youtube.com/watch?v=n4h7GAfAHTM

---------

Co-authored-by: Ricky G.P. <realtacoco@gmail.com>
2026-05-26 19:11:13 -07:00
Josh Harris 2d6342cd22 Add stale-if-error to app shell Cache-Control (#4009)
## Description:

Adds `stale-if-error=86400` to the `Cache-Control` header set on the
rendered app shell (`/`) in
[src/server/RenderHtml.ts](src/server/RenderHtml.ts). This lets shared
caches (CloudFlare, nginx `proxy_cache`) keep serving the last good
`index.html` for up to 24h if origin returns a 5xx, alongside the
existing `stale-while-revalidate` window.

Pairs with enabling HTML caching for the `/` route on CloudFlare in
"respect origin headers" mode — it already honors `s-maxage` (5 min edge
TTL) and `stale-while-revalidate`; this just extends the same safety net
to origin-error cases.

No behavior change for successful responses; browsers still revalidate
every load via `max-age=0`.

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

jish

---------

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-25 21:13:48 +01:00
Evan 3811d3cd89 Hide clan tags in public FFA games to prevent teaming (#4000)
## Description:

- Added optional `disableClanTags` to `GameConfig`. When set, the server
strips clan tags from `gameInfo` (lobby broadcasts/HTTP) and
`gameStartInfo` (start payload) before sending to clients. Archive keeps
the originals.
- Enabled `disableClanTags` for public FFA games (both the regular FFA
playlist and special when randomized to FFA). No UI; clients still see
their own clan tag via local input 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:

evan
2026-05-24 16:52:10 +01:00
RickD004 5a2c0504eb adds map of the Balkans (using Additional nations feature) (#3998)
## Description:

Adds map of the Balkan Peninsula and surroundings. Heavily requested map
with multiple posts on the Discord all with over 10 or 20 upvotes.

23 NPC/Nations based on countries and relevant regions of the area. Adds
an extra 39 nations for crowded Humans vs Nations gamemode for a total
of 62 NPCs, based on regions of multiple countries. Also some flags for
some regions.

Source from NASA DEM, already credited

Photo of base map, and 62 HvN:


<img width="614" height="588" alt="Captura de pantalla 2026-05-24
030105"
src="https://github.com/user-attachments/assets/5742a4c3-1b1f-4ca7-858d-91529861dd81"
/>

<img width="548" height="547" alt="image"
src="https://github.com/user-attachments/assets/758d8ad0-1515-41b8-8d42-14e76cdd54ed"
/>

This map completes the quartet row of "polemic" maps for v32

<img width="678" height="119" alt="image"
src="https://github.com/user-attachments/assets/9e6f4ef1-f0cc-48ea-a59f-b7ff69033b73"
/>

## 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-24 16:09:37 +01:00
evanpelle 14f2e36d15 set dev public lobby time back to 5 seconds 2026-05-23 21:43:37 +01:00
evanpelle 8f982ce123 Extend friend grouping to the lobby team preview
The preview was calling assignTeams without friend data, so the
team layout shown in the lobby could differ from the layout the
game actually started with. Wire friends through ClientInfo so
the preview matches.

Extract the publicId→clientID translation used by both start()
and gameInfo() into buildFriendsLookup() to remove the duplicate.
2026-05-23 20:52:13 +01:00
Evan db501c68d2 Put friends on the same team (#3994)
Fixes #3911

## Description:

- Server captures `publicId` and `friends` from `getUserMe()` and
includes each player's in-game friend `clientID`s in `PlayerSchema` on
game start
- Team assignment treats friends as a **soft preference** (best-effort):
a non-clan player goes to the team where the most of their friends
already are; if that team is full they spill to the next-emptiest team
rather than getting kicked
- Clans remain strict (kick overflow) since clan membership is an
explicit opt-in; friends are implicit, so a friend-of-friend chain that
doesn't fit shouldn't bench anyone
- Friendship is symmetric — an edge from either direction counts, which
keeps things working when one side's `getUserMe` is stale
- Lobby preview unchanged — friend grouping only takes effect once the
game actually starts (avoids exposing friend lists in the lobby payload)


## 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-23 18:02:41 +01:00
RickD004 b1ec3ac70f Adds Indian Subcontinent map (#3975)
## Description:

Adds Map of the Indian Subcontinent, with indian and pakistani states
and surrounding countries, important rivers like the Ganges, Brahmaputra
and Indus, and Tibet/ theHimalayas

2M land pixels and 52 Nations (i think its fitting that India has the
most nations of a regional map, only continental maps have more)

Should be nice to boost whatever indian playerbase this game might have.
This region also doesnt have any representation aside from continental
maps

<img width="584" height="598" alt="image"
src="https://github.com/user-attachments/assets/4089049a-800b-4e37-ab34-2afc5de821e8"
/>
<img width="418" height="462" alt="image"
src="https://github.com/user-attachments/assets/a68e2424-5972-4105-86c9-0312ab095024"
/>

Elevation data from NASA DEM, already credited in CREDITS.md

No reference test is needed, the test suite automatically iterates over
all GameMapType enum values — no map is hardcoded by name in the tests

## 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-23 17:38:03 +01:00
RickD004 6591b055c3 Adds map of Venice 🛶 (#3935)
## Description:

Adds map of Venice. A relatively small map (similar land area to World)
for heavy trade and lots of boating.

Because of the very low difference of elevation of the zone, terrain is
instead used to show buildings.

Map source from OpenStreetMap, already credited in CREDITS.md

Very requested map, with 2 discord posts suggesting it with +15 upvotes
each

<img width="794" height="569" alt="image"
src="https://github.com/user-attachments/assets/ca7d44f2-cfc9-4e93-b7d4-43dbe62f74d4"
/>

## 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-18 19:43:02 -07:00
evanpelle f23789883b Merge webgl2 — full WebGL2 renderer migration
relates to #893

Replaces the canvas2D + Pixi.js map renderer with a pure WebGL2 pipeline.
Map-space visuals (terrain, names, structures, units, FX, selection
boxes, build ghosts, status icons, nuke trajectories, defense zones,
spawn glow, water-nuke terrain deltas) all render through dedicated
passes in src/client/render/gl/passes/. Controllers in
src/client/controllers/ push state directly to the WebGL view; no
relay events. Assets unified under resources/ + assetUrl(). Mode
toggle wired to the existing darkMode UserSetting (no more day/night
cycle). One input system (InputHandler + EventBus + TransformHandler).

Known regressions to address in follow-up work:

- [ ] webgl: highlight structures when hover on build menu
- [ ] webgl: custom flags, flag atlas
- [ ] webgl: territory patterns
- [ ] webgl: defense post outline
- [ ] webgl: territory expanse smoothing
2026-05-18 12:09:11 -07:00
evanpelle b27c2984fd include atlases/ in the public asset manifest
resources/atlases/ wasn't in the manifest glob list, so the build
skipped hashing/copying it into static/_assets/ and the deploy
pipeline's R2 uploader had no keys for it — atlases 404'd on staging.
2026-05-17 13:08:08 -07:00
Berk 5fefc21cb8 security: remove duplicate express.json() middleware (SEC-04) (#3947)
## Description:

The app had `express.json()` registered twice in `app.ts`. This can
cause issues with body parsing and is redundant.

**Fix:** Removed the second call to `app.use(express.json())`.

## Please complete the following:

- [x] I have added screenshots for all UI updates (N/A - no UI changes)
- [x] I process any text displayed to the user through translateText()
(N/A)
- [x] I have added relevant tests to the test directory (N/A - existing
tests pass)
- [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:

barfires
2026-05-16 19:33:47 -07:00
Berk 749f496318 fix: prevent sendStartGameMsg from crashing server on client disconnect (#3939)
The catch block in sendStartGameMsg() re-throws the error, which means a
single client's WebSocket failure (e.g. disconnected during game start)
propagates up and can crash the entire game server. The start() method
calls sendStartGameMsg() in a forEach loop over all clients, so one bad
client kills the game for everyone.

Changes:
- Added readyState check before sending
- Replaced re-throw with structured error logging
- A single client failure now logs the error and continues gracefully

If this PR fixes an issue, link it below. If not, delete these two
lines.
Resolves #(issue number)

## Description:

Describe the PR.

## 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-05-16 11:20:18 -07:00
Berk 48b957c297 fix: guard all ws.send() calls with readyState check to prevent server crashes (#3936)
## Description:

Several ws.send() calls in GameServer.ts were missing WebSocket.OPEN
readyState guards. This can lead to server crashes if a client
disconnects precisely between a check and the send. Added guards to
prestart, kickClient, and handleSynchronization.

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

barfires

Co-authored-by: 22314621 <22314621@student.ciu.edu.tr>
2026-05-16 11:17:05 -07:00
RickD004 7dc5d472a7 Change name of map "The Straits" into "Danish Straits" (#3929)
## Description:

Renames TheStraits map. The people that suggested this map told me they
would prefer a more specific name for the map, rather than the generic
one it has right now. So im renaming it into Danish Straits

This map is for v32, it has not been released, it should be fine to
rename


## 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-15 08:59:28 +00:00
RickD004 7359e2bc3b Adds Northwest Passage map (using new additionalNations feature) (#3920)
## Description:

Adds map "Northwest Passage", map of the Canadian Arctic Archipelago ,
Greenland and surroundings. "Northwest Passage" (NWP) is the sea lane
between the Atlantic and Pacific oceans
(https://en.wikipedia.org/wiki/Northwest_Passage) .

21 default nations, based on the towns of the region.

This map uses the brand new additionalNations feature made by FloPinguin
https://github.com/openfrontio/OpenFrontIO/pull/3902 . Adds 39 extra
nations for a total of 60 nations (so that in gamemodes like Humans vs
Nations all the nations have names of real places)

Comparison: 
- Map with default nations
- Map with extra named nations, tested by raising the number of nations
in Solo

<img width="1050" height="412" alt="image"
src="https://github.com/user-attachments/assets/12ed94f1-0615-4fb3-b0d0-dcecb65006ea"
/>
<img width="1089" height="436" alt="image"
src="https://github.com/user-attachments/assets/6e7c11bf-7382-4e36-9433-229a9d463b68"
/>

Terrain source from OpenTopography, already credited in CREDITS.md

## 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-14 19:27:46 -07:00
FloPinguin 990eba6134 Improve MapPlaylist 🎲 (#3904)
## Description:

### 1. `SPECIAL_MODIFIER_POOL` rebalanced
Ticket weights adjusted to roughly track the community "favorite
modifier" poll

<img width="486" height="724" alt="Screenshot 2026-05-11 210740"
src="https://github.com/user-attachments/assets/bb1d2461-beb3-41c0-8d7b-b604db5fc033"
/>

- `isRandomSpawn`: 2 to 4
- `goldMultiplier`: 4 to 6
- `isWaterNukes`: 3 to 4
- `startingGold25M`: 1 to 3
- `startingGold5M`: 5 to 4
- `startingGold1M`: 3 to 2

### 2. New `SPECIAL_TEAM_MAPS` config
Replaces the hardcoded per-map branches in `getTeamCount` and
`buildMapsList`. Each entry maps a `GameMapType` to its preferred
`TeamCountConfig`. Shared constants:
- `SPECIAL_TEAM_FORCE_CHANCE = 0.75` (probability of overriding the
random team weights roll)
- `SPECIAL_TEAM_FREQ_MULTIPLIER = 2` (frequency boost in the team
playlist)

Current entries: Baikal (2), FourIslands (4), Luna (2). Behavior
preserved for the existing maps, but adding another special team map is
now a one-line entry.

### 3. New `FULL_LAND_MAPS` config (TheBox, Alps)
- Water nukes forced on 75% of the time in the special rotation
(overrides `WATER_NUKES_BOOSTED_MAPS`, which still applies its 50% boost
to FourIslands, Baikal, Luna, ArchipelagoSea). Because they make a lot
of fun on these two maps.
- The `isPortsDisabled` modifier is excluded unless water nukes is
boosted on, since ports are pointless on full-land maps. Because this
happened:
<img width="516" height="292" alt="image"
src="https://github.com/user-attachments/assets/cd9ce31d-25d0-4b35-a8ba-bb3ec1c02b70"
/>

### 4. Misc
- Renamed `frequency` constant to `FREQUENCY` for consistency with other
module-level constants.

### 5. Exclude `isNukesDisabled` on special team maps in team mode

On `SPECIAL_TEAM_MAPS` (FourIslands, Baikal, Luna) in team mode, the
`isNukesDisabled` modifier is now excluded from the pool. Otherwise an
extreme warship spam will follow.

## 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-05-11 19:27:02 -07:00
Evan 275fd0dccc refactor: collapse per-env Configs into ClientEnv + ServerEnv (#3906)
## Description:

This is a refactor to simplify config handling.

Replaces the per-environment DevConfig/PreprodConfig/ProdConfig class
hierarchy with two static classes: ClientEnv (browser main thread, reads
from window.BOOTSTRAP_CONFIG) and ServerEnv (Node server, reads from
process.env). The four config classes are deleted, the abstract
DefaultServerConfig is gone, and DefaultConfig is renamed to Config.

The values that flow server → client (gameEnv, numWorkers,
turnstileSiteKey, jwtAudience, instanceId) used to be baked into the
hardcoded per-env classes. They're now real env vars on the server,
embedded into a single window.BOOTSTRAP_CONFIG object in index.html at
request time (alongside the existing gitCommit/assetManifest/cdnBase
globals, which moved into the same object), and read back by ClientEnv
on the client. The dev defaults previously hidden inside DevServerConfig
are now explicit in start:server-dev (NUM_WORKERS=2,
TURNSTILE_SITE_KEY=1x..., JWT_AUDIENCE=localhost, etc.) and in
vite.config.ts's html plugin inject.data. Production deploys plumb
NUM_WORKERS and TURNSTILE_SITE_KEY through deploy.yml (GitHub vars) into
the remote env file; JWT_AUDIENCE is derived from DOMAIN in deploy.sh.
The dynamic /api/instance endpoint is gone — INSTANCE_ID rides along in
BOOTSTRAP_CONFIG now.

ServerEnv is the only thing server code touches; ClientEnv is
browser-only. The two classes have intentional overlap (env, numWorkers,
jwtIssuer, gameCreationRate, workerIndex, etc.) since they derive
identical logic from different sources — there's a TODO in each to
consolidate via a shared helper later. The game-logic Config no longer
stores a ServerConfig/ClientEnv reference and its serverConfig() getter
is gone; the one caller (MultiTabModal) now reads ClientEnv.env()
directly. Worker init no longer carries server-config values since
nothing in the worker actually reads them.

## 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-11 19:24:01 -07:00
RickD004 834a9757d7 Adds map "The Straits" (#3896)
## Description:

**Adds "The Straits" map:**

A map located around Denmark and the many surrounding straits: Kattegat,
Skagerrak and the Danish straits (thus the name, meant to be a creative
name like "Between Two Seas" and "Gateway to the Atlantic"). This map is
themed in the early 1900s, the nations/NPCs are traditional and
historical regions of Sweden-Norway, Denmark and the Germany.

Relatively small map with ~700k land tiles, similar to World

Inspired by this Discord thread with nearly 20 upvotes:
https://canary.discord.com/channels/1284581928254701718/1482089104110911634/1482089104110911634

<img width="365" height="506" alt="image"
src="https://github.com/user-attachments/assets/5ee16218-34c0-4b8b-9f9b-d33f219760b0"
/>

## 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-11 21:35:41 +00:00
Berk 2b6ebbfe2d fix: add readyState check before endTurn broadcast (#3879)
## Description:

Guard `ws.send()` in `endTurn()` with a `readyState === OPEN` check to
prevent sending messages to WebSocket connections that have already
closed.

Without this guard, broadcasting to a client whose connection closed
between ticks can throw an exception and crash the game loop.

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

barfires
2026-05-11 13:04:36 -07:00
RickD004 2b04c568fc Format the map lists in Main and MapPlaylist (#3889)
## Description:

Format the map lists in Main and MapPlaylist by alphabetical order. Many
maps were already standarized like this, but many recent ones werent.
Ideally, future maps should be added this way too.

Also ran npm run format in these 2 files, as they were not formatted
correctly before.

## 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-08 19:13:09 -07:00
RickD004 36c8fc0394 Add map of Taiwan Strait (#3878)
## Description:

Map of the Taiwan and the Chinese Mainland. 

Team heavy map like Baikal and Hormuz. Terrain Source from
OpenTopography, already credited

<img width="1800" height="1511" alt="image"
src="https://github.com/user-attachments/assets/45954469-8199-4882-9efe-899c5df87ce4"
/>

I also took the chance to standarize and sort alphabetically the map
lists in main.go and MapPlaylist.ts.

## 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.star 1011

NOTE: If the map gets added, please give contributor to
crunchybbbbb_59469 for this map on Discord. Every file was made by him,
his PR just had weird bugs that didnt allow the PR to be review
automatically

Original PR: https://github.com/openfrontio/OpenFrontIO/pull/3853 by
crunchybbb2-hash
2026-05-08 18:08:17 -07:00
Berk 79020e3b1e fix: typo 'handline' -> 'handling' in websocket error log (#3880)
## Description:

Fixes a typo in `GameServer.ts` - `handline` should be `handling` in the
websocket error log message.

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

barfires
2026-05-08 13:20:44 -07:00
evanpelle 879d502eb7 Merge branch 'v31' 2026-05-06 13:09:58 -06:00
VariableVince eca5794ebb Chore(deps): Update and remove dependencies (#3819)
## Description:

Only mentioning removals/major updates/notable changes below, not all
minor upgrades.

### Removed:
- "@aws-sdk/client-s3": not used anywhere (was used in Archive.ts
previously)
- chai, "@types/chai", sinon-chai: not used anywhere, probably leftover.
Vitest uses a bundled version of Chai for its expect asserations under
the hood too.
- protobufjs, "@types/google-protobuf": not used anywhere, probably left
from evan's experiment with it? Removed from vite.config.ts too.
- "@types/jquery": not used anywhere, probably leftover
- sinon, "@types/sinon": not used anywhere just like chai, probably
leftover. And Vitest provides us with the same functionality.
- "@types/systeminformation": dependency systeminformation was removed
last year, this is an unneeded, deprecated and unmaintained remainder.
- vite-tsconfig-paths: removed, and removed the import and usage in
vite.config.ts and replaced it by adding `tsconfigPaths: true` to the
`resolve` block. Because of this message displayed on running the tests:
"The plugin "vite-tsconfig-paths" is detected. Vite now supports
tsconfig paths resolution natively via the resolve.tsconfigPaths option.
You can remove the plugin and set resolve.tsconfigPaths: true in your
Vite config instead."
- vite-plugin-static-copy: removed, we don't use it anymore (was used in
our vite.config.ts once,, probably before Vite natively supported
copying static assets via its publicDir configuration)

### Updated:
- color.js: v0.5 > v0.6, no breaking change affecting us
- cross-env: v7 > v10. It's a publicly archived repo since Nov 2025. But
before that he got it up-to-date from June 2025, porting to TS, dropping
old Node versions, dependencies etc. Seems still good to use for some
amount of time to come.
- dotenv: v16 > v17, now logs an informational message by default when
it loads an environment file. Can be disabled by using
dotenv.config({quite: true}) if needed.
- ejs: v3 > v5: security patches mostly. Vite still uses v3 btw.
- eslint: v9 > v10. Newly enabled rules by default:
'no-unassigned-vars', 'no-useless-assignment' and
'preserve-caught-error'. Mostly faster and minimum support moved to
higher node versions, which shouldn't be a problem.
- "@eslint/compat": v1 > v2. Minimum supported Node versions, which
should not be a problem.
- intl-messageformat: v10 > v11 no breaking changes that affect us
- jdom: v27 > v29. Faster. Most notably minimum support moved to higher
node v22 version, which should not be a problem. Also, see types/node,
kind of expecting v24 to be installed now.
- nanoid: from v3 to v5, no breaking changes that affect us
- "@opentelemetry/sdk-logs": now that addLogRecordProcessor is removed,
changed Logger.ts to pass an (empty) provider array directly to the
LoggerProvider constructor. Follows the changes in
https://github.com/open-telemetry/opentelemetry-js/pull/5588
- "@tailwindcss/vite": supports vite v8 from 4.2.2, and a fix for it in
4.2.4
- tailwindcss: supports vite v8 from 4.2.2
-- in 4.1.15 (we were already above this version) break-words was
deprecated in favor of wrap-break-word. But break-words, which we use in
15 places, will still work as expected
(https://github.com/tailwindlabs/tailwindcss/pull/19157). Same goes for
also deprecated "order-none".
- "@types/node": from v22 to v24, assuming most now use node 24
- vite v7 > v8: 
-- is now on 8.0.10 so first bugs are out of it, while v8 itself also
fixed a big number of bugs.
-- in vite.config.ts, fixed Ts error/compilation issue by changing the
manualChunks option in build.rollupOptions.output to use the function
syntax, which is required by the updated types instead of the object
syntax.
- zod: no changes that affect us

### Prettier:
Updated only because of (new because of update?) Prettier errors for
files untouched in this PR originally:
- PathFinder.Parabola.ts
- WorkerMessages.ts
- ClanModal.handlers.test.ts
- ClanModal.rendering.test.ts‎
- CONTRIBUTING.md
- README.md

### ESLint:
Fixes needed to silence errors coming from newly enabled recommended
rules 'no-useless-assignment' and 'preserve-caught-error':

For 'no-useless-assignment' (default assignment never used because of
unreachable code or they are guaranteed to get a value, so they can be
undefinedat the start. Exception was AttackExecution, so made the
default value of 0 the default case in the switch statement):
- ClientGameRunner
- GameModeSelector
- NameBoxCalculator
- StructureDrawingUtils
- TerritoryLayer
- Diagnostics
- GameRunner
- ColorAllocator
- DefaultConfig
- AttackExecution
- AiAttackBehavior
- Worker.worker
- GamePreviewBuilder

For 'preserve-caught-error', disabled the rule here because the possible
fix `{cause: error}` was introduced in ES2022 while we're still on
target ES2020 currently:
- GameServer
- Privilege

_Error: The value assigned to 'gameMap' is not used in subsequent
statements. (no-useless-assignment)
Error: The value assigned to 'timeDisplay' is not used in subsequent
statements. (no-useless-assignment)
Error: The value assigned to 'scalingFactor' is not used in subsequent
statements. (no-useless-assignment)
Error: The value assigned to 'radius' is not used in subsequent
statements. (no-useless-assignment)
Error: The value assigned to 'teamColor' is not used in subsequent
statements. (no-useless-assignment)
Error: The value assigned to 'gl' is not used in subsequent statements.
(no-useless-assignment)
Error: The value assigned to 'power' is not used in subsequent
statements. (no-useless-assignment)
Error: The value assigned to 'tickExecutionDuration' is not used in
subsequent statements. (no-useless-assignment)
Error: The value assigned to 'selectedIndex' is not used in subsequent
statements. (no-useless-assignment)
Error: The value assigned to 'mag' is not used in subsequent statements.
(no-useless-assignment)
Error: The value assigned to 'speed' is not used in subsequent
statements. (no-useless-assignment)
Error: The value assigned to 'matchesCriteria' is not used in subsequent
statements. (no-useless-assignment)
Error: The value assigned to 'shouldContinue' is not used in subsequent
statements. (no-useless-assignment)
Error: The value assigned to 'description' is not used in subsequent
statements. (no-useless-assignment)
Error: There is no `cause` attached to the symptom error being thrown.
(preserve-caught-error)
Error: There is no `cause` attached to the symptom error being thrown.
(preserve-caught-error)_

All tests pass. TypeScript and ESLint errors resolved.

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

---------

Co-authored-by: Copilot <copilot@github.com>
2026-05-06 09:12:27 -06:00
RickD004 3744027e94 Adds map of the Middle East (#3829)
## Description:

Starting v32 maps right now!

Adds map of the Middle East. Probably one of the most highly requested
maps.

Very large map (3.4M land pixels, similar to Two Lakes, would become the
2nd or 3rd largest map by land area) of the arabian peninsula and
surrounding regions.
This map has both huge areas of land without water access full of desert
terrain, and massive trade chokepoints, which combined will result in
crazy endgames.

The theme of this map are historical, based on the end of WW1.
Historical flags have been added for the nation NPCs to use.

(High map rotation of 8 since this is probably going to become one of
the most popular maps given the relevancy of the region in real life.)

Terrain source from NASA DEM, already credited.


https://github.com/user-attachments/assets/6a1b345f-fd92-42c2-8f92-154fac4c9733

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

tri.star1011
2026-05-05 22:12:42 -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
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.
2026-05-04 18:18:36 -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
2026-05-04 12:53:02 -06:00
evanpelle 257fb9b38e temporarily disable turnstile 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
2026-05-03 14:31:00 -06:00
evanpelle ac679b68c5 update cache bust version to invalid bad response headers 2026-05-03 10:14:19 -06:00
evanpelle 5d6c48ebf2 Revert "Fix winner stats spoofing exploit"
This reverts commit 819edb21bb.
2026-05-03 09:54:50 -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.
2026-05-02 13:47:19 -06:00
evanpelle d071c8228f Add cache busting to asset urls to bust assets with bad headers 2026-05-02 07:26:06 -06:00
babyboucher 4f20d2b332 TypeScript update to 6.0.3 (#3806)
## Description:

Updating TypeScript to 6.0.3.
Updating TypeScript-eslint to 8.59.1 for TS6 support.
Concurrently needed to get updated as well to remove deprecated warning.

Most things deleted are now just defaults.

## 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-04-30 15:49:24 -06:00
FloPinguin 2a76a63e32 Restrict ArchipelagoSea to special rotation only 🗺️ (#3798)
## Description:

ArchipelagoSea is a very "special" map with the extreme amount of tiny
islands, and the map maker said "could there be a way to make
Archipelago Sea have 5M or 25M starters more often? I feel like the map
is too unorthodox to be played in normal settings"

So lets restrict it to the special rotation, like arcade maps. People
expect crazy-stupid games there.

## 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-29 16:58:24 -06:00
Evan 2994a5f848 Start game via WebSocket intent (#3794)
## Description:

Replaces the HTTP POST /api/start_game/:id endpoint with a WebSocket
intent, making private game start consistent with how kick_player and
update_game_config already work. Also verifies that only the lobby
creator can start a game.

## 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-04-29 13:26:14 -06:00
RickD004 a989bcbeb0 Rename Mediterranean to Mare Nostrum 🏛️ (#3768)
## Description:

Change inspired by Territorial.io . Renames the Mediterranean sea map to
Mare Nostrum, the ancient name of the sea given by the Romans. The NPCs
of the map are already roman provinces, so this change is more thematic
and also adds a creative name like "Gateway to the Atlantic" and
"Between Two Seas"

## 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-04-28 19:15:29 -06:00