Catching illegal movement with partial data

Started by
16 comments, last by tufflax 10 years ago

In my game the client sends movement updates each time he changes direction (or speed). It works fine, except for one thing: Recently I changed the game so that the client moves in the direction he is looking, and that can change every client frame, so that's a lot of updates.

But without sending every update, it's harder for the server to check that the client did not move illegally. It's a multiplayer game, and it's important that the clients can't cheat. With only a subset of the updates, I could check that the distance travelled between two updates is not too great, and that he does not in any of the updates stand in an illegal position. But that does not mean that he did not travel through something that he should not have been able to. But I can not just check the straight line, because that was maybe not actually the way that the client went. I suppose I could forget about checking that he did not go through anything, because if he cheats he will probably stand in an illegal position at some point.

Any ideas?

Advertisement

Can you give us a little more information about your game? What genre is it? Is it an FPS or top-down space shooter?

How fast is the player able to turn, i.e. is it possible to turn 360 degrees in a single frame (due to mouse-sensitivity etc)? If so then aim-botting is a possibility and you'll need to implement some sort of accuracy counter which measures how well someone is playing and deciding whether they're just good players or if they're cheating.

Since it's a multiplayer game maybe you could implement some sort of democratic system where the server gathers the information from each client as to what it thinks has happened, discarding the outliers, and then sending out the decided game state to everyone. You could also have game clients report collisions that it has witnessed to the server:

Client A: I saw client B get hit by an asteroid!

Client B: I didn't get hit.

Client C: I also saw client B get hit by an asteroid!

Server: Client B got hit.

This of course depends on the number of people playing at the time; if there's only 2 players, and one (or both!) is cheating then it won't work.

What you should really do is have the server play along and have it do its best at predicting what is happening and sending out its view to all the clients. At low latency this would work well but at a higher latency (170ms+) it'll become increasingly obvious to the player and possibly unplayable for them with 'snap-backs' etc,

It's an MMORPG. Aimbotting is not a problem. The amount turned does not matter. The server is the arbiter always. The movement is similar to that of World of Warcraft, i.e. the player's forward movement is in the direction he is looking. The only problem is that if the client does not send all the information, because it's too much, then the server cannot judge perfectly if the player is cheating or not. So, what's the next best thing?

Depending upon what sort of RPG you're developing, it might be best to send waypoint information rather than direct movement updates. This way, you only need to send updates when the player changes its point of interest. How the client gets from one place to another is less important, so long as the server allows it to do so.

You can (and probably should) send information about more than one time step in a single network datagram.
Use fixed time steps in your physics engine.
Number steps in "steps since time 0" rather than seconds or milliseconds.
Mark each packet with the first time step at which it contains data -- "this packet contains data starting at time step 14020"
Now, each command/input can be executed in order in the server.
If you don't care about deterministic playback, you can omit the time step number in the packet, and just put all the input commands in a queue for the player entity, pulling one set of timestep commands from that queue for each timestep of simulation on the server.
enum Bool { True, False, FileNotFound };

Depending upon what sort of RPG you're developing, it might be best to send waypoint information rather than direct movement updates. This way, you only need to send updates when the player changes its point of interest. How the client gets from one place to another is less important, so long as the server allows it to do so.

The player does not click to move, so that would not work.

You can (and probably should) send information about more than one time step in a single network datagram.
Use fixed time steps in your physics engine.
Number steps in "steps since time 0" rather than seconds or milliseconds.
Mark each packet with the first time step at which it contains data -- "this packet contains data starting at time step 14020"
Now, each command/input can be executed in order in the server.
If you don't care about deterministic playback, you can omit the time step number in the packet, and just put all the input commands in a queue for the player entity, pulling one set of timestep commands from that queue for each timestep of simulation on the server.

I'm using TCP for now. But I have not tested it, so I don't know if I'll change it later.

Anyway. The server runs at 10 FPS. But the client can run at 100+ FPS, or whatever really. And, if that was not clear, the player moves instantly on his own client to make the game feel more responsive, but the server checks the movement later. If I would somehow limit the FPS when it comes to movement, it would not feel as smooth as it could, so I don't like the idea of using fixed time steps. I don't use a physics engine, and don't quite know what would qualify as one. But even if I used fixed time steps, they would probably have to be shorter than 0.1 s (the steps the server use). And besides checking for cheating, more than 10 movement messages per second is unnecessary.

