Anti-Teleport Exploit Issues

In my game you go to npcs and attack them to gain levels, the main exploit people use to gain levels quick and fast without doing anything thing is a loop script which CFrames them to a npc attacks them until they are dead then goes to the next. I have attempted to add anti CFrame teleportation, but somehow they get passed it. If anyone has ideas on what I should to improve my anti teleport script or why I messed up please inform me. I also have the exact script most of these players are using to exploit my game.

Extra Info: My script is placed in the starter character and is a server script. I have also tried using the script without a wait() and it doesn’t work either.

My Script:

local RunService = game:GetService('RunService')
Check = false
Boop = false
if RunService:IsStudio() == false then	
RunService.Heartbeat:Connect(function(step)
if script.Parent:FindFirstChild("HumanoidRootPart") then
if Check == false and Boop == false then	
LastestPos = script.Parent.HumanoidRootPart.Position	
Boop = true
wait(.1)
Check = true
Boop = false
else
if Boop == false then	
local NewPos = script.Parent.HumanoidRootPart.Position	
if (LastestPos - NewPos).Magnitude > 35 and script.Parent:FindFirstChild("AESafe") == nil then
script.Parent.Humanoid.Health = 0	
end	
Check = false
Boop = false
end
end
end
end)
end

The Exploit Script:

_G.Farming = true


while _G.Farming do wait()
for i,v in pairs(game.Workspace:GetChildren()) do
if game.Players.LocalPlayer.Character and v:FindFirstChild("HumanoidRootPart") and v:FindFirstChild("Humanoid") then
if string.match(v.Name, "Orange Spirit") and v.Humanoid.Health > 0 then
repeat wait()
game.Players.LocalPlayer.Character.HumanoidRootPart.CFrame = v.HumanoidRootPart.CFrame + Vector3.new(0, -2, 0)
until v.Humanoid.Health == 0 or _G.Farming == false
end
end
end
end
1 Like

Try running a HumanoidRootPart:GetPropertyChanged() function and when that triggers, calculate the distance over studs of the average walkspeed. If that distance is over the d/s limit, then you caught a probable exploiter. Plus it decreases running thread time by using a property changed function instead of the RunService.

2 Likes

This would still run 1/60th of a second everytime the HumanoidRootPart changes position. Plus, with Roblox’s whole deal of having a rate limit and spamming the dev console with said rate limit, it’ll slow your game down more than if he used a RunService loop.

1 Like

Could you implement a heartbeat statement to account for that? Keep in mind there are no calls being made if the HumanoidRootPart doesn’t change position (aka the Character isn’t moving). Therefore, if properly handled, it could be more efficient.

(This is purely theoretical; I have not tested it. Also, it may not be a practical solution for your game.)

An interesting, unconventional approach would be setting “traps” for exploiters. An example would be to put an Orange Spirit somewhere that no normal player could ever reach. Then, rig a script that kills/kicks/bans any exploiter that enters the proximity of that trap (and potentially log their name). The only downside to this concept is that exploiters could adapt on a trap by trap basis.

2 Likes

@lando64000 had done something similar with PBB, quite a few of my friends fell for this bait so depending on the execution it could work out in your favor.

1 Like

What specifically do you mean by a heartbeat statement? If you mean wrapping the logic in the heartbeat function, the function will still get called every heartbeat, change made or not.

1 Like

Sorry, I meant RenderStepped:wait(). But looking back through it, you’re correct, it won’t change anything.

That’s not where my confusion stems from; it’s where you’re suggesting the use of RunService be used anywhere in your code, given your first response.

I don’t think the implementation here is proper or needed. Is RunService to be used inside or outside of GetPropertyChangedSignal? If it’s run inside, it’d be unnecessarily sleeping the thread every render frame when the HumanoidRootPart changes. Of outside, now you have an unnecessary call every render frame.

My solution would have been that when the HumanoidRootPart position changed, it fires at about 60 frames per second while continuously moving. It would have been to insert the RunService.RenderStepped:wait() into the function as a sort of debounce to counteract that rate limit. However, looking back through the documentation, that RenderStepped:wait() won’t do anything.

Realistically, yes, you only need to check the distance between an initial and final movement and determine if the distance travelled seems illegitimate according to WalkSpeed via the server.

1 Like

