Commit Graph
100 Commits
Author SHA1 Message Date
andrew 89c3e82554 Implement proxy weapon animation sync for ranged guns
Milestone 1: Proxy actors now equip remote players' right-hand weapons and play armed idle/locomotion poses when weaponDrawn=true. Adds rightHand weapon slot to equippedItems protocol, weapon graph variable support (iSyncGunDown: 0=drawn, 1=holstered), and weapon FSM events (weaponDraw, readyStateEnter, gunDownStateEnter). Fixes two critical animation state churn bugs: frustum-visibility flicker no longer resets animation state on every update tick, and idle proxies no longer register as changed on every frame. Includes WeaponBehavior graph loading via AIProcess::RequestLoadAnimationsForWeaponChange() and manual weapon attachment fallback. New docs/weapon-animation-sync.md reference guide maps animation events and variables from F4-Animation-Research. Experimental alert-state reassertion for armed proxies to test NPC combat state gating of weapon-ready poses.
2026-07-02 17:23:09 +12:00
andrew a6d4cc2ba6 Use console commands to start MQ102 on Vault exit
Replace direct TESQuest::SetStage usage with console commands to reliably start and advance MQ102 when leaving COVault109. TryStartOutOfTimeQuest now includes RE::Console, issues `startquest MQ102` and `setstage MQ102 10`, and uses a static one-time guard (outOfTimeQuestStartIssued) to avoid repeated issuance. Removed the unreliable currentStage check and adjusted constants/naming and log output. Updated changelog and dev-log to document the implementation and touched compiled script binary.
2026-06-30 22:46:06 +12:00
andrewandCursor 771f855f89 Add automatic quest start for Out of Time (MQ102) on COVault109 exit
When the player leaves COVault109 for the first time, the plugin now automatically
starts the Out of Time quest (MQ102, FormID 0x0001CC2A) and sets it to stage 10,
skipping the vault entry sequence for a smoother multiplayer transition.

