Skip to content

JumpToNode: apply the jump before returning so player state isn't stale#11

Open
Infinitegameworks wants to merge 1 commit into
heavybullets:mainfrom
Infinitegameworks:fix/synchronous-jump-to-node
Open

JumpToNode: apply the jump before returning so player state isn't stale#11
Infinitegameworks wants to merge 1 commit into
heavybullets:mainfrom
Infinitegameworks:fix/synchronous-jump-to-node

Conversation

@Infinitegameworks

Copy link
Copy Markdown

Problem

Calling JumpToNode only sets the state machine's new state — the graph isn't re-evaluated until the next tick. So for a frame or more, the AnimPlayer still reports the previous animation. Anything that reads the player right after jumping (e.g. getting the new animation's length for timing windows) gets stale data and has to work around it by waiting a tick.

Fix

  • JumpToNode now commits the jump before returning: a successful jump runs one zero-delta-time graph pass (update -> evaluate -> play), so the player and render component reflect the new state immediately.
  • CacheAnimation nodes deduped updates by GFrameNumber, which would serve stale cached data on a second traversal in the same frame. They now use a per-instance graph update counter instead.
  • During the jump pass, transition rules are suppressed (so the requested state can't be transitioned away before it renders), notifies are skipped, and overrides are re-published without being ticked — no delta time passes, so nothing advances or completes.
  • JumpToNode calls made from inside a callback (notify, state enter/exit, sequence-changed) are queued and applied when the current pass finishes, instead of mutating the state machine mid-update. A safety cap stops infinite jump->callback->jump cycles.

Notes for reviewers

  • OnPlaybackSequenceChanged now fires inside the JumpToNode call when the jump changes the rendered sequence. Graphs that bind to it after jumping should bind first (or just read the player directly, since it's now current on return).
  • FPaperZDAnimNode_StateMachine::JumpToNode returns bool (found and applied), and the cache node's LastUpdateFrameNumber field was renamed to LastGraphUpdateId — modules compiled against the old headers need a rebuild.
  • A jump on a state machine that isn't in the active graph path still changes its stored state but can't change what's rendered (same as before).

Testing

  • Builds clean on UE 5.8 (editor, game, shipping) via BuildPlugin.
  • Verified in a real project: player state reads correctly on the line after JumpToNode; active notify states are not interrupted by the extra pass; jumps requested from inside notify callbacks defer correctly without recursion.

🤖 Generated with Claude Code

JumpToNode previously only set the state machine state; the graph was
not re-evaluated until the next tick, so reads immediately after a jump
(current sequence, animation length) returned the previous animation.

A successful jump now runs one zero-delta-time graph pass before
returning. During that pass transition rules are suppressed, notifies
are skipped (including the deferred-notify reconcile, so active notify
states are not aborted), and overrides are re-published without being
ticked. CacheAnimation nodes dedupe by a per-instance graph update id
instead of GFrameNumber so a second same-frame traversal is not served
stale cached data. Jumps requested from inside callbacks are queued and
applied when the active pass finishes, with a bounded flush to stop
jump/callback cycles.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant