Implement quick unload
This commit is contained in:
@@ -16,6 +16,7 @@ MyModGlobal = {
|
||||
FABRICATOR_KEY = Keys.V,
|
||||
MAX_BUY = Keys.B,
|
||||
FIX = Keys.R,
|
||||
UNLOAD = Keys.E,
|
||||
NESTED_CONTAINERS = true,
|
||||
DEBUG_MODE = true,
|
||||
},
|
||||
@@ -56,6 +57,7 @@ local fabricatorstack = require("Cyka.fabricatorstack")
|
||||
local quickbuy = require("Cyka.quickbuy")
|
||||
local hotkeyrepair = require("Cyka.hotkeyrepair")
|
||||
local cursormacroer = require("Cyka.cursormacroer")
|
||||
local quickunload = require("Cyka.quickunload")
|
||||
require("Cyka.xpticker")
|
||||
|
||||
print(MyModGlobal.MOD_NAME .. " v" .. MyModGlobal.MOD_VERSION .. " loaded!")
|
||||
@@ -111,3 +113,8 @@ Hook.Patch("Barotrauma.Character", "ControlLocalPlayer", function(instance, ptab
|
||||
-- if not PlayerInput.PrimaryMouseButtonClicked() then return end
|
||||
cursormacroer.tryStackCursorItem()
|
||||
end, Hook.HookMethodType.After)
|
||||
|
||||
Hook.Patch("Barotrauma.Character", "ControlLocalPlayer", function(instance, ptable)
|
||||
if not PlayerInput.KeyHit(MyModGlobal.CONFIG.UNLOAD) then return end
|
||||
quickunload.tryUnloadCursorItem()
|
||||
end, Hook.HookMethodType.After)
|
@@ -228,5 +228,6 @@ end
|
||||
|
||||
return {
|
||||
tryStackCursorItem = tryStackCursorItem,
|
||||
setTargetInventory = setTargetInventory
|
||||
setTargetInventory = setTargetInventory,
|
||||
getInventorySlotsUnderCursor = getInventorySlotsUnderCursor
|
||||
}
|
||||
|
24
QuickStackToBag/Lua/Cyka/dump.lua
Normal file
24
QuickStackToBag/Lua/Cyka/dump.lua
Normal file
@@ -0,0 +1,24 @@
|
||||
---@param table table
|
||||
---@param depth number?
|
||||
local function dump(table, depth)
|
||||
if depth == nil then
|
||||
depth = 0
|
||||
end
|
||||
if (depth > 200) then
|
||||
print("Error: Depth > 200 in dumpTable()")
|
||||
return
|
||||
end
|
||||
if (type(table) ~= "table") then
|
||||
return tostring(table)
|
||||
end
|
||||
for k, v in pairs(table) do
|
||||
if (type(v) == "table") then
|
||||
print(string.rep(" ", depth) .. tostring(k) .. ":")
|
||||
dump(v, depth + 1)
|
||||
else
|
||||
print(string.rep(" ", depth) .. tostring(k) .. ": " .. tostring(v))
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
return dump
|
181
QuickStackToBag/Lua/Cyka/quickunload.lua
Normal file
181
QuickStackToBag/Lua/Cyka/quickunload.lua
Normal file
@@ -0,0 +1,181 @@
|
||||
-- luacheck: globals Character MyModGlobal Timer
|
||||
local cursormacroer = require("Cyka.cursormacroer")
|
||||
local dump = require("Cyka.dump")
|
||||
|
||||
---@class InventorySlot
|
||||
---@field slot Barotrauma.ItemSlot
|
||||
---@field inventory Barotrauma.ItemInventory
|
||||
---@field slotIndex number
|
||||
|
||||
---@param inventory Barotrauma.ItemInventory
|
||||
---@param predicate fun(slot: InventorySlot): boolean
|
||||
---@return InventorySlot[], string?
|
||||
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 inventorySlots = inventory.slots
|
||||
for _, inventorySlot in ipairs(inventorySlots) do
|
||||
for _, inventoryItem in ipairs(inventorySlot.items) do
|
||||
toUnload[#toUnload + 1] = inventoryItem
|
||||
-- This will only serve as O(1) lookup
|
||||
toUnloadByPrefab[inventoryItem.Prefab] = true
|
||||
end
|
||||
end
|
||||
|
||||
-- Where can we put our toUnload items?
|
||||
local nearbySlots = findSlotsThat(slot.inventory, function(islot)
|
||||
local isEmpty = #islot.slot.items == 0
|
||||
if isEmpty then return true end
|
||||
|
||||
for _, prefab in ipairs(toUnloadByPrefab) do
|
||||
local canAccept = islot.inventory.CanBePutInSlot(prefab, islot.slotIndex)
|
||||
if canAccept then return true end
|
||||
end
|
||||
return false
|
||||
end)
|
||||
-- print("Before sorting:")
|
||||
-- dump(nearbySlots)
|
||||
|
||||
table.sort(nearbySlots, function(a, b)
|
||||
local distanceA = math.abs(a.slotIndex - slot.slotIndex)
|
||||
local distanceB = math.abs(b.slotIndex - slot.slotIndex)
|
||||
return distanceA < distanceB
|
||||
end)
|
||||
-- print("After sorting:")
|
||||
-- dump(nearbySlots)
|
||||
|
||||
for _, iitem in ipairs(toUnload) do
|
||||
for _, nearbySlot in ipairs(nearbySlots) do
|
||||
local canAccept = nearbySlot.inventory.CanBePutInSlot(iitem.Prefab, nearbySlot.slotIndex)
|
||||
if canAccept then
|
||||
local moved = nearbySlot.inventory.TryPutItem(iitem, nearbySlot.slotIndex, true, false, nil)
|
||||
if moved then break end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function tryUnloadCursorItem()
|
||||
local slots, err = cursormacroer.getInventorySlotsUnderCursor()
|
||||
if err then
|
||||
-- MyModGlobal.debugPrint(string.format("Error getting inventory slot: %s", err))
|
||||
return
|
||||
end
|
||||
|
||||
if not slots or #slots == 0 then
|
||||
-- MyModGlobal.debugPrint("No items in slot")
|
||||
return
|
||||
end
|
||||
|
||||
for _, slot in ipairs(slots) do
|
||||
tryUnloadSlot(slot)
|
||||
end
|
||||
|
||||
-- local canAccept = inventorySlot.CanBePutInSlot(item, inventorySlot.slotIndex, item.Condition)
|
||||
-- if canAccept then
|
||||
-- toUnload[#toUnload + 1] = inventoryItem
|
||||
-- end
|
||||
-- local slots = findSlotsThat(inventory, function(slot)
|
||||
-- local canAccept
|
||||
-- end)
|
||||
|
||||
-- local inventory = targetInventory
|
||||
-- -- MyModGlobal.debugPrint(string.format("Target inventory: %s", tostring(inventory)))
|
||||
-- if not inventory then
|
||||
-- local controlledCharacter = Character.Controlled
|
||||
-- if not controlledCharacter then
|
||||
-- -- MyModGlobal.debugPrint("No controlled character found")
|
||||
-- return
|
||||
-- end
|
||||
-- local cinventory = controlledCharacter.Inventory
|
||||
-- if not cinventory or not cinventory.slots then
|
||||
-- -- MyModGlobal.debugPrint("No inventory found")
|
||||
-- return
|
||||
-- end
|
||||
-- local bagSlot = cinventory.slots[MyModGlobal.BAG_SLOT]
|
||||
-- if not bagSlot or not bagSlot.items or not bagSlot.items[1] then
|
||||
-- -- MyModGlobal.debugPrint("No bag slot found")
|
||||
-- return
|
||||
-- end
|
||||
-- local bagItem = bagSlot.items[1]
|
||||
-- if not bagItem or not bagItem.OwnInventory then
|
||||
-- -- MyModGlobal.debugPrint("Bag item has no own inventory")
|
||||
-- return
|
||||
-- end
|
||||
-- local bagInventory = bagItem.OwnInventory
|
||||
-- if not bagInventory or not bagInventory.slots then
|
||||
-- -- MyModGlobal.debugPrint("Bag inventory has no slots")
|
||||
-- return
|
||||
-- end
|
||||
-- inventory = bagInventory
|
||||
-- end
|
||||
-- if not inventory then
|
||||
-- -- MyModGlobal.debugPrint("No inventory found")
|
||||
-- return
|
||||
-- end
|
||||
|
||||
-- local itemTree
|
||||
-- itemTree, err = quickstack.buildItemTree(inventory)
|
||||
-- if err then
|
||||
-- -- MyModGlobal.debugPrint(string.format("Error building item tree: %s", err))
|
||||
-- return
|
||||
-- end
|
||||
-- itemTree = quickstack.sortItemTree(itemTree)
|
||||
|
||||
-- local itemsToMove = {}
|
||||
-- local now = Timer.GetTime()
|
||||
-- for _, slot in ipairs(slots) do
|
||||
-- local runAfter = slotThrottle[slot] or 0
|
||||
-- if now < runAfter then
|
||||
-- goto continue
|
||||
-- end
|
||||
-- -- MyModGlobal.debugPrint(string.format("Enqueuing slot: %s, before: %d", tostring(slot), #itemsToMove))
|
||||
-- utils.enqueueSlot(slot.slot, itemsToMove)
|
||||
-- -- MyModGlobal.debugPrint(string.format("Enqueuing slot: %s, after: %d", tostring(slot), #itemsToMove))
|
||||
-- slotThrottle[slot] = now + 1
|
||||
-- ::continue::
|
||||
-- end
|
||||
-- -- for _, item in ipairs(itemsToMove) do
|
||||
-- -- MyModGlobal.debugPrint(string.format("Enqueued item: %s", tostring(item)))
|
||||
-- -- end
|
||||
-- -- -- MyModGlobal.debugPrint(string.format("Enqueued %d items from the inventory slot", #itemsToMove))
|
||||
-- -- MyModGlobal.DumpTable(itemTree)
|
||||
|
||||
-- quickstack.tryMoveItems(itemsToMove, itemTree, true)
|
||||
-- -- local errors = quickstack.tryMoveItems(itemsToMove, itemTree, true)
|
||||
-- -- for _, error in ipairs(errors) do
|
||||
-- -- MyModGlobal.debugPrint(string.format("Error moving item: %s", error))
|
||||
-- -- end
|
||||
end
|
||||
|
||||
return {
|
||||
tryUnloadCursorItem = tryUnloadCursorItem,
|
||||
}
|
71
QuickStackToBag/Lua/Cyka/scratch.lua
Normal file
71
QuickStackToBag/Lua/Cyka/scratch.lua
Normal file
@@ -0,0 +1,71 @@
|
||||
function prettyPrint(value)
|
||||
local function helper(val, indent, visited)
|
||||
-- Handle non-tables and non-userdata
|
||||
if type(val) ~= 'table' and type(val) ~= 'userdata' then
|
||||
return tostring(val)
|
||||
end
|
||||
|
||||
-- Detect cycles (tables or userdata)
|
||||
if visited[val] then
|
||||
return "{...}"
|
||||
end
|
||||
visited[val] = true
|
||||
|
||||
-- Check if it's iterable (table or userdata with __pairs)
|
||||
local is_iterable = false
|
||||
local iterator_func = nil
|
||||
|
||||
if type(val) == 'table' then
|
||||
is_iterable = true
|
||||
iterator_func = pairs
|
||||
elseif type(val) == 'userdata' then
|
||||
-- Check for __pairs metamethod (Lua 5.2+)
|
||||
local mt = debug.getmetatable(val)
|
||||
if mt and mt.__pairs then
|
||||
is_iterable = true
|
||||
iterator_func = mt.__pairs(val)
|
||||
end
|
||||
end
|
||||
|
||||
-- If not iterable, just return tostring
|
||||
if not is_iterable then
|
||||
visited[val] = nil -- Clean up visited
|
||||
return tostring(val)
|
||||
end
|
||||
|
||||
-- Build key-value pairs
|
||||
local entries = {}
|
||||
local nextIndent = indent + 1
|
||||
for k, v in iterator_func(val) do
|
||||
local keyStr = helper(k, nextIndent, visited)
|
||||
local valStr = helper(v, nextIndent, visited)
|
||||
local entry = string.rep(" ", nextIndent) .. keyStr .. ": " .. valStr
|
||||
table.insert(entries, entry)
|
||||
end
|
||||
|
||||
-- Format output
|
||||
local result = "{\n"
|
||||
if #entries > 0 then
|
||||
result = result .. table.concat(entries, ",\n") .. "\n"
|
||||
end
|
||||
result = result .. string.rep(" ", indent) .. "}"
|
||||
|
||||
visited[val] = nil -- Allow reuse in different branches
|
||||
return result
|
||||
end
|
||||
|
||||
print(helper(value, 0, {}))
|
||||
end
|
||||
|
||||
local test = {
|
||||
numbers = { 1, 2, 3 },
|
||||
nested = {
|
||||
a = "apple",
|
||||
b = { c = "cherry" }
|
||||
},
|
||||
func = function() end,
|
||||
self = nil
|
||||
}
|
||||
test.self = test
|
||||
|
||||
prettyPrint(test)
|
Reference in New Issue
Block a user