It sucks that a few nasty apples (exploiters) make us devs have to do extra work to keep the game fair! UGH!

But yes, as @colbert2677 stated, you need to track

if finalPos - startPos > someSpeedLimit then
      --Go to town here.. log their name, crash them in a horrible way, 
      --as long as you're sure this script won't trigger on innocents
      --(I'll get to that) go do horrible things
end

As I mentioned, if you have vehicles or abilities that make you increase speed in your game, you need to be aware of these. If someone is in a boat (that is faster than walking) they can be picked up as an exploiter when really they are just using a vehicle. Make sure to maybe include in the speed limit maybe the absolute max speed a player can go.

SO much work… I hope you find a solution!!

So I do not believe you have to track CFrames… you’ll be fine with tracking a Vector3 as it houses just position, CFrames house position and rotation. Now, to calculate how far they have moved, you could maybe try calculating how far on each axis the player has moved, get the absolute value, and get the sum to see how far they have moved. Would be:

local xDelta = math.abs(finalPos.x - startPos.x);
--do the same for y and z

Now this is a lot of work to calculate the distance so I’ll play with some math and try to find an easier way.

Edit: Nope… they are separate terms no combining. You could add all axis together and do a mass subtraction but when you get negative values in there is gets messy as you can’t do Math.abs on it so we’re doing it by each axis. But Vector subtraction works by elements so we can do

local delta = finishVector - startVector

But we have to get math.abs on the parameters somehow so we get only positive values. Sorry I couldn’t do more!!

I think a much simpler way than checking position every so often would just be logging the player position every time they attack alongside with a timestamp.

Clear this log when they die and every time they attack just check if the time from the last attack is both between a certain threshold and if the distance from the last position they attacked isn’t too great. If either of these go off, just invalidate the attack.

This would work too. But, if an exploiter suddenly wants to attack players instead of NPCs, this would not work. Also, this doesn’t stop click to teleport scripts either (maybe an exploiter chickening out in a fight). This idea would be MUCH simpler (although you still have to calculate acceptable speeds) but only practical for attacking the NPCs.

If he only wanted to guard the NPCs, then it would be even simpler and more reliable to use @AwesomePossum212’s amazing trap idea.

Although, you did just indirectly point out a flaw in my system: if a player somehow gets flung at high speeds, they would get picked up as teleporting.

I don’t see how this doesn’t work for players too. It’s attacking both times.

1 Like

Oh my apologies. I somehow read it logs only when they attack an NPC.

The trap idea is hardly effective. Band-aid solutions are not proper fixes to problems and this doesn’t solve the initial problem. In the future, this is bound to generate XY circumstances.

There’s also the fact that you have to account for every NPC type if you decide to use this band-aid fix. You can use CollectionService to add tags to “farm catcher NPCs”, so long as you delete the tags straight away on the client - this way, exploiters can’t void potentially attacking a “trap NPC” by ignoring those with the filter tag. Again though, doesn’t solve the initial problem - teleporting can still happen.

Whichever way you go about it doesn’t matter; the point is to validate previous and current distance and see whether it’s acceptable or not.

cc @AwesomePossum212

First of all, the Heartbeat event is what you’re looking for to check for teleportation. It runs after physics meaning you’ll always have the exact position of the player and never miss a beat.
Secondly, you do not want to account for ping because ping can be spoofed pretty easily.

The way I check for speed hacks, teleportation, flying, etc is I check the Velocity of the HumanoidRootPart of every player and make sure it’s not over the ideal limit (take into account when they jump or sprint) Secondly I check the distance of their current HumanoidRootPart position to their last HumanoidRootPart position and I have a second threshold in case physics throttling is faster on the client vs the server. If the distance between these two positions is a certain amount over their velocity than you already know they are teleporting and or speed hacking.

As a bonus you can check for flying very easily by checking if they’re floating above the ground and Humanoid.FloorMaterial is equal to Enum.Material.Air.

Edit:
Make sure you don’t immediately kick the player (only for extreme distances or speed differences). You are probably actually looking to reset their position and velocity to the last recorded values which will simply cause a rubber band if the server or their internet is lagging.

1 Like

So I figured out the main reason my script isn’t working is because the exploiter can actually delete scripts in the character even if they are server and prevent them from working. To fix this I switched the location to Server Script Service and put it inside a OnCharacter added function.