Hey, I am wondering what the usual process is for sending key input from client, to tell the server they want to move "left" for example. Do I send a message each loop of the client that they are holding the key down? Or how is it normally done?
If you didn't realise, I am quite new to networking
Sending Keystroke across network
most games utilize a keystate byte, and use bitflags to set the current key-press state of the player's keystate byte before sending it to the server... so for example:
[source lang="cpp"]
#define KEY_FORWARD 1
#define KEY_BACKWARD 2
#define KEY_LEFTWARD 4
#define KEY_RIGHTWARD 8
#define KEY_JUMP 16
#define KEY_CROUCH 32
#define KEY_ATTACK1 64
#define KEY_ATTACK2 128
unsigned char player_keys = 0;
if(keys['w'])
player_keys |= KEY_FORWARD;
if(keys['s'])
player_keys |= KEY_BACKWARD;
if(keys['a'])
player_keys |= KEY_LEFTWARD;
if(keys['d'])
player_keys |= KEY_RIGHTWARD;
if(keys[' '])
player_keys |= KEY_JUMP;
if(keys[CONTROL])
player_keys |= KEY_CROUCH;
if(mouse[0])
player_keys |= KEY_ATTACK1;
if(mouse[1])
player_keys |= KEY_ATTACK2;
...etc
[/source]
then to actually use this on the server, just check each player's state ANDed with each possible keypress:
if(player[x].keystate & KEY_FORWARD)
{
// do some forward movement code...
}
for more info, read up on using bit flags and bitwise operators..
[source lang="cpp"]
#define KEY_FORWARD 1
#define KEY_BACKWARD 2
#define KEY_LEFTWARD 4
#define KEY_RIGHTWARD 8
#define KEY_JUMP 16
#define KEY_CROUCH 32
#define KEY_ATTACK1 64
#define KEY_ATTACK2 128
unsigned char player_keys = 0;
if(keys['w'])
player_keys |= KEY_FORWARD;
if(keys['s'])
player_keys |= KEY_BACKWARD;
if(keys['a'])
player_keys |= KEY_LEFTWARD;
if(keys['d'])
player_keys |= KEY_RIGHTWARD;
if(keys[' '])
player_keys |= KEY_JUMP;
if(keys[CONTROL])
player_keys |= KEY_CROUCH;
if(mouse[0])
player_keys |= KEY_ATTACK1;
if(mouse[1])
player_keys |= KEY_ATTACK2;
...etc
[/source]
then to actually use this on the server, just check each player's state ANDed with each possible keypress:
if(player[x].keystate & KEY_FORWARD)
{
// do some forward movement code...
}
for more info, read up on using bit flags and bitwise operators..
This is how I do it in my engine. Not sure if this is the best way, but it seems to work.
First of all I don't send keystrokes, I send input variables. Every variable is a float. Variables can be eg. forwardBackwardThrust, leftRightSteering or fireMissile. Yes, even fireMissile is a float. You never know if you want to make it analog later. Boolean values are currently just sent as true = 1.0, false = 0.0f. This also means that the same variables work for any sort of controller, be it the mouse, keyboard, a gamepad or any other device. The client just creates variables out of the currently active input device, and sends them forward.
Continuous input, such as movement controls, are sent as unreliable UDP messages. I send these continually, eg. 10 times per second or so. The packages can be numbered if we want to make sure we receive the packages in the correct order. The server can just drop older packages than it has already processed.
Event input, such as firing a missile, is sent as reliable messages in my engine. This way I only need to send that particular message once. Of course, whether or not this is a smart thing to do depends on how often the events occur. If you fire a missile every second it might not be such a good idea to have the messages be reliable, since it might stall the network.
First of all I don't send keystrokes, I send input variables. Every variable is a float. Variables can be eg. forwardBackwardThrust, leftRightSteering or fireMissile. Yes, even fireMissile is a float. You never know if you want to make it analog later. Boolean values are currently just sent as true = 1.0, false = 0.0f. This also means that the same variables work for any sort of controller, be it the mouse, keyboard, a gamepad or any other device. The client just creates variables out of the currently active input device, and sends them forward.
Continuous input, such as movement controls, are sent as unreliable UDP messages. I send these continually, eg. 10 times per second or so. The packages can be numbered if we want to make sure we receive the packages in the correct order. The server can just drop older packages than it has already processed.
Event input, such as firing a missile, is sent as reliable messages in my engine. This way I only need to send that particular message once. Of course, whether or not this is a smart thing to do depends on how often the events occur. If you fire a missile every second it might not be such a good idea to have the messages be reliable, since it might stall the network.
Games do not send keystrokes to the server. They send movement information. The packet will contain information to say, “I am changing my direction. I was here when I made this change and I my new direction is this way.”
Sending raw keystrokes does not work because of latency—keystrokes alone are not enough to simulate the game world. If packets arrive even just 2 or 3 milliseconds sooner or later, the simulation on the server (and thus on everyone else’s machine) would look entirely different from what you see on your screen. You have to send positional and directional information so the server can verify the integrity of the commands and then to correct its own simulation once verified within a reasonable epsilon. Having the server correct itself is necessary to avoid jitter on your end. If the server is not reasonably satisfied with the position you sent it, it will force your client instead to make the correction which results in jitter on your end. This only happens after severe lag if tuned properly.
Continuous movement does not require a continuous flow of packets. If you strafe left for a long time, the result is only 2 packets. One to start moving in X direction from X position and one to stop the movement and Y position.
Key-state information can be sent but is only used for miscellaneous information. It is never used to actually drive the simulation. It is extra information for the server “just in case”, but should only be sent if absolutely necessary. Otherwise it is easy for a player to spam the server with packets.
L. Spiro
Sending raw keystrokes does not work because of latency—keystrokes alone are not enough to simulate the game world. If packets arrive even just 2 or 3 milliseconds sooner or later, the simulation on the server (and thus on everyone else’s machine) would look entirely different from what you see on your screen. You have to send positional and directional information so the server can verify the integrity of the commands and then to correct its own simulation once verified within a reasonable epsilon. Having the server correct itself is necessary to avoid jitter on your end. If the server is not reasonably satisfied with the position you sent it, it will force your client instead to make the correction which results in jitter on your end. This only happens after severe lag if tuned properly.
Continuous movement does not require a continuous flow of packets. If you strafe left for a long time, the result is only 2 packets. One to start moving in X direction from X position and one to stop the movement and Y position.
Key-state information can be sent but is only used for miscellaneous information. It is never used to actually drive the simulation. It is extra information for the server “just in case”, but should only be sent if absolutely necessary. Otherwise it is easy for a player to spam the server with packets.
L. Spiro
Sending raw keystrokes does not work because of latency—keystrokes alone are not enough to simulate the game world. If packets arrive even just 2 or 3 milliseconds sooner or later, the simulation on the server (and thus on everyone else’s machine) would look entirely different from what you see on your screen. You have to send positional and directional information so the server can verify the integrity of the commands and then to correct its own simulation once verified within a reasonable epsilon.
Why would keystrokes not be enough to simulate the game world? Of course, if the packets do not arrive in time at the server, the result of the server simulation will differ from the result of the local simulation. (This is assuming you time stamp the input messages, and do client side extrapolation). In a case like this, where a packet is lost or late, the client would have to correct his local simulation after receiving a game state update from the server.
There is actually another topic in this forum discussing similar stuff:
http://www.gamedev.net/topic/635009-network-input-handling/
Wow, why would you send Keystrokes in the first place?? Thats a major no no IMO! Latency would kill the movement and the simulation! also, if the player press Up and Left, would you send two keystrokes to the server? why not say that the player moved one in X and one in Y as a message?
Sending the player movement as message is the way it should be done and it would reduce the amount of messages that you would need to send to the server in a long term.
Also, how would the server validate the position of the player? send back a keystroke to the user ? Why not use the same message to send back and forth between the user/server. This way it would all work in a "abstract way" and you could change the message structure and it would keep working.
Also sending movement information would help you long term if you have a slow connection, since you wouldnt need to send the information every single time, but instead would use a delta movement, like I moved by X units in the X axis tell if I am at valid position, then the server would reply, you need to go less 1 unit, since you are colliding with something. Ofcourse this would jagger a bit on the player screen, but it is how most games work nowdays and there are ways to work around this.
Sending the player movement as message is the way it should be done and it would reduce the amount of messages that you would need to send to the server in a long term.
Also, how would the server validate the position of the player? send back a keystroke to the user ? Why not use the same message to send back and forth between the user/server. This way it would all work in a "abstract way" and you could change the message structure and it would keep working.
Also sending movement information would help you long term if you have a slow connection, since you wouldnt need to send the information every single time, but instead would use a delta movement, like I moved by X units in the X axis tell if I am at valid position, then the server would reply, you need to go less 1 unit, since you are colliding with something. Ofcourse this would jagger a bit on the player screen, but it is how most games work nowdays and there are ways to work around this.
Why would keystrokes not be enough to simulate the game world?
Because that would make the server implementation extremely non-trivial (possibly provably impossible). It basically boils down to forcing the server to correct past mispredictions.
Let’s take the easiest example there is to make this easy to visualize.
In an FPS you can swirl your mouse around and fire at any time.
As you swirl there is no way to send a packet every single frame. Your client will be capped to something like 10 packets per second, so the server will never actually see the fluid motion of your swing. Neither will all the clients updated by the server.
But on your screen it will be fluent because that is important for your gameplay. The server allows your client some freedom in order not to give you a jittery jerky experience, but if you step out of epsilon it will correct you.
From here it should already be clear that input packets alone are not enough. If the server accepted packets at a rate of 60 times per second from every single client (because all of them will be moving their mouses at the same time, this would be a real-world scenario) then it would be obvious that the server will have some problems.
Instead it becomes obvious that clients are not allowed to flood the server and must send updates more sparingly. Mouse movements are sent at lower rates and the server sends the data to the rest of the clients who end up interpolating between them.
The server does not handle that interpolation because it does not make sense. The clients will provide the smoothest interaction by performing the interpolation themselves.
If the server did try to keep all clients up-to-date manually it would be a logical fallacy. Every client will have a different idea of what is “now” (even if off by just a few nanoseconds) so there is no possible way for the server to create a simulation that would be “current” to all clients.
So let’s get back to the basics. I swing my mouse around and fire randomly. There is no possible chance that the server understands the direction I was facing on my screen when I fired if all it does is receive the input commands and tries to simulate what I am seeing. If the server’s simulation is wrong by even 1 microsecond this error will be magnified by the distance from my gun. The repercussions across clients is huge.
It is just not stable to run a server simulation this way and it is never ever ever done in practice. It is literally impossible to run a simulation based on inputs from one client, then receive a series of inputs from another client whose time-stamps are older than the first client’s and thus should override the results of the previous simulation, etc. Multiply this by every client you have and you can see how ridiculous it is.
If you are just trying to simulate input commands you are bound to be spammed and then you also have no way to handle slightly inconsistent packet flow.
If you give each client a little leeway (to a degree) and each client sends its current position and new movement data as seen by that client, you can provide smooth movement to each client and a stable simulation fairly easily.
L. Spiro
What about stuff like http://en.wikipedia.org/wiki/GGPO
They run the simulation based on client input. Most RTS games also do it, but without the prediction.
And why would this be impossible to implement? You basically have exactly the same simulation code on the server and the client. I would not roll back on the server if input from one client is late. The client should correct its local simulation and adjust the extrapolation time. To battle jitter in the round trip delay you can buffer the inputs on the server side.
A first person shooter has some special requirements and for instant hit weapons you probably should be able to process input packets with a higher resolution than the simulation frequency. If the game in question actually is a FPS more information can be found here:
https://developer.valvesoftware.com/wiki/Latency_Compensating_Methods_in_Client/Server_In-game_Protocol_Design_and_Optimization
or here:
http://www.ra.is/unlagged/
They run the simulation based on client input. Most RTS games also do it, but without the prediction.
And why would this be impossible to implement? You basically have exactly the same simulation code on the server and the client. I would not roll back on the server if input from one client is late. The client should correct its local simulation and adjust the extrapolation time. To battle jitter in the round trip delay you can buffer the inputs on the server side.
A first person shooter has some special requirements and for instant hit weapons you probably should be able to process input packets with a higher resolution than the simulation frequency. If the game in question actually is a FPS more information can be found here:
https://developer.valvesoftware.com/wiki/Latency_Compensating_Methods_in_Client/Server_In-game_Protocol_Design_and_Optimization
or here:
http://www.ra.is/unlagged/
Player inputs are just information. It doesn't matter (strictly) whether they are actual key strokes, or mapped actions. What matters is how you deal with the latency and keep a level player field (because latency will cause advantages / disadvantages).
But yes, you don't want to send raw inputs. Rather, action mappings, requests, commands, orientation and auto-targets...
But yes, you don't want to send raw inputs. Rather, action mappings, requests, commands, orientation and auto-targets...
What about stuff like http://en.wikipedia.org/wiki/GGPO
They run the simulation based on client input. Most RTS games also do it, but without the prediction.
This link cites a very special use-case which will not be used in following Soulcaliber games.
An input command in an RTS game implicitly includes position data etc. If you click on a spot to tell the monsters where to go, firstly your own client is going to translate that click into a world position anyway because that is what is needed to tell the monsters to go somewhere.
Why would your client send the screen position and have the server also translate that into world coordinates? Especially when such a thing is non-trivial from the server’s perspective.
Your client already has the world position and that is what it sends to the server, yes as an input event.
I think you have misunderstood what data RTS games send to clients. They are input events, but the data associated with those input events is not screen coordinates. Your client always translates those into world coordinates and that is what gets sent to the server.
L. Spiro
This topic is closed to new replies.
Advertisement
Popular Topics
Advertisement