Tools not adding to inventory system

I tried several other ways, like making newer module’s with tool converting, to doing child adding and wouldn’t add

local ClientInventory = {}

-- Services
local Players, ReplicatedStorage, TweenService = game:GetService("Players"), game:GetService("ReplicatedStorage"), game:GetService("TweenService")
local UserInputService, RunService, StarterGui = game:GetService("UserInputService"), game:GetService("RunService"), game:GetService("StarterGui")

-- Setup
StarterGui:SetCoreGuiEnabled(Enum.CoreGuiType.Backpack, false)
local player, PlayerGui = Players.LocalPlayer, Players.LocalPlayer.PlayerGui
local character, remotes = player.Character or player.CharacterAdded:Wait(), ReplicatedStorage.Remotes
local playerBackpack = player.Backpack
local humanoid = character:WaitForChild("Humanoid")
local TradeablesData = require(ReplicatedStorage.Modules.Shared.TradeablesData)
local ClientInventoryViewport = require(ReplicatedStorage.Modules.ClientModules.ClientInventoryViewport)
local ClientInventoryEffects = require(ReplicatedStorage.Modules.ClientModules.ClientInventoryEffects)
local ClientInventoryDisplay = require(ReplicatedStorage.Modules.ClientModules.ClientInventoryDisplay)

local ScreenGui = PlayerGui:WaitForChild("HUD", math.huge)
local Backpack, Notifications = ScreenGui.Backpack, ScreenGui.Notifications
local Inventory, Hotbar, DraggingFrame, ToolTip = Backpack.Inventory, Backpack.Hotbar, Backpack.DraggingFrame, Backpack.ToolTip
local ToolTipTitle, ToolTipDescription  = ToolTip.ToolTipTitle, ToolTip.ToolTipDescription
local List, Equip, Unequip, ItemFrame, DisplayFrame = Inventory.List, Inventory.Equip, Inventory.Unequip, Inventory.ItemFrame, Inventory.DisplayFrame
local EquipmentFrame = Inventory.EquipmentFrame
local ItemFrameTitle, Slots = ItemFrame.Title, EquipmentFrame.Slots
local OutlineFrame, ViewportFrame, WorldModel = EquipmentFrame.Outline, EquipmentFrame.Outline.ViewportFrame, EquipmentFrame.Outline.ViewportFrame.WorldModel
local Chakra, ChakraInc, DamageInc, DefenseInc, Health, HealthInc, Speed, Stamina, StaminaInc = DisplayFrame.Chakra, DisplayFrame.ChakraInc, DisplayFrame.DamageInc, DisplayFrame.DefenseInc, DisplayFrame.Health, DisplayFrame.HealthInc,DisplayFrame.Speed, DisplayFrame.Stamina, DisplayFrame.StaminaInc

local equipAccessoryRemote = remotes.EquipAccessory
local unequipAccessoryRemote = remotes.UnequipAccessory
local checkItemRemote = remotes.CheckItem
local requestPreviewRemote = remotes.RequestAccessoryPreview
local updateAccessoryEquip = remotes.UpdateAccessoryEquipButton
local accessoryEquipSuccess = remotes.AccessoryEquipSuccess
local accessoryUnequipSuccess = remotes.AccessoryUnequipSuccess
local getInventoryData = remotes.GetInventoryData
local verifyUnequipRemote = remotes.VerifyUnequip
local requestPreviewRemotes = remotes.RequestAccessoryPreviews
local updateInventoryRemote = remotes.UpdateInventoryData
local refreshInventoryRemote = remotes.RefreshInventory

-- Private variables
local _isDragging, _draggedItem, _draggedItemOrigin, _draggedItemSlot, _draggedItemData = false, nil, nil, nil, nil
local _selectedSlot, _currentItem, _currentselectedSlot = 1, nil, nil
local _hotbarItems, _inventoryItems, _viewportModels, _slotItems, _toolMap, _previewRequests, _previewRequestsQueue = {}, {}, {}, {}, {}, {}, {}
local _dragOffsetX, _dragOffsetY = 0, 0
local equipped = {}
local selectedItemName = nil

local steps = 15
local waveStep = math.pi / 6
local colorSequenceCache = {}
local counter = 0
local frameCount = 0
local rotationIndex = 1
local mythicalGradients = {}
local _toolConnections = {}
local _equippedTool = nil

local _config = {
	SLOT_SIZE = 50,
	HORBAR_SIZE = 10,
	INVENTORY_ROWS = 4,
	INVENTORY_COLS = 6,
	VIEWPORT_ROTATION_SPEED = 1,
}

ClientInventory.hotbarItems, ClientInventory.inventoryItems, ClientInventory.slotItems = _hotbarItems, _inventoryItems, _slotItems

-- Convert Tool to inventory item format
function ConvertToolToItem(tool)
	if not tool or not tool:IsA("Tool") then return nil end

	local itemData = {
		name = tool.Name,
		rarity = tool:GetAttribute("Rarity") or "Common",
		description = tool:GetAttribute("Description") or "A useful tool",
		quantity = 1,
		id = tool.Name .. "_tool_" .. tostring(tool:GetDebugId()),
		toolInstance = tool, -- Reference to actual tool
		isRobloxTool = true, -- Flag to identify this as a Roblox tool
		toolExists = true
	}

	return itemData
end

