2024-10-12 07:37:07 +02:00

180 lines
3.6 KiB
Lua

local ItemStack = require("storage.itemstack")
local Sentinel = require("storage.sentinel")
local Chest = Sentinel:tag({}, Sentinel.CHEST)
Chest.__index = Chest
-- Homogeneity allows chest scan to clone empty itemDetail slot to all empty slots in chest
function Chest:fromPeripheral(chest, homogeneous)
if type(chest) == "string" then
local chestResult = peripheral.wrap(chest)
if chestResult == nil then
chestResult = peripheral.find(chest)
end
chest = chestResult
end
if chest == nil then
return nil
end
local obj = {
name = peripheral.getName(chest),
chest = chest,
size = chest.size(),
homogeneous = homogeneous
}
setmetatable(obj, self)
obj.__index = obj
obj:rescan()
return obj
end
function Chest:rescan()
-- Clear stack data
for i=1,self:getSize() do
self[i] = nil
end
self.size = self.chest.size()
local emptyStack = nil
local listData = self.chest.list()
for i=1,self:getSize() do
local data = listData[i]
local stack
if data == nil and self.homogeneous then
-- Empty stack
if emptyStack == nil then
emptyStack = ItemStack:fromDetail(self.chest, self.chest.getItemDetail(i), i)
if not emptyStack:isEmpty() then
error("Expected empty stack detail, but got populated stack!")
end
end
stack = emptyStack:clone(i)
else
stack = ItemStack:fromDetail(self.chest, self.chest.getItemDetail(i), i)
end
self[i] = stack
end
end
function Chest:toSerializable()
local ser = {
name = self:getName(),
size = self:getSize(),
homogeneous = self.homogeneous
}
local skipEmpty = false
for i,v in ipairs(self) do
local stackSer = v:toSerializable()
-- Skip all but the first homogeneous slot
if v:isEmpty() then
if skipEmpty then
goto continue
end
skipEmpty = self.homogeneous
end
ser[i] = stackSer
::continue::
end
return ser
end
function Chest:fromSerializable(ser, inv)
-- Auto-wrap if inventory is not supplied
if inv == nil then
inv = peripheral.wrap(ser.name)
if inv == nil then
return nil
end
end
local obj = {
name = ser.name,
size = ser.size,
homogeneous = ser.homogeneous,
chest = inv
}
local emptyStack = nil
for i=1,ser.size do
local stackSer = ser[i]
local stack
if stackSer == nil then
if emptyStack == nil then
-- Missing inventory slot data! Must get item detail
stack = ItemStack:fromDetail(inv, inv.getItemDetail(i), i)
else
stack = emptyStack:clone(i)
end
else
stack = ItemStack:fromSerializable(stackSer, inv)
end
if ser.homogeneous and emptyStack == nil and stack:isEmpty() then
emptyStack = stackSer
end
obj[i] = stack
end
setmetatable(obj, self)
obj.__index = obj
return obj
end
function Chest:hasChanged(thorough)
local mySize = self:getSize()
if mySize ~= self.chest.size() then
return true
end
local listData = self.chest.list()
for i=1,mySize do
if (listData[i] == nil) ~= (self[i] == nil) then
return true
end
if listData[i] ~= nil and self[i]:hasChanged(listData[i], thorough) then
return true
end
end
return false
end
function Chest:getSize()
return self.size
end
function Chest:getName()
return self.name
end
function Chest:getInventory()
return self.chest
end
function Chest:find(query)
local result = {}
for i=1,self:getSize() do
if self[i]:matches(query) then
table.insert(result, self[i])
end
end
return result
end
return Chest