How do I make a good anti teleport system?

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?

3 Likes

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.

3 Likes

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.

2 Likes

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)

1 Like

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
3 Likes

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)```
2 Likes

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!

69 Likes

I’m not the recipient, but damn! This was amazing! Kudos.

2 Likes

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.

1 Like

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.

4 Likes

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!

3 Likes

I agree with the not kicking part, some people accidentally get flinged, in some games. And they end up getting kicked, or punished.

1 Like

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

Part Spawning Exploit

Deleting objects that aren't BaseParts from your Character on the client replicates to the server

Deleting Humanoid With A LocalScript Replicates To 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.

1 Like

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