Scripting HelpersARCHIVE
A little piece of Roblox history. Preserved for everyone, one question at a time.Read about the archive →
COMMUNITY QUESTION

RemoteEvents for Cooldowns - Exploitable?

Hi,

So basically I have a cooldown system, but I also want to have a cooldown meter to give the player tactile feedback on when their cooldown is finished. I tried debounce ticks, etc. but I think server and client get desynced in terms of their times, and so the cooldown meter does not accurately represent the actual time being tracked by the server.

So, I'm using a remote to FireClient to my GUI cooldown, passing the argument of my desired cooldown time. The cooldown meter changes size until the cooldown is finished, THEN it uses FireServer to tell the server "ok, the cooldown is actually done on this client now". This works well for aligning the cooldowns on client/server perfectly, but how could this be exploitable? If it is exploitable, what is a better way to sync up cooldowns on server and client?

Context on a revised structure:

  • A Tool LocalScript receives input that I can't track with Tool.Activated (e.g. Right Click), then fires a remote to "activate" some action in a Script, still inside the Tool
  • Inside The Script deals with the Sword animation, damage changes/hitreg, and importantly the Right Click action including its cooldowns
  • When cooldowns are fired on the Script, it also fires :FireClient with relevant args to the LocalScript in the cooldown GUI, which does its thing irrespective of what's going on on the server

This is the alternate structure I implemented when researching and finding out about debounce/tick() timers, but this has the issue of client/server tick()s being desynced. Upon thinking about it, another way is a debounce table storing each player's data, though I'm concerned that if I put all my cooldown information, as well as server-side SwordScript code into a debounce script it'll become quite bloated (I have different characters with different swords, different cooldowns/abilities). Any thoughts?

I was able to, I think, resolve the desync problem using Quenty's TimeSyncService in Nevermore, which allowed me to get sort of "Clock" instance that returns the same time regardless of the time being requested on the client and server. I implemented it into the aforementioned debounce structure, and it works fine on local, but I'll have to try it out in game to be completely sure.

I also show the cooldown bars through BillboardGuis above players' heads, and I was able to use coroutines in the SwordScripts to basically do server-to-server calls (the SwordScript creates a coroutine responsible for calling a server ModuleScript, which receives the BillboardGui object as a parameter and so can, in a loop, display the cooldown happening in real time).

1 answer

Make sure to do the debounce on the server. Otherwise, the exploiter can just fire the remote event as many times as he wants.

This is a server script in preferably in ServerScriptService.

local debounce = {} -- This table will contain all the players' debounce value
local debounceTime = 2 

game.Players.PlayerAdded:Connect(function(plr)
	debounce[plr.Name] = false
end)

game.ReplicatedStorage.EventHere.OnServerEvent:Connect(function(player)
	if debounce[player.Name] == false then
		debounce[player.Name] = true
		--[[
		 -- Code for whatever here
		]]
		wait(debounceTime)
		debounce[player.Name] = false
	end
end)

This is how the debounce table looks like:

local debounce = {
	["Player1"] = true;
	["Player2"] = false;
	["Player3"] = false;
}

Now the player can't exploit the debounce, because it's on the server (which no player can access)

I hope this helps :)

10 comments

0

Hi, thanks for the reply! So I was thinking of using debounce timers, but is it possible for the client's GUI timer to finish before the server debounce is ready? If so I'm concerned that the cooldown meter will finish, notifying the player that they can perform the action again, but there will be an awkward delay while we wait for the server's debounce to finish. How should we get around this?

0

Learn about coroutines and spawn - which allows multiple threads to run at the same time in one script - https://www.youtube.com/watch?v=f3bcZK7_F-E and https://www.youtube.com/watch?v=lohokvnLYEU

0

Read this after you learn about threads - What you want to do is create a new thread and put the fireserver() function in there. Make sure to do this on the client. So if you do that correctly, the gui timer and the server debounce will be able to run at the same time :)

0

Hi, thank you for the video! I also found a coroutine doc on the Roblox wiki so I will be reading through that as well. What are you referring to with "FireServer" to have wrapped in the coroutine? The only FireServer I have at the moment is the CooldownScript (client) firing the remote to my server once the GUI cooldown is done.

0

Yes that event. Also in the script above, where I wrote "Code for whatever here" put the code for the tool to function. Example: Give points

0

On the client, use tool.activated and in that event fire the remote event wrapped in a coroutine, then do the gui stuff.

0

On the client, use tool.activated and in that event fire the remote event wrapped in a coroutine, then do the gui stuff .

0

Hi, so sorry for the late reply :( I didn't realize I was logged into my other account and so I never saw the notification. Could you explain what you mean by "for the tool to function"? I feel I may have an unorthodox way that I structured this originally, as I was building on the original LinkedSword:

0
  • I realized my structure description got too long, so please check the original post for the whole structure I have now *
0

Thank you for the intro to coroutines; in the original post you'll see I applied them to update in-world cooldowns, at least with my current cooldown structure! I may pivot to something else if a debounce table is a more effective solution. From the edit to the OP, what do you think? Would it be better to use coroutines instead of the synced server/client clock?

This discussion is preserved as it was. New answers, comments, and votes are closed.