Inventory Items Not Showing In Custom GUI

  1. What do you want to achieve?

I’ve more or less achieved exactly what I’ve wanted. I have a custom inventory. When a player picks up a new tool it adds to the inventory perfectly. But …

  1. What is the issue?

When a player receives the tool from a tool-giver or, more critically, buys the tool, it doesn’t appear in the inventory until the player respawns (not convenient.) Purchasing is happening, everything goes through and if I look at the player’s backpack in Explorer the newly given/purchased items are there … they’re just NOT showing in the GUI. Again, what’s strange is that if I simply pick-up a tool (no clicking, no purchasing) it appears instantly, no problem.

In the screenshot, I’ve just picked up the ‘ClassicSword’ and it appears instantly in Explorer AND in the GUI, as it should. I then clicked the Giver (for the ‘NoobBoard’ tool) … it appears in Explorer, so the player technically has it, but it won’t show in the GUI. (Fyi … The ‘NoobBoard’ tool is NOT the issue. The same thing happens regardless of what tool the Giver ‘gives’.)

InventoryIssue.rbxl (214.4 KB)

Hopefully the problem should be more obvious in the RBXL file. For the record I’ve also checked in a more advanced version of the game, with purchases all set-up. Purchases happen perfectly, the new tool appears in the player’s backpack (explorer) but again, DOESN’T show in the GUI. I’m assuming the ‘purchased tool’ is having the same issue as the ‘given tool’.

  1. What solutions have you tried so far? Did you look for solutions on the Developer Hub?
    I’ve looked here, and everywhere for solutions. For the record hotbar/inventory script is ‘borrowed’. I know this isn’t the best route, but up until this final issue the code was doing everything I wanted, perfectly - there seemed no reason to plunge in and develop my own. I’ve tweaked/modified the code slightly (mainly cosmetic/appearance stuff for the GUI.)

Is there something dumb and obvious I’m overlooking?

Thanks in advance for any help. I’m pulling my hair out!

Pro-tip: people are less likely to help when they have to download and open a file to find the issue. Plus, some (like me) use a mobile devforum. Paste your scripts if you want help faster.

Edit: I’m willing to help, but I have no way of accessing that file right now.

Hi there, and thanks for the reply. Here’s the script. Like I said, I’ve shamelessly borrowed this. Not a habit, but it initially seemed to do everything I wanted it to. Happy with all it does, and happy with my mods, but just can’t nail this final issue.

Here’s a screenshot of the hierarchy:
InventoryIssue02

The code (localscript):

game:GetService('StarterGui'):SetCoreGuiEnabled(Enum.CoreGuiType.Backpack, false)
local uis = game:GetService("UserInputService")
local player = game.Players.LocalPlayer
local char = workspace:WaitForChild(player.Name) -- added WaitForChild
local bp = player.Backpack
local hum = char:WaitForChild("Humanoid")
local mouse = player:GetMouse()
local frame = script.Parent.Hotbar
local template = frame.Template
local equipped = 0 -- icon transparencies
local unequipped = 0.7
local Inventory = script.Parent.Inventory
local Template = Inventory.Items.Template
local InventoryButton = script.Parent.InventoryButton

local HotbarItems = {}
local previousInput 

local inventoryOpen = false

-- Hotbar stuff

local iconSize = template.Size
local iconBorder = {x = 15, y = 5} -- pixel space between icons

local inputKeys = { -- dictionary for effective referencing
	["One"] = {txt = "1"},
	["Two"] = {txt = "2"},
	["Three"] = {txt = "3"},
	["Four"] = {txt = "4"},
	["Five"] = {txt = "5"},
	["Six"] = {txt = "6"},
	["Seven"] = {txt = "7"},
	["Eight"] = {txt = "8"},
	["Nine"] = {txt = "9"},
}

local inputOrder = { -- array for storing the order of the keys
	inputKeys["One"],inputKeys["Two"],inputKeys["Three"],inputKeys["Four"],inputKeys["Five"],inputKeys["Six"],inputKeys["Seven"],inputKeys["Eight"],inputKeys["Nine"]
}

-- So tool doesn't instasntly equip on pickup

local Tools = {}


for I, v in pairs(player.Backpack:GetChildren()) do
	Tools[v] = true
end

char.ChildAdded:connect(function(Obj)
	if Obj:IsA("Tool") then
		if not Tools[Obj.Name] then
			wait()
			Obj.Parent = player.Backpack
			if previousInput and previousInput["tool"] then
				handleEquip(previousInput["tool"])
			end
		end
	end
end)

--< functions >--

function getToolAmount(tool) -- Gets the total amount of a certain tool
	local toolAmount = 0
	for i,v in pairs(bp:GetChildren()) do
		if v.Name == tool.Name then
			toolAmount += 1
		end
	end
	if char:FindFirstChild(tool.Name) then
		toolAmount += 1
	end
	return toolAmount
end