Right now I think that just limiting the messages sent from the client, and on the server just checking that the client does not move too fast, and that he does not stand in an illegal position at any update, is the best solution so far. He could cheat by walking through a wall, for example, but it seems unlikely that, if he does not move too fast (which is checked for) he will not at any update/message stand in the wall.

What you have isn't really server-authoritative, therefore not secure. You need to send all the inputs of the clients to the server, as well as the client's predicted position every now and then, so the server can correct the client if needed. If you send partial inputs, you leave yourself opened to exploits. If you send all the inputs, then you know exactly what the client tried to do, where it landed, and if you need to send a correction. Then the client can 'rewind' his input stack, and correct himself.

https://developer.valvesoftware.com/wiki/Source_Multiplayer_Networking#Input_prediction

Client->server bandwidth is at a premium but luckily, if the client only has to send inputs, commands, and sometimes positions, that bandwidth usage is actually very low, even at 100hz. Do the maths, see how much data that actually is. e.g. 100 fps x 100 byte / input = 10kbytes / sec = 80 kbits / sec (plus TCP packet overheads). Secondly, since you will send your inputs reliably, you can use compression techniques to further reduce that bandwidth.

And since you use TCP, if you start sending too much too fast, the TCP frame will drop (i.e. the send() command will not complete, or will block). But in any case, short of a network issue, you should be easily be within the bandwidth limitations of home broadband. What you can do in case your TCP stream starts breaking up, is pause the game on the client side, to let the stream recover enough.

Everything is better with Metal.

The server runs at 10 FPS. But the client can run at 100+ FPS, or whatever really.


Rendering frame rate and simulation frame rate doesn't need to be the same (and often isn't.) Best practice for action-like games is to fix a simulation tick rate, and run that rate on both client and server.
There are many other ways of creating a fun networked game, some of which have different trade-offs in consistency, latency, cheat resistance, ease of implementation, etc.
enum Bool { True, False, FileNotFound };

I am by no means an expert, but if you want some checks without a fully authoritative server I'd suggest something like:

  • Check that the items and effects that they claim to have are possible, which should be server authoritative. For example they exist, are not owned by others, haven't expired or been destroyed, aren't on cooldown.
  • Calculate the max distance they could travel since last state with the current items and effects.
  • See if their new position is within that max distance. This could be as the crow flies, or a coarse graph-based check.

Having said that, no heuristic beats an authoritative server, so it really depends how big a problem cheating is likely to be for your style of game. The other point is that you don't need to catch every cheat, only game-breaking ones or a high enough percentage of cheats that a cheater will be caught and punished within a reasonable timeframe.

The server runs at 10 FPS. But the client can run at 100+ FPS, or whatever really.


Rendering frame rate and simulation frame rate doesn't need to be the same (and often isn't.) Best practice for action-like games is to fix a simulation tick rate, and run that rate on both client and server.
There are many other ways of creating a fun networked game, some of which have different trade-offs in consistency, latency, cheat resistance, ease of implementation, etc.

What would I include in those simulation frames, and what would be updated every rendering frame? And also, if I could not actually change my position faster than the simulation ticks, what would be the point of updating the rendering?

What you have isn't really server-authoritative, therefore not secure. You need to send all the inputs of the clients to the server, as well as the client's predicted position every now and then, so the server can correct the client if needed. If you send partial inputs, you leave yourself opened to exploits. If you send all the inputs, then you know exactly what the client tried to do, where it landed, and if you need to send a correction. Then the client can 'rewind' his input stack, and correct himself.

https://developer.valvesoftware.com/wiki/Source_Multiplayer_Networking#Input_prediction

Client->server bandwidth is at a premium but luckily, if the client only has to send inputs, commands, and sometimes positions, that bandwidth usage is actually very low, even at 100hz. Do the maths, see how much data that actually is. e.g. 100 fps x 100 byte / input = 10kbytes / sec = 80 kbits / sec (plus TCP packet overheads). Secondly, since you will send your inputs reliably, you can use compression techniques to further reduce that bandwidth.

And since you use TCP, if you start sending too much too fast, the TCP frame will drop (i.e. the send() command will not complete, or will block). But in any case, short of a network issue, you should be easily be within the bandwidth limitations of home broadband. What you can do in case your TCP stream starts breaking up, is pause the game on the client side, to let the stream recover enough.

If I'm gonna send stuff every frame, I might as well just send the position and direction, because as long as the server checks for speed and collisions, it's fine. No? And it's easier for the server to do that.

This topic is closed to new replies.

Advertisement