local module = {}
local replicatedStorage = game:GetService("ReplicatedStorage")
local remotes = replicatedStorage:FindFirstChild("Remotes")
local CowButtonDownRemote = remotes:FindFirstChild("CowButtonDown")
local CowButtonUpRemote = remotes:FindFirstChild("CowButtonUp")
local down = {}
CowButtonDownRemote.OnServerEvent:Connect(function(player)
local leaderstats = player:FindFirstChild("leaderstats")
local playerStats = player:FindFirstChild("PlayerStats")
local cows = leaderstats:FindFirstChild("Cows")
local cowsPerSecond = playerStats:FindFirstChild("CowHoldPerSecond")
local cowsPerClick = playerStats:FindFirstChild("CowsPerClick")
if not (down[player]) or down[player] - tick() > 1 / cowsPerSecond then
down[player] = tick()
coroutine.wrap(function()
while down[player] do
cows.Value += cowsPerClick.Value
task.wait(1 / cowsPerSecond.Value)
end
end)()
end
end)
CowButtonUpRemote.OnServerEvent:Connect(function(player)
down[player] = nil
end)
return module
This code is intended to limit users to only be able to get CowsPerSecond cows per second whether they click a button or hold it down (this is only the server side). The issue with this code is that you can spam click since the buttonup event removes the player from the debounce table. How can I work around this?
local module = {}
local replicatedStorage = game:GetService("ReplicatedStorage")
local remotes = replicatedStorage:FindFirstChild("Remotes")
local CowButtonDownRemote = remotes:FindFirstChild("CowButtonDown")
local CowButtonUpRemote = remotes:FindFirstChild("CowButtonUp")
local down = {}
CowButtonDownRemote.OnServerEvent:Connect(function(player)
local leaderstats = player:FindFirstChild("leaderstats")
local playerStats = player:FindFirstChild("PlayerStats")
local cows = leaderstats:FindFirstChild("Cows")
local cowsPerSecond = playerStats:FindFirstChild("CowHoldPerSecond")
local cowsPerClick = playerStats:FindFirstChild("CowsPerClick")
if not (down[player]) or down[player] - tick() > 1 / cowsPerSecond then
coroutine.wrap(function()
down[player] = tick()
task.wait(0.25) --// delay time
down[player] = nil
end)()
coroutine.wrap(function()
while down[player] do
cows.Value += cowsPerClick.Value
task.wait(1 / cowsPerSecond.Value)
end
end)()
end
end)
return module
This should work to achieve what you’re looking for:
local module = {}
local replicatedStorage = game:GetService("ReplicatedStorage")
local remotes = replicatedStorage.Remotes
local CowButtonDownRemote = remotes.CowButtonDown
local CowButtonUpRemote = remotes.CowButtonUp
local threads = {}
local time = {}
local function setCows(cows, cowsPerClick, cowsPerSecond)
while true do
cows.Value += cowsPerClick
task.wait(cowsPerSecond)
end
end
CowButtonDownRemote.OnServerEvent:Connect(function(player)
if threads[player] then return end -- Prevents overwriting the existing thread, which will cause multiple loops to run
local leaderstats = player:FindFirstChild("leaderstats") -- FindFirstChild will return nil if the Instance isn't found, and if so, will cause an error in the original code
local playerStats = player:FindFirstChild("PlayerStats")
if leaderstats and playerStats then
local cows = leaderstats:FindFirstChild("Cows")
local cowsPerSecond = playerStats:FindFirstChild("CowHoldPerSecond")
local cowsPerClick = playerStats:FindFirstChild("CowsPerClick")
if cows and cowsPerSecond and cowsPerClick then
if time[player] and (tick() - time[player]) < (1 / cowsPerSecond.Value) then return end
time[player] = tick()
threads[player] = task.spawn(setCows, cows, cowsPerClick.Value, 1 / cowsPerSecond.Value)
end
end
end)
CowButtonUpRemote.OnServerEvent:Connect(function(player)
if threads[player] then
task.cancel(threads[player])
threads[player] = nil
end
time[player] = nil
end)
return module
Do remember that FindFirstChild will return nil if the Instance isn’t found, and that you’ll need to use .Value to access a value that’s stored in a value instance:
@U_npluggedDev Added a guard statement to fix a bug that can cause the original thread to be overwritten, but still continue to run
The time[player] = nil may be interfering, and it’s safe and recommended to remove it with the code’s current state. It should work correctly without it
To clarify, the thread still needs to be cancelled when the mouse button is up, so that part has to stay, otherwise you’ll get an issue where two loops may run at the same time
Gotcha, and its a good thing its a module script since I can just make a function and call that function in my player removing script in a seperate file. Thank you so much for your help