Assistance writing anti-teleport code for game security

I have done some reading and know that I should be checking for large position changes from the server, but I have no clue where to begin code wise.

This is all uncharted territory. I have never worked with remote events or tried to create an anti exploit script.

How would I go about writing this?

1 Like

Alright, lets get in to it!

First thing you should keep in mind when writing a script for this is that anything on the client can be manipulated! This is extremely important for what we’re trying to achieve as we don’t want users to be able to bypass our anti-cheat by using metatables in order to spoof there location. So everything like this should be handled on the server for the maximum efficiency, but you should keep in mind that this also may cause random lagbacks if users have extremely bad ping.

Now you can do this two ways, checking the magnitude/distance by the players current location and there last location… or you could cast a ray and then figure out how long that said ray is. We’ll use the first way for now, if you want to learn the second way then feel free to ask!

So firstly we’ll want a table, your table could be named anything but for the sake of this anti-teleportation we’ll just call it lastLocations!

local lastLocations = {}

Boom, now we have a table. So this table is going to store all of the users last locations, we can then take the users current location and check the distance from there last location.

I’m assuming you want this anti-cheat to activate when the player first joins, so with that being said we will just use a join event.

local lastLocations = {}
local Players = game:GetService("Players")

function antiTeleport(Player)

end

Players.PlayerAdded:connect(antiTeleport)

Alright, now we have that. So where do we go from here? Well we know that a teleportation is a user moving from one location to another instantly/extremely quickly. So how do we go about fixing this? We can first make a loop which will saves the users old location.

while wait(timeBetweenChecks) do
--- This is the loop which will contain our checks!
end

Inside of this loop we need to make sure the player is alive, to do this we can just check if there character is a thing.

local Character = Player.Character
if Character and Character:FindFirstChild("HumanoidRootPart") then

end

That should do the trick! Okay, so we know the player is alive and in the game… now we actually make our anti-teleport at its core.

We will be using DistanceFromCharacter for this. So as it says we need a vector value, which is the value we will be storing inside our table (the users location from x amount of seconds ago)

local lastLocations = {} -- A table full of players and there last location
local Players = game:GetService("Players")

function antiTeleport(Player) -- Function that handles our antiTeleport
   local Character = Player.Character
   if Character and Character:FindFirstChild("HumanoidRootPart") then -- making sure the character is a thing!
      if lastLocations[Player] then -- Assuring our player is in the table!
         local distanceFromLast = Player:DistanceFromCharacter(lastLocations[Player])
         if distanceFromLast >= MAX_DISTANCE then
            -- Punish user accordingly, for this example we'll just teleport the player back!
            Character.HumanoidRootPart.Position = lastLocations[Player] -- Users current location for the next check
         end
         lastLocations[Player] = Character.HumanoidRootPart.Position
      else -- User isn't in our table, lets put them in!
         lastLocations[Player] = Character.HumanoidRootPart.Position -- A vector3 value
      end
   end
end

Players.PlayerAdded:connect(antiTeleport)

Disclaimer!

Everything here is untested and scripted within the devforums reply button, if something is wrong let me know!

20 Likes

Wow, thank you for this really in-depth explanation! Though something I should have mentioned is that the player characters are actually spheres with set network ownerships, not default characters.

Thats alright, rather then using the humanoidRootPart’s position just use the spheres!

lastLocations[Player] = playersSphere

2 Likes

Thanks a whole lot, I will get right on it.

Something that would be better to clarify is that MAX_DISTANCE should be set to relatively the same amount of speed that a character is walking or in this case whatever it is they are controlling.

Take the default walkspeed of 16 studs per second. So your MAX_DISTANCE should be ~16 obviously more due to latency, ping, etc.

Problem with this is the lag, and the OP is using a custom sphere apparently.

1 Like

The sphere still has some sort of movement velocity :slightly_smiling_face: this would still apply that the MAX_DISTANCE should be relative to the amount of studs they move per second.

1 Like

Not true

Your and statement will start with the first condition, if its true then it will move on to the next one.

If the first condition (Character) is nil then it wont continue the statement,

The and operator returns the first argument if it is false or nil , otherwise it will return the second argument.

2 Likes

Whoops, that’s my bad; I’ll delete my original post. An actual issue with your script is setting the HumanoidRootPart’s Position, since setting position directly can have weird effects (see below), and you generally want to set CFrame to teleport a character.
The issue with setting Position:
https://gyazo.com/a9b5211506768bf19d57eab13418c7aa.mp4

2 Likes

Yeah, you’re right. SetPrimaryPartCFrame would be better.

3 Likes

What happens if the server is moving a character somewhere? Would you remove the table value of the players position during teleportation from the server? Are you accounting for exploiters being able to create their own character that cannot be detected by this?

1 Like

An exploiter creating there own character? That would only be viewed by the client and the scripts provided are on the server.

What I posted is just a basic rundown on how you could make something like this… to add a bypass for a user teleporting just make a variable if the user can bypass it or not.

local lastLocations = {}
lastLocations[Player] = {
   lastLocation = Vector
   canBypass = false
};

Check if the users bypass value is false and then continue with the check.

Agreed, one of the many problems with FE. Is how the character works. Though if that was the case you could just check if the HumanoidRootPart exist, if it doesn’t then you know they created a custom character because due to how FE replication works with the character it would of replicated the destruction of the HumanoidRootPart to the server. We do that with humanoids to detect the “FE godmode”.

OP stated that his character is a custom ball.

Still can be done if the character is done in a certain way as seen in this POC.rbxl (14.7 KB) This was a quick whip up example, so code could of been done better.

Even if you check if the HumanoidRootPart exist, they can create their own proxy character that runs completely separate from the player.Character model. I’ve rarely seen this happen but it’s out there.