-- Sync tools from backpack to inventory
function SyncToolsToInventory()
	print("Syncing tools from backpack to inventory...")

	local toolsFound = 0
	for _, tool in pairs(playerBackpack:GetChildren()) do
		if tool:IsA("Tool") then
			toolsFound = toolsFound + 1
			local itemData = ConvertToolToItem(tool)
			if itemData then
				-- Check if tool already exists in inventory
				local existingIndex = nil
				for idx, item in pairs(_inventoryItems) do
					if item and item.isRobloxTool and item.name == tool.Name then
						existingIndex = idx
						break
					end
				end

				if not existingIndex then
					-- Add tool to inventory if not already there
					local success = ClientInventory.ManageItem("add", itemData)
					if success then
						print("Added tool to inventory:", tool.Name)
					end
				end
			end
		end
	end

	print("Found", toolsFound, "tools in backpack")
end

-- Remove tool from inventory when it's deleted from backpack
function RemoveToolFromInventory(toolName)
	for idx, item in pairs(_inventoryItems) do
		if item and item.isRobloxTool and item.name == toolName then
			_inventoryItems[idx] = nil
			CompactInventory()
			ClientInventory.UpdateSlots("inventory")
			print("Removed tool from inventory:", toolName)
			break
		end
	end
end

-- Equip tool to character
function EquipTool(itemData)
	if not itemData or not itemData.isRobloxTool then return false end

	-- Unequip current tool first
	if _equippedTool then
		_equippedTool.Parent = playerBackpack
		_equippedTool = nil
	end

	-- Find the tool in backpack
	local tool = playerBackpack:FindFirstChild(itemData.name)
	if tool and tool:IsA("Tool") then
		tool.Parent = character
		_equippedTool = tool

		-- Update UI to show equipped state
		ClientInventoryEffects.CreateNotification(1, "Tool Equipped", "Equipped " .. tool.Name)
		return true
	else
		print("Tool not found in backpack:", itemData.name)
		return false
	end
end

-- Unequip current tool
function UnequipCurrentTool()
	if _equippedTool then
		_equippedTool.Parent = playerBackpack
		local toolName = _equippedTool.Name
		_equippedTool = nil
		ClientInventoryEffects.CreateNotification(1, "Tool Unequipped", "Unequipped " .. toolName)
		return true
	end
	return false
end

-- Monitor backpack changes
function SetupBackpackMonitoring()
	-- Clean up existing connections
	for _, connection in pairs(_toolConnections) do
		connection:Disconnect()
	end
	_toolConnections = {}

	-- Monitor tools added to backpack
	table.insert(_toolConnections, playerBackpack.ChildAdded:Connect(function(child)
		if child:IsA("Tool") then
			print("Tool added to backpack:", child.Name)
			wait(0.1) -- Small delay to ensure tool is fully loaded
			local itemData = ConvertToolToItem(child)
			if itemData then
				ClientInventory.ManageItem("add", itemData)
			end
		end
	end))

	-- Monitor tools removed from backpack
	table.insert(_toolConnections, playerBackpack.ChildRemoved:Connect(function(child)
		if child:IsA("Tool") then
			print("Tool removed from backpack:", child.Name)
			RemoveToolFromInventory(child.Name)
		end
	end))

	-- Monitor character changes (for re-equipping tools)
	table.insert(_toolConnections, player.CharacterAdded:Connect(function(newCharacter)
		character = newCharacter
		humanoid = character:WaitForChild("Humanoid")
		_equippedTool = nil

		-- Re-sync tools after character respawn
		wait(1) -- Wait for character to fully load
		SyncToolsToInventory()
	end))
end

function FindEmptyInvSlot()
	for i = 1, _config.INVENTORY_ROWS * _config.INVENTORY_COLS do 
		if not _inventoryItems[i] then return i end 
	end
	return nil
end

function CompactInventory()
	local temp, idx = {}, 1
	for _, item in pairs(_inventoryItems) do
		if item then temp[idx], idx = item, idx + 1 end
	end
	_inventoryItems = temp
end

