Implement storage slot defragmentation

This commit is contained in:
Gabriel Tofvesson 2025-05-15 17:14:39 +02:00
parent c9ac64d6c5
commit 3dabc55825
5 changed files with 130 additions and 3 deletions

View File

@ -4,7 +4,6 @@ local item = {}
local metatable = { local metatable = {
__eq = util.deepEqual, __eq = util.deepEqual,
__metatable = nil,
__tostring = function(ser) __tostring = function(ser)
return textutils.serialise(ser, { compact = true }) return textutils.serialise(ser, { compact = true })
end end

View File

@ -30,7 +30,6 @@ local metatable = {
a.count == b.count and a.count == b.count and
a.itemLimit == b.itemLimit a.itemLimit == b.itemLimit
end, end,
__metatable = nil,
__index = prototype, __index = prototype,
__tostring = function(ser) __tostring = function(ser)
return textutils.serialise({ return textutils.serialise({

View File

@ -87,9 +87,12 @@ function prototype:moveItemsTo(count, fromSlot, otherChest, toSlot)
return tx return tx
end end
function prototype:getIdentifier()
return peripheral.getName(self.peripheral)
end
local metatable = { local metatable = {
__index = prototype, __index = prototype,
__metatable = nil,
__tostring = function(ser) __tostring = function(ser)
local slots = {} local slots = {}
for key,value in pairs(ser.slots) do for key,value in pairs(ser.slots) do

117
stackgroup.lua Normal file
View File

@ -0,0 +1,117 @@
local util = require("util")
local stackgroup = {}
local prototype = {}
local metatable = {}
function prototype:defragment(chests)
table.sort(self, function(a, b) return a.count < b.count end)
local resultGroup = {
item = self.item,
total = self.total
}
setmetatable(resultGroup, metatable)
local top = #self
local bottom = 1
-- Find largest non-full stack
for i=top,bottom,-1 do
local entry = self[i]
if entry:getStack(chests).availableCount() ~= 0 then
top = i
break
else
resultGroup[#resultGroup + 1] = entry
end
end
while top > bottom do
local topEntry = self[top]
local bottomEntry = self[bottom]
local txCap = math.min(bottomEntry.count, topEntry:getStack(chests).availableCount())
local tx = bottomEntry:getChest(chests):moveItemsTo(txCap, bottomEntry.slot, topEntry:getChest(chests), topEntry.slot)
if tx ~= txCap then
error("Safe inventory transfer failed unexpectedly: "..textutils.serialise({
from = { chest = bottomEntry:getChest(chests):getIdentifier(), slot = bottomEntry.slot },
to = { chest = topEntry:getChest(chests):getIdentifier(), slot = topEntry.slot },
txExpected = txCap,
txActual = tx
}))
end
bottomEntry.count = bottomEntry.count - tx
topEntry.count = topEntry.count + tx
if bottomEntry.count == 0 then
bottom = bottom + 1
end
if topEntry:getStack(chests).availableCount() == 0 then
top = top - 1
resultGroup[#resultGroup + 1] = topEntry
end
end
if top == bottom and self[top].count > 0 then
resultGroup[#resultGroup+1] = self[top]
end
return resultGroup
end
metatable.__index = prototype
local groupEntryPrototype = {}
function groupEntryPrototype:getStack(chests)
return self:getChest(chests).slots[self.slot]
end
function groupEntryPrototype:getChest(chests)
return chests[self.chestIndex]
end
local groupEntryMetatable = {
__index = groupEntryPrototype
}
function stackgroup.fromChests(...)
local chests = { ... }
local groups = {}
local outGroups = {}
for chestIndex,chest in ipairs(chests) do
for slotKey,slot in pairs(chest.slots) do
local group = util.find(groups, function(value) return value.item == slot.item end)
if group == nil then
group = {
item = slot.item,
total = 0
}
setmetatable(group, metatable)
groups[#groups + 1] = group
end
local entry = {
chestIndex = chestIndex,
slot = slotKey,
count = slot.count
}
setmetatable(entry, groupEntryMetatable)
group[#group + 1] = entry
group.total = group.total + slot.count
end
end
return outGroups
end
return stackgroup

View File

@ -25,4 +25,13 @@ function util.deepEqual(a, b)
return a == b return a == b
end end
function util.find(array, f)
for _,v in pairs(array) do
if f(v) then
return v
end
end
return nil
end
return util return util