You know what, I’ve done some testing and I’ve actually made it pretty alright.
Now this was fully tested in Studio, I highly recommend you test it yourself in your own game but even when changing the player’s state on the client (yes, it does replicate - I tested to make sure) and the server gives lenience of 100 studs per second (I check every .4 seconds so it translates to 40 studs on the Y axis every interval if the player is falling).
I added a Speed Gain feature to the module and tested with a +100 stud conveyor, and it works really really well!
So this is the new module for it.
local SpeedhackDetector = { tracking = {}, whitelist = {}, additionalSpeeds = {tags = {}, speeds = {}}, lastCheck = tick() }
local XZ = Vector3.new(1, 0, 1)
local Y = Vector3.yAxis
function SpeedhackDetector.Add(character)
SpeedhackDetector.tracking[character] = character.PrimaryPart.CFrame
character.Destroying:Connect(function()
SpeedhackDetector.tracking[character] = nil
end)
end
function SpeedhackDetector.WhitelistCharacter(character, duration)
local tag = tick()
SpeedhackDetector.whitelist[character] = tag
task.delay(duration, function()
if SpeedhackDetector.whitelist[character] == tag then
SpeedhackDetector.whitelist[character] = nil
end
end)
end
function SpeedhackDetector.BlacklistCharacter(character)
SpeedhackDetector.whitelist[character] = nil
end
function SpeedhackDetector.ChangeSpeedGain(character, speedGain)
SpeedhackDetector.additionalSpeeds.speeds[character] = speedGain
end
function SpeedhackDetector.IncreaseSpeedGain(character, tag, speedGain)
if not SpeedhackDetector.additionalSpeeds.speeds[character] then
SpeedhackDetector.additionalSpeeds.speeds[character] = 0
SpeedhackDetector.additionalSpeeds.tags[character] = {}
end
if SpeedhackDetector.additionalSpeeds.tags[character][tag] then
return
end
SpeedhackDetector.additionalSpeeds.tags[character][tag] = true
SpeedhackDetector.additionalSpeeds.speeds[character] += speedGain
end
function SpeedhackDetector.DecreaseSpeedGain(character, tag, speedGain)
local current = SpeedhackDetector.additionalSpeeds[character] or 0
SpeedhackDetector.additionalSpeeds.tags[character][tag] = nil
SpeedhackDetector.additionalSpeeds.speeds[character] = math.max(current - speedGain, 0)
end
function SpeedhackDetector.Update()
for character, lastCFrame in SpeedhackDetector.tracking do
local humanoid: Humanoid = character:FindFirstChild("Humanoid")
if not humanoid or SpeedhackDetector.whitelist[character] then
continue
end
--// Did a test, terminal velocity of jumping is roughly ~1.063*jumpPower.
--// I tested on different masses, gravities, jump powers, etc. All gave this result.
local distancePerSecond = humanoid.WalkSpeed * 1.1
local jumpDistancePerSecond = humanoid.JumpPower * 1.063 * 1.1
if humanoid:GetStateEnabled(Enum.HumanoidStateType.Freefall) then
jumpDistancePerSecond = 100
end
local speedGain = SpeedhackDetector.additionalSpeeds.speeds[character]
if speedGain then
distancePerSecond += speedGain
jumpDistancePerSecond += speedGain
end
local maxDistance = (tick() - SpeedhackDetector.lastCheck) * distancePerSecond
local maxDistanceY = (tick() - SpeedhackDetector.lastCheck) * jumpDistancePerSecond
local currentCFrame = character.PrimaryPart.CFrame
local compLast = lastCFrame.Position * XZ
local compCurrent = currentCFrame.Position * XZ
local compLastY = lastCFrame.Position * Y
local compCurrentY = currentCFrame.Position * Y
if (compLast - compCurrent).Magnitude > maxDistance or (compLastY - compCurrentY).Magnitude > maxDistanceY then
print("Player exceeded max distance")
character:PivotTo(lastCFrame)
SpeedhackDetector.tracking[character] = lastCFrame
else
SpeedhackDetector.tracking[character] = currentCFrame
end
end
SpeedhackDetector.lastCheck = tick()
end
return SpeedhackDetector
And I added a folder that contains items that will speed you up by touching it, but the API supports anything.
local function InitializeSpeeder(speedPart)
local gain = speedPart:GetAttribute("SpeedGain")
speedPart.Touched:Connect(function(h)
local c = h:FindFirstAncestorOfClass("Model")
if c and c:FindFirstChild("Humanoid") then
SpeedhackDetector.IncreaseSpeedGain(c, speedPart, gain)
end
end)
speedPart.TouchEnded:Connect(function(h)
local c = h:FindFirstAncestorOfClass("Model")
if c and c:FindFirstChild("Humanoid") then
task.delay(1, SpeedhackDetector.DecreaseSpeedGain, c, speedPart, gain)
end
end)
end
for _, speeder in workspace.SpeederUppers:GetChildren() do
InitializeSpeeder(speeder)
end
We can walk on the conveyor
https://gyazo.com/036d1cf6e741b772ae058c0d64d7a046
But not speed hack!
https://gyazo.com/fa8f3d14aa2317e81f324a497f8c804c
This is still not perfect though, exploiters can use around up to 110 Jump Power before being detected.
And this doesn’t address the velocity you get when jumping off a Truss.
Simulating 400 ping- it works well
https://gyazo.com/ae185df197f3e15683c3bed28ba61e35