Advertisement

How to send input data

Started by June 16, 2014 11:22 PM
1 comment, last by hplus0603 10 years, 4 months ago

I know there are many posts on this topic, but none of them answered the problems I have, or I don't have enough knowledge to comprehend them. I have client/server architecture, with server being authoritative. I implemented fixed timestep "physics" (for now its just moving) on both, client and server. I read about clien side prediction and server reconciliation, and I think I understand these concepts. What I don't get is how should input be handled. I read many posts about de-jitter buffers, packing many input samples into single packet and so on. But I never found a straightforward explanation how input plays with simulation.

I use RakNet, so I have quite high level networking lib that does all the magic for me like packing many similar messages into single packet, it has reliable UDP layer if I need it, I can have it ordered, reliable, unreliable etc. so its not a problem.

What I don't get is - when do I actually sample and send input data? Client ticks simulation at some rate, server ticks at another (but I guess its usually the same tick rate, right?). I use events for input so when key forward is pressed on the client, I receive event and set player state to "moving forward" and on next simulation step I move him forward one time (according to the current state). But when should that information be sent to the server? Should I send input state every simulation step? At the beginning? At the end? At different rate? I tried using different rate (like 20 input updates each second) but then client and server are getting out of sync because client logic sometimes does more steps (for example, pressing forward and releasing it quickly allowed for one simulation step on client, but server never received that input, the same for releasing key after some time - server did less steps than client).

If I send input every simulation frame and stick some frame id to it I should be able to have it synced but what if input stops arriving at the server (packet loss or something)? Does the server keep with the information it had on previous tick, or it does nothing? I mean, if player holds "FORWARD" do I move player forward on server until message arrives that says key is no longer held? Or rather other way around - I move player only if the server receives input tick that says to move player forward? First case will move player even if he stopped holding forward for the time until late packets arrive (if they do), second will stop player even if it should be moving (because packets didn't reach the server). What solution is most commonly used and why?

So, to reiterate - I have big problem understanding how simulation ticks on client/server work with client input - most tutorials I read never mention how input is actually sampled and sent to the server, they just mention it is and explain in more detail problems with lag compensation. I'd like to use server reconciliation but I can't until I understand how to mark input, keep it on client and still be able to refer to it when server sends update (that would be tied to some input it received, otherwise I won't be able to confirm it on client-side).


Where are we and when are we and who are we?
How many people in how many places at how many times?

Ok, since I got so many replies dry.png , I think it may be better that I ask some precise questions, maybe this will attact more crowd than my last post that wasn't probably clear on what the issues might be.

Summary: client-server simple (no advanced physics yet) player movement simulation using RakNet that supports UDP in RELIABLE and UNRELIABLE mode, allows ordering and sequencing of packets and so on. Right now server receives input commands that are sampled on client at fixed rate 30Hz, they are sent as soon as they're sampled but may be grouped into packets by RakNet. Server puts each received input command into queue and only consumes one command at its simulation tick (also 30Hz). This means it works as long as rate of messages sent from client is steady, and disallows problems with sudden jumps if I were to receive many commands at once.

Question 1: Should I send "empty" moves, where player does not press any key?

If I send empty moves I have sequential stream of client ticks, so it always goes 1,2,3,4,5,6 and missing tick would let me know that some message got lost. But then, I can use some of RakNet's delivery modes to make delivery reliable - would it be enough? This is where I'm really lost. For now I tried sending only real actions (so instead of 1,2,3,4,5,6 where 1,2,3 and 6 are empty actions, I'd send only 4, 5) and it seems to work when using ordered stream, only drawback I noticed are enormous lagspikes when some packet is greatly delayed (usually with some packet loss). But then, I'm not sure how would I solve it better using some UNRELIABLE mode and working with tick numbers?

Question 2: What mode should I use for sending user input commands to the server?

This is follow-up to previous question, because I'm confused what mode (reliable, unreliable, sequenced, ordered) should be used for sending commands. As I mentioned, when I use ordered reliable it means I get every message in the right order, but sometimes big lagspikes occur and this causes the server to stop simulating such player for a while, then it receives burst of messages. This makes the message queue longer, and makes the gap between client and server simulation bigger. When client stops, server easily catches up because it only consumes messages that are real actions, and client that doesn't move don't send them anyway. But considering client moving in some direction all the time, this gap will be bigger and bigger, to a point where server is behind client local simulation by more than several hundreds ms.

On the other hand, using unreliable fast messages I could probably avoid spikes, but at the cost of gaps between messages, plus I wouldn't know if I really lost a message that contained command, or there was no action taken by the client (assuming the same model I described in previous question, that I don't send empty moves).

Can I even afford to loose input messages or it will break things? Should I make sure that messages are either resend, or that I send some redundant information (I read about sending more than 1 input in message, like 1+N previous inputs in case previous ones are lost).

I hope these questions are better than in my previous post and will get some response - I read every thread I could find on the forums about client input prediction and timestamping and there are many methods and often discussions don't even end with some clear solution. I'd really like to at least start some discussion, I know this topic may be boring already, but somehow there is always something uncertain, no matter how much I read on this topic (probably due to many solutions that exist, different network frameworks used and so on).


Where are we and when are we and who are we?
How many people in how many places at how many times?
Advertisement

Should I send "empty" moves, where player does not press any key?


It depends. It's slightly more efficient to just assume "no command" when you have no command. Another option is to assume "command is the same as last tick" if you hear nothing -- that's generally the most likely outcome.

Separately, if you need to run a consistent simulation, it's useful to know that all clients are keeping up, and pause the simulation if you don't hear from one client. This is very common in smaller-scale, RTS-style games.

What mode should I use for sending user input commands to the server?


Depends on your simulation. Unreliable is generally fine, especially for FPS-type and RPG-type movement, and scales better for large numbers of players. You will need some mechanism that eventually synchronizes players with the server when things are dropped; re-sending baselines on a round-robin basis is one such mechanism.

If you use deterministic simulation, such as a RTS game, then you need to reliably get all commands for tick number X before you run tick number X on the server, and if you don't get all the commands in time, you need to stall all clients until the data arrives.
enum Bool { True, False, FileNotFound };

This topic is closed to new replies.

Advertisement