Hello there, I’m glad my presentation in Bali has been helpful! Indeed the presentation didn’t cover simulated proxies so I’ll provide my thoughts on your use case here.
“However in an online game the client shouldn’t I assume move the server character.”
I wouldn’t say you should never, because a responsive reaction from other characters is part of good game feel. There are just challenges with predicting movement effects on other characters. Other players would be most challenging since you’re dealing with their prediction outcome and your own prediction outcome, which differ. As for server controlled characters, it’s less complex but it’s still an advanced topic.
This article is a great primer on how simulated proxies are networked.
Simulated proxies receive movement updates from the server via AActor::ReplicatedMovement. Whenever a client receives the latest position info from the server, AActor::OnRep_ReplicatedMovement() calls into UCharacterMovementComponent::SmoothCorrection() which prepares how the sim proxy will smooth towards the server’s location. It also decides whether to start smoothing at all, or if the error is so large that the mesh will snap towards the server position. Some key info here is that the rendered location of a character is determined by two components:
- The actor’s location, i.e. the CapsuleComponent’s location (since the capsule is the root)
- The skeletal mesh’s offset (relative transform) from the capsule. It also factors in the mesh’s default offset as defined in the character BP.
The capsule’s location always immediately snaps to the server-received location for the capsule. All smoothing takes place via the skeletal mesh’s offset. That will happen over the next few frames via UCharacterMovementComponent::SmoothClientPosition().
When you want to predictively knockback a server controlled character, you have to be mindful that you’re not fighting this process, so:
- Locally modifying the actor’s (capsule) location will cause CMC::SmoothCorrection() to quicker teleport the sim proxy to the server-provided location. Existing solutions like modifying CMC->Velocity, LaunchCharacter etc trigger this.
- Locally moving the character mesh’s relative transform will be stomped by UCharacterMovementComponent::SmoothClientPosition(). That will be applying interpolation from ClientData->OriginalMeshTranslationOffset to 0 and apply that as relative transform to the skel mesh. The original offset value is prepared in SmoothCorrection().
So I have two ideas for you that, similar to in the best practices presentation falls into “simple, not perfect”, or “more control, hard to get perfect”:
- Apply the bump to the NPC on the game client. You can use actor-moving approaches like LaunchCharacter or modifying CMC->Velocity directly. Override CMC::SmoothCorrection() so that that NPC sim proxy will temporarily ignore the latest server position after a bump since you’re taking full control over it temporarily. At some point you accept server corrections again by calling Super::SmoothCorrection(). The challenge is to let that not suddenly cause a big correction from accumulated error. It starts with making sure your client and the server apply the same knockback values. Unlike CMC server moves, sim proxies don’t attempt to tick with the same delta time as the server, so velocity and gravitational forces can accumulate errors from different delta-time on server and client.
- Or, implement the bump as a local skeletal mesh rendering offset. Track some custom FVector Offset value that is driven by the predicted knockback velocity. Override SmoothClientPosition_UpdateVisuals() to modify ClientData->MeshTranslationOffset by adding your custom offset, then call Super::SmoothClientPosition_UpdateVisuals() so that MeshTranslationOffset is applied to the mesh, then restore the MeshTranslationOffset to not have your custom offset. Basically you have another layer of offset that you’re applying locally. Once the NPC is knocked back by the server as well, blend out the strength of your custom offset.
These are the two approaches I would consider to predictively bump NPCs.
“And on a related note; would the mover system perform significantly better in this kind of scenario?”
I’ll ask a colleague to comment on this.