The implementation uses TESDataHandler::LookupForm to safely resolve the quest,
includes defensive null checks, and only triggers once by checking the quest
currentStage field. Appropriate logging is added for debugging.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-06-30 22:33:21 +12:00
andrew d328bfb647 Add complexionFormId to appearance payload
Introduce complexionFormId (TXST) into RemoteAppearance and the appearance protocol so complexion textures are captured and serialized. Updates: header/state, Networking JSON parse/serialize, proxy actor comparisons, main capture logic, protocol docs, fake client/player samples, changelog and dev-log. Capture reads PlayerCharacter::complexion and serializes it, but applying to proxies is intentionally a no-op because TESNPC proxies lack a complexion field (documented in comments/dev-log). Files: plugin/include/F4TRemotePlayerState.h, plugin/src/*, protocol/packets.md, server/fake_client.py, server/fake_player.py, changelog.md, docs/dev-log.md.
2026-06-30 22:20:44 +12:00
andrew 76fd8772bd Add appearance tint syncing (appearance v3)
Introduce tint syncing for skin/complection/makeup/beard by adding RemoteAppearanceTint and a tints vector, and bump appearance payload version to 3. Parse/emit tints in networking and update fake server/client test payloads. Capture live Player/NPC tintingData during appearance capture. Apply tints to proxies by updating existing entries or reconstructing missing ones via template resolution and MakeTintEntry (game allocator + vtable fixup); unresolved templates are skipped with throttled warnings. Update docs/changelog and add logging for applied tints. Backwards compatible with v1/v2 packets.
2026-06-30 22:07:49 +12:00
andrew 5b54db64d4 Character Appearance Phase 1 Done
Bump appearance payloads to version 2 and add `morphRegions` and `facialBoneMorphs` capture, serialization, and proxy application. Also fix head-part syncing when sender and proxy counts differ by reallocating the proxy array instead of deferring the whole list, and update the Python harness and protocol docs to match.
2026-06-30 17:37:02 +12:00
andrew 8ff1a90fa5 Revert "Add Pip-Boy state to transform sync"
This reverts commit 4ed671464e.
2026-06-30 16:59:42 +12:00
andrew 683feabb77 Revert "Handle Vault 109 quest handoff"
This reverts commit 6fdc63c36d.
2026-06-30 16:59:34 +12:00
andrew 6fdc63c36d Handle Vault 109 quest handoff
When the local player leaves COVault109, the plugin now completes MQ101 and starts MQ102 at stage 10 on the game thread, with a log entry for confirmation. Updated the changelog and architecture/dev-log docs to reflect the new Vault 109 flow, and refreshed the compiled Creation Kit script artifact.
2026-06-30 16:21:30 +12:00
andrew 4ed671464e Add Pip-Boy state to transform sync
Adds optional `isPipboyOpen` to transform packets, remote player state, proxy animation logging, and fake client/player samples. Updates protocol and architecture docs to describe the new Pip-Boy open/raising/closing state and related movement-state handling.
2026-06-30 16:00:07 +12:00
andrew 4b8f5246c4 Add appearance sync and late-join replay
Adds optional `appearance` snapshots to transform packets, applies supported appearance data to runtime proxies, and has the server replay stored transforms to newly connected clients so late joiners receive current visuals immediately.
2026-06-29 16:46:50 +12:00
andrew ad7f287899 Add optional apparel sync (equippedItems)
Introduce an optional equippedItems transform extension to snapshot tracked visible apparel slots. Plugin: capture local equipped ARMO form IDs on the game-thread, include equippedItems in transform packets, parse equippedItems on the networking thread, and apply/clear synced apparel on runtime proxies (with defensive logging for missing forms). Server: fake_client parses and prints equippedItems. Docs and protocol updated; changelog and dev-log entry added. Backwards-compatible: equippedItems is optional and empty formId denotes intentional unequip.
2026-06-29 16:02:03 +12:00
andrew d0649667f7 Harden runtime proxy adoption
Ignore deleted actors during proxy candidate selection, delete stale saved runtime proxies before spawning fresh ones, and promote proxies based on loaded 3D instead of camera visibility. Updated docs and changelog accordingly.
2026-06-29 15:37:05 +12:00
andrew b505477e08 Add COVault109 solo-cell handling
Implement solo-cell logic to suppress transform packet sends and remote proxy representation while the local player is in COVault109, allowing first-time character creation to remain visually single-player. One entry location update is sent so other clients can hold stale proxies before suppression begins. Added F4TSoloCell.h helper for load-order-independent solo cell recognition by editor ID and cached FormID.
2026-06-29 14:46:11 +12:00
andrew aefeb8b51f Add Papyrus build and staging
Compile active Papyrus scripts during build and deploy flows, stage compiled `.pex` and source `.psc` files into the mod package, and update setup/dev docs plus changelog for the new workflow.
2026-06-28 22:09:00 +12:00
andrew 37d6afbd5a Improve first-time Looks menu face framing
Replace ineffective third-person zoom with FOV narrowing (40°) to magnify the character's face for easier facial-feature editing. Center the player on the fixed LooksMenu camera's optical axis for the first few polls to prevent off-center framing caused by the camera not being perfectly aimed at the player. Capture and restore FOV and player transforms on menu open/close. Add diagnostic logging to track camera position, player position, and menu camera behavior.
2026-06-28 21:31:15 +12:00
andrew 2f37feb5b7 Restore LooksMenu camera state
Capture the pre-LooksMenu third-person camera settings and restore them when character customization closes, so first-time customization returns to the normal over-the-shoulder view and movement controls. Also clear the saved snapshot during reset paths so cleanup still runs if the menu flow exits early.
2026-06-28 18:59:59 +12:00
andrew 22394a77ff Improve Vault109 chargen flow and LooksMenu handling
Move first-time character menu orchestration out of Papyrus and into the C++ session-launch flow. CO_Vault109StartQuestScript.psc now only teleports the player and sets stage 10. F4TSessionLaunch.cpp adds camera preparation/restoration, direct PlayerCamera/ThirdPersonState face-camera tuning, primary console ShowLooksMenu 14 path, Actor.ShowLooksMenu fallback, retry/timeouts and guarded state resets. Added logging and counters for Looks/SPECIAL menu polling. Updated changelog.md and docs/dev-log.md to describe the new flow and testing notes.
2026-06-28 17:39:47 +12:00
andrew b02c183ea9 Add vault door mesh and update Vault 109 mod
Add WorkshopVaultExteriorGearDoor01 mesh asset and update the CommonwealthOnline_Vault109 plugin to reference the new vault door model.
2026-06-27 22:27:58 +12:00
andrew 364531acc5 Update CommonwealthOnline_Vault109.esp 2026-06-27 21:15:32 +12:00
andrew d553e9761c Update CommonwealthOnline_Vault109.esp 2026-06-27 20:32:05 +12:00
andrew 904394999a Start first-time join in COVault109 and trigger quest
Change first-time session launch to use the COVault109 start cell and invoke a start quest so the quest can place the player at its preset spawn. Replaces coc SanctuaryExt with coc COVault109, changes the spawn-detection to match the COVault109 editor ID, adds a g_vault109StartQuestIssued flag and IssueVault109StartQuest() to run `startquest CO_Vault109StartQuest` once, and updates logs and reset logic. Also updates docs (changelog.md, docs/dev-log.md) and includes the updated CommonwealthOnline_Vault109.esp binary.
2026-06-26 17:59:57 +12:00
andrew 8772e024f8 Improve server profile resolution and save handling
Add host normalization and ResolveServerKey to match equivalent endpoints (localhost/127.0.0.1, bracketed IPv6, etc.) so reconnects reuse existing server profiles. Harden profile storage: sanitize save-folder components, use Documents fallback via _dupenv_s when needed, log write/open failures, and fix Windows build issues from unsafe getenv usage. Make session launch resilient to missing or rotated exit saves by accepting Exitsave... names, refreshing to the newest exit save, and falling back to first-time flow from the main menu (instead of hard-failing). Update session launch to prefer resolved profile keys, touch/bind profiles appropriately, and improve related load error handling. Also add a simple Creation Kit quest script (CO_Vault109StartQuestScript) and update changelog/docs to document these changes.
2026-06-26 15:29:16 +12:00
andrew 442cc06020 Update CommonwealthOnline_Vault109.esp 2026-06-25 17:14:54 +12:00
andrew 77751c69f7 Use world-state host for server weather actions
Stop hardcoding player 1 for server-initiated weather/time and instead use the current world-state host. Plugin code now defers weather commands until GetWorldStateHostPlayerId() is available, uses IsWorldStateHost() to gate execution, logs local/host IDs, and requeues when host assignment is missing. Relay logic now attempts ForceHostWorldStateBroadcast and logs if relay fails. Updated protocol docs, dev server UI tooltips, presets comment, changelog, and dev log to reflect world-state host terminology and behavior. This ensures weather/time control survives host reassignment and avoids dropped commands on reconnect/restart.
2026-06-25 10:48:18 +12:00
andrew c4466718a3 Convert HHmm to Fallout game-hour float
Add parsing and application of HHmm time strings as Fallout game-hour floats so GUI time presets apply correctly. Introduce ParseHHmmToGameHour in plugin/src/F4TWorldStateSync.cpp and use it when building the console command (formats as set gamehour to <float> with fallback to the raw HHmm string if parsing fails). Improve logging to indicate when a parsed HHmm was used. Update protocol/server-world-state.md, changelog.md, and docs/dev-log.md to document the behavior and rationale.
2026-06-24 12:34:18 +12:00
andrew 1493e68349 Fix GUI weather: valid IDs, defer & reset
Replace invalid Fallout 4 weather form IDs with valid ones (including fixing Clear from 0002852a -> 0002b52a) and update protocol examples and server presets accordingly. Change the plugin to re-queue/defer server weather payloads when the local assigned player ID is not yet available (so early GUI clicks are not dropped) and add a log entry when deferring. Reset player/host assignment on server startup (_next_player_id = 1 and clear _world_state_host_player_id) to avoid stale host IDs after restarts. Also update changelog and developer log entries describing the fixes and recommended manual testing steps.
2026-06-24 12:26:55 +12:00
andrew 4c17e70620 Add serverWorldState packet and GUI controls
Introduce a server-authoritative world-state packet to control weather and time from the dev server GUI. Adds protocol docs and message type (serverWorldState), a new Weather/Time tab in dev_server_app.py, server-side broadcasting in server_core.py, and preset utilities in server/world_state_presets.py. Plugin changes (F4TNetworking.cpp, F4TWorldStateSync.*) queue and apply incoming serverWorldState on the game thread, run `set gamehour` for all clients, and run `fw <8-digit-id>` on the assigned player 1 then force the host to relay a worldState snapshot. Also includes parsing/validation of hex form IDs, logging improvements, and minimal fake client handling. This ensures consistent server-driven time/weather and documents usage and presets.
2026-06-23 23:03:34 +12:00
andrew 70933db6e5 Event-driven world time sync (timeSync flag)
Introduce an optional timeSync field and event-driven time pushes so host time is only re-applied on connect, resume-from-freeze, or large jumps while weather continues on ~1 Hz heartbeats. Added IsGameTimeFrozen detection and client buffering of latest host time; clients apply host time only when timeSync is true or when gameplay just resumed. Updated networking to read/write timeSync, adjusted F4TWorldStateSync logic (separate time vs weather send/apply paths, changed function signatures and behavior), and updated protocol/docs/changelog and fake_client logging to reflect the new field and behavior.
2026-06-23 15:55:05 +12:00
andrew 87a264da80 Add changelog and update documentation rules
Add a top-level changelog.md and update documentation guidance to require and describe its use. .cursor/rules/documentation-rules.mdc: expanded description and added sections for “Changelog vs Dev Log” and “Changelog Format” with Keep a Changelog guidance and an example. .cursor/rules/project-overview.mdc: reference changelog.md and clarify that docs/dev-log.md is for milestones, testing, and discoveries. changelog.md: new file with an [Unreleased] section and an initial 0.0.1 stub (notes that docs/changelog.md was moved).
2026-06-23 15:35:05 +12:00
andrew d67d39d30c Mark install tests as completed
Update ROADMAP.md to check off four installation/test checklist items: Clean install test, Mod Organizer 2 install test, Second-machine install test, and Steam Deck or LAN client test package.
2026-06-22 22:08:27 +12:00
andrew 22eb923682 Update ROADMAP.md 2026-06-22 22:06:15 +12:00
andrew 1480f0b584 Rewrite ROADMAP.md and add archived initial roadmap
Replace the phase-based ROADMAP.md with a vertical-slice focused "Commonwealth Online Roadmap" that documents current status (Working Internal Vertical Slice) and the new playable slices (Same-Cell Foundation, Multiplayer Menu, Player State/Animation MVP, World-State Sync, Internal Playtest Package, Small Session, Gameplay Experiments, and later items). The previous Phase 0-6 plan is preserved verbatim in docs/ROADMAP_2026_06_Initial.md for archival reference. The change pivots tracking from low-level bootstrap tasks to playable vertical slices and highlights completed internal milestones and remaining tests.
2026-06-22 22:02:35 +12:00
andrew 99595ef87c Add host-authoritative world-state sync
Implement host-authoritative time/weather sync across server and clients. Adds a new worldState packet (and worldStateHost for host assignment) and server-side host tracking/reassignment to the lowest remaining playerId when the host disconnects. Plugin-side changes introduce F4T::WorldStateSync (new header + implementation), polling/apply hooks in the game-thread main loop, and Networking support to send/receive/parse worldState/worldStateHost packets. The server validates host-only sends, relays worldState to peers, broadcasts worldStateHost on host handoff, and augments logging/stats. Protocol and documentation files updated (protocol/world-state.md, docs/*) and server/fake_client.py extended to track/print host world-state snapshots.
2026-06-22 21:50:59 +12:00
andrew 9ceb6601ae Add LAN discovery and Local servers UI
Adds LAN server discovery and a Local tab in the multiplayer UI so clients can find relays on the same LAN. Introduces a new F4T::LanDiscovery module (plugin/include/F4TLanDiscovery.h, plugin/src/F4TLanDiscovery.cpp) that probes LAN hosts via UDP discover (port 7778) and TCP welcome fallback (port 7777). Server-side support includes a UDP responder (server/lan_discovery.py) and integration in server_core.py to start/stop discovery.

Plugin changes (F4TServerBrowserBridge/Data) add background scanning, dispatch results to the game thread, new local-server storage and events (scanLocalServers, localServersUpdated, localScanStarted/localScanFinished), and small join/recent handling updates. UI changes (ui/.../app.js and components) add localServers state, scanning UX, Recent persistence (localStorage), and join logic for local/direct entries. Docs updated (docs/protocol.md, docs/dev-log.md, server/README.md) and build script links iphlpapi. Also removes two unused exported sprite PNGs.
2026-06-22 15:53:17 +12:00
andrew 7efe407421 Add responsive UI scaling for server browser
Introduce resolution-aware UI scaling to keep fonts, glyphs, and panel chrome readable and aligned above 1920×1080. Adds a new components/layout.js that sets --co-ui-scale (baseline 1920×1080) on load/resize and exposes CO_Layout.update; index.html now loads it and app.js triggers updates onBrowserShown and on window resize. styles.css converts many fixed px values to calc()/em driven by --co-ui-scale, removes the old pixel-floor media queries and clamp caps, and scales borders, spacing, and font sizes. controller-glyphs.js multiplies glyph dimensions by the UI scale so controller icons grow correctly. Changes address small/drifting server browser content on high-res and ultrawide displays.
2026-06-18 15:51:42 +12:00
andrew 102acd3340 Add controller icon PNGs and tinting logic
Add per-platform controller PNGs and runtime tinting, hook them into prompts, and update deploy/stage scripts.

- Add many controller PNG assets under ui/Icons and copy them into browser/assets/icons on deploy/stage.
- New controller-glyphs.js: image-based glyph renderer that tints white pixels to the UI color via a canvas pixel pass, caches results, and supports platform selection.
- New controller-icons.js: adapter that forwards rendering to controller-glyphs.
- Update controller-prompts.js to render icon glyphs (and include LB/RB tab-switch prompts) and call hydrate after rendering.
- Call CO_ControllerGlyphs.onThemeApplied from theme.js so glyphs re-tint when theme changes.
- Include new scripts in index.html and add CSS rules for glyph image sizing in styles.css.
- Update docs/dev-log.md describing the change and testing/next steps.

This change replaces previous inline/SVG glyph handling with individual PNG icons and adds deploy-time copying so the repo keeps a single source for controller icons.
2026-06-18 15:41:46 +12:00
andrew 1353e5a52c Gamepad-aware cursor handling in server browser
Add gamepad-aware pointer handling so the server browser hides the mouse cursor when a controller is connected and only shows it after mouse movement/click. Changes include:

- PrismaUI: track browser pointer mode, prefer gamepad detection, suppress native CursorMenu/MenuCursor when in gamepad mode, unfocus the Ultralight view to prevent PrismaUI drawing its cursor, and restore pointer mode on mouse activity. Integrate pointer-mode initialization on browser show and call PollGamepad + UpdateBrowserPointerMode in the permanent task loop.
- MenuInput: expose IsGamepadConnected(), provide PollGamepad() wrapper and simplify Register() logging.
- UI: add window.CO_App.setPointerMode to toggle a co-gamepad-mode class and clear hover state; add CSS to hide the HTML cursor when co-gamepad-mode is active.
- docs: add dev-log entries describing the PrismaUI Ultralight cursor fix and the new gamepad-aware server browser behavior.

These changes ensure consistent cursor behavior between mouse and controller input, prevent the Ultralight cursor from appearing in controller mode, and restore the cursor after mouse interaction.
2026-06-18 14:37:31 +12:00
andrew f720d35d2a Add controller support and safe main menu hooks
Enable gamepad navigation for the PrismaUI server browser and install MainMenu input hooks safely. Poll XInput each game-thread tick and forward button/stick changes to the browser (ForwardButtonEvent / ForwardThumbstickEvent), allocate an input-enable layer to suppress vanilla kMenu events while the browser is open, and register polling via the F4SE task interface. Replace direct vtable writes that caused a loading-screen crash with REL::Relocation::write_vfunc on the MainMenu BSInputEventUser secondary vtable and install OnButton/OnThumbstick hooks once at plugin Install(). Add MainMenu API to suppress inputEventHandling and call it when showing/hiding the browser. Also update PrismaUI browser JS to support controller focus for direct-connect, filter activation/cycling, improved controller prompts, and add CSS for focused direct-connect fields. Files touched include plugin/src/F4TMenuInput.cpp, plugin/src/F4TMainMenuInject.cpp, plugin/include headers, PrismaUI view JS/components, styles, and documentation.
2026-06-18 14:26:33 +12:00
andrew 3d14918ee8 Add staging step and reorganize assets
Add stage-mod.bat and update build scripts to stage the mod package instead of automatically deploying (build-all.bat now calls stage-mod.bat; build.bat prints plugin output path and packaging hint). Reorganize Creation Kit assets into DataFolder and RawAssets directories, add new mesh/texture files, and update CommonwealthOnline_Vault109.esp. Also include ancillary updates to deploy scripts, docs, and server code to reflect the new packaging workflow.
2026-06-17 23:03:30 +12:00
andrew f56b6cf113 Maintain runtime proxy frustum visibility
Add periodic nudging to restore proxy frustum visibility when a proxy is near the local player to prevent proxies from remaining invisible after a frustum cull. Introduce kRuntimeProxyVisibilityNudgeInterval and kRuntimeProxyForceVisibilityRange, track lastObservedProxyVisible on ProxyActorSlot, and add MaintainRuntimeProxyFrustumVisibility and NudgeProxyFrustumVisibilityIfNearLocalPlayer helpers (with throttled logging and animation re-apply when visibility is regained). Switch several readiness checks from ProxyMeshReadyForPresentation to ProxyHasLoaded3D, and stop gating puppet updates on IsVisible so puppets continue to update while the mesh is loaded even if frustum-cleared. Also reset lastObservedProxyVisible when clearing a slot.
2026-06-16 16:44:09 +12:00
andrew cd3679e548 Improve runtime proxy 3D recovery and head refresh
Make proxy 3D/visibility handling more robust to avoid headless A-poses and corrupted movement after PlaceAtMe spawns or 3D reloads. Added helpers to check mesh readiness, queue targeted 3D updates, and refresh head/face nodes; introduce settle/wait timing (2s default, 12s max) and recovery state tracking on proxy slots. Retain proxies for prior exterior cells when appropriate, reset/clear additional slot flags on lifecycle changes, and block puppet updates while proxies are settling. Adjusted animation sync and puppet logic to require visible/loaded meshes before applying motion feedback. Added related includes and expanded logging to aid diagnostics.
2026-06-16 16:36:43 +12:00
andrew 73d44a828b Improve proxy mesh readiness and spawn logic
Introduce ProxyMeshReadyForPresentation to treat partially loaded but visible proxy meshes as ready (avoids headless A-poses). Track lastObservedRemoteCellId on proxy slots and use it to detect remote cell changes so proxies can be restored or snapped when needed. Harden spawn lifecycle handling: reset stale promoted state, add/clear fields (pendingSpawnHandle, spawnAttempted, spawnFailed, lifecycleState, holdReason, visibility flags) and ensure slots are properly reinitialized. Replace ProxyHasLoaded3D checks with the new readiness check in animation sync and movement updates. Also publish an initial transform (including cell/worldspace info) immediately on connect so host/client can resolve same-cell placements without waiting for movement.
2026-06-16 16:08:59 +12:00
andrew 31406a1275 Add hover sync and CO hover component
Add a hover system to restore :hover-like behavior for custom UI elements in the CommonwealthOnline view. Changes include:

- plugin/src/F4TPrismaUI.cpp: add SyncBrowserHover() which reads the native cursor position, converts it to client coordinates, and invokes a JS update on the server browser view; register a periodic task to call SyncBrowserHover every other tick.
- ui/views/CommonwealthOnline/browser/components/hover.js: new component that tracks pointer position, determines hovered targets using a selector list, and applies/removes a .hovered class; exposes bind(), updateFromPoint(), and clear().
- ui/views/CommonwealthOnline/browser/app.js & index.html: include and bind the new hover component during UI initialization.
- ui/views/CommonwealthOnline/browser/styles.css: add .hovered variants and transitions for nav items, buttons, rows, and filter controls to match hover visuals.
- steam_interfaces.txt: add a list of Steam interface version strings (new file).

Purpose: ensure custom buttons/rows that don't receive native :hover updates from the renderer get visible hover feedback by syncing the native cursor into the web UI and toggling a .hovered class.
2026-06-16 15:55:32 +12:00
andrew 7ab3f080f7 Add new Vault and furniture 3D assets
Add several new 3D assets for the creation kit: 109-Entrance-Test.fbx (stored via Git LFS), FurnitureMarkerSit.obj with its FurnitureMarkerSit.mtl (exported with NifSkope), Vault95Exterior.fbx, and VaultGearRoom assets including Vault109Exterior.fbx, Vault109Exterior.nif, and Vault109ExteriorCOL.obj/.mtl (collision mesh and material). These files provide exterior and furniture geometry for the Vault 109 area.
2026-06-16 15:11:06 +12:00
andrew 6ef383a23e Add wall mural OBJ/MTL; update bench NIF & ESP
Add new wall mural assets (creation-kit/assets/WallMurals/VltWallFree01.obj and .mtl). Remove Substance Painter lock for the double-sided bench and update its NIF mesh (CO_VltDoubleSidedBench01.nif). Update creation-kit/esp/CommonwealthOnline_Vault109.esp (binary) to include or reflect these asset changes.
2026-06-14 22:20:21 +12:00
andrew 0f376eb6d3 Add DoubleSidedBench art assets
Add a complete DoubleSidedBench asset set: Blender source files, OBJ/MTL, Fallout 4 NIF and BGSM material files, many textures (DDS/PNG), decals and exports, and painter lock/spp LFS pointers. Remove legacy CO_DoubleSidedBench.fbx and duplicate FBX/spp files. Also reorganize VaultLeather textures into a VaultLeather subfolder and update related .blend and .spp files.
2026-06-13 22:33:20 +12:00
andrew e593060282 changed backslashes in file path to forward slashes 2026-06-12 18:18:58 +12:00
andrew 0980567605 Update CommonwealthOnline_Vault109.esp 2026-06-10 23:09:04 +12:00
andrew 0bf7a1c5ef Add Vault109 ESP; update CommonwealthOnline
Adds a new plugin file creation-kit/esp/CommonwealthOnline_Vault109.esp and updates the existing binary creation-kit/esp/CommonwealthOnline.esp. The change introduces a Vault 109-specific ESP alongside an updated main CommonwealthOnline ESP binary, likely to add or modify in-game records/assets for that location.
2026-06-10 18:29:28 +12:00
andrew 8ff760ed39 Add main menu button injection guide
Add a comprehensive step-by-step guide for injecting a custom main-menu button from an F4SE C++ plugin (docs/MainMenu_Button_Injection_Guide.md). Update existing docs to reference the new guide: add link in docs/MainMenu_Injection.md and expand the setup note in docs/setup.md to point to the full how-to and project-specific notes.
2026-06-09 22:44:18 +12:00
andrew e61922678b Add server validation, profile store, session launch
Introduce server validation and a session launch flow with persistent server profiles.

- Add ConnectAndValidateServer to Networking to validate handshake/timeouts and return human-friendly errors; avoid auto-connecting in transform send path and remove unconditional local connect on startup.
- Add ServerProfileStore (header + implementation) to persist server->saveFile bindings under Documents/My Games/.../CommonwealthOnline/server-profiles.json with thread-safe load/save, lookup, touch and bind operations.
- Add SessionLaunch (header + implementation) to handle launching validated sessions, first-time join flow (auto coc to SanctuaryExt, character creation menus, save binding), F4SE message handling and periodic Update processing.
- Update ServerBrowserBridge to parse/validate ports, use ConnectAndValidateServer, display joinLoading UI events, schedule validated session launch on the game task thread, and centralize join success/failure handling.
- Wire SessionLaunch into main.cpp (update loop and F4SE message hook).
- Improve direct-connect UI in app.js with client-side validation, port parsing, and handling of joinLoading events.

These changes provide better connection validation, user feedback during joins, and automatic handling for first-time server joins with persistence of associated saves.
2026-06-09 16:26:33 +12:00
andrew e6748556ae Update framework-F4-Conversion 2026-06-09 15:19:24 +12:00
andrew fb4e238fcc Add dynamic UI theme for server browser
Introduce runtime-driven UI theming for the server browser

- Expose PushUITheme() in F4TServerBrowserBridge and implement ColorToJson + PushUIThemeInternal to serialize HUD colors and invoke a JS hook.
- Call PushUITheme on UI initialization and when the browser is shown so the webview receives current HUD colors.
- Add frontend handler for "uiTheme" in app.js and a new components/theme.js that implements window.applyCoTheme to set CSS vars and tint the cursor SVG.
- Update styles.css to use RGB component CSS variables (--co-r/--co-g/--co-b and background equivalents) so colors can be overridden at runtime.
- Update index.html to include the new theme script and tweak cursor SVG stroke width; cursor asset updated as well.

This enables the plugin to synchronize the in-game HUD colors with the browser UI dynamically.
2026-06-09 15:19:03 +12:00
andrew 1f80b8ea49 Ensure main menu in MAIN_STATE before multiplayer
Add EnsureMainMenuMainState to try returning the main menu to MAIN_STATE by repeatedly invoking onCancelPress (up to 12 attempts with args true,false). Modify OpenMultiplayerMenu to early-return on null, call the new helper and log a warning if it cannot restore MAIN_STATE before proceeding, and preserve the existing uiMovie handling.
2026-06-09 14:56:38 +12:00
andrew d4d3268b12 Add runtime MainMenu injection and docs
Introduce a C++ runtime injection that adds a Multiplayer row to the Fallout 4 main menu instead of patching MainMenu.swf. Adds F4TMainMenuInject.h/cpp implementing injection, ITEM_PRESS handling, accept/button hooks, resync tasks and logging; integrates installation by calling MainMenuInject::Install() from PrismaUI init. Update PrismaUI to use the new helper and remove a duplicate IsMainMenuOnMainPanel implementation. Documentation updated to deprecate FFDec SWF patching (new docs/MainMenu_Injection.md, note in FFDEC guide, and setup.md) and restore-vanilla-mainmenu.ps1 messaging updated to instruct using the runtime injection.
2026-06-09 14:52:27 +12:00
andrew 1f39c3a929 framework f4 2026-06-09 11:47:33 +12:00
andrew 9c84c9d4bc Add FFDec docs/tools and server-browser fixes
Add comprehensive FFDec walkthrough and short patch docs for safely adding a Multiplayer item to MainMenu.swf, plus helper scripts to extract the vanilla SWF and restore it (tools/extract_ba2.py, tools/restore-vanilla-mainmenu.ps1). Update exported MainMenu.as with a warning comment and remove an outdated exported PATCH markdown. Patch binary Interface/MainMenu.swf (updated).

Hardening fixes in the plugin: include GFx headers, avoid leaving the PrismaUI overlay focused after menu changes, only call OnBrowserHidden when the browser was actually visible, and add IsMainMenuOnMainPanel() so WatchMainMenuState ignores MainMenu when not on the MAIN_STATE. Ensure events are only dispatched when the browser is valid & visible (CanDispatchToBrowser) and make Scaleform UI hide the browser immediately during transitions. These changes prevent the overlay from staying focused during Settings transitions and stop JS events from being sent to a hidden/invalid view.
2026-06-08 22:26:00 +12:00
andrew 50d48f1f99 Add custom cursor assets and deploy step
Add F4MouseCursor.png and F4MouseCursor.svg assets and wire up a CSS variable (--co-cursor) to use the custom cursor in the browser. Update styles.css to apply the cursor variable to body and interactive elements. Modify deploy-all.bat to create %PRISMA_ROOT%\misc and copy the PNG to %PRISMA_ROOT%\misc\cursor.png at deploy time, with a warning if the file is missing. This enables a consistent custom cursor for the PrismaUI_F4 runtime (runtime reads misc\cursor.png) while still providing a browser CSS fallback.
2026-06-08 14:54:58 +12:00
andrew cfd1fab6b2 Revamp CommonwealthOnline browser UI and styles
Rework the CommonwealthOnline browser UI: restructure HTML into a nav + subpanel layout, add SVG/PNG/font assets and new sprites, and overhaul styles with a new font-face and refreshed color/spacing variables. Refactor components: tabs use a left nav list; filters extraction (renderRow) and reset focus handling; direct-connect renders into a dedicated container; server-list switched to compact row layout and adds a scroll indicator; server-details now uses a preview area and simplified preview/stats rendering. Update app logic: adjust focus zone handling (nextFocusZone), limit zones per tab, update connection status/count display, and avoid rendering details for direct-connect. Overall changes improve responsiveness, visual hierarchy, and focus/navigation behavior.
2026-06-08 14:40:00 +12:00
andrew fe620020be Add PrismaUI HTML server browser & integration
Integrate a PrismaUI_F4-based HTML server browser and related tooling. Adds a ThirdParty submodule (framework-F4-Conversion), UI views (CommonwealthOnline browser HTML/JS/CSS), and multiple plugin headers/sources to bridge PrismaUI/Scaleform, handle menu input, and manage server browser data and actions (mock server list, join/connect flow).

Key changes:
- New build/deploy scripts: build-prismaui.bat, build-all.bat, deploy-all.bat, deploy-ui.bat and a PowerShell helper for linking the Ultralight SDK (ULTRALIGHT_SDK_PATH, default F:\\UltralightSDK).
- Plugin additions: F4TPrismaUI, F4TScaleformUI, F4TServerBrowserBridge, F4TServerBrowserData, F4TMenuInput, F4TDebugOverlay and implementations to create/show/hide the HTML view, forward controller input, register Scaleform functions (openManager/closeManager), and push UI events.
- Networking: add ConnectToServer(host,port) and keep ConnectToLocalServer() as wrapper; update connection logs and error handling.
- Main menu SWF/AS updates: updated MainMenu.swf and MainMenu.as to call closeManager() when leaving multiplayer and to integrate open/close hooks.
- Documentation: plugin/setup.md updated with PrismaUI build/deploy instructions.
- Removed Main_ModManager.swf (deleted).

Primary intent: provide an in-game HTML server browser (toggleable with F9 or Scaleform calls), wire up controller input, and add build/deploy workflow for PrismaUI/Ultralight so developers can build and deploy the UI and plugin together. Mock server data is used for now; network join/connect plumbing is provided for local/dev servers.
2026-06-08 14:02:49 +12:00
andrew 2ced73f7b9 Handle runtime proxy 3D unload/recovery
Track and recover runtime proxy actors when their 3D meshes unload and reload. Adds slot flags (proxyObservedLoaded3D, proxyPending3DRecovery, proxy3DResetQueued), MaintainRuntimeProxy3DState and RecoverRuntimeProxyAfter3DReload to defer animation/puppet updates while mesh is missing, queue Reset3D and restore animation/locomotion state once fully loaded. Integrates checks throughout controller logic to skip smoothing/updates for proxies without 3D and updates slot initialization/reset. Also prevents puppet-driven motion/graph speed writes when the actor's 3D is unloaded to avoid corrupted PlaceAtMe proxies, with logging for diagnostics.
2026-06-07 21:31:28 +12:00
andrew 9b133b3109 Add proxy positioning API and CK-placed pool
Add a ProxyGameAPI (F4TProxyGameAPI.h/.cpp) exposing PositionRemoteActor which centralizes positioning logic, play-space resolution, MoveRefrToPosition-style moves, and 20Hz throttling bypass for forced moves. Replace ad-hoc SetPosition/SetHeading calls across the proxy controller to use the new API, ensuring correct cell/worldspace migration, logging, and move-rate throttling.

Introduce support for Creation Kit placed proxy refs: detect CK-placed proxies by editor ID prefix or base form, populate a per-cell proxy pool, and prefer assigning CK-placed proxies for runtime remotes (with fallbacks). Update proxy spawn/holding logic (skip smooth frame once, handle settle states, preserve/reuse CK pool entries) and improve worldspace/cell mismatch checks to avoid incorrect movement across play spaces.

Other changes: add CommonwealthOnline.esp resource file, update setup.md with the new local FormID (0x002666) for COPlayerProxy, enable animation sync gating to require loaded 3D, and small logging/message improvements.
2026-06-07 21:24:07 +12:00
andrew cc4d8aac5a Add Papyrus sync scripts and proxy spawn refactor
Add new Papyrus scripts (CoSync.psc, CoSyncPlayer.psc, CoSyncQuest.psc) providing native bindings and quest/player proxy logic for networking: connection/session APIs, entity management, world/weather/workshop/companion sync, consumable/pipboy/door/power-armor events, and proxy animation/initialization handlers. Refactor the proxy actor controller (F4TProxyActorController.cpp) to support dynamic/runtime proxy spawning and improved lifecycle/visibility handling: change proxy base/form IDs to COPlayerProxy/CommonwealthOnline, add process-list actor lookup, spawn helpers, play-space/cell checks, 3D visibility refresh, ActorHandle usage, and spawn mutexes and globals for safer spawning. Update docs and setup (architecture.md, limitations.md, plugin/setup.md) to describe global dynamic spawn behavior, max runtime proxies (kMaxRuntimeProxyActors = 4), and validation checklist; update launch-two-fallout4.bat to show instance log locations. Misc: small tweaks to logging and debug flags to gate diagnostics.
2026-06-07 20:31:51 +12:00
andrew 21c8bf9593 Smooth remote proxy rotation and conditional snapping
Add interpolation for remote proxy rotation and conditional snapping logic. Introduces kProxyRotationLerpAlpha and a ShouldSnapRemoteMovement declaration, and uses LerpRotation to smoothly apply headings for non-slot proxies (and slot-backed proxies in frame smoothing) unless movement type or large drift forces a snap. Adds a kLargeDriftSnapDistance threshold and threads a computed headingToApply through proxy locomotion/animation calls. Also updates the informational log to mention rotation lerp and removes an unused void cast.
2026-06-07 16:34:21 +12:00
andrew 8dfec0a4b3 Rename project to Commonwealth Online
Replace occurrences of "Fallout 4 Together" with "Commonwealth Online" across docs and testing guidance. Add Interface assets and tooling: MainMenu/Pipboy SWFs, translation/fonts, exported scripts (Interface/exported/scripts/MainMenu.as) and a PATCH_MainMenu_Multiplayer.md describing how to add a Multiplayer menu entry that calls root.f4se.plugins.commonwealthOnline.openManager(). Also add build/run batch scripts and apply assorted updates to README, plugin, server and protocol documentation/source to align with the rename and UI changes.
2026-06-07 16:22:50 +12:00
andrew 4adc7d57ef Add third-party networking dependencies 2026-06-07 15:50:56 +12:00
andrew 4e459b789c TP 2026-06-07 15:50:12 +12:00
andrew 0d00938396 Add x64_vc11 Release .obj files and tlogs
Add prebuilt Visual C++ x64 (vc11) Release object files and associated build tlog metadata under ThirdParty/common and ThirdParty/xse_common. The changes introduce multiple .obj files for common interfaces (IBufferStream, IDataStream, IDebugLog, IDirectoryIterator, IErrors, IEvent, IFileStream, IInterlockedLong, IMutex, IPrefix, ISegmentStream, ISingleton, ITimer, ITypes) and tlog files (CL.*, Lib.*, Cl.items.tlog, common_vc11.lastbuildstate) including an unsuccessfulbuild marker for xse_common. These are generated build artifacts capturing the last build state and compilation records.
2026-06-07 15:48:26 +12:00
andrew c4a7b6dedb Fix proxy stop/land animation linger & snap
Prevent proxies from continuing jog/landing animations after a remote stops and fix snap desyncs. Treat network-authoritative idle (graphSpeed < 0) as definitive and stop falling back to measured lerp speed; pin/snap position when remote is not locomoting and ensure transforms snap on stop receive. Shorten sender-side hold times for movement and jump states to reduce stale motion in packets, and use isMoving (not stale graphSpeed) for landing resume decisions. Changes in plugin sources and main config, plus an updated dev log entry.
2026-06-05 16:12:34 +12:00
andrew 9412fcf8ea Improve proxy jump sync and event handling
Handle remote jump state more robustly and avoid locomotion graph clobbering. Changes: detect jumping early in ActorController and short-circuit to apply jump animation/state; suppress locomotion (Speed/Sprint) while airborne and keep graphSpeed for landing-tier selection; add ApplyJumpStateToGraph helper to set jump vars; only write bulk descriptor fields when not airborne to avoid stomping jump graph; change snapshot writes so in-jump vars are not overwritten by descriptor bulk writes; reorder and refine jump/movement event logic so jump start/up/down/land are handled before locomotion tier events and preserve the pre-jump locomotion tier for landing transitions; ensure graph updates are applied while jumping; set puppet locomotion speed to -1 when jumping or idle so the engine's idle speed remains; and increase the network jump hold duration from 200ms to 400ms. These changes prevent missed/incorrect jump animations and improve landing clip selection.
2026-06-05 15:59:35 +12:00
andrew f4b37b6d12 Improve proxy animation motion handling
Add explicit motion-driven animation sync and strengthen moving logic to reduce desyncs. Initialize puppetGraphSpeed and reset applied animation state for non-moving puppets on restore. Introduce SyncProxyAnimationFromMotion to drive proxy animation from measured per-frame speed (with a 8.0F threshold) and to clear puppet graph speed when the remote isn't locomoting. Replace previous inline motion/graph merge logic in ApplySmoothFrameMovement with this helper. In F4TProxyAnimationSync, make isMoving authoritative (require both isMoving flag and movementSpeed >= idle threshold) and clear movingHoldUntil when the remote is not moving to avoid stale hold states.
2026-06-05 15:52:01 +12:00
andrew a137821406 Improve proxy locomotion, tier & jump sync
Fix multiple proxy animation issues: stale graph Speed collapsing jog into walk, missing slow-walk/jog tiers, and jump takeoff/landing not playing. Key changes:

- Prefer position-derived movementSpeed when animationGraphSpeed is missing/stale (ResolveLocomotionGraphSpeed) and fall back to graph Speed only when it agrees within a tolerance; sender now transmits movementSpeed when local graph read is 0 and TryReadLocalAnimationGraphSpeed falls back to SpeedSmoothed.
- Introduce locomotion tiers (Walk/Jog/Run) with ComputeLocomotionTier and sync ints (iSyncWalkRun/iSyncLocomotionSpeed/iSyncJumpState) to the graph; fire corresponding tier events when starting or changing tier.
- Fix proxy motion application: persist per-proxy velocity and worldDelta so the Update hook does not zero-out controller motion; use measured frame motion to drive animation when network flags are sparse.
- Restore correct jump behavior: fire MT/weapon-compatible jump events for takeoff and landing (JumpUp/JumpStartFrom*/jumpLand/jumpLandTo*), clear bInJumpState on landing and remove the extra proxy-side jump hold so landings exit the jump loop.
- Misc: add constants and thresholds for tier/run/walk/run-land decisions and update logs to include tier labels.

