mirror of
https://github.com/openfrontio/OpenFrontIO.git
synced 2026-06-25 17:04:36 +00:00
182d008ddd536b7a85fa1e87c12c6d431d541ac4
8 Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
182d008ddd |
Generate a single MapInfo list; move SPECIAL_TEAM_MAPS and en.json map names into info.json (#4231)
**Add approved & assigned issue number here:** N/A — maintainer follow-up to #4227. ## Description: Follow-up to #4227, finishing the "info.json is the single source of truth" refactor. **Maps.gen.ts now generates one `MapInfo` interface and a `maps` list** instead of parallel lookup records. `mapCategories`, `mapTranslationKeys`, and `multiplayerFrequency` are gone — consumers read the list directly (`map.categories`, `map.translationKey`, `map.multiplayerFrequency`). MapPicker got simpler in the process: it renders from `MapInfo` objects, so the reverse `Object.entries(GameMapType)` lookup to recover the enum key is gone. The featured-rank sort moved out of the Go codegen into the picker, where the presentation concern belongs. **`SPECIAL_TEAM_MAPS` moves into info.json** as an optional `special_team_count` field (set on the same 17 maps with the same values). MapPlaylist derives its map from the generated list; `SPECIAL_TEAM_FORCE_CHANCE` and the frequency multiplier behavior are unchanged. **The en.json `map` section is now generated.** A new optional `display_name` field in info.json (defaulting to `name`) is written to `resources/lang/en.json` by the generator, preserving the section's non-map UI keys (`map`, `featured`, `all`, `favorites`, `random`). The 8 maps whose English display name intentionally differs from the frozen enum value (e.g. `MENA`, `Milky Way`, `Europe (Classic)`, `Baikal (Nuke Wars)`) declare it via `display_name`, so no display text changes. The section is emitted alphabetically; since #4232 already sorted en.json and every value matches, regeneration is byte-identical and this PR has no en.json diff. Other languages remain Crowdin-managed. The generator also now validates `translation_key` is exactly `map.<folder>` and `special_team_count >= 2`. MapConsistency tests compare info.json directly against the generated list and the en.json section, and fail with a "run `npm run gen-maps`" message on drift. No behavior changes: enum values, playlist frequencies, special-team counts, featured order, and display names are all byte-identical. ## Please complete the following: - [x] I have added screenshots for all UI updates (no UI changes — internal refactor, rendering output identical) - [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: evanpelle 🤖 Generated with [Claude Code](https://claude.com/claude-code) --------- Co-authored-by: Claude Fable 5 <noreply@anthropic.com> |
||
|
|
3de5fb4204 |
Move map metadata into info.json and generate map TypeScript from it (#4227)
**Add approved & assigned issue number here:** N/A — maintainer refactor. ## Description: Makes each map's `info.json` the single source of truth for map metadata — adding a map is now a folder with `image.png` + `info.json`, a `gen-maps` run, and an en.json display name. **info.json / manifest.json carry full map metadata.** Every `map-generator/assets/maps/<map>/info.json` declares `id` (the `GameMapType` enum key), `name` (the enum value — wire format, unchanged for all 94 maps), `translation_key`, `categories`, and `multiplayer_frequency` (the public-playlist weight that used to be the `FREQUENCY` record in MapPlaylist.ts). The generator validates everything and mirrors it into `resources/maps/<map>/manifest.json`. 23 stale info.json `name` values were normalized to the canonical enum value; enum values are byte-identical, so replays and stored game configs are unaffected. **The generator emits the TypeScript and discovers maps itself.** New `map-generator/codegen.go` generates `src/core/game/Maps.gen.ts` (`GameMapType`, `GameMapName`, `mapCategories`, `mapTranslationKeys`, `multiplayerFrequency` — now a full `Record<GameMapName, number>`, killing the old `Partial`) on every run; `Game.ts` re-exports it. The hardcoded map registry in `main.go` is gone — maps are auto-discovered from the `assets/maps` / `assets/test_maps` directories. MapConsistency tests fail with a "run `npm run gen-maps`" message if info.json, manifest.json, and Maps.gen.ts drift. The tracked `map-generator/map-generator` binary is rebuilt to match. **New categories: continents + world/cosmic/tournament/other, multi-category support.** `continental`/`regional`/`fantasy`/`arcade` are replaced by `featured`, `world`, `europe`, `asia`, `north_america`, `africa`, `south_america`, `oceania`, `antarctica`, `cosmic`, `tournament`, and `other`. Maps can list multiple categories, so straddlers (Black Sea, Bosphorus, Caucasus, Between Two Seas, Bering Sea/Strait, Mena, Strait of Gibraltar, Hawaii, Arctic) appear under both regions. Featured is itself a category (same 7 maps as before). MapPlaylist keeps its arcade exclusion via an explicit set. **Map picker UI.** Two tabs: **Featured** (default — featured maps plus a Favorites section when maps are starred) and **All** (one prominent collapsible bar per category with a map count, collapsed by default). The selected map is prepended to the featured grid when it lives elsewhere. `getMapName()` resolves through the generated `mapTranslationKeys`, which also fixes tourney maps never resolving a valid translation key. ## Please complete the following: - [ ] I have added screenshots for all UI updates (maintainer change — picker described above) - [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: evanpelle 🤖 Generated with [Claude Code](https://claude.com/claude-code) --------- Co-authored-by: Claude Fable 5 <noreply@anthropic.com> |
||
|
|
fe0b79ef21 |
Feat: Favourite maps tab (#4207)
Resolves #4202 ## Description: As suggested in some suggestions in the main OF server [[thread](https://discord.com/channels/1284581928254701718/1472496670267805782)], we should have a map favouriting system since there are over 70 maps already. People (myself included) have some maps we constantly play during solo/private matches, so a favourite tab would be huge. This feature adds the favourites tab to the solo and private match selection screens. It works using localStorage for saving (device persistence) but I can just as easily implement an infra update where players have a 1-many relation with a `FavouriteMaps` table. That can be a future solution. Video example right now: https://github.com/user-attachments/assets/e8e278ab-d305-499a-81a9-d570e05db051 ## 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: bijx |
||
|
|
62299c9714 |
standardize UI colors to fit brand guidelines (#3754)
## Description: We have brand colors: <img width="738" height="900" alt="Screenshot 2026-04-25 at 12 52 29 PM" src="https://github.com/user-attachments/assets/aac69e87-91f2-4c3f-9f1e-f69f48f5943e" /> So update the homepage & in-game UI to use those colors: <img width="1185" height="946" alt="Screenshot 2026-04-25 at 12 51 06 PM" src="https://github.com/user-attachments/assets/89a0b12c-2db1-43d4-9500-fcf405c0f7ff" /> Also updated buttons to use the o-button element ## 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 |
||
|
|
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 |
||
|
|
0b9d43cb46 |
Configurable nation count 🤖 (#3338)
## Description: I hope we can get this into v30? The nation count is configurable now, just like the bot count. Replaced the "Disable Nations" toggle with a nations slider (0–400) in SinglePlayer and Host Lobby modals. <img width="710" height="121" alt="Screenshot 2026-03-03 021952" src="https://github.com/user-attachments/assets/c8d0f0c3-db51-4303-95fa-dbc770460ec2" /> Public games are staying exactly the same, this is just for singleplayer and private lobby fun. Youtubers could play HvN against 400 nations, for example. Singleplayer enjoyers no longer have to play against 1 nation in HvN, they can freely choose. `GameConfig.disableNations: boolean` got replaced by `nations: number (0-400, optional)` `undefined` = map default, `0` = disabled, number = custom count Nations slider defaults to the map's nation count, shows "(MAP DEFAULT)" label when unchanged Compact map toggle reduces nations to 25% when at default, restores when toggled off (just like we already do with bots) The nation count for HvN no longer automatically matches the human count in singleplayer and private games, only in public games. **What if there aren't enough nations configured for the map?** We just use the HvN logic (Generate random nations) ### Warning **This infra PR also needs to get merged: https://github.com/openfrontio/infra/pull/263 Otherwise players can set 0 nations and get achievements.** ## 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 |
||
|
|
f8c14398c8 |
UI Extraction Host/Solo Modal (#3181)
## Description: UI Extraction Host/Solo Modal - Made all buttons do the same "press" feel (options/settings/random map) are now the same as the map button. - Also fixed a bug where you could "drag" the map image off the button. ## 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 |
||
|
|
1314115d3f |
Add map picker with Featured/All tabs (#3005)
Resolves #2996 ## Description: Replace map selection UI in src/client/SinglePlayerModal.ts and src/client/HostLobbyModal.ts with the picker (Featured/All tabs + random map card). Also, since the html was getting quite long, I extracted the shared parts into a separate component. <img width="575" height="592" alt="スクリーンショット 2026-01-23 21 57 03" src="https://github.com/user-attachments/assets/fc6bfbc3-cb66-452a-b971-436940b0fb99" /> <img width="633" height="648" alt="スクリーンショット 2026-01-23 21 57 12" src="https://github.com/user-attachments/assets/1aa409a1-b801-4a60-8b26-ba20e343d66e" /> I separated Map.ts because the display logic looked reusable in other places, but I’m also open to merging it back if that makes more sense. If the review prefers it integrated, I can combine them again. ## 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: aotumuri |