if SERVER then return end -- Register necessary types and make fields accessible LuaUserData.RegisterType("Barotrauma.Items.Components.ItemContainer+SlotRestrictions") LuaUserData.RegisterType('System.Collections.Immutable.ImmutableArray`1[[Barotrauma.Items.Components.ItemContainer+SlotRestrictions, Barotrauma]]') LuaUserData.MakeFieldAccessible(Descriptors['Barotrauma.Items.Components.ItemContainer'], 'slotRestrictions') LuaUserData.MakeFieldAccessible(Descriptors['Barotrauma.ItemInventory'], 'slots') LuaUserData.MakeFieldAccessible(Descriptors["Barotrauma.CharacterInventory"], "slots") -- Simple configuration local HAND_SLOTS = { 6, 7 } local PRIORITY_CONTAINERS = { "toolbelt", "backpack", "pouch" } -- Identifiers for priority containers -- Helper function to move an item to a container, but only if matching items exist local function moveItemToContainer(item, containerInv) if not item or not containerInv then return false end print("[QuickStack] Attempting to stack with existing items in container (" .. #containerInv.slots .. " slots)") -- Only try to find matching items to stack with local foundMatchingItem = false -- Check if the container has any matching items first for slotIndex = 0, #containerInv.slots - 1 do for _, containerItem in ipairs(containerInv.slots[slotIndex + 1].items) do if containerItem.Prefab.Identifier.Equals(item.Prefab.Identifier) then foundMatchingItem = true print("[QuickStack] Found matching item in container") break end end if foundMatchingItem then break end end -- If no matching items exist in the container, don't move the item if not foundMatchingItem then print("[QuickStack] No matching items in container, skipping") return false end -- Try to stack with existing items for slotIndex = 0, #containerInv.slots - 1 do for _, containerItem in ipairs(containerInv.slots[slotIndex + 1].items) do if containerItem.Prefab.Identifier.Equals(item.Prefab.Identifier) then -- Try to stack with existing item print("[QuickStack] Stacking with existing item") if containerInv.TryPutItem(item, slotIndex, true, false, nil) then return true end end end end -- We don't try to place in empty slots anymore, only stack with existing items print("[QuickStack] Failed to stack with existing items") return false end -- Sort containers by priority local function sortContainersByPriority(containers) table.sort(containers, function(a, b) local aPriority = -1 local bPriority = -1 -- Check priority for first container for i, identifier in ipairs(PRIORITY_CONTAINERS) do if a.Prefab.Identifier.Value:find(identifier) then aPriority = i break end end -- Check priority for second container for i, identifier in ipairs(PRIORITY_CONTAINERS) do if b.Prefab.Identifier.Value:find(identifier) then bPriority = i break end end return aPriority < bPriority end) return containers end -- Recursively find all containers in the player's inventory, including nested ones local function findAllContainers(inventory, containers) if not inventory or not inventory.slots then return containers end containers = containers or {} for _, slot in ipairs(inventory.slots) do for _, item in ipairs(slot.items) do if item.OwnInventory then -- Add this container print("[QuickStack] Found container: " .. item.Name .. " (" .. item.Prefab.Identifier.Value .. ")") table.insert(containers, item) -- Recursively search inside this container findAllContainers(item.OwnInventory, containers) end end end return containers end -- Find the currently open container using the better approach with opened GUIs local function getOpenContainer() -- Check if any ItemContainer GUIs are open for _, gui in pairs(GUI.OpenGuis) do if gui.UserData ~= nil and gui.UserData.Inventory ~= nil then -- Make sure it's not the player's inventory if gui.UserData.Item ~= nil and gui.UserData.Item.Inventory ~= Character.Controlled.Inventory then print("[QuickStack] Found open container: " .. gui.UserData.Item.Name) return gui.UserData.Item end end end -- Try an alternative approach using opened inventories for _, inventory in pairs(ItemInventory.OpenInventories) do if inventory.Owner ~= nil and inventory.Owner.Inventory ~= Character.Controlled.Inventory then -- Found a non-player inventory print("[QuickStack] Found open inventory: " .. inventory.Owner.Name) return inventory.Owner end end print("[QuickStack] No open container found") return nil end -- Function to stack from open container to player containers local function stackFromOpenContainer(character, playerContainers, openContainer) if not character or not openContainer or not openContainer.OwnInventory then return 0 end print("[QuickStack] Stacking from open container: " .. openContainer.Name) local itemsMoved = 0 local openContainerInv = openContainer.OwnInventory -- Process each slot in the open container for slotIndex = 0, #openContainerInv.slots - 1 do local slot = openContainerInv.slots[slotIndex + 1] -- Process items in the slot for i = #slot.items, 1, -1 do local item = slot.items[i] -- Skip container items if item.OwnInventory then goto nextItem end -- Try to move the item to each player container for _, container in ipairs(playerContainers) do if moveItemToContainer(item, container.OwnInventory) then print("[QuickStack] Stacked " .. item.Name .. " from open container into " .. container.Name) itemsMoved = itemsMoved + 1 break end end ::nextItem:: end end return itemsMoved end -- Function to quickly stack items from inventory to containers local function quickStackItems(character) if not character then return end print("[QuickStack] Function called") local inventory = character.Inventory if not inventory or not inventory.slots then return end -- Find all containers in player inventory, including nested ones local containers = findAllContainers(inventory, {}) print("[QuickStack] Found " .. #containers .. " containers (including nested)") if #containers == 0 then print("[QuickStack] No containers with inventory found!") return end -- Sort containers by priority containers = sortContainersByPriority(containers) local itemsMoved = 0 -- Process inventory slots for slotIndex, slot in ipairs(inventory.slots) do -- Skip hand slots local isHandSlot = false for _, handSlot in ipairs(HAND_SLOTS) do if slotIndex == handSlot then isHandSlot = true break end end if isHandSlot then goto continueSlot end -- Process items in the slot for i = #slot.items, 1, -1 do local item = slot.items[i] -- Skip container items if item.OwnInventory then goto nextItem end -- Try to move the item to each container for _, container in ipairs(containers) do if moveItemToContainer(item, container.OwnInventory) then print("[QuickStack] Stacked " .. item.Name .. " into " .. container.Name) itemsMoved = itemsMoved + 1 break end end ::nextItem:: end ::continueSlot:: end -- Check if there's an open container to stack from local openContainer = getOpenContainer() if openContainer then local openContainerItemsMoved = stackFromOpenContainer(character, containers, openContainer) itemsMoved = itemsMoved + openContainerItemsMoved end if itemsMoved > 0 then print("[QuickStack] Stacked " .. itemsMoved .. " items into containers") else print("[QuickStack] No matching items to stack") end end -- Hook into player control to listen for key press Hook.Patch("Barotrauma.Character", "ControlLocalPlayer", function(instance, ptable) if not PlayerInput.KeyHit(Keys.F) then return end local character = instance if not character then return end quickStackItems(character) end, Hook.HookMethodType.After)