Files updated: plugin/include/F4TProxyAnimationSync.h, plugin/src/F4TProxyAnimationSync.cpp, plugin/src/F4AnimationDescriptor.cpp, plugin/src/F4TProxyPuppet.cpp, plugin/src/F4TProxyActorController.cpp, plugin/src/main.cpp, and docs/dev-log.md.
2026-06-05 15:48:16 +12:00
andrew 6a38e7226c Use authoritative FO4 animation variable names
Replace previously guessed graph variable names/types with the real FO4 humanoid movement behavior names (from MTBehavior.hkx) and update syncing logic accordingly. F4AnimationDescriptor now lists only the variables F4T drives (Speed, SpeedSmoothed, IsSprinting, bInJumpState, iIsInSneak) to avoid clobbering graph state; Direction is intentionally not written. Enable proxy sneak sync using the INT32 iIsInSneak, change SpeedSampled -> SpeedSmoothed, and update all Set/Get calls and diagnostic logging to the new names. Fix jump detection by relying on the actor IsJumping() API (removing the noisy vertical-speed heuristic that produced false positives and caused proxies to remain in jump state). Changes touch descriptor, proxy sync, puppet, main logic, and related docs to explain the rationale and testing notes.
2026-06-05 15:29:31 +12:00
andrew 5ba440ab5d Add crouch state and fix jump sync
Add isCrouching to network, state and animation systems; enable proxy jump syncing with a jump-hold debounce and update animation descriptor and server tooling.