function SetupSlotEvents(slot, idx, isHb)
	slot.InputBegan:Connect(function(input)
		if input.UserInputType == Enum.UserInputType.MouseButton1 then
			if isHb and not Inventory.Visible then 
				ClientInventory.SelectSlot(idx) 
				return 
			end
			local iData = isHb and _hotbarItems[idx] or _inventoryItems[idx]
			local hasItem = iData and (not isHb or iData.name ~= "Item Name")
			if not isHb and hasItem then 
				ClientInventoryDisplay.DisplayItemInFrame(iData)
				_currentItem, _currentselectedSlot = iData, idx 
			end
			if hasItem then
				_isDragging, _draggedItemOrigin = true, isHb and "hotbar" or "inventory"
				_draggedItemSlot, _draggedItemData = idx, iData
				_draggedItem = slot:Clone()
				_draggedItem.Parent = DraggingFrame
				local mPos = UserInputService:GetMouseLocation()
				local sCenter = slot.AbsolutePosition + (slot.AbsoluteSize / 2)
				_dragOffsetX, _dragOffsetY = mPos.X - sCenter.X, mPos.Y - sCenter.Y
				_draggedItem.Position = UDim2.new(0, mPos.X-(_config.SLOT_SIZE/2)-_dragOffsetX, 0, mPos.Y-(_config.SLOT_SIZE/2)-_dragOffsetY)
				_draggedItem.Size, _draggedItem.ZIndex = UDim2.new(0, _config.SLOT_SIZE, 0, _config.SLOT_SIZE), 101
			end
			if isHb then
				ClientInventory.SelectSlot(idx)
				if Inventory.Visible and iData and iData.name ~= "Item Name" then
					ClientInventoryDisplay.DisplayItemInFrame(iData)
					_currentItem, _currentselectedSlot = iData, idx
				end
			end
		elseif input.UserInputType == Enum.UserInputType.MouseMovement then
			TweenService:Create(slot, TweenInfo.new(0.1), {BackgroundColor3 = Color3.fromRGB(70, 70, 70)}):Play()
			local iData = isHb and _hotbarItems[idx] or _inventoryItems[idx]
			if iData and iData.name ~= "Item Name" then ClientInventoryEffects.ShowTooltip(iData, UserInputService:GetMouseLocation(), script.GradTemplates) end
		end
	end)
	slot.InputChanged:Connect(function(input)
		if input.UserInputType == Enum.UserInputType.MouseMovement then
			local iData = isHb and _hotbarItems[idx] or _inventoryItems[idx]
			if iData and iData.name ~= "Item Name" and ToolTip.Visible then 
				ClientInventoryEffects.ShowTooltip(iData, UserInputService:GetMouseLocation(), script.GradTemplates) 
			end
		end
	end)
	slot.InputEnded:Connect(function(input)
		if input.UserInputType == Enum.UserInputType.MouseMovement then
			TweenService:Create(slot, TweenInfo.new(0.1), {BackgroundColor3 = Color3.fromRGB(50, 50, 50)}):Play()
			ClientInventoryEffects.HideTooltip()
		end
	end)
end

function HandleDragEnd(pos)
	if not Inventory.Visible and _draggedItemOrigin == "hotbar" then
		if _draggedItem then _draggedItem:Destroy() end
		_isDragging, _draggedItemOrigin, _draggedItemSlot, _draggedItemData = false, nil, nil, nil
		return
	end
	if _draggedItem then _draggedItem:Destroy() end
	if not _isDragging or not _draggedItemOrigin or not _draggedItemSlot or not _draggedItemData then 
		_isDragging = false 
		return 
	end
	local tgtSlot, tgtType, tgtIdx = nil, nil, nil
	-- Check hotbar slots first
	for i = 1, _config.HORBAR_SIZE do
		local sName = i == 10 and "0" or tostring(i)
		local s = Hotbar:FindFirstChild(sName)
		if s and pos.X >= s.AbsolutePosition.X and pos.X <= s.AbsolutePosition.X + s.AbsoluteSize.X and
			pos.Y >= s.AbsolutePosition.Y and pos.Y <= s.AbsolutePosition.Y + s.AbsoluteSize.Y then
			tgtSlot, tgtType, tgtIdx = s, "hotbar", i
			break
		end
	end
	-- If not dropped on hotbar and inventory is open, check inventory slots
	if not tgtSlot and Inventory.Visible then
		for i = 1, _config.INVENTORY_ROWS * _config.INVENTORY_COLS do
			local s = List:FindFirstChild("InventorySlot"..i)
			if s and pos.X >= s.AbsolutePosition.X and pos.X <= s.AbsolutePosition.X + s.AbsoluteSize.X and
				pos.Y >= s.AbsolutePosition.Y and pos.Y <= s.AbsolutePosition.Y + s.AbsoluteSize.Y then
				tgtSlot, tgtType, tgtIdx = s, "inventory", i
				break
			end
		end
		-- If dragging from hotbar and dropped in inventory area but not on slot, find empty slot
		if not tgtSlot and _draggedItemOrigin == "hotbar" then
			local invPos, invSize = Inventory.AbsolutePosition, Inventory.AbsoluteSize
			if pos.X >= invPos.X and pos.X <= invPos.X + invSize.X and 
				pos.Y >= invPos.Y and pos.Y <= invPos.Y + invSize.Y then
				local slot = FindEmptyInvSlot()
				if slot then tgtType, tgtIdx = "inventory", slot end
			end
		end
	end
	-- Process the drop
	if (tgtType and tgtIdx) then
		if _draggedItemOrigin ~= tgtType or _draggedItemSlot ~= tgtIdx then 
			ClientInventory.MoveItem(_draggedItemOrigin, _draggedItemSlot, tgtType, tgtIdx) 
		end
	elseif _draggedItemOrigin == "hotbar" and _draggedItemData.name ~= "Item Name" then
		local slot = FindEmptyInvSlot()
		if slot then ClientInventory.MoveItem(_draggedItemOrigin, _draggedItemSlot, "inventory", slot) end
	end
	_isDragging, _draggedItemOrigin, _draggedItemSlot, _draggedItemData = false, nil, nil, nil
end

