commit 33ac91e24bf77d05f5db3649435ca142b5908084 Author: Gabriel Tofvesson Date: Thu May 15 02:16:23 2025 +0200 Implement basic inventory scanning and transfer diff --git a/item.lua b/item.lua new file mode 100644 index 0000000..dec3830 --- /dev/null +++ b/item.lua @@ -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 \ No newline at end of file diff --git a/itemstack.lua b/itemstack.lua new file mode 100644 index 0000000..c37f0ae --- /dev/null +++ b/itemstack.lua @@ -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 \ No newline at end of file diff --git a/localchest.lua b/localchest.lua new file mode 100644 index 0000000..49c83f0 --- /dev/null +++ b/localchest.lua @@ -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 \ No newline at end of file diff --git a/util.lua b/util.lua new file mode 100644 index 0000000..ce7c0f2 --- /dev/null +++ b/util.lua @@ -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 \ No newline at end of file