Key changes:
- Networking: F4TNetworking.h/cpp: added a_isCrouching, include "isCrouching" in transform packets and parsing, and logging.
- Remote state: F4TRemotePlayerState.h: added isCrouching field.
- Proxy animation: F4TProxyAnimationSync.*: added crouch fields, enabled jump sync, implemented ApplyJumpHoldState and jump hold timing, wrote crouch/jump bools into descriptors when available, updated event firing and logs.
- Animation descriptor: F4AnimationDescriptor.cpp: added isJumping and isCrouching to bool variable list.
- Local detection: main.cpp: added isCrouching in movement state, stubbed GetCrouchState(), adjusted jump hold timing and included crouch in outgoing transform calls.
- Server/dev tooling: server/dev_server_app.py, fake_client.py, fake_player.py, README.md: added crouch reporting, toggle UI/control and fake client support for crouch, and updated docs/logging.
- Docs: docs/dev-log.md updated with notes on jump/crouch fixes and testing.

Rationale: ensure remote players can report crouch state and make jump animations transition reliably by debouncing jump state on proxies and writing available graph bools; also provide dev-server controls and fake-client support for testing.
2026-06-05 14:22:17 +12:00
andrew 7f1aa11281 Update F4TProxyPuppet.cpp 2026-06-05 13:32:06 +12:00
andrew 65553a0c61 Drive proxy cadence from measured motion
Tie proxy locomotion/cadence to actual per-frame movement and motion-feedback instead of only replaying transmitted Speed.

