Call mouse clicks to server without exploiters abusing my remotes

Lets say I have a game where one of the clear objective is to swing or throw some sort of weapon to deal damage. But obviously this weapon requires a cooldown so we need to account for that.

Normally you could just detect a mouse click on the client and lock that click behind a debounce, then just call to server using a remote event or function to tell the server that I want to deal damage. The server then returns the true damage dealt, and the true remaining health of my target, neither of which should be calculated on the client. However, that doesn’t mean an exploiter can’t abuse that remote to fire my clicked event repeatedly to basically avoid the weapons attacking speed.

Clearly in this case adding some sort of debounce on the client won’t be sufficient enough to combat exploiters, so we somehow need to add this debounce check on the server where the solution is slightly bugging me.

The server is global of course, so my current solution is to add some sort of attribute or value to each individual player to act as a cooldown timer, then use a RunService loop to accurately count down the timer to 0 which would allow the function to be passed again (or alternatively, a task.delay() function). The question is, is this the only and best way to handle sever-sided debounce on a player to player basis? Or is there some sort of method that I’m not seeing that could easily be applied to avoid exploiters?

I’m slowly delving into more combat-oriented games where I need to handle player to player damage and also player to NPC damage, and before I get into a super sophisticated system I want to clear my confusion here before I make a totally unnecessary system that handles this kind of cooldown timer.

TL;DR: What is the best and most efficient/optimized way to handle debounce on the server to accurately calculate when/how to allow the player to deal damage to avoid exploiters from abusing remotes?

2 Likes

You should only use attributes and ValueObjects if you want the client or other scripts to access those properties without using a ModuleScript.

Here is a server-sided cooldown:

local remote = -- [the remote's location]
local cooldowns = {}

remote.OnServerEvent:Connect(function(player)
    if table.find(cooldowns, player) then
        return

    else
        table.insert(cooldowns, player)

        task.delay(--[[Cooldown time]], function()
            table.remove(cooldowns, table.find(cooldowns, player))
        end)
    end

    -- Your other code.
end)

Tables! Brilliant! Not sure how I overlooked that but seems so obvious now haha! But you make a good point, I definitely had no need to access any of those values/attributes outside of the script itself so that makes this a much cleaner solution, thanks!

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