diff --git a/docs/lobby/FEATURES.md b/docs/lobby/FEATURES.md new file mode 100644 index 0000000000..88d21160a7 --- /dev/null +++ b/docs/lobby/FEATURES.md @@ -0,0 +1,328 @@ +# Custom-Game Lobby — Feature Inventory (parity yardstick) + +This catalogs **everything the current custom-game lobby does**, so a ground-up +MVC rebuild has a measurable parity target. It is a behaviour spec, not a design. + +> Line references are **approximate** (gathered by code exploration; the files +> drift). Treat them as "look near here", and re-confirm against current source. +> Primary sources: [`/lua/ui/lobby/lobby.lua`](/lua/ui/lobby/lobby.lua) (~7400 lines), +> [`/lua/ui/lobby/lobbyComm.lua`](/lua/ui/lobby/lobbyComm.lua), +> [`/lua/ui/lobby/lobbyOptions.lua`](/lua/ui/lobby/lobbyOptions.lua), +> [`/lua/ui/lobby/ModsManager.lua`](/lua/ui/lobby/ModsManager.lua), +> [`/lua/ui/lobby/UnitsManager.lua`](/lua/ui/lobby/UnitsManager.lua), +> [`/lua/ui/lobby/presets.lua`](/lua/ui/lobby/presets.lua), +> [`/lua/ui/lobby/gameselect.lua`](/lua/ui/lobby/gameselect.lua), +> [`/lua/ui/dialogs/mapselect.lua`](/lua/ui/dialogs/mapselect.lua), +> [`/lua/ui/lobby/data/gamedata.lua`](/lua/ui/lobby/data/gamedata.lua), +> [`/lua/ui/lobby/data/playerdata.lua`](/lua/ui/lobby/data/playerdata.lua). + +## What we're replacing (scale) + +- `lobby.lua` alone is ~7,400 lines; the lobby ecosystem ~10,700 lines. +- Central state `gameInfo` is a hybrid: plain tables (`GameOptions`, `ClosedSlots`, + `SpawnMex`, `GameMods`, `AutoTeams`) + reactive `WatchedValueArray` for + `PlayerOptions` / `Observers`. **The reactivity primitive already exists** and + there's a standing TODO to replace `SetSlotInfo` sledgehammers with lazy callbacks. +- Networking: **host-authority**. Non-hosts send requests; host validates and + broadcasts authoritative state. ~30 message types. Full `GameInfo` dump on join. +- UI is driven by ~10 "refresh-everything" functions (`SetSlotInfo`, + `RefreshOptionDisplayData`, `refreshObserverList`, …) called after each change. + +--- + +## A. Lifecycle & entry + +| Feature | Who | Trigger / function | Notes | +|---|---|---|---| +| Game discovery list | all | `gameselect.lua` LAN/IP discovery | shows map, name, players | +| Create game | host | `gameselect.lua` → `gamecreate` | nickname validation 2–32 chars | +| Direct IP connect | all | IP+port input, stored in prefs | | +| Host a lobby | host | `HostGame` (lobby.lua ~780); `lobbyComm.Hosting` (~5706) | loads last scenario/options from prefs, host into slot 1, keep-alive thread (30s) | +| Join a lobby | client | `JoinGame` (~788); `ConnectionToHostEstablished` (~5596) | sends `SetAvailableMods` + `AddPlayer`; host replies with full `GameInfo` | +| Leave / abort | all | `ReturnToMenu` (~1878), Escape handler (~669) | confirm dialog; destroys `lobbyComm`/`GUI`; quit-to-desktop if `/gpgnet` | +| Rehost | host | `/rehost` flag (~179, ~5812) | restores last-game preset, reassigns players/AIs to prior slots | +| Launch transition | host | `GameLaunched` (~5677) | saves loading faction, kills threads, destroys UI + comm | + +--- + +## B. Slots & players + +**Slot states & context menu** (`GetSlotMenuData` ~246, `GetSlotMenuTables` ~341, `DoSlotBehavior` ~548): + +| Slot state | Host menu entries | Client menu entries | +|---|---|---| +| Open | Close, Close-spawn-mex (adaptive), Occupy | Occupy | +| Closed | Open, Close-spawn-mex (adaptive) | — | +| Human-occupied | Whisper, Move to Observer, Kick, Move to slot N | Whisper | +| AI-occupied | Remove (Kick), AI personality list | — | + +**Actions:** + +| Feature | Who | Function | Message | State | +|---|---|---|---|---| +| Open/close slot | host | `HostUtils.SetSlotClosed` (~6839) | `SlotClosed` | `ClosedSlots[slot]` | +| Close + spawn-mex (adaptive) | host | `SetSlotClosedSpawnMex` (~6859) | `SlotClosedSpawnMex` | `ClosedSlots`+`SpawnMex` | +| Occupy empty slot | player | host: `MovePlayerToEmptySlot` (~7039); client → host | `MovePlayer`→`SlotMove` | move player, force unready | +| Move player to slot | host | `SwapPlayers` (~7078) | `SlotMove`/`SwapPlayers` | relocate, unready | +| Swap two players | host | `SwapPlayers`/`DoSlotSwap` (~6762) | `SwapPlayers` | swap incl. team, unready both | +| Kick player | host | `EjectPeer` + confirm dialog (~590) | engine eject + `SystemMessage` | slot cleared; kick msg saved to prefs | + +**Slot row display** (`CreateSlotsUI` ~2718, `SetSlotInfo` ~1032, `ClearSlotInfo` ~1245): +slot #, country flag, rating (R: mean±3·dev tooltip), games (G:), name (context-menu +combo, colour-coded host/player/you/AI), colour combo, faction combo, team combo, +CPU bar, ping bar, ready checkbox. `SetSlotInfo` recomputes the whole row on any change. + +--- + +## C. Per-player settings + +| Feature | Who | Function | Message | Notes | +|---|---|---|---|---| +| Faction | player (own) / host (AI) | faction combo + large selector `CreateUI_Faction_Selector` (~6375) | `PlayerOptions{Faction}` | per-map availability; random=5 resolved at launch; sets skin; saved to prefs | +| Colour | player (own) / host | colour combo; `Check_Availaible_Color` (~6706), `IsColorFree` (~1304) | client `RequestColor` → host `SetColor` | **scarcity**: taken colours hidden; host validates/reverts | +| Team | player (own) / host | team combo | `PlayerOptions{Team}` | disabled when AutoTeams active or ready; backend team = UI team+1 | +| Ready | player (own) | ready checkbox (~2991) | `PlayerOptions{Ready}` | disables own controls; gates launch; host can force-unready (`SetPlayerNotReady`) | +| Start position | player/host | map-preview click/drag `ConfigureMapListeners` (~4931) | `MovePlayer`/`SlotMove`/`AutoTeams` | fixed-spawn: move self; host swap mode; manual AutoTeams via map clicks | + +--- + +## D. AI management (host-only) + +| Feature | Function | Message | Notes | +|---|---|---|---| +| Add AI | `HostUtils.AddAI` → `TryAddPlayer` (~7186) | `SlotAssigned` | personality list from `aitypes.lua` (`GetAItypes`); AI auto-ready, `Human=false` | +| Remove AI | `HostUtils.RemoveAI` (~6988) | `ClearSlot` | | +| AI rating | `ComputeAIRating` (~456), `GetAIPlayerData` (~503) | — | from cheat/build/map multipliers + omni bonus (per `AILobbyProperties`) | +| AI faction/colour/team | via PlayerData | `PlayerOptions` | colour from `GetAvailableColor`/inherited; team via AutoTeams or explicit | +| Move/swap AI | `SwapPlayers`/`MovePlayerToEmptySlot` | `SlotMove`/`SwapPlayers` | same path as players | +| Fill slots | "Fill Slots" + AI combo (~3210) | `SlotAssigned` ×N | | + +--- + +## E. Observers + +| Feature | Who | Function | Message | +|---|---|---|---| +| Join as observer | auto (slots full / requested) | `TryAddObserver` (~7113) | `ObserverAdded` | +| Player → observer | host or player-request | `ConvertPlayerToObserver` (~6879) / `RequestConvertToObserver` | `ConvertPlayerToObserver` | +| Observer → player | host or observer-request | `ConvertObserverToPlayer` (~6923) / `RequestConvertToPlayer` (opt. slot) | `ConvertObserverToPlayer` | +| Observer list UI | all | `refreshObserverList` (~926) | name + rating + ping + CPU; team ratings if >2 teams | +| Kick observer | host | `KickObservers` (~7379) | engine eject; also auto-kick at launch if observers disallowed | +| Observer chat | observer | `AddChatText` greys observer names | `PublicChat`/`PrivateChat` | +| Rehost slot negotiation | host | `FindRehostSlotForID` (~841) | observers reclaim prior slots on rehost | + +--- + +## F. Host authority & validation + +- **Pattern**: client mutates own slot → broadcasts `PlayerOptions` (host `Accept` + checks `SenderID == OwnerID`); non-owned mutations go request→host-validate→broadcast. + Host-only gate: `AmHost` (~5067) on relevant handlers. +- **Optimistic UI**: client applies colour locally, host may revert (~5357). +- **Ready-gating**: `RefreshButtonEnabledness` (~7248) disables host option buttons + while any human is not ready; launch enabled only when all ready (or single-player / host-observes). +- **Force unready**: `SetPlayerNotReady` (one), `SetAllPlayerNotReady` (all, on option reset). +- **Race guards**: e.g. ignore a move request if the player became ready meanwhile (~5323). + +--- + +## G. Game options (complete enumeration — `lobbyOptions.lua`) + +### Team options (~72–226) +| Key | Values | Default | +|---|---|---| +| `TeamSpawn` | fixed, penguin_autobalance, random, balanced, balanced_flex, random_reveal, balanced_reveal, balanced_reveal_mirrored, balanced_flex_reveal | fixed | +| `TeamLock` | locked, unlocked | locked | +| `AutoTeams` | none, tvsb, lvsr, pvsi, manual | none | +| `CommonArmy` | Off, UnionWhenDisconnected, Union, Common | Off | +| `TeamShareOverflow` | enabled, disabled | enabled | + +### Global options (~229–706) +| Key | Values | Default | +|---|---|---| +| `Share` | FullShare, ShareUntilDeath, PartialShare, TransferToKiller, Defectors, CivilianDeserter | FullShare | +| `DisconnectShare` | SameAsShare | SameAsShare | +| `DisconnectShareCommanders` | Explode | Explode | +| `ShareUnitCap` | none, allies, all | allies | +| `ManualUnitShare` | all, no_builders, none | all | +| `RestrictedCategories` | set (Unit Manager) | none | +| `Victory` | demoralization, decapitation, domination, eradication, sandbox | demoralization | +| `FogOfWar` | explored, none | explored | +| `GameSpeed` | normal, fast, adjustable | normal | +| `CheatsEnabled` | false, true | false | +| `CivilianAlliance` | enemy, neutral, removed | enemy | +| `RevealCivilians` | Yes, No | Yes | +| `PrebuiltUnits` | Off, On | Off | +| `NoRushOption` | Off, 1..5,10,15,…,60 | Off | +| `RandomMap` | Off, Official, All | Off | +| `Score` | yes, no | yes | +| `UnitCap` | 125,250,…,1000,1250,1500 | 1000 | +| `AllowObservers` | true/false | true | +| `Timeouts` | 0, 3, -1 (MP only) | 3 | +| `DisconnectionDelay02` | 10, 30, 90 (MP only) | 90 | +| `Unranked` | No, Yes | No | + +### AI options (~709–814) +| Key | Values | Default | +|---|---|---| +| `CheatMult` | 0.5–5.9 | 1.0 | +| `BuildMult` | 0.5–5.9 | 1.0 | +| `TMLRandom` | 0–20% | 0 | +| `LandExpansionsAllowed` | 0–8, 99999 | 6 | +| `NavalExpansionsAllowed` | 0–8, 99999 | 5 | +| `OmniCheat` | on, off | on | + +Plus **map-specific options** (`mapname_options.lua`, validated by `maputil`) and +**custom AI options** from mods (`/lua/AI/LobbyOptions/`). Storage: `gameInfo.GameOptions[key]` ++ `Prefs LobbyOpt_`; host writes via `SetGameOption(s)` (~5938) → `GameOptions` broadcast ++ GpgNet (`RestrictedCategories`→bool, `ScenarioFile`, `Slots`). Reset via `OptionUtils.SetDefaults` (~2592). +Display: `RefreshOptionDisplayData` (~4543), scrollable `GUI.OptionContainer`, optional "show changed only". + +--- + +## H. Auto-teams & spawn + +- **AutoTeams** (`AssignAutoTeams` ~1802): none / tvsb / lvsr / pvsi / manual (host clicks map markers, requires random spawn). +- **Spawn variants** (`TeamSpawn`): fixed, random, balanced (+flex, +reveal, +mirrored), penguin_autobalance. +- **Spawn-mex** (adaptive maps): per-slot `SpawnMex` toggle; embedded into GameOptions at launch. +- **Launch-time** (`TryLaunch` ~2077): `AssignAutoTeams`, `AssignRandomFactions`, `FixFactionIndexes`, + `AssignRandomStartSpots`, `AssignAINames`, flatten gameInfo, build Ratings/ClanTags tables. + +--- + +## I. Map selection (`mapselect.lua`) + +- Map browser dialog `CreateDialog` (~453): list + preview + filters + options panel + Mods/Unit-Manager buttons. +- **Filters** (~117): supported players (2–16), size (5–81 km), type (official/custom), AI markers, hide-obsolete; persisted in prefs. Name search. +- **Preview**: `ResourceMapPreview` (terrain, water/cliff/buildable masks, mass/hydro markers, start spots). +- **Metadata** (`maputil` `LoadScenario` ~53): name, map/save/script/preview, size, reclaim, type, version, AdaptiveMap, Configurations (teams/armies). +- **Enumeration**: `EnumerateSkirmishScenarios` (~312) over `/maps/*` + mod map dirs; playable skirmish only. +- Hardcoded official-maps list for the "official" filter. + +--- + +## J. Mods manager (`ModsManager.lua`) + +- Dialog `CreateDialog(parent, isHost, availableMods, saveBehaviour)` (~160). +- **Types**: GAME (sim, network-replicated, disables rating), UI (local only), BLACKLISTED, LOCAL (host has, peers don't), NO_DEPENDENCY. +- **Browse**: grid (expand/collapse), sort (status/type/name/author/version), free-text search; prefs-persisted. +- **Favorites**: per-mod star; "Activate Favorites" (host: sim+UI, client: UI only). +- **Dependencies**: forward auto-activate, backward auto-deactivate, conflict prompts (`Mods.GetDependencies`). +- **Peer availability**: `availableMods[peerID]`; `EveryoneHasMod`; sim mods auto-disabled / peers kicked if missing. +- **Apply**: split sim/UI, `saveBehaviour(simMods, uiMods)` → host `UpdateMods` → `ModsChanged` broadcast; `Mods.SetSelectedMods`. + +--- + +## K. Unit restrictions manager (`UnitsManager.lua` + `UnitsRestrictions.lua`) + +- Dialog `CreateDialog(parent, initial, OnOk, OnCancel, isHost)` (~216); scales to ~90% screen. +- **150+ presets** in ~15 groups (tech levels, unit types, spam, snipes, anti-air, torpedo, direct-fire, defensive/intel, SCU/ACU, economy, missiles, engineers). +- **Expression system**: category algebra (`*` AND, `+` OR, `-` NOT, `()`), UPPERCASE categories + lowercase unit ids + enhancement names. +- Grid: presets + per-faction × category unit matrix; host editable, client read-only. +- Stored in `GameOptions.RestrictedCategories`; broadcast + GpgNet bool; saved in presets. + +--- + +## L. Chat + +| Feature | Trigger / function | Message | +|---|---|---| +| Public chat | `GUI.chatEdit` Enter → `PublicChat` (~1924) | `PublicChat` | +| Whisper | `/whisper`,`/pm`,`/w`,`/private` → `ParseWhisper` (~192) → `PrivateChat` (~1934) | `PrivateChat` | +| Unknown command | "Command Not Known" | — | +| Join/leave & connection notices | `AddPlayer`, `Peer_Really_Disconnected`, `CalcConnectionStatus` | `SystemMessage` | +| Rating in chat/list | `refreshObserverList` | — | +| Clickable names | `chatarea.lua` author click → prefill `/w name` | — | +| Input history | up/down over `commandQueue` | — | +| Scroll / auto-bottom | `AddChatText` (~4819) | — | + +--- + +## M. Connectivity & health + +| Feature | Function | Message | Notes | +|---|---|---|---| +| CPU benchmark | `UpdateBenchmark`/`StressCPU` (~6226) | `CPUBenchmark` | auto on connect + manual button; 0–450; cached in prefs; host re-broadcasts | +| CPU bar | `SetSlotCPUBar` (~6300) | — | green/yellow/red thresholds | +| Ping bar | ping thread (~4406) | — | shown if >500ms; status texture 1–4 | +| Connection tracking | `CalcConnectionStatus` (~4742) | — | ConnectionEstablished/CurrentConnection/ConnectedWithProxy | +| Pre-launch connectivity | `EveryoneHasEstablishedConnections` (~4785) | — | every important peer must reach every other | +| Peer disconnect | `PeerDisconnected` (~5833) | `Peer_Really_Disconnected` | clears slot/observer; chat notice | +| Host keep-alive/timeout | thread (~5616), `quietTimeout` 30s | — | "Keep Trying / Give Up" dialog | + +--- + +## N. Compatibility & launch validation + +- **Version check**: host `AddPlayer.Accept` (~5272) compares Version/GameType/Commit → reject + eject on mismatch. +- **Missing map**: `MissingMap` → `PlayerMissingMapAlert` (~7190) sets `BadMap`, system message; local fallback to default scenario; `ClearBadMapFlags` on map change. +- **Mods exchange**: `SetAvailableMods` → `availableMods[peer]`; `IsModAvailable` requires all peers; missing → kick with list. +- **Launch blockers** (`TryLaunch` ~2077): no players; host-as-observer when observers disallowed; observers present → confirm-kick; missing connections; map missing (warn, proceeds with fallback). + +--- + +## O. Presets & rehost (`presets.lua`) + +- Save preset (map, options, mods, restrictions, player options) to profile; load/apply (`ApplyGameSettings` ~6683); delete; rename. +- Auto-save "lastGame" preset at launch (`SaveLastGamePreset`). +- Rehost (`/rehost`): restore last-game settings; reassign returning players to prior slots (evicting AIs / displacing to observer), restore AIs, relocate host. +- Presets dialog UI: list + detail + Load/Create/Save/Delete/Help/Quit. + +--- + +## P. Lobby preferences dialog (`ShowLobbyOptionsDialog` ~6519) + +Local, non-game-affecting: background mode (factions/concept/screenshot/map/none), +chat font size, snowflake count, windowed lobby, stretch background, faction font colour, +player-colour-in-chat. Applied immediately; stored in prefs. + +## Q. Other dialogs + +- Briefing dialog (campaign/scenario), large map preview (water/cliff/buildable masks), + save/load dialog (skirmish), kick/reset confirm popups. + +--- + +## Network message catalog (~30) + +`AddPlayer`, `PlayerOptions`, `MovePlayer`, `RequestColor`, `SetColor`, +`RequestConvertToObserver`, `RequestConvertToPlayer`, `ConvertPlayerToObserver`, +`ConvertObserverToPlayer`, `ObserverAdded`, `SlotAssigned`, `SlotMove`, `SwapPlayers`, +`ClearSlot`, `SlotClosed`, `SlotClosedSpawnMex`, `AutoTeams`, `GameOptions`, +`ModsChanged`, `SetAvailableMods`, `MissingMap`, `GameInfo` (full sync on join), +`Launch`, `PublicChat`, `PrivateChat`, `SystemMessage`, `CPUBenchmark`, +`SetPlayerNotReady`, `SetAllPlayerNotReady`, `Peer_Really_Disconnected`. + +Engine callbacks: `Hosting`, `ConnectionToHostEstablished`, `PeerDisconnected`, +`DataReceived`, `GameLaunched`, `Ejected`, `ConnectionFailed`, `GameConfigRequested`. + +--- + +## Data model + +- **`gameInfo`** (`gamedata.lua`): `GameOptions` (table), `PlayerOptions` / + `Observers` (`WatchedValueArray`), `ClosedSlots`, `SpawnMex`, `GameMods`, `AutoTeams`, `AdaptiveMap`. +- **`PlayerData`** (`playerdata.lua`): OwnerID, PlayerName, Human, Faction, PlayerColor, + ArmyColor, Team, StartSpot, Ready, PL/MEAN/DEV/NG, PlayerClan, Country, AIPersonality, + AILobbyProperties, Version/GameType/Commit, Civilian, BadMap, ObserverListIndex. +- Module globals: `gameInfo`, `lobbyComm`, `GUI`, `localPlayerID`, `hostID`, + `availableMods`, `selectedSimMods`/`selectedUIMods`, `CPU_Benchmarks`, `rehostPlayerOptions`. + +## "Refresh-everything" functions to replace with reactive subscriptions + +`SetSlotInfo` (~1032), `ClearSlotInfo` (~1245), `UpdateGame` (~2302), +`refreshObserverList` (~926), `RefreshOptionDisplayData` (~4543), +`UpdateFactionSelector` (~6445), `RefreshButtonEnabledness` (~7248), +`Check_Availaible_Color` (~6706), `RefreshLobbyBackground`, `RefreshMapPositionForAllControls`. + +--- + +## Reuse vs rebuild + +**Relatively portable** (self-contained): map preview (`ResourceMapPreview`), mods +manager dialog, unit manager dialog, options definitions (`lobbyOptions.lua` data), +faction selector, CPU benchmark, chat (the new chat-MVC), presets storage. + +**Deeply tangled core** (rebuild against the model): slot/player sync (`SetSlotInfo` ++ `HostUtils`), the 30-message dispatch, host-authority request/validate/broadcast, +connection tracking. These are where the MVC rebuild's value — and risk — concentrate. diff --git a/docs/lobby/UI.md b/docs/lobby/UI.md new file mode 100644 index 0000000000..bd22e1e5d1 --- /dev/null +++ b/docs/lobby/UI.md @@ -0,0 +1,76 @@ +# UI element priorities + +Based on the lobby features, this document collects the information requirements that need to be displayed in the UI. +As we can't display everything at once, we will have to make use of additional dialog windows. To understand what needs to be immediately present and what can be tucked away behind additional clicks, we give a priority score. + +- **1** must be immediately visible +- **2** can require a click or hovering to show, but would be nice to have immediately visible if we can afford the space +- **3** can and probably should require a click to show to not clutter the main ui +- **4** even lower priority +- **0** we shouldn't / don't need to display this at all + + +## General +| Priority | Element | Notes | +|----------|------------|-------| +| | lobby name | | + +## Map +| Priority | Element | Notes | +|----------|--------------------|-------| +| | Main Map preview | +| | Map name | +| | Map author | +| | starting positions | +| | Reclaim | +| | Water areas | + +## Game settings +| Priority | Element | Notes | +|----------|---------------------------|-------| +| | Non-default-option | | +| | default options | | +| | Mod names | | +| | Mod description | | +| | Mod url | | +| | Mod icon | | +| | unit restriction count | | +| | specific restricted units | | + +## Players +| Priority | Element | Notes | +|----------|-------------------|-------| +| | rating | | +| | division | | +| | game count | | +| | avatar | | +| | selected color | | +| | color selector | | +| | selected factions | | +| | faction selector | | +| | country flag | | +| | ready | | + +## slot state +| Priority | Element | Notes | +|----------|-----------------------|-------| +| | closed | | +| | free | | +| | number | | +| | team | | +| | player pinned to slot | | + +## Chat +| Priority | Element | Notes | +|----------|---------------|-------| +| | chat messages | | +| | message box | | + +## Management +| Priority | Element | Notes | +|----------|------------------------|-------| +| | AI slot filling | | +| | autobalance | | +| | combined team strength | | +| | game launch button | | +| | game quality | | \ No newline at end of file diff --git a/docs/lobby/user-stories.md b/docs/lobby/user-stories.md new file mode 100644 index 0000000000..294208ac43 --- /dev/null +++ b/docs/lobby/user-stories.md @@ -0,0 +1,188 @@ +# Custom-Game Lobby — User Stories + +Companion to [`FEATURES.md`](FEATURES.md). Same A–Q structure, so each story +traces back to a catalogued feature. Format: **As a ``, I want ``, so +that ``** — with *when/given* conditions where they matter. + +Roles: **Host**, **Player** (human in a slot), **Observer**, **Joining client** +(connecting peer), **System** (automatic / engine-driven). + +> **Progress** (updated as the [`customlobby/`](customlobby/CLAUDE.md) rebuild lands slices): +> ✅ done · 🟡 partial / works with gaps · ⬜ not started. Markers reflect the reactive-MVC +> rebuild, not the legacy `lobby.lua`. Launch itself isn't wired yet, so anything that only +> resolves *at launch* is ⬜ even when its inputs are configurable. + +--- + +## A. Lifecycle & entry + +- ⬜ As a **player**, I want to browse discovered games (map, name, player count), so that I can pick one to join. +- 🟡 As a **host**, I want to create a game with a name and a starting map, so that others can find and join it. *(Given a valid nickname, 2–32 non-space chars.)* — *host/client connect + sync work; the create-game entry UI (name, nickname validation) isn't rebuilt.* +- 🟡 As a **player**, I want to join by direct IP:port, so that I can connect when discovery doesn't list the game. *(Engine join path works in testing; no direct-IP entry UI yet.)* +- ✅ As a **joining client**, I want to receive the full lobby state on connect, so that I immediately see the current map, slots, options and mods. *(`BroadcastPlayers` + `BroadcastLaunchInfo` + `BroadcastSessionState` on join.)* +- 🟡 As a **player**, I want to leave the lobby with a confirmation prompt, so that I don't exit by accident; *and when launched via `/gpgnet`*, leaving quits to desktop instead of the menu. — *Leave/Esc → menu works; no confirm prompt, no gpgnet quit-to-desktop.* +- ⬜ As a **host**, I want to rehost my last game, so that the previous map/options/mods and player slots are restored automatically. +- ⬜ As a **player**, I want my lobby UI to tear down cleanly when the game launches, so that no stale threads or windows linger. + +## B. Slots & players + +- 🟡 As a **host**, I want to open or close an empty slot, so that I control how many players can join. *(Closed-slot state is modelled + synced; the open/close control isn't wired.)* +- ⬜ As a **host on an adaptive map**, I want to close a slot as "spawn-mex", so that the position yields mass instead of an ACU. +- ✅ As a **player**, I want to occupy an empty open slot, so that I can join the game; *when* I'm not already marked ready. +- ✅ As a **host**, I want to move a player to another slot or swap two players, so that I can arrange start positions and teams. *(Drag a row onto another → `RequestSwapSlots`.)* +- 🟡 As a **host**, I want to kick a player with an optional message, so that I can remove someone; *and* the message is remembered for next time. *(Eject works; no message / recall.)* +- 🟡 As a **player**, I want each slot row to show name, rating, country, faction, colour, team, ping, CPU and ready state, so that I can assess the lobby at a glance. *(Name, CPU/headroom, ready shown; rating/country/faction/colour/team/ping not yet.)* +- ✅ As a **player**, I want a slot's controls to reflect who owns it (me / another player / host / AI) via colour and an appropriate right-click menu, so that I only see actions I'm allowed to take. + +## C. Per-player settings + +- ⬜ As a **player**, I want to choose my faction (including Random), so that I play what I want; *given* the map allows it and I'm not ready. +- ⬜ As a **player**, I want to pick a colour, so that I'm visually distinct; *when* the colour is free — taken colours are hidden and the host reverts conflicts. +- ⬜ As a **player**, I want to set my team, so that I'm allied correctly; *when* AutoTeams is off and I'm not ready. +- ✅ As a **player**, I want to toggle Ready, so that I signal I'm set; *and when* ready, my own controls lock until I unready. +- ⬜ As a **host**, I want to force a player not-ready, so that I can change settings that affect them. +- ⬜ As a **player**, I want to pick my start position on the map preview, so that I control where I spawn; *when* spawn is fixed (host gets swap/assign tools otherwise). +- ⬜ As a **player**, I want my last faction/colour remembered, so that I don't re-pick every lobby. + +## D. AI management (host) + +- ⬜ As a **host**, I want to add an AI of a chosen personality to a slot, so that I can fill the game; *and* the AI is auto-ready. +- ⬜ As a **host**, I want the AI personality list to include built-in and mod-provided AIs, so that all installed AIs are selectable. +- ⬜ As a **host**, I want to remove an AI from a slot, so that I can free it. +- ⬜ As a **host**, I want AIs to get a computed rating from cheat/build/map multipliers, so that game quality estimates stay meaningful. +- ⬜ As a **host**, I want to set an AI's faction/colour/team and move/swap it like a player, so that I can arrange AI-inclusive setups. +- ⬜ As a **host**, I want a quick "fill slots" action, so that I can populate remaining slots with AIs at once. + +## E. Observers + +- 🟡 As a **joining client**, I want to enter as an observer when no slot is free or when I request it, so that I can still watch. *(Observers are modelled/synced; auto-enter-as-observer on a full lobby isn't wired.)* +- 🟡 As a **player**, I want to become an observer (or request it from the host), so that I can step out of the game without leaving. *(Host moves a player to observers via the context menu, and an **"Observe" button** moves the local player out of their slot — host-side; a non-host's request-to-host path isn't wired yet.)* +- ✅ As an **observer**, I want to become a player / request a specific slot, so that I can join in; *given* a slot is available (host may evict an AI). *(Right-click → "Play this slot".)* +- 🟡 As a **player**, I want to see the observer list with rating, ping and CPU, so that I know who's spectating. *(Observer strip shows count + names; no rating/ping/CPU.)* +- ⬜ As a **host**, I want to kick an observer, so that I can manage spectators; *and* observers are auto-kicked at launch if observers are disallowed. +- ⬜ As an **observer**, I want to use public and private chat (shown greyed), so that I can still communicate. + +## F. Host authority & validation + +- ✅ As a **host**, I want to be the single source of truth, so that all clients converge on one authoritative state. *(Host-authoritative: request → validate → broadcast snapshot.)* +- 🟡 As a **player**, I want my own-slot changes applied optimistically and then confirmed by the host, so that the UI feels responsive but stays consistent. *(Round-trips through the host; not yet optimistic.)* +- ⬜ As a **host**, I want option-changing buttons disabled while any human is not ready, so that settings can't shift after people commit. +- 🟡 As a **host**, I want the launch button enabled only when everyone is ready (or single-player / I'm observing), so that I can't start prematurely. *(Launch works — `RequestLaunch` builds the config, broadcasts a `LaunchGame` message and calls the engine; it's validated on click (host + a map + ≥1 seat + every other human ready, the host exempt). Not yet reactively enabled/disabled, and the block reason is only logged.)* +- ⬜ As a **system**, I want to ignore a move request if the player became ready in the meantime, so that races don't corrupt slot state. + +## G. Game options (host) + +- ✅ As a **host**, I want to set the victory condition (assassination / decapitation / supremacy / annihilation / sandbox), so that the win rule fits the game. *(Options dialog.)* +- ✅ As a **host**, I want to configure share conditions (full / until-death / partial / transfer-to-killer / defectors / civilian-deserter) and share-unit-cap, so that resource/unit transfer on death matches our preference. +- ✅ As a **host**, I want to set unit cap, fog of war, game speed, no-rush timer, prebuilt units, civilians, score and cheats, so that the match rules are tuned. +- ✅ As a **host**, I want to mark the game unranked, so that it doesn't affect ratings. +- ✅ As a **host (multiplayer)**, I want to set timeouts and disconnection delay, so that disconnect handling fits the context (tournament/quick/regular). +- ✅ As a **host**, I want to set AI multipliers (cheat/build), omni, TML randomization and expansion limits, so that AIx difficulty is tuned. *(AI column of the options dialog.)* +- 🟡 As a **host**, I want a "reset to defaults" action, so that I can clear all options at once (which also unreadies everyone). *(Reset button clears to defaults; the auto-unready side-effect isn't wired.)* +- ✅ As a **host**, I want map-specific and mod-provided options surfaced alongside the standard ones, so that nothing is hidden. *(Scenario + Mods columns.)* +- ✅ As a **player**, I want to see the active (and optionally only the changed) options, so that I understand the ruleset. *(The config panel's **Options tab** shows the current values read-only to everyone, grouped Lobby / Scenario / Mods, with a hide-defaults toggle and origin markers; the host edits them via the Options dialog.)* + +## H. Auto-teams & spawn + +- 🟡 As a **host**, I want AutoTeams modes (top/bottom, left/right, odd/even, manual), so that teams are assigned by position without manual fiddling. *(Selectable as a lobby option; the actual auto-teaming/launch resolution isn't wired.)* +- ⬜ As a **host**, I want manual AutoTeams by clicking map markers, so that I can hand-place teams on random spawn. +- 🟡 As a **host**, I want spawn variants (fixed, random, balanced/flex/reveal, penguin-autobalance), so that start placement matches the desired fairness/secrecy. *(Selectable as a lobby option; placement is resolved at launch, which isn't wired.)* +- ⬜ As a **host on an adaptive map**, I want per-slot spawn-mex, so that closed positions still contribute economy. +- 🟡 As a **system**, I want random factions/start spots/AI names and the ratings/clan tables resolved at launch, so that the final config is complete and fair. *(At launch `BuildGameConfiguration` resolves random factions to a concrete one, assigns army numbers in slot order, and stamps the ratings/clan-tag tables into the game options; start-spot/AutoTeams resolution and AI names aren't done yet.)* + +## I. Map selection (host) + +- ✅ As a **host**, I want to browse maps with a preview, so that I can choose a map informedly. +- 🟡 As a **host**, I want to filter maps by player count, size, type (official/custom), AI markers and hide-obsolete, and search by name, so that I find the right map quickly; *and* my filters persist. *(Size, player count, name search + persistence done; type/AI-markers/hide-obsolete filters not.)* +- 🟡 As a **host**, I want a resource-aware preview (mass/hydro, water/cliff/buildable masks, start spots), so that I understand the map layout. *(Preview shows start spots, mass/hydro, wrecks; the lobby's Map tab also shows reclaim totals + description / author / url / version; terrain masks not.)* +- ✅ As a **host**, I want to pick a random map, so that I can play something fresh. +- ✅ As a **player**, I want clear warnings when a map's files are missing, so that I'm not stuck on an unplayable map. *(File-health check disables Select.)* + +## J. Mods manager + +- 🟡 As a **host**, I want to enable/disable sim mods, so that gameplay-affecting mods apply to everyone; *and* doing so disables ranking. *(Enable/disable + sync done via `RequestSetGameMods`; the ranking-disable side-effect isn't wired.)* +- ✅ As a **player**, I want to enable UI mods locally, so that my client UI changes without affecting others. +- 🟡 As a **player**, I want to browse, sort, search, expand/collapse and favorite mods, so that I can manage a large mod list; *and* my preferences persist. *(Browse, search, type filters, persistence done; sort + expand/collapse not; favorites replaced by presets — see next.)* +- 🟡 As a **player**, I want "activate favorites" in one click, so that I quickly enable my usual set (host: sim+UI, client: UI only). *(Replaced by named **presets** — load a saved selection; the host/client sim-vs-UI split is honoured.)* +- ✅ As a **player**, I want mod dependencies and conflicts handled automatically, so that I don't end up with a broken set. *(`ResolveEnable`/`ResolveDisable`.)* +- ⬜ As a **host**, I want to see which peers lack a sim mod, so that missing-mod peers are flagged/auto-disabled or kicked rather than causing desyncs. + +## K. Unit restrictions (host) + +- ⬜ As a **host**, I want to apply unit-restriction presets (tech levels, types, spam/snipe/anti-air/etc.), so that I can shape allowed units fast. +- ⬜ As a **host**, I want to toggle individual units per faction, so that I can fine-tune beyond presets. +- ⬜ As a **player**, I want a read-only view of the restrictions, so that I know what's banned. +- ⬜ As a **host**, I want restrictions saved with presets and reflected in rating eligibility, so that custom rulesets are reusable and correctly rated. + +## L. Chat + +- ⬜ As a **player/observer**, I want to send public chat, so that everyone in the lobby sees it. +- ⬜ As a **player/observer**, I want to whisper via `/whisper` `/pm` `/w` `/private`, so that I can message one person privately. +- ⬜ As a **player**, I want clear feedback on an unknown command or an invalid whisper target, so that I know it didn't send. +- ⬜ As a **player**, I want join/leave/connection notices in chat, so that I'm aware of lobby changes. +- ⬜ As a **player**, I want to click a name in chat to prefill a whisper, so that replying is quick. +- ⬜ As a **player**, I want command history (up/down) and auto-scroll with a "new message" indicator, so that chatting is comfortable. +- ⬜ As a **player**, I want ratings shown alongside names, so that I gauge the lobby's skill. + +## M. Connectivity & health + +- 🟡 As a **player**, I want my CPU benchmarked (auto on connect, and on demand), so that others can see my performance; *and* the result is cached and re-broadcast by the host. *(Stored benchmark is shared + re-broadcast; no live/on-demand stress test.)* +- 🟡 As a **player**, I want CPU and ping bars per slot (ping shown when poor), so that I can spot weak links. *(CPU column with cap-headroom done; ping not.)* +- 🟡 As a **system**, I want to track per-peer connection status, so that the UI reflects who is fully connected. *(`EstablishedPeers`/`OnPeerDisconnected` tracked; not fully surfaced.)* +- ⬜ As a **host**, I want launch blocked until every important peer is connected to every other, so that the game doesn't start with broken links. +- 🟡 As a **player**, I want a peer's disconnect to clear its slot and notify chat, so that the lobby stays accurate. *(Disconnect frees the slot for everyone; no chat notice — chat isn't in the lobby yet.)* +- ⬜ As a **client**, I want a "host timed out — keep trying / give up" prompt, so that I can decide what to do on a stalled connection. + +## N. Compatibility & launch validation + +- ⬜ As a **host**, I want to reject peers on a different game version/type/commit, so that desyncs are prevented (with a clear ejection reason). +- 🟡 As a **player**, I want missing-map situations flagged (and a fallback used), so that the lobby communicates the problem instead of silently breaking. *(The map dialog flags missing files; in-lobby fallback not.)* +- ⬜ As a **host**, I want peers' available mods exchanged and validated, so that everyone has the required sim mods before launch. +- ⬜ As a **host**, I want launch blocked with a clear reason (no players, host-as-observer when disallowed, observers present, missing connections), so that I know exactly what to fix. + +## O. Presets & rehost + +- ⬜ As a **host**, I want to save the current setup (map, options, mods, restrictions, players) as a named preset, so that I can reuse it. *(Only **mod** selections have presets so far — not the full setup.)* +- ⬜ As a **host**, I want to load/delete/rename presets, so that I can manage reusable configurations. +- ⬜ As a **system**, I want the last game auto-saved as a preset at launch, so that rehost can restore it. +- ⬜ As a **host**, I want rehost to reseat returning players to their prior slots (displacing AIs/others as needed), so that a replay setup reconstitutes quickly. + +## P. Lobby preferences (per user) + +- ⬜ As a **player**, I want to choose the lobby background mode, chat font size, snowflake count, windowed mode, background stretch and chat colours, so that the lobby looks how I like; *and* changes apply immediately and persist. + +## Q. Other dialogs + +- ⬜ As a **host**, I want a briefing dialog for scenarios that have one, so that players see the operation context. +- ⬜ As a **player**, I want a large map preview (with terrain/resource masks), so that I can study the map closely. +- ⬜ As a **host (skirmish)**, I want a save/load dialog, so that I can resume saved games. +- ⬜ As a **host**, I want confirmation prompts for destructive actions (kick, reset options), so that I don't trigger them by mistake. + +## R. New requests + +- ⬜ As a **host**, I want the ability to lock players in-place when autobalance is applied so that players that want to play together stay in the same team. +- ⬜ As a **player**, I want the observer bug that can freeze/crash the lobby fixed — or at least a warning when it's hit — so that observing doesn't break the lobby. *(Reliable repro needs a debuggable lobby setup.)* +- ⬜ As a **player**, I want to randomise among a chosen subset of factions (multi-choice), so that I get variety without pure random. +- ⬜ As a **player**, I want my FAF avatar shown in the lobby, so that players are recognisable. +- ⬜ As a **host**, I want a "players vs AI" AutoTeams option, so that all humans are teamed against the AIs automatically. +- ⬜ As a **host**, I want closing a slot to auto-move its player to a free slot (in opti), so that rearranging doesn't drop anyone. +- ⬜ As a **host**, I want an opti team preview, so that I can see the balanced teams before committing. +- ⬜ As a **host**, I want flexible mirror balancing, so that mirror match-ups can be balanced with some give. +- ⬜ As a **host**, I want a system for balancing premades, so that pre-made groups are distributed fairly across teams. *(Related to locking players in place during autobalance, above.)* +- ⬜ As a **player**, I want easier rehosting — a dedicated in-game/lobby rehost button that works with the client, including rehosting someone else's lobby (when they're AFK, or just to duplicate it), so that rehosting is quick. *(Extends the "rehost my last game" stories in A/O.)* +- ⬜ As a **non-host player**, I want to save presets as a client, so that I keep my setups even when I'm not hosting. +- ⬜ As a **host**, I want to load presets without switching maps, so that applying a preset doesn't force a map change. +- ⬜ As a **player**, I want lobby options categorised by mod, so that mod-provided options are grouped clearly. +- ⬜ As a **player**, I want to collapse lobby-option categories, so that I can focus on the ones I care about. +- ⬜ As a **non-host player**, I want to read each option's description, so that I understand what every setting does. +- ⬜ As a **host**, I want the unit-manager bug fixed where presets stop appearing after you disable units manually, so that presets keep working. +- ⬜ As a **host**, I want better unit stats in the unit manager, so that I can judge units when restricting them. +- ⬜ As a **host**, I want faster map/option loading when many maps are installed, so that the lobby isn't slow to open. +- ⬜ As a **player**, I want faster mod-manager loading, so that opening it isn't slow. +- ⬜ As a **modder**, I want a moddable lobby UI, so that the lobby can be extended/customised by mods. +- ⬜ As a **player**, I want mod presets kept separate from lobby-option presets, so that the two don't get entangled. +- ⬜ As a **host**, I want map-specific lobby options to persist between sessions when I rehost the same map, so that I don't reconfigure them each time. +- ⬜ As a **host**, I want last game's mods NOT auto-enabled when the game didn't launch (but kept when it did, for rehosting), so that a failed launch doesn't silently carry mods forward. +- ⬜ As a **player**, I want "disable all sim / UI / all mods" buttons, so that I can clear mods in one click. +- ⬜ As a **player**, I want the mod manager's dependency-related UI updates fixed, so that enabling/disabling reflects dependencies correctly. +- ⬜ As a **developer**, I want mod-dependency management reworked in the lobby frontend so it no longer keys off singular version UUIDs, so that the dependency system is fixed at the source. \ No newline at end of file