Files
Commonwealth-Online-Public/changelog.md
T
andrewandCursor 7a3e0855b0 Add consumer server CLI with Typer + Rich and Windows launcher
Introduce production-ready CLI for hosting Commonwealth Online servers in
cloud and on-premises environments.

Features:
- Server orchestration service (server_service.py) wrapping relay lifecycle
- JSON configuration system (config.py) for hosted deployments
- Typer+Rich CLI (consumer_server_cli.py) with serve/status/clients/world commands
- Windows launcher (start.bat) for one-click server startup
- Auto-detection of LAN addresses and dependency installation
- Machine-readable JSON output for monitoring and automation

Cli commands:
  serve - Start server with optional config overrides
  status - Display server stats and packet counters
  clients - List connected players
  world time - Set in-game time for all clients
  world weather - Set weather for all clients
  config init - Generate default configuration file

Documentation:
  - Updated docs/setup.md with CLI quick-start guide
  - Added server/README.md with usage instructions
  - Updated changelog and dev-log with test results

Testing: - Verified config generation and loading
  - Verified server startup banner and LAN detection
  - Verified fake client connection and welcome packet
  - Verified CLI help and command routing
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-07-09 20:44:40 +12:00

194 lines
27 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Changelog
All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
For testing notes, milestone summaries, known issues, and next steps, see [`docs/dev-log.md`](docs/dev-log.md). Do not include testing content in this file.
## [Unreleased]
### Added
- **Consumer server CLI** (`server/consumer_server_cli.py`): Production-ready CLI for hosting Commonwealth Online servers in cloud and on-premises environments using Typer and Rich.
- **Server orchestration service** (`server/server_service.py`): Reusable service facade for wrapping server lifecycle, configuration, and admin operations (stats, world-state control).
- **Configuration module** (`server/config.py`): JSON-based config loading, validation, and generation for hosted deployment (host, port, server name, max players, logging verbosity).
- **Windows launcher** (`server/start.bat`): Double-click to start server with automatic dependency installation and config generation.
- **Server README** (`server/README.md`): Quick-start guide for Windows users and CLI reference.
- CLI commands: `serve`, `status`, `clients`, `world time`, `world weather`, `config init`.
- JSON output mode for all commands (`--json` flag) suitable for monitoring and automation.
- Server startup banner with connection instructions and LAN address detection.
- Updated `server/requirements.txt` with `typer` and `rich` dependencies.
### Changed
- Documentation updated: `docs/setup.md` now includes quick-start CLI hosting instructions.
### Fixed
- None currently in this release.
- Custom main menu overlay and open sub-panels (server browser, settings) now hide when a server join begins loading the game, so the overlay no longer obscures or blocks the vanilla loading screen.
- Mouse cursor no longer trampolines back to a centered box in the custom main menu (previously only worked with a gamepad connected). In mouse mode the title-screen engine repositions/clips the OS cursor to a small centered box every frame; with a gamepad active that path never runs, so the pointer was free. Fixed by intercepting `SetCursorPos` and `ClipCursor` in the Fallout4.exe import table (IAT) and making them no-ops while the Commonwealth Online overlay owns the pointer, so the game can no longer move or box in the Windows cursor. Only the game module's imports are patched, leaving PrismaUI's own cursor rendering untouched. Also hooks the `MainMenu` `OnCursorMoveEvent`/`OnMouseMoveEvent` vtable slots and keeps the `MenuCursor` release (`forceOSCursorPos = false`, cleared parallax constraints, widened bounds) as defense-in-depth.
### Added
- **Custom main menu overlay**: PrismaUI full-screen overlay of Commonwealth Online main menu (MULTIPLAYER, CREATIONS, SETTINGS, HELP, QUIT) auto-shows on Fallout 4 title screen, replacing the vanilla list menu.
- **Main menu input capture**: Keyboard (↑↓ / ENTER / ESC) and gamepad (dpad / A / B) navigation of custom main menu overlay; vanilla menu input is blocked so the underlying CONTINUE/NEW/LOAD/SETTINGS rows remain unreachable.
- **Main menu vanilla settings gateway**: SETTINGS → GAME SETTINGS → OPEN FALLOUT 4 SETTINGS calls `openGameSettings` stub (full vanilla settings sub-flow is planned for v1.1).
- `F4TMainMenuBridge.cpp` and `F4TMainMenuBridge.h` for main menu↔C++ event routing (controller input logging; full JS dispatch pending).
- `F4TMainMenuVanillaSettings.cpp` and `F4TMainMenuVanillaSettings.h` discovery stubs for vanilla settings panel access (ready for GFx work).
- `IsMainMenuVisible()`, `ShowMainMenu()`, `HideMainMenu()`, `IsCustomMenuInputCaptured()` public API in F4TPrismaUI.
- `SetMainMenuActive(bool)` in F4TMenuInput to route gamepad input to main menu or server browser (active target determines recipient).
- Unified pointer mode tracking and mouse/gamepad mode switching for both main menu and server browser overlays (single active menu at a time).
### Changed
- Server browser extracted into reusable `CO_Browser.create()` module (`browser/browser.js`, `browser/browser-modal.css`) matching the settings modal pattern; standalone `browser/index.html` still works for F9/dev via thin `app.js` bootstrap.
- Main menu MULTIPLAYER now opens the server browser as an embedded modal (left nav stays visible, background dims) instead of swapping to a separate PrismaUI view.
- `F4TPrismaUI` routes `ServerBrowserBridge`, `coAction`, `closeBrowser`, and hover sync through the main menu view when the embedded browser is active; all JS hooks (`dispatchCoEvent`, `onBrowserShown`, `closeBrowser`, `setConnectionStatus`, `CO_App`) are unchanged.
- `ServerBrowserBridge::SetView()` added so the C++ bridge can target the active PrismaUI view.
- **Main menu→multiplayer bridge**: MULTIPLAYER opens the server browser as a modal overlay on the main menu (main menu stays visible); closing the browser returns to the main menu list.
### Changed
- F4TPrismaUI renamed internal globals for clarity: `g_visible``g_browserVisible`, `g_domReady``g_browserDomReady`, `g_browserMouseCursorVisible``g_menuMouseCursorVisible`, `g_browserPreferGamepad``g_menuPreferGamepad` (shared across both views).
- Multiplayer row injection is now gated behind `constexpr bool kInjectMultiplayerRow = false` in F4TMainMenuInject.cpp. The custom main menu overlay supersedes the injected row; existing code is preserved for v1.1 opt-in.
- Controller input dispatch (`ForwardButtonPhase`) now checks active menu (main menu vs server browser) and routes to the appropriate bridge (`MainMenuBridge::ForwardControllerInput` or `ServerBrowserBridge::ForwardControllerInput`).
- `IsCustomMenuInputCaptured()` returns true when main menu OR server browser is visible, centralizing the input block guard in MainMenu hooks.
- `main-menu/script.js` now includes `window.CO_App` object with `setPointerMode()` for C++ to invoke, and `handleControllerInput()` stub for gamepad dispatch (wired in v1.1 when dispatch is complete).
### Fixed
- Game crashed on load with `REL/Trampoline.cpp: Failed to handle allocation request` because `MenuCursor` detour hooks required trampoline memory the plugin never allocated. Replaced detours with a `MainMenu::AdvanceMovie` vtable hook (no trampoline) that re-expands cursor bounds after vanilla parallax runs.
- Mouse cursor could not move away from the center of the screen while the custom main menu overlay was shown. Root causes: (1) overlay could appear during Please Stand By / intro Binks; (2) vanilla `RE::MenuCursor` min/max bounds were re-applied each frame by title-screen parallax. Fixed by gating show on intro completion, clearing constraints each frame, releasing again after `MainMenu::AdvanceMovie` and on `UIAdvanceMenusFunctionCompleteEvent`, and using `disableFocusMenu=true` for the main menu overlay.
### Changed
- Pause menu settings panel fades and slides in subtly on open and animates out on back (opacity + 10px vertical offset, 220ms ease-out).
- Pause menu no longer opens the settings panel automatically on load; the pause screen starts with no menu selection and no sub-view open.
- Settings panel uses a fixed width/height and centered position in the pause menu; tab panes share a stacked content area so switching FALLOUT 4 / MULTIPLAYER no longer resizes the window.
- Settings controller prompt bar no longer changes labels or visibility when switching tabs (MOVE, CHANGE, SELECT, BACK, SWITCH FOCUS stay consistent).
- Pause menu settings UI extracted into reusable module at `ui/views/CommonwealthOnline/settings/` (`settings-data.js`, `settings.js`, `settings.css`). Pause menu mounts it via `CO_Settings.create()` so the same component can be embedded in a future custom main menu with `layout: "standalone"`.
- Pause menu map wheel zoom now scales smoothly toward the mouse cursor instead of snapping to the viewport center.
- Pause menu map drag-pan eases toward the pointer and coasts with inertia on release.
- Pause menu settings prototype now uses two tabs only: **GAME SETTINGS** (placeholder to open vanilla Fallout 4 settings later) and **MULTIPLAYER SETTINGS** (custom Commonwealth Online options for Profile, Voice Chat, Map & Social, and Network). Removed the full category clone (Gameplay, Display, Audio, Controls, Accessibility, etc.).
- Multiplayer settings are data-driven (`text`, `toggle`, `select`, `slider`, `keybind`) with selected-row descriptions and keyboard navigation (tabs / list focus, value cycling).
- `window.CommonwealthOnlineUI` bridge stubs now expose `openGameSettings`, `setMultiplayerSetting`, `onBack`, and `onOpenView`.
- Selected multiplayer setting rows use a solid amber bar with a thin green leading edge instead of a muddy green-to-amber fade.
- Main menu prototype menu rows trimmed to MULTIPLAYER, CREATIONS, SETTINGS, HELP, and QUIT (removed CONTINUE, NEW, and LOAD).
- Cross-view UI assets consolidated under `ui/views/CommonwealthOnline/shared/` (logo, controller icons). Pause menu, main menu, and server browser now reference `../shared/` instead of per-view icon copies.
### Fixed
- Pause menu settings panel fade-in now runs reliably (dedicated `is-open` class with reflow before transition).
- Pause menu settings: pause-nav selection bars no longer spill into the settings panel (clip bars in settings mode).
- Dedicated PC back button on the pause menu map (`ESC` keycap + BACK label, top-left) so mouse users can leave map mode without relying on the controller B prompt. Fades in after the left panel hides and fades out immediately on exit so it does not overlap the logo.
- Static HTML/CSS/JS pause menu concept prototype at `ui/views/CommonwealthOnline/pause-menu/` — Fallout 4styled multiplayer map pause screen with left menu, server info panel, controller prompts, and keyboard navigation (MAP selected by default).
- Mouse wheel zoom and click-drag pan on the pause menu map background (`ui/views/CommonwealthOnline/pause-menu/script.js`), previewing the intended Fallout 76-style navigable map; markers move with the map via shared CSS custom properties.
### Fixed
- Pause menu player/ally map markers share the map's blur filter (via a `.map-world` wrapper) so they blur and unblur in lockstep with the map instead of fading on a separate timing.
- Pause menu controller prompts: map navigation prompts (MOVE, ZOOM, SELECT, BACK) now appear on the map mode bar instead of the pause menu bar; pause menu shows SELECT and BACK only.
- Pause menu prototype's `--co-ui-scale` formula (`ui/views/CommonwealthOnline/pause-menu/styles.css`) divided a length by a bare number (`calc(100vw / 1920)`), which is a different CSS type than the plain numbers used alongside it in `clamp()`/`min()`. That type mismatch made the whole custom property invalid at the point of use, so every `calc(Npx * var(--co-ui-scale))` silently fell back to `auto` — causing the logo, menu items, and selection bar to stretch to fill their containers instead of their intended sizes. Fixed by dividing by a length (`1920px`/`1080px`) so the result is a valid unitless ratio.
- Pause menu map background switched from a cropped `cover` fit to `contain` so the full regional map is visible (less zoomed-in) instead of a tightly cropped strip, closer to a Fallout 76-style full map overview.
### Changed
- Map mode controller prompts now use LS for MOVE and RS for ZOOM (replacing the incorrect Menu glyph for move), with A SELECT and B BACK unchanged.
- Pause menu and map mode controller prompts now use Xbox PNG glyphs from `ui/Icons/Xbox` (amber-tinted like the server browser): LS (`T_X_L_2D_Alt`) MOVE, RS Y-axis (`T_X_R_Y_Alt`) ZOOM, A SELECT, B BACK.
- Rewrote root `README.md` for current project stage: structured status (working / in progress / planned / out of scope), architecture summary, developer quick start, updated repository layout and requirements, honest scale limits (4 proxies per client vs 16+ design target), and aligned license/legal sections with `LICENSE`.
### Added
- `docs/project-comparison.md` comparing Commonwealth Online with DoxyCoSync (architecture, scale, sync scope, collaboration).
- Updated root `README.md` status to reflect functional multiplayer foundation (remote proxies, appearance, apparel, weapons).
- Experimental proxy weapon alert forcing: while a remote player reports `weaponDrawn=true`, runtime proxies now periodically execute scoped `<proxyRef>.setalert 1` before weapon animation sync, then clear alert on holster, to test whether Fallout 4's NPC alert state is what keeps weapon-ready poses alive.
- One-time-per-proxy diagnostic log (`Runtime proxy weapon graph DIAGNOSTIC`) reporting the loaded animation-graph and bound-channel counts when a proxy first has a weapon equipped, to help determine why weapon FSM events are being rejected by the graph.
- Weapon animation sync for ranged guns: proxy actors now equip remote players' right-hand weapons and play armed idle/locomotion poses when `weaponDrawn=true`.
- `rightHand` weapon slot to `equippedItems` protocol: syncs equipped `WEAP` form IDs alongside apparel items. Optional field; unresolved weapons skip with throttled warning (no crash).
- Weapon-drawn animation state tracking via `iSyncGunDown` graph variable: `0` = drawn/ready, `1` = holstered/gun-down. Fires `weaponDraw` and `readyStateEnter` events on draw, `gunDownStateEnter` on holster.
- Local player right-hand weapon capture (`GetEquippedWeaponFormId`) and network transmission in transform packets.
- `docs/weapon-animation-sync.md` reference guide documenting WeaponBehavior graph events, variables, and clip naming from F4-Animation-Research unpacked XML.
- Weapon candidate graph variables to local animation graph debug probe: `iSyncGunDown`, `iRifleDrawnStateID`, `iAttackState`, `isFiring`, etc. for manual in-game validation.
- Quest auto-start on COVault109 exit: "Out of Time" quest (MQ102) now starts automatically via console `startquest`/`setstage` commands when the player leaves COVault109 for the first time.
- Complexion texture form reference (`complexionFormId`) to appearance payload so hands, arms, and body match the synced skin tone (follows the existing hair colour pattern).
- Appearance protocol version 3 with an optional `tints` field (character tint layers: skin tone, complexion, makeup, beard shade) so proxies can mirror the sender's skin colour and facial detail.
- Capture of player/NPC `tintingData` in `CaptureLocalAppearance`, plus game-thread application of tints onto runtime proxies: existing entries are updated in place by template ID, and missing entries are reconstructed against the proxy race's tint templates (skipped when no template resolves).
- `server/fake_client.py` parsing/output and `server/fake_player.py` sample payload for the new `tints` appearance field.
- Appearance protocol version 2 with optional `morphRegions` (region morph slider values) and `facialBoneMorphs` (bone-based facial morph transforms) fields so proxies receive advanced face-shape morphs that previously did not sync.
- Capture of `TESNPC::morphRegionSliderValues` and `TESNPC::facialBoneRegionSliderValues` in `CaptureLocalAppearance`, plus game-thread application of both onto runtime proxies in `ApplyProxyAppearanceFromRemoteState`.
- `server/fake_client.py` parsing/output and `server/fake_player.py` sample payloads for the new `morphRegions` and `facialBoneMorphs` appearance fields.
- Optional `appearance` transform snapshots for best-effort runtime proxy body and face visuals, including height, body morph weight, body tint, hair colors, head-part IDs, and morph slider values while leaving gender switching out.
- Game-thread proxy appearance application for supported `appearance` fields after runtime proxy 3D is ready, with race switching deferred for future proxy-base compatibility work.
- `server/fake_client.py` parsing/output and `server/fake_player.py` sample payloads for relayed `appearance` transform data.
- `COVault109` solo-cell handling in the plugin so first-time character-creation space suppresses outgoing transform packets and remote proxy representation.
- `compile-papyrus.bat` to compile active Papyrus sources from `creation-kit\scripts\source` into `creation-kit\scripts\compiled` using the Fallout 4 Creation Kit Papyrus compiler, resolving the Fallout 4 install with the same path workflow as `deploy-all.bat`, using saved `.fallout4-path` values without re-prompting during builds, and skipping reference-only `CoSync*.psc` files.
- `build-all.bat` now compiles Papyrus scripts before staging the mod package, and still stages the repo build folder for inspection when Papyrus compilation fails.
- `deploy-all.bat` now resolves the Fallout 4 path, compiles Papyrus scripts, stages the repo build folder, and then deploys from `build\Fallout 4\Data` into the Fallout 4 `Data` folder.
- `stage-mod.bat` now stages active Papyrus scripts recursively: compiled `creation-kit\scripts\compiled\*.pex` into `Data\Scripts` and raw `creation-kit\scripts\source\*.psc` into `Data\Scripts\Source\User`, while skipping reference-only `CoSync*` files.
- Server-authoritative weather and time control via `serverWorldState` packets from the dev server GUI.
- **Weather / Time** tab in `server/dev_server_app.py` with preset buttons for `fw` weather form IDs and `set gamehour to HHmm` time values.
- `server/world_state_presets.py` with shared weather and time preset definitions.
- `protocol/server-world-state.md` documenting the new packet type.
- Event-driven world time resync via optional `timeSync` field on `worldState` packets; the current world-state host pushes time after menus, loading screens, save/load, wait/sleep, and other time freezes.
- `timeSync` tracking in `server/fake_client.py` host world-state snapshot output.
- Optional `equippedItems` transform snapshots for visible apparel slots so proxies can mirror clothing, armor, hats, and eyewear changes.
- Game-thread proxy equipment application for synced apparel, including explicit tracked-slot unequips and cleanup when runtime proxy slots are held, reused, or reassigned.
- `server/fake_client.py` parsing and output for relayed `equippedItems` transform data.
### Fixed
- **Weapon animation graph now loads on proxies.** Proxy actors now trigger `AIProcess::RequestLoadAnimationsForWeaponChange()` after weapon equip/unequip, which loads the `WeaponBehavior` animation subgraph. This allows weapon events (`weaponDraw`, `readyStateEnter`, `gunDownStateEnter`) to be accepted by the animation system and enables proper weapon-drawn state animations to persist instead of immediately reverting to idle/holstered poses. Fixes: weapon briefly appears then holsters immediately on proxy.
- Proxy weapon attachment now avoids the generic queued equipment 3D refresh after a successful manual weapon attach, preventing the freshly attached weapon model from being immediately cleared again. Weapon draw/holster transitions and subsequent drawn-weapon updates also re-run weapon reparent/draw calls as a fallback while Fallout 4's `WeaponBehavior` graph is still not accepting the standard weapon animation events on proxies. Drawn-weapon states now use targeted graph writes instead of descriptor bulk writes so unrelated weapon graph variables are not clobbered back to idle/holstered defaults.
- Runtime proxy animation state no longer resets on every camera-frustum visibility flicker; only genuine 3D teardown/reload (already handled separately) now clears applied animation state. Previously, `IsVisible()` flapping on culled proxies caused the entire animation state to be treated as "just initialized" on effectively every update tick, forcing edge-triggered events (including `weaponDraw`/`readyStateEnter`/`gunDownStateEnter`) to re-fire continuously and flooding the log.
- `HasDesiredStateChanged` no longer reports "changed" on almost every tick for idle proxies. Locomotion tier comparison is now skipped while the proxy isn't moving instead of always evaluating `!lastLocomotionTier` as changed (that field is intentionally reset to empty while idle).
- Proxy head parts (including hair) now apply even when the sender's head-part count differs from the proxy base; the head-part array is reallocated with the game allocator instead of deferring the whole list on a count mismatch.
- Appearance apply log now reports applied-vs-sent head-part counts (`headParts=applied/sent`) so deferred or partial head-part application is visible.
- New clients now receive existing players' last transform snapshots immediately after `welcome`, including `appearance`, so late joiners do not start with default proxy visuals while waiting for the next sender heartbeat.
- Runtime proxy candidate isolation now ignores actors flagged as deleted, so a freshly spawned proxy is controlled instead of the slot adopting a still-present stale proxy that was marked for deletion the same frame.
- Stale saved runtime `COPlayerProxy` actors are deleted before spawning a fresh PlaceAtMe proxy, preventing duplicate visible proxies when an old uncontrolled proxy persisted in a save.
- Runtime proxy promotion no longer waits for camera-frustum `IsVisible()` before assigning a newly spawned proxy, preventing remote players from appearing only after the local player turns toward them.
- Fixed Papyrus staging path construction so `.pex` and `.psc` files are copied into `build\Fallout 4\Data\Scripts` and `build\Fallout 4\Data\Scripts\Source\User`.
- If a server profile exists but its associated save was deleted, joining from the main menu now falls back to first-time character creation and re-binds the profile to the newly created save instead of hard-failing.
- Pending first-time profile binding now completes as soon as a save exists even if character-creation phase flags are still active, preventing repeated `coc` first-time launches on reconnect.
- Session launch now resolves equivalent server endpoints (for example `localhost`, `127.0.0.1`, and legacy host-case variants) to an existing server profile before deciding first-time join flow, preventing unintended new-character creation when reconnecting.
- Server profile persistence now uses a sanitized save-folder path with a Documents fallback and write-failure logging, preventing silent loss of server profile bindings across game restarts.
- Pending profile binding now accepts exit saves (including `Exitsave...`) so the last auto-save on game exit can be rebound and loaded on reconnect, reducing accidental progress loss.
- Fixed Windows build issues in server profile path fallback by replacing unsafe `getenv` usage and accepting `std::string_view` save-folder names in folder sanitization.
- Reconnect now refreshes stale associated `Exitsave...` names to the newest available exit save before load, preventing fallback to first-time flow when exit-save filenames rotate between sessions.
- Server GUI weather now runs `fw <8-digit-form-id>` on the current `worldStateHostPlayerId` client (not hardcoded to player 1), scheduled on the game thread.
- Weather `serverWorldState` handling now defers until world-state host assignment is known, then skips only non-host clients.
- Weather `serverWorldState` packets are broadcast to all clients so the designated host receives them even after host reassignment.
- Server restart now resets player/host assignment so the first client is `playerId` 1 again, preventing GUI weather from being ignored after restart.
- Plugin now defers server weather commands until player assignment is available, preventing initial GUI clicks from being dropped right after connect.
- Replaced invalid default GUI weather IDs with valid Fallout 4 weather form IDs so `fw <id>` no longer fails with "Invalid weather ...".
- Corrected `Clear` preset ID typo from `0002852a` to valid `0002b52a` (`CommonwealthClear`).
- Time apply now converts `timeHHmm` to Fallout game-hour float before executing `set gamehour`, fixing 2200-style values applying incorrectly.
- Corrected `CO_Vault109StartQuestScript.psc` to compile against Fallout 4 Papyrus by replacing unsupported `Actor.ShowLooksMenu`/`UI.IsMenuOpen` calls with `Game.ShowRaceMenu` and `Utility.IsInMenuMode`.
- Race customization now forces third-person camera and a short pre-menu settle delay before `ShowRaceMenu`, fixing cases where the menu opens but the player model is not visible.
- `CO_Vault109StartQuestScript` now uses configurable `RaceMenuMode` (default `0`) plus `RaceMenuFallbackMode` (default `1`) for `ShowRaceMenu`.
- Race menu open flow now retries with fallback mode if the primary mode does not enter menu mode.
- Moved first-time character customization menu control out of `CO_Vault109StartQuestScript.psc`; the quest now only handles spawn/stage while plugin C++ session-launch flow owns Looks/SPECIAL sequencing.
- First-time C++ character creation now prepares camera context with `ForceThirdPerson`, opens Looks via `ShowLooksMenu 14`, retries with `Actor.ShowLooksMenu` fallback, and times out/reset safely if Looks menu never opens.
- When `LooksMenu` is confirmed open, C++ now applies chargen camera context (`SetInChargen 1` + `ForceThirdPerson`) and restores it on close, fixing first-person camera persistence during customization.
- Looks menu camera correction now directly sets `PlayerCamera` to third-person state for several polls while `LooksMenu` is open, avoiding reliance on console-only camera commands.
- Looks menu camera correction now configures the `ThirdPersonState` for face editing by zeroing shoulder offsets, flipping camera yaw toward the player, enabling free rotation, and applying a closer zoom offset.
- Looks menu camera cleanup now restores the pre-customization third-person offsets, yaw, zoom, and free-rotation flags so movement controls return to normal after first-time customization closes.
### Changed
- Weather presets store the exact `fw` console argument (8-digit hex); edit `server/world_state_presets.py` only if a preset ID fails in your console.
- Updated protocol weather examples/default preset table to match the new valid Fallout 4 preset IDs.
- World time no longer re-applies on every `worldState` heartbeat; weather heartbeats continue at ~1 Hz while time stays in sync during normal gameplay.
- Updated Weather/Time UI and protocol wording to use world-state host terminology instead of hardcoded player-1 wording.
- Reformatted `changelog.md` to follow [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).
- First-time character creation launch now uses `coc COVault109` and waits for the `COVault109` start cell instead of `SanctuaryExt`.
- First-time `COVault109` launch now starts `CO_Vault109StartQuest` once per first-time join flow so the quest can move the player to its preset spawn marker.
- `CO_Vault109StartQuest` now opens `ShowRaceMenu(player, 1)` after stage-10 spawn completion, waits for menu mode to close, then opens `ShowSPECIALMenu` for name/S.P.E.C.I.A.L. setup.
- First-time Looks menu now narrows the camera FOV while open (restored on close) to magnify the face for easier facial-feature editing, since LooksMenu uses its own fixed camera that ignores third-person zoom offsets.
- First-time Looks menu now centers the player on the fixed LooksMenu camera's optical axis for the first few polls (preserving distance and facing the camera), fixing the off-center face caused by the FOV zoom; the player's original transform is restored when the menu closes.
- Added temporary diagnostic logging to LooksMenu centering (camera position/heading, target vs actual player position per poll) to confirm whether `SetPosition` takes effect and whether the menu camera is fixed or follows the player.
- Documented optional apparel equipment sync in protocol and architecture docs.
## [0.0.1] - 2026-06-23
### Added
### Changed
### Removed
- `docs/changelog.md` — moved to project root.