Making sure server-sided cooldown is in sync with client

Hello. I’m currently making my first serious project and have little experience with preventing exploitation. I figured I should change my cooldowns to be server-sided, red about sever-sided cooldowns and decided attributes are a good way to do them.

However there is something I’m skeptical about. Here’s the structure of my code.


-- localscript
if input.UserInputType == Enum.UserInputType.MouseButton2 then
   if chr:GetAttribute("CD") == true then return end

   event:FireServer()
   -- animations and such play here
end

-- serverscript
event.OnServerEvent:Connect(function(plr)
   plr.Character:SetAttribute("CD", true)
   task.delay(1, function()
       plr.Character:SetAttribute("CD", false)
   end)

    -- stuff handled by server goes here
end)

This creates a cooldown, but what I’m afraid of is the local script’s function happening more than once before cooldown is set.
Is it possible for somebody to trigger it twice or more before the server manages to set the cooldown? Does the server event happen instantly? Like for instance would somebody using a auto clicker or somebody with high latency be able to do this?

How could I make this cooldown secure?

1 Like

normally I do something like this:

-- server script

local eventInProgress = false

event.OnServerEvent:Connect(function(whateverVariables)
    if eventInProgress == false then
        eventInProgress = true
        -- whatever goes in the function here
        wait(1)
        eventInProgress = false
    end
end
1 Like

Hey, thanks for the reply. This does prevent the remote event’s function from happening again. But like I wrote in the code’s comments, there’s some things that happen after the line where the event is fired. The event wouldn’t do anything, but the lines after still happen.

1 Like

A slightly hacky but valid workaround nonetheless would be to, on the client, :SetAttribute("CD", true) right after you check whether there already is an active cooldown.

The server will likely take a few ms to respond to the event, at which point the server will also :SetAttribute("CD", true), bringing the 2 environments back into sync. Then, after your task.delay, the cooldown is removed.

Either that, or use a local debounce var and have the task.delay logic on both sides - admittedly the workaround requires less code.

Alternatively you could check whether you’re already playing the animation on the client (as it’s likely more than a few ms long) and return if you are, prior to firing an event or trying to play animations etc again.

2 Likes

Huh, true. That does work. And do you reckon this will be secure enough against exploiters? Thanks for the answer.

1 Like

Yup! It’s exploit proof as all code runs synchronously; even non-main threads due to processor scheduling etc. Essentially the server will only truly run one line at a time, even utilising multithreading.

Hope I helped, good luck!

2 Likes

Gotcha, thanks a lot for helping me. Been very insecure about this for a bit.
Cheers.

1 Like

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.