Advertisement

Trusting The Client

Started by July 21, 2016 12:52 AM
10 comments, last by Kylotan 8 years, 4 months ago

Hey folks, since my last post here has received great help (specifically by @hplus) -- I figured I'd keep on asking more questions. Warning, this includes a lot of babble, bear with me.

Let me explain my current mindset and thoughts so far:

  1. I don't have a physics loop on the server. When players skills are used, the only thing I am validating server-side is whether or not the player is in range.
  2. I am sending around 20 PPS when a player is moving. The only validation here on the server is to check the difference between the players last and new position. And if that value is higher than XXX, they are speed hacking / changing their intended X, Y values. This way, no physics server loop is needed and the client can handle all collisions.
  3. After that validation, the server basically relays the players positioning packets to everyone in a game. Then, I use a lerping method to smooth out the movement. And 20 messages per seconds seems like the minimum needed for smoothness. I could lower this, and use tweens, but ew.

What I'm trying to get at, is.. I am relying on the client for a lot of things. Say for example, since physics are not on the server, if a player shoots a fireball and when it reaches a target. this packet is sent to the server. I then check if that player is in range of that monster, and if the skill is NOT on cooldown, it goes through. This would be enough to prevent speed hackers that attack at 1000 times a second, but not enough for pixel perfect collision (physics) on the server. So, a player could just send that packet (opening up Chrome Dev Tools) while they are two screen widths away from the monster and it won't validate on the server because that monster's not in range. The player could also send the packet before the fireball's animation is done and it would be validated as the server has no sense of physics. Is that acceptable / okay?

Basically, I'm a nervous wreck and just need some confirmation (or criticism) about my thought process of this.

What I am worried about is the 20 PPS the client is sending to the server (when they are moving). Is this even something that other games do? I mean, I know you're supposed to just send the "Player is moving right key" instead of having a TCP stream of data being send from the client.. but man, doing this helps so much! Collision is done for you, no physics loop on the server, lag compensation is so easy to deal with, fixed timestep isn't needed (although, that's because my clientside game framework (Phaser) is weird...But, this all comes with the cost of the extra bandwidth and processing power for those extra messages. And that is why I am scared if nodejs is appropriate for this type of design.

So, I'm looking what are your thoughts on my train of thought here. Am I too paranoid?

Also, I just thought of an issue about the no physics on the server. Let's say, for example two players are in a game. John and Muffin. Muffin shoots a fireball towards John. Muffin manipulates his client so that fireball packet (that tells the server he hit him with a fireball) doesn't get sent. John see's this fireball coming towards him and it doesn't do anything (not notified by server). And thus, John doesn't get hit.. I'm not sure but John would most likely be happy that he received no damage, but this is not good design and just one flaw I found without a physics loop on the server. But then again, this is only detrimental towards Muffin and not John. And since Muffin is technically manipulating the client, his fireball doesn't hit John and thus, he doesn't do any damage. (Obviously the server still checks for skill cooldown, and player range on the server), but this could end up in some serious "distorted gameplay", but not really harmful gameplay... (as no damage will be done towards John) -- And Muffin, is not necessarily going to be mad because he is trying to "hack", and knows what he is doing.

So.. trusting the client has its negatives and positives but for the general small indie game dev, it should be fine?

for the general small indie game dev, it should be fine?

This is an "it depends" answer.

Most small games will never take off. Those that get a small success are unlikely to ever be attacked or hacked.

However, in the extremely unlikely event the game starts to be popular then people will attack the protocol and find ways to abuse them. A few bad actors could ruin the popularity in an instant by finding the exploit.

Deciding if it is worth it to spend the effort to remove the exploit for an unlikely situation is up to you.

Advertisement

for the general small indie game dev, it should be fine?

This is an "it depends" answer.

Most small games will never take off. Those that get a small success are unlikely to ever be attacked or hacked.

However, in the extremely unlikely event the game starts to be popular then people will attack the protocol and find ways to abuse them. A few bad actors could ruin the popularity in an instant by finding the exploit.

Deciding if it is worth it to spend the effort to remove the exploit for an unlikely situation is up to you.

Good points, thanks! I guess in my example, the only person that would abuse the game is Muffin. And John will be affected by it, but not really negatively since he's not receiving any damage. But, I guess objectively it's a flawed design and sooner or later, a different design choice might be needed? (maybe rhetorical)

If you got time, can you comment on my client to server relationship? Is 20PPS to the server when the character is moving weird, normal or bad? I read some reddit posts saying it's fine, but I'd much rather get advice from here :)

