Would this anticheat detect teleporting?

I am making an anticheat, and I would do a true do loop when the character is added. This is what I am doing:

		coroutine.resume(coroutine.create(function()
			local oldposition = nil
			local detected = false
			while true do
				if oldposition == nil then
					oldposition = Root.Position
				else
					local newpos = Root.Position
					local Distance = (oldposition - newpos).Magnitude
					if Distance >= 80 then
						if detected == false then
							Root.CFrame = CFrame.new(Root.Position)
							Root.Anchored = true
							detected = true
							coroutine.resume(coroutine.create(function()
								wait(3)
								Root.Anchored = false
								wait(5)
								detected = false
							end))
						else
							player:Kick()
						end
					end
					oldposition = Root.Position
				end
				wait(1/60)
			end
		end))

(I am using a custom wait, allowing me to wait quicker than 1/30.)

No, this does not detect teleporting. If this is all wrapped in a PlayerAdded function “oldpos” will be saved as the position that the HumanoidRootPart was at when the player first joined the game, then it will constantly loop and see if the current HumanoidRootPart position is 80 studs away from the old position. So if the player walks 80 studs away from the spawn point, they will be kicked.

Making anticheats can be very tedious and use up unnecessary server memory as well as they can detect false positives which may kick an innocent player if the were lagging or some type of physics bug happened which ended up flinging the player which to the server may seem like teleporting. User experience always comes first, you don’t want a player to stop playing your game because they were kicked do to a false positive. For these reasons I encourage you to not make an anticheat.

2 Likes

This is in a CharacterAdded function, if I would still face the same issue in a characteradded event, how would I disconnect the loop when the player dies, and then reconnect when they respawn?

Although, good advice, but I want to make a baseline for an anticheat so further down the line I can make something that is accurate, as this is my first time making something like this.

You can’t :Disconnect() a while loop, but you can break it. Though there wouldn’t be a real reason to break this while loop. Also, since you’re waiting 1/60 of a second with a custom wait function, why not just use heartbeat? It’s much better than yielding the entire script and it will get rid of that ugly coroutine.

Once again, I do not encourage you to use this in any game you are making. Though, it is fine for learning purposes.

1 Like

One more question, printing the Distance comes out as 0 even though the new position and old position are different when I teleport the player up in the air.

			local oldposition = nil
			local detected = false
			while true do
				if oldposition == nil then
					oldposition = Root.Position
				else
					local newpos = Root.Position
					local Distance = (newpos - oldposition).Magnitude
					print(oldposition, newpos)
					if Distance >= 80 then
						if detected == false then
						Root.CFrame = CFrame.new(Root.Position)
						Root.Anchored = true
						detected = true
						coroutine.resume(coroutine.create(function()
							wait(3)
								Root.Anchored = false
								wait(5)
								detected = false
							end))
						else
							player:Kick()
						end
					end
				end
				game:GetService("RunService").Heartbeat:Wait()
				oldposition = Root.Position
			end

From reading the script I think you detect teleportation as if the player moves from one position to another very quickly twice in a span of 5 seconds, then that player will be kicked. Not sure why you anchor the HumanoidRootPart on the first detection though. I added a cooldown time which is kind of like a debounce, it will only run all of that code every time a certain amount of time passes defined in the “coolDownTime” variable and it utilizes os.time() to do so. I also removed the while loop and replaced it with a heartbeat. As for distance printing 0, I don’t seem to get that error in my script. Maybe there’s something interfering with the code you provided somewhere else in the script. Here’s the code that I used to replace yours:

local coolDownTime = 0.1
local startTime = os.time()

game.Players.PlayerAdded:Connect(function(player)
	local character = player.Character or player.CharacterAdded:Wait()
	local Root = character.HumanoidRootPart
	local oldposition = nil
	local detected = false
	game:GetService("RunService").Heartbeat:Connect(function()
		if os.time() - startTime >= coolDownTime then
			if oldposition == nil then
				oldposition = Root.Position
			else
				local newpos = Root.Position
				local Distance = (newpos - oldposition).Magnitude
				print(Distance)
				if Distance >= 80 then
					if detected == false then
						Root.CFrame = CFrame.new(Root.Position)
						Root.Anchored = true
						detected = true
						coroutine.resume(coroutine.create(function()
							wait(3)
							Root.Anchored = false
							wait(5)
							detected = false
						end))
					else
						player:Kick()
					end
				end
			end
			oldposition = Root.Position
			startTime = os.time()
		end
	end)
end)

If you want to read up on RunService and os.time() here are some pages from the devhub and how to use os.time(): os.time(), Runservice, multiple use cases of os.time() / tick(). tick() is almost the same as os.time() except it’s relative to timezones where as os.time() isn’t.

1 Like