Is it possible to consider laggy players during anti-cheat?

The title is self-explanatory. I’m doing an anti-teleport system, but I keep failing to detect laggy players. Is it even possible to??

type plrPositions = {
	[Model] : {
		HumanoidRootPart : BasePart,
		Player : Player,
		Last : Vector3, 
		CanTeleport : boolean,
	}
}

local plrs = game:GetService("Players")
local RS = game:GetService("RunService")

local tp1 = workspace.TP1
local tp2 = workspace.TP2

local maxDistance = 5
local lastTime = os.clock()

local plrPositions : plrPositions = {}

type plrPosition = typeof(plrPositions[Instance.new("Model")])

local function watchPlayerPosition(char : Model, data : plrPosition, elapsed : number) : ()
	local canTeleport = data.CanTeleport

	if not char:IsDescendantOf(game) then
		plrPositions[char] = nil

		return			
	end

	local HRP = data.HumanoidRootPart
	local plr = data.Player

	local current = HRP.Position

	if not canTeleport then
		local ping = plr:GetNetworkPing()

		local velocity = HRP.AssemblyLinearVelocity

		local verticalSpeed = velocity.Y

		local difference = current - data.Last
		local expectedMaxDistance = velocity.Magnitude * (elapsed + (1 + ping * 5))

		local fallbackMaxDistance = maxDistance * (1 + ping * 5)

		local possibleSuspiciousMovement = (velocity.Magnitude < 1 and verticalSpeed > -1)

		local bigJump = difference.Magnitude > fallbackMaxDistance

		local movedTooFar = difference.Magnitude > expectedMaxDistance

		if (possibleSuspiciousMovement or movedTooFar) and bigJump then
			HRP.Anchored = false

			HRP.CFrame = CFrame.new(data.Last)

			return
		end
	end

	data.Last = current
end

local function watchPositions(elapsed : number) : ()
	for char, data in plrPositions do
		task.spawn(pcall, watchPlayerPosition, char, data, elapsed)
	end
end

local function watchPlayer(char : Model, plr : Player) : ()
	local HRP = char:WaitForChild("HumanoidRootPart") :: BasePart

	plrPositions[char] = {
		HumanoidRootPart = HRP,
		Player = plr,
		Last = HRP.Position,
		CanTeleport = false,
	}
end

local function wormholeTouched(hit : BasePart, wormhole : BasePart) : ()
	local model = hit:FindFirstAncestorOfClass("Model")

	if not model then return end

	local HRP = model:FindFirstChild("HumanoidRootPart")

	if not HRP then return end

	local target = wormhole == tp1 and tp2 or tp1

	plrPositions[model].CanTeleport = true

	model:PivotTo(CFrame.new(target.Position) * CFrame.new(5, 0, 5))

	RS.Heartbeat:Wait()

	task.wait()

	plrPositions[model].CanTeleport = false
end

local function onPlayerAdded(plr : Player) : ()
	plr.CharacterAdded:Connect(function(char)
		watchPlayer(char, plr)
	end)
end

plrs.PlayerAdded:Connect(onPlayerAdded)
RS.Heartbeat:Connect(watchPositions)

tp1.Touched:Connect(function(hit)
	wormholeTouched(hit, tp1)
end)

tp2.Touched:Connect(function(hit)
	wormholeTouched(hit, tp2)
end)
2 Likes

You could do a violation based system to count how many times it is violated and only act if a user has persistently violated the anti-teleport so many times and you would obviously only do this for small magnitude changes to consider laggy players.

1 Like

Maybe, but that may not work since I could have 2K ping, and I would be punished after some violations, no?

You could loosen the security for player’s with high ping.

Read: Player | Documentation - Roblox Creator Hub

Just realised you are already doing something like this - if you detect insane ping you could provide more buffer.

Yea, but that’s the problem I’m facing.

It’s not precise; it doesn’t return the replication lag itself, which would be expected.

You could create your own replication lag detection system manually using a remote event and a local script to calculate (server sends ping, detects when client returns pong and do this repeatedly).

Although then exploiters would be able to make it seem like they are lagging.

yes, exploiters could easily do anything they want /:

i was thinking about an average position magnitude system

Possible but it still doesn’t prevent teleporting if a cheater moves in intervals consistently and won’t that mean laggy players could still be effected if they freeze or get a massive movement update when they stop lagging.

yea, so is there any way at all?? I can’t think of anything because laggy players are already really similar enough to exploiters, about TPing to places

I think in some way you would have to just trust the client.

You could do the replication lag detection idea and try to secure it using obfuscation (not just the script but renaming remotes or mixing in junk data or encoding the payload - just to try make it harder) and handshaking.

I would use a RemoteFunction and the server sends a request to the client with the current timestamp and a nonce and then the client immediately responds with both values and then the server compares the difference and the nonce and the frequency of the late responses to detect fake lag.

1 Like

If I somehow get the replication lag, what should I do with it?

But, indeed, I could get it and compare with the server one to see if it’s not that different

Take that into consideration instead of GetNetworkPing() since it’s more reliable.

I would honestly also compare GetNetworkPing and the replication lag since there will be some kind of pattern (again to prevent exploiters faking lag).

1 Like

But would that consider laggy players then?

EDIT: Are there any formulas I can use to make it more certain that it is a laggy player

I believe so since you said the only problem with :GetNetworkPing() is it doesn’t take into account replication lag.

So I would use your own replication lag system to ensure it is accurate.

And then obviously do something on the server-end to ensure that exploiters aren’t just faking replication lag in order to teleport by comparing it to the player’s network ping.

Something like:

local expectedPing = player:GetNetworkPing() / 2 -- / 2 because we're using a one way system
local collectedPing = serverTime / clientEchoTime

local difference = math.abs(expectedPing - collectedPing)

if difference > 0.3 then -- 300ms
      print("difference is over 300ms - client could be faking lag")
end
2 Likes

Also, I’ve noticed that if you go to the wormhole and gets teleported, I wanted to make it so it doesn’t flag and the player gets teleported normally

but if the player is laggy, it would still flag because the “CanTeleport” would be false before they actually teleported

If the teleporting actually occurs on the server (the server script is modifying the CFrame of the player) then it shouldn’t be a problem.

If you’re doing it on the client then change it to fire a remote event to teleport which automatically toggles off the anti teleport system, moves them and re-enables the anti-teleport.

Yes, but sometimes the player is not “teleported fast enough” until “CanTeleport” is false. It’s something like:

Players goes to wormhole → Due to lag, they don’t get positioned before CanTeleport is set to false → CanTeleport is set to false → They teleport, it consider as exploiting

But if you’re doing the checks on the server end and the server end is moving their CFrame it shouldn’t be a problem - I believe?

If not you could add a grace period based on their replication lag and network ping.

yes but apparently it’s still error’ing. Let me show you a video of someone testing it:

Uploading: 0800_15072025_033825.mp4…

EDIT: The video bugged, but anyway…