Alright! Thanks to ToyB-Chan on Discord, I understand exactly what’s going on. There are some nuances worth going over, and it’s all thanks to ToyB-Chan rather than my own research.
-
Every actor ticks before their components tick. This is true as long as their tick groups match. Otherwise, the tick group decides which one ticks first. (All actors default to
PrePhysics
, the earliest it can be) -
Blueprints process their latent actions on their tick. Everything else gets processed between
PostPhysics
andPostUpdateWork
.
Hopefully from that alone, you can start to see what’s going on. So by default, when you create a latent action and bind the CallbackTarget
to the ActorComponent, it will be executed between PostPhysics
and PostUpdateWork
. Keeping in mind that a character’s actor’s tick and CMC tick will likely be PrePhysics
, the character and its CMC will update before our ActorComponent’s latent action. That’s what causes the jitter.
In order to achieve the seamless character riding, the latent action needs to be bound to the Actor
NOT the ActorComponent
. This is to ensure our latent action updates before our character and its CMC.
In a blueprint ActorComponent, you are more or less out of luck. You can’t control directly how the latent action is bound in BP.
In a C++ ActorComponent, you can control the binding.
MovementHandle.CallbackTarget = GetOwner();
And as simple as that, it’s seamless! The downside is that you lose a callback to a function in the ActorComponent. However, you can get around this by creating a new timer and running it parallel to your move latent action. See the original post at the top for a code example of a simple timer.