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)