Simplify stacker

To hopefully not die
This commit is contained in:
2025-03-29 19:33:12 +01:00
parent 7115a9fe36
commit 82ec45b855

View File

@@ -8,236 +8,162 @@ LuaUserData.MakeFieldAccessible(Descriptors['Barotrauma.Items.Components.ItemCon
LuaUserData.MakeFieldAccessible(Descriptors['Barotrauma.ItemInventory'], 'slots') LuaUserData.MakeFieldAccessible(Descriptors['Barotrauma.ItemInventory'], 'slots')
LuaUserData.MakeFieldAccessible(Descriptors["Barotrauma.CharacterInventory"], "slots") LuaUserData.MakeFieldAccessible(Descriptors["Barotrauma.CharacterInventory"], "slots")
-- Configuration -- Simple configuration
local CONFIG = { local HAND_SLOTS = { 6, 7 }
TRIGGER_KEY = Keys.F, -- Key to press for quick stacking local PRIORITY_CONTAINERS = { "toolbelt", "backpack", "pouch" } -- Identifiers for priority containers
BAG_TAGS = { "container", "cargocontainer" }, -- Tags that identify bags/containers
MAX_ITEMS_TO_PROCESS = 100, -- Safety limit to prevent infinite loops
PREFER_EXISTING_STACKS = true, -- Prefer stacking into existing item stacks
CHECK_ALL_CONTAINERS = true, -- Check all containers in inventory, not just bag slot
PRIMARY_BAG_SLOT = 8, -- Slot number for the primary bag (typically slot 8)
SKIP_HAND_SLOTS = true, -- Skip hand slots when processing items
HAND_SLOTS = { 6, 7 }, -- Slot numbers for hands (typically slots 6 and 7)
SKIP_DIVING_GEAR = true, -- Skip diving gear when processing items
DIVING_GEAR_TAGS = { "divingsuit", "divingmask", "oxygensource" } -- Tags for diving gear
}
-- Function to check if an item is a bag/container -- Helper function to move an item to a container, but only if matching items exist
local function isContainer(item) local function moveItemToContainer(item, containerInv)
if not item then return false end if not item or not containerInv then return false end
for _, tag in ipairs(CONFIG.BAG_TAGS) do print("[QuickStack] Attempting to stack with existing items in container (" .. #containerInv.slots .. " slots)")
if item.HasTag(tag) then return true end
-- Only try to find matching items to stack with
local foundMatchingItem = false
-- Check if the container has any matching items first
for slotIndex = 0, #containerInv.slots - 1 do
for _, containerItem in ipairs(containerInv.slots[slotIndex + 1].items) do
if containerItem.Prefab.Identifier.Equals(item.Prefab.Identifier) then
foundMatchingItem = true
print("[QuickStack] Found matching item in container")
break
end
end
if foundMatchingItem then break end
end end
-- 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")
return false
end
-- Try to stack with existing items
for slotIndex = 0, #containerInv.slots - 1 do
for _, containerItem in ipairs(containerInv.slots[slotIndex + 1].items) do
if containerItem.Prefab.Identifier.Equals(item.Prefab.Identifier) then
-- Try to stack with existing item
print("[QuickStack] Stacking with existing item")
if containerInv.TryPutItem(item, slotIndex, true, false, nil) then
return true
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")
return false return false
end end
-- Function to check if an item is diving gear -- Sort containers by priority
local function isDivingGear(item) local function sortContainersByPriority(containers)
if not CONFIG.SKIP_DIVING_GEAR or not item then return false end table.sort(containers, function(a, b)
local aPriority = -1
local bPriority = -1
for _, tag in ipairs(CONFIG.DIVING_GEAR_TAGS) do -- Check priority for first container
if item.HasTag(tag) then return true end for i, identifier in ipairs(PRIORITY_CONTAINERS) do
end if a.Prefab.Identifier.Value:find(identifier) then
return false aPriority = i
break
end
end
-- Check priority for second container
for i, identifier in ipairs(PRIORITY_CONTAINERS) do
if b.Prefab.Identifier.Value:find(identifier) then
bPriority = i
break
end
end
return aPriority < bPriority
end)
return containers
end end
-- Function to find all containers in inventory -- Function to quickly stack items from inventory to containers
local function findContainersInInventory(character) local function quickStackItems(character)
local containers = {} if not character then return end
print("[QuickStack] 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 return containers end -- First identify all containers in inventory
local containers = {}
-- First add the primary bag if available (priority container) for slotIndex, slot in ipairs(inventory.slots) do
if #inventory.slots >= CONFIG.PRIMARY_BAG_SLOT then for _, item in ipairs(slot.items) do
for _, item in ipairs(inventory.slots[CONFIG.PRIMARY_BAG_SLOT].items) do -- Add to containers if it has its own inventory
if isContainer(item) and item.OwnInventory then if item.OwnInventory then
print("[QuickStack] Found container: " .. item.Name .. " (" .. item.Prefab.Identifier.Value .. ")")
table.insert(containers, item) table.insert(containers, item)
end end
end end
end end
-- Add all other containers if configured to do so print("[QuickStack] Found " .. #containers .. " containers")
if CONFIG.CHECK_ALL_CONTAINERS then if #containers == 0 then
for slotIndex, slot in ipairs(inventory.slots) do print("[QuickStack] No containers with inventory found!")
-- Skip the primary bag slot as we already processed it return
if slotIndex == CONFIG.PRIMARY_BAG_SLOT then goto continueSlot end
-- Skip hand slots if configured to do so
if CONFIG.SKIP_HAND_SLOTS then
local isHandSlot = false
for _, handSlot in ipairs(CONFIG.HAND_SLOTS) do
if slotIndex == handSlot then
isHandSlot = true
break
end
end
if isHandSlot then goto continueSlot end
end
for _, item in ipairs(slot.items) do
if isContainer(item) and item.OwnInventory and not isDivingGear(item) then
table.insert(containers, item)
end
end
::continueSlot::
end
end end
return containers -- Sort containers by priority
end containers = sortContainersByPriority(containers)
-- Function to check if an item can be stacked with another local itemsMoved = 0
local function canStackWith(targetItem, sourceItem)
if not targetItem or not sourceItem then return false end
-- Check if items have same identifier -- Process inventory slots
if not targetItem.Prefab.Identifier.Equals(sourceItem.Prefab.Identifier) then return false end for slotIndex, slot in ipairs(inventory.slots) do
-- Skip hand slots
-- Additional stacking checks could be added here local isHandSlot = false
return true for _, handSlot in ipairs(HAND_SLOTS) do
end
-- Function to try stacking an item into a specific slot in container
local function tryStackItemInSlot(container, sourceItem, slotIndex)
if not container or not sourceItem then return false end
local slot = container.slots[slotIndex + 1] -- +1 because Lua is 1-indexed but slots are 0-indexed
-- Check if slot exists
if not slot then return false end
-- Try to find an existing stack of the same type
for _, targetItem in ipairs(slot.items) do
if canStackWith(targetItem, sourceItem) then
return container.TryPutItem(sourceItem, slotIndex, true, false, nil)
end
end
-- If no existing stack and slot has space, try to put item there
if container.CanBePutInSlot(sourceItem, slotIndex) then
return container.TryPutItem(sourceItem, slotIndex, false, false, nil)
end
return false
end
-- Function to process a single inventory slot
local function processInventorySlot(playerInv, slotIndex, containers, processedCount, stackedCount)
-- Check if this slot should be skipped (hand slots)
if CONFIG.SKIP_HAND_SLOTS then
for _, handSlot in ipairs(CONFIG.HAND_SLOTS) do
if slotIndex == handSlot then if slotIndex == handSlot then
return processedCount, stackedCount isHandSlot = true
break
end end
end end
end if isHandSlot then goto continueSlot end
local slot = playerInv.slots[slotIndex] -- Process items in the slot
if not slot then return processedCount, stackedCount end for i = #slot.items, 1, -1 do
local item = slot.items[i]
-- Process items in the slot -- Skip container items
for i = #slot.items, 1, -1 do -- Iterate backwards to safely remove if item.OwnInventory then goto nextItem end
local item = slot.items[i]
local success = false
-- Skip containers themselves -- Try to move the item to each container
if isContainer(item) then goto nextItem end for _, container in ipairs(containers) do
if moveItemToContainer(item, container.OwnInventory) then
-- Skip diving gear if configured to do so print("[QuickStack] Stacked " .. item.Name .. " into " .. container.Name)
if isDivingGear(item) then goto nextItem end itemsMoved = itemsMoved + 1
break
processedCount = processedCount + 1
if processedCount > CONFIG.MAX_ITEMS_TO_PROCESS then
print("QuickStack: Safety limit reached")
return processedCount, stackedCount
end
-- Try each container in order
for _, container in ipairs(containers) do
local containerInv = container.OwnInventory
if not containerInv then goto nextContainer end
-- First try to stack with existing stacks if configured to do so
if CONFIG.PREFER_EXISTING_STACKS then
for bagSlotIndex = 0, #containerInv.slots - 1 do
for _, containerItem in ipairs(containerInv.slots[bagSlotIndex + 1].items) do
if canStackWith(containerItem, item) then
success = tryStackItemInSlot(containerInv, item, bagSlotIndex)
if success then break end
end
end
if success then break end
end end
end end
-- If not stacked yet, try any valid slot ::nextItem::
if not success then
for bagSlotIndex = 0, #containerInv.slots - 1 do
success = tryStackItemInSlot(containerInv, item, bagSlotIndex)
if success then break end
end
end
if success then
stackedCount = stackedCount + 1
break -- Stop trying containers if we succeeded
end
::nextContainer::
end end
::nextItem:: ::continueSlot::
end end
return processedCount, stackedCount if itemsMoved > 0 then
end print("[QuickStack] Stacked " .. itemsMoved .. " items into containers")
else
-- Function to quick stack items into containers print("[QuickStack] No matching items to stack")
local function quickStackToContainers(character, containers)
if not character or #containers == 0 then return 0 end
local playerInv = character.Inventory
local processedCount = 0
local stackedCount = 0
-- Process each inventory slot
for slotIndex = 1, #playerInv.slots do
processedCount, stackedCount = processInventorySlot(
playerInv,
slotIndex,
containers,
processedCount,
stackedCount
)
end end
return stackedCount
end end
-- Hook into the 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(Keys.F) then return end
local character = instance local character = instance
if not character then return end if not character then return end
-- Find all containers in inventory quickStackItems(character)
local containers = findContainersInInventory(character)
if #containers == 0 then
Game.ShowChatMessage("No containers found in inventory", ChatMessageType.Server)
return
end
-- Perform quick stacking
local stackedCount = quickStackToContainers(character, containers)
-- Notify player
if stackedCount and stackedCount > 0 then
Game.ShowChatMessage("Quick stacked " .. stackedCount .. " items to containers", ChatMessageType.Server)
else
Game.ShowChatMessage("No items could be stacked to containers", ChatMessageType.Server)
end
end, Hook.HookMethodType.After) end, Hook.HookMethodType.After)