Your refresh rates are up to you, your target environment, and your game designs.

You've got 20 updates per second. If there are only two people in the game, that seems excessive as the one other player is probably not generating that many events per second.

Most action games use events for their communication streams. It looks something like:

player faced direction at time

player started running at time

player faced direction at time

player faced direction at time

player stopped running at time

player faced direction at time

player fired shot at time

etc.

The server is sending back similar packets to the individual clients. Occasionally the server will send out authoritative blobs listing the actual positions or orientations for items, or the game will request the server's position details, but even that is generally kept on an as-needed basis.

There might be one or two events per second per player. Someone actively looking around might generate a few more as rapid updates, but even for that 20 updates seems a bit much in typical play.

In your situation where many more objects are being sent for updates, it might be necessary. As you mentioned in the original post, this does open you up for more cheating potential, but because that was your design choice you get to live with it.

Your refresh rates are up to you, your target environment, and your game designs.

You've got 20 updates per second. If there are only two people in the game, that seems excessive as the one other player is probably not generating that many events per second.

Most action games use events for their communication streams. It looks something like:

player faced direction at time

player started running at time

player faced direction at time

player faced direction at time

player stopped running at time

player faced direction at time

player fired shot at time

etc.

The server is sending back similar packets to the individual clients. Occasionally the server will send out authoritative blobs listing the actual positions or orientations for items, or the game will request the server's position details, but even that is generally kept on an as-needed basis.

There might be one or two events per second per player. Someone actively looking around might generate a few more as rapid updates, but even for that 20 updates seems a bit much in typical play.

In your situation where many more objects are being sent for updates, it might be necessary. As you mentioned in the original post, this does open you up for more cheating potential, but because that was your design choice you get to live with it.

Thanks again! Hmmm, I will re-think about my design choice tonight.

A thing that I hate about the 20hz model is when a player quickly strife's right/left/up/down, and then when these X and Y values get lerped from the server (other players) -- you cannot notice them strafing that quick. It makes the players look like they are floating around moving with no "re-activeness". I could increase the lerping, but that usually distorts / creates jitterness.

The only positive with the 20hz client to server is if a player is moving and shooting, this data get's added to the stream.. So I guess that saves 1 extra packet compared to the event model. But, when a player holds down D to go right, and holds it down for 20 seconds, that will be 400 wasted packets. (Technically not wasted, as now the server is in sync, but in compared to the action model, it is)

I have an idea @frob:

What if, I use the player driven event model with no physics server? This would allow for that "re-activeness".

For example:

  • Create a heartbeat that sends the players x and y values 2 times/s
  • Use the command driven model above. Only send commands to server (W,A,S,D) relay these to players in game (creates re-activeness)

The only downside would be if a player joins a game, they would have to wait a half a second or so to become synced. This way, I cannot really check for speed hackers though, since I'm not running a physics server. Client could literally send any X, Y values and I wouldn't know where they were before, because I don't know how long they traveled (velocity being updated on client, they could hold down W for 10 seconds and be top of the map).

I am thinking the 20hz stream will be fine, but now that I think of it, the event driven model seems better. Much more re-activeness and action orientated gameplay, especially compared to that interpolation/lerping stuff. Now that I think of it, I really hate it.

Most small games will never take off. Those that get a small success are unlikely to ever be attacked or hacked.

However, in the extremely unlikely event the game starts to be popular then people will attack the protocol and find ways to abuse them. A few bad actors could ruin the popularity in an instant by finding the exploit.


