134 lines
4.0 KiB
Lua
134 lines
4.0 KiB
Lua
local util = require("util")
|
|
|
|
local stackgroup = {}
|
|
local prototype = {}
|
|
|
|
function prototype:defragment(chests)
|
|
table.sort(self, function(a, b) return a.count < b.count end)
|
|
|
|
local top = #self
|
|
|
|
-- Find largest non-full stack
|
|
for i=top,1,-1 do
|
|
local entry = self[i]
|
|
if entry:getStack(chests):availableCount() ~= 0 then
|
|
top = i
|
|
break
|
|
end
|
|
end
|
|
|
|
while top > 1 do
|
|
local topEntry = self[top]
|
|
local bottomEntry = self[1]
|
|
|
|
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
|
|
top = top - 1
|
|
table.remove(self, 1)
|
|
end
|
|
|
|
if topEntry:getStack(chests):availableCount() == 0 then
|
|
top = top - 1
|
|
end
|
|
end
|
|
end
|
|
|
|
function prototype:moveItemsToPeripheral(chests, count, per, slot)
|
|
if count > self.total then
|
|
error("Insufficient items available to transfer to peripheral: "..textutils.serialise({
|
|
available = self.total,
|
|
count = count
|
|
}))
|
|
end
|
|
table.sort(self, function(a, b) return a.count < b.count end)
|
|
|
|
local totalMoved = 0
|
|
while totalMoved < count do
|
|
local currentSlot = self[1]
|
|
local txCap = math.min(currentSlot.count, count - totalMoved)
|
|
local tx = currentSlot:getChest(chests):moveItemsToPeripheral(txCap, currentSlot.slot, per, slot)
|
|
|
|
if tx == 0 then
|
|
error("Unexpected error when transferring items to peripheral: "..textutils.serialise({
|
|
expected = txCap,
|
|
from = { chest = currentSlot:getChest(chests):getIdentifier(), count = currentSlot.count },
|
|
to = { peripheral = peripheral.getName(per) }
|
|
}))
|
|
end
|
|
|
|
self.total = self.total - tx
|
|
totalMoved = totalMoved + tx
|
|
if tx == currentSlot.count then
|
|
table.remove(self, 1)
|
|
end
|
|
end
|
|
end
|
|
|
|
local groupEntryPrototype = {}
|
|
|
|
function groupEntryPrototype:getStack(chests)
|
|
return self:getChest(chests).slots[self.slot]
|
|
end
|
|
|
|
function groupEntryPrototype:getChest(chests)
|
|
return chests[self.chestIndex]
|
|
end
|
|
|
|
local stackgroupSetPrototype = {}
|
|
function stackgroupSetPrototype:findGroup(item)
|
|
return util.find(self, function(group) return group.item == item end)
|
|
end
|
|
|
|
function stackgroupSetPrototype:findAllGroups(groupPattern)
|
|
return util.findAll(self, function(group) return util.fuzzyEquals(group, groupPattern) end)
|
|
end
|
|
|
|
function stackgroup.fromChests(...)
|
|
local chests = { ... }
|
|
local groups = {}
|
|
setmetatable(groups, { __index = stackgroupSetPrototype })
|
|
|
|
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, { __index = prototype })
|
|
|
|
groups[#groups + 1] = group
|
|
end
|
|
|
|
local entry = {
|
|
chestIndex = chestIndex,
|
|
slot = slotKey,
|
|
count = slot.count
|
|
}
|
|
setmetatable(entry, { __index = groupEntryPrototype })
|
|
|
|
group[#group + 1] = entry
|
|
group.total = group.total + slot.count
|
|
end
|
|
end
|
|
|
|
return groups
|
|
end
|
|
|
|
return stackgroup |