Improving anti-teleport system to account for ping

I thought about starting to create an Anti-Teleport system in my game and, so far, it is working well. I had to adapt it a lot, since my game has a teleport player system (inside the map) So far it has worked well and without any problems, however I’m testing at RobloxStudio, where I don’t have the real experience of a player playing and I’m also concerned with ping the players.I tested it and found that it can get in the way (of errors that the high ping itself generates)

an example of error is the ping itself (imagine), I recorded a video as an example:
I created a script that will teleport the player that plays to an x ​​position (that’s all).

note that for some reason, the player goes back to an old position and takes it back to its new position.

this is a problem because the script understands it as if it had teleported, when it didn’t!

I would like to know how I could adapt my script for players who are pinging high

first script, it creates a “StringValue” in ServerScriptService (a safe place and out of reach of Exploiters) with the name of the player when he enters. In this String Value, my idea was that I could change its Value (in this case, its Text) depending on the situation in which the player was, for example, if he was playing normally on the map (without touching any teleporter) his text would be: “World” and, if he touches a teleporter, the text would be: “Teleport” to indicate that, the reason his magnitude is high is because he touched a teleporter(a legal Teleport Server System).

game.Players.PlayerAdded:Connect(function(plr)
	local stringg = Instance.new("StringValue",game.ServerScriptService)
    stringg.Name = plr.Name
stringg.Value = "World"
db = false
end)
workspace.teleporter.Touched:Connect(function(hit)
	if hit.Parent:FindFirstChild("HumanoidRootPart") then
		if db == false then db = true
		hit.Parent.Humanoid.WalkSpeed = 30
		local touch = game.ServerScriptService:FindFirstChild(hit.Parent.Name)
		touch.Value = "Teleport"
				
		hit.Parent.HumanoidRootPart.CFrame = workspace.GrassPlate.CFrame * CFrame.new(50,20,10)
		end)
end
end)
--just below I added more parameters to the script, but I will not put it so that the post doesn't get too big (if it hasn't already)

in other scripts I asked him to check every 1 second and,if he touches another type of teleporter (to send the player back to the map),the value of StringValue would be equal to “Teleport to”.

coroutine.resume(coroutine.create(function()	
game.Players.PlayerAdded:Connect(function(player)
	player.CharacterAdded:Wait()
	local db = false
	
	local character = player.Character
	coroutine.resume(coroutine.create(function()
	workspace.Part.Touched:Connect(function(hit)
	
	if hit.Parent:FindFirstChild("Humanoid") then
	if db == false then db = true
	game.ServerScriptService:FindFirstChild(hit.Parent.Name).Value = "Teleport to"
	hit.Parent.HumanoidRootPart.CFrame = CFrame.new(100,0,0) --(teleport player to Map)
wait() db = false
end
end
end)	
end))
coroutine.resume(coroutine.create(function()
	player.Character.Humanoid.Died:Connect(function()
		player.CharacterAdded:Connect(function()
			character = player.Character
		end)
	end)
end))

while wait() do
		
		if player.Character:FindFirstChild("HumanoidRootPart") then
			local pos1x = player.Character.HumanoidRootPart.Position.X
			local pos1z = player.Character.HumanoidRootPart.Position.Z
			local pos1 = Vector3.new(pos1x,0,pos1z)
			wait(1)
			if player.Character:FindFirstChild("HumanoidRootPart") then
			local pos2x = player.Character.HumanoidRootPart.Position.X 
			local pos2z = player.Character.HumanoidRootPart.Position.Z
			local pos2 = Vector3.new(pos2x,0,pos2z)
			
			print((pos1 - pos2).magnitude)
			local mag = (pos1 - pos2).magnitude
			local valuer = game.ServerScriptService:FindFirstChild(player.Name).Value
			if mag > 40 then
				if character.Humanoid.Health > 0 then
				
				wait()
				print(valuer)
				if valuer == "Teleport" then
					print("okay, his magnitude is high because he touched a teleporter")
					
					elseif valuer == "World" then
				
						player:Kick("Teleport. Stop it!")
						
				
					elseif valuer == "Teleport to" then print("all right, he just entered the world")
					 
					end
					
				end
			end
			
		end
	end
end)
end))

my question is: how would i adapt this script to ping the player? or something so that the system does not fail and ends up kicking an innocent player that has a high ping?

another doubt:I created this script from scratch, without any help, is there anything wrong with it or some way to make it better?

2 Likes

