Synchronize field battle horse animations - #2300
Conversation
…le-animation-desync
Remote mount packets did not carry rendered playback speed or clear the authoritative no-action state, so stopped puppets could keep walking in place. Replicate and apply the owner gait speed and stopped state while preserving legitimate idle animations.
Cap the staged cavalry at zero speed while held or turning, then restore normal speed for movement orders so combat AI cannot invalidate the animation oracle.
Use Bannerlord action-defined blending when the authoritative client installs a synthetic stationary mount turn. This keeps small facing corrections from snapping the horse pose while preserving the advancing replicated turn phase.
Resolve the movement batching conflict so synthetic mount-turn state and progress still reach remote clients while unchanged movement remains filtered.
The live-test camera hook runs during ordinary mission pre-display ticks. Use reference null checks so mock missions do not initialize Bannerlord's unavailable native object bridge.
garrettluskey
left a comment
There was a problem hiding this comment.
The core fix is sound — zeroing puppet input when the owner is stationary and syncing the gait playback speed is the right call for the walk-in-place desync, and the test coverage is thorough. But there are two correctness holes in the remote synthetic-turn lifecycle and some wire/perf costs on the movement hot path I want addressed before this merges. Details inline.
Also flagging scope: BattleDebugCommands grew by ~645 lines of camera/pose-capture tooling that the PR description doesn't mention. I'm fine keeping the tooling, but it's more than half the production diff of a "bug fix" PR — give it a sentence in the description so the changelog and reviewers aren't surprised.
garrettluskey
left a comment
There was a problem hiding this comment.
Re-reviewed e00cc43..50a37ec. All seven requested changes are in and each got a regression test — verified in code, not just the replies:
- Remote replay now drops turn state once the mount or rider is locally controlled, with an authority-transfer test covering it.
- Resume-during-grace takes the incoming progress; test pins it at 0.1 after a resumed turn.
- Channel 0 goes back through
GetActionNameWithCodeand fails closed — the unknown-index test asserting zeroSetActionChannelcalls is the right trade, since the harness can't resolve names and the positive path was only E2E-testable while the code cheated with raw indices. Matches whatTryResolveActionTransitionalready does. - Field 19 ships as index+1 with the private wire property, and the
DeepCloneround-trip proves the encoding. - Moving mounts skip the skeleton read entirely.
TrySetActionnarrows toNullReferenceException.- The debug tick lives in a self-registering
MissionBehavior; the controller no longer referencesBattleDebugCommands.
Build, unit, and all eight E2E shards are green. CodeFactor is red — glance at it before merging, but I'm not blocking on a linter.
Two take-it-or-leave-it notes inline; neither needs another round.
…le-animation-desync # Conflicts: # source/Missions/Agents/Packets/AgentMountData.cs # source/Missions/Battles/BattleDebugCommands.cs # source/Missions/CoopMissionController.cs
PR Checklist
Please check if your PR fulfills the following requirements:
PR Type
What kind of change does this PR introduce?
What is the current behavior?
Cavalry horses can stop moving at their destination on one client while continuing to play a walking animation on another.
What is the new behavior?
Cavalry horse movement animations now settle consistently on every client when horses stop, and resume at the authoritative playback speed when they move again.
Battle diagnostics can also focus the camera on a synchronized mount and capture its rendered head-pose timeline for desync evidence.
Bot Changelog Entry