3
\$\begingroup\$

I have been trying to implement some lag compensation techniques for a real-time game, I've found some good resources online, but I don't think I fully understand the server-side part of the problem.

The game is a simple 2D game, where the player moves an entity around the map. There will be other entities with their own behavior that are controlled by the server, but I made it so that their movement can be easily interpolated. The player input is quite simple: an analog stick and some commands (pick target, loot objective, etc.). The game runs at a fixed 10 TPS (it's on mobile and it's not that action packed, 10 TPS will suffice). The client will send the input state every tick (even if no input is present, like the analog stick is in the default position).

It is worth mentioning that only one player is connected at the same time, so in a way this is not multiplayer, but I need to run this on the server as well to prevent cheating.

I understand client-side prediction and that's quite straightforward to implement. I am struggling with the server-side part. As far as I can see I have 3 options:

  1. The server waits for the input from the client then computes the new game state and sends it to the client. This is a viable option only because there is only one player.
  2. The server runs the game loop waiting up to 100ms (10 TPS -> 100ms / tick) for an input. If it gets one, it will be taken into consideration when computing the next state, otherwise it will be discarded. If an input arrives after the tick was done, it will be discarded. If an input arrives during this timespan, but the tick numbers don't match (client send input for tick 5, but server is at tick 7) it will be also discarded.
  3. The server runs the game loop waiting up to 100ms (10 TPS -> 100ms / tick) for an input. If it gets one, it will be taken into consideration when computing the next state, otherwise it will be discarded. In this case it will not care if the input is not for the current tick, it will apply it anyways.

Option 1 is the easiest to implement and will be more consistent. The biggest issue with this is that I believe it's easy to cheat. Since the server is waiting for input, the player might be able to "pause" the game, analyze the situation then dispatch the action, basically allowing a cheating player to play in slow-motion. The client-side reconciliation in this case seems easy, when the player moves, it will move instantly on the screen and when it received the updated state from the server it will do it's reconciliation.

Option 2 is a tad harder to implemented (not by much though), but it will be unplayable (literally, the player won't be able to move) if their ping is higher than 100ms.

Option 3 has the same complexity as Option 2. It will work with pings higher than 100ms but it will most probably lead to some frustration on the player's side since their inputs will not arrive in time.

Is there a better way to do this? What are your thoughts?

\$\endgroup\$
  • \$\begingroup\$ "It is worth mentioning that only one player is connected at the same time, so in a way this is not multiplayer, but I need to run this on the server as well to prevent cheating." Out of curiosity, is there anything the player submits online (like a high score) ? Otherwise, it shouldn't really matter if the player cheats or not, no? Maybe you are overthinking this and add extra complexity without needing to. \$\endgroup\$ – TomTsagk Aug 20 '18 at 14:40
  • \$\begingroup\$ Option 1 and then count the average client tick rate, and if it's less than 10TPS then kick them out of the game? \$\endgroup\$ – user253751 Aug 21 '18 at 0:12
  • \$\begingroup\$ @TomTsagk the game itself is multiplayer, this part is not. This part will add items to the player's inventory and update character's health, so I cannot allow it to be only played on the client side since cheaters will have an easy time cheating. \$\endgroup\$ – Paul Aug 21 '18 at 5:56
  • \$\begingroup\$ @immibis this is an interesting suggestion, I have to see how this works. It might lead to some frustration on the player's side because the TPS might accidentally be lower than 10 even if the player does not cheat. \$\endgroup\$ – Paul Aug 21 '18 at 5:58
0
\$\begingroup\$

From previous readings and a bit of experience your option 3 plus interpolation would work; essentially when the server receives input in the correct time frame it deals with it as usual, but when it receives input a bit late it will essentially add back in some extra input.

Say for example that the user can move the entity around at 1 unit per tick, and the input arrives 1 tick late(so it has been 2 ticks since the user pressed the input) then the server will treat that second tick of input as "extra input" and interpolate it back in by allowing the player to move slightly faster visually while the calculations are performed as if the player started the movement at the desired time. Its up to you to decide how fast you want that "extra input" to be evened out so you will have to test and tweak until it feels right for your game

\$\endgroup\$
  • \$\begingroup\$ Thank you for your answer! I don't think having the extra input is necessary because of the way the client-side handles updates that happened in the past. When the client-side receives an update from the server, it will replay the events from when that update occurred using the stored input snapshots. The client side will store a list of states and a list of inputs. Upon receiving the update it will discard older elements from both lists. \$\endgroup\$ – Paul Aug 21 '18 at 6:02
  • \$\begingroup\$ Glad you found a solution to your problem then! Since you went with your own solution maybe putting in your own answer and accepting that one so others will have that answer to refer to as well when looking for the same problem would greatly help the community ;3 \$\endgroup\$ – TurtleKwitty Aug 21 '18 at 12:47
  • \$\begingroup\$ I will do that, but I want to validate that it actually works this way. I'll submit an answer with some conclusions when my testing is done. Thanks again! \$\endgroup\$ – Paul Aug 22 '18 at 7:03

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.