Entering and exiting item placement mode with ContextActionService seems not to work

Hello!

I’m working on a game placement mode which allows you to place objects and cancel object placement. I’m trying to use ContextActionService, however the function seems not to bind, as no input affects anything. I’ve added a print and that doesn’t do anything either.

The actual function:

local function buildMode(actionName, key, inputObject)
	if actionName == 'buildMode' then
		if key.UserInputType == Enum.UserInputType.MouseButton1 then
			local canPlace
			local s,e = pcall(function()
				canPlace = Functions.PurchaseObject:InvokeServer(Selection.PrimaryPart.CFrame)
			end)
			if not s then return end
			if canPlace == true then
				print('canPlace')
				return
			end
		elseif key.UserInputType == Enum.UserInputType.Keyboard then
			if key.KeyCode == Enum.KeyCode.R then
				PlacementModule:Rotate(Mouse, Selection)
			end
		end
	end
end

What should bind and unbind the action

btn.MouseButton1Click:Connect(function()
		local SelectionRS = game.ReplicatedStorage.Models.PlotModels[Model.Name]
	    Selection = SelectionRS:Clone()
		if not Selection.PrimaryPart then
			Selection.PrimaryPart = Selection:FindFirstChild('BoundingBox')
		end
		local canPlace = Functions.RequestCanPlace:InvokeServer(SelectionRS)
		Mouse.Move:Connect(function()
			PlacementModule:SnapToGrid(Mouse, Selection, false)
		end)
		
		CAS:BindAction('buildMode', buildMode, false)
		UIS.InputBegan:Connect(function(key, isSystemReserved)
			if key.KeyCode == Enum.KeyCode.Q then
				CAS:UnbindAction('buildMode')
			end
		end)
	end)

The inputs need to be binded:

CAS:BindAction("buildMode", buildMode, false, Enum.KeyCode.R, Enum.UserInputType.MouseButton1)

Also addressing some other issues in the script:

  • Don’t nest connections if you’re not going to disconnect them – the Mouse.Move and InputBegan connections nested in the MouseButton1Click event brought up my concern. Having multiple events created for the same thing may cause unintended results and even memory leaks. Consider using :Disconnect() to disconnect the event when you’re done with them:
local moveCon

btn.MouseButton1Click:Connect(function()
    -- blah, blah, blah. Put whatever was above the code below
    moveCon = Mouse.Move:Connect(function()
        PlacementModule:SnapToGrid(Mouse, Selection, false)
    end)
end)

-- UIS event doesn't need to be in the MouseButton1Click event

UIS.InputBegan:Connect(function(key, isSystemReserved)
	if key.KeyCode == Enum.KeyCode.Q then
		CAS:UnbindAction('buildMode')
        moveCon:Disconnect()
        moveCon = nil
	end
end)
  • Whenever you press or release the buttons, it’ll trigger the function two times – you’d only want it to trigger once:
local function buildMode(actionName, state, key)
    if actionName == "buildMode" and state == Enum.UserInputState.Begin then
        -- blah, blah, blah. Rest of the code in this scope
    end
end
1 Like

Thanks! It worked very well, I also took your recommendations, my script looks cleaner IMO. Thanks for those as well!