How to avoid for loop from running more than once?

First for loop gets all the tools that has the tag “PlacementTool” but when I equipp a tool the “Equipped” runs more than twice, DB/Debounce is not preventing it.

	function Update_CollectionService()
	
	for i, PlacementTool in pairs(CollectionService:GetTagged("PlacementTool")) do -- gets all tools tagged with "PlacementObject"
		local Mouse_Moving = nil

		PlacementTool.Equipped:Connect(function() -- once tool Equipped
			if not DB then DB = true
				
				if not PlayerIn_EditMode then -- if tool equipped and player not in edit mode
					Unequipped_Tools("Player Not In Edit Mode")
					return
				end
				
				if Placement_Hologram == nil then -- if not already placing hologram
					
					-- Clones the model in replicatedstorage to make a hologram of it to show where its being placed
					Placement_Hologram = PlacableObjects:FindFirstChild(PlacementTool.Name):Clone()
					print(Placement_Hologram)
					
					-- For loop welds parts inside the hologram and also does other adjustable stuff
					Weld_Hologram(Placement_Hologram)
					
					Placement_Hologram.Parent = TempHologram -- Parents the cloned hologram to folder

					-- Display Size to Info
					local Size = Placement_Hologram:GetBoundingBox()
					local FormatedSize_X, FormatedSize_Y, FormatedSize_Z = string.format("%.1f", Size.X), string.format("%.1f", Size.Y), string.format("%.1f", Size.Z)
					Info.SizeText.Text = "Size: " .. FormatedSize_X .. ", " .. FormatedSize_Y .. ", " .. FormatedSize_Z
					
					local function CalculateMass(Hologram) -- calculates mass by getting descendants mass and doing addition and also displays it on "Info"
						Info.MassText.Text = "Mass: " .. "Calculating"
						local Total_Mass = 0
						
						for index, Part in pairs(Hologram:GetDescendants() ) do
							if Part:IsA("BasePart") then
								Total_Mass += Part.Mass
							end
						end
						
						local Formatted_Mass = string.format("%.2f", Total_Mass)
						
						Info.MassText.Text = "Mass: " .. Formatted_Mass.."kg"
					end
					
					CalculateMass(Placement_Hologram)

				else -- no "DB = false" since this script runs more than once this statement will be ment and cause bug with the placing Hologram
					print("Already Placing")
				end

				--- Moves hologram right to mouse once equipped rather than waiting until mouse moves
				Hologram_PosCalc()

				Mouse_Moving = Mouse.Move:Connect(function()
					Hologram_PosCalc()
				end)

				--- Hologram Rotation
				UserInputService.InputBegan:Connect(function(Input) -- if input began

					if Input.KeyCode == Enum.KeyCode.R or Enum.KeyCode.T then
						if not Rotating then Rotating = true

							if Placement_Hologram and Placement_Hologram.PrimaryPart then
								
								local orientation = Placement_Hologram.PrimaryPart.Orientation
								
								if Input.KeyCode == Enum.KeyCode.R then -- if input is R

									-- Rotates hologram on Y axis
									Placement_Hologram:SetPrimaryPartCFrame(Placement_Hologram.PrimaryPart.CFrame * CFrame.Angles(0, math.rad(Degrees_Value.Value),0))

								elseif Input.KeyCode == Enum.KeyCode.T then -- if input is T

									-- Rotates hologram on Z axis
									Placement_Hologram:SetPrimaryPartCFrame(Placement_Hologram.PrimaryPart.CFrame * CFrame.Angles(0,0, math.rad(Degrees_Value.Value)))

								end

								-- Updates UI info about rotation
								local ori = Placement_Hologram.PrimaryPart.Orientation
								Info.Ori.Text = "Orientation: " .. ori.X .. ", " .. ori.Y .. ", " .. ori.Z

							end

							wait() -- wait time before next rotation
							Rotating = false
						end
					end
				end)

				--- Place function
				PlacementTool.Activated:Connect(function() -- if clicked

					local result, errorMsg = pcall(function()
						PlacePlacement:FireServer(Placement_Hologram.Name, Placement_Hologram.PrimaryPart.CFrame)
					end)

					if not result then
						warn("Couldn't Place:", PlacementTool.Name, "ErrorMsg:", errorMsg)
					else
						if Mouse_Moving then
							Mouse_Moving:Disconnect()
						end
						PlacementTool:Destroy()
						ResetINFO_UI()
						
						wait()
						Placement_Hologram = nil
					end
					
				end)
				
				DB = false
			end
		end)
		
		--- Unequipped function
		PlacementTool.Unequipped:Connect(function()
			if Mouse_Moving then
				Mouse_Moving:Disconnect()
			end
			local HologramToDelete = TempHologram:FindFirstChild(PlacementTool.Name)
			
			if HologramToDelete then
				HologramToDelete:Destroy()
				ResetINFO_UI()
				
				wait()
				Placement_Hologram = nil
			end
			
		end)

	end