function ClientInventory.CreateSlot(type, num, item)
	local script = script
	-- Make sure item is valid before proceeding
	if not item then
		warn("CreateSlot called with nil item for slot", num)
		-- Create a default item to avoid errors
		item = {name = "Item Name", rarity = "Common"}
	end

	-- Ensure item has required properties
	if not item.rarity then item.rarity = "Common" end
	if not item.name then item.name = "Item Name" end

	local rarity = item.rarity
	local tmpl = script.HotbarTemplates:FindFirstChild(rarity.."Template") or script:FindFirstChild("CommonTemplate")

	if not tmpl then  warn("Could not find template for rarity:", rarity) return nil  end

	local slot = tmpl:Clone()
	slot.Name = type == "Inventory" and (tostring(item.name) or "InventorySlot"..num) or tostring(num)

	local lbl, btn, qty = slot:FindFirstChild("Slot"), slot:FindFirstChild("Button"), slot:FindFirstChild("Quanity")
	local qtyT = qty:WaitForChild("Title", math.huge)

	if lbl then lbl.Text, lbl.Visible = tostring(num), (type == "Hotbar") end

	-- Add tool indicator
	if item.isRobloxTool then
		-- Create a small tool indicator
		local toolIndicator = Instance.new("Frame")
		toolIndicator.Name = "ToolIndicator"
		toolIndicator.Size = UDim2.new(0, 8, 0, 8)
		toolIndicator.Position = UDim2.new(1, -10, 0, 2)
		toolIndicator.BackgroundColor3 = Color3.fromRGB(0, 255, 0)
		toolIndicator.BorderSizePixel = 0
		toolIndicator.Parent = slot

		-- Make it round
		local corner = Instance.new("UICorner")
		corner.CornerRadius = UDim.new(0, 4)
		corner.Parent = toolIndicator
	end

	if btn then
		if type == "Inventory" and item then
			lbl.Visible = false
			qtyT.Visible = false
			btn.Text = ""
			btn.MouseButton1Click:Connect(function()
				local isAlreadySelected = _currentselectedSlot == tostring(num)
				if _currentselectedSlot then
					local prev = List:FindFirstChild("InventorySlot".._currentselectedSlot)

					if prev and prev:FindFirstChild("UIStroke") then 
						TweenService:Create(prev.UIStroke, TweenInfo.new(0.2), {Thickness = 0}):Play() 
					end
				end

				if isAlreadySelected then
					ItemFrame.Visible = false
					_currentselectedSlot, _currentItem = nil, nil
				else
					_currentselectedSlot, _currentItem = tostring(num), item
					if slot:FindFirstChild("UIStroke") then 
						TweenService:Create(slot.UIStroke, TweenInfo.new(0.2), {Thickness = 3}):Play() 
					end

					ClientInventoryDisplay.DisplayItemInFrame(item)

					-- Call DisplayItemInfo with the item name when selecting
					if item and item.name and item.name ~= "Item Name" then
						ClientInventoryDisplay.DisplayItemInfo(item.name)
					end
				end
			end)
		elseif type == "Hotbar" then 
			btn.MouseButton1Down:Connect(function() 
				ClientInventory.SelectSlot(num) 
			end) 
		end
	end
	if item then slot:SetAttribute("ItemName", item.name) end
	if item and item.name and item.name ~= "Item Name" then
		local existing = slot:FindFirstChild("ItemViewport")
		if existing then existing:Destroy() end

		-- Wrap in pcall to catch any errors in CreateViewPort
		pcall(function()
			ClientInventoryViewport.CreateViewPort(slot, item.name)
		end)
	end
	if qty then 
		qty.Visible = (item and item.quantity and item.quantity > 1)
		if item and item.quantity and item.quantity > 1 then qtyT.Text = tostring(item.quantity) end
	end

	slot:SetAttribute("TooltipConnected", true)
	return slot
end

function ClientInventory.SelectSlot(idx)
	if _selectedSlot == idx then return end
	_selectedSlot = idx
	for i = 1, _config.HORBAR_SIZE do
		local slotName = i == 10 and "0" or tostring(i)
		local slot = Hotbar:WaitForChild(slotName, math.huge)
		if slot and slot:WaitForChild("UIStroke", math.huge) then
			local isSelected = (i == _selectedSlot)
			TweenService:Create(
				slot.UIStroke, 
				TweenInfo.new(0.2), 
				{
					Thickness = isSelected and 5 or 0,
					Transparency = isSelected and 0 or 1
				}
			):Play()
		end
	end
	local selectedItem = _hotbarItems[idx]
	if selectedItem and selectedItem.name ~= "Item Name" then
		-- If it's a tool, equip it
		if selectedItem.isRobloxTool then
			EquipTool(selectedItem)
		end
		ClientInventoryEffects.CreateNotification(1, "Selected", "Selected " .. selectedItem.name)
	end
end

