Cancelling a function

function drawWall:StartPlacingWall(player, mouse)
		local playersPlot = workspace.Plots:FindFirstChild(player.Name)
		if playersPlot then
			local renderStepped
				
		local wall = Instance.new('Model', playersPlot.CameraPart)
		wall.Name = 'Wall'
		
		local pole1 = createPole:Pole('Pole1', wall)
				
		local pole2
		local wallPart
		local click
		local nope
		local generateWall
		
		local lowerX, upperX, lowerZ, upperZ = checkBase:GetBaseSize(playersPlot.Base)
		
		local renderStepped = runService.RenderStepped:Connect(function()
			renderPosition:Render(playersPlot, mouse.Hit.p, pole1, lowerX, upperX, lowerZ, upperZ)
		end)
		
		click = mouse.Button1Down:Connect(function()
			renderStepped:Disconnect()
			pole2 = createPole:Pole('Pole2', wall)
			
			local renderStepped = runService.RenderStepped:Connect(function()
				renderPosition:Render(playersPlot, mouse.Hit.p, pole2, lowerX, upperX, lowerZ, upperZ)
			end)
			
			nope = mouse.Button1Up:connect(function()
				nope:Disconnect()
				if pole2.CFrame ~= pole1.CFrame then
					renderStepped:Disconnect()
					generateWall:Disconnect()
					
					pole1.Transparency = 0
					pole2.Transparency = 0
					wallPart.Transparency = 0
					if click then
						click:Disconnect()
					end
					placing:FireServer('Wall', pole1.CFrame, pole2.CFrame)
					wall:Destroy()
					self:StartPlacingWall(player, mouse)
                end
            end
        end
end

I have this in a module (I’ve cut a lot out as I don’t want people stealing all of it, but basically runs like how the Sims wall placement works. You click, drag, it places a wall and it runs the function again ( so you dont have to keep clicking ‘Place wall’ for the function to run) so the self:StartPlacingWall(player, mouse) obviously runs the function again.

That works fine and dandy, but a problem that I’ve just noticed is cancelling. When a player cancel placement, I destroy the ‘placing part’ which is like a transparent part to show where the thing would be placed. However if you happen to click, it still places down the wall. Reason being is that even though they’ve cancelled the placement, the function above is still running.

function cancel:Cancel(cameraPart)
	cameraPart:ClearAllChildren()
	drawWall.StartPlacingWall:Disconnect()
end

That’s the cancel function (run in a seperate module)

[attempt to index field ‘StartPlacingWall’ (a function value)] on line 3 of the cancel function. I’m not sure what I am doing wrong, but is there a way to cancel the function after it’s already been running? I’m trying to think of how to do this in the best way possible (as in the future, there’s gonna be more modules for different placement, like paths, windows, furniture, etc.) and I dont wanna have to go through every single module and cancel the function.

I put it into a GIF to hopefully a little more sense as it’s kinda hard to explain.
com-video-to-gif

As you can from the GIF, you click wall, you can place wall, works good. Then when you click cancel the pole disappears, which is what should happen. But then, after I’ve left edit mode and I click, I can place the parts, as the function was still running (just without the transparent pole being there.

You could add a debounce called editModeEnabled, which when true let’s you edit, and false simply returns nil.

if not editModeEnabled then return end

Sure the events will still be running in the background, but it’s a temporary solution til you find something better.

1 Like

Only connections can be disconnected, not functions.

Here’s a way you could handle your connections so you can easily disconnect them later:

local drawWall = {Connections = {}}
drawWall.__Index = drawWall

function drawWall:StartPlacingWalls(...)
    ...
    local click
    ...
    table.insert(self.Connections, runService.RenderStepped:Connect(...))
    ...
    click = mouse.Button1Down:Connect(function(...)
        ...
        table.insert(self.Connections, runService.RenderStepped:Connect(...))
        ...
        table.insert(self.Connections, mouse.Button1Up:Connect(...))
        ...
    end)
    table.insert(self.Connections, click)
end

function drawWall:Disconnect()
    for _, connection pairs(self.Connections) do
        if connection.Connected then
            connection:Disconnect()
        end
    end
    self.Connections = {}
end

Then you can replace:

function cancel:Cancel(cameraPart)
	cameraPart:ClearAllChildren()
-	drawWall.StartPlacingWall:Disconnect()
+	drawWall:Disconnect()
end
5 Likes

Off topic but how do you highlight in code boxes?

3 Likes

image

5 Likes

That’s cool, kinda hard to read in dark theme tho (especially green)

4 Likes
function drawWall:StartPlacingWall(player, mouse)
	--if var.drawing then
		local playersPlot = workspace.Plots:FindFirstChild(player.Name)
		if playersPlot then
			local renderStepped
					
			local wall = Instance.new('Model', playersPlot.CameraPart)
			wall.Name = 'Wall'
			
			local pole1 = createPole:Pole('Pole1', wall)
					
			local pole2
			local wallPart
			local click
			local nope
			local generateWall
			
			local lowerX, upperX, lowerZ, upperZ = checkBase:GetBaseSize(playersPlot.Base)
			
			local renderStepped = table.insert(self.Connections, runService.RenderStepped:Connect(function()
				renderPosition:Render(playersPlot, mouse.Hit.p, pole1, lowerX, upperX, lowerZ, upperZ)
			end))

			click = table.insert(self.Connections, mouse.Button1Down:Connect(function()
				renderStepped:Disconnect()
				pole2 = createPole:Pole('Pole2', wall)
				
				local renderStepped = table.insert(self.Connections, runService.RenderStepped:Connect(function()
					renderPosition:Render(playersPlot, mouse.Hit.p, pole2, lowerX, upperX, lowerZ, upperZ)
				end))

				nope = table.insert(self.Connections, mouse.Button1Up:Connect(function()
					nope:Disconnect()
					if pole2.CFrame ~= pole1.CFrame then
						renderStepped:Disconnect()
						generateWall:Disconnect()
						
						pole1.Transparency = 0
						pole2.Transparency = 0
						wallPart.Transparency = 0
						if click then
							click:Disconnect()
						end
						placing:FireServer('Wall', pole1.CFrame, pole2.CFrame)
						wall:Destroy()
						self:StartPlacingWall(player, mouse)
					end
				end))
			end))				
			
			wallPart = Instance.new('Part', wall)
			wallPart.Anchored = true
			wallPart.CanCollide = false
			wallPart.Transparency = 1
			wallPart.Material = Enum.Material.SmoothPlastic
			wallPart.Name = 'WallPart'
			wallPart.Orientation = Vector3.new(0, 0, math.rad(90))
			
			generateWall = runService.RenderStepped:connect(function()
				if pole1 and pole2 then	
					wallPart.Transparency = 0.2
					wallPart.Size = Vector3.new((pole1.Position - pole2.Position).Magnitude, 10, 0.4)
					wallPart.CFrame = CFrame.new(
						pole1.Position + 0.5*(pole2.Position - pole1.Position),
						pole1.Position + 0.5*(pole2.Position - pole1.Position) + (pole1.Position - pole2.Position).Unit:Cross(Vector3.new(0, 1, 0))
					)
				end
			end)
		end
	--end
end

Not working :confused: not sure what I am doing wrong. Problems on the table.insert lines

Error here:
renderStepped:Disconnect()
attempt to index upvalue ‘renderStepped’ (a nil value)

1 Like
local renderStepped = table.insert(self.Connections, runService.RenderStepped:Connect(function()
					renderPosition:Render(playersPlot, mouse.Hit.p, pole2, lowerX, upperX, lowerZ, upperZ)
				end))

table.insert doesn’t return a value. You will need to find the position in the table when you set it and save that to the variable instead.

1 Like
local renderStepped = runService.RenderStepped:Connect(...)
table.insert(self.Connections, renderStepped)
1 Like