For a past 3 days, I were working on my own anti-cheat, which should detect:
- Teleporting
- Walkspeed increase
- JumpHeight increase
- Air walking
- Air jumping
I have never dealt with anticheats and cheats before, so, I want to know - is it good? How I can improve it?
Note: Light/Heavy are gravity modifiers, Excuses added with my game specific SERVER things, like events, and impossible to get from client. Same for aleby.
local SSS = game:GetService("ServerScriptService")
local SS = game:GetService("ServerStorage")
local RS = game:GetService("ReplicatedStorage")
local Bindables = SS:WaitForChild("Bindables")
local RunService = game:GetService("RunService")
local Players = game:GetService("Players")
local CurrentItems = require(RS:WaitForChild("Libraries"):WaitForChild("CurrentItemsData"))
local IsLobby = (game.PlaceId == 16725804854 or game.PlaceId == 83201107517231)
local Module = {
Players = {}
}
local ModuleMeta = {}
ModuleMeta.__index = ModuleMeta
local Vector3XZ = Vector3.new(1, 0, 1)
local CheckDelay = 0.5
local function FuzzyEq(V1, V2, e)
local V3 = V1-V2
return (V3.X < e or V3.X > -e) and (V3.Y < e or V3.Y > -e) and (V3.Z < e or V3.Z > -e)
end
local function Vector3abs(v)
return Vector3.new(v.X>0 and v.X or -v.X, v.Y>0 and v.Y or -v.Y, v.Z>0 and v.Z or -v.Z)
end
local AffectorDetectParams = OverlapParams.new()
AffectorDetectParams.FilterType = Enum.RaycastFilterType.Exclude
AffectorDetectParams.FilterDescendantsInstances = {}
AffectorDetectParams.RespectCanCollide = true
local FloorDetectParams = OverlapParams.new()
FloorDetectParams.FilterType = Enum.RaycastFilterType.Exclude
FloorDetectParams.FilterDescendantsInstances = {}
FloorDetectParams.RespectCanCollide = true
FloorDetectParams.MaxParts = 1
local function OnCharacterRemoved(Player)
if Player.Parent then
Module.Players[Player].Character = nil
if Module.Players[Player].Connections.CharacterFell then
Module.Players[Player].Connections.CharacterFell:Disconnect()
Module.Players[Player].Connections.CharacterFell = nil
end
if Module.Players[Player].Connections.CharacterJumped then
Module.Players[Player].Connections.CharacterJumped:Disconnect()
Module.Players[Player].Connections.CharacterJumped = nil
end
if Module.Players[Player].Connections.CharacterLanded then
Module.Players[Player].Connections.CharacterLanded:Disconnect()
Module.Players[Player].Connections.CharacterLanded = nil
end
if Module.Players[Player].Connections.Touches then
for Part, Connection in Module.Players[Player].Connections.Touches do
Connection:Disconnect()
end
Module.Players[Player].Connections.Touches = nil
end
end
end
local function OnCharacterAdded(Player)
local Character = Player.Character
Module.Players[Player].Character = Character
Module.Players[Player].CheckData = {}
local Primary = Character.PrimaryPart
Module.Players[Player].AllowedSpeed = Vector3.new(Character.Humanoid.WalkSpeed, 0, Character.Humanoid.WalkSpeed)
Module.Players[Player].Connections.CharacterFell = Primary.AncestryChanged:Connect(function()
if Primary.Parent == nil then
OnCharacterRemoved(Player)
end
end)
Module.Players[Player].Connections.Touches = {}
for _, Part in Character:GetChildren() do
if Part:IsA("BasePart") and Part.CanCollide then
Module.Players[Player].Connections.Touches[Part] = Part.Touched:Connect(function(Other)
Module.Players[Player].Aleby.Affectors[Other] = DateTime.now().UnixTimestampMillis/1000 + (Other.AssemblyLinearVelocity.Magnitude/10)^0.5 + CheckDelay*1.1
end)
end
end
Module.Players[Player].Connections.CharacterJumped = Character.Humanoid.Jumping:Connect(function(State)
if State then
if Module.Players[Player].Aleby.AllowJump == 0 then
print("Player was disallowed to jump!!!")
table.insert(Module.Players[Player].Penalties, {
Time = DateTime.now().UnixTimestampMillis/1000,
Expire = DateTime.now().UnixTimestampMillis/1000 + 60,
Value = 2,
Data = {
Type = "DisallowedJump"
},
})
else
local HitboxCFrame, HitboxSize = Character:GetBoundingBox()
local WeightModifier = (Module.Players[Player].Aleby.Heavy and Module.Players[Player].Aleby.Heavy.Power or 1) / (Module.Players[Player].Aleby.Light and Module.Players[Player].Aleby.Light.Power or 1)
local JumpHeight = (Character.Humanoid.JumpPower*Character.Humanoid.JumpPower)/(workspace.Gravity*WeightModifier*2)*1.1
if Module.Players[Player].Aleby.Bounce then
JumpHeight += Module.Players[Player].Aleby.Bounce.Power
end
FloorDetectParams.FilterDescendantsInstances = {Character}
local CorrectJump = false
if Module.Players[Player].Aleby.AllowJump then
if Module.Players[Player].Aleby.Climbing then
local FloorJump = workspace:GetPartBoundsInBox(HitboxCFrame*CFrame.new(0, -(HitboxSize.Y+JumpHeight)/2, -(HitboxSize.Z+JumpHeight)/2), Vector3.new(HitboxSize.X, JumpHeight, JumpHeight), FloorDetectParams)
CorrectJump = #FloorJump == 1
else
local FloorJump = workspace:GetPartBoundsInBox(HitboxCFrame-Vector3.new(0, (HitboxSize.Y+JumpHeight)/2, 0), Vector3.new(HitboxSize.X, JumpHeight, HitboxSize.Z), FloorDetectParams)
CorrectJump = #FloorJump == 1
end
end
if not CorrectJump then
print("Player is air-jumping! " .. (Module.Players[Player].Aleby.Climbing == 1 and "Climbing" or "Ground"))
table.insert(Module.Players[Player].Penalties, {
Time = DateTime.now().UnixTimestampMillis/1000,
Expire = DateTime.now().UnixTimestampMillis/1000 + 60,
Value = 2,
Data = {
Type = "AirJump"
},
})
else
Module.Players[Player].Aleby.Jumping = {
Time = DateTime.now().UnixTimestampMillis/1000,
StartHeight = Character.PrimaryPart.Position.Y,
Power = JumpHeight,
Expiration = DateTime.now().UnixTimestampMillis/1000 + (Character.Humanoid.JumpPower/(workspace.Gravity*WeightModifier)) + CheckDelay*1.1
}
end
end
end
end)
local JumpAllowStates = {
Enum.HumanoidStateType.Landed,
Enum.HumanoidStateType.Seated,
Enum.HumanoidStateType.GettingUp,
Enum.HumanoidStateType.Swimming,
}
local JumpDisallowStates = {
Enum.HumanoidStateType.FallingDown,
Enum.HumanoidStateType.Ragdoll,
Enum.HumanoidStateType.Flying,
Enum.HumanoidStateType.PlatformStanding,
Enum.HumanoidStateType.Dead,
Enum.HumanoidStateType.Physics,
}
local ClimbNotCancelStates = {
Enum.HumanoidStateType.Climbing,
Enum.HumanoidStateType.Freefall,
Enum.HumanoidStateType.Jumping,
}
Module.Players[Player].Aleby.AllowJump = true
Module.Players[Player].Connections.CharacterLanded = Character.Humanoid.StateChanged:Connect(function(PrevState, NewState)
if NewState == Enum.HumanoidStateType.Climbing then
Module.Players[Player].Aleby.AllowJump = true
Module.Players[Player].Aleby.Climbing = {
Time = DateTime.now().UnixTimestampMillis/1000,
}
elseif table.find(JumpAllowStates, NewState) then
Module.Players[Player].Aleby.AllowJump = true
elseif table.find(JumpDisallowStates, NewState) then
Module.Players[Player].Aleby.AllowJump = false
end
if not table.find(ClimbNotCancelStates, NewState) then
Module.Players[Player].Aleby.Climbing = nil
end
if NewState == Enum.HumanoidStateType.Landed then
local WeightModifier = (Module.Players[Player].Aleby.Heavy and Module.Players[Player].Aleby.Heavy.Power or 1) / (Module.Players[Player].Aleby.Light and Module.Players[Player].Aleby.Light.Power or 1)
local Velocity = -Character.PrimaryPart.AssemblyLinearVelocity.Y
local JumpHeight = (Velocity*Velocity)/(workspace.Gravity*WeightModifier*2)*1.1
Module.Players[Player].Aleby.Bounce = {
Time = DateTime.now().UnixTimestampMillis/1000,
StartHeight = Character.PrimaryPart.Position.Y,
Power = JumpHeight,
Expiration = DateTime.now().UnixTimestampMillis/1000 + (Velocity/(workspace.Gravity*WeightModifier)) + CheckDelay*1.1,
}
end
end)
end
local function Initialize(Player)
local self = setmetatable({}, ModuleMeta)
self.Penalties = {}
self.Excuses = {}
self.Aleby = {}
self.Aleby.Affectors = {}
self.CheckData = {}
self.Connections = {}
self.Connections.CharacterAdded = Player.CharacterAdded:Connect(function()
OnCharacterAdded(Player)
end)
self.Connections.PlayerRemoved = Player.Destroying:Connect(function()
for k, v in pairs(self.Connections) do
v:Disconnect()
end
Module.Players[Player] = nil
end)
self.LastCheck = DateTime.now().UnixTimestampMillis/1000
Module.Players[Player] = self
OnCharacterRemoved(Player)
end
function ModuleMeta:GetAffectors()
local HitboxCFrame, HitboxSize = self.Character:GetBoundingBox()
AffectorDetectParams.FilterDescendantsInstances = {self.Character}
local Nearby = workspace:GetPartBoundsInBox(HitboxCFrame, HitboxSize, AffectorDetectParams)
for i = 1, #Nearby, 1 do
self.Aleby.Affectors[Nearby[i]] = DateTime.now().UnixTimestampMillis/1000 + (Nearby[i].AssemblyLinearVelocity.Magnitude*2/workspace.Gravity)^0.5 + CheckDelay*1.1
end
end
function ModuleMeta:CheckTeleport(Player:Player)
if not self.CheckData.TeleportData then
self.CheckData.TeleportData = {
LastCheck = DateTime.now().UnixTimestampMillis/1000,
PrevCFrame = self.Character.PrimaryPart.CFrame,
}
return
end
local CheckData = self.CheckData.TeleportData
local PrevCFrame, CurCFrame = CheckData.PrevCFrame or self.Character.PrimaryPart.CFrame, self.Character.PrimaryPart.CFrame
local LastCheck = CheckData.LastCheck
local Delta = DateTime.now().UnixTimestampMillis/1000 - LastCheck
local Ping = Player:GetNetworkPing()
if Ping >= Delta then return end
local MovedDistance = (CurCFrame.Position - PrevCFrame.Position)
local MovedHorizontal = MovedDistance * Vector3XZ
local MovedVertical = MovedDistance.Y
local AllowedHorizontal = (self.AllowedSpeed*Vector3XZ).Magnitude * 1.2 --self.Character.Humanoid.WalkSpeed * 1.2
AllowedHorizontal *= (Delta + Ping)
local AllowedVertical = self.Character.Humanoid.WalkSpeed * (self.Character.Humanoid:GetState() == Enum.HumanoidStateType.Climbing and 1 or 0.7071067811865476) --math.cos(math.rad/4)
AllowedVertical = AllowedVertical + self.AllowedSpeed.Y --AffectorImpact.Y
if self.Aleby.Jumping then
local AddedHeight = math.max(self.Aleby.Jumping.Power - (CurCFrame.Position.Y - self.Aleby.Jumping.StartHeight), 0)
AllowedVertical = AllowedVertical + AddedHeight
end
if AllowedHorizontal <= MovedHorizontal.Magnitude then
print("Player cheated (horizontal), teleported from: " .. tostring(PrevCFrame) .. " to " .. tostring(CurCFrame))
local Power = MovedHorizontal.Magnitude / AllowedHorizontal
table.insert(self.Penalties, {
Time = DateTime.now().UnixTimestampMillis/1000,
Expire = DateTime.now().UnixTimestampMillis/1000 + 60 * Power,
Value = 1,
Data = {
Type = "Teleport/Walkspeed",
Start = PrevCFrame,
End = CurCFrame,
},
})
end
if AllowedVertical <= MovedVertical then
print("Player cheated (vertical), teleported from: " .. tostring(PrevCFrame) .. " to " .. tostring(CurCFrame))
local Power = MovedVertical / AllowedVertical
table.insert(self.Penalties, {
Time = DateTime.now().UnixTimestampMillis/1000,
Expire = DateTime.now().UnixTimestampMillis/1000 + 60 * Power,
Value = Power,
Data = {
Type = "Teleport/HiJump",
Start = PrevCFrame,
End = CurCFrame,
},
})
end
CheckData.PrevCFrame = CurCFrame
CheckData.LastCheck = DateTime.now().UnixTimestampMillis/1000
end
function ModuleMeta:CheckAirWalk(Player:Player)
if not self.CheckData.AirWalkData then
self.CheckData.AirWalkData = {
LastCheck = DateTime.now().UnixTimestampMillis/1000,
PrevCFrame = self.Character.PrimaryPart.CFrame,
NotFallStack = 0,
Acceleration = 0
}
return
end
local CheckData = self.CheckData.AirWalkData
local CurCFrame = self.Character.PrimaryPart.CFrame
local LastCheck = CheckData.LastCheck
local Delta = DateTime.now().UnixTimestampMillis/1000 - LastCheck
local Ping = Player:GetNetworkPing()
if Ping >= Delta then return end
local HitboxCFrame, HitboxSize = self.Character:GetBoundingBox()
FloorDetectParams.FilterDescendantsInstances = {self.Character}
local FloorBelow = false
if Module.Players[Player].Aleby.Climbing then
local FloorJump = workspace:GetPartBoundsInBox(HitboxCFrame*CFrame.new(0, -(HitboxSize.Y+2)/2, -(HitboxSize.Z)/2), Vector3.new(HitboxSize.X, HitboxSize.Y, 2), FloorDetectParams)
FloorBelow = #FloorJump == 1
else
local FloorJump = workspace:GetPartBoundsInBox(HitboxCFrame-Vector3.new(0, HitboxSize.Y/2, 0), Vector3.new(HitboxSize.X, 2, HitboxSize.Z), FloorDetectParams)
FloorBelow = #FloorJump == 1
end
if not FloorBelow then
print("No floor found")
local MovedDistance = (CurCFrame.Position - CheckData.PrevCFrame.Position)
local MovedVertical = MovedDistance.Y
local WeightModifier = (Module.Players[Player].Aleby.Heavy and Module.Players[Player].Aleby.Heavy.Power or 1) / (Module.Players[Player].Aleby.Light and Module.Players[Player].Aleby.Light.Power or 1)
local Acceleration = workspace.Gravity*WeightModifier*Delta*0.9
local Allowed = -CheckData.Acceleration
if self.Aleby.Jumping then
local AddedHeight = math.max(self.Aleby.Jumping.Power - (CurCFrame.Position.Y - self.Aleby.Jumping.StartHeight), 0)
Allowed = Allowed + AddedHeight
Acceleration = 0
print(self.Aleby.Jumping, DateTime.now().UnixTimestampMillis/1000)
end
print("Acceleration needed: " .. tostring(Acceleration))
if MovedVertical >= Allowed then
CheckData.NotFallStack += 1
if CheckData.NotFallStack >= 10 then
print("Airwalked")
table.insert(self.Penalties, {
Time = DateTime.now().UnixTimestampMillis/1000,
Expire = DateTime.now().UnixTimestampMillis/1000 + 60,
Value = 1,
Data = {
Type = "Airwalk",
}
})
end
else
CheckData.Acceleration += Acceleration
end
else
CheckData.NotFallStack = 0
CheckData.Acceleration = 0
end
CheckData.PrevCFrame = CurCFrame
CheckData.LastCheck = DateTime.now().UnixTimestampMillis/1000
end
Players.PlayerAdded:Connect(Initialize)
function Module.AddExcuse(Player, Id, Excuse)
Module.Players[Player].Excuses[Id] = Excuse
for i = #Module.Players[Player].Penalties, 1, -1 do
local Penalty = Module.Players[Player].Penalties[i]
if Penalty.Time >= Excuse.Time and Penalty.Time <= Excuse.Expire then
if typeof(Excuse.Target) == "function" and Excuse.Target(Penalty) or table.find(Excuse.Target, Penalty.Reason) then
table.remove(Module.Players[Player].Penalties, i)
print("Excused penalty " .. tostring(i))
end
end
end
end
function Module.RemoveExcuse(Player, Id)
Module.Players[Player].Excuses[Id] = nil
end
function Module.AddAleby(Player, Id, Excuse)
Module.Players[Player].Aleby[Id] = Excuse
for i = #Module.Players[Player].Penalties, 1, -1 do
local Penalty = Module.Players[Player].Penalties[i]
if Penalty.Time >= Excuse.Time and Penalty.Time <= Excuse.Expire then
if typeof(Excuse.Target) == "function" and Excuse.Target(Penalty) or table.find(Excuse.Target, Penalty.Reason) then
table.remove(Module.Players[Player].Penalties, i)
print("Excused penalty " .. tostring(i))
end
end
end
end
function Module.RemoveAleby(Player, Id)
Module.Players[Player].Aleby[Id] = nil
end
coroutine.wrap(function()
while true do
local Waited = task.wait(CheckDelay)
for Player, Data in pairs(Module.Players) do
if not Data.Character then
continue
end
local CurTime = DateTime.now().UnixTimestampMillis/1000
if IsLobby then
local LobbyPlotCenter = Vector3.new(-14, 2.525, 51)
local Diffirence = Module.Players[Player].Character.PrimaryPart.Position - LobbyPlotCenter
if FuzzyEq(LobbyPlotCenter, Module.Players[Player].Character.PrimaryPart.Position, 40) then
Module.Players[Player].Excuses.LobbyPlot = {
Time = CurTime-Waited,
Expire = CurTime+Waited,
Target = function(Penalty)
return true
end,
}
end
end
local AllowedVelocity = Vector3.max(Vector3.new(Data.Character.Humanoid.WalkSpeed, 0, Data.Character.Humanoid.WalkSpeed), Vector3.min(Vector3abs(Data.Character.PrimaryPart.AssemblyLinearVelocity), Data.AllowedSpeed))
for Affector, Time in pairs(Data.Aleby.Affectors) do
if Time < CurTime then
Data.Aleby.Affectors[Affector] = nil
else
AllowedVelocity = Vector3.max(AllowedVelocity, Vector3abs(Affector.AssemblyLinearVelocity))
end
end
Data.AllowedSpeed = AllowedVelocity
for Id, Aleby in pairs(Data.Aleby) do
if typeof(Aleby) == "table" and Aleby.Expiration and Aleby.Expiration <= CurTime then
Data.Aleby[Id] = nil
end
end
Data:GetAffectors()
Data:CheckTeleport(Player)
Data:CheckAirWalk(Player)
local Total = 0
for Id, Excuse in pairs(Data.Excuses) do
if Excuse.Expire <= CurTime then
Data.Excuses[Id] = nil
continue
end
end
for i = #Data.Penalties, 1, -1 do
local Penalty = Data.Penalties[i]
if Penalty.Expire <= CurTime then
table.remove(Data.Penalties, i)
continue
end
for Id, Excuse in pairs(Data.Excuses) do
if Penalty.Time >= Excuse.Time and Penalty.Time <= Excuse.Expire then
if typeof(Excuse.Target) == "function" and Excuse.Target(Penalty) or table.find(Excuse.Target, Penalty.Reason) then
table.remove(Module.Players[Player].Penalties, i)
print("Excused penalty " .. tostring(i))
end
end
end
Total += Penalty.Value
end
if Total >= 20 then
warn("Cheater detected, bounty is " .. tostring(Total))
end
end
end
end)()
return Module
- Yes
- Somewhat
- No (tell me why please)
0 voters