--Original
function ClientInventory.UpdateSlots(type)
	if type == "hotbar" or type == "both" then
		-- Clear existing hotbar slots
		for _, child in pairs(Hotbar:GetChildren()) do 
			if child:IsA("ImageLabel") then child:Destroy() end 
		end
		-- Create new hotbar slots
		for i = 1, _config.HORBAR_SIZE do
			local item = _hotbarItems[i]
			local slot = ClientInventory.CreateSlot("Hotbar", i, item)
			if slot then
				slot.Parent = Hotbar
				slot.Visible = Inventory.Visible or (item and item.name ~= "Item Name")
				local ivp, qty, slbl, btn = slot:FindFirstChild("ItemViewport"), slot:FindFirstChild("Quanity"), slot:FindFirstChild("Slot"), slot:FindFirstChild("Button")
				if ivp then ivp.Visible = false end
				if qty then qty.Visible = true end
				if slbl then slbl.Visible = true end
				if btn then btn.Text = (item and item.name ~= "Item Name") and item.name or "" end
				SetupSlotEvents(slot, i, true)
			end
		end
		-- Update selection indicator
		for i = 1, _config.HORBAR_SIZE do
			local s = Hotbar:FindFirstChild(i == 10 and "0" or tostring(i))
			if s and s:FindFirstChild("UIStroke") then s.UIStroke.Thickness = (i == _selectedSlot) and 3 or 0 end
		end
	end

	if type == "inventory" or type == "both" then
		-- Clear existing inventory slots
		for _, child in pairs(List:GetChildren()) do 
			if child:IsA("ImageLabel") then child:Destroy() end 
		end
		-- Create new inventory slots
		for i = 1, _config.INVENTORY_ROWS * _config.INVENTORY_COLS do
			if _inventoryItems[i] then
				local slot = ClientInventory.CreateSlot("Inventory", i, _inventoryItems[i])
				if slot then
					slot.Parent = List
					slot.Name = "InventorySlot" .. i  -- Ensure consistent naming
					local qty, slbl, btn = slot:FindFirstChild("Quanity"), slot:FindFirstChild("Slot"), slot:FindFirstChild("Button")
					if qty then qty.Visible = false end
					if slbl then slbl.Visible = false end
					if btn then btn.Text = "" end
					SetupSlotEvents(slot, i, false)
				end
			end
		end
	end
end

