Clean up quickstack
This commit is contained in:
@@ -35,305 +35,6 @@ local function debugPrint(message)
|
|||||||
end
|
end
|
||||||
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
|
---@class ItemLocation
|
||||||
---@field inventory Barotrauma.ItemInventory
|
---@field inventory Barotrauma.ItemInventory
|
||||||
---@field slotIndex number
|
---@field slotIndex number
|
||||||
@@ -426,9 +127,7 @@ local function moveItemsTo(slot, itemLocation)
|
|||||||
for _, item in ipairs(slot.items) do
|
for _, item in ipairs(slot.items) do
|
||||||
itemLocation.inventory.TryPutItem(item, itemLocation.slotIndex, false, true, nil)
|
itemLocation.inventory.TryPutItem(item, itemLocation.slotIndex, false, true, nil)
|
||||||
itemLocation.maxFits = itemLocation.inventory.HowManyCanBePut(item.Prefab, itemLocation.slotIndex)
|
itemLocation.maxFits = itemLocation.inventory.HowManyCanBePut(item.Prefab, itemLocation.slotIndex)
|
||||||
if itemLocation.maxFits <= 0 then
|
if itemLocation.maxFits <= 0 then return end
|
||||||
return
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -521,151 +220,11 @@ 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()
|
local openContainerInventory = getOpenContainer()
|
||||||
if openContainerInventory then
|
if openContainerInventory then
|
||||||
stackInventoryItems(openContainerInventory, itemTree)
|
stackInventoryItems(openContainerInventory, itemTree)
|
||||||
end
|
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
|
end
|
||||||
|
|
||||||
-- Hook into player control to listen for key press
|
-- Hook into player control to listen for key press
|
||||||
|
|||||||
Reference in New Issue
Block a user