How to make remote event only fire once every cooldown

Hello!
I’ve been making a simple script where if a certain button is pressed, a remote event will fire.
However, the remote event fires mutliple times. About every 1 time I click “E” it fires around 11 times.

I want the remote event to fire only ONCE when I press “E”

I also have the problem where when the remote event is SPAMMED, after the cooldown is done, it fires again.

Heres the local script in StarterCharacterScripts:

cooldown = false

local player = game.Players.LocalPlayer
repeat wait() until player.Character.Humanoid

local Special = game.ReplicatedStorage:WaitForChild("Special")
local ShowKnightEvent = game.ReplicatedStorage:WaitForChild("ShowSpecialKnife")

local humanoid = player.Character.Humanoid
local mouse = player:GetMouse()
local character = player.Character

local HPR = character:WaitForChild("HumanoidRootPart")

mouse.KeyDown:connect(function(key)
	if not cooldown then
		if key == "e" then
			cooldown = true
			Special:FireServer()
			ShowKnightEvent:FireServer()
			wait(20)
			cooldown = false
		end
	elseif cooldown == true then
		print("still on special cooldown") 
	end
end)

As always, any help is appreciated.

4 Likes

I would check the time since the event was last fired on the server, not the client. An exploiter can delete your LocalScript and rewrite it to fire constantly.

Fortunately, LuaU has something that can help here, called tick(). This is a measure of the time that has elapsed since January 1st, 1970, and can be used to relatively count time.

Instead, on a server script, try something similar to:

local time_since_last_fired : number = tick()

event.OnServerEvent:Connect(function(plyr : Player)

    -- If the current time since 1970/01/01 minus the time since the
    -- event was last fired, and time_since_last_fired was updated
    -- is less than 10 seconds, halt the function
    if tick() - time_since_last_fired < 10 then return end

    -- Update the above value to the time the event was fired
    time_since_last_fired = tick()
end)

Note that this will be applicable to all players that fire the event, meaning that every player will have to wait until the cooldown has elapsed.

If you want to fix this, I suggest appending the player’s name & time_since_last_tick to a table, and then checking from there.

Hope this helps.

2 Likes

I think your problem is the wait(20) which stops the function for 20 seconds and then the debounce runs which cause the player to be able to spam it so many times.

2 Likes

should probably try using UserInputService like below and check key before cooldown if its even the right input

with the way you where doing it I think any key pressed would cause it to fire to the last if statement and print

local player = game.Players.LocalPlayer
repeat wait() until player.Character.Humanoid

local Special = game.ReplicatedStorage:WaitForChild("Special")
local ShowKnightEvent = game.ReplicatedStorage:WaitForChild("ShowSpecialKnife")

local humanoid = player.Character.Humanoid
local mouse = player:GetMouse()
local character = player.Character

local HPR = character:WaitForChild("HumanoidRootPart")

local UserInputService = game:GetService('UserInputService')

local cooldown

UserInputService.InputBegan:Connect(function(InputObject, onGui)
	if InputObject.KeyCode == Enum.KeyCode.E then
		if cooldown then
			print("still on special cooldown") 
		else
			cooldown = true
			Special:FireServer()
			ShowKnightEvent:FireServer()
			wait(20)
			cooldown = nil
		end
	end
end)

also as stated above you should probably have a server side cool down to keep this from being hacked/repeat fired

4 Likes

Sorry, I was asleep. I will try all of these!

2 Likes

This works, but, If I do spam it, the servers will automatically fire when the cooldown is done.

2 Likes
local cooldownplayers = {}
local cooldowntime = 3
game.ReplicatedStorage.RemoteEvent.OnServerEvent:Connect(function(player)
	if not cooldownplayers[player] then 
		print('success')
		spawn(function() -- In a spawn function so that the function does not stop.
			cooldownplayers[player] = true
			task.wait(cooldowntime)
			cooldownplayers[player] = false
		end)
	else
		print('not success')
	end
end)
3 Likes

try this, i’ve explained all changes and uses in the script

local cooldown = false
local uis = game:GetService("UserInputService") --First I would replace mouse.KeyDown() with uis since KeyDown is depricated
uis.InputBegan:Connect(function(key,typing)
	if typing then return end --This will stop the function if the player is typing in a textbox of some sort (like the chat)
	if key.KeyCode == Enum.KeyCode.E then --first we get then enum keycode by doing key.keycode
		
		if not cooldown then --then we check if cooldown is false ("not cooldown" is the same thing as "cooldown == false")
			cooldown = true
			Special:FireServer()
			ShowKnightEvent:FireServer()
			delay(20,function() --using delay to prevent any possible yielding
				cooldown = false
			end)
		elseif cooldown then --same thing here just putting cooldown is the same thing as "cooldown == true"
			print("cooldown is active")
		end
		
	end
end)
3 Likes

I was taking a nap. I’ll try these and mark solution. (If there is one)

1 Like

This still causes the same problem. If I spam it, when the cooldown is over, the remote event will automatically fire.

1 Like

Actually, I think this is just a problem with MY script.

1 Like

Sorry for uh… saying that. I’ll try changing the main script for the remote event. (And ill change the script y’all gave me a bit)

1 Like
cooldown = false

local player = game.Players.LocalPlayer
repeat wait() until player.Character.Humanoid

local Special = game.ReplicatedStorage:WaitForChild("Special")
local ShowKnightEvent = game.ReplicatedStorage:WaitForChild("ShowSpecialKnife")

local humanoid = player.Character.Humanoid
local mouse = player:GetMouse()
local character = player.Character

local HPR = character:WaitForChild("HumanoidRootPart")

mouse.KeyDown:Connect(function(key)
	if key == "e" and cooldown == false then
		Special:FireServer()
		ShowKnightEvent:FireServer()
		cooldown = true
		task.wait(20)
		cooldown = false
	elseif key == "e" and cooldown == true then
		print("still on special cooldown") 
	end	
end)
	

What do you mean by it will automatically fire? If your spamming it then that is the cause of it firing again after the cooldown.

2 Likes

Thanks for another code! I’ll try this too.

1 Like

I meant by if I spam it before the cooldown is done, it will automatically fire right when the cooldown is over

1 Like

Might be because you set the cooldown to true, before the RemoteEvent fired.

1 Like

No. That doesnt fix it. I tried it already

1 Like

Maybe, but this is a guess…

mouse.KeyDown:Connect(function(key)
	if key == "e" and cooldown == false then
		Special:FireServer()
		ShowKnightEvent:FireServer()
		cooldown = true
		task.wait(20)
		cooldown = false
	end
	if key == "e" and cooldown == true then
		print("still on special cooldown") 
	end
end)			
2 Likes

Doesnt work. If I spam the key, it all fires one after the other.

1 Like

I wonder if theres a way to “cancel” a remote event.

1 Like