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 = {} 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 groups end return stackgroup