Changes:
- docs/dev-log.md: add detailed dev log describing measured-cadence fix and cadence/animationSpeed work.
- plugin/include/F4TProxyPuppet.h: added NiPoint3 include and new API: SetProxyLocomotionState, SetProxyDesiredSpeed (legacy alias), and ApplyProxyLocomotionFrame.
- plugin/lib/commonlibf4/include/RE/A/ActorMotionFeedbackOutput.h: new tentative struct for motion-feedback output.
- plugin/lib/commonlibf4/include/RE/Fallout.h: include new ActorMotionFeedbackOutput header.
- plugin/src/F4TProxyActorController.cpp: track per-frame timing/puppet state, compute frame delta, use proxy->Move() with measured frameDelta and call ApplyProxyLocomotionFrame (instead of SetPosition/Lerp-only), and pass measured graph speed/direction to proxy.
- plugin/src/F4TProxyAnimationSync.cpp: use SetProxyLocomotionState to include direction when writing proxy locomotion state.
- plugin/src/F4TProxyPuppet.cpp: introduce ProxyLocomotionState map, sync controller motion fields, compute/push engine motion-feedback (via Compute/Update feedback vtable calls), use UpdateNoAI + manual motion feedback to drive cadence, implement ApplyProxyLocomotionFrame which derives velocity from world delta, clamps/chooses feedback speed (uses measured horizontal speed unless provided graph speed is valid), applies an idle threshold (<8 u/s -> idle), and writes graph speed back to the animation graph.

