Executing a loop twice causes a script timeout

Hello. I’m trying to make a script where a loop occurs while the mouse button is held down. A remote event is fired when the mouse is held and fired again when it is released. The script works perfectly, with the exception of the fact that Studio freezes for a short moment and returns a script timeout if the player clicks twice, supposedly if the player clicks while the looped code is still running.

I tried a debounce but it didn’t help. How could I prevent this timeout from occurring? Thanks in advance.

Below is my server-side code:

local replicated = game:GetService("ReplicatedStorage")
local hold = false

replicated.Combat:FindFirstChild(script.Name).OnServerEvent:Connect(function(player, attacktype, holding)
	if holding == true and hold == false then
		hold = true
		while hold == true and holding == true do
		--lots of redacted code here
		task.wait(0.3)
	else
		hold = false
	end
end)

And below is my client-side code, in case it is needed:

local uis = game:GetService("UserInputService")
local storage = game:GetService("ReplicatedStorage")
local event = storage.Combat:FindFirstChild(script.Name)

uis.InputBegan:Connect(function(input, _gameProcessed)
	if input.UserInputType == Enum.UserInputType.MouseButton1 then
		local attacktype = "Primary"
		local holding = true
		event:FireServer(attacktype, holding)
	end
end)

uis.InputEnded:Connect(function(input, _gameProcessed)
	if input.UserInputType == Enum.UserInputType.MouseButton1 then
		local attacktype = "Primary"
		local holding = false
		event:FireServer(attacktype, holding)
	end
end)
2 Likes

I decided to turn the attack code into a function:

replicated.Combat:FindFirstChild(script.Name).OnServerEvent:Connect(function(player, attacktype, holding)
	print(holding)
	if holding == true then
		hold = true
	elseif holding == false then
		hold = false
	end
	while hold == true do
		attack(player, attacktype)
	end
end)

And it still works, but the script timeout still occurs if I click while the code triggered by the loop is still running.

Edit: I fixed it by adding “task.wait(0.01)” to the “while true do” part of the code, but I feel like it’s more of a bandaid solution than anything. Are there any better ways of fixing that issue?

1 Like

It really depends how many times per seconds do you want the code inside the while loop to execute. Ideally, you would try to minimize that amount, especially if the code is heavy and can cause some performance issues. Nonetheless, there exists RunService.Heartbeat, which marks a function as executing every frame (I believe the server runs at 60 FPS so we’re looking at a cooldown of 1/60 so 0.016 seconds).

Connections aren’t as easy to interrupt as loops, but you can disconnect any time you need.

In pratice,

local RunService = game:GetService("RunService")

local connection: RBXScriptConnection? = nil

enableSomeFunctionality:Connect(function()
    connection = RunService.Heartbeat:Connect(function()
        -- something that runs every frame
    end)
end)

disableSomeFunctionality:Connect(function()
    connection:Disconnect()
    -- prevent the connection from running (until it is connected back again)
end)

Not that it’s my problem, but you should consider a better approach for how you’re handling input. As a reference, check out Suphi’s video. It’s for a different purpose but you could learn a lot from the way he does it.

2 Likes