I've only been a part of the development of one online game so I don't know how far this holds in general. Though we never left 'beta', and only had <30 active users at most, some of our active users repeatedly tried to exploit the game by manipulating the data packets, manipulating the game itself (mostly using CheatEngine), and so on. Luckily they were just script-kiddies in our case. Still was a bit of a nuisance though. We were also DDoS'd several times, and (from other users) had multiple racially-explicit and sexually-explicit verbal harassment incidents.

If users like your game enough that they keep returning, I'd theorize that they'd also like your game enough to cheat and grief, regardless of how successful the game is.

i.e. if 1 out of 10 users (for example) are griefers, they aren't going to 'not grief' just because the community is small. If 1 out of 10 users are cheaters and script kiddies, they're still going to muck with your security even if the game is small. If 1 out of 10 users are verbally racist and sexually harassing, they're still going to be racist and sexist even when the community is small. Perhaps moreso, because they are more in the spotlight.

Ofcourse with a larger community, you get more racists, more griefers, more cheaters, more script-kiddies, and perhaps even a few real hackers. But the probability of rolling a "cheater" for each new user you get is much higher than 0.

Advertisement

What I'm trying to get at, is.. I am relying on the client for a lot of things. Say for example, since physics are not on the server, if a player shoots a fireball and when it reaches a target. this packet is sent to the server. I then check if that player is in range of that monster, and if the skill is NOT on cooldown, it goes through. This would be enough to prevent speed hackers that attack at 1000 times a second, but not enough for pixel perfect collision (physics) on the server.


You don't need to run a full physics simulation to be able to perform a good enough approximation. If an object moves very quickly (eg. bullet speed), you can simulate it like a ray at the moment of firing. If an object moves less quickly (eg. a fireball) then you should probably simulate on the server to check position - but that's no harder than tracking where the players are.

What I am worried about is the 20 PPS the client is sending to the server (when they are moving). Is this even something that other games do? I mean, I know you're supposed to just send the "Player is moving right key" instead of having a TCP stream of data being send from the client..


I don't know where you heard that (and I hear it a lot on these forums lately), but I think it's wrong. Sending keypresses only is a sure way to get yourself into synchronization problems. Game networking has traditionally been using the "rapid position updates" method, and although it seems wasteful of bandwidth it helps ensure everybody is relatively up to date at all times. The majority of networking problems I see on these forums ultimately come down to the problem that the time between a user pressing and releasing a key does not equal the time between the server receiving the keydown message and the server receiving the keyup message. Send positions instead of change events and that problem stops existing.

Collision is done for you, no physics loop on the server, lag compensation is so easy to deal with, fixed timestep isn't needed (although, that's because my clientside game framework (Phaser) is weird...But, this all comes with the cost of the extra bandwidth and processing power for those extra messages.


The point of frequent updates is not to remove the need for performing collision or physics on the server, but to allow the client to have the first go at it in order to improve responsiveness, and to reduce the errors caused by accumulated network jitter, etc.

And that is why I am scared if nodejs is appropriate for this type of design.


Does Node allow you to have a simulation loop? If not, then it's not suitable. If it does, then it is.

So, I'm looking what are your thoughts on my train of thought here. Am I too paranoid?


No. As others pointed out, even tiny games will draw cheaters, and it only takes 1 cheater to upset all the other players.


What I am worried about is the 20 PPS the client is sending to the server (when they are moving). Is this even something that other games do? I mean, I know you're supposed to just send the "Player is moving right key" instead of having a TCP stream of data being send from the client..


The majority of networking problems I see on these forums ultimately come down to the problem that the time between a user pressing and releasing a key does not equal the time between the server receiving the keydown message and the server receiving the keyup message. Send positions instead of change events and that problem stops existing.

Thanks Kylotan!

This is exactly what I ran into when doing player action driven events. Maybe I've just read wrong, but I've always "heard" that the only thing you're supposed to send to the game server is a players command. But, when I tested this, I couldn't get it to become smooth because of latency issues like you hinted to.