Why: This makes foot cadence reflect on-screen translation (eliminating mild foot slide/stop-overstay) by measuring applied displacement each frame, updating controller velocity/motion-feedback, and re-asserting animation graph inputs after UpdateNoAI.
2026-06-04 21:39:26 +12:00
andrew abef899505 Add proxy puppet hook and graph speed sync
Introduce a puppet vtable hook to preserve networked locomotion Speed and fix proxy cadence. Added F4TProxyPuppet (header + impl) which installs an Actor::Update hook that writes the desired graph Speed and calls UpdateNoAI for proxy actors so the engine does not recompute/zero Speed from controller velocity. Publish active proxy FormIDs and per-proxy desired speeds so the hook targets only proxy actors.

Wire animationGraphSpeed through networking: parse/send a new "animationGraphSpeed" field and store it on RemotePlayerState. Proxy animation sync now prefers the authoritative animationGraphSpeed when present, otherwise maps movementSpeed ~1:1 to graph Speed (with sprint floor and clamping). Added graph variables speedSampled/speedDamped alongside Speed and updated snapshot population and diagnostics. Removed character-controller velocity injection (was causing physics/animation conflicts) and adjusted proxy movement logic to rely on graph variables plus kinematic SetPosition.

Also: Publish puppet diagnostics from the controller, add sender-side local graph speed read diagnostic, update fake_player to compute and send animationGraphSpeed, and append detailed dev-log entries describing the root cause, diagnostics, and fixes. Build and runtime diagnostics added to verify hook behavior and cadence changes.
2026-06-04 20:18:34 +12:00
andrew 2aab83087f Debounce movement stop for animations/network
Add a short "moving" hold to reduce flicker when movement briefly stops. Introduces a 300ms stop-hold for both proxy animation sync and local player movement sampling: add chrono include and movingHoldUntil to ProxyAppliedAnimationState, a kProxyMovingStopHoldDuration constant, ApplyMovingHoldState and BuildDebouncedDesiredState in F4TProxyAnimationSync, and replace direct desired-state usage with the debounced version. In main.cpp add kMovementStopHoldDuration, ResolveMovementHoldState, refactor BuildPlayerMovementState, add an overloaded GetPlayerMovementState, and separate debug vs network sampling (with separate movingHoldUntil variables) so logging uses per-frame debug state while network sends use the debounced network state. Also gate diagnostic logging behind a flag. These changes aim to stabilize isMoving/isSprinting transitions and avoid rapid toggles between frames and network updates.
2026-06-04 17:34:16 +12:00
andrew feec915f35 Inject controller velocity & send anim events
Add runtime velocity injection to the proxy character controller so the engine has velocity available when evaluating animation graphs (accessed via Actor::currentProcess->middleHigh->charController). Introduce animation graph event constants, TrySendGraphEvent helper, and SendLocomotionTransitionEvents to fire move/sprint/sneak start/stop events on state transitions (with diagnostic logging). Call SendLocomotionTransitionEvents before applying the new graph state so FSM transitions are driven correctly. Respect compile-time flags (kEnableProxyLocomotionSync, kEnableProxySneakSync).
2026-06-03 23:09:42 +12:00
andrew a11c7d4475 Add interpolation system and integrate into proxy
Introduce a waypoint-based interpolation system and integrate it into the proxy actor controller. Added F4T::InterpolationSystem (header + implementation) with TimePoint, InterpolationComponent, Lerp helpers and Update() logic. Integrates per-slot InterpolationComponent into F4TProxyActorController, switches to kinematic SetPosition-based smoothing (per-frame Lerp with snap thresholds) and removes character-controller velocity injection to prevent drift; also clears waypoints on hard snaps and uses steady_clock for timing. Added a descriptor-based bulk animation write (ApplyDesiredStateToGraphDescriptorBased) in ProxyAnimationSync for efficient graph variable updates with failure logging. Also included testing and debugging docs (phase2-interpolation-testing.md and phase2-interpolation-debugging.md) and flipped some debug flags to false.
2026-06-03 22:46:57 +12:00
andrew b128729ebf Stabilize proxy visibility and smooth movement
Fix proxy orbiting and improve motion/visibility handling.

