Can I improve this server-side anti-exploit magnitude checker?

Hi, I just made a script that checks every second to see if a player hasn’t walked too far in that one second. If this is the case, the player will teleport back to his original position.

local function onPlayerAdded(player: Player)
	local function onCharacterAdded(character: Model)
		local humanoid = character:WaitForChild("Humanoid") :: Humanoid

		local primaryPart: BasePart = character.PrimaryPart or character:GetPropertyChangedSignal("PrimaryPart"):Wait()
		local primaryPartCFrame: CFrame = CFrame.new(0, 0, 0)

		while true do
			if not primaryPart then return end

			local magnitude: number = (primaryPartCFrame.Position - primaryPart.CFrame.Position).Magnitude
			primaryPartCFrame = primaryPart.CFrame

			print(magnitude)

			local isMagnitudeHigherThanWalkspeed: boolean = if magnitude > (humanoid.WalkSpeed + 3) then true else false
			if isMagnitudeHigherThanWalkspeed then primaryPart.CFrame = primaryPartCFrame end

			task.wait(1)
		end
	end

	player.CharacterAdded:Connect(onCharacterAdded)
end

game:GetService("Players").PlayerAdded:Connect(onPlayerAdded)

I’m still looking to improve this script. If anyone has a comment, don’t be afraid to use the reply button!

2 Likes

I think it would’ve been simpler if you used tenary operators instead like this:
magnitude > (humanoid.WalkSpeed + 3) and true or false

You could’ve just set the network owner to nil for 5 seconds like bedwars anticheat does.
It should look something like this:

primaryPart:SetNetworkOwner(nil)
task.delay(5,function() primaryPart:SetNetworkOwner(player) end)

Also you should use while character do instead, since loops still run after the character dies, so if the player dies 100 times then there will be 100 loops which will slow down the server A LOT

Edit: This solution apparently does not work, instead you should define an “alive” variable which is used to run the loop if its true, and when the character dies, set the alive variable to false (by the using Humanoid.Died event)

Therefore the script should be like this:

        local alive = true
		char.Humanoid.Died:Connect(function()
			alive = false
		end)
		while alive do
             --rest of the script here

I’m quite surprised no one pointed out my mistake.

1 Like

hi
this has a vulnerability in it where players can delete their humanoidrootpart to prevent the script from seeing their last position due to this “if not primaryPart then return end”
I suggest adding a childremoved check on the character to prevent them from removing any baseparts, this will prevent players from deleting their rootpart.

1 Like

Wouldn’t the server still see the PrimaryPart as the exploits are run on the client?

Hi there;

The answer you want is in fact, no, the server would not see the PrimaryPart as the Client usually (unless implicitly set by the Server) has NetworkOwnership of their entire Character, meaning if they delete something in it, it will replicate.

However, when the HumanoidRootPart is removed, depending on the game and some other factors, their exploits become handicapped since they effectively break their ability to use tools/other humanoid dependent things.

Removing the HumanoidRootPart is rather uncommon though, and requires rather undesirable methods of character management on most exploiters ends.

1 Like