function ClientInventory.MoveItem(fromType, fromIdx, toType, toIdx)
	-- Debug output
	print("Moving item from " .. fromType .. "[" .. tostring(fromIdx) .. "] to " .. toType .. "[" .. tostring(toIdx) .. "]")

	-- Validate the inventory is visible if dealing with hotbar
	if not Inventory.Visible and (fromType == "hotbar" or toType == "hotbar") then 
		print("Inventory must be visible to interact with hotbar items")
		return 
	end

	-- Get source and target item arrays
	local srcItems = fromType == "hotbar" and _hotbarItems or _inventoryItems
	local tgtItems = toType == "hotbar" and _hotbarItems or _inventoryItems

	-- Get the source item
	local srcItem = srcItems[fromIdx]
	if not srcItem then 
		print("Source item not found at " .. fromType .. "[" .. tostring(fromIdx) .. "]")
		return 
	end

	-- Get target item (if any)
	local tgtItem = tgtItems[toIdx]

	-- Debug print items
	print("Source item: " .. (srcItem.name or "nil"))
	print("Target item: " .. (tgtItem and tgtItem.name or "nil"))

	-- Handle different movement cases
	if fromType ~= toType then
		-- Moving between inventory and hotbar
		if fromType == "inventory" and toType == "hotbar" then
			-- Moving from inventory to hotbar
			print("Moving from inventory to hotbar")

			-- Check if we're moving to a valid hotbar slot
			if toIdx < 1 or toIdx > _config.HORBAR_SIZE then
				print("Invalid hotbar slot index: " .. tostring(toIdx))
				return
			end

			-- Move the item and handle the swap
			if tgtItem and tgtItem.name ~= "Item Name" then
				-- Swap items if target has a real item
				local tempSrcItem = srcItem
				tgtItems[toIdx] = tempSrcItem
				srcItems[fromIdx] = tgtItem
			else
				-- Move to empty hotbar slot or slot with placeholder
				tgtItems[toIdx] = srcItem
				srcItems[fromIdx] = nil  -- Remove completely, don't leave placeholder
				CompactInventory()
			end
		elseif fromType == "hotbar" and toType == "inventory" then
			-- Moving from hotbar to inventory
			print("Moving from hotbar to inventory")

			-- Make sure we have a valid target index
			local tIdx = (toIdx > #_inventoryItems + 1) and FindEmptyInvSlot() or toIdx
			if not tIdx then
				print("No empty inventory slots available")
				return
			end

			-- Place the item in inventory and leave an empty slot in hotbar
			if tgtItem then
				-- If target has an item, swap
				local tempSrcItem = srcItem
				srcItems[fromIdx] = tgtItem
				tgtItems[tIdx] = tempSrcItem
			else
				-- If target is empty, just move
				tgtItems[tIdx] = srcItem
				srcItems[fromIdx] = {name = "Item Name", rarity = "Common"} -- Empty placeholder in hotbar
			end
		end
	else
		-- Moving within the same area (hotbar or inventory)
		if fromType == "hotbar" then
			-- Hotbar to hotbar swapping
			tgtItems[toIdx], srcItems[fromIdx] = srcItem, tgtItem or {name = "Item Name", rarity = "Common"}
		else
			-- Inventory to inventory swapping
			-- Store both items in temporary variables first
			local tempSrcItem = srcItem
			local tempTgtItem = tgtItem

			-- Then perform the swap
			if tempTgtItem then
				-- If target has an item, perform proper swap
				srcItems[fromIdx] = tempTgtItem
				tgtItems[toIdx] = tempSrcItem
			else
				-- If target is empty, move source to target and clean up
				tgtItems[toIdx] = tempSrcItem
				srcItems[fromIdx] = nil  -- Remove completely, don't leave placeholder
				CompactInventory()
			end
		end
	end

	-- Update selection indicators and item frame
	if _currentItem and _currentselectedSlot then
		if fromType == "inventory" and fromIdx == _currentselectedSlot then
			if toType == "inventory" then
				_currentselectedSlot, _currentItem = toIdx, _inventoryItems[toIdx]

				ClientInventoryDisplay.DisplayItemInFrame(_currentItem)

				local prevSlot = List:FindFirstChild("InventorySlot"..fromIdx)
				local newSlot = List:FindFirstChild("InventorySlot"..toIdx)

				if prevSlot and prevSlot:FindFirstChild("UIStroke") then 
					TweenService:Create(prevSlot.UIStroke, TweenInfo.new(0.2), {Thickness = 0}):Play() 
				end

				if newSlot and newSlot:FindFirstChild("UIStroke") then 
					TweenService:Create(newSlot.UIStroke, TweenInfo.new(0.2), {Thickness = 3}):Play() 
				end
			else
				ItemFrame.Visible, _currentItem, _currentselectedSlot, _currentVanityItem = false, nil, nil, nil
			end
		elseif toType == "inventory" and toIdx == _currentselectedSlot then
			_currentItem = _inventoryItems[_currentselectedSlot]
			ClientInventoryDisplay.DisplayItemInFrame(_currentItem)
		end
	end

	-- Update UI
	ClientInventory.UpdateSlots("hotbar") 
	ClientInventory.UpdateSlots("inventory")

	-- Debugging
	print("Move completed successfully!")
end

function ClientInventory.ToggleInventory(visible)
	Inventory.Visible = visible
	if not visible and ItemFrame then 
		ItemFrame.Visible = false 
		_currentItem = nil
		_currentVanityItem = nil
		_currentselectedSlot = nil 
	end
	ClientInventory.UpdateSlots("hotbar")
end

function ClientInventory.ToggleVanityMode(enabled)
	_isVanityMode = enabled

	-- Reset selection when switching modes
	if _currentselectedSlot then
		local currentSlot = List:FindFirstChild("InventorySlot".._currentselectedSlot)
		if currentSlot and currentSlot:FindFirstChild("UIStroke") then
			TweenService:Create(currentSlot.UIStroke, TweenInfo.new(0.2), {Thickness = 0}):Play()
		end
	end

	-- Clear current selections
	_currentselectedSlot = nil
	_currentItem = nil
	_currentVanityItem = nil

	-- Hide item frame
	if ItemFrame then
		ItemFrame.Visible = false
	end

	-- Update UI to show the mode change
	ClientInventoryEffects.CreateNotification(2, _isVanityMode and "Vanity Mode" or "Normal Mode", _isVanityMode and "Switched to Vanity Mode" or "Switched to Normal Mode")

	-- Refresh inventory display
	ClientInventory.UpdateSlots("inventory")
end

-- CLIENT MODULE - Fixed ManageItem function
function ClientInventory.ManageItem(action, itemData)
	-- Enhanced debug diagnostics
	print("ManageItem called with action:", action)
	print("itemData type:", type(itemData))

	-- Validate itemData
	if not itemData then
		warn("ManageItem called with nil itemData")
		return false
	end

	if type(itemData) ~= "table" then
		-- If it's a string, convert it to a simple table
		if type(itemData) == "string" then
			itemData = {
				name = itemData, 
				id = itemData .. "_id_" .. tostring(os.time()),
				rarity = "Common",
				description = "No description",
				quantity = 1
			}
		else
			warn("ManageItem called with invalid itemData type:", type(itemData))
			return false
		end
	end

	-- Print all keys and values (for debugging)
	print("ItemData contents:")
	for k, v in pairs(itemData) do
		print("  - " .. tostring(k) .. " = " .. tostring(v))
	end

	-- Check for required properties, trying both lowercase and uppercase versions
	local itemName = itemData.name or itemData.Name
	if not itemName or type(itemName) ~= "string" then
		warn("ManageItem called with invalid or missing name property:", tostring(itemName))
		return false
	end

	-- Get other properties with fallbacks and validation
	local itemRarity = itemData.rarity or itemData.Rarity or "Common"
	local itemId = itemData.id or itemData.Id or (itemName .. "_id_" .. tostring(os.time()))
	local itemDescription = itemData.description or itemData.Description or "No description available"
	local itemQuantity = tonumber(itemData.quantity or itemData.Quantity or 1)

	-- Ensure quantity is valid
	if not itemQuantity or itemQuantity < 1 then
		itemQuantity = 1
	end

	if action == "setupinventory" then
		-- Check if item already exists by ID first, then by name
		local existingIndex = nil
		for idx, item in pairs(_inventoryItems) do
			if item and (item.id == itemId or (not item.id and item.name == itemName)) then
				existingIndex = idx
				break
			end
		end

		if existingIndex then
			-- Update existing item quantity
			local currentQty = _inventoryItems[existingIndex].quantity or 1
			_inventoryItems[existingIndex].quantity = currentQty + itemQuantity
			print("Updated existing item quantity:", itemName, "new quantity:", _inventoryItems[existingIndex].quantity)
		else
			-- Add as new item
			local idx = FindEmptyInvSlot()
			if not idx then 
				ClientInventoryEffects.CreateNotification(3, "Inventory Full", "Cannot add more items to your inventory!")
				return false 
			end

			-- Create clean item object
			_inventoryItems[idx] = {
				name = itemName,
				id = itemId,
				rarity = itemRarity,
				description = itemDescription,
				quantity = itemQuantity
			}
			print("Added new item to inventory:", itemName, "at slot:", idx)
		end

		ClientInventory.UpdateSlots("inventory")
		return true
	elseif action == "jutsu" then
		local existingIndex = nil
		for idx, item in pairs(_inventoryItems) do
			if item and (item.id == itemId or (not item.id and item.name == itemName)) then
				existingIndex = idx
				break
			end
		end

		if existingIndex then
			-- Update existing item quantity
			local currentQty = _inventoryItems[existingIndex].quantity or 1
			_inventoryItems[existingIndex].quantity = currentQty + itemQuantity
			print("Updated existing item quantity:", itemName, "new quantity:", _inventoryItems[existingIndex].quantity)
		else
			-- Add as new item
			local idx = FindEmptyInvSlot()
			if not idx then 
				ClientInventoryEffects.CreateNotification(3, "Inventory Full", "Cannot add more items to your inventory!")
				return false 
			end

			-- Create clean item object
			_inventoryItems[idx] = {
				name = itemName,
				id = itemId,
				rarity = itemRarity,
				description = itemDescription,
				quantity = itemQuantity,
				toolExists = itemData.toolExists -- Preserve tool existence flag
			}
			print("Added new item to inventory:", itemName, "at slot:", idx)
		end
		return true
	elseif action == "add" or action == "purchase" then
		-- Check for accessory previews if needed
		if not ReplicatedStorage:FindFirstChild("AccessoryPreviews") or 
			not ReplicatedStorage.AccessoryPreviews:FindFirstChild(itemName) then
			-- Only request preview if the remote exists
			if requestPreviewRemote then
				requestPreviewRemote:InvokeServer(itemName)
			end
		end

		-- Check if we already have this item (by id first, then by name)
		local existingIndex = nil
		for idx, item in pairs(_inventoryItems) do
			if item and (item.id == itemId or (not item.id and item.name == itemName)) then
				existingIndex = idx
				break
			end
		end

		if existingIndex then
			-- Update existing item
			local currentQty = _inventoryItems[existingIndex].quantity or 1
			_inventoryItems[existingIndex].quantity = currentQty + itemQuantity
		else
			-- Add as new item
			local idx = FindEmptyInvSlot()
			if not idx then 
				ClientInventoryEffects.CreateNotification(3, "Inventory Full", "Cannot add more items to your inventory.") 
				return false 
			end

			_inventoryItems[idx] = {
				name = itemName,
				id = itemId,
				rarity = itemRarity,
				description = itemDescription,
				quantity = itemQuantity
			}
		end

		ClientInventory.UpdateSlots("inventory")

		-- Show notification
		local title = action == "add" and "Item Received" or "Purchase Complete!"
		local msg = "[" .. (action == "add" and "Received " or "Successfully purchased ") .. itemName .. "!]"
		ClientInventoryEffects.CreateNotification(3, title, msg)
		return true

	elseif action == "remove" then
		local idx, name

		-- Handle different input types for removal
		if type(itemData) == "string" then
			-- String could be ID or name
			for i, item in pairs(_inventoryItems) do
				if item and (item.id == itemData or item.name == itemData) then
					idx, name = i, item.name
					break
				end
			end
		elseif type(itemData) == "table" then
			local searchId = itemId
			local searchName = itemName

			for i, item in pairs(_inventoryItems) do
				if item and ((searchId and item.id == searchId) or (searchName and item.name == searchName)) then
					idx, name = i, item.name
					break
				end
			end
		end

		if idx and name then
			-- Close item frame if this item is currently selected
			if ItemFrame and ItemFrame.Visible and _currentItem and _currentItem.name == name then 
				ItemFrame.Visible = false 
				_currentItem, _currentselectedSlot = nil, nil 
			end

			-- Handle quantity
			local currentQty = _inventoryItems[idx].quantity or 1
			if currentQty > 1 then
				_inventoryItems[idx].quantity = currentQty - 1
			else
				_inventoryItems[idx] = nil
				CompactInventory()
			end

			ClientInventory.UpdateSlots("inventory")
			ClientInventoryEffects.CreateNotification(3, "Item Removed", "[Removed " .. name .. "!]")
			return true
		else
			warn("Could not find item to remove:", tostring(itemData))
			return false
		end
	end

	warn("Unknown action in ManageItem:", action)
	return false
end

-- Add this helper function to ClientInventory module
function ClientInventory.ClearInventory()
	ClientInventory.inventoryItems = {}
	ClientInventory.slotItems = {}
	-- Update UI
	ClientInventory.UpdateSlots("inventory")
	ClientInventory.UpdateSlots("hotbar")
end

-- Function to add and initialize test items
function ClientInventory.AddTestItems()
	for i = 1, 10 do _hotbarItems[i] = {name = "Item Name", rarity = "Common"} end
end

function ClientInventory.GetSelectedItem()
	if _isVanityMode then
		return _currentVanityItem
	else
		return _currentItem
	end
end

-- Event handlers
UserInputService.InputChanged:Connect(function(input)
	if _isDragging and _draggedItem and input.UserInputType == Enum.UserInputType.MouseMovement then
		local mPos = UserInputService:GetMouseLocation()
		_draggedItem.Position = UDim2.new(0, mPos.X-(_config.SLOT_SIZE/2)-_dragOffsetX, 0, mPos.Y-(_config.SLOT_SIZE/2)-_dragOffsetY)
	end
end)

UserInputService.InputEnded:Connect(function(input)
	if _isDragging and input.UserInputType == Enum.UserInputType.MouseButton1 then HandleDragEnd(UserInputService:GetMouseLocation()) end
end)

RunService.RenderStepped:Connect(function() 
	if _isDragging and _draggedItem then _draggedItem.Rotation = math.sin(tick() * 5) * 5 end 
end)

-- Handle preview requests from server
requestPreviewRemotes.OnClientEvent:Connect(function(itemName)
	-- First check if preview already exists
	if not ReplicatedStorage:FindFirstChild("AccessoryPreviews") or
		not ReplicatedStorage.AccessoryPreviews:FindFirstChild(itemName) then
		-- Request preview from server
		local success = requestPreviewRemote:InvokeServer(itemName)
		if not success then
			warn("Failed to get preview for:", itemName)
		end
	end
	if List then
		for _, slot in pairs(List:GetChildren()) do
			if slot:IsA("ImageLabel") or slot:IsA("Frame") then
				local viewport = slot:FindFirstChild("ItemViewport")
				if viewport and viewport:GetAttribute("PendingModelLoad") == itemName then
					ClientInventoryViewport.LoadModelIntoViewPort(viewport, itemName)
					viewport:SetAttribute("PendingModelLoad", nil)
				end
			end
		end
	end
end)



-- Handle inventory data updates from server
updateInventoryRemote.OnClientEvent:Connect(function(slotIndex, itemData)
	_inventoryItems[slotIndex] = itemData
end)

-- Handle refresh requests from server
refreshInventoryRemote.OnClientEvent:Connect(function()
	ClientInventory.UpdateSlots("inventory")
end)

-- CLIENT SIDE - Fixed event handler
remotes.InventoryRemotes.InventoryHandler.OnClientEvent:Connect(function(action, itemData)
	print("=== INVENTORY EVENT RECEIVED ===")
	print("Action:", action)
	print("ItemData type:", type(itemData))

	-- Add more detailed logging for debugging
	if type(itemData) == "table" then
		print("ItemData name:", itemData.name or itemData.Name or "NO_NAME")
	end

	-- Validate that we received proper data
	if not itemData then
		warn("Received nil itemData for action:", action)
		return
	end

	if action == "SyncInventory" then
		if type(itemData) == "table" then
			print("Processing SyncInventory with", #itemData, "items")
			for i, item in ipairs(itemData) do
				-- Enhanced validation
				if type(item) ~= "table" then
					warn("Invalid item in inventory sync at index", i, ":", tostring(item))
					continue
				end

				-- Debug the item
				local itemName = item.name or item.Name
				print("Processing inventory item #" .. i .. ":", itemName or "unknown")

				-- Create a clean item structure with all required properties
				local cleanItem = {
					name = itemName,
					rarity = item.rarity or item.Rarity or 
						(TradeablesData[itemName] and TradeablesData[itemName].Rarity) or "Common",
					id = item.id or item.Id or (itemName .. "_id_" .. tostring(os.time()) .. "_" .. i),
					quantity = item.quantity or item.Quantity or 1,
					description = item.description or item.Description or "No description",
					toolExists = item.toolExists
				}

				-- Only process items with valid names
				if cleanItem.name and type(cleanItem.name) == "string" then
					local success = ClientInventory.ManageItem("setupinventory", cleanItem)
					print("Added inventory item:", cleanItem.name, "Success:", success)
				else
					warn("Item missing valid name property at index", i, ":", tostring(cleanItem.name))
				end
			end
			ClientInventory.UpdateSlots("hotbar")
			ClientInventory.UpdateSlots("inventory")
			print("Completed SyncInventory processing")
		else
			warn("Invalid data format for SyncInventory:", type(itemData))
		end
	elseif action == "AddedItem" then 
		print("Adding item:", itemData.name or itemData.Name or "unknown")
		ClientInventory.ManageItem("add", itemData)
	elseif action == "RemovedItem" then 
		print("Removing item:", itemData.name or itemData.Name or tostring(itemData))
		ClientInventory.ManageItem("remove", itemData)
	elseif action == "PurchaseItem" then 
		print("Purchasing item:", itemData.name or itemData.Name or "unknown")
		ClientInventory.ManageItem("purchase", itemData)
	else
		warn("Unknown inventory action:", action)
	end

	print("=== END INVENTORY EVENT ===")
end)

ClientInventoryDisplay.SetupEquipUnequipHandlers({
	GetCurrentItemCallback = function()
		return _currentItem
	end
})

return ClientInventory

So does anyone have an idea how to get this to work by any chance?

4 Likes

Does anyone know how to get this to work by any chance even if it small, just really curious because I am stuck.

2 Likes

Can you elaborate on what you are trying to solve? It’s difficult to understand what your problem is with just a script. If possible, specify what part of the script you are having trouble with. If you can’t find where the problem is in the script, try to utilize print, warn, or pcall.

1 Like

Its due to inventory slots not being created when players have backpack items in their own player backpack

edit: I should’ve had specify that in the issue that’s my fault

anyone else want to help fix this?

if no one wants to really help, I have to close this topic because pointless.