Simplify stacker
To hopefully not die
This commit is contained in:
@@ -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
|
||||||
|
end
|
||||||
|
if foundMatchingItem then break 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
|
||||||
|
if a.Prefab.Identifier.Value:find(identifier) then
|
||||||
|
aPriority = i
|
||||||
|
break
|
||||||
end
|
end
|
||||||
return false
|
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
|
end
|
||||||
|
|
||||||
-- Skip hand slots if configured to do so
|
-- Sort containers by priority
|
||||||
if CONFIG.SKIP_HAND_SLOTS then
|
containers = sortContainersByPriority(containers)
|
||||||
|
|
||||||
|
local itemsMoved = 0
|
||||||
|
|
||||||
|
-- Process inventory slots
|
||||||
|
for slotIndex, slot in ipairs(inventory.slots) do
|
||||||
|
-- Skip hand slots
|
||||||
local isHandSlot = false
|
local isHandSlot = false
|
||||||
for _, handSlot in ipairs(CONFIG.HAND_SLOTS) do
|
for _, handSlot in ipairs(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 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
|
|
||||||
|
|
||||||
return containers
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Function to check if an item can be stacked with another
|
|
||||||
local function canStackWith(targetItem, sourceItem)
|
|
||||||
if not targetItem or not sourceItem then return false end
|
|
||||||
|
|
||||||
-- Check if items have same identifier
|
|
||||||
if not targetItem.Prefab.Identifier.Equals(sourceItem.Prefab.Identifier) then return false end
|
|
||||||
|
|
||||||
-- Additional stacking checks could be added here
|
|
||||||
return true
|
|
||||||
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
|
|
||||||
return processedCount, stackedCount
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
local slot = playerInv.slots[slotIndex]
|
|
||||||
if not slot then return processedCount, stackedCount end
|
|
||||||
|
|
||||||
-- Process items in the slot
|
-- Process items in the slot
|
||||||
for i = #slot.items, 1, -1 do -- Iterate backwards to safely remove
|
for i = #slot.items, 1, -1 do
|
||||||
local item = slot.items[i]
|
local item = slot.items[i]
|
||||||
local success = false
|
|
||||||
|
|
||||||
-- Skip containers themselves
|
-- Skip container items
|
||||||
if isContainer(item) then goto nextItem end
|
if item.OwnInventory then goto nextItem end
|
||||||
|
|
||||||
-- Skip diving gear if configured to do so
|
-- Try to move the item to each container
|
||||||
if isDivingGear(item) then goto nextItem end
|
|
||||||
|
|
||||||
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
|
for _, container in ipairs(containers) do
|
||||||
local containerInv = container.OwnInventory
|
if moveItemToContainer(item, container.OwnInventory) then
|
||||||
if not containerInv then goto nextContainer end
|
print("[QuickStack] Stacked " .. item.Name .. " into " .. container.Name)
|
||||||
|
itemsMoved = itemsMoved + 1
|
||||||
-- First try to stack with existing stacks if configured to do so
|
break
|
||||||
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
|
||||||
end
|
end
|
||||||
if success then break end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
-- If not stacked yet, try any valid slot
|
|
||||||
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
|
|
||||||
|
|
||||||
::nextItem::
|
::nextItem::
|
||||||
end
|
end
|
||||||
|
|
||||||
return processedCount, stackedCount
|
::continueSlot::
|
||||||
end
|
|
||||||
|
|
||||||
-- Function to quick stack items into containers
|
|
||||||
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
|
if itemsMoved > 0 then
|
||||||
|
print("[QuickStack] Stacked " .. itemsMoved .. " items into containers")
|
||||||
|
else
|
||||||
|
print("[QuickStack] No matching items to stack")
|
||||||
|
end
|
||||||
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)
|
||||||
|
|||||||
Reference in New Issue
Block a user