1
\$\begingroup\$

I have been developing a server/client model for a game project I am working on. Everything works great, client side prediction works, server reconciliation works. Basically, the character can move smoothly without any hiccups.

However, the problem is that I am currently not using frame independent movement, it doesn't rely on the elapsed time between updates. Every time a movement packet is received, it will move the character x amounts of pixels. The packets are gathered on the client with a certain rate.

If someone were to modify the rate so that it would gather it faster, that means it would send more packets and make it move faster. Essentially, they would be speed hacking.

How would I go about preventing this behavior. If I try to add frame independent movement, server reconciliation doesn't work any longer since it doesn't know how much to move it after the server correction was received. Is the best way to just limit how many movement packets that can be received server side per second?

I have been reading the source networking article, but they do not mention anything about this as far as I can see.

By the way, when I send these packets, I do not send them as they are gathered, rather I send them bunched together at another rate, to reduce bandwidth.

Edit: I think I was a little bit unclear about my packets. My packets contain user commands that holds the current state of the keyboard, mouse and whatever else is collected. The server receives the packet, which can hold MORE THAN 1 user command, as it sends the pakcets at a slower rate than the commands are collected. This is exactly what is described in the source networking article. The server receives the packet and handles ALL user commands as soon as it is received, thus if the packet contains a lot of user commands (the client modified the rate of which it collects them, or duplicated them) the server will move it more than intended. Modifying how often it sends the packets doesn't matter, but the gathering of the user commands does.

Let's say the server sends the packets every 100ms, and collects the commands every 50ms. That means every packet will hold 2 user commands. But if someone modifies the collection rate to, say every 10ms. Every packet will contain 10 user commands which would move the character further since the server moves it for every user command.

\$\endgroup\$
  • \$\begingroup\$ What about just capping the movements to some value per tick/second ? \$\endgroup\$ – Kromster May 13 '15 at 15:23
  • \$\begingroup\$ Sounds to me like you're looking for a bandaid for a cannonball wound. Fix your timestep first! \$\endgroup\$ – Thebluefish May 13 '15 at 17:02
  • \$\begingroup\$ Fps's don't use fixed time steps as the norm, the fear engine makes it so you can only move so far per update, like krom said. Fixed time step and/or lockstep will ruin your responsiveness. \$\endgroup\$ – Alan Wolfe May 13 '15 at 18:38
  • \$\begingroup\$ @AlanWolfe this is what I was thinking of doing, but I was just wondering if this is the correct way to go. Also, the source engine uses a fixed time step, as described in the source networking article I linked in my post. \$\endgroup\$ – Metamist May 14 '15 at 17:06
1
\$\begingroup\$

Your game shouldn't depend on the speed at which the packets are sent as it will vary depending on your internet connection regardless of what rate you attempt to send them.

Instead your server should move the character depending on the user actions (e.g. while they are pressing (sending) W move them forward, or if you are counting mouse clicks then send how many times they clicked since the last packet was sent).

Depending on how many movement packets a client has sent is simply too unreliable.

\$\endgroup\$
  • \$\begingroup\$ -1 from me; many games implement the client movement packet method because it is the simplest and works. Ultimately, you need to rely on your players input for ANY packets. \$\endgroup\$ – Vaughan Hilts May 13 '15 at 19:49
  • \$\begingroup\$ If you have a game where response time is important you will use UDP for performance and UDP packets will not always arrive to destination. That's why you can't rely on the frequency of received packets. (Please note that I am not saying that sending packets at fixed rate is bad, it's actually very practical, but relying on them to be received on server at fixed rate is definitely not) \$\endgroup\$ – zoran404 May 13 '15 at 19:58
  • \$\begingroup\$ @VaughanHilts Name three games which move the character based on the number of packets received, rather than based on any other factor. \$\endgroup\$ – Trevor Powell May 14 '15 at 10:15
  • \$\begingroup\$ I'm sorry, I must have been unclear. I am not sending packets that say "move character 1 unit on x", I am sending packets of the current input state, which keys are pressed, mouse position etc. The server however, handles them as they are received, thus making it move if the W key is down for example, but only when the packets are received \$\endgroup\$ – Metamist May 14 '15 at 16:41
1
\$\begingroup\$

I would suggest making a separate buffer for each player that is responsible for squashing commands together.

Basically, it should reduce a set of network packets into an approximation of user's input, which is sampled only once per game update that should result in equally significant change for every player.

The question is, what should be sampled from the state and what strategy to use for squashing commands together.

For instance, if the player were to send one of WASD events, you could build up a vector of his movement and sample its direction, resetting the vector back to 0 after that to accept new input. Like, having received DDWSWW the sampler would output pi/4 degrees as a direction of vector (2; 2), and you would move the player in the given direction, same distance for everyone. Of course, this example is primitive and suits hardly any game, but the pattern is quite generic.

You can employ more sophisticated strategies with squashing commands, like leaving a tiny fraction of the previous input sample to apply further incoming commands on top of it, much like smoothing the movement. There's a lot to play with there.

\$\endgroup\$
  • 1
    \$\begingroup\$ I was thinking of doing this, but how would I apply server reconciliation to this? Wouldn't the client correct itself incorrectly if it is handling the squashed commands at a different rate than the server (if the frame time is increased due to fps lag) \$\endgroup\$ – Metamist May 15 '15 at 21:51
  • \$\begingroup\$ @Metamist I don't see a reason for squashing on the client: there is only one way for the client to interpret data from the server since "it's always right", the question is how to present correction to the player. \$\endgroup\$ – D-side May 15 '15 at 22:06

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.