Client prediction & reconciliation theory for physics based movement

I’m using my own physics-enabled “character” pawn class which uses AddForce to move instead of UCharacterMovementComponent, thus I don’t get any of the fancy features that CharacterMovementComponent has to offer, such as client prediction.

I want to implement client prediction as the game is quite action-based, but even though I feel I understand the theory of how it works, the implementation of INetworkPredictionInterface with UCharacterMovementComponent seems very complex and unclear to me.

I decided I could just implement my own simple prediction, but I’m not sure what the best way is to reconcile the client’s current predicted state with the last agreed state received from the server.

The way to do it is apparently to revert back to the last agreed state when received from the server, and reapply all input that occured since the client was in that state.

Reapplying the input seems to be the challenge here.
What I currently do for input is call AddForce every frame depending on player input, but I have no idea how to simulate the addition of force for a period of time.

The client would have to store a state for every frame, being the velocity change (or acceleration) from before to after the addForce (I’m not sure if this works!), and also the delta time.

To reapply input, the client would have to iterate through all the frame states since the last agreed state, applying the change in velocity and then translating the character it’s velocity * deltaTime for each stored frame state.

I’m not sure if this would work at all (particularly measuring a velocity change from addForce) or if this would have any weird collision interactions since the character is being translated, potentially into other objects.

It’s a pretty complex/specific situation, but any tips for this? D:

I’m about to head down this rabbit hole as well. I’m wondering if it’s possible to modify the way the client side prediction works. The traditional approach (as you’ve outlined) is to remember the input history on the client, and when the server sends through a position/rotation for some time in the past, you reposition the client there and then reapply the client input history to figure out the new current position + rotation. I’m wondering if it’s possible to replace the client input history with a position/rotation delta history instead, so when a server position/rotation arrives, you move the client there, then reapply the delta position/rotation history for the client to get the new current position + rotation.

I’ve actually been thinking about this again recently (never solved it back in June) so I was interested to get your comment just now.

I was toying with the idea of using that delta method a while ago instead of rewind/replay. I wasn’t sure how robust it is as it was just an idea I had myself rather than the classic rewind/replay which I had read about everywhere, and I didn’t really give it much of a try.

I’m thinking it would probably work well given low enough latency though.

These were my notes from back when I first had the idea:

Store position and
timestamp of each frame. When LAS
(last agreed state) is received,
offset the current position by the
difference between the locally stored
location from the time of the LAS and
the received location. Snap to LAS
velocity. This is likely much easier
than the above solution, but I thought
it up myself instead of reading it
somewhere, so it might have some kind
of design flaw, though it’s difficult
to imagine. It’s almost too simple…

Just checking in again. I tried my method of making the client-side history store physics deltas (position + rotation changes) instead of moves (raw input). It worked okay-ish at really low latencies (under 200ms) but anything above that revealed a major problem with the design: using client-side physics deltas to recreate the current client physics state from a previous physics state causes a feedback loop over time, since we’re also messing with the client-side position each frame to move it closer to the predicted current position, and that affects the next frame’s adjustment, and so on, until you get this horrible spring-like thrashing that’s proportional to the amount of lag. Seems obvious now I’ve tried it!

The approach I’m going for now is a lot simpler, namely making each player fully authoritative over their vehicle’s position on their own machine, which is pushed to the server and then propagated out to other clients. This means all the latency + lag is seen on other players’ vehicles instead of their own vehicle being corrected, which is awesome as the vehicles handle perfectly for everyone regardless of lag, but it does open the game up to cheating since any player could use a hacked client to do “bad things”. Fortunately we can use UE4’s server RPC validation to prevent obvious hacks (eg. sudden large unreasonable movements).

I’ve spent a lot of time over the last few weeks reading about client-side prediction and I think this is the only reasonable way to handle inertia-based movement for fast-moving objects like vehicles. I’d love to see some technical articles for other games that do this, but I haven’t found any online.

Have you made any headway on this? I am trying to implement the same thing. Thanks in advance.

Yeah the final solution was the method I described above, where each net client is authoritative over all its local players’ positions. We’ve been road-testing it now for over 6 months and it seems stable and handles lag better than any other solution I’ve seen. The obvious compromise is the potential for cheaters to mess with the game, which we can only prevent to a limited extent. But I think that’s a worthwhile compromise. (Ask me again after we’ve released, haha!)

Micheal, I understand the UE4 Character class is network enabled, in my multiplayer mini game which Is LAN, the APawn class is not network enabled.
Your solution intrigues me, you handle all the physics and movement on the client, and the send the clients position to the server, which then replicates it to all clients, right ?

This is probably the kind of thing you want to ask on the forums to be honest to get a discussion going, but I will link you to a couple of posts that I’ve made regarding this. I had a very long and tiresome attempt at making server-authoritative network physics in Unreal, but it’s an uphill struggle.

Long story short this is very, very difficult in UE4. Largely because syncing time-stamps for move history is nigh-on-impossible without having a fixed timestep (not necessarily fix frame-rate). You also need to separate your collision from your visual mesh, since you have no control over the render position of the object and you need to do that for smoothing.

Here’s a few posts I wrote on the matter. Rama interestingly enough has made posts suggesting he has pulled it off but I haven’t seen any source yet (we may never), so you may be able to ask him. As I said in the thread though, making a one-size-fits-all network physics component is not really an easy thing to do.

TheJamsh, if the ACharacter class is network enabled, then why isn’t APawn network enabled with forces, sorry it’s something for the engine developers, but your work shows that you know the engine better than me.