- Capture a per-slot visibleDebugAnchorPosition (reset on reassignment) to keep pre-placed proxies visually stable and avoid orbiting when the local player moves.
- Remove the debug +20Z offset so pre-placed actors remain grounded.
- Add GetRuntimeProxyVisibleTargetPosition to compute a stable visible target (anchored base + scaled remote delta).
- Replace teleport-heavy updates with smooth movement: add InjectProxyMovementVelocity to publish velocity into bhkCharacterController, call Actor::Move() per-frame and inject velocity for animation blending.
- Prefer reusing pre-placed pool proxies before attempting dynamic spawn.
- Implement dynamic spawn via NEW_REFR_DATA / TESDataHandler::CreateReferenceAtLocation, apply debug visibility to spawned actors, and store handles in the dynamic pool.
- Harden debug visibility setup: explicitly enable/disable 3D, alpha, display geometry, set 3D update flags and queue a TaskQueueInterface 3D update; expand debug logging.
- Remove unsafe currentProcess target-clearing code and other minor cleanups.
- Add dev-log entries describing Phase 6 debugging and fixes.
2026-06-03 18:27:06 +12:00
andrewandCursor fb59eea0a2 fix: resolve Phase 6 compilation errors - unblock testing
- Made F4AnimationDescriptor constructor public
- Fixed logging macros by using std::string_view and renaming helpers
- Fixed int32_t/uint32_t type mismatch in animation variable reads/writes
- Disabled actor state flag setting (needs bitfield mapping in Phase 7)
- Disabled dynamic spawn APIs pending CommonLibF4 verification (Phase 7)
- Added move semantics to RemoteActionQueue for ProxyActorSlot

Build status: clean compilation, Phase 6 testing ready with pre-placed proxies

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-06-03 17:18:15 +12:00
andrew 56d9c2c514 Add Phase 6 testing docs and update dev-log
Add comprehensive Phase 6 documentation and testing artifacts: a high-level PHASES-1-6 summary, a Phase 6 quick-start checklist, and a detailed Phase 6 testing & iteration guide. Also append a Phase 6 entry to docs/dev-log.md describing the testing framework, test cases (including the critical velocity→animation test), success criteria, and next steps for in-game validation. These docs prepare the repo for Phase 6 in-game testing and outline debugging, performance benchmarks, and iteration procedures.
2026-06-03 17:09:30 +12:00
andrew 40bc637103 Add RemoteActionQueue and descriptor animation sync
Add a RemoteActionComponent (header + impl) implementing RemoteActionSnapshot and RemoteActionQueue to capture, queue (max 16) and replay discrete remote actions with comprehensive logging. Integrate the action queue into ProxyActorSlot by including the new header and adding an actionQueue member. Replace string-based per-frame animation writes with a descriptor-based bulk sync function (ApplyProxyAnimationFromRemoteStateDescriptorBased) that builds indexed AnimationVariableSnapshot and calls descriptor.LoadAnimationVariablesToCache for a single bulk write (reduces string lookups and improves performance). Update docs/dev-log with Phase 5 summary and details of the action replay and descriptor-based animation sync changes.
2026-06-03 17:05:49 +12:00
andrew e14b91d94e Dynamic proxy spawning, velocity & state sync
Implements Phase 4 dynamic proxy spawning and actor state synchronization. Adds a dynamic proxy pool (g_dynamicProxyPool), SpawnDynamicProxyActor and GetOrSpawnDynamicProxy to spawn/reuse actors via Player::PlaceAtMe, and updates slot resolution to prefer dynamic proxies with a pre-placed pool fallback. Verifies/integrates existing character-controller velocity injection and clamps speed, and applies remote actor state flags to proxies before animation sync. Enhanced logging for spawn, velocity and state transitions. Changes in plugin/src/F4TProxyActorController.cpp and updated dev log (docs/dev-log.md).
2026-06-03 17:01:41 +12:00
andrew a6b2505242 Add animation sync docs and descriptor infra
Add detailed design and implementation scaffolding for TiltedEvolution-style animation synchronization. New documentation: animation-architecture-alignment.md, animation-sync-analysis.md, f4-animation-descriptor.md, phase1-3-completion-report.md and updates to dev-log.md describing Phase 1-3 progress. Plugin: introduce F4AnimationDescriptor (plugin/include/F4AnimationDescriptor.h, plugin/src/F4AnimationDescriptor.cpp) and extend remote state handling (plugin/include/F4TRemotePlayerState.h). Integrate protocol/state extensions and refactor points: plugin/src/F4TNetworking.cpp now parses optional actorStateFlags and actionEvents; proxy controller and animation sync files (F4TProxyActorController.cpp, F4TProxyAnimationSync.cpp) updated to support descriptor-based bulk variable snapshots and actor state replication. Server/tools: update server/dev_server_app.py and server/fake_client.py to handle and display the new optional fields. These changes are additive and backward-compatible and set up phases for action capture, dynamic proxy spawn, and action-replay integration.
2026-06-03 16:52:47 +12:00
andrewandCursor 9d05344e4c fix: actually assign proxies from pool to remote player slots
KEY FIX:
We were discovering pre-placed proxies into a pool, but NEVER
actually USING them when assigning remote players to slots!

CHANGES:
- Modified TryResolveSlotProxy() to grab from proxy pool
- If slot has no proxyHandle, try TryGetProxyFromPool()
- Assign pooled proxy to slot on first resolution
- Log when proxy is assigned from pool

Now the flow is:
1. InitializeProxyPool() discovers pre-placed proxies  ✅
2. Remote player connects, slot is created  ✅
3. TryResolveSlotProxy() called - grabs from pool  ✅ NEW!
4. Proxy assigned to remote player  ✅ NEW!
5. Movement and animations work!  ✅

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-06-03 15:22:50 +12:00
andrewandCursor 7b3a2b51bb feat: initialize proxy pool on first remote player update
Calls InitializeProxyPool() when first remote player is processed.
This discovers all pre-placed proxies in the current cell and logs:
- Number of proxies found
- Max concurrent players supported
- Warning if no proxies found

The proxy pool is now ready for use when assigning proxies to
remote players. Since we only use pre-placed proxies with proper
AI, animations should now work smoothly.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-06-03 15:10:57 +12:00
andrewandCursor 3edce921c0 feat: implement proxy pool architecture using pre-placed proxies
ARCHITECTURE SHIFT:
Instead of dynamically spawning proxies (which lack proper AI),
use a pre-placed proxy pool from the Creation Kit.

