Debounce for remote functions?

Hey, I was looking into making a debounce for my remote function so that exploiters can’t spam the server with requests through the script.

My solution currently was to do this:

game.ReplicatedStorage.Event.OnServerInvoke = function(player)
if playerDebounce[player.Name] then return false end 

	placeDebounce[player.Name] = true

    if blahblah then 
        return true
    end

	wait(0.05)
	placeDebounce[player.Name] = nil
		

	return false
end

The problem with this is that the playerDebounce never runs if it runs true since it returns. I’ve heard about using the delay function but people have said that has the potential to not work or add an extra wait. I also have heard about using the os.clock feature and doing a time relative debounce, but that seems like it might be too much for just a 0.05 second debounce. What can I do?

3 Likes

Try using a coroutine, a coroutine can perform a different task without yielding the script

local playerDebounce = {}

game.ReplicatedStorage.Event.OnServerInvoke = function(player)
	if playerDebounce[player.Name] then return false end 
	
	playerDebounce[player.Name] = true
	coroutine.resume(coroutine.create(function()
		task.wait(.05)
		playerDebounce[player.Name] = nil
	end))

	if blahblah then 
		-- Some code I assume
		
		
		return true
	end
	
	return false
end
3 Likes

Yeah, I’ve heard about that too but I don’t want to use too many resources just for a debounce. Would it cause too much server load?

2 Likes

As long as you don’t use it like 100 times at the same time, it’s totally fine to use it.
It’s also not even a loop, just two lines of code so I’m pretty sure it’s fine.

3 Likes

If you really don’t want to use coroutines or task.delay, you could just save the last time the player used the remote to a table, then ever time they use it check how long it’s been since their last use.
To check this, you’d essentially just do

if os.clock() - (playerTable[player.Name] or 0) < 0.05 then return end
playerTable[player.Name] = os.clock()
4 Likes

This should be the preferred option. Using coroutines will open up new threads which is completely unnecessary and can impact performance.

2 Likes

Sorry for the late reply, thanks for the response! I was just worried that this method would cause the tables to overflow overtime is someone left. Would I just take out the debounce when the player is removing?

1 Like

Since Player objects are supposed to get cleaned up when they leave, it might be the case that you don’t have to do this kind of clean-up manually. You should probably test this, i.e. start a server with 2 players, print a list of players every second and the first player leave, see if the print still contains that Player and also see how it affects the structure of the table (do subsequent player Objects get shifted down similar to a table.remove call?).

If you do need to clean it up, consider using weak tables:

local playerDebounce = setmetatable({}, {__mode="k"})

This has the effect of allowing things to be GC’ed even if they’re referenced as keys in that table. Otherwise it would prevent GC’ing. Read more in the Lua manual or Lua Users.

Yeah, you can take out the value once they leave. (Set their index to nil)