Odd Duplication Glitch

Hello robloxians! I am making a Flood Escape “Zipline Tools” plugin, which allows you to add points. However, when I try to click the button, it adds more than one point. Why does this happen?

script

gui.editFrame.addPoint.Activated:Connect(function()
	if selectedPoint == 0 then
		print("No point selected.")
	else
		local oldPoint = selectedRope:FindFirstChild("Point"..selectedPoint)

		local point = Instance.new("Part")

		point.Color = Color3.fromRGB(17, 17, 17)
		point.Size = Vector3.new(0.6, 0.4, 0.4)
		point.Material = "DiamondPlate"
		point.CanCollide = false
		point.CFrame = oldPoint.CFrame
		point.Parent = selectedRope
		point.Name = "Point"..selectedPoint + 1

		for i, v in pairs(selectedRope:GetChildren()) do
			if string.sub(v.Name, 1, 5) == "Point" and v ~= point then
				local number1 = tonumber((string.sub(v.Name, 6, #v.Name)))

				if number1 > selectedPoint then
					v.Name = "Point"..number1 + 1
				end
			end
		end

		selectedPoint = tonumber((string.sub(point.Name, 6, #point.Name)))
		gui.editFrame.selectedPoint.Text = "Selected Point: Point "..selectedPoint

		SelectionService:Set({point})

		RefreshGUI1(selectedRope)

		return
	end
end)
2 Likes

A quick glimpse seems like your code looks fine, I’d suggest you throw in different print statements to see where in your code it stops executing.

1 Like

Hello! Sorry but that kinda fixed itself, but added a new problem and I updated the post accordingly.

1 Like

Try adding a debounce so that you can limit the rate

1 Like

There is a lot going on, but maybe try making sure the addition is done before it is concentrated with a string?

So instead of point.Name = "Point"..selectedPoint + 1
try, point.Name = "Point"..(selectedPoint + 1)

2 Likes

Hello! I have updated the script to add comments.

gui.editFrame.addPoint.Activated:Connect(function()
	if addDebounce then return end
	if selectedPoint == 0 then
		print("No point selected.")
	else
		addDebounce = true
		
		
		-- Gets the point selected
		local oldPoint = selectedRope:FindFirstChild("Point"..selectedPoint)
		
		-- Creates a new point
		local point = Instance.new("Part")

		point.Color = Color3.fromRGB(17, 17, 17)
		point.Size = Vector3.new(0.6, 0.4, 0.4)
		point.Material = "DiamondPlate"
		point.CanCollide = false
		point.CFrame = oldPoint.CFrame
		point.Parent = selectedRope
		point.Name = "Point"..(selectedPoint + 1)
		
		-- Updates other points accordingly
		for i, v in pairs(selectedRope:GetChildren()) do
			if string.sub(v.Name, 1, 5) == "Point" and v ~= point then
				local number1 = tonumber((string.sub(v.Name, 6, #v.Name)))

				if number1 > selectedPoint then
					v.Name = "Point"..number1 + 1
				end
			end
		end
		
		-- Automatically select the new point in studio, and the plugin
		selectedPoint = tonumber((string.sub(point.Name, 6, #point.Name)))
		gui.editFrame.selectedPoint.Text = "Selected Point: Point "..selectedPoint

		SelectionService:Set({point})
		
		-- Refreshes the gui
		RefreshGUI1(selectedRope)
		
		return
	end
end)
1 Like

Make sure you set the debounce variable to false after your code has finished executing or else it will not run again.

1 Like

Hello! That debounce does not matter because that debounce doesn’t work!

Make sure you’re updating other points the same way?
image
v.Name = "Point"..(number1 + 1)

Hello! I have tried that, it doesn’t work :frowning:
I seriously have no idea what is going on with this.

The full script:

local ChangeHistoryService = game:GetService("ChangeHistoryService")
local SelectionService = game:GetService("Selection")

local toolbar = plugin:CreateToolbar("FE2 Zipline Tools")

local newZiplineButton = toolbar:CreateButton("Create New Zipline", "Creates a brand new zipline.", "rbxassetid://15858367780")
local editPointsButton = toolbar:CreateButton("Edit Points", "Edit the points of a zipline.", "rbxassetid://15858367780")

local gui = script:WaitForChild("mainGuiFE2Zipline")

local selectedPoint = 0
local selectedRope = nil

local addDebounce = false

newZiplineButton.Click:Connect(function()
	local zipline = game.InsertService:LoadAsset(15858266853)
	zipline.Parent = workspace
	
	local actualZipline = zipline.Zipline
	
	actualZipline.Parent = workspace
	actualZipline:SetPrimaryPartCFrame(workspace.Camera.CFrame)
	--actualZipline:SetPrimaryPartCFrame(workspace.Camera.CFrame * CFrame.Angles(math.rad(actualZipline.Part.Orientation.X * -1), math.rad(actualZipline.Part.Orientation.Y * -1), math.rad(actualZipline.Part.Orientation.Z * -1)))
	actualZipline.Part:Destroy()
	
	ChangeHistoryService:SetWaypoint("Added new zipline.")
	SelectionService:Set({actualZipline})
	
	zipline:Destroy()
end)

editPointsButton.Click:Connect(function()
	if gui.Parent == script then
		for i, v in pairs(game.CoreGui:GetChildren()) do
			if string.find(v.Name, "mainGuiFE2Zipline") then
				gui = script.mainGuiFE2Zipline:Clone()
				v:Destroy()
			end
		end
		gui.Parent = game:WaitForChild("CoreGui")
	else
		gui.Parent = script
	end
end)

local function RefreshGUI1(selection)
	for i, v in pairs(gui.editFrame.points:GetChildren()) do
		if v.Name ~= "template" and v.Name ~= "UIListLayout" then
			v:Destroy()
		end
	end
	
	local points
	local selected

	if selection.Name == "_Rope" then
		selected = selection
		points = selection:GetChildren()
	end

	for i, p in pairs(points) do
		if p:IsA("Configuration") then
			table.remove(points, i)
		end
	end
	
	for i, v in pairs(points) do
		local btn = gui.editFrame.points.template:Clone()
		
		btn.Name = "Point "..string.sub(v.Name, 6, #v.Name)

		btn.po.Text = "Point "..string.sub(v.Name, 6, #v.Name)
		btn.LayoutOrder = string.sub(v.Name, 6, #v.Name)

		btn.Visible = true
		btn.Parent = gui.editFrame.points
		
		btn.MouseButton1Click:Connect(function()
			for i, x in pairs(gui.editFrame.points:GetChildren()) do
				if string.find(x.Name, "Point ") then
					x.TextColor3 = Color3.fromRGB(255, 255, 255)
				end
			end
			local number2 = tonumber((string.sub(btn.Name, 7, #btn.Name)))
			selectedPoint = number2
			gui.editFrame.selectedPoint.Text = "Selected Point: Point "..selectedPoint
			btn.TextColor3 = Color3.fromRGB(0, 255, 0)
		end)
		
		gui.editFrame.addPoint.Activated:Connect(function()
			if selectedPoint == 0 then
				print("No point selected.")
			else
				local oldPoint = selectedRope:FindFirstChild("Point"..selectedPoint)

				local point = Instance.new("Part")

				point.Color = Color3.fromRGB(17, 17, 17)
				point.Size = Vector3.new(0.6, 0.4, 0.4)
				point.Material = "DiamondPlate"
				point.CanCollide = false
				point.CFrame = oldPoint.CFrame
				point.Parent = selectedRope
				point.Name = "Point"..selectedPoint + 1

				for i, v in pairs(selectedRope:GetChildren()) do
					if string.sub(v.Name, 1, 5) == "Point" and v ~= point then
						local number1 = tonumber((string.sub(v.Name, 6, #v.Name)))

						if number1 > selectedPoint then
							v.Name = "Point"..number1 + 1
						end
					end
				end

				selectedPoint = tonumber((string.sub(point.Name, 6, #point.Name)))
				gui.editFrame.selectedPoint.Text = "Selected Point: Point "..selectedPoint

				SelectionService:Set({point})

				RefreshGUI1(selectedRope)
				
			end
		end)
		
		gui.editFrame.deletePoint.MouseButton1Click:Connect(function()
			if selectedPoint == 0 then
				warn("No point selected.")
			else
				if #points > 2 then
					for i, n in pairs(points) do
						if selected:FindFirstChild("Point"..i) then
							local number2 = selectedPoint
							
							if number2 == #points or number2 == 1 then
								warn("Cannot delete first or last point.")
								return
							else
								if i > number2 then
									local number1 = tonumber((string.sub(v.Name, 6, #v.Name)))

									selected:FindFirstChild("Point"..i).Name = "Point"..(i - 1)
								end
							end
						else
							warn("Point "..i.." not found.")
							return
						end
					end
					
					ChangeHistoryService:SetWaypoint("Deleted point.")
					
					v:Destroy()

					RefreshGUI1(selection)
				else
					warn("Not enough points.")
				end
			end
		end)
	end
end

SelectionService.SelectionChanged:Connect(function()
	local selection = SelectionService:Get()
	if #selection == 1 then
		for i, v in pairs(gui.editFrame.points:GetChildren()) do
			if v.Name ~= "template" and v.Name ~= "UIListLayout" then
				v:Destroy()
			end
		end
		
		if selection[1].Name == "_Rope" then
			selectedRope = selection[1]
			RefreshGUI1(selection[1])
		elseif selection[1]:FindFirstAncestor("_Rope") then
			selectedRope = selection[1]:FindFirstAncestor("_Rope")
			RefreshGUI1(selection[1]:FindFirstAncestor("_Rope"))
		else
			selectedPoint = 0
			gui.editFrame.selectedPoint.Text = "Selected Point: None"
			warn("No rope selected.")
			return
		end
	elseif #selection >= 2 then
		for i, v in pairs(gui.editFrame.points:GetChildren()) do
			if v.Name ~= "template" and v.Name ~= "UIListLayout" then
				v:Destroy()
			end
		end
		
		selectedPoint = 0
		gui.editFrame.selectedPoint.Text = "Selected Point: None"
		
		warn("Multi-selections are currently not compatible.")
		return
	elseif #selection == 0 then
		warn("No rope selected.")
		return
	end
end)

gui.editFrame.addPoint.Activated:Connect(function()
	if selectedPoint == 0 then
		print("No point selected.")
	else
		-- Gets the point selected
		local oldPoint = selectedRope:FindFirstChild("Point"..selectedPoint)
		
		-- Creates a new point
		local point = Instance.new("Part")

		point.Color = Color3.fromRGB(17, 17, 17)
		point.Size = Vector3.new(0.6, 0.4, 0.4)
		point.Material = "DiamondPlate"
		point.CanCollide = false
		point.CFrame = oldPoint.CFrame
		point.Parent = selectedRope
		point.Name = "Point"..(selectedPoint + 1)
		
		-- Updates other points accordingly
		for i, v in pairs(selectedRope:GetChildren()) do
			if string.sub(v.Name, 1, 5) == "Point" and v ~= point then
				local number1 = tonumber((string.sub(v.Name, 6, #v.Name)))

				if number1 > selectedPoint then
					v.Name = "Point"..(number1 + 1)
				end
			end
		end
		
		-- Automatically select the new point in studio, and the plugin
		selectedPoint = tonumber((string.sub(point.Name, 6, #point.Name)))
		gui.editFrame.selectedPoint.Text = "Selected Point: Point "..selectedPoint

		SelectionService:Set({point})
		
		-- Refreshes the gui
		RefreshGUI1(selectedRope)
		
		return
	end
end)

Aha! I found the issue! For some reason, I had the adding function in the RefreshGui1() function. That was causing the issue!

New problem, it doesn’t work again.

1 Like

It solved your issue and then it didn’t?

1 Like

Yes, sadly. Sometimes that happens to people I guess :sweat_smile:

Did you touch anything else? Sometimes that’s how I feel, but I might’ve moved something else around

No, I only removed that random function. That was the only part I touched.

Does it not work at all or is it still duplicating?

Nope, it’s completely broken now.

Did you try putting print statements to see how far your code gets before it stops executing?

Yes, just did that. Prints nothing in the output.

Does it even detect when the button is pressed?