Help with Lag Compensation Methods

I’ve recently been working on a couple of projects and have been trying to make systems that fight latency while also being far more secure than the conventional Roblox game. Since Roblox themselves haven’t decided to implement any sort of server authoritative physics models (that don’t result in input lag), I have been working on my own solutions. This is what I have so far.
https://i.gyazo.com/ec6360ce01fc8c37b8099afaad147dc8.mp4
In the video, you can see that jumping is only client-side and I try various different exploits like speed-hacking and teleportation and none of them work anymore! (In fact, even if users were to bypass the correction feature, they would be completely out of sync with the server and be unable to do anything!) This is awesome, however, I am still trying to figure out what I can do to improve this system, as I have run into a couple of issues. The biggest one is that the player jitters a bit when changing directions very quickly (because it is trying to move to where the server thinks they should be) and when stopping. I was wondering if anybody has any solutions or better ways to deal with these problems.

Before I send replication information I first tell the client I have spawned a character for them.

  1. The character is created on the server (with no animations and no nothing aside from the hitbox and humanoid)
  2. The client (and other clients) receive this message
  3. A local version of the character is created for the client with more visual features
  4. The character replication process occurs, replicating other clients, and correcting the local character

My current replication methods involve this process:

  1. Server initiates communication to client via repeated firing of a RemoteFunction to send and receive data, as well as measure ping
  2. Client responds, sending over the movement direction and facing angles
  3. Server simulates physics steps in order to sync the client with the server (based on their Ping) and keeps the character in motion
  4. (occurs before 2, when receiving communication) Client updates the corrective position (also with Ping accounted for) and will try to correct themselves smoothly to the position

What the client and server see:
https://i.gyazo.com/b5623c62deb29842fe5c476f26eafdf1.mp4

All of this information is being sent through using my NetworkManager module via the RemoteFunction it uses to communicate.

Hopefully, I will be able to resolve a couple of these issues or be able to figure out what else I can do to improve this system. It will most likely not be public as it is currently very difficult to set up and requires a lot of tinkering to get right.

If you need any more information on how this process works, I can provide it.

EDIT:
From what I see in other games, I think I should employ a softer correction (far less noticable) if I am really close to the expected position, and a much harsher correction if I am further away. Still trying to work out how I will do this though.

6 Likes

Here are the results with the smoothness mechanic going on:
https://i.gyazo.com/c02b61f7f0c4e19b2c3ebfcd711fb822.mp4
Jitter is slightly improved but still visible. You can also notice a bit of sliding going on when they stop moving.

Is it possible that the jitter is due to a time interval difference between client and server? For example, on the client they think the a key is pressed for 125 ms but the server calculates a 150 ms button press, and thus applies a slight correction to the humanoid.

Well, yes of course. I am, however, trying to somewhat mitigate or reduce this by performing what I call a “cross-machine sync” where I offset them based on their ping. If someone has high ping, their information takes longer to reach the server, thus, they should be pushed further ahead than someone who has lower ping. The objective of this method (with client prediction) is to get all machines in sync so that players are in relatively the same position across all machines, instead of completely out of sync based on how late replicated information was sent/recieved. Also, the ping is computed on both the client and the server. The client uses their locally deduced ping to adjust the server’s result, and the server uses the server deduced ping to adjust the client’s result.

How is it that client input is sent to the server though?

If you’re simply sending a snapshot of the client’s current movement vector, I think it’s possible that movement occurring in between client pings to the server has the potential of being lost (and subsequently corrected by the server). If this is how you handle it, do you think changing what data is sent to the server would fix the jitter? If you send all client inputs (and the time intervals the client saw for those inputs) between pings, the server would have all the information the client has.

I am trying to do something similar, as well as try to do a radius limited solution where the client sends a position and the server determines whether or not that position is valid within the radius they could have moved within since the last update. And if it is, update the position on the server to sync, and if not, clamp the position inside of the radius.

My internal “something-is-not-right-there” alarms started when reading that paragraph.

If you are making the server call ‘a client’ via a RemoteFunction and waits for a response, then I do hope you take precautions in the server-side code, so it does not “halt”.

Exploiters could easily break this, by never or slowly responding to the RemoteFunction-call. Well, even a genuine player with a very bad network-connection could cause the server-side code to “become slow”, because of the implementation ‘server waits for the client to respond’.

Perhaps take a look at the red box in ‘Server to Client’ section, from the page ‘Remote Functions and Events’.

Well yes obviously, every client runs their communication in their own threads. All of the logic of course is separate from the communication. I have been working with remote functions and remote events ever since they came out so there is nothing wrong here. The reason why I use remote functions and not remote events is specifically because of the reason that they respond! This allows me to communicate information to and from machines while also only communicating once a message has been received, allowing me to accurately assess ping (the values are correct and match the values in the developer console) and separate game logic in a way where if something has been received or not, and other information, can manipulate the state of replication and other things. This is definitely not the issue.

Sorry, but what do you mean by similar? You’re position-checking the client similar to the solution I proposed or similar to the problem I outlined?

As for the radius-check (which I assume is what’s going on in the third video), does increasing the radius eliminate the problems altogether, or are there other checks the server is performing which could be attributed to the jerkiness/sliding?

I haven’t done any of that yet. I all I did in the last video is modify the smoothness factor of the interpolation clientside to where the server had moved them