Compare commits
8 Commits
Author | SHA1 | Date | |
---|---|---|---|
355bfe4df6 | |||
a9490c039e | |||
88187358e8 | |||
bb7dc1da32 | |||
21eda6a5ac | |||
50d84f5ba5 | |||
856dc8b305 | |||
91b8576385 |
23
CykaQuick/.vscode/settings.json
vendored
Normal file
23
CykaQuick/.vscode/settings.json
vendored
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
{
|
||||||
|
"highlight.regex.workspace.regexes": [
|
||||||
|
{
|
||||||
|
"name": "namedGroups",
|
||||||
|
"regexes": [
|
||||||
|
{
|
||||||
|
"regex": "(?:(\\?<[^>]+>)[^)]+)",
|
||||||
|
"decorations": [
|
||||||
|
{
|
||||||
|
"backgroundColor": "#000000",
|
||||||
|
"color": "#1CAFC4"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"Lua.diagnostics.libraryFiles": "Enable",
|
||||||
|
"Lua.workspace.library": [
|
||||||
|
"../Meta/Types/client",
|
||||||
|
"../Meta/Types/shared"
|
||||||
|
],
|
||||||
|
}
|
@@ -7,7 +7,6 @@ if SERVER then
|
|||||||
require("Cyka.xpticker")
|
require("Cyka.xpticker")
|
||||||
else
|
else
|
||||||
---@class MyModGlobal
|
---@class MyModGlobal
|
||||||
---@field CONFIG {QUICKSTACK_KEYS: Keys, FABRICATOR_KEY: Keys, MAX_BUY: Keys, NESTED_CONTAINERS: boolean, DEBUG_MODE: boolean}
|
|
||||||
---@field MOD_NAME string
|
---@field MOD_NAME string
|
||||||
---@field MOD_VERSION string
|
---@field MOD_VERSION string
|
||||||
---@field DumpTable fun(table: table, depth?: number)
|
---@field DumpTable fun(table: table, depth?: number)
|
||||||
|
@@ -4,7 +4,7 @@ if not CLIENT then return end
|
|||||||
local dump = require("Cyka.dump")
|
local dump = require("Cyka.dump")
|
||||||
local quickstack = require("Cyka.quickstack")
|
local quickstack = require("Cyka.quickstack")
|
||||||
|
|
||||||
---@class ItemLocation
|
---@class ItemLocationDistance
|
||||||
---@field item Barotrauma.Item
|
---@field item Barotrauma.Item
|
||||||
---@field distance number
|
---@field distance number
|
||||||
|
|
||||||
|
@@ -60,7 +60,7 @@ local function tryStackCursorItem()
|
|||||||
end
|
end
|
||||||
itemTree = quickstack.sortItemTree(itemTree)
|
itemTree = quickstack.sortItemTree(itemTree)
|
||||||
|
|
||||||
local itemsToMove = {}
|
local options = {}
|
||||||
local now = Timer.GetTime()
|
local now = Timer.GetTime()
|
||||||
for _, slot in ipairs(slots) do
|
for _, slot in ipairs(slots) do
|
||||||
local runAfter = slotThrottle[slot] or 0
|
local runAfter = slotThrottle[slot] or 0
|
||||||
@@ -68,7 +68,7 @@ local function tryStackCursorItem()
|
|||||||
goto continue
|
goto continue
|
||||||
end
|
end
|
||||||
-- MyModGlobal.debugPrint(string.format("Enqueuing slot: %s, before: %d", tostring(slot), #itemsToMove))
|
-- MyModGlobal.debugPrint(string.format("Enqueuing slot: %s, before: %d", tostring(slot), #itemsToMove))
|
||||||
utils.enqueueSlot(slot.slot, itemsToMove)
|
options = utils.enqueueSlot(slot.inventory.slots[slot.slotIndex1], options)
|
||||||
-- MyModGlobal.debugPrint(string.format("Enqueuing slot: %s, after: %d", tostring(slot), #itemsToMove))
|
-- MyModGlobal.debugPrint(string.format("Enqueuing slot: %s, after: %d", tostring(slot), #itemsToMove))
|
||||||
slotThrottle[slot] = now + 1
|
slotThrottle[slot] = now + 1
|
||||||
::continue::
|
::continue::
|
||||||
@@ -79,7 +79,7 @@ local function tryStackCursorItem()
|
|||||||
-- -- MyModGlobal.debugPrint(string.format("Enqueued %d items from the inventory slot", #itemsToMove))
|
-- -- MyModGlobal.debugPrint(string.format("Enqueued %d items from the inventory slot", #itemsToMove))
|
||||||
-- MyModGlobal.DumpTable(itemTree)
|
-- MyModGlobal.DumpTable(itemTree)
|
||||||
|
|
||||||
quickstack.tryMoveItems(itemsToMove, itemTree, true)
|
quickstack.tryMoveItems(options.itemQueue, itemTree, true)
|
||||||
-- local errors = quickstack.tryMoveItems(itemsToMove, itemTree, true)
|
-- local errors = quickstack.tryMoveItems(itemsToMove, itemTree, true)
|
||||||
-- for _, error in ipairs(errors) do
|
-- for _, error in ipairs(errors) do
|
||||||
-- MyModGlobal.debugPrint(string.format("Error moving item: %s", error))
|
-- MyModGlobal.debugPrint(string.format("Error moving item: %s", error))
|
||||||
@@ -101,14 +101,7 @@ local function setTargetInventory()
|
|||||||
-- If we get multiple we'll use the first valid one
|
-- If we get multiple we'll use the first valid one
|
||||||
-- Although everything is valid to us...
|
-- Although everything is valid to us...
|
||||||
for _, slot in ipairs(slots) do
|
for _, slot in ipairs(slots) do
|
||||||
local item
|
local item = slot.item
|
||||||
local items = slot.slot.items
|
|
||||||
if not items or #items == 0 then
|
|
||||||
print(string.format("Slot is empty, setting target inventory to %s", tostring(slot.inventory)))
|
|
||||||
targetInventory = slot.inventory
|
|
||||||
goto continue
|
|
||||||
end
|
|
||||||
item = items[1]
|
|
||||||
if not item then
|
if not item then
|
||||||
print(string.format("Item in slot is nil, setting target inventory to %s", tostring(slot.inventory)))
|
print(string.format("Item in slot is nil, setting target inventory to %s", tostring(slot.inventory)))
|
||||||
targetInventory = slot.inventory
|
targetInventory = slot.inventory
|
||||||
|
@@ -3,7 +3,7 @@ if not CLIENT then return end
|
|||||||
local utils = require("Cyka.utils")
|
local utils = require("Cyka.utils")
|
||||||
local dump = require("Cyka.dump")
|
local dump = require("Cyka.dump")
|
||||||
|
|
||||||
---@return {item: Barotrauma.Item, fabricator: Barotrauma.FabricatorComponent}, string?
|
---@return {item: Barotrauma.Item, fabricator: Barotrauma.Items.Components.Fabricator}?, string?
|
||||||
local function getOpenFabricator()
|
local function getOpenFabricator()
|
||||||
-- Get the controlled character
|
-- Get the controlled character
|
||||||
local controlledCharacter = Character.Controlled
|
local controlledCharacter = Character.Controlled
|
||||||
@@ -29,8 +29,8 @@ end
|
|||||||
---@field targetItem {identifier: string, name: string, amount: number}
|
---@field targetItem {identifier: string, name: string, amount: number}
|
||||||
---@field requiredItems {amount: number, minCondition: number, maxCondition: number, prefabs: string[]}[]
|
---@field requiredItems {amount: number, minCondition: number, maxCondition: number, prefabs: string[]}[]
|
||||||
|
|
||||||
---@param fabricator Barotrauma.FabricatorComponent
|
---@param fabricator Barotrauma.Items.Components.Fabricator
|
||||||
---@return RecipeInfo, string?
|
---@return RecipeInfo?, string?
|
||||||
local function getSelectedRecipeRequirements(fabricator)
|
local function getSelectedRecipeRequirements(fabricator)
|
||||||
-- local openFabricator, err = getOpenFabricator()
|
-- local openFabricator, err = getOpenFabricator()
|
||||||
-- if err then return nil, err end
|
-- if err then return nil, err end
|
||||||
@@ -73,7 +73,7 @@ local function tryStackFabricator(character)
|
|||||||
MyModGlobal.debugPrint("Character inventory is nil.")
|
MyModGlobal.debugPrint("Character inventory is nil.")
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
---@type Barotrauma.ItemInventory.Slot
|
---@type Barotrauma.Inventory.ItemSlot
|
||||||
local bagSlot = inventory.slots[MyModGlobal.BAG_SLOT]
|
local bagSlot = inventory.slots[MyModGlobal.BAG_SLOT]
|
||||||
if not bagSlot then
|
if not bagSlot then
|
||||||
MyModGlobal.debugPrint("Bag slot not found.")
|
MyModGlobal.debugPrint("Bag slot not found.")
|
||||||
@@ -91,14 +91,14 @@ local function tryStackFabricator(character)
|
|||||||
end
|
end
|
||||||
|
|
||||||
local fabricator, err = getOpenFabricator()
|
local fabricator, err = getOpenFabricator()
|
||||||
if err then
|
if err or not fabricator then
|
||||||
print(string.format("Error getting open fabricator: %s", err))
|
print(string.format("Error getting open fabricator: %s", err))
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
local recipe
|
local recipe
|
||||||
recipe, err = getSelectedRecipeRequirements(fabricator.fabricator)
|
recipe, err = getSelectedRecipeRequirements(fabricator.fabricator)
|
||||||
if err then
|
if err or not recipe then
|
||||||
print(string.format("Error getting selected recipe requirements: %s", err))
|
print(string.format("Error getting selected recipe requirements: %s", err))
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
@@ -147,7 +147,10 @@ local function tryStackFabricator(character)
|
|||||||
-- dump(itemsOnSubmarine)
|
-- dump(itemsOnSubmarine)
|
||||||
-- MyModGlobal.DumpTable(toGet)
|
-- MyModGlobal.DumpTable(toGet)
|
||||||
|
|
||||||
local items, _ = utils.enqueueAllOwnedItems({}, filter)
|
local items, _ = utils.enqueueAllOwnedItems({
|
||||||
|
recurse = true,
|
||||||
|
itemPredicate = filter
|
||||||
|
})
|
||||||
-- if err then
|
-- if err then
|
||||||
-- print(string.format("Error enqueueing all owned items: %s", err))
|
-- print(string.format("Error enqueueing all owned items: %s", err))
|
||||||
-- return
|
-- return
|
||||||
|
@@ -4,12 +4,12 @@ if not CLIENT then return end
|
|||||||
---@return Barotrauma.Location.StoreInfo[], string?
|
---@return Barotrauma.Location.StoreInfo[], string?
|
||||||
local function getCurrentStore()
|
local function getCurrentStore()
|
||||||
if not Game or not Game.GameSession or not Game.GameSession.Campaign then
|
if not Game or not Game.GameSession or not Game.GameSession.Campaign then
|
||||||
return nil, "No game session found"
|
return {}, "No game session found"
|
||||||
end
|
end
|
||||||
|
|
||||||
local map = Game.GameSession.Campaign.Map
|
local map = Game.GameSession.Campaign.Map
|
||||||
if not map or not map.CurrentLocation or not map.CurrentLocation.Stores then
|
if not map or not map.CurrentLocation or not map.CurrentLocation.Stores then
|
||||||
return nil, "No map found"
|
return {}, "No map found"
|
||||||
end
|
end
|
||||||
|
|
||||||
local location = map.CurrentLocation
|
local location = map.CurrentLocation
|
||||||
@@ -17,13 +17,13 @@ local function getCurrentStore()
|
|||||||
-- Otherwise, determine which store is active by checking the cargo manager
|
-- Otherwise, determine which store is active by checking the cargo manager
|
||||||
local cargoManager = Game.GameSession.Campaign.CargoManager
|
local cargoManager = Game.GameSession.Campaign.CargoManager
|
||||||
if not cargoManager then
|
if not cargoManager then
|
||||||
return nil, "No cargo manager found"
|
return {}, "No cargo manager found"
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Find which store has items in the cart
|
-- Find which store has items in the cart
|
||||||
local stores = {}
|
local stores = {}
|
||||||
for _, store in pairs(location.Stores) do
|
for _, store in pairs(location.Stores) do
|
||||||
if #cargoManager:GetBuyCrateItems(store) > 0 then
|
if #cargoManager:GetBuyCrateItems() > 0 then
|
||||||
stores[#stores + 1] = store
|
stores[#stores + 1] = store
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -47,7 +47,7 @@ local function tryBuy()
|
|||||||
for _, store in ipairs(stores) do
|
for _, store in ipairs(stores) do
|
||||||
local toAdd = {}
|
local toAdd = {}
|
||||||
-- Get items available at the store
|
-- Get items available at the store
|
||||||
local items = cargoManager:GetBuyCrateItems(store)
|
local items = cargoManager:GetBuyCrateItems()
|
||||||
for item in items do
|
for item in items do
|
||||||
-- We have already added this many of item
|
-- We have already added this many of item
|
||||||
toAdd[item.ItemPrefab.Identifier.Value] = {
|
toAdd[item.ItemPrefab.Identifier.Value] = {
|
||||||
@@ -55,6 +55,7 @@ local function tryBuy()
|
|||||||
prefab = item.ItemPrefab -- Store the ItemPrefab object
|
prefab = item.ItemPrefab -- Store the ItemPrefab object
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
---@diagnostic disable-next-line: undefined-field
|
||||||
for item in store.Stock do
|
for item in store.Stock do
|
||||||
-- So if we add the total amount available
|
-- So if we add the total amount available
|
||||||
-- We get the amount we have to add to buy entire stock
|
-- We get the amount we have to add to buy entire stock
|
||||||
@@ -68,6 +69,7 @@ local function tryBuy()
|
|||||||
if info.quantity > 0 then
|
if info.quantity > 0 then
|
||||||
MyModGlobal.debugPrint(string.format("Adding %d of %s to the buy crate", info.quantity, idValue))
|
MyModGlobal.debugPrint(string.format("Adding %d of %s to the buy crate", info.quantity, idValue))
|
||||||
-- Use the stored ItemPrefab object, not the string identifier
|
-- Use the stored ItemPrefab object, not the string identifier
|
||||||
|
---@diagnostic disable-next-line: undefined-field
|
||||||
cargoManager:ModifyItemQuantityInBuyCrate(store.Identifier, info.prefab, info.quantity)
|
cargoManager:ModifyItemQuantityInBuyCrate(store.Identifier, info.prefab, info.quantity)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@@ -16,14 +16,13 @@ local LOAD_MAP = require("Cyka.quickreload_loadmap")
|
|||||||
---@param inventory Barotrauma.ItemInventory
|
---@param inventory Barotrauma.ItemInventory
|
||||||
---@return InventorySlot[]
|
---@return InventorySlot[]
|
||||||
local function getSlots(inventory)
|
local function getSlots(inventory)
|
||||||
|
---@type InventorySlot[]
|
||||||
local slots = {}
|
local slots = {}
|
||||||
|
---@type Barotrauma.Inventory.ItemSlot[]
|
||||||
local inventorySlots = inventory.slots
|
local inventorySlots = inventory.slots
|
||||||
for i, inventorySlot in ipairs(inventorySlots) do
|
for i, _ in ipairs(inventorySlots) do
|
||||||
slots[#slots + 1] = {
|
local invSlot = MyModGlobal.InventorySlot.new(inventory, i)
|
||||||
inventory = inventory,
|
slots[#slots + 1] = invSlot
|
||||||
slotIndex = i - 1,
|
|
||||||
slot = inventorySlot
|
|
||||||
}
|
|
||||||
end
|
end
|
||||||
return slots
|
return slots
|
||||||
end
|
end
|
||||||
@@ -36,7 +35,11 @@ local function getItemsPerSlot(slots)
|
|||||||
---@type table<InventorySlot, Barotrauma.Item[]>
|
---@type table<InventorySlot, Barotrauma.Item[]>
|
||||||
local movableBySlot = {}
|
local movableBySlot = {}
|
||||||
-- Get all the items and then we will sort them by condition and shit
|
-- Get all the items and then we will sort them by condition and shit
|
||||||
utils.enqueueAllPlayerItems({}, function(ititem, itemRef)
|
utils.enqueuePlayerItems({
|
||||||
|
recurse = true,
|
||||||
|
loadRefs = true,
|
||||||
|
itemPredicate = function(ititem, itemRef)
|
||||||
|
MyModGlobal.debugPrint(string.format("Checking item: %s", tostring(ititem)))
|
||||||
-- We don't want to take oxygen out of our diving suit to load our plasma cutter
|
-- We don't want to take oxygen out of our diving suit to load our plasma cutter
|
||||||
-- Most loadable items have 1 capacity
|
-- Most loadable items have 1 capacity
|
||||||
-- But some have 2 or 3 (coil speargun)
|
-- But some have 2 or 3 (coil speargun)
|
||||||
@@ -48,7 +51,7 @@ local function getItemsPerSlot(slots)
|
|||||||
-- dump(slots)
|
-- dump(slots)
|
||||||
-- MyModGlobal.debugPrint(ititem.Prefab.Identifier.Value)
|
-- MyModGlobal.debugPrint(ititem.Prefab.Identifier.Value)
|
||||||
for _, inventorySlot in ipairs(slots) do
|
for _, inventorySlot in ipairs(slots) do
|
||||||
local canMove = inventorySlot.inventory.CanBePutInSlot(ititem, inventorySlot.slotIndex)
|
local canMove = inventorySlot.inventory.CanBePutInSlot(ititem, inventorySlot.slotIndex1 - 1)
|
||||||
-- MyModGlobal.debugPrint(string.format("Can move to slot %d: %s", inventorySlot.slotIndex, tostring(canMove)))
|
-- MyModGlobal.debugPrint(string.format("Can move to slot %d: %s", inventorySlot.slotIndex, tostring(canMove)))
|
||||||
if canMove then
|
if canMove then
|
||||||
movableBySlot[inventorySlot] = movableBySlot[inventorySlot] or {}
|
movableBySlot[inventorySlot] = movableBySlot[inventorySlot] or {}
|
||||||
@@ -57,7 +60,8 @@ local function getItemsPerSlot(slots)
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
return false
|
return false
|
||||||
end, true)
|
end
|
||||||
|
})
|
||||||
return movableBySlot
|
return movableBySlot
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -93,11 +97,11 @@ local function printPermissibleItems(movableBySlot)
|
|||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
---@param slot InventorySlot
|
---@param invSlot InventorySlot
|
||||||
---@param preferMinCondition boolean
|
---@param preferMinCondition boolean
|
||||||
local function tryReloadSlot(slot, preferMinCondition)
|
local function tryReloadSlot(invSlot, preferMinCondition)
|
||||||
---@type Barotrauma.Item
|
---@type Barotrauma.Item
|
||||||
local item = slot.slot.items[1]
|
local item = invSlot.item
|
||||||
if not item then
|
if not item then
|
||||||
MyModGlobal.debugPrint("No item in slot")
|
MyModGlobal.debugPrint("No item in slot")
|
||||||
return
|
return
|
||||||
@@ -115,13 +119,10 @@ local function tryReloadSlot(slot, preferMinCondition)
|
|||||||
MyModGlobal.debugPrint("No slots")
|
MyModGlobal.debugPrint("No slots")
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
-- MyModGlobal.debugPrint("Slots:")
|
|
||||||
-- dump(slots)
|
|
||||||
|
|
||||||
---@type table<InventorySlot, Barotrauma.Item[]>
|
---@type table<InventorySlot, Barotrauma.Item[]>
|
||||||
local movableBySlot = getItemsPerSlot(slots)
|
local movableBySlot = getItemsPerSlot(slots)
|
||||||
-- MyModGlobal.debugPrint("Movable by slot:")
|
-- MyModGlobal.debugPrint("Movable by slot:")
|
||||||
-- dump(movableBySlot)
|
|
||||||
|
|
||||||
local permissibleItems = LOAD_MAP[tostring(item.Prefab.Identifier.Value)]
|
local permissibleItems = LOAD_MAP[tostring(item.Prefab.Identifier.Value)]
|
||||||
if not permissibleItems then
|
if not permissibleItems then
|
||||||
@@ -156,22 +157,19 @@ local function tryReloadSlot(slot, preferMinCondition)
|
|||||||
-- We loaded as many as we have been allowed to
|
-- We loaded as many as we have been allowed to
|
||||||
-- And we do this check up front because an item may already
|
-- And we do this check up front because an item may already
|
||||||
-- Be partially loaded
|
-- Be partially loaded
|
||||||
local nowHave = #inventorySlot.slot.items
|
local nowHave = inventorySlot.stackSize
|
||||||
if nowHave >= permissible then
|
if nowHave >= permissible then
|
||||||
-- MyModGlobal.debugPrint(string.format(
|
MyModGlobal.debugPrint(string.format(
|
||||||
-- "Finished processing item: %s. Current slot has reached the permissible limit of %d items.",
|
"Finished processing item: %s. Current slot has reached the permissible limit of %d items.",
|
||||||
-- tostring(ititem.Prefab.Identifier.Value), permissible))
|
tostring(ititem.Prefab.Identifier.Value), permissible))
|
||||||
break
|
break
|
||||||
end
|
end
|
||||||
|
|
||||||
local moved = inventorySlot.inventory.TryPutItem(ititem, inventorySlot.slotIndex, false, true, Character.Controlled, true)
|
if not inventorySlot:canFit(ititem.Prefab) then
|
||||||
-- When the slot is full no more will be able to be moved
|
break
|
||||||
-- And tat that point we're done with that slot
|
end
|
||||||
if not moved then break end
|
utils.enqueueMove(ititem, inventorySlot)
|
||||||
numMoved = numMoved + 1
|
numMoved = numMoved + 1
|
||||||
|
|
||||||
-- else
|
|
||||||
-- MyModGlobal.debugPrint(string.format("Not permissible: %s", tostring(ititem.Prefab.Identifier.Value)))
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@@ -5,20 +5,14 @@ if not CLIENT then return end
|
|||||||
local utils = require("Cyka.utils")
|
local utils = require("Cyka.utils")
|
||||||
local dump = require("Cyka.dump")
|
local dump = require("Cyka.dump")
|
||||||
|
|
||||||
---@class ItemLocation
|
|
||||||
---@field inventory Barotrauma.ItemInventory
|
|
||||||
---@field slotIndex number
|
|
||||||
---@field depth number
|
|
||||||
---@field maxFits number
|
|
||||||
|
|
||||||
-- The resulting item tree is a table where the key is an ID of an item
|
-- The resulting item tree is a table where the key is an ID of an item
|
||||||
-- And the value is an object that represents where that item is located
|
-- And the value is an object that represents where that item is located
|
||||||
-- In our inventory
|
-- In our inventory
|
||||||
-- Special case are empty slots where any item fits
|
-- Special case are empty slots where any item fits
|
||||||
---@param inventory Barotrauma.ItemInventory
|
---@param inventory Barotrauma.Inventory
|
||||||
---@param itemTree table<string, ItemLocation[]>
|
---@param itemTree? table<string, InventorySlot[]>
|
||||||
---@param depth number
|
---@param depth? number
|
||||||
---@return table<string, ItemLocation[]>
|
---@return table<string, InventorySlot[]>
|
||||||
local function buildItemTree(inventory, itemTree, depth)
|
local function buildItemTree(inventory, itemTree, depth)
|
||||||
itemTree = itemTree or {}
|
itemTree = itemTree or {}
|
||||||
depth = depth or 0
|
depth = depth or 0
|
||||||
@@ -29,38 +23,24 @@ local function buildItemTree(inventory, itemTree, depth)
|
|||||||
|
|
||||||
-- One slot can have one item but multiple of it
|
-- One slot can have one item but multiple of it
|
||||||
-- The number of an item in a slot is #slot.items
|
-- The number of an item in a slot is #slot.items
|
||||||
for slotIndex, slot in ipairs(inventory.slots) do
|
for slotIndex, _ in ipairs(inventory.slots) do
|
||||||
-- MyModGlobal.debugPrint(string.format("Building item tree for inventory at slot index: %d", slotIndex))
|
local invSlot = MyModGlobal.InventorySlot.new(inventory, slotIndex):with({ depth = depth })
|
||||||
-- MyModGlobal.debugPrint(string.format("Slot %d has %d items", slotIndex, #slot.items))
|
if not invSlot.item then
|
||||||
if #slot.items == 0 then
|
|
||||||
-- MyModGlobal.debugPrint(string.format("Slot %d is empty, adding to itemTree as 'empty'", slotIndex))
|
-- MyModGlobal.debugPrint(string.format("Slot %d is empty, adding to itemTree as 'empty'", slotIndex))
|
||||||
itemTree['empty'] = itemTree['empty'] or {}
|
itemTree['empty'] = itemTree['empty'] or {}
|
||||||
itemTree['empty'][#itemTree['empty'] + 1] = {
|
itemTree['empty'][#itemTree['empty'] + 1] = invSlot
|
||||||
inventory = inventory,
|
|
||||||
slotIndex = slotIndex - 1,
|
|
||||||
maxFits = 60,
|
|
||||||
depth = depth
|
|
||||||
}
|
|
||||||
-- MyModGlobal.debugPrint(string.format("Added empty slot to itemTree at index: %d", slotIndex))
|
-- MyModGlobal.debugPrint(string.format("Added empty slot to itemTree at index: %d", slotIndex))
|
||||||
else
|
else
|
||||||
---@type Barotrauma.Item
|
local identifier = invSlot.item.Prefab.Identifier.Value
|
||||||
local item = slot.items[1]
|
|
||||||
local identifier = item.Prefab.Identifier.Value
|
|
||||||
-- MyModGlobal.debugPrint(string.format("Found item: %s with identifier: %s", item.Name, identifier))
|
|
||||||
itemTree[identifier] = itemTree[identifier] or {}
|
itemTree[identifier] = itemTree[identifier] or {}
|
||||||
-- We DO want even slots with maxFits = 0
|
-- We DO want even slots with maxFits = 0
|
||||||
-- Because that indicates that we DO HAVE the item
|
-- Because that indicates that we DO HAVE the item
|
||||||
-- At all
|
-- At all
|
||||||
-- And based on that we decide to move it
|
-- And based on that we decide to move it
|
||||||
itemTree[identifier][#itemTree[identifier] + 1] = {
|
itemTree[identifier][#itemTree[identifier] + 1] = invSlot
|
||||||
inventory = inventory,
|
|
||||||
slotIndex = slotIndex - 1,
|
|
||||||
maxFits = slot.HowManyCanBePut(item.Prefab),
|
|
||||||
depth = depth
|
|
||||||
}
|
|
||||||
-- MyModGlobal.debugPrint(string.format("Added item to itemTree under identifier: %s", identifier))
|
-- MyModGlobal.debugPrint(string.format("Added item to itemTree under identifier: %s", identifier))
|
||||||
|
|
||||||
local tags = item.Prefab.Tags
|
local tags = invSlot.item.Prefab.Tags
|
||||||
local shouldSuss = false
|
local shouldSuss = false
|
||||||
for tag in tags do
|
for tag in tags do
|
||||||
if tag.value:find("container") then
|
if tag.value:find("container") then
|
||||||
@@ -71,7 +51,7 @@ local function buildItemTree(inventory, itemTree, depth)
|
|||||||
|
|
||||||
if shouldSuss then
|
if shouldSuss then
|
||||||
-- MyModGlobal.debugPrint(string.format("Searching inside %s for nested containers", item.Name))
|
-- MyModGlobal.debugPrint(string.format("Searching inside %s for nested containers", item.Name))
|
||||||
buildItemTree(item.OwnInventory, itemTree, depth + 1)
|
buildItemTree(invSlot.item.OwnInventory, itemTree, depth + 1)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -81,19 +61,20 @@ local function buildItemTree(inventory, itemTree, depth)
|
|||||||
end
|
end
|
||||||
|
|
||||||
-- We would like to fill larger stacks first
|
-- We would like to fill larger stacks first
|
||||||
---@param itemTree table<string, ItemLocation[]>
|
---@param itemTree table<string, InventorySlot[]>
|
||||||
---@return table<string, ItemLocation[]>
|
---@return table<string, InventorySlot[]>
|
||||||
local function sortItemTree(itemTree)
|
local function sortItemTree(itemTree)
|
||||||
for _, item in pairs(itemTree) do
|
for _, item in pairs(itemTree) do
|
||||||
table.sort(item, function(a, b)
|
table.sort(item, function(a, b)
|
||||||
---@cast a ItemLocation
|
---@cast a InventorySlot
|
||||||
---@cast b ItemLocation
|
---@cast b InventorySlot
|
||||||
|
local maxfitsA, maxfitsB = a:maxFits(), b:maxFits()
|
||||||
if a.depth ~= b.depth then
|
if a.depth ~= b.depth then
|
||||||
return a.depth < b.depth
|
return a.depth < b.depth
|
||||||
elseif a.maxFits ~= b.maxFits then
|
elseif maxfitsA ~= maxfitsB then
|
||||||
return a.maxFits > b.maxFits
|
return maxfitsA > maxfitsB
|
||||||
else
|
else
|
||||||
return a.slotIndex < b.slotIndex
|
return a.slotIndex0 < b.slotIndex0
|
||||||
end
|
end
|
||||||
end)
|
end)
|
||||||
end
|
end
|
||||||
@@ -102,16 +83,16 @@ local function sortItemTree(itemTree)
|
|||||||
end
|
end
|
||||||
|
|
||||||
---@param item Barotrauma.Item
|
---@param item Barotrauma.Item
|
||||||
---@param itemTree table<string, ItemLocation[]>
|
---@param itemTree table<string, InventorySlot[]>
|
||||||
---@param force boolean
|
---@param force boolean
|
||||||
---@return string
|
---@return string?
|
||||||
local function tryMoveItem(item, itemTree, force)
|
local function tryMoveItem(item, itemTree, force)
|
||||||
-- MyModGlobal.debugPrint(string.format("Attempting to move item: %s", item.Prefab.Identifier.Value))
|
-- MyModGlobal.debugPrint(string.format("Attempting to move item: %s", item.Prefab.Identifier.Value))
|
||||||
force = force or false
|
force = force or false
|
||||||
local location = itemTree[item.Prefab.Identifier.Value]
|
local location = itemTree[item.Prefab.Identifier.Value]
|
||||||
if not location and not force then
|
if not location and not force then
|
||||||
-- MyModGlobal.debugPrint("No locations for item, not stacking (not forced)")
|
-- MyModGlobal.debugPrint("No locations for item, not stacking (not forced)")
|
||||||
return nil, "No locations for item, not stacking (not forced)"
|
return "No locations for item, not stacking (not forced)"
|
||||||
end
|
end
|
||||||
-- MyModGlobal.debugPrint(string.format("Attempting to move item: %s", item.Prefab.Identifier.Value))
|
-- MyModGlobal.debugPrint(string.format("Attempting to move item: %s", item.Prefab.Identifier.Value))
|
||||||
-- MyModGlobal.DumpTable(location)
|
-- MyModGlobal.DumpTable(location)
|
||||||
@@ -121,23 +102,13 @@ local function tryMoveItem(item, itemTree, force)
|
|||||||
-- First try to move to existing stacks
|
-- First try to move to existing stacks
|
||||||
for _, itemLocation in ipairs(location) do
|
for _, itemLocation in ipairs(location) do
|
||||||
-- We cannot stack items with decreased condition
|
-- We cannot stack items with decreased condition
|
||||||
local canBePut = itemLocation.inventory.CanBePutInSlot(item.Prefab, itemLocation.slotIndex, item.Condition)
|
local canFit = itemLocation:canFit(item.Prefab)
|
||||||
-- MyModGlobal.debugPrint(string.format("Can be put in slot %d: %s", itemLocation.slotIndex, tostring(canBePut)))
|
if canFit then
|
||||||
|
-- There's no more guess work, if we call move then we must be sure we can move
|
||||||
if itemLocation.maxFits > 0 and canBePut then
|
utils.enqueueMove(item, itemLocation)
|
||||||
moved = moved or
|
moved = true
|
||||||
itemLocation.inventory.TryPutItem(item, itemLocation.slotIndex, false, true, Character.Controlled,
|
|
||||||
true)
|
|
||||||
if moved then
|
|
||||||
itemLocation.maxFits = itemLocation.inventory.HowManyCanBePut(item.Prefab, itemLocation.slotIndex)
|
|
||||||
break
|
break
|
||||||
end
|
end
|
||||||
-- if moved then
|
|
||||||
-- MyModGlobal.debugPrint(string.format("Moved item to existing stack at slot index: %d", itemLocation .slotIndex))
|
|
||||||
-- else
|
|
||||||
-- MyModGlobal.debugPrint(string.format("Failed to move item to existing stack at slot index: %d", itemLocation .slotIndex))
|
|
||||||
-- end
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -149,29 +120,17 @@ local function tryMoveItem(item, itemTree, force)
|
|||||||
return "No empty slots found"
|
return "No empty slots found"
|
||||||
end
|
end
|
||||||
for _, itemLocation in ipairs(itemTree['empty']) do
|
for _, itemLocation in ipairs(itemTree['empty']) do
|
||||||
local maxFits = itemLocation.maxFits
|
|
||||||
-- These empty slots are not guranteed to be empty, ironically
|
-- These empty slots are not guranteed to be empty, ironically
|
||||||
-- After we insert an item into one it's no longer empty
|
-- After we insert an item into one it's no longer empty
|
||||||
-- But it still is in the empty table
|
-- But it still is in the empty table
|
||||||
-- So we want to make sure we can insert our item
|
-- So we want to make sure we can insert our item
|
||||||
-- Into the maybe empty slots
|
-- Into the maybe empty slots
|
||||||
itemLocation.maxFits = itemLocation.inventory.HowManyCanBePut(item.Prefab, itemLocation.slotIndex)
|
local canFit = itemLocation:canFit(item.Prefab)
|
||||||
|
if canFit then
|
||||||
if maxFits > 0 then
|
utils.enqueueMove(item, itemLocation)
|
||||||
-- MyModGlobal.debugPrint(string.format("Trying to move item to empty slot at index: %d", itemLocation.slotIndex))
|
moved = true
|
||||||
moved = moved or
|
|
||||||
itemLocation.inventory.TryPutItem(item, itemLocation.slotIndex, true, false, Character.Controlled,
|
|
||||||
true)
|
|
||||||
if moved then
|
|
||||||
itemLocation.maxFits = itemLocation.inventory.HowManyCanBePut(item.Prefab, itemLocation.slotIndex)
|
|
||||||
break
|
break
|
||||||
end
|
end
|
||||||
-- if moved then
|
|
||||||
-- MyModGlobal.debugPrint(string.format("Moved item to empty slot at index: %d", itemLocation.slotIndex))
|
|
||||||
-- else
|
|
||||||
-- MyModGlobal.debugPrint(string.format("Failed to move item to empty slot at index: %d", itemLocation.slotIndex))
|
|
||||||
-- end
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -185,8 +144,8 @@ local function tryMoveItem(item, itemTree, force)
|
|||||||
end
|
end
|
||||||
|
|
||||||
---@param items Barotrauma.Item[]
|
---@param items Barotrauma.Item[]
|
||||||
---@param itemTree table<string, ItemLocation[]>
|
---@param itemTree table<string, InventorySlot[]>
|
||||||
---@param force boolean
|
---@param force? boolean
|
||||||
---@return string[]
|
---@return string[]
|
||||||
local function tryMoveItems(items, itemTree, force)
|
local function tryMoveItems(items, itemTree, force)
|
||||||
force = force or false
|
force = force or false
|
||||||
@@ -202,7 +161,7 @@ local function tryMoveItems(items, itemTree, force)
|
|||||||
end
|
end
|
||||||
|
|
||||||
---@param character Barotrauma.Character
|
---@param character Barotrauma.Character
|
||||||
---@return table<string, ItemLocation[]>, string
|
---@return table<string, InventorySlot[]>, string?
|
||||||
local function tryBuildCharacterItemTree(character)
|
local function tryBuildCharacterItemTree(character)
|
||||||
local itemTree = {}
|
local itemTree = {}
|
||||||
-- MyModGlobal.debugPrint(string.format("Preparing to stack items into the bag..."))
|
-- MyModGlobal.debugPrint(string.format("Preparing to stack items into the bag..."))
|
||||||
@@ -267,7 +226,7 @@ end
|
|||||||
-- Function to quickly stack items from inventory to containers
|
-- Function to quickly stack items from inventory to containers
|
||||||
-- 6 and 7 are hands
|
-- 6 and 7 are hands
|
||||||
-- 9..18 are main slots
|
-- 9..18 are main slots
|
||||||
local inventorySlotsToStack = { 6, 7, }
|
-- local inventorySlotsToStack = { 6, 7, }
|
||||||
-- local inventorySlotsToStack = { 6, 7, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18 }
|
-- local inventorySlotsToStack = { 6, 7, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18 }
|
||||||
---@param character Barotrauma.Character
|
---@param character Barotrauma.Character
|
||||||
local function quickStackItems(character)
|
local function quickStackItems(character)
|
||||||
@@ -276,12 +235,10 @@ local function quickStackItems(character)
|
|||||||
-- Then stack all items from the parent inventory into the mouseover container
|
-- Then stack all items from the parent inventory into the mouseover container
|
||||||
local mouseover = utils.getFirstSlotUnderCursor()
|
local mouseover = utils.getFirstSlotUnderCursor()
|
||||||
if mouseover then
|
if mouseover then
|
||||||
---@type Barotrauma.Item
|
local itemInventory = mouseover.item.OwnInventory
|
||||||
local slotItem = mouseover.slot.items[1]
|
|
||||||
local itemInventory = slotItem.OwnInventory
|
|
||||||
if itemInventory then
|
if itemInventory then
|
||||||
MyModGlobal.debugPrint(string.format("Item inventory found: %s", tostring(itemInventory)))
|
MyModGlobal.debugPrint(string.format("Item inventory found: %s", tostring(itemInventory)))
|
||||||
local err = stackToContainer(slotItem)
|
local err = stackToContainer(mouseover.item)
|
||||||
if err then
|
if err then
|
||||||
MyModGlobal.debugPrint(string.format("Error stacking items to container: %s", err))
|
MyModGlobal.debugPrint(string.format("Error stacking items to container: %s", err))
|
||||||
end
|
end
|
||||||
@@ -341,6 +298,7 @@ local function quickStackItems(character)
|
|||||||
-- end
|
-- end
|
||||||
-- end
|
-- end
|
||||||
|
|
||||||
|
-- TODO: enqueueOpenContainers?
|
||||||
local openContainers = utils.getOpenContainers()
|
local openContainers = utils.getOpenContainers()
|
||||||
for _, container in ipairs(openContainers) do
|
for _, container in ipairs(openContainers) do
|
||||||
local inventories = container.OwnInventories
|
local inventories = container.OwnInventories
|
||||||
@@ -367,48 +325,38 @@ local function stackToCursor()
|
|||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
local item, slot
|
|
||||||
local function predicate(ititem)
|
local function predicate(ititem)
|
||||||
if ititem.Prefab.Identifier.Value == item.Prefab.Identifier.Value then
|
for _, invSlot in ipairs(slots) do
|
||||||
if item == ititem then return false end
|
if invSlot:canFit(ititem.Prefab) then
|
||||||
-- We are moving items in the predicate because we expect to only
|
utils.enqueueMove(ititem, invSlot)
|
||||||
-- Select a small subset of all items
|
|
||||||
-- And it is much easier to let the game decide when we can not move
|
|
||||||
-- Any more items (via return value of TryPutItem)
|
|
||||||
-- And we then know that we can safely stop
|
|
||||||
-- UPDATE: OK well that was a stupid idea, it returns an error for other shit as well
|
|
||||||
-- What other shit? Wish I knew
|
|
||||||
-- So we'll use HowManyCanBePut instead...
|
|
||||||
local moved = slot.inventory.TryPutItem(ititem, slot.slotIndex - 1, false, true, Character.Controlled,
|
|
||||||
true)
|
|
||||||
if not moved then
|
|
||||||
MyModGlobal.debugPrint(string.format("Failed to move item %s to slot %d", ititem.Name, slot
|
|
||||||
.slotIndex - 1))
|
|
||||||
-- return false, true
|
|
||||||
end
|
|
||||||
local maxFits = slot.inventory.HowManyCanBePut(ititem.Prefab, slot.slotIndex - 1)
|
|
||||||
if maxFits <= 0 then
|
|
||||||
MyModGlobal.debugPrint(string.format("Item %s has no more fits in slot %d", ititem.Name, slot
|
|
||||||
.slotIndex - 1))
|
|
||||||
return false, true
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
local haveSpace = false
|
||||||
|
for _, invSlot in ipairs(slots) do
|
||||||
|
-- Empty slot or has space for more items
|
||||||
|
if (invSlot.stackSize < invSlot.maxStackSize) or not invSlot.item then
|
||||||
|
haveSpace = true
|
||||||
|
break
|
||||||
|
end
|
||||||
|
end
|
||||||
|
if not haveSpace then return false, true end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
---@type EnqueueOptions
|
||||||
|
local options = {
|
||||||
|
itemPredicate = predicate,
|
||||||
|
recurse = true,
|
||||||
|
}
|
||||||
-- We gotta do a little juggling...
|
-- We gotta do a little juggling...
|
||||||
for _, sslot in ipairs(slots) do
|
for _, invSlot in ipairs(slots) do
|
||||||
slot = sslot
|
if not invSlot.item then
|
||||||
local items
|
|
||||||
if not slot.slot.items or #slot.slot.items == 0 then
|
|
||||||
MyModGlobal.debugPrint("No items in slot")
|
MyModGlobal.debugPrint("No items in slot")
|
||||||
goto continue
|
goto continue
|
||||||
end
|
end
|
||||||
|
|
||||||
item = slot.slot.items[1]
|
MyModGlobal.debugPrint(string.format("Stacking all player items to %s", invSlot.item.Prefab.Identifier.Value))
|
||||||
MyModGlobal.debugPrint(string.format("Stacking all player items to %s", item.Prefab.Identifier.Value))
|
utils.enqueuePlayerItems(options)
|
||||||
items = {}
|
utils.enqueueOpenContainers(options)
|
||||||
utils.enqueueAllPlayerItems(items, predicate)
|
|
||||||
utils.enqueueOpenContainers(items, predicate)
|
|
||||||
::continue::
|
::continue::
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -420,45 +368,38 @@ local function stackAllToCursor()
|
|||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
for _, slot in ipairs(slots) do
|
local function predicate(ititem)
|
||||||
local item, predicate
|
for _, invSlot in ipairs(slots) do
|
||||||
if not slot.slot.items or #slot.slot.items == 0 then
|
if invSlot:canFit(ititem.Prefab) then
|
||||||
|
utils.enqueueMove(ititem, invSlot)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
local haveSpace = false
|
||||||
|
for _, invSlot in ipairs(slots) do
|
||||||
|
-- Empty slot or has space for more items
|
||||||
|
if (invSlot.stackSize < invSlot.maxStackSize) or not invSlot.item then
|
||||||
|
haveSpace = true
|
||||||
|
break
|
||||||
|
end
|
||||||
|
end
|
||||||
|
if not haveSpace then return false, true end
|
||||||
|
end
|
||||||
|
|
||||||
|
---@type EnqueueOptions
|
||||||
|
local options = {
|
||||||
|
itemPredicate = predicate,
|
||||||
|
recurse = true,
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, invSlot in ipairs(slots) do
|
||||||
|
if not invSlot.item then
|
||||||
MyModGlobal.debugPrint("No items in slot")
|
MyModGlobal.debugPrint("No items in slot")
|
||||||
goto continue
|
goto continue
|
||||||
end
|
end
|
||||||
|
|
||||||
item = slot.slot.items[1]
|
MyModGlobal.debugPrint(string.format("Stacking all items to %s", invSlot.item.Prefab.Identifier.Value))
|
||||||
MyModGlobal.debugPrint(string.format("Stacking all items to %s", item.Prefab.Identifier.Value))
|
utils.enqueueSubmarineItems(options)
|
||||||
predicate = function(ititem)
|
utils.enqueuePlayerItems(options)
|
||||||
if ititem.Prefab.Identifier.Value == item.Prefab.Identifier.Value then
|
|
||||||
if item == ititem then return false end
|
|
||||||
-- We are moving items in the predicate because we expect to only
|
|
||||||
-- Select a small subset of all items
|
|
||||||
-- And it is much easier to let the game decide when we can not move
|
|
||||||
-- Any more items (via return value of TryPutItem)
|
|
||||||
-- And we then know that we can safely stop
|
|
||||||
-- UPDATE: OK well that was a stupid idea, it returns an error for other shit as well
|
|
||||||
-- What other shit? Wish I knew
|
|
||||||
-- So we'll use HowManyCanBePut instead...
|
|
||||||
local moved = slot.inventory.TryPutItem(ititem, slot.slotIndex - 1, false, true, Character.Controlled,
|
|
||||||
true)
|
|
||||||
if not moved then
|
|
||||||
MyModGlobal.debugPrint(string.format("Failed to move item %s to slot %d", ititem.Name, slot
|
|
||||||
.slotIndex - 1))
|
|
||||||
-- return false, true
|
|
||||||
end
|
|
||||||
local maxFits = slot.inventory.HowManyCanBePut(ititem.Prefab, slot.slotIndex - 1)
|
|
||||||
if maxFits <= 0 then
|
|
||||||
MyModGlobal.debugPrint(string.format("Item %s has no more fits in slot %d", ititem.Name, slot
|
|
||||||
.slotIndex - 1))
|
|
||||||
return false, true
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
utils.enqueueAllSubmarineItems({}, predicate)
|
|
||||||
utils.enqueueAllPlayerItems({}, predicate)
|
|
||||||
|
|
||||||
::continue::
|
::continue::
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@@ -2,106 +2,49 @@
|
|||||||
if not CLIENT then return end
|
if not CLIENT then return end
|
||||||
|
|
||||||
local utils = require("Cyka.utils")
|
local utils = require("Cyka.utils")
|
||||||
|
local dump = require("Cyka.dump")
|
||||||
|
|
||||||
---@param inventory Barotrauma.ItemInventory
|
---@param invSlot InventorySlot
|
||||||
---@param predicate fun(slot: InventorySlot): boolean
|
local function tryUnloadSlot(invSlot)
|
||||||
---@return InventorySlot[], string?
|
---@type table<Barotrauma.ItemPrefab, boolean>
|
||||||
local function findSlotsThat(inventory, predicate)
|
|
||||||
local slots = {}
|
|
||||||
for i, slot in ipairs(inventory.slots) do
|
|
||||||
local inventorySlot = {
|
|
||||||
slot = slot,
|
|
||||||
inventory = inventory,
|
|
||||||
slotIndex = i - 1
|
|
||||||
}
|
|
||||||
if predicate(inventorySlot) then
|
|
||||||
slots[#slots + 1] = inventorySlot
|
|
||||||
end
|
|
||||||
end
|
|
||||||
return slots
|
|
||||||
end
|
|
||||||
|
|
||||||
---@param slot InventorySlot
|
|
||||||
local function tryUnloadSlot(slot)
|
|
||||||
---@type Barotrauma.Item
|
|
||||||
local item = slot.slot.items[1]
|
|
||||||
if not item then
|
|
||||||
MyModGlobal.debugPrint("No item in slot")
|
|
||||||
return
|
|
||||||
end
|
|
||||||
local inventory = item.OwnInventory
|
|
||||||
if not inventory then
|
|
||||||
MyModGlobal.debugPrint("Item has no own inventory")
|
|
||||||
return
|
|
||||||
end
|
|
||||||
|
|
||||||
local toUnload = {}
|
|
||||||
local toUnloadByPrefab = {}
|
local toUnloadByPrefab = {}
|
||||||
local inventorySlots = inventory.slots
|
|
||||||
for _, inventorySlot in ipairs(inventorySlots) do
|
local itemInventory = invSlot.item.OwnInventory
|
||||||
for _, inventoryItem in ipairs(inventorySlot.items) do
|
if not itemInventory then
|
||||||
toUnload[#toUnload + 1] = inventoryItem
|
MyModGlobal.debugPrint("No inventory for item")
|
||||||
-- This will only serve as O(1) lookup
|
return
|
||||||
toUnloadByPrefab[inventoryItem.Prefab] = true
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
MyModGlobal.debugPrint(string.format("Enqueuing inventory %s", tostring(itemInventory)))
|
||||||
|
|
||||||
|
local toUnload = utils.enqueueInventory(itemInventory, {
|
||||||
|
itemPredicate = function(item)
|
||||||
|
toUnloadByPrefab[item.Prefab] = true
|
||||||
|
return true
|
||||||
|
end,
|
||||||
|
recurse = false,
|
||||||
|
})
|
||||||
|
MyModGlobal.debugPrint(string.format("Moving %d items to unload %s", #toUnload.itemQueue, tostring(invSlot.item)))
|
||||||
|
|
||||||
-- Where can we put our toUnload items?
|
-- Where can we put our toUnload items?
|
||||||
local nearbySlots = findSlotsThat(slot.inventory, function(islot)
|
local nearbySlots = invSlot:getNearbySlots(function(islot)
|
||||||
local isEmpty = #islot.slot.items == 0
|
local isEmpty = not islot.item
|
||||||
if isEmpty then return true end
|
if isEmpty then return true end
|
||||||
|
|
||||||
for _, prefab in ipairs(toUnloadByPrefab) do
|
for prefab, _ in pairs(toUnloadByPrefab) do
|
||||||
local canAccept = islot.inventory.CanBePutInSlot(prefab, islot.slotIndex)
|
local canFit = islot:canFit(prefab)
|
||||||
if canAccept then return true end
|
if canFit then return true end
|
||||||
end
|
end
|
||||||
return false
|
return false
|
||||||
end)
|
end)
|
||||||
-- print("Before sorting:")
|
MyModGlobal.debugPrint(string.format("Into %d nearby slots", #nearbySlots))
|
||||||
-- dump(nearbySlots)
|
|
||||||
|
|
||||||
-- Some inventories don't have slots per row, like the player inventory
|
|
||||||
local slotsPerRow = 900
|
|
||||||
local ok, err = pcall(function()
|
|
||||||
slotsPerRow = slot.inventory.slotsPerRow
|
|
||||||
end)
|
|
||||||
if not ok then
|
|
||||||
MyModGlobal.debugPrint(string.format("Error getting slots per row: %s", err))
|
|
||||||
end
|
|
||||||
|
|
||||||
local getGridPos = function(slotIndex)
|
for _, iitem in ipairs(toUnload.itemQueue) do
|
||||||
local x = slotIndex % slotsPerRow
|
|
||||||
local y = math.floor(slotIndex / slotsPerRow)
|
|
||||||
return x, y
|
|
||||||
end
|
|
||||||
|
|
||||||
-- We are offsetting here by 1 because the backend uses 0-indexed slots
|
|
||||||
-- And the lua uses 1-indexed slots
|
|
||||||
-- We are trying to match the backend behavior for sorting
|
|
||||||
local slotx, sloty = getGridPos(slot.slotIndex - 1)
|
|
||||||
-- print(string.format("Slot position %d: %d, %d", slot.slotIndex, slotx, sloty))
|
|
||||||
table.sort(nearbySlots, function(a, b)
|
|
||||||
local ax, ay = getGridPos(a.slotIndex)
|
|
||||||
local bx, by = getGridPos(b.slotIndex)
|
|
||||||
|
|
||||||
local distA = math.max(math.abs(ax - slotx), math.abs(ay - sloty))
|
|
||||||
local distB = math.max(math.abs(bx - slotx), math.abs(by - sloty))
|
|
||||||
|
|
||||||
if distA == distB then
|
|
||||||
return a.slotIndex < b.slotIndex
|
|
||||||
end
|
|
||||||
return distA < distB
|
|
||||||
end)
|
|
||||||
-- print(string.format("Current slot: %d at (%d, %d)", slot.slotIndex, slotx, sloty))
|
|
||||||
|
|
||||||
for _, iitem in ipairs(toUnload) do
|
|
||||||
for _, nearbySlot in ipairs(nearbySlots) do
|
for _, nearbySlot in ipairs(nearbySlots) do
|
||||||
local canAccept = nearbySlot.inventory.CanBePutInSlot(iitem.Prefab, nearbySlot.slotIndex)
|
local canAccept = nearbySlot:canFit(iitem.Prefab)
|
||||||
if canAccept then
|
if canAccept then
|
||||||
local moved = nearbySlot.inventory.TryPutItem(iitem, nearbySlot.slotIndex, true, false,
|
utils.enqueueMove(iitem, nearbySlot)
|
||||||
Character.Controlled, true)
|
break
|
||||||
-- print(string.format("Moved item %s to slot %d", iitem.Name, nearbySlot.slotIndex))
|
|
||||||
if moved then break end
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -110,12 +53,12 @@ end
|
|||||||
local function tryUnloadCursorItem()
|
local function tryUnloadCursorItem()
|
||||||
local slots, err = utils.getSlotsUnderCursor()
|
local slots, err = utils.getSlotsUnderCursor()
|
||||||
if err then
|
if err then
|
||||||
-- MyModGlobal.debugPrint(string.format("Error getting inventory slot: %s", err))
|
MyModGlobal.debugPrint(string.format("Error getting inventory slot: %s", err))
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
if not slots or #slots == 0 then
|
if not slots or #slots == 0 then
|
||||||
-- MyModGlobal.debugPrint("No items in slot")
|
MyModGlobal.debugPrint("No items in slot")
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@@ -1,15 +1,290 @@
|
|||||||
-- luacheck: globals Character MyModGlobal
|
-- luacheck: globals Character MyModGlobal Timer _
|
||||||
-- luacheck: max line length 420
|
-- luacheck: max line length 420
|
||||||
|
|
||||||
---@class ItemRefs
|
---@class Barotrauma.Inventory.ItemSlot
|
||||||
---@field item Barotrauma.Item
|
---@field items Barotrauma.Item[]
|
||||||
---@field inventory Barotrauma.ItemInventory
|
|
||||||
---@field slot Barotrauma.ItemInventory.Slot
|
---@class HollowInventorySlot
|
||||||
|
---@field inventory? Barotrauma.Inventory
|
||||||
|
---@field slotIndex1? number Lua based item slots
|
||||||
|
---@field slotIndex0? number Barotrauma API based item slots
|
||||||
|
---@field item? Barotrauma.Item
|
||||||
|
---@field stackSize? number
|
||||||
|
---@field maxStackSize? number
|
||||||
|
---@field depth? number Currently almost always 0
|
||||||
|
|
||||||
|
-- local globalInventorySlotCache = {}
|
||||||
|
---@class InventorySlot ---@field slot Barotrauma.Inventory.ItemSlot
|
||||||
|
---@field inventory Barotrauma.Inventory
|
||||||
|
---@field slotIndex1 number Lua based item slots
|
||||||
|
---@field slotIndex0 number Barotrauma API based item slots
|
||||||
|
---@field item Barotrauma.Item
|
||||||
|
---@field stackSize number
|
||||||
|
---@field maxStackSize number
|
||||||
|
---@field depth number Currently almost always 0
|
||||||
|
-- ---@field lastUpdated number
|
||||||
|
MyModGlobal.InventorySlot = {
|
||||||
|
---@param inventory Barotrauma.Inventory
|
||||||
|
---@param slotIndex1 number
|
||||||
|
---@return InventorySlot
|
||||||
|
new = function(inventory, slotIndex1)
|
||||||
|
local self = setmetatable({}, {
|
||||||
|
__index = MyModGlobal.InventorySlot
|
||||||
|
})
|
||||||
|
self.inventory = inventory
|
||||||
|
self.slotIndex1 = slotIndex1
|
||||||
|
self.slotIndex0 = slotIndex1 - 1
|
||||||
|
self.stackSize = 0
|
||||||
|
self.maxStackSize = 0
|
||||||
|
self.depth = 0
|
||||||
|
-- self:update()
|
||||||
|
|
||||||
|
if inventory and inventory.slots and #inventory.slots > 0 then
|
||||||
|
self.slot = inventory.slots[slotIndex1]
|
||||||
|
end
|
||||||
|
if self.slot and self.slot.items and #self.slot.items > 0 then
|
||||||
|
self.item = self.slot.items[1]
|
||||||
|
self.stackSize = #self.slot.items
|
||||||
|
-- At this point inventory has to exist
|
||||||
|
-- If it didn't slot wouldn't either and then this wouldn't either
|
||||||
|
self.maxStackSize = self.item.Prefab.GetMaxStackSize(inventory)
|
||||||
|
end
|
||||||
|
|
||||||
|
return self
|
||||||
|
end,
|
||||||
|
--- A very weird builder indeed
|
||||||
|
---@param self InventorySlot
|
||||||
|
---@param other HollowInventorySlot
|
||||||
|
with = function(self, other)
|
||||||
|
if other.inventory ~= nil then
|
||||||
|
self.inventory = other.inventory
|
||||||
|
end
|
||||||
|
if other.slotIndex1 ~= nil then
|
||||||
|
self.slotIndex1 = other.slotIndex1
|
||||||
|
end
|
||||||
|
if other.slotIndex0 ~= nil then
|
||||||
|
self.slotIndex0 = other.slotIndex0
|
||||||
|
end
|
||||||
|
if other.item ~= nil then
|
||||||
|
self.item = other.item
|
||||||
|
end
|
||||||
|
if other.stackSize ~= nil then
|
||||||
|
self.stackSize = other.stackSize
|
||||||
|
end
|
||||||
|
if other.maxStackSize ~= nil then
|
||||||
|
self.maxStackSize = other.maxStackSize
|
||||||
|
end
|
||||||
|
if other.depth ~= nil then
|
||||||
|
self.depth = other.depth
|
||||||
|
end
|
||||||
|
return self
|
||||||
|
end,
|
||||||
|
---@param self InventorySlot
|
||||||
|
---@param item Barotrauma.Item
|
||||||
|
pretendMoved = function(self, item)
|
||||||
|
if not self.inventory then
|
||||||
|
MyModGlobal.debugPrint("Error pretending moved but it was moved to nil inventory")
|
||||||
|
return
|
||||||
|
end
|
||||||
|
-- Slot was previously empty, we want to figure out its max stack for the new item
|
||||||
|
if not self.item then
|
||||||
|
self.maxStackSize = item.Prefab.GetMaxStackSize(self.inventory)
|
||||||
|
end
|
||||||
|
self.item = item
|
||||||
|
self.stackSize = self.stackSize + 1
|
||||||
|
end,
|
||||||
|
update = function(self)
|
||||||
|
-- self.lastUpdated = Timer.GetTime()
|
||||||
|
if not self.inventory then
|
||||||
|
MyModGlobal.debugPrint("Error updating inventory slot, inventory not found")
|
||||||
|
return
|
||||||
|
end
|
||||||
|
if not self.inventory.slots then
|
||||||
|
MyModGlobal.debugPrint("Error updating inventory slot, inventory has no slots")
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
local slot = self.inventory.slots[self.slotIndex1]
|
||||||
|
if not slot then
|
||||||
|
MyModGlobal.debugPrint("Error updating inventory slot, slot not found")
|
||||||
|
return
|
||||||
|
end
|
||||||
|
self.slot = slot
|
||||||
|
if not slot.items or #slot.items == 0 then
|
||||||
|
-- MyModGlobal.debugPrint("Error updating inventory slot, slot is empty")
|
||||||
|
return
|
||||||
|
end
|
||||||
|
self.item = slot.items[1]
|
||||||
|
self.stackSize = #slot.items
|
||||||
|
self.maxStackSize = self.item.Prefab.GetMaxStackSize(self.inventory)
|
||||||
|
end,
|
||||||
|
__tostring = function(self)
|
||||||
|
return string.format(
|
||||||
|
"InventorySlot(inventory=%s, item=%s, stackSize=%d, maxStackSize=%d, slotIndex1=%d, slotIndex0=%d)",
|
||||||
|
tostring(self.inventory), tostring(self.item), self.stackSize, self.maxStackSize, self.slotIndex1,
|
||||||
|
self.slotIndex0)
|
||||||
|
end,
|
||||||
|
---@param self InventorySlot
|
||||||
|
---@param predicate? fun(slot: InventorySlot): boolean
|
||||||
|
---@return InventorySlot[]
|
||||||
|
getNearbySlots = function(self, predicate)
|
||||||
|
predicate = predicate or function() return true end
|
||||||
|
|
||||||
|
local slotsPerRow = 900
|
||||||
|
local ok, err = pcall(function()
|
||||||
|
slotsPerRow = self.inventory.slotsPerRow
|
||||||
|
end)
|
||||||
|
if not ok then
|
||||||
|
MyModGlobal.debugPrint(string.format("Error getting slots per row: %s", err))
|
||||||
|
end
|
||||||
|
|
||||||
|
local getGridPos = function(slotIndex)
|
||||||
|
local x = slotIndex % slotsPerRow
|
||||||
|
local y = math.floor(slotIndex / slotsPerRow)
|
||||||
|
return x, y
|
||||||
|
end
|
||||||
|
|
||||||
|
local slots = {}
|
||||||
|
for slotIndex, _ in ipairs(self.inventory.slots) do
|
||||||
|
local inventorySlot = MyModGlobal.InventorySlot.new(self.inventory, slotIndex)
|
||||||
|
if predicate(inventorySlot) then
|
||||||
|
slots[#slots + 1] = inventorySlot
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local slotx, sloty = getGridPos(self.slotIndex0)
|
||||||
|
table.sort(slots, function(a, b)
|
||||||
|
local ax, ay = getGridPos(a.slotIndex0)
|
||||||
|
local bx, by = getGridPos(b.slotIndex0)
|
||||||
|
|
||||||
|
-- Chebyshev distance
|
||||||
|
local distA = math.max(math.abs(ax - slotx), math.abs(ay - sloty))
|
||||||
|
local distB = math.max(math.abs(bx - slotx), math.abs(by - sloty))
|
||||||
|
|
||||||
|
if distA == distB then
|
||||||
|
return a.slotIndex0 < b.slotIndex0
|
||||||
|
end
|
||||||
|
return distA < distB
|
||||||
|
end)
|
||||||
|
|
||||||
|
return slots
|
||||||
|
end,
|
||||||
|
--- TODO: What about item condition?
|
||||||
|
---@param self InventorySlot
|
||||||
|
---@param itemPrefab Barotrauma.ItemPrefab
|
||||||
|
---@return number
|
||||||
|
howManyCanFit = function(self, itemPrefab)
|
||||||
|
-- There is an item in the slot and it's not stackable with itemPrefab
|
||||||
|
if self.item and not self.item.Prefab.Equals(itemPrefab) then
|
||||||
|
return 0
|
||||||
|
end
|
||||||
|
-- The slot is empty - we can fit as many as the game tells us
|
||||||
|
if not self.item then
|
||||||
|
return itemPrefab.GetMaxStackSize(self.inventory)
|
||||||
|
end
|
||||||
|
-- The slot has an item that is stackable with itemPrefab
|
||||||
|
-- We can fit as many as to fill the stack
|
||||||
|
return self.maxStackSize - self.stackSize
|
||||||
|
end,
|
||||||
|
---@param self InventorySlot
|
||||||
|
---@param itemPrefab Barotrauma.ItemPrefab
|
||||||
|
---@return boolean
|
||||||
|
canFit = function(self, itemPrefab)
|
||||||
|
return self:howManyCanFit(itemPrefab) > 0
|
||||||
|
end,
|
||||||
|
---@param self InventorySlot
|
||||||
|
---@return number
|
||||||
|
maxFits = function(self)
|
||||||
|
return self.maxStackSize - self.stackSize
|
||||||
|
end
|
||||||
|
-- hash = function(self)
|
||||||
|
-- return string.format("%s:%d:%d", tostring(self.inventory), self.slotIndex1, self.slotIndex0)
|
||||||
|
-- end
|
||||||
|
}
|
||||||
|
|
||||||
|
---@class ItemMoveRequest
|
||||||
|
---@field what Barotrauma.Item
|
||||||
|
---@field where InventorySlot
|
||||||
|
---@field allowSwap boolean
|
||||||
|
---@field allowCombine boolean
|
||||||
|
|
||||||
|
local enqueueMove
|
||||||
|
do
|
||||||
|
-- A bit of cheeky scoping
|
||||||
|
local enabled = true
|
||||||
|
---@type ItemMoveRequest[]
|
||||||
|
local itemMoveQueue = {}
|
||||||
|
---@type table<Barotrauma.Item, boolean>
|
||||||
|
local itemLookup = {}
|
||||||
|
local rate = 500
|
||||||
|
local perIteration = 30
|
||||||
|
local noQueue = true
|
||||||
|
-- rate / 1000 is ms to seconds and *perIteraion is number of items per second
|
||||||
|
local maxQueueSize = 10 * (1000 / rate * perIteration)
|
||||||
|
local function processQueue()
|
||||||
|
if noQueue then return end
|
||||||
|
-- MyModGlobal.debugPrint("Processing queue")
|
||||||
|
Timer.Wait(processQueue, rate)
|
||||||
|
if not enabled then return end
|
||||||
|
if #itemMoveQueue == 0 then return end
|
||||||
|
local iterations = math.min(perIteration, #itemMoveQueue)
|
||||||
|
for _ = 1, iterations do
|
||||||
|
---@type ItemMoveRequest
|
||||||
|
local moveRequest = table.remove(itemMoveQueue, 1)
|
||||||
|
|
||||||
|
-- TODO: Maybe try and figure out if we CAN put A into B
|
||||||
|
moveRequest.allowCombine = moveRequest.allowCombine or false
|
||||||
|
moveRequest.allowSwap = moveRequest.allowSwap or false
|
||||||
|
local success = moveRequest.where.inventory.TryPutItem(moveRequest.what, moveRequest.where.slotIndex0,
|
||||||
|
moveRequest.allowSwap, moveRequest.allowCombine, nil)
|
||||||
|
if not success then
|
||||||
|
MyModGlobal.debugPrint(string.format("Failed moving item from %s to %s", tostring(moveRequest.what),
|
||||||
|
tostring(moveRequest.where:__tostring())))
|
||||||
|
end
|
||||||
|
itemLookup[moveRequest.what] = nil
|
||||||
|
end
|
||||||
|
end
|
||||||
|
processQueue()
|
||||||
|
|
||||||
|
---@param what Barotrauma.Item
|
||||||
|
---@param where InventorySlot
|
||||||
|
---@param allowSwap? boolean
|
||||||
|
---@param allowCombine? boolean
|
||||||
|
enqueueMove = function(what, where, allowSwap, allowCombine)
|
||||||
|
allowCombine = allowCombine == true
|
||||||
|
allowSwap = allowSwap == true
|
||||||
|
if noQueue then
|
||||||
|
local success = where.inventory.TryPutItem(what, where.slotIndex0,
|
||||||
|
allowSwap, allowCombine, nil)
|
||||||
|
if not success then
|
||||||
|
MyModGlobal.debugPrint(string.format("Failed moving item from %s to %s", tostring(what),
|
||||||
|
tostring(where:__tostring())))
|
||||||
|
end
|
||||||
|
where:pretendMoved(what)
|
||||||
|
else
|
||||||
|
if #itemMoveQueue >= maxQueueSize then
|
||||||
|
MyModGlobal.debugPrint("Queue is full, skipping move")
|
||||||
|
return
|
||||||
|
end
|
||||||
|
if itemLookup[what] then
|
||||||
|
MyModGlobal.debugPrint("Item is already in the queue, skipping move")
|
||||||
|
return
|
||||||
|
end
|
||||||
|
MyModGlobal.debugPrint(string.format("Enqueuing move from %s to %s, now in queue %d/%d", tostring(what),
|
||||||
|
tostring(where:__tostring()), #itemMoveQueue, maxQueueSize))
|
||||||
|
table.insert(itemMoveQueue, {
|
||||||
|
what = what,
|
||||||
|
where = where,
|
||||||
|
allowSwap = allowSwap or false,
|
||||||
|
allowCombine = allowCombine ~= false,
|
||||||
|
})
|
||||||
|
itemLookup[what] = true
|
||||||
|
-- We will very optimistically pretend that this will 100% for sure work
|
||||||
|
where:pretendMoved(what)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
---@class InventorySlot
|
|
||||||
---@field slot Barotrauma.ItemSlot
|
|
||||||
---@field inventory Barotrauma.ItemInventory
|
|
||||||
---@field slotIndex number
|
|
||||||
|
|
||||||
---@return Barotrauma.Item[], string?
|
---@return Barotrauma.Item[], string?
|
||||||
local function getOpenContainers()
|
local function getOpenContainers()
|
||||||
@@ -23,7 +298,9 @@ end
|
|||||||
---@return Barotrauma.Item, string?
|
---@return Barotrauma.Item, string?
|
||||||
local function getFirstOpenContainer()
|
local function getFirstOpenContainer()
|
||||||
local containers, err = getOpenContainers()
|
local containers, err = getOpenContainers()
|
||||||
|
---@diagnostic disable-next-line: return-type-mismatch
|
||||||
if err then return nil, err end
|
if err then return nil, err end
|
||||||
|
---@diagnostic disable-next-line: return-type-mismatch
|
||||||
if #containers == 0 then return nil, "No open containers" end
|
if #containers == 0 then return nil, "No open containers" end
|
||||||
return containers[1], nil
|
return containers[1], nil
|
||||||
end
|
end
|
||||||
@@ -32,194 +309,232 @@ end
|
|||||||
-- And enqueueItem calls enqueueInventory
|
-- And enqueueItem calls enqueueInventory
|
||||||
-- So unless we define them both before using them
|
-- So unless we define them both before using them
|
||||||
-- We will get an error saying either is undefined
|
-- We will get an error saying either is undefined
|
||||||
|
-- TODO: Rework these enqueue functions to accept a params object
|
||||||
|
-- That will house all optional parameters
|
||||||
|
-- And in that include recurse boolean
|
||||||
|
|
||||||
|
---@class ItemRefs
|
||||||
|
---@field item Barotrauma.Item
|
||||||
|
---@field inventory Barotrauma.Inventory
|
||||||
|
---@field slot Barotrauma.Inventory.ItemSlot
|
||||||
|
---@field slotIndex1 number
|
||||||
|
|
||||||
|
---@class EnqueueOptions
|
||||||
|
---@field itemQueue? Barotrauma.Item[]
|
||||||
|
---@field slotQueue? Barotrauma.Inventory.ItemSlot[]
|
||||||
|
---@field inventoryQueue? Barotrauma.Inventory[]
|
||||||
|
---@field itemPredicate? fun(item: Barotrauma.Item, itemRef: ItemRefs): boolean
|
||||||
|
---@field slotPredicate? fun(slot: Barotrauma.Inventory.ItemSlot, itemRef: ItemRefs): boolean
|
||||||
|
---@field inventoryPredicate? fun(inventory: Barotrauma.Inventory, itemRef: ItemRefs): boolean
|
||||||
|
---@field loadRefs? boolean
|
||||||
|
---@field itemRef? ItemRefs
|
||||||
|
---@field recurse? boolean
|
||||||
|
|
||||||
|
---@param options EnqueueOptions
|
||||||
|
---@return EnqueueOptions
|
||||||
|
local function ensureOptionsDefaults(options)
|
||||||
|
options = options or {}
|
||||||
|
options.itemQueue = options.itemQueue or {}
|
||||||
|
options.slotQueue = options.slotQueue or {}
|
||||||
|
options.inventoryQueue = options.inventoryQueue or {}
|
||||||
|
options.itemPredicate = options.itemPredicate or function() return true end
|
||||||
|
options.slotPredicate = options.slotPredicate or function() return true end
|
||||||
|
options.inventoryPredicate = options.inventoryPredicate or function() return true end
|
||||||
|
options.loadRefs = options.loadRefs == true
|
||||||
|
options.itemRef = options.itemRef or {}
|
||||||
|
options.recurse = options.recurse == true
|
||||||
|
return options
|
||||||
|
end
|
||||||
|
|
||||||
local enqueueItem
|
local enqueueItem
|
||||||
local enqueueSlot
|
local enqueueSlot
|
||||||
local enqueueInventory
|
local enqueueInventory
|
||||||
|
local enqueuePlayerItems
|
||||||
local enqueueOpenContainers
|
local enqueueOpenContainers
|
||||||
local allPlayerItems
|
local enqueueSubmarineItems
|
||||||
local allSubmarineItems
|
local enqueueAllOwnedItems
|
||||||
local allOwnedItems
|
|
||||||
local _
|
|
||||||
|
|
||||||
---@alias FilterPredicate fun(item: Barotrauma.Item, inventoryRef?: Barotrauma.ItemInventory, slotRef: Barotrauma.ItemInventory.Slot): boolean
|
|
||||||
|
|
||||||
-- Loading refs is optional because it MAY have a performance impact
|
|
||||||
|
|
||||||
|
do
|
||||||
---@param item Barotrauma.Item
|
---@param item Barotrauma.Item
|
||||||
---@param queue Barotrauma.Item[]
|
---@param options EnqueueOptions
|
||||||
---@param predicate? FilterPredicate
|
---@return EnqueueOptions, string?
|
||||||
---@param loadRefs? boolean
|
enqueueItem = function(item, options)
|
||||||
---@param itemRef? ItemRefs
|
options = ensureOptionsDefaults(options)
|
||||||
---@return Barotrauma.Item[], string?
|
if not item then return options, "No item" end
|
||||||
enqueueItem = function(item, queue, predicate, loadRefs, itemRef)
|
|
||||||
queue = queue or {}
|
|
||||||
predicate = predicate or function() return true end
|
|
||||||
itemRef = itemRef or {}
|
|
||||||
-- debugPrint(string.format("Enqueuing item: %s", item.Prefab.Identifier.Value))
|
|
||||||
-- local err
|
|
||||||
-- This should make it breadth first, right...?
|
|
||||||
-- No, not yet...
|
|
||||||
if not item then return queue, "No item" end
|
|
||||||
|
|
||||||
local ok, stop = predicate(item, itemRef)
|
local ok, stop = options.itemPredicate(item, options.itemRef)
|
||||||
if ok then
|
if ok then
|
||||||
queue[#queue + 1] = item
|
options.itemQueue[#options.itemQueue + 1] = item
|
||||||
end
|
end
|
||||||
if stop then return queue, "Stop" end
|
if stop then return options, "Stop" end
|
||||||
|
|
||||||
|
local err
|
||||||
if item.OwnInventory then
|
if item.OwnInventory then
|
||||||
-- As far as I know every item has only one inventory
|
-- As far as I know every item has only one inventory
|
||||||
-- Only machines have multiple
|
-- Only machines have multiple
|
||||||
-- So inventrorY should be fine here
|
-- So inventrorY should be fine here
|
||||||
-- debugPrint("Item has its own inventory, enqueuing inventory...")
|
if options.recurse then
|
||||||
if loadRefs then
|
if options.loadRefs then
|
||||||
itemRef.item = item
|
options.itemRef.item = item
|
||||||
queue, _ = enqueueInventory(item.OwnInventory, queue, predicate, loadRefs, itemRef)
|
options.inventoryQueue, err = enqueueInventory(item.OwnInventory, options)
|
||||||
else
|
else
|
||||||
queue, _ = enqueueInventory(item.OwnInventory, queue, predicate, itemRef)
|
options.inventoryQueue, err = enqueueInventory(item.OwnInventory, options)
|
||||||
end
|
end
|
||||||
-- if err then
|
|
||||||
-- debugPrint(string.format("Error enqueuing inventory: %s", err))
|
|
||||||
-- end
|
|
||||||
end
|
end
|
||||||
-- debugPrint(string.format("Item enqueued. Current queue size: %d", #queue))
|
end
|
||||||
return queue, nil
|
return options, err
|
||||||
end
|
end
|
||||||
|
|
||||||
---@param slot Barotrauma.ItemInventory.Slot
|
---@param slot Barotrauma.Inventory.ItemSlot
|
||||||
---@param queue Barotrauma.Item[]
|
---@param options EnqueueOptions
|
||||||
---@param predicate? FilterPredicate
|
---@return EnqueueOptions, string?
|
||||||
---@param loadRefs? boolean
|
enqueueSlot = function(slot, options)
|
||||||
---@param itemRef? ItemRefs
|
options = ensureOptionsDefaults(options)
|
||||||
---@return Barotrauma.Item[], string?
|
if not slot then return options, "No slot" end
|
||||||
enqueueSlot = function(slot, queue, predicate, loadRefs, itemRef)
|
if not slot.items then return options, "No items" end
|
||||||
queue = queue or {}
|
|
||||||
predicate = predicate or function() return true end
|
local ok, stop = options.slotPredicate(slot, options.itemRef)
|
||||||
itemRef = itemRef or {}
|
if ok then
|
||||||
-- debugPrint(string.format("Enqueuing slot with %d items.", #slot.items))
|
options.slotQueue[#options.slotQueue + 1] = slot
|
||||||
-- We don't want to shadow queue
|
end
|
||||||
local err
|
if stop then return options, "Stop" end
|
||||||
-- If the slot is empty there's nothing to iterate
|
|
||||||
-- And we will naturally return queue as is
|
|
||||||
if not slot then return queue, "No slot" end
|
|
||||||
if not slot.items then return queue, "No items" end
|
|
||||||
|
|
||||||
for _, item in ipairs(slot.items) do
|
for _, item in ipairs(slot.items) do
|
||||||
-- Only the final leaf nodes decide upon the predicate
|
-- We redeclare err every iteration so it doesn't spill over
|
||||||
if loadRefs then
|
|
||||||
itemRef.slot = slot
|
|
||||||
queue, err = enqueueItem(item, queue, predicate, loadRefs, itemRef)
|
|
||||||
else
|
|
||||||
queue, err = enqueueItem(item, queue, predicate)
|
|
||||||
end
|
|
||||||
if err then
|
|
||||||
return queue, err
|
|
||||||
end
|
|
||||||
end
|
|
||||||
-- debugPrint(string.format("Finished enqueuing slot. Current queue size: %d", #queue))
|
|
||||||
return queue
|
|
||||||
end
|
|
||||||
|
|
||||||
---@param inventory Barotrauma.ItemInventory
|
|
||||||
---@param queue Barotrauma.Item[]
|
|
||||||
---@param predicate? FilterPredicate
|
|
||||||
---@param loadRefs? boolean
|
|
||||||
---@param itemRef? ItemRefs
|
|
||||||
---@return Barotrauma.Item[], string?
|
|
||||||
enqueueInventory = function(inventory, queue, predicate, loadRefs, itemRef)
|
|
||||||
queue = queue or {}
|
|
||||||
predicate = predicate or function() return true end
|
|
||||||
itemRef = itemRef or {}
|
|
||||||
-- debugPrint(string.format("Enqueuing inventory with %d slots.", #inventory.slots))
|
|
||||||
local err
|
local err
|
||||||
if not inventory then return queue, "No inventory" end
|
if options.loadRefs then
|
||||||
if not inventory.slots then return queue, "No slots" end
|
options.itemRef.slot = slot
|
||||||
|
options, err = enqueueItem(item, options)
|
||||||
for _, slot in ipairs(inventory.slots) do
|
|
||||||
-- Only the final leaf nodes decide upon the predicate
|
|
||||||
if loadRefs then
|
|
||||||
itemRef.inventory = inventory
|
|
||||||
queue, err = enqueueSlot(slot, queue, predicate, loadRefs, itemRef)
|
|
||||||
else
|
else
|
||||||
queue, err = enqueueSlot(slot, queue, predicate)
|
options, err = enqueueItem(item, options)
|
||||||
end
|
end
|
||||||
if err then
|
if err then
|
||||||
return queue, err
|
return options, err
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
-- debugPrint(string.format("Finished enqueuing inventory. Current queue size: %d", #queue))
|
return options
|
||||||
return queue
|
|
||||||
end
|
end
|
||||||
|
|
||||||
local relevantPlayerInventorySlots = { 6, 7, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, MyModGlobal.BAG_SLOT }
|
---@param inventory Barotrauma.Inventory
|
||||||
---@param queue Barotrauma.Item[]
|
---@param options EnqueueOptions
|
||||||
---@param predicate? FilterPredicate
|
---@return EnqueueOptions, string?
|
||||||
---@param loadRefs? boolean
|
enqueueInventory = function(inventory, options)
|
||||||
---@return Barotrauma.Item[], string?
|
options = ensureOptionsDefaults(options)
|
||||||
allPlayerItems = function(queue, predicate, loadRefs)
|
if not inventory then return options, "No inventory" end
|
||||||
queue = queue or {}
|
if not inventory.slots then return options, "No slots" end
|
||||||
predicate = predicate or function() return true end
|
|
||||||
|
local ok, stop = options.inventoryPredicate(inventory, options.itemRef)
|
||||||
|
if ok then
|
||||||
|
options.inventoryQueue[#options.inventoryQueue + 1] = inventory
|
||||||
|
end
|
||||||
|
if stop then return options, "Stop" end
|
||||||
|
|
||||||
|
for i, slot in ipairs(inventory.slots) do
|
||||||
|
local err
|
||||||
|
if options.loadRefs then
|
||||||
|
options.itemRef.inventory = inventory
|
||||||
|
options.itemRef.slot = slot
|
||||||
|
options.itemRef.slotIndex1 = i
|
||||||
|
options, err = enqueueSlot(slot, options)
|
||||||
|
else
|
||||||
|
options, err = enqueueSlot(slot, options)
|
||||||
|
end
|
||||||
|
if err then
|
||||||
|
return options, err
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return options
|
||||||
|
end
|
||||||
|
|
||||||
|
local relevantPlayerInventorySlots = {
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
true,
|
||||||
|
true,
|
||||||
|
true,
|
||||||
|
true,
|
||||||
|
true,
|
||||||
|
true,
|
||||||
|
true,
|
||||||
|
true,
|
||||||
|
true,
|
||||||
|
true,
|
||||||
|
true,
|
||||||
|
true,
|
||||||
|
true,
|
||||||
|
}
|
||||||
|
---@param options EnqueueOptions
|
||||||
|
---@return EnqueueOptions, string?
|
||||||
|
enqueuePlayerItems = function(options)
|
||||||
|
options = ensureOptionsDefaults(options)
|
||||||
|
|
||||||
local character = Character.Controlled
|
local character = Character.Controlled
|
||||||
if not character then return queue, "No character" end
|
if not character then return options, "No character" end
|
||||||
|
|
||||||
local inventory = character.Inventory
|
local inventory = character.Inventory
|
||||||
if not inventory then return queue, "No inventory" end
|
if not inventory then return options, "No inventory" end
|
||||||
|
|
||||||
|
options.loadRefs = true
|
||||||
|
local originalItemPredicate = options.itemPredicate or function() return true end
|
||||||
|
options.itemPredicate = function(item)
|
||||||
|
if not item then return false end
|
||||||
|
local parentInventory = item.ParentInventory
|
||||||
|
if not parentInventory then return false end
|
||||||
|
if not parentInventory.Equals(inventory) then return false end
|
||||||
|
return originalItemPredicate(item, options.itemRef)
|
||||||
|
end
|
||||||
|
local originalSlotPredicate = options.slotPredicate or function() return true end
|
||||||
|
options.slotPredicate = function(slot, itemRef)
|
||||||
|
if not slot then return false end
|
||||||
|
if itemRef.slotIndex1 and relevantPlayerInventorySlots[itemRef.slotIndex1] then
|
||||||
|
return originalSlotPredicate(slot, itemRef)
|
||||||
|
end
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
|
||||||
for _, slotid in ipairs(relevantPlayerInventorySlots) do
|
|
||||||
local slot = inventory.slots[slotid]
|
|
||||||
local err
|
local err
|
||||||
|
options, err = enqueueInventory(inventory, options)
|
||||||
|
if err then return options, err end
|
||||||
|
|
||||||
if not slot then goto continue end
|
return options
|
||||||
if #slot.items == 0 then goto continue end
|
|
||||||
|
|
||||||
queue, err = enqueueSlot(slot, queue, predicate, loadRefs)
|
|
||||||
if err then return queue, err end
|
|
||||||
|
|
||||||
::continue::
|
|
||||||
end
|
end
|
||||||
|
|
||||||
return queue
|
---@param options EnqueueOptions
|
||||||
end
|
---@return EnqueueOptions, string?
|
||||||
|
enqueueOpenContainers = function(options)
|
||||||
---@param queue Barotrauma.Item[]
|
options = ensureOptionsDefaults(options)
|
||||||
---@param predicate? FilterPredicate
|
|
||||||
---@param loadRefs? boolean
|
|
||||||
---@return Barotrauma.Item[], string?
|
|
||||||
enqueueOpenContainers = function(queue, predicate, loadRefs)
|
|
||||||
queue = queue or {}
|
|
||||||
predicate = predicate or function() return true end
|
|
||||||
|
|
||||||
local containers, err = getOpenContainers()
|
local containers, err = getOpenContainers()
|
||||||
if err then return queue, err end
|
if err then return options, err end
|
||||||
|
|
||||||
for _, container in ipairs(containers) do
|
for _, container in ipairs(containers) do
|
||||||
local inventories = container.OwnInventories
|
local inventories = container.OwnInventories
|
||||||
if not inventories then goto continue end
|
if not inventories then goto continue end
|
||||||
for containerInventory in inventories do
|
for containerInventory in inventories do
|
||||||
queue, err = enqueueInventory(containerInventory, queue, predicate, loadRefs)
|
options, err = enqueueInventory(containerInventory, options)
|
||||||
if err then return queue, err end
|
if err then return options, err end
|
||||||
end
|
end
|
||||||
::continue::
|
::continue::
|
||||||
end
|
end
|
||||||
|
|
||||||
return queue
|
return options
|
||||||
end
|
end
|
||||||
|
|
||||||
---@param queue Barotrauma.Item[]
|
---@param options EnqueueOptions
|
||||||
---@param predicate? FilterPredicate
|
---@return EnqueueOptions, string?
|
||||||
---@return Barotrauma.Item[], string?
|
enqueueSubmarineItems = function(options)
|
||||||
allSubmarineItems = function(queue, predicate)
|
options = ensureOptionsDefaults(options)
|
||||||
queue = queue or {}
|
|
||||||
predicate = predicate or function() return true end
|
|
||||||
-- This only exists so predicate does not explode
|
-- This only exists so predicate does not explode
|
||||||
-- Even if its empty
|
-- Even if its empty
|
||||||
local itemRef = {}
|
local itemRef = {}
|
||||||
|
|
||||||
local character = Character.Controlled
|
local character = Character.Controlled
|
||||||
if not character then return queue, "No character" end
|
if not character then return options, "No character" end
|
||||||
|
|
||||||
local submarine = character.Submarine
|
local submarine = character.Submarine
|
||||||
if not submarine then return queue, "No submarine" end
|
if not submarine then return options, "No submarine" end
|
||||||
|
|
||||||
for item in submarine.GetItems(false) do
|
for item in submarine.GetItems(false) do
|
||||||
-- We do NOT want to call enqueueItem here because enqueueItem
|
-- We do NOT want to call enqueueItem here because enqueueItem
|
||||||
@@ -227,32 +542,30 @@ allSubmarineItems = function(queue, predicate)
|
|||||||
-- And this call (GetItems) already gets all items
|
-- And this call (GetItems) already gets all items
|
||||||
-- So we would be doing double the work (at best case)
|
-- So we would be doing double the work (at best case)
|
||||||
-- It also means we won't have refs here which sucks
|
-- It also means we won't have refs here which sucks
|
||||||
local ok, stop = predicate(item, itemRef)
|
local ok, stop = options.itemPredicate(item, itemRef)
|
||||||
if ok then
|
if ok then
|
||||||
queue[#queue + 1] = item
|
options.itemQueue[#options.itemQueue + 1] = item
|
||||||
end
|
end
|
||||||
if stop then return queue, "Stop" end
|
if stop then return options, "Stop" end
|
||||||
end
|
end
|
||||||
|
|
||||||
return queue
|
return options
|
||||||
end
|
end
|
||||||
|
|
||||||
---@param queue Barotrauma.Item[]
|
---@param options EnqueueOptions
|
||||||
---@param predicate? FilterPredicate
|
---@return EnqueueOptions, string?
|
||||||
---@param loadRefs? boolean
|
enqueueAllOwnedItems = function(options)
|
||||||
---@return Barotrauma.Item[], string?
|
options = ensureOptionsDefaults(options)
|
||||||
allOwnedItems = function(queue, predicate, loadRefs)
|
|
||||||
queue = queue or {}
|
|
||||||
predicate = predicate or function() return true end
|
|
||||||
|
|
||||||
local err
|
local err
|
||||||
queue, err = allPlayerItems(queue, predicate, loadRefs)
|
options, err = enqueuePlayerItems(options)
|
||||||
if err then return queue, err end
|
if err then return options, err end
|
||||||
|
|
||||||
queue, err = allSubmarineItems(queue, predicate)
|
options, err = enqueueSubmarineItems(options)
|
||||||
if err then return queue, err end
|
if err then return options, err end
|
||||||
|
|
||||||
return queue
|
return options
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
-- There is actually no need to recurse deep
|
-- There is actually no need to recurse deep
|
||||||
@@ -260,8 +573,8 @@ end
|
|||||||
-- And not an item in an item in the inventory
|
-- And not an item in an item in the inventory
|
||||||
-- So in theory we only need to recurse 1 deep
|
-- So in theory we only need to recurse 1 deep
|
||||||
---@param inventory Barotrauma.Inventory
|
---@param inventory Barotrauma.Inventory
|
||||||
---@param slots InventorySlot[]
|
---@param slots? InventorySlot[]
|
||||||
---@param depth number
|
---@param depth? number
|
||||||
---@return InventorySlot[], string?
|
---@return InventorySlot[], string?
|
||||||
local function getMouseoverSlots(inventory, slots, depth)
|
local function getMouseoverSlots(inventory, slots, depth)
|
||||||
slots = slots or {}
|
slots = slots or {}
|
||||||
@@ -269,7 +582,7 @@ local function getMouseoverSlots(inventory, slots, depth)
|
|||||||
if depth > 1 then return slots, nil end
|
if depth > 1 then return slots, nil end
|
||||||
|
|
||||||
local visualSlots = inventory.visualSlots
|
local visualSlots = inventory.visualSlots
|
||||||
if not visualSlots then return nil, "Inventory has no visual slots" end
|
if not visualSlots then return slots, "Inventory has no visual slots" end
|
||||||
|
|
||||||
for i, visualSlot in ipairs(visualSlots) do
|
for i, visualSlot in ipairs(visualSlots) do
|
||||||
local item
|
local item
|
||||||
@@ -305,11 +618,8 @@ local function getMouseoverSlots(inventory, slots, depth)
|
|||||||
|
|
||||||
::mouseover::
|
::mouseover::
|
||||||
if visualSlot:MouseOn() then
|
if visualSlot:MouseOn() then
|
||||||
slots[#slots + 1] = {
|
local inventorySlot = MyModGlobal.InventorySlot.new(inventory, i)
|
||||||
inventory = inventory,
|
slots[#slots + 1] = inventorySlot
|
||||||
slotIndex = i,
|
|
||||||
slot = slot
|
|
||||||
}
|
|
||||||
end
|
end
|
||||||
|
|
||||||
::continue::
|
::continue::
|
||||||
@@ -320,15 +630,17 @@ end
|
|||||||
|
|
||||||
---@return InventorySlot[], string?
|
---@return InventorySlot[], string?
|
||||||
local function getSlotsUnderCursor()
|
local function getSlotsUnderCursor()
|
||||||
|
local slots = {}
|
||||||
-- Make sure we have a controlled character
|
-- Make sure we have a controlled character
|
||||||
local controlledCharacter = Character.Controlled
|
local controlledCharacter = Character.Controlled
|
||||||
if not controlledCharacter then return nil, "No controlled character" end
|
if not controlledCharacter then return slots, "No controlled character" end
|
||||||
|
|
||||||
local inventory = controlledCharacter.Inventory
|
local inventory = controlledCharacter.Inventory
|
||||||
if not inventory then return nil, "No inventory" end
|
if not inventory then return slots, "No inventory" end
|
||||||
|
|
||||||
local mouseoverSlots, err = getMouseoverSlots(inventory)
|
local err
|
||||||
if err then return mouseoverSlots, err end
|
slots, err = getMouseoverSlots(inventory, slots)
|
||||||
|
if err then return slots, err end
|
||||||
|
|
||||||
-- Even if we don't get them we're still fine
|
-- Even if we don't get them we're still fine
|
||||||
local openContainers, _ = getOpenContainers()
|
local openContainers, _ = getOpenContainers()
|
||||||
@@ -337,35 +649,30 @@ local function getSlotsUnderCursor()
|
|||||||
for _, container in ipairs(openContainers) do
|
for _, container in ipairs(openContainers) do
|
||||||
local containerInventories = container.OwnInventories
|
local containerInventories = container.OwnInventories
|
||||||
for containerInventory in containerInventories do
|
for containerInventory in containerInventories do
|
||||||
local slot
|
|
||||||
if not containerInventory or not containerInventory.visualSlots then
|
if not containerInventory or not containerInventory.visualSlots then
|
||||||
MyModGlobal.debugPrint("Container inventory has no visual slots")
|
MyModGlobal.debugPrint("Container inventory has no visual slots")
|
||||||
goto continue
|
goto continue
|
||||||
end
|
end
|
||||||
for i, visualSlot in ipairs(containerInventory.visualSlots) do
|
for i, visualSlot in ipairs(containerInventory.visualSlots) do
|
||||||
if visualSlot:MouseOn() then
|
if visualSlot:MouseOn() then
|
||||||
slot = containerInventory.slots[i]
|
local inventorySlot = MyModGlobal.InventorySlot.new(containerInventory, i)
|
||||||
mouseoverSlots[#mouseoverSlots + 1] = {
|
slots[#slots + 1] = inventorySlot
|
||||||
inventory = containerInventory,
|
|
||||||
slotIndex = i,
|
|
||||||
slot = slot
|
|
||||||
}
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
::continue::
|
::continue::
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
return mouseoverSlots, nil
|
return slots, nil
|
||||||
end
|
end
|
||||||
|
|
||||||
---@return InventorySlot, string?
|
---@return InventorySlot, string?
|
||||||
local function getFirstSlotUnderCursor()
|
local function getFirstSlotUnderCursor()
|
||||||
local slots, err = getSlotsUnderCursor()
|
local slots, err = getSlotsUnderCursor()
|
||||||
if err then return nil, err end
|
if err then return slots, err end
|
||||||
if #slots == 0 then return nil, "No slots found under cursor" end
|
if #slots == 0 then return slots, "No slots found under cursor" end
|
||||||
for _, slot in ipairs(slots) do
|
for _, slot in ipairs(slots) do
|
||||||
if slot.slot.items and #slot.slot.items > 0 then
|
if slot.item then
|
||||||
return slot
|
return slot
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -376,12 +683,13 @@ return {
|
|||||||
enqueueItem = enqueueItem,
|
enqueueItem = enqueueItem,
|
||||||
enqueueSlot = enqueueSlot,
|
enqueueSlot = enqueueSlot,
|
||||||
enqueueInventory = enqueueInventory,
|
enqueueInventory = enqueueInventory,
|
||||||
enqueueAllPlayerItems = allPlayerItems,
|
enqueuePlayerItems = enqueuePlayerItems,
|
||||||
enqueueAllSubmarineItems = allSubmarineItems,
|
enqueueSubmarineItems = enqueueSubmarineItems,
|
||||||
enqueueAllOwnedItems = allOwnedItems,
|
enqueueAllOwnedItems = enqueueAllOwnedItems,
|
||||||
enqueueOpenContainers = enqueueOpenContainers,
|
enqueueOpenContainers = enqueueOpenContainers,
|
||||||
getOpenContainers = getOpenContainers,
|
getOpenContainers = getOpenContainers,
|
||||||
getFirstOpenContainer = getFirstOpenContainer,
|
getFirstOpenContainer = getFirstOpenContainer,
|
||||||
getSlotsUnderCursor = getSlotsUnderCursor,
|
getSlotsUnderCursor = getSlotsUnderCursor,
|
||||||
getFirstSlotUnderCursor = getFirstSlotUnderCursor,
|
getFirstSlotUnderCursor = getFirstSlotUnderCursor,
|
||||||
|
enqueueMove = enqueueMove,
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user