BENEFITS:
- ✅ All proxies have full AI, character controllers, and animations
- ✅ Pre-placed = guaranteed proper setup and initialization
- ✅ Simpler architecture (no dynamic spawning complexity)
- ✅ Predictable player limits (# of placed proxies = max players)

IMPLEMENTATION:
- Added InitializeProxyPool() to discover pre-placed proxies in cell
- Added TryGetProxyFromPool() to get available proxies
- Logs number of available proxies and max concurrent players
- Falls back gracefully if no proxies found (warns user)

USAGE:
1. Create proxy actor references in Creation Kit
2. Place them in the game cell
3. Ensure they have AI packages (for animations to work)
4. Plugin finds and manages them automatically

LIMITATIONS:
- Max concurrent players = number of pre-placed proxies
- Users must place proxies in CK (documented requirement)

This is a pragmatic solution for testing and can remain for release.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-06-03 15:10:05 +12:00
andrewandCursor 47a7caac0e fix: disable PlaceAtMe spawning, use pre-placed proxies instead
ROOT CAUSE IDENTIFIED:
User found that pre-placed CK proxy HAS AI while spawned proxies DON'T.
This explains ALL the issues:
- Move() calls don't work without AIProcess
- No animations play (AI drives animation state)
- Movement is jerky (no character controller velocity management)
- AI goes neutral (proxy was never properly alive as NPC)

THE ISSUE:
PlaceAtMe spawned actors don't get proper AIProcess initialization.
They are shells without AI.

THE SOLUTION:
Disable PlaceAtMe spawning (kUsePlaceAtMeBackedRuntimeProxySpawn = false)
Use pre-placed proxy references from the Creation Kit instead.
These have full AI, character controllers, and can run naturally.

EXPECTED RESULT:
- ✅ Proxies have active AI
- ✅ Move() will work properly (AI + character controller)
- ✅ Smooth animations (velocity updates trigger animation graph)
- ✅ Natural NPC behavior (aggro state is maintained)
- ✅ No more jerky movement (continuous character controller)

NEXT:
The plugin will search for pre-placed proxy refs in the cell.
If none exist, needs fallback or user must place proxies in CK.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-06-03 15:04:46 +12:00
andrewandCursor 2449525175 fix: eliminate frequent SetPosition calls that break AI
BREAKTHROUGH INSIGHT:
The user reported: AI goes aggressive then immediately returns to neutral.
This matches the symptom of SetPosition() breaking the character controller.

ROOT CAUSE:
- We were calling SetPosition() every 500ms
- SetPosition() bypasses character controller → kills all movement
- Between SetPosition calls, Move() had to re-establish control
- This constant switching BREAKS the AI's ability to function

THE FIX:
- ONLY use SetPosition() for emergencies (drift > 300 units OR > 2 seconds)
- Always use Move() with small, bounded deltas (max 50 units/frame)
- This lets the character controller and AI run continuously
- AI can now maintain state and play animations properly

CRITICAL CHANGES:
1. Emergency thresholds: 300 unit drift OR 2 second timeout (not 200/500ms)
2. Normal movement: Use Move() with small incremental deltas
3. Never SetPosition during normal gameplay
4. SetPosition only as emergency correction

EXPECTED RESULT:
- ✅ Smooth continuous movement (no more jerky jumps)
- ✅ AI stays active (can get aggro and respond naturally)
- ✅ Proper animations (velocity continuous, not reset every 500ms)
- ✅ Network sync maintained (emergency corrections prevent drift)

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-06-03 14:59:08 +12:00
andrewandCursor e156d048ec fix: call Move() EVERY FRAME for smooth animations
CRITICAL FIX:
The problem wasn't that we needed less SetPosition() - it was that we needed
MORE Move() calls!

ROOT CAUSE:
The AI doesn't automatically call Move(). We have to call it ourselves.
Without frequent Move() calls, there's no velocity updates, no animations.

THE FIX:
- Call Move() EVERY FRAME with the calculated delta (0.016F frame time)
- This updates character controller velocity every frame
- Havok animation graph sees velocity and evaluates animations
- SetPosition() only every 500ms to correct accumulated position error

RESULT:
- Smooth continuous movement (Move() every frame = smooth locomotion)
- Proper animations (velocity updates trigger graph evaluation)
- Network sync (SetPosition() prevents drift)

The key insight: We're not letting AI do it naturally - we're DRIVING the
Move() calls ourselves! The proxy is a puppet, but we can control it properly
by actively updating its velocity via Move() every frame.

Expected behavior:
- Proxy moves smoothly and continuously
- Walking/running animations play
- Position stays synchronized with network data

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-06-03 14:53:53 +12:00
andrewandCursor 90ddcb19d8 feat: implement hybrid movement for AI-driven animations
IMPLEMENTATION BREAKTHROUGH:
- Proxies are real NPCs with active AIProcess
- AIProcess naturally calls Move() each game frame
- Move() updates character controller velocity
- Animation graph evaluates velocity and plays animations
- Solution: Let AI drive movement naturally, not just SetPosition()

CHANGES:
1. Added lastPositionSyncTime to ProxyActorSlot
   - Tracks when position was last overridden for sync

2. Rewrote ApplyRuntimeProxyTransform():
   - New parameter: optional ProxyActorSlot pointer
   - Hybrid logic:
     * Don't override position most of the time
     * AI's natural Move() calls update velocity automatically
     * Animations play because velocity is real
     * Override position only when needed:
       - Snap required (cell change, teleport)
       - Sync timer expired (~300ms)
       - Drift exceeds threshold (>150 units)
   - Falls back to always-sync for fallback proxy (no slot)

3. Updated call sites:
   - MoveSlotProxyToRemotePlayer: passes &a_slot
   - RestoreSlotProxyForRemotePlayer: passes &a_slot
   - MoveProxyToRemotePlayer: uses default nullptr (fallback)

RESULT:
- Proxy uses natural AI movement most of the time
- Animation system sees real velocity updates
- Animations should now play automatically
- Network sync maintained with periodic position override
- Smooth visual movement + proper animations = immersion!

Next: TEST IN GAME to verify animations work
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-06-03 14:49:49 +12:00
andrewandCursor 2ac4b8f07c docs: animation breakthrough - proxies ARE real NPCs with AI
Key discovery: The proxy is a real NPC (has voice lines, can aggro) which means
it has a full active AIProcess. This changes everything!

ROOT CAUSE IDENTIFIED:
- We use SetPosition() which bypasses the character controller
- This prevents Move() from being called
- Without Move(), velocity is never updated
- Animation graph never sees velocity, so no animations

SOLUTION:
- Let the proxy's AIProcess drive Move() calls naturally
- This will update velocity and trigger animations automatically
- Use SetPosition() only occasionally (~200ms) to correct network drift
- Result: Smooth networked movement WITH proper animations

Why this wasn't realized before:
- Previous investigation assumed proxies were 'puppets'
- We now know they're real NPCs with full AI capability
- We were just bypassing the animation pipeline with SetPosition()

Added:
- ApplyRuntimeProxyTransformWithAI() function (hybrid approach template)
- Comprehensive breakthrough notes in dev-log

Next: Implement actual hybrid movement that lets AI drive animations
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-06-03 14:46:09 +12:00
andrewandCursor 89249db2d1 chore: add AI state diagnostics for animation investigation
Added diagnostic functions to inspect proxy actor AI state:
- DiagnosticProxyAIState(): logs AIProcess presence, current package, pathfinding state
- EnableProxyAIAnimationMode(): placeholder for AI animation enablement
- Called on proxy spawn to gather evidence about AI setup

This is part of the AI approach investigation - we need to verify if proxies
already have active AIProcess instances and what packages they have assigned.
If the animation issue is just about calling Move() naturally (which happens
when the AI runs), we can potentially enable this by assigning proper packages
to the proxy and letting the game loop drive movement.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-06-03 14:41:19 +12:00
andrewandCursor b9ea0ac8a7 docs: proxy animation investigation conclusive - animations not feasible
Investigation summary:
- Tested velocity-based animation triggering: graph variable writes, animation
  events, character controller velocity manipulation, and Move() API calls
- All approaches failed: animations do not play on SetPosition-backed proxy actors
- Root cause: Fallout 4's animation system requires active AIProcess-driven
  locomotion packages, which are incompatible with networked puppet actors
- Fallout 4's animation system fundamentally ties animation evaluation to the
  character controller's actual velocity AND active AI-driven locomotion state
- PlaceAtMe proxies updated via SetPosition cannot provide either requirement

Proxy actors currently work correctly for:
- Smooth position synchronization
- Heading/rotation updates
- Jump animations (via Z-position)
- Network sync and lifecycle

What remains impossible without deep engine access:
- Walk/run/sneak animation playback
- Animation graph variable manipulation affecting behavior
- Character controller velocity synthesis for puppets

Recommendation: Accept this architectural limitation and provide alternative
visual feedback (particles, glows, state indicators) instead of animations.

Files changed:
- plugin/src/F4TProxyActorController.cpp: Reverted to SetPosition-only approach
- docs/dev-log.md: Added comprehensive investigation summary and conclusions

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-06-03 14:33:48 +12:00
andrew 3d301a436b Add local animation graph read-only debug
Introduce a game-thread-only, read-only diagnostic helper to probe local player animation graph variables and (optionally) numeric cache IDs. Adds F4TLocalAnimationGraphDebug.h/cpp with UpdateLocalPlayerAnimationGraphDebug(...) and wires a call into plugin/src/main.cpp immediately after GetPlayerMovementState. The helper probes curated variable names via CommonLibF4 read-only APIs, logs availability/changes, and includes a disabled-by-default numeric cache ID scan (kEnableLocalPlayerAnimationGraphCacheIdReadOnlyDebug = false) due to a reported crash during testing. Update also adds extensive dev-log documentation (docs/dev-log.md) describing behavior, testing notes, and rollback instructions. Build succeeded; manual F4SE in-game verification remains pending.
2026-06-03 12:40:26 +12:00
andrew 1aecccefb7 proxy: document visual sneak SetSneaking result 2026-06-03 12:12:42 +12:00
andrew 18379f2b28 Add proxy visual sneak scaffolding
Introduce default-off scaffolding for proxy visual sneak experiments: add kEnableProxyVisualSneakSync and kEnableProxyVisualSneakExperimentalGraph flags (false), include ACTOR_STANCE, and add a non-mutating ApplyProxyVisualSneakIfEnabled helper that reads proxy sneak/stance/forceSneak and emits one-time diagnostics when visual sneak is disabled. Add per-slot tracking fields (hasAppliedVisualSneakingState, hasLoggedVisualSneakDisabled, lastAppliedVisualSneakingState), ResetSlotVisualSneakTracking and calls to reset tracking when holding/reusing/disconnecting slots, and switch UpdateProxyAnimationStateDebug to accept a non-const RE::Actor&. Update docs/dev-log.md with an entry describing the change. Comments/TODOs note a future, separately approved experiment to call RE::Actor::SetSneaking(...) behind a disabled gate; current scaffolding intentionally avoids mutating actors, animation graph writes/events, or AI/package crouch logic. Build tested locally (plugin rebuild).
2026-06-03 11:51:04 +12:00