Functions not being called, Keybinds not working, and Gui problems

First and foremost, I followed a zblox youtube tutorial to get the maths and general system out of the way. I have been modifying it with my own keybinds and code since. (I probably broke something)

  1. What do you want to achieve? Keep it simple and clear!
    A fully functioning placement system; more specifically I want the placement:finish() function to be called.

  2. What is the issue? Include screenshots / videos if possible!
    Placing items using my Inventory GUI works for two of the three buttons, and completely breaks when the third one becomes in use. When you click the gui button and press “E” to place the object, a few things happen. I have printed them out in the console for debugging reasons and I just cannot find the issue. This is what occurs.

  3. A table containing plot information is updated

  4. The inventory table has the item removed (is it now in the plot table because it is placed)

  5. The Gui button and everything in it is destroyed (including the local script… maybe it has something to do with it?)

  6. The placement:finish() function calls to finish the placement and destroy the object so you dont have the grid and object following you anymore but it only calls for the first 2 GUI Buttons.

There are no errors, just the Output saying that the finish placement function was not called the 3rd and final time. (And outright refuses to let me place or cancel or use any other keybind i set in the localscript until i click on a different button) button to place an object. It just seems to be the last one that does not work ??? Also, I am using the ContextActionService Service to assign and bind functions. Maybe this has something to do with it?

The finish placement function

function placement:finish()
-- basically its the same as cancel function above but u dont use a keybind. useful for when game needs to force quit placement instead of user ending placement and incase any other script needs to use.
        object:Destroy()

        if plot:FindFirstChild("Texture") then

            plot:FindFirstChild("Texture"):Destroy()

        end
        
        --contextActionService:UnbindAction("Place")
        print("Finish placement called")
        
        mouse.TargetFilter = nil
end

The place function

local function place(actionName, inputState, inputObject)
if inputState == Enum.UserInputState.Begin then
    
        -- cframe for the part to be placed
        local cf = getInstantCframe()

            -- Invoke a remote server function with the object's name, placed objects, CFrame, and plot
        
        game.ReplicatedStorage.Remotes.Place:InvokeServer(object.Name, placedobjects, cf, plot, IsMoving)
        

        placement:finish() -- this should be called when i place the last object down, but for some reason  in the output it is only called for the first 2 times.
        --unbindInputs() -- Doesnt do anything for some reason???
        
        
    --[[ needs work
        if IsMoving == true then
            
            IsMoving = false
            print(IsMoving)
            placement:finish()
            return 
        end
    --]]
    
    end
end

The local script (inside the gui button)

local player = game.Players.LocalPlayer
local location = player:WaitForChild("Plot")
local module = require(game:GetService("ReplicatedStorage").Modules.PlacementHandler)
local plot = game.Workspace.Plots:FindFirstChild(location.Value)


local placement = module.new(
    1, --grid size
    game.ReplicatedStorage.Items,
    Enum.KeyCode.R, Enum.KeyCode.X,Enum.KeyCode.M,Enum.KeyCode.E
    
)



local mouse = game.Players.LocalPlayer:GetMouse()


script.Parent.MouseButton1Down:Connect(function()
    
    placement:bindInputs()
    placement:activate("crate", plot.itemHolder, plot, false)
    
end)

the place remote event

local Datastorev2 = require(game:GetService("ServerScriptService"):WaitForChild("Modules"):WaitForChild("DataStore2"))
local key = require(game.ServerScriptService.Modules.Dataversion)[1]



-- handles collisions on the hitbox

local function handleCollisions(object, char)
	local collided = false
	if object then

		local collisionpoint = object.PrimaryPart.Touched:Connect(function() end)
		local collisionpoints = object.PrimaryPart:GetTouchingParts()

		for i = 1, #collisionpoints, 1 do
			if not collisionpoints[i]:IsDescendantOf(object) and not collisionpoints[i]:IsDescendantOf(char) then
				collided = true

				break
			end
		end

		collisionpoint:Disconnect()

		return collided
	end

end

local function place(plr, id, location, cf, plot, wasmovedobject)
	
	local item = game.ReplicatedStorage.Items:FindFirstChild(id):Clone()
	item.PrimaryPart.CanCollide = false
	item:PivotTo(cf)

	
	
	if plot then
		
		item.Parent = location
		
		local PlayerDatastore = Datastorev2(key, plr)
		PlayerDatastore:Update(function(DataTable)
			
			local relative = plot.CFrame:ToObjectSpace(cf)
	
			local saveitem = {
				
				["id"] = id,
				["CFrame"] = tostring(relative), 
				["Location"] = tostring(location)
				
				}
				
			local index = #DataTable.Plot + 1
			
			print(index.." placed down on plot")
			
			DataTable.Plot[index] = saveitem
			
			print(DataTable.Plot)
			
			local objectid = Instance.new("NumberValue")
			objectid.Parent = item
			objectid.Name = "TableID"
			objectid.Value = index  -- Use the index instead of DataTable.Plot[saveitem]
			
			
			
			local ItemTable = DataTable.Inventory.Items


		if wasmovedobject == false then -- dont need to subtract from the inventory if the item was moved bc it was already on the plot to begin with
			
			for object,ammount in pairs(ItemTable) do
				-- find the item that was placed, and remove it from the items table bc it was put on the plot
				if object == id then
					
					local invgui = plr.PlayerGui.Inventory.Holder.ScrollingFrame:GetChildren()
					
					for i,v in pairs(invgui) do
						
						if v:IsA("TextButton") and v.tablenum.value == ammount then
							
							print(v.Name.." was removed from the gui")
							
							v:Destroy()
							
						end
					
					end
					
					
					ItemTable[object] = ammount - 1
					
					print(ItemTable[object].." in inventory left")
					
					if ItemTable[object] == 0 then
						-- if they place all the items u dont want a random entry being ["Desk"] = 0; bc thats just a waste of rescourses so get rid of it
						ItemTable[object] = nil
						
					end
					
				end

			end
		end	
			
			return DataTable
		end)
		
		if handleCollisions(item, plr.Character) and wasmovedobject == false then
			item:Destroy()
			return false
		end
	end
	
	return true
	
end

game.ReplicatedStorage.Remotes.Place.OnServerInvoke = place -- use "place" function when invoked from client

The keybinds


function placement:bindInputs()
	
	contextActionService:BindAction("Rotate", rotate, false, ROTATE_KEY) -- XBOX ROTATE KEY HERE IF CONSOLE ETC
	contextActionService:BindAction("Cancel", cancel, false, TERMINATE_KEY)
	contextActionService:BindAction("Move", move, false, MOVE_KEY)
	contextActionService:BindAction("Place",place, false, PLACE_KEY)
end

Screenshots
Output


The last Gui button that breaks everything

And example of what placing one of the other buttons looks like (no grid left no box left bc placement:finish() was called)

placing the last gui button (green arrow) (placed the object, but didnt delete the grid or the object and placement:finish() was not called)

I’m sorry if this post is confusing or clunky (or the code) I’m still very inexperienced and I dont post much here; I’m trying my hardest to make a game. Thanks for all your help! :heart: