Anti TP script help

I am making an anti teleport script. The goal is for each second, it will count each player with a character location, then it will store each player in a table list and compare it to their last location, if the vector value of x and z have changed a lot, it will recognize this as them being suspicious then it will run the scannearbyplayers function and check if there is an admin nearby (this way it can see if an admin just teleported them etc.)

I’ve scripted some of this, but I am not very experienced with tables so I’m not sure how to do the rest. If anyone is and can help out, so that I can read and learn from them I would appreciate it!

local Players = game:GetService("Players")

local StaffRankNum = 249

local list = {}

local function ScanNearbyPlayers(targPlayer)
	for _,player in pairs(Players:GetPlayers()) do
		if player.Character and player.Character.PrimaryPart then
			local distance = player:DistanceFromCharacter(targPlayer.Character)
			
			if distance <= 100 then
				if player:GetRankInGroup(4525406) >= StaffRankNum then --near staff
					return
				else
					targPlayer.Character.Health = 0 -- not near staff and teleporting
				end
			end
			
		end
	end
end

while true do
	wait(1)
	
	for _,player in pairs(Players:GetPlayers()) do
		wait(.5)
		
	end

end

Also, I forgot to mention. I know that scanning each second on the server could take up space, so I decided that I would also have a small .5 second wait between each player scan so that it isn’t taking up too much processing speed.

Use Magnitude checks to see the distance from their previous position.

Fixed code:

--//Services
local Players = game:GetService("Players")

--//Controls
local StaffRankNum = 249

--//Functions
local function IsStaffNear(playerPosition)
	for i, player in ipairs(Players:GetPlayers()) do
		if player:GetRankInGroup(4525406) < StaffRankNum then
			continue
		end
		
		local character = player.Character
		local humanoidRootPart = character and character:FindFirstChild("HumanoidRootPart")
		
		if not humanoidRootPart then
			continue
		end
		
		local distance = (playerPosition - humanoidRootPart.Position).Magnitude
		
		if distance <= 100 then
			return true
		end
	end
	
	return
end

Players.PlayerAdded:Connect(function(player)
	player.CharacterAdded:Connect(function(character)
		local humanoidRootPart = character:WaitForChild("HumanoidRootPart")
		local previousPosition = humanoidRootPart.Position
		
		while task.wait(1) and character:IsDescendantOf(workspace) do
			local playerPosition = humanoidRootPart.Position
			local distance = (playerPosition - previousPosition.Position).Magnitude
			
			if distance >= 50 and IsStaffNear(playerPosition) then
				--//I would personally use :LoadCharacter instead
				pcall(player.LoadCharacter, player)
			end
		end
	end)
end)

Wouldn’t this lag the server? You would be creating an event task for each character instead of globally checking.

It would perform pretty similarly because even though I’m creating more loops, it’s only checking 1 character, contrary to just 1 loop, that checks every player ingame.

You can rewrite the code if you want to but another benefit of having separate loops is that it won’t have to yield for all the Magnitude checks of other players to end before starting the loop again.

example of how you could store each player’s position in a table and compare it to their last position (sorry for poor code written)

local StaffRankNum = 249
local list = {}

local function ScanNearbyPlayers(targPlayer)
    for _,player in pairs(Players:GetPlayers()) do
        if player.Character and player.Character.PrimaryPart then
            local distance = (player.Character.PrimaryPart.Position - targPlayer.Character.PrimaryPart.Position).magnitude
            if distance <= 100 then
                if player:GetRankInGroup(4525406) >= StaffRankNum then --near staff
                    return
                else
                    targPlayer.Character.Humanoid.Health = 0 -- not near staff and teleporting
                end
            end
        end
    end
end

while true do
    wait(1)
    for _,player in pairs(Players:GetPlayers()) do
        if player.Character and player.Character.PrimaryPart then
            local currentPosition = player.Character.PrimaryPart.Position
            local lastPosition = list[player]
            if lastPosition then
                local distance = (currentPosition - lastPosition).magnitude
                if distance > 100 then -- Change this value to adjust the threshold for what is considered "teleporting"
                    ScanNearbyPlayers(player)
                end
            end
            list[player] = currentPosition -- Store the current position for the next check
        end
    end
end

you can check this out for reference