From 1dd4f9aa228259a7aa6158e5f2e4e71c672dab2d Mon Sep 17 00:00:00 2001 From: PhatPhuckDave Date: Sat, 29 Mar 2025 19:58:38 +0100 Subject: [PATCH] Also stack from open container --- QuickStackToBag/Lua/Autorun/init.lua | 252 +++++++++++++++++++++------ 1 file changed, 201 insertions(+), 51 deletions(-) diff --git a/QuickStackToBag/Lua/Autorun/init.lua b/QuickStackToBag/Lua/Autorun/init.lua index 78cadbd..9588948 100644 --- a/QuickStackToBag/Lua/Autorun/init.lua +++ b/QuickStackToBag/Lua/Autorun/init.lua @@ -2,20 +2,55 @@ if SERVER then return end -- Register necessary types and make fields accessible LuaUserData.RegisterType("Barotrauma.Items.Components.ItemContainer+SlotRestrictions") -LuaUserData.RegisterType('System.Collections.Immutable.ImmutableArray`1[[Barotrauma.Items.Components.ItemContainer+SlotRestrictions, Barotrauma]]') +LuaUserData.RegisterType( + 'System.Collections.Immutable.ImmutableArray`1[[Barotrauma.Items.Components.ItemContainer+SlotRestrictions, Barotrauma]]') LuaUserData.MakeFieldAccessible(Descriptors['Barotrauma.Items.Components.ItemContainer'], 'slotRestrictions') LuaUserData.MakeFieldAccessible(Descriptors['Barotrauma.ItemInventory'], 'slots') LuaUserData.MakeFieldAccessible(Descriptors["Barotrauma.CharacterInventory"], "slots") -- Simple configuration -local HAND_SLOTS = { 6, 7 } -local PRIORITY_CONTAINERS = { "toolbelt", "backpack", "pouch" } -- Identifiers for priority containers +local CONFIG = { + TRIGGER_KEY = Keys.F, -- Key to press for quick stacking + NESTED_CONTAINERS = true, -- Whether to include nested containers + DEBUG_MODE = true, -- Print debug messages + HAND_SLOTS = { 6, 7 }, -- Slot numbers for hands (typically slots 6 and 7) + PRIORITY_CONTAINERS = { "toolbelt", "backpack", "pouch" } -- Priority order for containers +} + +-- MOD INFO +local MOD_NAME = "Quick Stack To Containers" +local MOD_VERSION = "1.1.0" + +print(MOD_NAME .. " v" .. MOD_VERSION .. " loaded!") + +-- Debugging helper function +local function debugPrint(message) + if CONFIG.DEBUG_MODE then + print("[" .. MOD_NAME .. "] " .. message) + end +end + +-- Show notification to player +local function showNotification(message) + -- Try different methods to show a message to the player + debugPrint(message) + + -- Method 1: Print to console (always works) + print("[" .. MOD_NAME .. "] " .. message) + + -- Method 2: Try to use GUIMessageBox if available + pcall(function() + if GUI and GUI.AddMessage then + GUI.AddMessage(message, GUI.Font.Default) + end + end) +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 - print("[QuickStack] 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 local foundMatchingItem = false @@ -25,7 +60,7 @@ local function moveItemToContainer(item, containerInv) for _, containerItem in ipairs(containerInv.slots[slotIndex + 1].items) do if containerItem.Prefab.Identifier.Equals(item.Prefab.Identifier) then foundMatchingItem = true - print("[QuickStack] Found matching item in container") + debugPrint("Found matching item in container: " .. containerItem.Name) break end end @@ -34,7 +69,7 @@ local function moveItemToContainer(item, containerInv) -- If no matching items exist in the container, don't move the item if not foundMatchingItem then - print("[QuickStack] No matching items in container, skipping") + debugPrint("No matching items in container, skipping " .. item.Name) return false end @@ -43,16 +78,19 @@ local function moveItemToContainer(item, containerInv) for _, containerItem in ipairs(containerInv.slots[slotIndex + 1].items) do if containerItem.Prefab.Identifier.Equals(item.Prefab.Identifier) then -- Try to stack with existing item - print("[QuickStack] Stacking with existing item") + debugPrint("Trying to stack " .. item.Name .. " with existing item") if containerInv.TryPutItem(item, slotIndex, true, false, nil) then + debugPrint("Successfully stacked " .. item.Name) return true + else + debugPrint("Failed to stack " .. item.Name .. " - TryPutItem failed") end end end end -- We don't try to place in empty slots anymore, only stack with existing items - print("[QuickStack] Failed to stack with existing items") + debugPrint("Failed to stack with existing items") return false end @@ -63,7 +101,7 @@ local function sortContainersByPriority(containers) local bPriority = -1 -- Check priority for first container - for i, identifier in ipairs(PRIORITY_CONTAINERS) do + for i, identifier in ipairs(CONFIG.PRIORITY_CONTAINERS) do if a.Prefab.Identifier.Value:find(identifier) then aPriority = i break @@ -71,7 +109,7 @@ local function sortContainersByPriority(containers) end -- Check priority for second container - for i, identifier in ipairs(PRIORITY_CONTAINERS) do + for i, identifier in ipairs(CONFIG.PRIORITY_CONTAINERS) do if b.Prefab.Identifier.Value:find(identifier) then bPriority = i break @@ -87,48 +125,119 @@ 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 -- Add this container - print("[QuickStack] Found container: " .. item.Name .. " (" .. item.Prefab.Identifier.Value .. ")") + debugPrint("Found container: " .. item.Name .. " (" .. item.Prefab.Identifier.Value .. ")") table.insert(containers, item) - - -- Recursively search inside this container - findAllContainers(item.OwnInventory, containers) + + -- 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 - + return containers end --- Find the currently open container using the better approach with opened GUIs +-- Find the currently open container local function getOpenContainer() - -- Check if any ItemContainer GUIs are open - for _, gui in pairs(GUI.OpenGuis) do - if gui.UserData ~= nil and gui.UserData.Inventory ~= nil then - -- Make sure it's not the player's inventory - if gui.UserData.Item ~= nil and gui.UserData.Item.Inventory ~= Character.Controlled.Inventory then - print("[QuickStack] Found open container: " .. gui.UserData.Item.Name) - return gui.UserData.Item + debugPrint("Attempting to find open container...") + + -- Method 1: Check if Inventory.OpenState is accessible and has an open container + pcall(function() + if Character.Controlled and Character.Controlled.SelectedCharacter then + local selectedChar = Character.Controlled.SelectedCharacter + if selectedChar.Inventory then + debugPrint("Checking selected character's inventory") + -- This is likely the container the player is interacting with + return selectedChar + end + end + end) + + -- Method 2: Inspect GUI components to find inventory GUI components + 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 + pcall(function() + if Character.Controlled and Character.Controlled.SelectedItem then + local selectedItem = Character.Controlled.SelectedItem + -- Check if selected item is interacting with something + if selectedItem.InteractingWith and selectedItem.InteractingWith.OwnInventory then + debugPrint("Found open container via current interaction: " .. selectedItem.InteractingWith.Name) + return selectedItem.InteractingWith + end + end + end) + + -- Method 4: Try to use Inventory.DraggingInventory (if it exists) + 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 item in Item.ItemList do + if item and item.OwnInventory then + 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 - - -- Try an alternative approach using opened inventories - for _, inventory in pairs(ItemInventory.OpenInventories) do - if inventory.Owner ~= nil and inventory.Owner.Inventory ~= Character.Controlled.Inventory then - -- Found a non-player inventory - print("[QuickStack] Found open inventory: " .. inventory.Owner.Name) - return inventory.Owner - end - end - - print("[QuickStack] No open container found") + + debugPrint("No open container found") return nil end @@ -136,7 +245,7 @@ end local function stackFromOpenContainer(character, playerContainers, openContainer) if not character or not openContainer or not openContainer.OwnInventory then return 0 end - print("[QuickStack] Stacking from open container: " .. openContainer.Name) + debugPrint("Stacking from open container: " .. openContainer.Name) local itemsMoved = 0 local openContainerInv = openContainer.OwnInventory @@ -150,12 +259,18 @@ local function stackFromOpenContainer(character, playerContainers, openContainer local item = slot.items[i] -- Skip container items - if item.OwnInventory then goto nextItem end + if item.OwnInventory then + debugPrint("Skipping container item: " .. item.Name) + goto nextItem + end + + 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 - print("[QuickStack] Stacked " .. item.Name .. " from open container into " .. container.Name) + debugPrint("Stacked " .. item.Name .. " from open container into " .. container.Name) itemsMoved = itemsMoved + 1 break end @@ -170,23 +285,34 @@ end -- Function to quickly stack items from inventory to containers local function quickStackItems(character) - if not character then return end - print("[QuickStack] Function called") + if not character then + debugPrint("No character found") + return + end + + debugPrint("Quick stack function called") local inventory = character.Inventory - if not inventory or not inventory.slots then return end + if not inventory or not inventory.slots then + debugPrint("Character has no inventory") + return + end -- Find all containers in player inventory, including nested ones local containers = findAllContainers(inventory, {}) - print("[QuickStack] Found " .. #containers .. " containers (including nested)") + debugPrint("Found " .. #containers .. " containers" .. (CONFIG.NESTED_CONTAINERS and " (including nested)" or "")) if #containers == 0 then - print("[QuickStack] No containers with inventory found!") + debugPrint("No containers with inventory found!") 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 @@ -194,25 +320,34 @@ local function quickStackItems(character) for slotIndex, slot in ipairs(inventory.slots) do -- Skip hand slots local isHandSlot = false - for _, handSlot in ipairs(HAND_SLOTS) do + for _, handSlot in ipairs(CONFIG.HAND_SLOTS) do if slotIndex == handSlot then isHandSlot = true break end end - if isHandSlot then goto continueSlot 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] -- Skip container items - if item.OwnInventory then goto nextItem end + if item.OwnInventory then + debugPrint("Skipping container item: " .. item.Name) + goto nextItem + end + + 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 - print("[QuickStack] Stacked " .. item.Name .. " into " .. container.Name) + debugPrint("Stacked " .. item.Name .. " into " .. container.Name) itemsMoved = itemsMoved + 1 break end @@ -227,20 +362,35 @@ local function quickStackItems(character) -- 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 - print("[QuickStack] Stacked " .. itemsMoved .. " items into containers") + debugPrint("Stacked " .. itemsMoved .. " items into containers") + pcall(function() + Game.PlaySound("hit") + end) + showNotification("Stacked " .. itemsMoved .. " items") else - print("[QuickStack] No matching items to stack") + debugPrint("No matching items to stack") + showNotification("No matching items to stack") 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.Patch("Barotrauma.Character", "ControlLocalPlayer", function(instance, ptable) - if not PlayerInput.KeyHit(Keys.F) then return end + if not PlayerInput.KeyHit(CONFIG.TRIGGER_KEY) then return end local character = instance if not character then return end