Also stack from open container

This commit is contained in:
2025-03-29 19:58:38 +01:00
parent a1a3952645
commit 1dd4f9aa22

View File

@@ -2,20 +2,55 @@ if SERVER then return end
-- Register necessary types and make fields accessible -- Register necessary types and make fields accessible
LuaUserData.RegisterType("Barotrauma.Items.Components.ItemContainer+SlotRestrictions") 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.Items.Components.ItemContainer'], 'slotRestrictions')
LuaUserData.MakeFieldAccessible(Descriptors['Barotrauma.ItemInventory'], 'slots') LuaUserData.MakeFieldAccessible(Descriptors['Barotrauma.ItemInventory'], 'slots')
LuaUserData.MakeFieldAccessible(Descriptors["Barotrauma.CharacterInventory"], "slots") LuaUserData.MakeFieldAccessible(Descriptors["Barotrauma.CharacterInventory"], "slots")
-- Simple configuration -- Simple configuration
local HAND_SLOTS = { 6, 7 } local CONFIG = {
local PRIORITY_CONTAINERS = { "toolbelt", "backpack", "pouch" } -- Identifiers for priority containers 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 -- Helper function to move an item to a container, but only if matching items exist
local function moveItemToContainer(item, containerInv) local function moveItemToContainer(item, containerInv)
if not item or not containerInv then return false end 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 -- Only try to find matching items to stack with
local foundMatchingItem = false local foundMatchingItem = false
@@ -25,7 +60,7 @@ local function moveItemToContainer(item, containerInv)
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 foundMatchingItem = true
print("[QuickStack] Found matching item in container") debugPrint("Found matching item in container: " .. containerItem.Name)
break break
end end
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 no matching items exist in the container, don't move the item
if not foundMatchingItem then if not foundMatchingItem then
print("[QuickStack] No matching items in container, skipping") debugPrint("No matching items in container, skipping " .. item.Name)
return false return false
end end
@@ -43,16 +78,19 @@ local function moveItemToContainer(item, containerInv)
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
-- Try to stack with existing item -- 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 if containerInv.TryPutItem(item, slotIndex, true, false, nil) then
debugPrint("Successfully stacked " .. item.Name)
return true return true
else
debugPrint("Failed to stack " .. item.Name .. " - TryPutItem failed")
end end
end end
end end
end end
-- We don't try to place in empty slots anymore, only stack with existing items -- 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 return false
end end
@@ -63,7 +101,7 @@ local function sortContainersByPriority(containers)
local bPriority = -1 local bPriority = -1
-- Check priority for first container -- 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 if a.Prefab.Identifier.Value:find(identifier) then
aPriority = i aPriority = i
break break
@@ -71,7 +109,7 @@ local function sortContainersByPriority(containers)
end end
-- Check priority for second container -- 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 if b.Prefab.Identifier.Value:find(identifier) then
bPriority = i bPriority = i
break break
@@ -94,41 +132,112 @@ local function findAllContainers(inventory, containers)
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 -- 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) table.insert(containers, item)
-- Recursively search inside this container -- Recursively search inside this container if enabled
if CONFIG.NESTED_CONTAINERS then
debugPrint("Searching inside " .. item.Name .. " for nested containers")
findAllContainers(item.OwnInventory, containers) findAllContainers(item.OwnInventory, containers)
end end
end end
end end
end
return containers return containers
end end
-- Find the currently open container using the better approach with opened GUIs -- Find the currently open container
local function getOpenContainer() local function getOpenContainer()
-- Check if any ItemContainer GUIs are open debugPrint("Attempting to find open container...")
for _, gui in pairs(GUI.OpenGuis) do
if gui.UserData ~= nil and gui.UserData.Inventory ~= nil then -- Method 1: Check if Inventory.OpenState is accessible and has an open container
-- Make sure it's not the player's inventory pcall(function()
if gui.UserData.Item ~= nil and gui.UserData.Item.Inventory ~= Character.Controlled.Inventory then if Character.Controlled and Character.Controlled.SelectedCharacter then
print("[QuickStack] Found open container: " .. gui.UserData.Item.Name) local selectedChar = Character.Controlled.SelectedCharacter
return gui.UserData.Item 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 end
end end
-- Try an alternative approach using opened inventories debugPrint("No open container found")
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")
return nil return nil
end end
@@ -136,7 +245,7 @@ end
local function stackFromOpenContainer(character, playerContainers, openContainer) local function stackFromOpenContainer(character, playerContainers, openContainer)
if not character or not openContainer or not openContainer.OwnInventory then return 0 end 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 itemsMoved = 0
local openContainerInv = openContainer.OwnInventory local openContainerInv = openContainer.OwnInventory
@@ -150,12 +259,18 @@ local function stackFromOpenContainer(character, playerContainers, openContainer
local item = slot.items[i] local item = slot.items[i]
-- Skip container items -- 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 -- Try to move the item to each player container
for _, container in ipairs(playerContainers) do for _, container in ipairs(playerContainers) do
debugPrint("Trying to stack " .. item.Name .. " into " .. container.Name)
if moveItemToContainer(item, container.OwnInventory) then 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 itemsMoved = itemsMoved + 1
break break
end end
@@ -170,23 +285,34 @@ end
-- Function to quickly stack items from inventory to containers -- Function to quickly stack items from inventory to containers
local function quickStackItems(character) local function quickStackItems(character)
if not character then return end if not character then
print("[QuickStack] Function called") debugPrint("No character found")
return
end
debugPrint("Quick stack function called")
local inventory = character.Inventory 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 -- Find all containers in player inventory, including nested ones
local containers = findAllContainers(inventory, {}) 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 if #containers == 0 then
print("[QuickStack] No containers with inventory found!") debugPrint("No containers with inventory found!")
return return
end end
-- Sort containers by priority -- Sort containers by priority
containers = sortContainersByPriority(containers) 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 local itemsMoved = 0
@@ -194,25 +320,34 @@ local function quickStackItems(character)
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
for _, handSlot in ipairs(HAND_SLOTS) do for _, handSlot in ipairs(CONFIG.HAND_SLOTS) do
if slotIndex == handSlot then if slotIndex == handSlot then
isHandSlot = true isHandSlot = true
break break
end end
end end
if isHandSlot then goto continueSlot end if isHandSlot then
debugPrint("Skipping hand slot: " .. slotIndex)
goto continueSlot
end
-- 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]
-- Skip container items -- 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 -- Try to move the item to each container
for _, container in ipairs(containers) do for _, container in ipairs(containers) do
debugPrint("Trying container: " .. container.Name)
if moveItemToContainer(item, container.OwnInventory) then if moveItemToContainer(item, container.OwnInventory) then
print("[QuickStack] Stacked " .. item.Name .. " into " .. container.Name) debugPrint("Stacked " .. item.Name .. " into " .. container.Name)
itemsMoved = itemsMoved + 1 itemsMoved = itemsMoved + 1
break break
end end
@@ -227,20 +362,35 @@ local function quickStackItems(character)
-- 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
debugPrint("Found open container to stack from: " .. openContainer.Name)
local openContainerItemsMoved = stackFromOpenContainer(character, containers, openContainer) local openContainerItemsMoved = stackFromOpenContainer(character, containers, openContainer)
itemsMoved = itemsMoved + openContainerItemsMoved itemsMoved = itemsMoved + openContainerItemsMoved
else
debugPrint("No open container found to stack from")
end end
if itemsMoved > 0 then 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 else
print("[QuickStack] 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(Keys.F) then return end if not PlayerInput.KeyHit(CONFIG.TRIGGER_KEY) then return end
local character = instance local character = instance
if not character then return end if not character then return end