From d01d0e6a38ea6c65125dddb85bc064d2f926a201 Mon Sep 17 00:00:00 2001 From: PhatPhuckDave Date: Sat, 29 Mar 2025 22:48:06 +0100 Subject: [PATCH] Clean up quickstack --- QuickStackToBag/Lua/Autorun/init.lua | 445 +-------------------------- 1 file changed, 2 insertions(+), 443 deletions(-) diff --git a/QuickStackToBag/Lua/Autorun/init.lua b/QuickStackToBag/Lua/Autorun/init.lua index 0e9cf36..1e95c25 100644 --- a/QuickStackToBag/Lua/Autorun/init.lua +++ b/QuickStackToBag/Lua/Autorun/init.lua @@ -35,305 +35,6 @@ local function debugPrint(message) end end ----@param table table ----@param depth number? -function DumpTable(table, depth) - if depth == nil then - depth = 0 - end - if (depth > 200) then - print("Error: Depth > 200 in dumpTable()") - return - end - for k, v in pairs(table) do - if (type(v) == "table") then - print(string.rep(" ", depth) .. k .. ":") - DumpTable(v, depth + 1) - else - print(string.rep(" ", depth) .. k .. ": ", v) - end - end -end - --- Show notification to player --- Helper function to check if an item is a tool rather than a container -local function isTool(item) - if not item or not item.Prefab or not item.Prefab.Identifier then return false end - - -- Never exclude priority containers - local identifier = item.Prefab.Identifier.Value:lower() - for _, alwaysInclude in ipairs(CONFIG.ALWAYS_INCLUDE) do - if identifier:find(alwaysInclude) then - debugPrint("Always including high priority container: " .. item.Name) - return false - end - end - - -- Check tags first - most reliable method - local hasTags = false - pcall(function() - if item.Tags and item.Tags ~= "" then - hasTags = true - local tags = item.Tags:lower() - - -- If item has explicit container tag, it's a container - if tags:find("container") then - debugPrint("Item has container tag: " .. item.Name) - return false - end - - -- If item has tool or weapon tag, it's a tool - if tags:find("tool") or tags:find("weapon") then - debugPrint("Item has tool/weapon tag: " .. item.Name) - return true - end - end - end) - - -- If we found tags and made a decision based on them, return the result - if hasTags then - -- If we got here, the tags didn't conclusively identify this as a tool - -- For items with tags but no tool/weapon tag, check the number of slots - if item.OwnInventory and item.OwnInventory.slots and #item.OwnInventory.slots > 1 then - -- Items with multiple slots are likely containers - return false - end - end - - -- Fall back to identifier checks - for _, toolId in ipairs(CONFIG.TOOL_IDENTIFIERS) do - if identifier:find(toolId) then - -- Skip known exceptions - if toolId == "tool" and identifier:find("toolbox") or identifier:find("toolbelt") then - return false - end - return true - end - end - - -- Final check based on slots - tools typically have 1 slot, containers have multiple - if item.OwnInventory and item.OwnInventory.slots then - -- Consider items with more than 2 slots as containers - if #item.OwnInventory.slots > 2 then - return false - elseif #item.OwnInventory.slots == 1 then - -- Most single-slot inventories are tools, but check for exceptions - -- Some special container items might have 1 slot but still be containers - if identifier:find("container") or identifier:find("box") or identifier:find("crate") then - return false - end - -- Otherwise likely a tool - return true - end - end - - -- When in doubt, don't classify as a tool - return false -end - --- 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 - - debugPrint("Attempting to stack with existing items in container (" .. #containerInv.slots .. " slots)") - - -- Get max stack size for this item (default to 1 if we can't determine) - local maxStackSize = 60 - pcall(function() - print(item.Prefab.MaxStackSize) - if item.Prefab and item.Prefab.MaxStackSize then - maxStackSize = item.Prefab.MaxStackSize - end - end) - - -- Get current condition/quality of item (for proper stacking) - local itemCondition = 100 - pcall(function() - if item.Condition then - itemCondition = item.Condition - end - end) - - -- Check if the container has any matching items first - local foundMatchingItem = false - local matchingSlots = {} - - -- First pass: find all matching slots - 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 - -- Check similar condition/quality (within 10%) - local containerItemCondition = 100 - pcall(function() - if containerItem.Condition then - containerItemCondition = containerItem.Condition - end - end) - - -- Only consider similar quality items - if math.abs(containerItemCondition - itemCondition) <= 10 then - foundMatchingItem = true - table.insert(matchingSlots, { - slotIndex = slotIndex, - currentSize = #containerInv.slots[slotIndex + 1].items, - remainingSpace = maxStackSize - #containerInv.slots[slotIndex + 1].items - }) - end - end - end - end - - -- If no matching items exist in the container, don't move the item - if not foundMatchingItem then - debugPrint("No matching items in container, skipping " .. item.Name) - return false - end - - -- Sort slots by most available space first - table.sort(matchingSlots, function(a, b) - return a.remainingSpace > b.remainingSpace - end) - - -- Try to stack with existing items that have space - for _, matchingSlot in ipairs(matchingSlots) do - -- Only try to put in slots that have space - if matchingSlot.remainingSpace > 0 then - debugPrint("Trying to stack " .. - item.Name .. " with existing items (slot has " .. matchingSlot.remainingSpace .. " space)") - - -- Try to move the full item - if containerInv.TryPutItem(item, matchingSlot.slotIndex, true, false, nil) then - debugPrint("Successfully stacked " .. item.Name) - return true - else - debugPrint("Failed full stack, likely due to size limits") - - -- If full stack failed, try to split and move part of it (if possible) - pcall(function() - -- Check if we can split stacks and if the item is a stack - if item.SplitStack and maxStackSize > 1 then - local currentStackSize = 1 - -- Try to determine current stack size - pcall(function() - if item.Count then currentStackSize = item.Count end - end) - - -- If current stack is larger than 1, try to split it - if currentStackSize > 1 then - -- Calculate how much we can move - local amountToMove = math.min(matchingSlot.remainingSpace, currentStackSize - 1) - - if amountToMove > 0 then - debugPrint("Attempting to split stack and move " .. amountToMove .. " items") - - -- Try to split the stack - local splitItem = item:SplitStack(amountToMove) - if splitItem then - -- Try to put the split item into the slot - if containerInv.TryPutItem(splitItem, matchingSlot.slotIndex, true, false, nil) then - debugPrint("Successfully moved partial stack of " .. splitItem.Name) - return true - else - debugPrint("Failed to move split stack") - -- If it fails, try to recombine the original stack - pcall(function() - item:AddItem(splitItem) - end) - end - else - debugPrint("Failed to split stack") - end - end - end - end - end) - end - end - end - - -- If we couldn't stack with existing partial stacks, look for empty slots - -- But only if we're still stacking by finding matching items - debugPrint("Failed to stack with existing items, checking for empty slots") - - -- Find empty slots - local emptySlots = {} - for slotIndex = 0, #containerInv.slots - 1 do - if #containerInv.slots[slotIndex + 1].items == 0 then - table.insert(emptySlots, slotIndex) - end - end - - -- If there are empty slots, try to put the item there - for _, slotIndex in ipairs(emptySlots) do - debugPrint("Trying to put " .. item.Name .. " in empty slot " .. slotIndex) - if containerInv.TryPutItem(item, slotIndex, false, false, nil) then - debugPrint("Successfully put " .. item.Name .. " in empty slot") - return true - end - end - - debugPrint("Failed to stack with existing items or find empty slots") - 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(CONFIG.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(CONFIG.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 - -- Skip tools if configured to do so - if CONFIG.EXCLUDE_TOOLS and isTool(item) then - debugPrint("Skipping tool: " .. item.Name .. " (" .. item.Prefab.Identifier.Value .. ")") - else - -- Add this container - debugPrint("Found container: " .. item.Name .. " (" .. item.Prefab.Identifier.Value .. ")") - table.insert(containers, item) - - -- Recursively search inside this container if enabled - if CONFIG.NESTED_CONTAINERS then - debugPrint("Searching inside " .. item.Name .. " for nested containers") - findAllContainers(item.OwnInventory, containers) - end - end - end - end - end - - return containers -end - ---@class ItemLocation ---@field inventory Barotrauma.ItemInventory ---@field slotIndex number @@ -426,9 +127,7 @@ local function moveItemsTo(slot, itemLocation) for _, item in ipairs(slot.items) do itemLocation.inventory.TryPutItem(item, itemLocation.slotIndex, false, true, nil) itemLocation.maxFits = itemLocation.inventory.HowManyCanBePut(item.Prefab, itemLocation.slotIndex) - if itemLocation.maxFits <= 0 then - return - end + if itemLocation.maxFits <= 0 then return end end end end @@ -521,151 +220,11 @@ local function quickStackItems(character) local itemTree = buildItemTree(inventory, {}) itemTree = sortItemtreeBySlots(itemTree) stackInventoryItems(inventory, itemTree) + local openContainerInventory = getOpenContainer() if openContainerInventory then stackInventoryItems(openContainerInventory, itemTree) end - - -- Find all containers in player inventory, including nested ones - -- local containers = findAllContainers(inventory, {}) - - -- -- Fallback: If no containers found, try a direct search for known container types - -- if #containers == 0 then - -- debugPrint("No containers found with standard method, trying fallback method...") - - -- -- Direct slot search for common container types - -- for _, slot in ipairs(inventory.slots) do - -- for _, item in ipairs(slot.items) do - -- if item.OwnInventory then - -- local identifier = item.Prefab.Identifier.Value:lower() - -- -- Force include specific items that we know should be containers - -- if identifier:find("toolbelt") or identifier:find("backpack") or - -- identifier:find("pouch") or identifier:find("container") or - -- identifier:find("box") or identifier:find("crate") or - -- item.Name:find("Container") or item.Name:find("Box") then - - -- debugPrint("Fallback: Force including known container: " .. item.Name) - -- table.insert(containers, item) - - -- -- Also check container slots - -- if CONFIG.NESTED_CONTAINERS and #item.OwnInventory.slots > 2 then - -- for _, containerSlot in ipairs(item.OwnInventory.slots) do - -- for _, containerItem in ipairs(containerSlot.items) do - -- if containerItem.OwnInventory and - -- (containerItem.Prefab.Identifier.Value:lower():find("container") or - -- containerItem.Name:find("Container")) then - - -- debugPrint("Fallback: Found nested container: " .. containerItem.Name) - -- table.insert(containers, containerItem) - -- end - -- end - -- end - -- end - -- end - -- end - -- end - -- end - -- end - - -- debugPrint("Found " .. #containers .. " containers" .. (CONFIG.NESTED_CONTAINERS and " (including nested)" or "")) - -- if #containers == 0 then - -- debugPrint("No containers with inventory found!") - -- showNotification("No containers found! Make sure you have a backpack, toolbelt, or storage box.") - -- return - -- end - - -- -- Sort containers by priority - -- containers = sortContainersByPriority(containers) - -- for i, container in ipairs(containers) do - -- debugPrint(i .. ": " .. container.Name .. " - priority container: " .. - -- tostring(container.Prefab.Identifier.Value:find(CONFIG.PRIORITY_CONTAINERS[1]) ~= nil)) - -- end - - -- local itemsMoved = 0 - - -- -- Create a cache of processable items to avoid redundant checks - -- local itemsToProcess = {} - -- local processedIdentifiers = {} - - -- -- First collect all items we might want to stack - -- for slotIndex, slot in ipairs(inventory.slots) do - -- -- Skip hand slots - -- local isHandSlot = false - -- for _, handSlot in ipairs(CONFIG.HAND_SLOTS) do - -- if slotIndex == handSlot then - -- isHandSlot = true - -- break - -- end - -- end - -- if isHandSlot then - -- debugPrint("Skipping hand slot: " .. slotIndex) - -- goto continueSlot - -- end - - -- -- 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) - -- goto nextItem - -- end - - -- debugPrint("Adding to process list: " .. item.Name) - -- table.insert(itemsToProcess, { - -- item = item, - -- slotIndex = slotIndex - -- }) - - -- -- Mark identifier as scheduled for processing - -- processedIdentifiers[identifierValue] = true - - -- ::nextItem:: - -- end - - -- ::continueSlot:: - -- end - - -- -- Now process the collected items - this greatly reduces redundant container checks - -- for _, itemData in ipairs(itemsToProcess) do - -- local item = itemData.item - - -- debugPrint("Processing inventory item: " .. item.Name .. " (" .. item.Prefab.Identifier.Value .. ")") - - -- -- Try to move the item to each container - -- for _, container in ipairs(containers) do - -- debugPrint("Trying container: " .. container.Name) - -- if moveItemToContainer(item, container.OwnInventory) then - -- debugPrint("Stacked " .. item.Name .. " into " .. container.Name) - -- itemsMoved = itemsMoved + 1 - -- break - -- end - -- end - -- end - - -- -- Check if there's an open container to stack from - -- local openContainer = getOpenContainer() - -- if openContainer then - -- debugPrint("Found open container to stack from: " .. openContainer.Name) - -- local openContainerItemsMoved = stackFromOpenContainer(character, containers, openContainer) - -- itemsMoved = itemsMoved + openContainerItemsMoved - -- else - -- debugPrint("No open container found to stack from") - -- end - - -- if itemsMoved > 0 then - -- debugPrint("Stacked " .. itemsMoved .. " items into containers") - -- else - -- debugPrint("No matching items to stack") - -- end end -- Hook into player control to listen for key press