Files
barotrauma-localmods/QuickStackToBag/Lua/Autorun/init.lua

250 lines
8.8 KiB
Lua

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)