I made this system to prevent exploiters spamming remote events and kicking/banning them if the server catches them firing faster than the cooldown. From my testing, I had this running for about 8 hours while the client was firing the event every 0.5 seconds (which is the cooldown) and it hasn’t had a problem.
client:
local RunService = game:GetService("RunService")
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local cooldown = 0.5
local lastCooldownTime = -cooldown
task.wait(8)
RunService.Heartbeat:Connect(function()
local currentTime = tick()
if currentTime - lastCooldownTime >= cooldown then
lastCooldownTime = currentTime
local serverTime = workspace:GetServerTimeNow()
ReplicatedStorage.RemoteEvent:FireServer(serverTime)
end
end)
server:
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local cooldown = 0.5
local lastTime = -cooldown
ReplicatedStorage.RemoteEvent.OnServerEvent:Connect(function(player, clientTime)
local serverTime = workspace:GetServerTimeNow()
local timeTaken = serverTime - clientTime
local timeSinceLast = serverTime - timeTaken - lastTime
if clientTime > serverTime then
warn("Time too high by: ", clientTime - serverTime)
end
print(string.format("Event took %f seconds; time since last: %f", timeTaken, timeSinceLast))
if timeSinceLast < cooldown then
warn(string.format("Event fired %f seconds too early", cooldown - timeSinceLast))
else
lastTime = serverTime - timeTaken
end
end)
This doesn’t relate to the post but I’d like give something similar I made
local tblDebouce = {}
local PlayerService = game:GetService("Players")
PlayerService.PlayerAdded:Connect(function(plr)
tblDebouce[plr.Name] = {} -- adds storage when player joins
end)
PlayerService.PlayerRemoving:Connect(function(plr)
tblDebouce[plr.Name] = nil -- removes storage when player leaves
end)
function addWaitPlr(plrName, WaitName, timeWait)
tblDebouce[plrName][WaitName] = true -- sets something for player which'll be used to detect if waiting
task.spawn(function() -- task.spawn used to allow script to keep running
task.wait(timeWait)
tblDebouce[plrName][WaitName] = nil -- removes the *wait* I guess after specified time
end)
end
RemoteEvent.OnServerEvent:Connect(function(plr)
if not tblDebouce[plr.Name]["Name Here"] then
addWaitPlr(plr.Name,"Name Here",0.25)
-- Code here :p
end
end)
This is basically cooldown for firing remote events, it doesn’t kick but you can easily add a else statement to kick the player.
If theres a sudden ping spike for players who have bad internet, it may fire events that all get to the server at the same time once the client catches up and stops lagging. Maybe you dont want to kick them but just ignore the events.