Skip to main content
gamedev.net
🔒 Locked

Client Side Prediction

Started by chinchi11a Sep 3, 2011 at 4:46 PM 4 replies 3.1k views
Original Post
chinchi11a
chinchi11a
I've been reading up on client-side prediction for player movement (see Unreal's Networking Architecture, or Half-Life's -- I believe it's from Duke Nukem 3D / QuakeWorld originally).

The idea is great and I get the general idea, but:

How are they apparently applying player movements "in the past?" When the client receives an acknowledged ( / corrected) movement from the server, along with a timestamp, it's supposed to then toss out any saved movements since before that timestamp and re-apply, from that server-given corrected movement, all player inputs that happened afterwards up to the present.
The thing is, how can you apply a movement in the past? The player object can't just determine its position from the inputs alone, because other objects could be moving / colliding with it. So, say a flying rock were to have hit my player in-between the server-acknowledged movement that was sent, and the present... simply applying the player movements would ignore the rock's collision. I'd have to somehow re-do each game "tick" (frame / update) that happened since the server-acknowledged movement's timestamp??

Also, just to check, a "movement" is just an applied acceleration vector, yes?
hplus0603
hplus0603

The thing is, how can you apply a movement in the past? The player object can't just determine its position from the inputs alone, because other objects could be moving / colliding with it.


This is one reason why you don't see a lot of highly interactive physics objects in most FPS games!
If you support collisions, you have to save the state of all objects in the simulation for a number of time steps. This quickly becomes a large amount of RAM if you have lots of objects. In general, you'll also want the server to "lag behind" by whatever the slowest client is, and not "commit" to state until it has input from all clients.


The way this works is something like:

At my step X, I shoot a picture of you on my screen that is at step (X-RTT), which was active on the server at my step (X-RTT/2).

Now, at my step (X+RTT/2), the server will get the message "at step X, I shot at you at step X-RTT."

You will note that all the information the server has is in the past at that point -- the server can have committed up to X (measured in my steps, which are a fixed offset from server steps, so they are "the same thing.")

At that point, you need the position of the player at time X, and of all the other objects at time (X-RTT), and then you run the shot simulation as a raycast through that physics scene. If I hit, that message will actually get to you at time X+RTT -- two RTT after the event happened! Hence, why you think you dodged into cover, but actually got shot right before.

Note that there is no re-simulation necessary, just putting objects back at their snapshot positions for the time steps involved.
enum Bool { True, False, FileNotFound };
chinchi11a
chinchi11a
Thanks for the quick response!

I think the last statement is causing me some confusion:

Note that there is no re-simulation necessary, just putting objects back at their snapshot positions for the time steps involved.

I'm not seeing how I can get back to the client's present timestep without re-simulating after the adjusted position comes from the server. Using the example, if I find out I got hit by a gunshot that I had thought to be dodged, doesn't that potentially have a cascading effect on the simulation between the impact of the gunshot and my "present", that would need to be re-simulated?

But after learning some of the limitations on resources that you mentioned, perhaps there's a more important question: I'm creating a 2D isometric multiplayer game at the moment. There may be several moving, colliding objects spawned by players. I think a good analogy of the type of networked gameplay would be a multiplayer Diablo 2 game. Is client-side prediction what I want?

I had wanted to make the multiplayer react as optimally as possible, but am I over-engineering for this gametype? Perhaps client-side prediction is only really necessary where the majority of player actions are "instant." Then again, I'd hate to limit myself to "slow" abilities / gameplay. I suppose I don't have a great perspective on what's playable, what's noticeable, etc. Also, even if it's okay for there to be a small blip before an ability comes out, movement feels lagged if it's not totally instant..

I'd really love to read up on Diablo 2's networking architecture and use that as my starting point, but I haven't found anything yet. One thing I'm wondering though, is if the RTS-like movement controls in Diablo make its latency less noticeable. My game will be using WASD, and it seems very annoying if that doesn't respond immediately.
hplus0603
hplus0603

[quote name='hplus0603' timestamp='1315071943' post='4857214']
Note that there is no re-simulation necessary, just putting objects back at their snapshot positions for the time steps involved.