For example, for smooth movement, I want to my move my character instantly and not wait for a packet. But, this means the player will always be xxMS behind because of latency towards other players. Since the velocities (if using physics) on the client will move the character xx amount of time before other players receive the signal. You probably already know this, I'm just kind of ranting at this point. :rolleyes:

Hplus has noted don't let the character move until you get a response packet back. Now, this actually works great and I have tested it. There is a problem though because if the server lets say has a "hiccup" of even 5,10,20 or even 50ms the characters in the game will become unsynced. Obviously, you can run a timer to sync them up periodically. Then, there is another problem, if two players are connected to the UsWest realm, and 1 player is in Europe it will become more unsynced. I guess this is where I need to read about the lag compensation on valve's page, but it just seems like such a big mess and makes me want to just do the 20hz to the server data stream method.

I have messaged the wilds.io dev since he's sending 15 packets per second to the server, and has a downstream rate of 15 or 20 per second. So, he's basically doing the same thing and can house around 100, 140 active players on a $5 Digital Ocean box. I have no idea if this number is good because I have no experience with a basic C/C++ TCP Server, but I am pretty sure a pure C style TCP server can handle far more than 6k packets per second. Anyone have any numbers on this? I cannot find benchmarks anywhere for the rates on a pure TCP Server. (in and out rate combined).

It's certainly possible to get a send-commands-only game working, because in theory it should be no different and any updates in between are redundant. In practice, having regular updates in between slices up your potential timing errors into smaller chunks so that there are fewer surprises, which in turn let you make stronger assumptions about position (and thereby your ability to verify it). The MMOs I've worked on, and some (most?) FPS games, worked this way.

Some game types, eg. many RTSes, require that all clients are synchronized, and this usually requires waiting for a positive response before moving. I think that is what HPlus was referring to (in another thread?) But it's not a universal solution to all games. Most action games allow the client to start moving locally, and send corrections later if necessary.

You say that the game gets unsynced by following this approach, but actually, all games are always unsynced. All you can do is attempt to minimize the amount, and the effect, of the desynchronisation. You can never get around the fact that some packet might take longer to reach one player than it did to reach another, and that's nothing to do with waiting for confirmations or not. In fact, the wait-for-confirmation method usually is the least likely to get out of sync because the server tries to notify everybody of a change at the same time. The approach where you start moving locally is more prone to problems because if the server has a 50ms hiccup then the other players get a 50ms extra delay between that player moving locally on their own machine and that player being seen to move on the other player machines. This is the tradeoff you make for responsiveness.

Whether you need 20 messages per second (don't call them packets, especially if you're using TCP, because the protocol decides what goes in a packet, not you) is down to your game type, bandwidth, etc. It also depends somewhat on how quickly players can change direction and velocity, and on how accurately you're able to extrapolate it on the server for the benefit of other players. For the type of games I write, i.e. not shooters, I would probably try 10Hz, or 5Hz.

I'm feeling uneasy with trusting the client. Without even addressing the paragraph containing fireballs: You make sure that people are not speedhacking by taking a delta. OK, fine. So that means as long as I do not move faster than running speed, I am allowed to walk over water and over chasms. I am allowed to fly and attack my enemies (who cannot reach me with melee) with missle attacks from above, too, as long as I am not moving faster than X. Having the client do the physics can be OK, but there certainly needs to be a validation for plausibility, or you need a means of making sure that cheating is not that easy and has an overwhelming chance of being detected. One example how such an offload can be done would for example be to let the client do the collision checking against traps that the player can step on using a Bloom filter (or a spatial hash with enough collisions). Bloom filters have false positives, so the knowledge the client can extract and use to its advantage is limited. When the client reports "hit something (maybe)", the server checks if really something happened. If a client doesn't report so and so often, or if some explicit verification markers aren't reported, it is cheating. It's hard for the client to selectively drop only the harmful events because it doesn't know what it is that just gave a "positive" result, might be a true positive or false positive. On the other hand, the server only has to do the heavy lifting once every 20 or 30 (or even fewer) steps, not every step.

This topic is closed to new replies.

Advertisement