youre probably thinking of this in a bit of a wrong way
i think you just want a simple system that can detect if a player moved way more than they should’ve, but also want to let it not be detected by the teleport system in your game

doing this is pretty easy

  1. create a bindable event somewhere in ServerStorage. This will allow your teleport script to communicate with your anti-teleport script

  2. when the server teleports every player, fire that bindable event.

the anti-teleport code might look something like this. it doesn’t touch the player, so its secure and shouldnt cause issues with ping:

    canTP = false
oldPositions = {} -- store each player's old position to detect how much theyve moved
-- format is like {string:"playerName", Vector3:Position}

tpThreshold = 50  -- how far can the player move each check cycle

game:GetService"ServerStorage".BindableEvent.Event:connect(function()
    canTP = true
    wait(2)
    canTP = false -- make sure server gives player ample time to teleport before enabling security again
end)


while wait(2) do
    local newPlrTable = {}
    for i,plr in pairs(game:GetService"Players":GetPlayers()) do
        local playerTable = nil
        
        -- get the player's last position
        for x,v in pairs(oldPositions) do
            if (v[1] == plr.Name) then
                playerTable = v
                break;
            end
        end

        -- find out how much the player's moved
        if (playerTable) then
            local oldPos = playerTable[2]
            local dPos = (plr.Character.HumanoidRootPart.Position-oldPos).magnitude

            if (dPos > tpThreshold) and (not canTP) then
                warn(playerTable[1].." probably just teleported")
                -- do whatever to the teleporter
            end
        end

        -- store player's new position
        local newPlayerInfo = {plr.Name, plr.HumanoidRootPart.Position}

        -- add it to the new table
        table.insert(newPlrTable, newPlayerInfo)
    end

    -- finally, update the official player data table
    oldPositions = newPlrTable
end
2 Likes

your idea is to check the magnitude and when the player teleports (with a game teleport) I connect a function,instead of using a StringValue,Correct?. It’s a good idea, I’ll test it.
However, is there any delay in the connection of the bindable event?

there shouldnt be any delay on the script that calls the event, since it just sends a signal to the other script

a delay would only be caused if it was a bindable FUNCTION.

Oh yes, I understand. I just have one last question:
I realized that this system you created is universal, that is, I don’t need to create a function for each player because it already checks all players. example: if any player teleports (a hacker), but another player used the teleporter (from the map) at the same time, he will leave unscathed

I tried to follow your pattern (PlrName, CanTP = (false or true)) but I couldn’t, can you help me?
my script:

game.Players.PlayerAdded:Wait()
local canTP = {}

local oldPositions = {}
local tpThreshold = 50  

--CanTpEvent
game:GetService"ServerStorage".canteleport.Event:connect(function()    

for i,v in pairs (canTP) do
	print(v)
	print(v[1]) -- (plr.Name)
	print(v[2]) --for some reason v [2] is nil, even though I set "Cantp = false" at the end of    --the script
end
v[2] = true	
    wait(2.5)
v[2] = false
  
end)


while wait(2) do
    local newPlrTable = {}
	local newcantp = {}    
for i,plr in pairs(game:GetService"Players":GetPlayers()) do
        local playerTable = nil
        newinsertp = nil
     
        for x,v in pairs(oldPositions) do
            if (v[1] == plr.Name) then
                playerTable = v

                break;
            end
        end

		for a,b in pairs (canTP) do
			if (b[1] == plr.Name) then
				newinsertp = b
			end
		end

        if (playerTable) and (newinsertp) then
            local oldPos = playerTable[2]
            local dPos = (Vector3.new(game.Players:FindFirstChild(playerTable[1]).Character.HumanoidRootPart.Position.X,0,game.Players:FindFirstChild(playerTable[1]).Character.HumanoidRootPart.Position.Z) -oldPos).magnitude
			print(dPos)

            if (dPos > tpThreshold) and (newinsertp[2] == false) then
				
                warn(playerTable[1].." probably just teleported")
				plr:Kick("Teleport")
            
        end
end		
		if not plr.Character then plr.CharacterAdded:Wait() end
		local newvec = Vector3.new(plr.Character.HumanoidRootPart.Position.X,0,plr.Character.HumanoidRootPart.Position.Z)
		        
        newPlayerInfo = {plr.Name, newvec}
		
		local newcan = {plr.Name,Cantp = false}  
		table.insert(newcantp,newcan)
		
       
        table.insert(newPlrTable, newPlayerInfo)

    oldPositions = newPlrTable
canTP = newcantp
end

I’m trying to do the same as you did with “OldPositions” but I’m not getting