I want to make sure my game is nice and healthy. To do this, I have to make sure a player can’t teleport 1000 studs away from their point. How can I do this, without people getting detected just for being a lagger, or glitching off the map?
Well it really depends on the exploit script being used on _G or other scripts but the main thing you need to know is don’t put your scripts on the Character as the exploiter can delete it even if they are in the Server and prevent them from working. Second thing you may put your script in ServerScriptService and add a OnCharacter Function.
Second note that, anything on the client can be added or deleted
You could also make a system using metatables or casting a ray.
You can cache every player part’s position on the X or Z axis and then compare it to the current part position depending on how frequent you want to check it (the default is 1.6 studs per second iirc) and teleport them back to their prior cached location. There’s ways exploiters can get around this but this will stop most exploiters from teleporting and zooming around your game.
Metatables aren’t very relevant to having an anti-teleportation system on the server, can you elaborate? and teleportation scripts don’t rely on _G (they might store their variables there but that’s very rare and most exploiters sandbox _G from the real Roblox environment)
Alright. So the main point is, never trust the client. All your scripts should be in ServerScriptService.
To make the anti-exploit:
- Connect a function to Stepped or Heartbeat
- Loop through all the players characters, if they have a previous position, check that against the current one based on the time passed.
- Then store their current positions in a array.
To check between the past position and current position:
local dist = (currentPos - lastPos).magnitude
Can you maybe elaborate a bit more? How do you use a metatable to “automatically activate” a script? Provide some sample code maybe?
Or you could write a simple loop script that check the HumanoidRootPart position every .6 seconds.
With that, make it so if the player distance is > position + 996 than the previous position, it will fire a remote event that kicks the player.
If you want to know what are metatables, you could try out this topic: What is a Metatable? - #2 by Operatik
For example a example really:
You need to make a table a example (note you can rename the metatable to anything you want, local previousLocations = {}
To active when a player joins the game:
local previousLocations = {}
local Players = game:GetService("Players")
function antiTeleport(Player)
end
Players.PlayerAdded:connect(antiTeleport)```
Server Security
Understanding
The problem with creating anti cheats is understanding the importance of how your anti-cheat should function, to get the most secure results this will want to be handled on the server, however that makes things much more difficult and can tend to have unreliable results.
Reliability
As of right now one of the best ways to make sure that your anti cheat isn’t false flagging is to check the players ping, I will not be covering this here however, although there are many posts that will show you how to get a users ping.
Another way to make sure that your anti cheat wont false flag users is to give it some leanway, your client may do unexpected behaviors that result in false flags, however in this post specifically you’re looking for long distance teleports; which you can do quite easily without needing to deal with ping.
Pros
- The client can’t modify or remove any code to disable your anti cheat
- The client has no way to view our code in order to create a bypass
- No use of events will be needed
- The client can’t teleport themselves using our implemented functions
Cons
- Can be unreliable without the proper testing and checks
- May cause lag on the server if its being abused
- May not detect a user instantly
Code
So with that being said, lets dive right in to it! I noticed how you requested above that we use metatables and OOP
While coding this anti teleport system I realized quite soon that it truly wasn’t needed, however I included it anyways.
Player Connection
When a player joins the game we’ll want to begin our checks in order to detect teleportation.
local players = game:GetService("Players")
players.PlayerAdded:Connect(function(player) -- Connect a function when a player joins
-- Begin the anti cheat code here,
end)
Creating the Anti Cheat
Now that we know when the player joins, we’ll begin creating our anti teleport.
local cache = {}
local players = game:GetService("Players")
function teleport:Teleport(pos) -- Teleport a user to the given location without flagging our anti cheat
local player = self.player
local character = player.Character or player.CharacterAdded:Wait() -- Grabbing the character and making sure it exists
local humanoidRootPart = character:WaitForChild("HumanoidRootPart") -- HumanoidRootPart, will be used to teleport the user
self.teleported = tick() -- Saving the time that the user was teleported, that way it does flag our teleport
humanoidRootPart.CFrame = CFrame.new(pos) -- Teleporting the user to the given location
end
function teleport:Begin() -- Begin the loop checks, will use settings
local player = self.player -- The player that we'll be enforcing checks on
self.func = coroutine.create(function() -- Our function for ease of removal to prevent memory leaks
while wait(1) do
local character = player.Character or player.CharacterAdded:Wait() -- Our players character & potentially waiting for one
local humanoidRootPart = character:WaitForChild("HumanoidRootPart") -- humanoidRootPart, will be used for our positions
local newPosition, savedPosition = humanoidRootPart.Position, self.position
if savedPosition then -- Ensuring the player has a stored position, if not then set one later on
local SXZ, XZ = Vector3.new(savedPosition.X, 0,savedPosition.Z), Vector3.new(newPosition.X, 0,newPosition.Z) -- Removing the Y axis from both the saved position & new position
local distance = (SXZ - XZ).magnitude -- Distance between the two points (saved and new)
if distance > 40 and tick() - self.teleported > 3 then -- If the user hasn't recently been teleported and they've moved over 40 studs in a second; enforce a punishment
self:Teleport(savedPosition) -- Teleports them back to the previous spot!
end
end
self.position = newPosition -- Saves the new position
end
end)
coroutine.resume(self.func) -- Begins the loop!
end
function teleport:End() -- Will clear all existance of the checks to prevent memory leaks
local player = self.player
if self.func then
coroutine.yield(self.func) -- ends the loop
self.func = nil -- removes the function completely
self = nil
end
cache[player] = nil -- removes table from cache
end
function teleport.new(player) -- Creates & Returns our TeleportClass
return setmetatable({ -- Create a simple OOP
position = nil,
player = player,
teleported = tick()
}, {
__index = teleport -- Teleport table will be our class
})
end
players.PlayerAdded:Connect(function(player) -- Connect a function when a player joins
if cache[player] then
cache[player]:End() -- If the player already is stored, then remove it
end
cache[player] = teleport.new(player) -- Create the class
cache[player]:Begin() -- Call a custom function on the class that will begin our loop/checks
end)
players.PlayerRemoving:Connect(function(player) -- Connects a function when a player leaves
if cache[player] then
cache[player]:End() -- Ends it
end
end)
Video
Conclusion
I would’ve loved to make this post a lot bigger and separated the code more, however I ran out of time! If you have any questions please let me know!
I’m not the recipient, but damn! This was amazing! Kudos.
This is not at all true. A client side exploit cannot stop a server script from running that is impossible. These checks also should not be done on the client and are easily and reliably done on the server. Metatables are useless for stopping exploits and you shouldn’t be implementing script protection like this because it has no effect. _G has nothing to do with scripts, it’s just a table that all scripts have access to. RayCasting has nothing to do with detecting teleportation either.
As for the question,
my article gives a some examples of preventing movement exploits from the server including stopping teleportation. How you should secure your game - A beginner guide for secure networking and developing anticheats - #43 by Hexcede
I would not recommend kicking or punishing players for teleporting either, but rather simply stopping this teleportation like I show in my examples.
This is very well written! It’s similar to mine but it doesn’t take into account player speed and doesn’t sync with physics in any way which will lead to more false positives. Tips: A player’s max horizontal velocity is their WalkSpeed and the max upwards velocity is their JumpPower. Stepped runs before physics and Heartbeat runs after which means Stepped is good for detecting and preventing movement exploits before they even replicate to other players.
To add on to this, there’s also currently no respawn detection so a false-positive will be thrown in the event of a character respawning.
Other than these things, it’s a really solid reply - just what everyone would love to see more of here!
I agree with the not kicking part, some people accidentally get flinged, in some games. And they end up getting kicked, or punished.
About that… it actually is half true, at least for characters. This has been an issue since the inception of FilteringEnabled where deletions of stuff from the character replicates, including server scripts.
Related threads list
FilteringEnabled :Destroy() replicates anyway
Do not replicate :Destroy() in characters with Filtering enabled
Deleting objects that aren't BaseParts from your Character on the client replicates to the server
Now the code will (probably) still run given it’s server-side and the client is unable to tamper with server-side execution, but the deletion of the instance would still replicate.
That doesn’t seem right. I’ll have to do some testing because I know for a fact there was an exploit related to the characters Humanoid existing on the server but not the client which would make them invincible.
Can confirm what colbert said is right. For some reason deleting any descendant of your character on the client replicates to the server, doesn’t matter if it’s a Part, a Script or a Value.
This is also a common way for exploiters to create “god mode” scripts by deleting an instance such as a NumberValue parented to the character which the server-sided damage handler accesses directly every time and never expects it to not be there, therefor erroring mid way and not dealing damage.
Honestly, just don’t do it. There are lot of cons when trying to make anti teleport systems.
Server:
A way to make an Anti Teleport system is using a simple Magnitude check from the Player’s last position, and their new position. Though this works and cannot be deleted or modified by the client becaue it’s server sided, it also comes with a con of affecting multiple players at once even though some players may not be hacking. What do I mean by affecting multiple players? Well Ping, if a client has bad ping it can result in the client being teleported back to their last position, this results in a very unpleasant user experience.
Client:
Another way to make an Anti Teleport system is through Local Scripts, with the same method mentioned above. This pretty pointless to do any type of anti cheat on the client because it can be removed by the client. Anything that is available to the client, localscripts, etc can be deleted and modified.
So as a conclusion, I say stop trying to make these “Anti Cheats” on games.
All anti-exploits are not bad. There is a sweet area to anti-exploits, especially with anti speed and teleport systems. If you make your threshold reasonable, and don’t instantly kick players, anti-exploits can be pretty effective.
The exploiter can teleport around during that .6 seconds and then get back to the previous spot to avoid getting kicked. That’s not effective