I'm not seeing how I can get back to the client's present timestep without re-simulating after the adjusted position comes from the server. Using the example, if I find out I got hit by a gunshot that I had thought to be dodged, doesn't that potentially have a cascading effect on the simulation between the impact of the gunshot and my "present", that would need to be re-simulated?
[/quote]

On the client, yes -- I was thinking server. However, you *could* make it so that simulation only is affected from the time step when you're told. This would work something like:

1) When you take the first hit, nothing changes, so it doesn't matter (just blood stains in the graphics)
2) When you take the second hit, you run slower. Server-side, this could be implemented as "you start running slower 400 ms after getting hit" to give time for the message to go back to clients.
3) When you take the third hit, you die. You can solve this either by snapping the player back and doing ragdoll, or by collapsing the player wherever it happens to be, so it looks OK on the local system, but is not fully globally consistent.


But after learning some of the limitations on resources that you mentioned, perhaps there's a more important question: I'm creating a 2D isometric multiplayer game at the moment. There may be several moving, colliding objects spawned by players. I think a good analogy of the type of networked gameplay would be a multiplayer Diablo 2 game. Is client-side prediction what I want?
[/quote]

When it comes to client-vs-client collisions, you have a fundamental trade-off: Latency, or consistency. You can choose to impose a round-trip latency for each command, and be 100% consistent. If lag is long, this will be annoying. Or you can choose to predict ahead on the client, at the risk of running into client/server inconsistencies, which have to be detected and corrected, which will lead to a really poor experience (much worse than lag) when it happens. Compare Counter-Strike: when you run right alongside another teammate, you will keep snapping back and running slower because of this.


I'd really love to read up on Diablo 2's networking architecture and use that as my starting point, but I haven't found anything yet. One thing I'm wondering though, is if the RTS-like movement controls in Diablo make its latency less noticeable. My game will be using WASD, and it seems very annoying if that doesn't respond immediately.
[/quote]

WASD is certainly more directly interactive than click-to-move. These decisions are not independent from each other.
enum Bool { True, False, FileNotFound };
Infernal0010
Infernal0010
I for one do not like lag compensation with bullet hits. The most prolific FPS multiplayer game was quake3 and it never used that mode. The impact of moving objects in multiplayer is easily seen in even quake3 whenever you step onto a moving or spinning platform. I jitters like mad. This is a potential problem if you have alot of these items bouncing around. If they have to hit a player it can be troublesome for the local client. If you want your player to move fluently and respond immediately to your command, you WILL have to predict the movement. Even 100ms round trip feels extremely lagged when your character responds to your mvement keys (WASD) a tenth of a second later. One thing to note is that there are two streams, not piecemeeal interactions.. while the server's message about what last acknowledged movement/timestamp pair is in transit to you, it is already executing new commands sent in your upstream. Will that guarantee impacts with the moving objects in the scene? Depends on the latency. Quake3 has an inherent render delay where it only begins rendering when it has two snapshots complete from the server to interpolate items between. It also has the event list which dispatches events int your game based on the gametime. basically, what you see on your screen for that object moving around is what the server sent to you at he same time as your last acknowledged command ( you can interpolate it further if you want, but that's not necessary as it is currently time synched with everything else in the snapshot).

In high lag, the system breaks down, but you also have to realize that for at least up to 250ms ping (125 each way) the gap in time is a tenth of a second. from the state on the server to the state you see.

I don't think there is any optimal system possible until we all have entangled electrons shared with the server. Or everything goes pure Fiber.
chinchi11a
chinchi11a
Thanks for all the help! After considering it both ways, I think I'm going to change my movement method to point-and-click, and use the deterministic model with a bit of latency. Maybe I'll add a little startup effect when you change directions, too, to hide it a bit. Movement isn't as twitchy and central in my game as an FPS, whereas not finding out that there's a fireball hurtling towards you for the first few yards could be really game-crushing.

I have to say, it's been really interesting reading about this stuff on the forums here. I wasn't aware that there were such prevalent pros and cons to every networking architecture - even in games I've been playing, and that it's tied so closely with the game design choices. I'm used to programming all my problems away, but I suppose there's RTT and it just has to be dealt with in one way or another.

Topic Locked

This topic has been locked by a moderator. New replies are not allowed.

Sign in to reply to this topic.