Implement stacking from open containers

This commit is contained in:
2025-03-29 22:47:13 +01:00
parent 6333be421b
commit 6357346544

View File

@@ -469,146 +469,25 @@ local function stackInventoryItems(inventory, itemTree)
debugPrint("Completed stacking inventory items.") debugPrint("Completed stacking inventory items.")
end end
-- Find the currently open container - improved version -- This is a bit fucking sucky.....
-- But I really don't know better
-- Maybe it will be fine...
---@return Barotrauma.ItemInventory
local function getOpenContainer() local function getOpenContainer()
debugPrint("Attempting to find open container...") debugPrint("Attempting to find open container...")
for item in Item.ItemList do
local openContainer = nil ---@cast item Barotrauma.Item
local hasVisibleInventory = false if item and item.OwnInventory then
if item.OwnInventory.visualSlots and #item.OwnInventory.visualSlots > 0 then
-- Method 1: Try to use Inventory.CurrentInventory or similar properties return item.OwnInventory
pcall(function()
if Inventory and Inventory.CurrentContainer and Inventory.CurrentContainer.Owner then
openContainer = Inventory.CurrentContainer.Owner
hasVisibleInventory = true
debugPrint("Found open container via CurrentContainer: " .. openContainer.Name)
end
end)
if hasVisibleInventory and openContainer then return openContainer end
-- Method 2: Check if Inventory.OpenInventories exists and has entries
pcall(function()
if Inventory and Inventory.OpenInventories and #Inventory.OpenInventories > 0 then
-- Get the last opened inventory
for _, inv in ipairs(Inventory.OpenInventories) do
if inv and inv.Owner and inv.Owner ~= Character.Controlled then
openContainer = inv.Owner
hasVisibleInventory = true
debugPrint("Found open container via OpenInventories: " .. openContainer.Name)
break
end
end end
end end
end)
if hasVisibleInventory and openContainer then return openContainer end
-- Method 3: Check if currently selected item is interacting with a container
pcall(function()
if Character.Controlled and Character.Controlled.SelectedItem then
local selectedItem = Character.Controlled.SelectedItem
-- Check if selected item is interacting with something
if selectedItem.InteractingWith and selectedItem.InteractingWith.OwnInventory and
selectedItem.InteractingWith ~= Character.Controlled then
openContainer = selectedItem.InteractingWith
hasVisibleInventory = true
debugPrint("Found open container via current interaction: " .. openContainer.Name)
end
end
end)
if hasVisibleInventory and openContainer then return openContainer end
-- For safety, add a visual check - only return a container if it has a visible UI element
if openContainer then
-- Verify this container actually has a visible UI
local isVisible = false
pcall(function()
-- Common method to check if inventory is visible - look for visual components
if openContainer.OwnInventory and openContainer.OwnInventory.visualSlots and
#openContainer.OwnInventory.visualSlots > 0 then
isVisible = true
end
end)
if not isVisible then
debugPrint("Container found but not visibly open in UI: " .. openContainer.Name)
return nil
end
end end
debugPrint("No open container found") debugPrint("No open container found")
return nil return nil
end 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
debugPrint("Stacking from open container: " .. openContainer.Name)
local itemsMoved = 0
local openContainerInv = openContainer.OwnInventory
-- Create a cache of processable items to avoid redundant checks
local itemsToProcess = {}
local processedIdentifiers = {}
-- 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]
local identifierValue = item.Prefab.Identifier.Value
-- Skip container items
if item.OwnInventory then
debugPrint("Skipping container item: " .. item.Name)
goto nextItem
end
-- Skip if we've already processed an item of this type
if processedIdentifiers[identifierValue] then
debugPrint("Already processed items of type: " .. identifierValue .. " from open container")
goto nextItem
end
table.insert(itemsToProcess, {
item = item,
slotIndex = slotIndex
})
-- Mark identifier as scheduled for processing
processedIdentifiers[identifierValue] = true
::nextItem::
end
end
-- Now process the collected items - this greatly reduces redundant container checks
for _, itemData in ipairs(itemsToProcess) do
local item = itemData.item
debugPrint("Processing item from container: " .. item.Name)
-- Try to move the item to each player container
for _, container in ipairs(playerContainers) do
debugPrint("Trying to stack " .. item.Name .. " into " .. container.Name)
if moveItemToContainer(item, container.OwnInventory) then
debugPrint("Stacked " .. item.Name .. " from open container into " .. container.Name)
itemsMoved = itemsMoved + 1
break
end
end
end
return itemsMoved
end
-- We would like to fill larger stacks first -- We would like to fill larger stacks first
---@param itemTree table<string, ItemLocation[]> ---@param itemTree table<string, ItemLocation[]>
---@return table<string, ItemLocation[]> ---@return table<string, ItemLocation[]>
@@ -642,6 +521,10 @@ local function quickStackItems(character)
local itemTree = buildItemTree(inventory, {}) local itemTree = buildItemTree(inventory, {})
itemTree = sortItemtreeBySlots(itemTree) itemTree = sortItemtreeBySlots(itemTree)
stackInventoryItems(inventory, itemTree) stackInventoryItems(inventory, itemTree)
local openContainerInventory = getOpenContainer()
if openContainerInventory then
stackInventoryItems(openContainerInventory, itemTree)
end
-- Find all containers in player inventory, including nested ones -- Find all containers in player inventory, including nested ones
-- local containers = findAllContainers(inventory, {}) -- local containers = findAllContainers(inventory, {})