Help needed with a serverside anticheat to prevent speed exploiters

Hey there! I’m attempting to create a server side anti-cheat to prevent teleportation and speed exploiters. After about a day of trying different things, this works. ‘sort off’ It has MANY false positives and in particular an issue where after a player is ‘unfrozen’, the anti-cheat continues to rubber-band them back to their previous position unless they stand still for a few seconds. I’ve printed the distance values during these frequent episodes and they can range up to the hundreds which is particularly strange since there is no way the player had managed to move that distance within a frame after being frozen, resetting their velocity didn’t help much at all. Also for reference the vehicle seats are for boats that travel faster then the player so the anti cheat must account for that to.

I am not looking for ways to make this code run ‘faster’ NOR an argument on the best way to handle an anti-cheat like in many similar threads I’ve read where a conclusion was seemingly never reached. I’m just looking for a straightforward solution for this problem from hopefully someone who has made and uses a good anti-cheat. Also an anti-cheat is magnitudes of importance for this game since it is a PVP game.

ANTICHEAT CODE:

local players = game:GetService("Players")
local run  = game:GetService("RunService")

local Rep = game:GetService("ReplicatedStorage")
local GU = require(game:GetService("ReplicatedStorage"):WaitForChild("Modules"):WaitForChild("GameUtil"))
local Inflictions = require(game:GetService("ReplicatedStorage"):WaitForChild("Modules"):WaitForChild("StatusEffects"):WaitForChild("Inflictions"))
_G.playerMaxSpeed = {} -- exact numbers
local playerLastPosition = {}
_G.playerTeleported = {}
local playerFreezes = {}
local frozenPlayers = {}
local FallingThresholds = {}
local Pings = {}
local FreezeTolerance = {}


local DEFAULT_WALKSPEED = 16 -- default walkspeed
local STUD_SPEED_FREEDOM = 10 -- INCREASE IF PLAYERS ARE GETTING FALSELY KICKED/FROZEN - DECREASE IF EVERYONE IS TELEPORTING

local FREEZE_TIME = 0.5 -- how long they are frozen
local MAX_FREEZES = 3 -- if they have 3 freezes, kick them


players.PlayerAdded:Connect(function(player)
	_G.playerMaxSpeed[player] = DEFAULT_WALKSPEED
	--_G.playerTeleported[player] = true
	playerWarnings[player] = {}
	playerLastPosition[player] = nil
	playerFreezes[player] = {}
	FallingThresholds[player] = 0
	Pings[player] = {}
	FreezeTolerance[player] = 0
end)

players.PlayerRemoving:Connect(function(player)
	_G.playerMaxSpeed[player] = nil
	playerWarnings[player] = nil
	playerLastPosition[player] = nil
	playerFreezes[player] = nil
	
	_G.playerTeleported[player] = nil
	
	FallingThresholds[player] = nil
	Pings[player] = nil
end)

local ElpasedSinceLastCast = 0.2 + tick()


local ElapsedSinceLastPing = 0.3 + tick()


run.Heartbeat:Connect(function(dt)
	for _,player in pairs(game.Players:GetPlayers()) do
		if player.Character then
			
			local char = player.Character
			
			local Trackingpart = char.PrimaryPart
			
			if Trackingpart and Trackingpart == char:FindFirstChild("HumanoidRootPart") and playerWarnings[player] then
				
				local CheckSpeed = _G.playerMaxSpeed[player]
				
				local hum = char:FindFirstChild("Humanoid")
				
				if hum and hum.SeatPart then
					if hum.SeatPart:IsA("VehicleSeat") then
						CheckSpeed = hum.SeatPart.MaxSpeed
						
					elseif hum.SeatPart.Parent:FindFirstChild("VehicleSeat") then
						CheckSpeed = hum.SeatPart.Parent:FindFirstChild("VehicleSeat").MaxSpeed
					end
				end
				
				
				if #playerFreezes[player] > 3 then
					player:Kick("Exploiting is prohibited")

				elseif #playerFreezes[player] > 0 then
					for key,Freeze in pairs(playerFreezes[player]) do
						
						if tick() - Freeze > FREEZE_TIME then
							
							table.remove(playerFreezes[player],key)
						end
						
						FreezeTolerance[player] = CheckSpeed
						
						Trackingpart.Velocity = Vector3.new(0,0,0)
						
						if hum and hum.SeatPart and hum.SeatPart:IsA("VehicleSeat") then
							hum.SeatPart.Parent.PrimaryPart.Velocity = Vector3.new(0,0,0)
						end
					end
					
					if #playerFreezes[player] == 0 then
						
						char.PrimaryPart.Anchored = false
					end
				end
				

				playerLastPosition[player] = playerLastPosition[player] or Trackingpart.Position

				
				local CurrentPosXZ = Vector3.new(Trackingpart.Position.X,0,Trackingpart.Position.Z)
				
				local OldPosXZ = Vector3.new(playerLastPosition[player].X,0,playerLastPosition[player].Z)
				
				
				
				--local DistanceCovered = (((CurrentPosXZ - OldPosXZ).Magnitude / dt)/(1+(Pings[player]["ClientTime"] or 0)))/STUD_SPEED_FREEDOM
				
				local freedom = STUD_SPEED_FREEDOM + (Pings[player]["ClientTime"] or 0) + FreezeTolerance[player]
				
				local DistanceCovered = ((CurrentPosXZ - OldPosXZ).Magnitude / dt) - freedom
				
				FreezeTolerance[player] = 0
				
				
				
				if DistanceCovered > CheckSpeed and not _G.playerTeleported[player] then
					
					char:SetPrimaryPartCFrame(CFrame.new(playerLastPosition[player]))
					
					char.PrimaryPart.Anchored = true
					
					local currentime = tick()
					
					table.insert(playerFreezes[player],currentime)
					
					
				elseif _G.playerTeleported[player] then
					_G.playerTeleported[player] = nil
				end
				
				playerLastPosition[player] = char.PrimaryPart.Position
				
				
				if tick() > ElapsedSinceLastPing then
					
					ElapsedSinceLastPing = tick() + 0.3
					
					
					
					Pings[player]["ServerTime"] = tick()
					
					Rep.Relay.GetPing:FireAllClients()
				end
				
			else
				player:Kick("Exploiting is prohibited")
			end
			
		end
	end
end)

Rep.Relay.GetPing.OnServerEvent:Connect(function(player)
	
	Pings[player]["ClientTime"] = tick() - (Pings[player]["ServerTime"] or tick())
	
end)

Here is a good Reference for you, Hope this Helps. (It is serverside)

1 Like

The post you’ve redirected me to is likely to cause more false positives then my current code. Here I am using delta time from a heartbeat loop while they are just waiting one second before every check, robloxs task scheduling system can take LONGER then the outlined time before the next iteration which will cause false positives. I am using change in velocity / delta time to calculate my speed which gives much more accurate results as it accommodates for server lag.

1 Like

This thing may help, it can’t really be bypassed, so this may be your answer, sorry if I am advertising

Link: ----> Waffle AntiCheat - Roblox