Didn’t really know where to put this, so I put this here. I have developed this within 8 hours and it protects against speed and fly hacks. I want to know how reliable it is when there are other people in the server. Thanks.
If you want people to critique your anti exploit you should post the source so that actual possible security holes can be found.
If the response to that goes anything along the lines of “but it’s local” and “but it’s supposed to be obfuscated/hidden” then it’s not going to be effective at all in a real game and people will have no problems getting around it.
Thanks for the response! This is the server-sided anti-exploit class I wrote:
local HISTORY_LENGTH = 60
local AntiCheat = {}
AntiCheat.__index = AntiCheat
local RunService = game:GetService("RunService")
function AntiCheat:Kill()
self._updateListener:Disconnect()
end
function AntiCheat.new(character, maxSpeed)
local self = setmetatable({}, AntiCheat)
self._character = character
self._humanoidRoot = character:WaitForChild("HumanoidRootPart")
self._maxSpeed = maxSpeed
self._isStandingHeight = character:WaitForChild("Humanoid").HipHeight + 1-- The height which is used to determine if the root part is mid air or stood on a platform
self._history = {} -- Keeps a history of all the positions that the humanoid root has been
self._heartbeatDeltaHistory = {} -- Keeps a log of the delta between heartbeat events
self._lastValidPosition = self._humanoidRoot.Position
self._updateListener = RunService.Heartbeat:Connect(function(dt)
self:_update(dt)
end)
return self
end
function AntiCheat:_update(dt)
self:_updateHistory()
self:_updateHeartbeatDeltaHistory(dt)
local speedIsValid = self:_validateSpeed()
local heightIsValid = self:_validateHeight()
if speedIsValid and heightIsValid then
self._lastValidPosition = self._history[#self._history]
else
self._humanoidRoot.CFrame = CFrame.new(self._lastValidPosition)
end
end
function AntiCheat:_updateHistory()
table.insert(self._history, self._humanoidRoot.Position)
if #self._history > HISTORY_LENGTH then
table.remove(self._history, 1)
end
end
function AntiCheat:_updateHeartbeatDeltaHistory(dt)
table.insert(self._heartbeatDeltaHistory, dt)
if #self._heartbeatDeltaHistory > HISTORY_LENGTH then
table.remove(self._heartbeatDeltaHistory, 1)
end
end
function AntiCheat:_validateHeight()
-- Check if the character is standing on a plaform
if not self._heightRaycastParams then
local params = RaycastParams.new()
params.FilterDescendantsInstances = {self._character}
params.FilterType = Enum.RaycastFilterType.Blacklist
self._heightRaycastParams = params
end
local halfX = self._humanoidRoot.Size.X/2
local halfY = self._humanoidRoot.Size.Y/2
local halfZ = self._humanoidRoot.Size.Z/2
local raycastOrigins = {
self._humanoidRoot.CFrame * CFrame.new(-halfX, -halfY, halfZ),
self._humanoidRoot.CFrame * CFrame.new(-halfX, -halfY, -halfZ),
self._humanoidRoot.CFrame * CFrame.new(halfX, -halfY, halfZ),
self._humanoidRoot.CFrame * CFrame.new(halfX, -halfY, -halfZ),
}
local raycastDirection = Vector3.new(0, -self._isStandingHeight, 0)
local isStanding = false
for _, v in ipairs(raycastOrigins) do
local result = workspace:Raycast(v.Position, raycastDirection, self._heightRaycastParams)
if result then
isStanding = true
break
end
end
-- Are they in flight?
if isStanding then
self._inJump = false
self._totalHeightJumped = 0
return true -- They are valid
end
-- Find the total height covered so far:
self._inJump = true
if not self._totalHeightJumped then self._totalHeightJumped = 0 end
local p1 = self._history[#self._history]
local p2 = (self._history[#self._history - 1] or p1)
local heightDifference = (p1-p2).Y
if heightDifference > 0 then
self._totalHeightJumped += heightDifference
else
return true
end
if self._totalHeightJumped >= 9 then
return false
else
return true
end
end
function AntiCheat:_validateSpeed()
-- Get the average speed if the world was on a plane:
local speedSum = 0
local lastPosition
for i, v in ipairs(self._history) do
local p1 = Vector2.new(v.X, v.Z)
if not lastPosition then lastPosition = p1 end
local thisSpeed = (lastPosition - p1).magnitude / self._heartbeatDeltaHistory[1]
speedSum += thisSpeed
lastPosition = p1
end
local speedAverage = speedSum / #self._history
local isValid = speedAverage < self._maxSpeed
return isValid
end
return AntiCheat
This looks pretty solid. I would of course advise that it’s tweaked depending on the game it’s applied to due to variations in gameplay. Just looking at it I couldn’t say if there are any weird edge cases so you should also test for those, but other than that it looks like it should work.
In the future also consider the Code Review category for things like this.