function adjust() -- adjusts all icons in the hotbar
	for key, value in pairs(inputKeys) do
		local tool = value["tool"]
		local icon = frame:FindFirstChild(value["txt"])

		if tool then
			icon.Image = tool.TextureId
			icon.BackgroundTransparency = 0

			wait(0.2) 

			local toolAmount = getToolAmount(tool)
			if toolAmount > 1 then
				icon.Label.Visible = true
				icon.ImageLabel.Visible = true
			else
				icon.Label.Visible = false
				icon.ImageLabel.Visible = false
			end
			icon.Label.Text = toolAmount
			
			if char:FindFirstChild(tool.Name) then -- if the tool is equipped...
				icon.BackgroundTransparency = equipped
			end
		else
			icon.Label.Text = 0
			icon.Label.Visible = false
			icon.ImageLabel.Visible = false
			icon.BackgroundTransparency = unequipped
			icon.Image = ""
		end
	end
end

function handleEquip(tool) -- Equips and unequips the tools
	if tool then
		if tool.Parent ~= bp then
			Tools[tool.Name] = false
			hum:UnequipTools()
		else
			Tools[tool.Name] = true
			hum:EquipTool(tool)
		end
		adjust()
	end
end

function onKeyPress(inputObject) -- press keys to equip/unequip
	local key = inputObject.KeyCode.Name
	local value = inputKeys[key]
	if value and uis:GetFocusedTextBox() == nil then -- don't equip/unequip while typing in text box
		previousInput = value
		handleEquip(value["tool"])
		
		if value["tool"].Parent == char then
			previousInput = value
		else
			previousInput = nil
		end
	end 
end

function handleAddition(adding) -- Fires when a tool is added to the backpack
	if adding:IsA("Tool") then
		local new = true
		
		for key, value in pairs(inputKeys) do
			local tool = value["tool"]
			if tool then -- if there is a tool...
				if tool.Name == adding.Name then -- and the tool has the same name as the tool being added...
					
					new = false -- then the tool being added is not new
				end
			end
		end
	
		if new then
			for i = 1, #inputOrder do
				local tool = inputOrder[i]["tool"]
				if not tool and table.find(HotbarItems, adding.Name)  then -- if the tool slot is free...
					inputOrder[i]["tool"] = adding
					
					break
				end
			end
		end
		adjust()
	end
end

function handleRemoval(removing) -- Fires when a tool is removed from the player's character
	if removing and removing:IsA("Tool") then
		for i = 1, #inputOrder do
			if removing.Parent ~= bp then
				if inputOrder[i]["tool"] and inputOrder[i]["tool"].Name == removing.Name then
					Tools[removing.Name] = false
					if getToolAmount(removing) <= 0 then
						-- If there is no more of the tool in the player backpack or on their character, 
						-- it is safe to assume it has been dropped into the workspace
						inputOrder[i]["tool"] = nil
						previousInput = nil
						table.remove(HotbarItems, table.find(HotbarItems, removing.Name))
					else 
						wait() -- added a wait because, without it, it would cause some timing issues
						local tool = bp:FindFirstChild(removing.Name)
						inputOrder[i]["tool"] = tool
						handleEquip(tool)
					end
					break
				end
			end
		end 
	end
	adjust()
end

function create() -- creates all the icons at once (and will only run once)
	local toShow = #inputOrder -- # operator can only be used with an array, not a dictionary
	local totalX = (toShow*iconSize.X.Offset)+((toShow+1)*iconBorder.x)
	local totalY = iconSize.Y.Offset + (2*iconBorder.y)

	frame.Size = UDim2.new(0, totalX, 0, totalY)
	frame.Position = UDim2.new(0.5, -(totalX/2), 1, -(totalY+(iconBorder.y*2)))
	frame.Visible = true -- just in case!

	for i = 1, #inputOrder do

		local value = inputOrder[i]		
		local clone = template:Clone()
		clone.Parent = frame
		clone.Label.Text = value["txt"]
		clone.Name = value["txt"]
		clone.Visible = true
		clone.Position = UDim2.new(0, (i-1)*(iconSize.X.Offset)+(iconBorder.x*i), 0, iconBorder.y)
		clone.ImageTransparency = 0
		
		local tool = value["tool"]
		
		-- Creates a display label to show the tool's name
		local label
		clone.MouseEnter:Connect(function()
			if value["tool"] then
				local labelClone = script.Parent.ItemLabel:Clone()

				labelClone.Text = "Test"
				labelClone.Position = UDim2.new(0, mouse.X, 0, mouse.Y + 10)
				labelClone.Visible = true
				label = labelClone
				labelClone.Parent = script.Parent
				
			end
		end)
		clone.MouseLeave:Connect(function()
			if label then
				label:Destroy()
			end
		end)

		clone.Tool.Activated:Connect(function() -- click icon to equip/unequip
			for key, value in pairs(inputKeys) do
				if value["txt"] == clone.Name and value["tool"] then
					if inventoryOpen == true then 
						-- If the inventory is open, then the player is taking the tool off of their hotbar
						if label then
							label:Destroy()
						end
						previousInput = nil
						table.remove(HotbarItems, table.find(HotbarItems, value["tool"].Name))
						createInventorySlot(inputOrder[i]["tool"])
						if char:FindFirstChild(value["tool"].Name) then
							handleEquip(char:FindFirstChild(value["tool"].Name))
						end
						inputOrder[i]["tool"] = nil
						handleRemoval(value["tool"])
						clone.Parent.Image = ""
						
					else -- If it is closed then they are trying to equip/unequip it
						
						if char:FindFirstChild(value["tool"].Name) then
							previousInput = nil
							handleEquip(char:FindFirstChild(value["tool"].Name))
						else
							previousInput = value
							handleEquip(bp:FindFirstChild(value["tool"].Name))
						end
					end
				end 
			end
		end)

	end	
	template:Destroy()