end
				
1 Like

is that the entire block of code?

if so, you aren’t returning if DB is true, youre just saying if its false then make it true

	for i, PlacementTool in pairs(CollectionService:GetTagged("PlacementTool")) do -- gets all tools tagged with "PlacementObject"
		local Mouse_Moving = nil

		PlacementTool.Equipped:Connect(function() -- once tool Equipped
			if not DB then return end
DB = true
1 Like

No, the entire code is too long, by default the DB is set to false

I’ve update it now with entire code

Could it be that I don’t have “DB = false” in Unquipped?

ok so what im getting is when equipped make debounce true and when unequipped make the debounce false??

I’m not sure, I should be adding “DB = false” to unequipped?

yeah,

the second PlacementTool.Equipped: runs, DB = false, thats probably why it runs multiple times.

What is the purpose of the DB variable? It does not look like it’s a debounce of any sort, and at a glance there’s no evidence of the code in between the DB = true and DB = false yielding, so it’s serving no purpose unless there is yielding code in our of your unshown helper functions that is running on the event firing (e.g. Weld_Hologram, CalculateMass, Hologram_PosCalc)

It’s not clear to me if one copy of ‘DB’ shared by all of the tools is even what you want. You call it a ‘debounce’, which suggests you are trying to prevent re-equipping of the same tool, but it’s set up like more of a mutex, in that equipping any tool would (if there is yielding code) momentarily block equipping of the other tools. What is your real intent?

That said, normally when something like an event handler runs more times than expected, it’s because multiple copies of anonymous functions are binding to it. Are you calling Update_CollectionService() more than once, ever? There are no RBXScriptSignal variables here or signal:Disconnects() so your connections that we see will all last for the lifetime of the tools themselves, and binding multiple times to Equipped or Unequipped is certainly a possibility.

This script is for a placement system that I have, I don’t want the player to spam equip to prevent it from breaking or placing multiple objects at a fast rate, the problem was that I had put the “DB = false” on the wrong line, its fixed now by placing it in “Unequipped” and “Activated”, yes I do have yielding in unshown function Unequipped_Tools().

Update_CollectionService() is called everytime a new tool leaves or enters the player backpack if I remember correctly.

Its okay now I’ve updated a lot of parts of the script and its not the same as pasted one.

Which type of connections btw?

That’s going to bind a new copy of the event handlers for Equipped and Unequipped, for every tool. If a new tool enters the backpack, you need to hookup the handlers for just that tool, not that tool plus all of the others.

Every time you call SomeInstance.SomeKindOfEvent:Connect() it returns a reference to the RBXScriptSignal that you’re meant to hang on to, so that you can do things like:

equippedSignalConn = tool.Equipped:Connect( function()
    --do some stuff
end)

so that you can later call:

equippedSignalConn:Disconnect()

If you want to re-establish a connection to an event, to bind it to a different function, you normally want to kill off the old connection, then make a new one, e.g.:

if equippedSignal then
    equippedSignal:Disconnect()
end
equippedSignal = tool.Equipped:Connect(function()
    --do something different than before
end)

If you never Disconnect() any RBXScriptSignals, they all stay bound for as long as the instance that fires the event exists. So every PlacementTool will fire its Equipped function as many times as Update_CollectionService() got call while it was in the backpack (e.g. once as intended, but then once more for each tool that got added to the backpack after it).

I do end the bound for the Mouse_Moving, but your suggesting that I should do it for the equipped and unequipped too?