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
|
||||||
|
-- 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
|
foundMatchingItem = true
|
||||||
debugPrint("Found matching item in container: " .. containerItem.Name)
|
table.insert(matchingSlots, {
|
||||||
break
|
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
|
||||||
|
-- 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)
|
debugPrint("Successfully stacked " .. item.Name)
|
||||||
return true
|
return true
|
||||||
else
|
else
|
||||||
debugPrint("Failed to stack " .. item.Name .. " - TryPutItem failed")
|
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
|
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,6 +292,10 @@ 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
|
||||||
|
-- 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
|
-- Add this container
|
||||||
debugPrint("Found container: " .. item.Name .. " (" .. item.Prefab.Identifier.Value .. ")")
|
debugPrint("Found container: " .. item.Name .. " (" .. item.Prefab.Identifier.Value .. ")")
|
||||||
table.insert(containers, item)
|
table.insert(containers, item)
|
||||||
@@ -143,97 +308,78 @@ local function findAllContainers(inventory, containers)
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
end
|
||||||
|
|
||||||
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
|
end
|
||||||
return selectedChar
|
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)
|
end)
|
||||||
|
|
||||||
-- Method 2: Inspect GUI components to find inventory GUI components
|
if hasVisibleInventory and openContainer then return openContainer end
|
||||||
pcall(function()
|
|
||||||
if GUI and GUI.Components then
|
|
||||||
for _, component in pairs(GUI.Components) do
|
|
||||||
-- Look for UI components related to inventory
|
|
||||||
if component.RectTransform and component.RectTransform.GUIComponent and
|
|
||||||
component.RectTransform.GUIComponent.UserData and
|
|
||||||
component.RectTransform.GUIComponent.UserData.Item then
|
|
||||||
local item = component.RectTransform.GUIComponent.UserData.Item
|
|
||||||
if item.OwnInventory then
|
|
||||||
debugPrint("Found open container via GUI component: " .. item.Name)
|
|
||||||
return item
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
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
|
||||||
|
|
||||||
|
-- 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()
|
pcall(function()
|
||||||
if Inventory and Inventory.DraggingInventory and
|
-- Common method to check if inventory is visible - look for visual components
|
||||||
Inventory.DraggingInventory.Owner and
|
if openContainer.OwnInventory and openContainer.OwnInventory.visualSlots and
|
||||||
Inventory.DraggingInventory.Owner ~= Character.Controlled then
|
#openContainer.OwnInventory.visualSlots > 0 then
|
||||||
debugPrint("Found open container via DraggingInventory: " .. Inventory.DraggingInventory.Owner.Name)
|
isVisible = true
|
||||||
return Inventory.DraggingInventory.Owner
|
|
||||||
end
|
end
|
||||||
end)
|
end)
|
||||||
|
|
||||||
-- Method 5: Check all items in the game with open inventories
|
if not isVisible then
|
||||||
for item in Item.ItemList do
|
debugPrint("Container found but not visibly open in UI: " .. openContainer.Name)
|
||||||
if item and item.OwnInventory then
|
return nil
|
||||||
local isOpened = false
|
|
||||||
-- Try different ways to detect if an inventory is opened
|
|
||||||
|
|
||||||
-- Method 5.1: Check IsOpenedByPlayer if available
|
|
||||||
pcall(function()
|
|
||||||
if item.OwnInventory.IsOpenedByPlayer then
|
|
||||||
isOpened = item.OwnInventory.IsOpenedByPlayer
|
|
||||||
end
|
|
||||||
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
|
||||||
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,6 +415,28 @@ local function stackFromOpenContainer(character, playerContainers, openContainer
|
|||||||
goto nextItem
|
goto nextItem
|
||||||
end
|
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)
|
debugPrint("Processing item from container: " .. item.Name)
|
||||||
|
|
||||||
-- Try to move the item to each player container
|
-- Try to move the item to each player container
|
||||||
@@ -275,9 +448,6 @@ local function stackFromOpenContainer(character, playerContainers, openContainer
|
|||||||
break
|
break
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
::nextItem::
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
return itemsMoved
|
return itemsMoved
|
||||||
@@ -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,6 +555,31 @@ local function quickStackItems(character)
|
|||||||
goto nextItem
|
goto nextItem
|
||||||
end
|
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 .. ")")
|
debugPrint("Processing inventory item: " .. item.Name .. " (" .. item.Prefab.Identifier.Value .. ")")
|
||||||
|
|
||||||
-- Try to move the item to each container
|
-- Try to move the item to each container
|
||||||
@@ -352,11 +591,6 @@ local function quickStackItems(character)
|
|||||||
break
|
break
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
::nextItem::
|
|
||||||
end
|
|
||||||
|
|
||||||
::continueSlot::
|
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Check if there's an open container to stack from
|
-- Check if there's an open container to stack from
|
||||||
@@ -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