end

function setup() -- sets up all the tools already in the backpack (and will only run once)
	local tools = bp:GetChildren()
	for i = 1, #tools do 
		if tools[i]:IsA("Tool") then -- does not assume that all objects in the backpack will be a tool (2.11.18)
			for i = 1, #inputOrder do
				local value = inputOrder[i]
				
				if not value["tool"] then -- if the tool slot is free...
					--value["tool"] = tools[i]	
					
					break -- stop searching for a free slot
				end
			end
		end
	end
	create()
end

--< events >--
uis.InputBegan:Connect(onKeyPress)

--< start >--
setup()

bp.ChildAdded:Connect(handleAddition)
char.ChildRemoved:Connect(handleRemoval)

-- Inventory stuff

function hotbarAddition(tool) -- Adds a tool into the hotbar
	table.insert(HotbarItems, tool.Name)	
	handleAddition(tool)
end

function createInventorySlot(tool) -- creates an item slot for a tool
	local clone = Template:Clone() -- creates a clone of the item to display it
	clone.Name = tool.Name
	
	clone.Parent = Inventory.Items
	
	local toolAmount = getToolAmount(tool)
	if toolAmount > 1 then
		clone.Label.Visible = true
	end
	clone.Label.Text = tostring(toolAmount)
	
	local object = tool:Clone()
	object.Parent = clone
	
	object.Handle.Orientation = Vector3.new(0,0,0)
	object.Handle.Position = Vector3.new(0,0,0)

	clone.Image = object.TextureId
	local label -- creates a label to display the name
	clone.MouseEnter:Connect(function()
		local labelClone = script.Parent.ItemLabel:Clone()
		labelClone.Text = object.Name
		labelClone.Position = UDim2.new(0, mouse.X, 0, mouse.Y + 10)
		labelClone.Visible = true
		label = labelClone
		labelClone.Parent = script.Parent
	end)
	clone.MouseLeave:Connect(function()
		if label then
			label:Destroy()
		end
	end)
	
	clone.Activated:Connect(function()
		local FilledInputs = 0
		for i = 1, #inputOrder do -- counts how many spot on the hotbar are full
			if inputOrder[i]["tool"] then
				FilledInputs += 1
			end
		end
		
		if FilledInputs < #inputOrder then -- if the hotbar has an open space
			clone:Destroy()
			if label then
				label:Destroy()
			end
			hotbarAddition(tool)
		end	
	end)
	
	clone.Visible = true
	clone.Parent = Inventory.Items
end

function adjustInventory(child,tool)
	if Inventory.Items:FindFirstChild(child.Name) then
		local toolAmount = getToolAmount(child)

		if toolAmount <= 0 then
			Inventory.Items:FindFirstChild(child.Name):Destroy()
		else
			if toolAmount == 1 then
				Inventory.Items:FindFirstChild(child.Name).Label.Text = toolAmount
				Inventory.Items:FindFirstChild(child.Name).Label.Visible = false
				Inventory.Items:FindFirstChild(child.Name).ImageLabel.Visible = false
			else
				Inventory.Items:FindFirstChild(child.Name).Label.Text = toolAmount
				Inventory.Items:FindFirstChild(child.Name).Label.Visible = true
				Inventory.Items:FindFirstChild(child.Name).ImageLabel.Visible = true
			end

		end
		else if not table.find(HotbarItems, child.Name) then
			createInventorySlot(child)		
		end
	end
end

function createInventory() -- setups the entire initial inventory
	for _,tool in pairs(bp:GetChildren()) do
		local toolAmount = getToolAmount(tool)
		if not Inventory.Items:FindFirstChild(tool) then
			if toolAmount < 2 then
				createInventorySlot(tool)
			end			
		end
		adjustInventory(tool)	
	end
end

InventoryButton.Activated:Connect(function() -- toggles the inventory
	if Inventory.Visible == true then
		Inventory.Visible = false
		inventoryOpen = false
	else
		Inventory.Visible = true
		inventoryOpen = true
	end
end)

bp.ChildAdded:Connect(adjustInventory)
bp.ChildRemoved:Connect(adjustInventory)

char.ChildAdded:Connect(adjustInventory)
char.ChildRemoved:Connect(adjustInventory)

createInventory()



Dang! Well, I worked it out. It was all down to adding a 1 second ‘wait’ call before a function, and all works well.
The ‘wait’ goes into the ‘function adjustInventory(child,tool)’ if anyone experiences a similar issue.
All down to timing. Grrrrrrr…