Implement basic inventory scanning and transfer

This commit is contained in:
Gabriel Tofvesson 2025-05-15 02:16:23 +02:00
commit 33ac91e24b
4 changed files with 287 additions and 0 deletions

42
item.lua Normal file
View File

@ -0,0 +1,42 @@
local util = require("util")
local item = {}
local metatable = {
__eq = util.deepEqual,
__metatable = nil,
__tostring = function(ser)
return textutils.serialise(ser, { compact = true })
end
}
function item.fromDetail(detail)
local detailItem = {
name = detail.name,
displayName = detail.displayName,
tags = detail.tags,
itemGroups = detail.itemGroups,
maxCount = detail.maxCount
}
setmetatable(detailItem, metatable)
return detailItem
end
function item.fromString(str)
local strItem = textutils.unserialize(str)
if type(strItem.name) ~= "string" or
type(strItem.displayName) ~= "string" or
type(strItem.tags) ~= "table" or
type(strItem.itemGroups) ~= "table" or
type(strItem.maxCount) ~= "number" then
error("Could not parse item: "..str)
end
setmetatable(strItem, metatable)
return strItem
end
return item

83
itemstack.lua Normal file
View File

@ -0,0 +1,83 @@
local item = require("item")
local itemstack = {}
local prototype = {}
function prototype:isBlank()
return self.item == nil
end
function prototype:availableCount()
return self.itemLimit - self.count
end
function prototype:canTransferTo(otherStack)
if self:isBlank() or self.item ~= otherStack.item then
return 0
end
local availableCount = otherStack:availableCount()
if availableCount >= self.count then
return self.count
end
return availableCount
end
local metatable = {
__eq = function(a, b)
return a.item == b.item and
a.count == b.count and
a.itemLimit == b.itemLimit
end,
__metatable = nil,
__index = prototype,
__tostring = function(ser)
return textutils.serialise({
item = tostring(ser.item),
count = ser.count,
itemLimit = ser.itemLimit
}, { compact = true })
end
}
local function newItemStack(itemInst, count, itemLimit)
local stack = {
item = itemInst,
count = count,
itemLimit = itemLimit
}
setmetatable(stack, metatable)
return stack
end
function itemstack.blank(itemLimit)
return newItemStack(nil, 0, itemLimit)
end
function itemstack.fromItemDetail(detail, itemLimit)
if detail == nil then
return itemstack.blank(itemLimit)
end
return newItemStack(item.fromDetail(detail), detail.count, itemLimit)
end
function itemstack.fromString(str)
local strStack = textutils.unserialize(str)
if type(strStack.item) ~= "string" or
type(strStack.count) ~= "number" or
type(strStack.itemLimit) ~= "number" then
error("Could not parse itemstack: "..str)
end
strStack.item = item.fromString(strStack.item)
setmetatable(strStack, metatable)
return strStack
end
return itemstack

134
localchest.lua Normal file
View File

@ -0,0 +1,134 @@
local itemstack = require("itemstack")
local localchest = {}
local prototype = {}
function prototype:exists()
return self.peripheral.size() ~= nil
end
function prototype:scanSlot(slot)
local stack = itemstack.fromItemDetail(self.peripheral.getItemDetail(slot), self.peripheral.getItemLimit(slot))
self.slots[slot] = stack
return stack
end
function prototype:rescan()
if not self:exists() then
return false
end
self.slots = {}
self.size = self.peripheral.size()
for key,_ in pairs(self.peripheral.list()) do
self:scanSlot(key)
end
return true
end
function prototype:sanityCheck()
if not self:exists() then
return false
end
local listData = self.peripheral.list()
for key,_ in pairs(self.slots) do
if listData[key] == nil then
return false
end
end
for key,stackData in pairs(listData) do
local cachedStack = self.slots[key]
if cachedStack == nil or cachedStack.item.name ~= stackData.name or cachedStack.count ~= stackData.count then
return false
end
end
return true
end
function prototype:getSlot(slot)
local stack = self.slots[slot]
if stack == nil then
return itemstack.blank(self.peripheral.getItemLimit(slot))
end
return stack
end
function prototype:moveItemsTo(count, fromSlot, otherChest, toSlot)
if not otherChest:exists() then
return 0
end
local myStack = self:getSlot(fromSlot)
local targetStack = otherChest:getSlot(toSlot)
local txCap = myStack:canTransferTo(targetStack)
if count > txCap then
return 0
end
local tx = self.peripheral.pushItems(peripheral.getName(otherChest.peripheral), fromSlot, count, toSlot)
myStack.count = myStack.count - tx
targetStack.count = targetStack.count + tx
return tx
end
local metatable = {
__index = prototype,
__metatable = nil,
__tostring = function(ser)
local slots = {}
for key,value in pairs(ser.slots) do
slots[key] = tostring(value)
end
return textutils.serialise({
peripheral = peripheral.getName(ser.peripheral),
slots = slots,
size = ser.size
}, { compact = true })
end
}
function localchest.fromPeripheral(per)
local chest = {
peripheral = per,
slots = {},
size = 0
}
setmetatable(chest, metatable)
return chest
end
function localchest.fromString(str)
local chest = textutils.unserialize(str)
if type(chest.peripheral) ~= "string" or
type(chest.slots) ~= "table" or
type(chest.size) ~= "number" then
error("Could not parse localchest: "..str)
end
local per = peripheral.wrap(chest.peripheral)
if per == nil then
error("Could not wrap peripheral for chest: "..chest.peripheral)
end
chest.peripheral = per
for key,value in pairs(chest.slots) do
chest.slots[key] = itemstack.fromString(value)
end
setmetatable(chest, metatable)
return chest
end
return localchest

28
util.lua Normal file
View File

@ -0,0 +1,28 @@
local util = {}
function util.deepEqual(a, b)
local varType = type(a)
if varType ~= type(b) then
return false
end
if varType == "table" then
for key,_ in pairs(b) do
if a[key] == nil then
return false
end
end
for key,value in pairs(a) do
if not util.deepEqual(value, b[key]) then
return false
end
end
return true
end
return a == b
end
return util