Modular Anticheat - Anti-Fly Module Review

I’m working on an experimental modular anticheat where systems and methods are compiled into their own modules and executed by just one loader.

This is an anti-fly module. I added little patches here and there while testing in-game. I’m satisfied that it works well now. However, I took a whatever-floats approach on the patching, and I feel the module has at least some code smell.

I’m stuck on what to fix without touching the current mechanic.
I need help reviewing if there are indeed bad practices in the code, and what can be changed. Any help is appreciated, and thank you in advance!

AntiFly.lua
--[[ AntiFly
Raycast downwards, X positive, Z positive, X negative, Z negative, by how much
	a player can possibly jump
Collect results. If results are blank or over the jump limit, player may be flying. 
Start a timer. Collect current position.
Timer ends: Player is flying if the comparisons show that:
- Player is not grounded
Optionals:
- Raycasting downwards still returns nil or is not less than 
- Y velocity is going higher instead of negative or slower
- Player's Y doesn't fluctuate much as in jumping, which means something unusual is keeping them up
]]

local AntiFly = {}
local leeway = 3
local StarterPlayer = game:GetService("StarterPlayer")

local function getMaxJumpHeight (JumpPower)
	return math.pow(JumpPower,2) / (2*workspace.Gravity)
end

local function RayDown(char)
	local HRP = char.HumanoidRootPart
	local RayParams = RaycastParams.new()
	RayParams.FilterType = Enum.RaycastFilterType.Blacklist
	RayParams.FilterDescendantsInstances = {char}
	
	local maxJumpHeight = getMaxJumpHeight(char.Humanoid.JumpPower) + char.Humanoid.HipHeight + leeway
	
	local results = workspace:Raycast(HRP.Position, Vector3.new(0,-(maxJumpHeight*2),0), RayParams)
	if not results then return nil end
	return results.Position
end

local function IsOnGround (char)
	local Humanoid = char.Humanoid
	local HRP = char.HumanoidRootPart
	
	local GroundArea = Region3.new(
		HRP.Position+Vector3.new(0,-2-Humanoid.HipHeight,-2), 
		HRP.Position+Vector3.new(2,1-Humanoid.HipHeight,0)
	)
	
	local checks = {
		["Floor"] = (Humanoid.FloorMaterial ~= Enum.Material.Air);
		["Region3"] = (workspace:FindPartsInRegion3(GroundArea, char,math.huge)[1] ~= nil);
		["Ray"] = (RayDown(char) ~= nil);
	}
	
	if 	(checks["Floor"] and (checks["Ray"] or checks["Region3"])) or  --
		(checks["Region3"])
	then return true end
	return false
end


local function Check(char, player, flagEvent)
	local Humanoid = char.Humanoid
	local HRP = char.HumanoidRootPart
	local flags = 0

	if Humanoid.SeatPart then return flags end
	if IsOnGround(char) then return flags end
	
	--print("On air. Start check")
	coroutine.wrap(function()
		local lastHRPPos = HRP.Position
		local lastHRPVel = HRP.Velocity
		local lastRay = RayDown(char)
		wait(3)
		local currentRay = RayDown(char)
		local conditions = {
			["YVelocity"]=(HRP.Velocity.Y > lastHRPVel.Y + leeway);
			["Fluctuation"]= (math.abs(lastHRPPos.Y-HRP.Position.Y) < leeway);
			["Ray"] = (currentRay == nil or lastRay and lastRay.Y < currentRay.Y);
		}
		
		if 	not IsOnGround(char) and (
				(conditions["YVelocity"] and conditions["Fluctuation"]) or
				(conditions["Ray"] and conditions["Fluctuation"])
			)
		then
			--print("Flying Flag!")
			--for i,v in pairs (conditions) do print(i, v) end 
			flagEvent:Fire()
		end
	end)()
	
	return flags
end


function AntiFly.BindCheck(char, player)
	local flagEvent = Instance.new("BindableEvent")
	local flags = 0
	
	player.CharacterRemoving:Connect(function()char = nil flagEvent = nil end)
	char.Humanoid.Died:Connect(function() char = nil flagEvent = nil end)
	
	coroutine.wrap(function()
		while char do 
			wait(1)
			Check(char,player,flagEvent)
			if flags >= 5 then player:LoadCharacter() end
		end
	end)()
	
	flagEvent.Event:Connect(function() flags = flags+1 end)
end

return AntiFly 

(GitHub file for a more readable version)

3 Likes

Do players that get flinged randomly by physics or by players get marked as flying?

You should also add checks for unauthorized tools in the player’s backpack or a BodyForce/BodyGyro in their torso.

1 Like