Mover LayeredMoves end one frame in advance

In UMovementModeStateMachine::OnSimulationTick, we check FLayeredMoveBase::IsFinished first to remove expired LayeredMove, then we invoke FLayeredMoveBase::GenerateMove. This will cause LayeredMove skip its GenerateMove at its last frame. For example, in FLayeredMove_LinearVelocity, we sample a curve MagnitudeOverTime, but we can never use TimeValue=1. to sample it, because at that frame FLayeredMove_LinearVelocity will be ended and won’t be invoked GenerateMove.

Would it be more resonable to check FLayeredMoveBase::IsFinished and invoke EndMove after executing FLayeredMoveBase::GenerateMove?

[Attachment Removed]

Looking at this, I believe the handling of time and IsFinished ordering is correct. It appears this may just be a problem of how it’s mapping a movement timestep (from time T0 -> T1) to a discreet sampling of the MagnitudeOverTime curve at time T0.

If we changed it to map [Timestep T0 -> T1] to MagnitudeOverTime at T1, that would ensure you get the final TimeValue clamped to 1.

The downside is you’d never get an initial sample where TimeValue 0 is used. Another alternative might be to use a blend between the magnitudes at times T0 and T1.

Would any of these options be preferable?

[Attachment Removed]

Thanks for your reply. I think CMC RootMotionSource also has this problem. According to FRootMotionSource_ConstantForce::PrepareRootMotion, it use Timestep T0 as TimeValue, while in FRootMotionSource_MoveToForce::PrepareRootMotion it use T1 as current time. So I think this problem is inessential unless we require to reach the goal at the end frame. For our project, we are now uniformly using Timestep T1 as TimeValue.

[Attachment Removed]