How do I make an obstacle course game fair for players with high ping while still being secure from hackers?

Motivation

This is more of a thought experiment than something that I’m actually working on, but it’s something I’ve really wondered about for a while now.

Because there is a limit to how fast data can be sent across a wire (or any medium, for that matter), there will always be a difference between what the server sees and what a player sees when they move their character around. The bigger this difference, the more challenging it can be to make the experience fair for players while also being secure from hackers.

Example

Imagine a game where players are stationary but can jump vertically to avoid a speeding block that tries to hit them every few seconds. The block is created on the server, its position is sent to all the players, and then the block begins moving. Note that the block starts moving immediately after it appears.

Due to latency, players won’t see the block for at least a few milliseconds, and players with a poor connection might not see the block until 500 milliseconds or more after the server creates it! How we handle this issue will greatly affect players’ experiences.

Doing it client-side

The easiest way to handle this is to have a local script that checks on the client if the player is hit by the part. If the player doesn’t see themselves touch the part, then they didn’t touch the part. What the server thinks or sees doesn’t matter at all. This is great when it comes to latency because even players with over 10,000 ms ping will be able to dodge an obstacle just as effectively as a player with 0 ping. The amount of time it takes for the server to tell the player that a block appears is irrelevant.
I guess this doesn’t account for things like packet loss, but let’s assume that this isn’t a problem.

The problem with this approach is that it gives full control the the player. They can delete the script that handles hit detection so that they can just stand there and let the block phase through them, or they can even just delete the block on the client so that it never reaches them. It’s too easy for a bad actor to cheat.

Doing it server-sided

Instead of using a local script, you can use a server script to check if the part touches any players, but this means that the server is relying completely on what it sees. From the point of view of the server, that one player with 500 ms ping doesn’t jump in time to dodge the speeding block. From the point of view of that player, they see the part appear, they jump over it, and then they die anyway. By the time the player sees the block appear, it has already hit them from the server’s point of view, so they can’t dodge it at all.

While this approach prevents hackers from avoiding the part because clients can’t modify server-sided things, it’s not really fair to players with bad connections because there is a big disconnect between what the server sees and what the player sees.

Alternative?

Is there a way to get the best of both worlds? The secureness of server-side code and the responsiveness of client-side code? I was thinking of having each player send their position and position of the moving block with timestamps to the server and then having the server analyze the data for any suspicious behavior, such as a player jumping 100 feet into the air or floating, or their report of the part saying that the part isn’t moving, etc. But that requires a lot of data to be sent over the wire, as well as a lot of processing done by the server. There has to be a better way…

Any ideas?

I don’t think there is a good solution for this, but correct me if im wrong about that because I would also love to hear about it.

My idea for this is a a sort of hybrid solution of what you suggested.
When the server creates the speeding block, it gets replicated to the clients as well so thats the responsiveness fixed. And to deal with the hackers, the server will periodically check on each client, sending out authoritative state updates to the clients (basically moving things on the client where the server thinks those things should be), and if the server calculates that the client’s predicted state (the client’s position of the speeding block and the player in your case) to be different on the client and on the server, the server will make changes to make sure the client’s state is the same as the server.

But other than sending information to be validated back and forth, I don’t think there really is a better solution as you can never trust the client.