Remove some bullshit from quickstack
This commit is contained in:
		@@ -14,7 +14,12 @@ local CONFIG = {
 | 
				
			|||||||
    NESTED_CONTAINERS = true,                                 -- Whether to include nested containers
 | 
					    NESTED_CONTAINERS = true,                                 -- Whether to include nested containers
 | 
				
			||||||
    DEBUG_MODE = true,                                        -- Print debug messages
 | 
					    DEBUG_MODE = true,                                        -- Print debug messages
 | 
				
			||||||
    HAND_SLOTS = { 6, 7 },                                    -- Slot numbers for hands (typically slots 6 and 7)
 | 
					    HAND_SLOTS = { 6, 7 },                                    -- Slot numbers for hands (typically slots 6 and 7)
 | 
				
			||||||
    PRIORITY_CONTAINERS = { "toolbelt", "backpack", "pouch" } -- Priority order for containers
 | 
					    PRIORITY_CONTAINERS = { "toolbelt", "backpack", "pouch" }, -- Priority order for containers
 | 
				
			||||||
 | 
					    EXCLUDE_TOOLS = true,                                     -- Exclude tools from container list
 | 
				
			||||||
 | 
					    TOOL_IDENTIFIERS = { "welding", "gun", "weapon", "revolver", "smg", "rifle", "shotgun",
 | 
				
			||||||
 | 
					                         "diving", "oxygen", "scanner", "card", "id", "fuel", "rod", "battery",
 | 
				
			||||||
 | 
					                         "fabricator", "deconstructor" }, -- Common tool identifiers to exclude
 | 
				
			||||||
 | 
					    ALWAYS_INCLUDE = { "toolbelt", "backpack", "pouch" }      -- Always include these items even if they match tool criteria
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
-- MOD INFO
 | 
					-- MOD INFO
 | 
				
			||||||
@@ -31,19 +36,79 @@ local function debugPrint(message)
 | 
				
			|||||||
end
 | 
					end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
-- Show notification to player
 | 
					-- Show notification to player
 | 
				
			||||||
local function showNotification(message)
 | 
					-- Helper function to check if an item is a tool rather than a container
 | 
				
			||||||
    -- Try different methods to show a message to the player
 | 
					local function isTool(item)
 | 
				
			||||||
    debugPrint(message)
 | 
					    if not item or not item.Prefab or not item.Prefab.Identifier then return false end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    -- Method 1: Print to console (always works)
 | 
					    -- Never exclude priority containers
 | 
				
			||||||
    print("[" .. MOD_NAME .. "] " .. message)
 | 
					    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
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    -- Method 2: Try to use GUIMessageBox if available
 | 
					    -- Check tags first - most reliable method
 | 
				
			||||||
 | 
					    local hasTags = false
 | 
				
			||||||
    pcall(function()
 | 
					    pcall(function()
 | 
				
			||||||
        if GUI and GUI.AddMessage then
 | 
					        if item.Tags and item.Tags ~= "" then
 | 
				
			||||||
            GUI.AddMessage(message, GUI.Font.Default)
 | 
					            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
 | 
				
			||||||
    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
 | 
					end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
-- Helper function to move an item to a container, but only if matching items exist
 | 
					-- Helper function to move an item to a container, but only if matching items exist
 | 
				
			||||||
@@ -52,19 +117,50 @@ local function moveItemToContainer(item, containerInv)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    debugPrint("Attempting to stack with existing items in container (" .. #containerInv.slots .. " slots)")
 | 
					    debugPrint("Attempting to stack with existing items in container (" .. #containerInv.slots .. " slots)")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    -- Only try to find matching items to stack with
 | 
					    -- Get max stack size for this item (default to 1 if we can't determine)
 | 
				
			||||||
    local foundMatchingItem = false
 | 
					    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
 | 
					    -- 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 slotIndex = 0, #containerInv.slots - 1 do
 | 
				
			||||||
        for _, containerItem in ipairs(containerInv.slots[slotIndex + 1].items) do
 | 
					        for _, containerItem in ipairs(containerInv.slots[slotIndex + 1].items) do
 | 
				
			||||||
            if containerItem.Prefab.Identifier.Equals(item.Prefab.Identifier) then
 | 
					            if containerItem.Prefab.Identifier.Equals(item.Prefab.Identifier) then
 | 
				
			||||||
                foundMatchingItem = true
 | 
					                -- Check similar condition/quality (within 10%)
 | 
				
			||||||
                debugPrint("Found matching item in container: " .. containerItem.Name)
 | 
					                local containerItemCondition = 100
 | 
				
			||||||
                break
 | 
					                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
 | 
					        end
 | 
				
			||||||
        if foundMatchingItem then break end
 | 
					 | 
				
			||||||
    end
 | 
					    end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    -- If no matching items exist in the container, don't move the item
 | 
					    -- If no matching items exist in the container, don't move the item
 | 
				
			||||||
@@ -73,24 +169,89 @@ local function moveItemToContainer(item, containerInv)
 | 
				
			|||||||
        return false
 | 
					        return false
 | 
				
			||||||
    end
 | 
					    end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    -- Try to stack with existing items
 | 
					    -- Sort slots by most available space first
 | 
				
			||||||
    for slotIndex = 0, #containerInv.slots - 1 do
 | 
					    table.sort(matchingSlots, function(a, b)
 | 
				
			||||||
        for _, containerItem in ipairs(containerInv.slots[slotIndex + 1].items) do
 | 
					        return a.remainingSpace > b.remainingSpace
 | 
				
			||||||
            if containerItem.Prefab.Identifier.Equals(item.Prefab.Identifier) then
 | 
					    end)
 | 
				
			||||||
                -- Try to stack with existing item
 | 
					
 | 
				
			||||||
                debugPrint("Trying to stack " .. item.Name .. " with existing item")
 | 
					    -- Try to stack with existing items that have space
 | 
				
			||||||
                if containerInv.TryPutItem(item, slotIndex, true, false, nil) then
 | 
					    for _, matchingSlot in ipairs(matchingSlots) do
 | 
				
			||||||
                    debugPrint("Successfully stacked " .. item.Name)
 | 
					        -- Only try to put in slots that have space
 | 
				
			||||||
                    return true
 | 
					        if matchingSlot.remainingSpace > 0 then
 | 
				
			||||||
                else
 | 
					            debugPrint("Trying to stack " .. item.Name .. " with existing items (slot has " .. matchingSlot.remainingSpace .. " space)")
 | 
				
			||||||
                    debugPrint("Failed to stack " .. item.Name .. " - TryPutItem failed")
 | 
					
 | 
				
			||||||
                end
 | 
					            -- 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
 | 
					        end
 | 
				
			||||||
    end
 | 
					    end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    -- We don't try to place in empty slots anymore, only stack with existing items
 | 
					    -- If we couldn't stack with existing partial stacks, look for empty slots
 | 
				
			||||||
    debugPrint("Failed to stack with existing items")
 | 
					    -- 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
 | 
					    return false
 | 
				
			||||||
end
 | 
					end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -131,14 +292,19 @@ local function findAllContainers(inventory, containers)
 | 
				
			|||||||
    for _, slot in ipairs(inventory.slots) do
 | 
					    for _, slot in ipairs(inventory.slots) do
 | 
				
			||||||
        for _, item in ipairs(slot.items) do
 | 
					        for _, item in ipairs(slot.items) do
 | 
				
			||||||
            if item.OwnInventory then
 | 
					            if item.OwnInventory then
 | 
				
			||||||
                -- Add this container
 | 
					                -- Skip tools if configured to do so
 | 
				
			||||||
                debugPrint("Found container: " .. item.Name .. " (" .. item.Prefab.Identifier.Value .. ")")
 | 
					                if CONFIG.EXCLUDE_TOOLS and isTool(item) then
 | 
				
			||||||
                table.insert(containers, item)
 | 
					                    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
 | 
					                    -- Recursively search inside this container if enabled
 | 
				
			||||||
                if CONFIG.NESTED_CONTAINERS then
 | 
					                    if CONFIG.NESTED_CONTAINERS then
 | 
				
			||||||
                    debugPrint("Searching inside " .. item.Name .. " for nested containers")
 | 
					                        debugPrint("Searching inside " .. item.Name .. " for nested containers")
 | 
				
			||||||
                    findAllContainers(item.OwnInventory, containers)
 | 
					                        findAllContainers(item.OwnInventory, containers)
 | 
				
			||||||
 | 
					                    end
 | 
				
			||||||
                end
 | 
					                end
 | 
				
			||||||
            end
 | 
					            end
 | 
				
			||||||
        end
 | 
					        end
 | 
				
			||||||
@@ -147,93 +313,73 @@ local function findAllContainers(inventory, containers)
 | 
				
			|||||||
    return containers
 | 
					    return containers
 | 
				
			||||||
end
 | 
					end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
-- Find the currently open container
 | 
					-- Find the currently open container - improved version
 | 
				
			||||||
local function getOpenContainer()
 | 
					local function getOpenContainer()
 | 
				
			||||||
    debugPrint("Attempting to find open container...")
 | 
					    debugPrint("Attempting to find open container...")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    -- Method 1: Check if Inventory.OpenState is accessible and has an open container
 | 
					    local openContainer = nil
 | 
				
			||||||
 | 
					    local hasVisibleInventory = false
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    -- Method 1: Try to use Inventory.CurrentInventory or similar properties
 | 
				
			||||||
    pcall(function()
 | 
					    pcall(function()
 | 
				
			||||||
        if Character.Controlled and Character.Controlled.SelectedCharacter then
 | 
					        if Inventory and Inventory.CurrentContainer and Inventory.CurrentContainer.Owner then
 | 
				
			||||||
            local selectedChar = Character.Controlled.SelectedCharacter
 | 
					            openContainer = Inventory.CurrentContainer.Owner
 | 
				
			||||||
            if selectedChar.Inventory then
 | 
					            hasVisibleInventory = true
 | 
				
			||||||
                debugPrint("Checking selected character's inventory")
 | 
					            debugPrint("Found open container via CurrentContainer: " .. openContainer.Name)
 | 
				
			||||||
                -- This is likely the container the player is interacting with
 | 
					 | 
				
			||||||
                return selectedChar
 | 
					 | 
				
			||||||
            end
 | 
					 | 
				
			||||||
        end
 | 
					        end
 | 
				
			||||||
    end)
 | 
					    end)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    -- Method 2: Inspect GUI components to find inventory GUI components
 | 
					    if hasVisibleInventory and openContainer then return openContainer end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    -- Method 2: Check if Inventory.OpenInventories exists and has entries
 | 
				
			||||||
    pcall(function()
 | 
					    pcall(function()
 | 
				
			||||||
        if GUI and GUI.Components then
 | 
					        if Inventory and Inventory.OpenInventories and #Inventory.OpenInventories > 0 then
 | 
				
			||||||
            for _, component in pairs(GUI.Components) do
 | 
					            -- Get the last opened inventory
 | 
				
			||||||
                -- Look for UI components related to inventory
 | 
					            for _, inv in ipairs(Inventory.OpenInventories) do
 | 
				
			||||||
                if component.RectTransform and component.RectTransform.GUIComponent and
 | 
					                if inv and inv.Owner and inv.Owner ~= Character.Controlled then
 | 
				
			||||||
                    component.RectTransform.GUIComponent.UserData and
 | 
					                    openContainer = inv.Owner
 | 
				
			||||||
                    component.RectTransform.GUIComponent.UserData.Item then
 | 
					                    hasVisibleInventory = true
 | 
				
			||||||
                    local item = component.RectTransform.GUIComponent.UserData.Item
 | 
					                    debugPrint("Found open container via OpenInventories: " .. openContainer.Name)
 | 
				
			||||||
                    if item.OwnInventory then
 | 
					                    break
 | 
				
			||||||
                        debugPrint("Found open container via GUI component: " .. item.Name)
 | 
					 | 
				
			||||||
                        return item
 | 
					 | 
				
			||||||
                    end
 | 
					 | 
				
			||||||
                end
 | 
					                end
 | 
				
			||||||
            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
 | 
					    -- Method 3: Check if currently selected item is interacting with a container
 | 
				
			||||||
    pcall(function()
 | 
					    pcall(function()
 | 
				
			||||||
        if Character.Controlled and Character.Controlled.SelectedItem then
 | 
					        if Character.Controlled and Character.Controlled.SelectedItem then
 | 
				
			||||||
            local selectedItem = Character.Controlled.SelectedItem
 | 
					            local selectedItem = Character.Controlled.SelectedItem
 | 
				
			||||||
            -- Check if selected item is interacting with something
 | 
					            -- Check if selected item is interacting with something
 | 
				
			||||||
            if selectedItem.InteractingWith and selectedItem.InteractingWith.OwnInventory then
 | 
					            if selectedItem.InteractingWith and selectedItem.InteractingWith.OwnInventory and
 | 
				
			||||||
                debugPrint("Found open container via current interaction: " .. selectedItem.InteractingWith.Name)
 | 
					               selectedItem.InteractingWith ~= Character.Controlled then
 | 
				
			||||||
                return selectedItem.InteractingWith
 | 
					                openContainer = selectedItem.InteractingWith
 | 
				
			||||||
 | 
					                hasVisibleInventory = true
 | 
				
			||||||
 | 
					                debugPrint("Found open container via current interaction: " .. openContainer.Name)
 | 
				
			||||||
            end
 | 
					            end
 | 
				
			||||||
        end
 | 
					        end
 | 
				
			||||||
    end)
 | 
					    end)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    -- Method 4: Try to use Inventory.DraggingInventory (if it exists)
 | 
					    if hasVisibleInventory and openContainer then return openContainer end
 | 
				
			||||||
    pcall(function()
 | 
					 | 
				
			||||||
        if Inventory and Inventory.DraggingInventory and
 | 
					 | 
				
			||||||
            Inventory.DraggingInventory.Owner and
 | 
					 | 
				
			||||||
            Inventory.DraggingInventory.Owner ~= Character.Controlled then
 | 
					 | 
				
			||||||
            debugPrint("Found open container via DraggingInventory: " .. Inventory.DraggingInventory.Owner.Name)
 | 
					 | 
				
			||||||
            return Inventory.DraggingInventory.Owner
 | 
					 | 
				
			||||||
        end
 | 
					 | 
				
			||||||
    end)
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    -- Method 5: Check all items in the game with open inventories
 | 
					    -- For safety, add a visual check - only return a container if it has a visible UI element
 | 
				
			||||||
    for item in Item.ItemList do
 | 
					    if openContainer then
 | 
				
			||||||
        if item and item.OwnInventory then
 | 
					        -- Verify this container actually has a visible UI
 | 
				
			||||||
            local isOpened = false
 | 
					        local isVisible = false
 | 
				
			||||||
            -- Try different ways to detect if an inventory is opened
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
            -- Method 5.1: Check IsOpenedByPlayer if available
 | 
					        pcall(function()
 | 
				
			||||||
            pcall(function()
 | 
					            -- Common method to check if inventory is visible - look for visual components
 | 
				
			||||||
                if item.OwnInventory.IsOpenedByPlayer then
 | 
					            if openContainer.OwnInventory and openContainer.OwnInventory.visualSlots and
 | 
				
			||||||
                    isOpened = item.OwnInventory.IsOpenedByPlayer
 | 
					               #openContainer.OwnInventory.visualSlots > 0 then
 | 
				
			||||||
                end
 | 
					                isVisible = true
 | 
				
			||||||
            end)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            -- Method 5.2: Check if inventory has visualSlots created
 | 
					 | 
				
			||||||
            pcall(function()
 | 
					 | 
				
			||||||
                if item.OwnInventory.visualSlots and #item.OwnInventory.visualSlots > 0 then
 | 
					 | 
				
			||||||
                    isOpened = true
 | 
					 | 
				
			||||||
                end
 | 
					 | 
				
			||||||
            end)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            -- Method 5.3: Check if OpenState > 0
 | 
					 | 
				
			||||||
            pcall(function()
 | 
					 | 
				
			||||||
                if item.OwnInventory.OpenState and item.OwnInventory.OpenState > 0 then
 | 
					 | 
				
			||||||
                    isOpened = true
 | 
					 | 
				
			||||||
                end
 | 
					 | 
				
			||||||
            end)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            if isOpened then
 | 
					 | 
				
			||||||
                debugPrint("Found open container: " .. item.Name)
 | 
					 | 
				
			||||||
                return item
 | 
					 | 
				
			||||||
            end
 | 
					            end
 | 
				
			||||||
 | 
					        end)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if not isVisible then
 | 
				
			||||||
 | 
					            debugPrint("Container found but not visibly open in UI: " .. openContainer.Name)
 | 
				
			||||||
 | 
					            return nil
 | 
				
			||||||
        end
 | 
					        end
 | 
				
			||||||
    end
 | 
					    end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -250,6 +396,10 @@ local function stackFromOpenContainer(character, playerContainers, openContainer
 | 
				
			|||||||
    local itemsMoved = 0
 | 
					    local itemsMoved = 0
 | 
				
			||||||
    local openContainerInv = openContainer.OwnInventory
 | 
					    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
 | 
					    -- Process each slot in the open container
 | 
				
			||||||
    for slotIndex = 0, #openContainerInv.slots - 1 do
 | 
					    for slotIndex = 0, #openContainerInv.slots - 1 do
 | 
				
			||||||
        local slot = openContainerInv.slots[slotIndex + 1]
 | 
					        local slot = openContainerInv.slots[slotIndex + 1]
 | 
				
			||||||
@@ -257,6 +407,7 @@ local function stackFromOpenContainer(character, playerContainers, openContainer
 | 
				
			|||||||
        -- Process items in the slot
 | 
					        -- Process items in the slot
 | 
				
			||||||
        for i = #slot.items, 1, -1 do
 | 
					        for i = #slot.items, 1, -1 do
 | 
				
			||||||
            local item = slot.items[i]
 | 
					            local item = slot.items[i]
 | 
				
			||||||
 | 
					            local identifierValue = item.Prefab.Identifier.Value
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            -- Skip container items
 | 
					            -- Skip container items
 | 
				
			||||||
            if item.OwnInventory then
 | 
					            if item.OwnInventory then
 | 
				
			||||||
@@ -264,22 +415,41 @@ local function stackFromOpenContainer(character, playerContainers, openContainer
 | 
				
			|||||||
                goto nextItem
 | 
					                goto nextItem
 | 
				
			||||||
            end
 | 
					            end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            debugPrint("Processing item from container: " .. item.Name)
 | 
					            -- Skip if we've already processed an item of this type
 | 
				
			||||||
 | 
					            if processedIdentifiers[identifierValue] then
 | 
				
			||||||
            -- Try to move the item to each player container
 | 
					                debugPrint("Already processed items of type: " .. identifierValue .. " from open container")
 | 
				
			||||||
            for _, container in ipairs(playerContainers) do
 | 
					                goto nextItem
 | 
				
			||||||
                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
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            table.insert(itemsToProcess, {
 | 
				
			||||||
 | 
					                item = item,
 | 
				
			||||||
 | 
					                slotIndex = slotIndex
 | 
				
			||||||
 | 
					            })
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            -- Mark identifier as scheduled for processing
 | 
				
			||||||
 | 
					            processedIdentifiers[identifierValue] = true
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            ::nextItem::
 | 
					            ::nextItem::
 | 
				
			||||||
        end
 | 
					        end
 | 
				
			||||||
    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
 | 
					    return itemsMoved
 | 
				
			||||||
end
 | 
					end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -301,9 +471,48 @@ local function quickStackItems(character)
 | 
				
			|||||||
    -- 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, {})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    -- 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 ""))
 | 
					    debugPrint("Found " .. #containers .. " containers" .. (CONFIG.NESTED_CONTAINERS and " (including nested)" or ""))
 | 
				
			||||||
    if #containers == 0 then
 | 
					    if #containers == 0 then
 | 
				
			||||||
        debugPrint("No containers with inventory found!")
 | 
					        debugPrint("No containers with inventory found!")
 | 
				
			||||||
 | 
					        showNotification("No containers found! Make sure you have a backpack, toolbelt, or storage box.")
 | 
				
			||||||
        return
 | 
					        return
 | 
				
			||||||
    end
 | 
					    end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -316,7 +525,11 @@ local function quickStackItems(character)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    local itemsMoved = 0
 | 
					    local itemsMoved = 0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    -- Process inventory slots
 | 
					    -- 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
 | 
					    for slotIndex, slot in ipairs(inventory.slots) do
 | 
				
			||||||
        -- Skip hand slots
 | 
					        -- Skip hand slots
 | 
				
			||||||
        local isHandSlot = false
 | 
					        local isHandSlot = false
 | 
				
			||||||
@@ -334,6 +547,7 @@ local function quickStackItems(character)
 | 
				
			|||||||
        -- Process items in the slot
 | 
					        -- Process items in the slot
 | 
				
			||||||
        for i = #slot.items, 1, -1 do
 | 
					        for i = #slot.items, 1, -1 do
 | 
				
			||||||
            local item = slot.items[i]
 | 
					            local item = slot.items[i]
 | 
				
			||||||
 | 
					            local identifierValue = item.Prefab.Identifier.Value
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            -- Skip container items
 | 
					            -- Skip container items
 | 
				
			||||||
            if item.OwnInventory then
 | 
					            if item.OwnInventory then
 | 
				
			||||||
@@ -341,24 +555,44 @@ local function quickStackItems(character)
 | 
				
			|||||||
                goto nextItem
 | 
					                goto nextItem
 | 
				
			||||||
            end
 | 
					            end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            debugPrint("Processing inventory item: " .. item.Name .. " (" .. item.Prefab.Identifier.Value .. ")")
 | 
					            -- Skip if we've already processed an item of this type
 | 
				
			||||||
 | 
					            if processedIdentifiers[identifierValue] then
 | 
				
			||||||
            -- Try to move the item to each container
 | 
					                debugPrint("Already processed items of type: " .. identifierValue)
 | 
				
			||||||
            for _, container in ipairs(containers) do
 | 
					                goto nextItem
 | 
				
			||||||
                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
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            debugPrint("Adding to process list: " .. item.Name)
 | 
				
			||||||
 | 
					            table.insert(itemsToProcess, {
 | 
				
			||||||
 | 
					                item = item,
 | 
				
			||||||
 | 
					                slotIndex = slotIndex
 | 
				
			||||||
 | 
					            })
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            -- Mark identifier as scheduled for processing
 | 
				
			||||||
 | 
					            processedIdentifiers[identifierValue] = true
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            ::nextItem::
 | 
					            ::nextItem::
 | 
				
			||||||
        end
 | 
					        end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        ::continueSlot::
 | 
					        ::continueSlot::
 | 
				
			||||||
    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 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
 | 
					    -- Check if there's an open container to stack from
 | 
				
			||||||
    local openContainer = getOpenContainer()
 | 
					    local openContainer = getOpenContainer()
 | 
				
			||||||
    if openContainer then
 | 
					    if openContainer then
 | 
				
			||||||
@@ -371,23 +605,11 @@ local function quickStackItems(character)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    if itemsMoved > 0 then
 | 
					    if itemsMoved > 0 then
 | 
				
			||||||
        debugPrint("Stacked " .. itemsMoved .. " items into containers")
 | 
					        debugPrint("Stacked " .. itemsMoved .. " items into containers")
 | 
				
			||||||
        pcall(function()
 | 
					 | 
				
			||||||
            Game.PlaySound("hit")
 | 
					 | 
				
			||||||
        end)
 | 
					 | 
				
			||||||
        showNotification("Stacked " .. itemsMoved .. " items")
 | 
					 | 
				
			||||||
    else
 | 
					    else
 | 
				
			||||||
        debugPrint("No matching items to stack")
 | 
					        debugPrint("No matching items to stack")
 | 
				
			||||||
        showNotification("No matching items to stack")
 | 
					 | 
				
			||||||
    end
 | 
					    end
 | 
				
			||||||
end
 | 
					end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
-- Show a small message to the user when the mod loads
 | 
					 | 
				
			||||||
Hook.Add("think", "quickStackInitMessage", function()
 | 
					 | 
				
			||||||
    -- Use a safer method to show a message
 | 
					 | 
				
			||||||
    showNotification(MOD_NAME .. " loaded! Press F to stack items.")
 | 
					 | 
				
			||||||
    Hook.Remove("think", "quickStackInitMessage")
 | 
					 | 
				
			||||||
end)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
-- Hook into player control to listen for key press
 | 
					-- Hook into player control to listen for key press
 | 
				
			||||||
Hook.Patch("Barotrauma.Character", "ControlLocalPlayer", function(instance, ptable)
 | 
					Hook.Patch("Barotrauma.Character", "ControlLocalPlayer", function(instance, ptable)
 | 
				
			||||||
    if not PlayerInput.KeyHit(CONFIG.TRIGGER_KEY) then return end
 | 
					    if not PlayerInput.KeyHit(CONFIG.TRIGGER_KEY) then return end
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user