Sending Keystroke across network
#1 Members - Reputation: 187
Posted 14 December 2012 - 01:11 PM
If you didn't realise, I am quite new to networking
#2 Members - Reputation: 419
Posted 14 December 2012 - 02:52 PM
[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 128unsigned 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..
#3 Members - Reputation: 359
Posted 14 December 2012 - 03:04 PM
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.
#4 Crossbones+ - Reputation: 5143
Posted 14 December 2012 - 06:12 PM
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
I spent most of my life learning the courage it takes to go out and get what I want. Now that I have it, I am not sure exactly what it is that I want. - L. Spiro 2013
L. Spiro Engine: http://lspiroengine.com
L. Spiro Engine Forums: http://lspiroengine.com/forums
#5 Members - Reputation: 623
Posted 17 December 2012 - 07:22 AM
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/
#6 Members - Reputation: 301
Posted 17 December 2012 - 09:10 AM
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.
Check out my new blog: Morphexe
#7 Crossbones+ - Reputation: 5143
Posted 17 December 2012 - 09:28 AM
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.Why would keystrokes not be enough to simulate the game world?
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
I spent most of my life learning the courage it takes to go out and get what I want. Now that I have it, I am not sure exactly what it is that I want. - L. Spiro 2013
L. Spiro Engine: http://lspiroengine.com
L. Spiro Engine Forums: http://lspiroengine.com/forums
#8 Members - Reputation: 623
Posted 17 December 2012 - 11:35 AM
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/
#9 GDNet+ - Reputation: 1771
Posted 17 December 2012 - 05:06 PM
But yes, you don't want to send raw inputs. Rather, action mappings, requests, commands, orientation and auto-targets...
That's the coolest thing since the mullet!
#10 Crossbones+ - Reputation: 5143
Posted 17 December 2012 - 06:03 PM
This link cites a very special use-case which will not be used in following Soulcaliber games.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.
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
I spent most of my life learning the courage it takes to go out and get what I want. Now that I have it, I am not sure exactly what it is that I want. - L. Spiro 2013
L. Spiro Engine: http://lspiroengine.com
L. Spiro Engine Forums: http://lspiroengine.com/forums
#11 Members - Reputation: 623
Posted 18 December 2012 - 01:59 AM
But the OP was asking about moving a character with the keyboard and not about hit detection in a FPS. My point was, that sending a bitmask of key or action states, for each simulation frame can work perfectly fine. You just have to make sure that the user commands arrive in time most of the time.
#12 Members - Reputation: 187
Posted 19 December 2012 - 03:05 PM
I have posted a related question to this with regards to threading, I wanted it to be separate from this as it may or may not be directly related.
#13 GDNet+ - Reputation: 1771
Posted 20 December 2012 - 11:08 AM
What serialisation does is convert your object properties back and forth into byte streams / bitstreams, or a byte array.
It is similar to writing or reading your data into a binary file, or even a screen console output, if you are more familiar with that.
If you use UDP, then you can wrap a char array with a binary stream handler to convert your objects to and from binary.
Look up boost serialization, if you want to delve deeper.
But really, if you want the short answer, you would do something like this
//--------------------------------
// player definition.
//--------------------------------
struct Player
{
float px;
float py;
float vx;
float vy;
u32 actions;
};
//--------------------------------
// CLIENT
//--------------------------------
Player player;
sendto(socket_handle, &player, sizeof(player), 0, &server_address, sizeof(server_address));
//--------------------------------
// SERVER
//--------------------------------
Player player;
recvfrom(socket_handle, &player, sizeof(player), 0, &client_address, &client_address_len);
Note that I strongly suggest you do not use that method and do proper serialization, or at the very least understand the many problems associated with the code above.
Edited by papalazaru, 20 December 2012 - 11:10 AM.
That's the coolest thing since the mullet!






