Preventing exploits on custom characters based on physics

The Scripting Support sub-category is intended for all development support relating to programming on the Roblox platform. This includes questions ranging in difficulty from extremely basic to even the most technical of issues.

You may present your thread how you choose, but you are required to answer the following questions in your thread;

  • What are you attempting to achieve? (Keep it simple and clear)
  • What is the issue? (Keep it simple and clear - Include screenshots/videos/GIFs if possible)
  • What solutions have you tried so far? (Have you searched for solutions through the Roblox Wiki yet?)

You may then include any further details.

So basically, my game Marble Sim uses custom characters that have movement heavily relying on physics. Lately a lot of exploiters have come by to ruin the fun for my small community of speed runners by teleporting their marble to the finish getting impossible times.

I would like to combat these clowns somehow and I’ve tried to but there’s some issues.

What I had tried seemed like a simple solution but it spawned more problems. I made a script that ran every hearbeat on the server that compared the current position of the marble and the last position of the marble to its current velocity (and yes I took in to account the delay between each heartbeat.) Sadly this didnt work due to how fast the marbles can go. Their range of speed is very large. It’s hard to describe but I hope you can understand what I mean. This method ended up kicking more innocent players than bad, and the bad players were still able to get impossible times somehow.

Here’s the code for that btw, maybe Im just dumb.

code
local lt = tick()
game:GetService("RunService").Heartbeat:connect(function()
    local td = tick() - lt

    lt = tick()

    if td > 0.02 then return end
    for _,v in pairs(game.Workspace.PlayerBalls:GetChildren()) do
        local pp = v.PrimaryPart

        local p = game.Players:GetPlayerFromCharacter(v)
        if p and pp and pp.ls.Value.Magnitude > 0.1 and p.Playing.Value then
            if (pp.ls.Value - pp.Position).magnitude > (pp.Velocity.Magntiude) * (1+td) then
                game.Players:GetPlayerFromCharacter(v):Kick("Your speed was a little suspicious. In order to keep the game fair we had to kick you! Sorry :(")
            end
        end
        pp.ls.Value = pp.Position
    end
end)

I just want to know if there’s any other methods I should try out. Just like any possible fix for these teleporting exploiters.

I found a post. For an addition, you can raycast(and check length as previously mentioned in the post linked above) between the next location with previous to see if the player passed through a CanCollide wall. However, there is a problem with this method, if your check unluckily starts around a corner and when you round the corner really fast. Unless your check is too fast to find those false positives…

And maybe you can find something in here that can be useful to your code? Such as Player:DistanceFromCharacter().

Options


Timer
Apparently RunService.Heartbeat runs on frame rate, if you have 60 FPS, you’d get 1/60 rate. Therefore, it’ll check every 1/60th second or every frame. Also there’s a step parameter, which is the time between the signals. You could use step for checking the speed per second and adding the “highest” limit.

The Finish
You could add invisible checkpoints around the map and void the finish until they reach these checkpoints. This counters the issue of exploiters being able to teleport into the finish directly and finish the map immediately, but we could also counter this issue by trying to remain in the finish for a split second without moving(?).

Last Option
Or, if all else fails, you could check if their traveling distance is exaggeratingly high(100 studs w00t), just kick them. Also you might as well find the highest velocity you can possibly get and from that you can kick them if they reach above this velocity.


These are, of course, options. Let me know if something is not quite accurate in this post, perhaps someone else has a better solution?

2 Likes

Note: Local exploit prevention can always be bypassed or completely disabled.

@Operatik’s methods seem really good.

@GalaxysEve If your original script fails, try remaking it. Try making it in such a way that each custom character has its own script (on the server), keeps track of its own position etc. This way using any raycasts, magnitude checks etc. (in servers with a lot of players) won’t slow down the rate the checks are happening in. (Using a spawn() function would probably work too.)

1 Like

The way I do it involves a few simple checks and no raycasting. Heartbeat runs immediately AFTER every physics frame. This is VERY important for this to work reliably.

First, check if the ball’s position since the last frame is further than its Velocity.Magnitude of that frame multiplied by the frameTime value. Due to ping you’ll maybe want to include a stud or so of padding. This will ensure the ball hasn’t teleported.

If you want you can adapt these checks for each individual direction for even more reliability.

Secondly, check if the ball’s velocity has jumped up faster than physically possible since the last frame. This will prevent the exploiter from setting their velocity high enough to travel this distance.

If your ball is controlled by gravity, the speed the ball falls will increase over time. I’m not sure the way you’d estimate this speedup but you can test this yourself using differently massed balls.

Finally, if the ball has done one of these you’ll want to reset its Velocity and CFrame to that of the last frame. Optionally you can simply move the ball by its Velocity (multiplied by frameTime) for a smoother effect.

Since Heartbeat runs AFTER physics and BEFORE they are replicated you can make any changes to these and it will appear perfectly smooth to other players while the exploiter will lag back based on their ping.

This is especially noticable when teleporting every frame on the client. You’ll continue to be lagged backwards while other players will never notice anything occuring.