Add a public comparison of Commonwealth Online and DoxyCoSync, and update the README and changelog to reflect Commonwealth Online’s current multiplayer foundation and dedicated relay-server focus.
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.
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.
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>
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
Introduce resolve-fallout4-path.bat to centralize locating the Fallout 4 installation. deploy-all.bat and deploy-ui.bat now call the resolver (accept an optional path arg or prompt interactively), and the chosen path is saved to a local .fallout4-path file (added to .gitignore). Updated docs (docs/dev-log.md, plugin/setup.md) to reflect the new behavior and usage examples. The resolver normalizes game or Data paths, probes common Steam locations, prompts the user when needed, and exports F4_DIR and DATA_DIR for callers.
Add Ultralight SDK as a git submodule (ThirdParty/Ultralight-SDK, Windows branch) and update build/deploy tooling and docs to use the vendored SDK by default. Updated .gitmodules and added the submodule pointer; build-prismaui.bat and deploy-all.bat now default UL_SDK to the submodule path and build-prismaui.bat checks the submodule is initialized. The PowerShell linker script (scripts/setup-ultralight-link.ps1) now falls back to ThirdParty/Ultralight-SDK when no SdkPath is provided. Documentation and developer log updated (docs/setup.md, plugin/setup.md, docs/dev-log.md) to document submodule initialization and usage; ULTRALIGHT_SDK_PATH can still override the default. Run 'git submodule update --init --recursive' on clones to initialize the SDK.
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.
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.
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.
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.
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.
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.
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.
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.
- 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>
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.
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.
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).
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.
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>
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>