diff --git a/core/apis/chestAdapter18.lua b/core/apis/chestAdapter18.lua index f79aadb..71610b8 100644 --- a/core/apis/chestAdapter18.lua +++ b/core/apis/chestAdapter18.lua @@ -137,8 +137,8 @@ function ChestAdapter:provide(item, qty, slot, direction) local stacks = self.list() for key,stack in Util.rpairs(stacks) do if stack.name == item.name and - (not item.damage or stack.damage == item.damage) and - (not item.nbtHash or stack.nbtHash == item.nbtHash) then + stack.damage == item.damage and + stack.nbtHash == item.nbtHash then local amount = math.min(qty, stack.count) if amount > 0 then amount = self.pushItems(direction or self.direction, key, amount, slot) diff --git a/milo/apis/milo.lua b/milo/apis/milo.lua index 7a3fe2a..039eed0 100644 --- a/milo/apis/milo.lua +++ b/milo/apis/milo.lua @@ -19,18 +19,6 @@ function Milo:getContext() return self.context end -function Milo:requestCrafting(item) - local key = Milo:uniqueKey(item) - - if not self.context.craftingQueue[key] then - item.crafted = 0 - item.pending = { } - item.key = key - self.context.craftingQueue[key] = item - os.queueEvent('milo_cycle') - end -end - function Milo:pauseCrafting() self.craftingPaused = true Milo:showError('Crafting Paused') @@ -105,52 +93,33 @@ function Milo:getItem(items, inItem, ignoreDamage, ignoreNbtHash) end end -function Milo:getItemWithQty(res, ignoreDamage, ignoreNbtHash) - local items = self:listItems() - local item = self:getItem(items, res, ignoreDamage, ignoreNbtHash) - local count = 0 - - if item and (ignoreDamage or ignoreNbtHash) then - for _,v in pairs(items) do - if item.name == v.name and - (ignoreDamage or item.damage == v.damage) and - (ignoreNbtHash or item.nbtHash == v.nbtHash) then - count = count + v.count - end - end - elseif item then - count = item.count - end - - return item, count -end - -function Milo:getMatches(items, item, ignoreDamage, ignoreNbtHash) +-- returns a list of items that matches along with a total count +function Milo:getMatches(item, flags) local t = { } + local count = 0 + local items = self:listItems() - if not ignoreDamage and not ignoreNbtHash then + if not flags.ignoreDamage and not flags.ignoreNbtHash then local key = item.key or Milo:uniqueKey(item) - local e = items[key] - if e then - t[key] = Util.shallowCopy(e) + local v = items[key] + if v then + t[key] = Util.shallowCopy(v) + count = v.count end else - for k,v in pairs(items) do + for key,v in pairs(items) do if item.name == v.name and - (ignoreDamage or item.damage == v.damage) and - (ignoreNbtHash or item.nbtHash == v.nbtHash) then - local e = t[k] - if not e then - t[k] = Util.shallowCopy(v) - else - e.count = e.count + item.count - end + (flags.ignoreDamage or item.damage == v.damage) and + (flags.ignoreNbtHash or item.nbtHash == v.nbtHash) then + + t[key] = Util.shallowCopy(v) + count = count + v.count end end end - return t + return t, count end function Milo:clearGrid() @@ -172,6 +141,18 @@ function Milo:getTurtleInventory() return list end +function Milo:requestCrafting(item) + local key = Milo:uniqueKey(item) + + if not self.context.craftingQueue[key] then + item.crafted = 0 + item.pending = { } + item.key = key + self.context.craftingQueue[key] = item + os.queueEvent('milo_cycle') + end +end + -- queue up an action that reliees on the crafting grid function Milo:queueRequest(request, callback) if Util.empty(self.context.queue) then diff --git a/milo/apis/storage.lua b/milo/apis/storage.lua index 08f7576..718e15c 100644 --- a/milo/apis/storage.lua +++ b/milo/apis/storage.lua @@ -256,9 +256,9 @@ function Storage:export(target, slot, count, item) local amount = adapter:provide(item, count, slot, target) if amount > 0 then - _G._debug('EXT: %s(%d): %s -> %s%s', - item.displayName or item.name, amount, sn(adapter.name), sn(target), - slot and string.format('[%d]', slot) or '') + _G._debug('EXT: %s(%d): %s -> %s%s', + item.displayName or item.name, amount, sn(adapter.name), sn(target), + slot and string.format('[%d]', slot) or '[*]') self:updateCache(adapter, key, -amount) self:updateCache(self, key, -amount) @@ -277,8 +277,17 @@ function Storage:export(target, slot, count, item) end end - _G._debug('STORAGE: MISS: %s - %d', key, count) + _G._debug('MISS: %s(%d): %s%s %s', + item.displayName or item.name, count, sn(target), + slot and string.format('[%d]', slot) or '[*]', key) +-- TODO: If there are misses when a slot is specified than something is wrong... +-- The caller should confirm the quantity beforehand +-- If no slot and full amount is not exported, then no need to check rest of adapters +-- ... so should not reach here + + +--[[ -- not found - scan all others for _, adapter in self:onlineAdapters() do if not adapter.cache or not adapter.cache[key] then @@ -289,11 +298,15 @@ function Storage:export(target, slot, count, item) end end end +--]] return total end function Storage:import(source, slot, count, item) + if not source then error('Storage:import: source is required') end + if not slot then error('Storage:import: slot is required') end + local total = 0 local key = item.key or table.concat({ item.name, item.damage, item.nbtHash }, ':') @@ -305,9 +318,9 @@ function Storage:import(source, slot, count, item) local amount = adapter:insert(slot, count, nil, source) if amount > 0 then -_G._debug('INS: %s(%d): %s[%d] -> %s', - item.displayName or item.name, amount, - sn(source), slot, sn(adapter.name)) + _G._debug('INS: %s(%d): %s[%d] -> %s', + item.displayName or item.name, amount, + sn(source), slot, sn(adapter.name)) self:updateCache(adapter, key, amount) self:updateCache(self, key, amount) @@ -347,11 +360,15 @@ _G._debug('INS: %s(%d): %s[%d] -> %s', end if not itemDB:get(item) then - if not slot then + if item.displayName then + -- this item already has metadata + itemDB:add(item) + elseif not slot then _G._debug("IMPORT: NO SLOT") elseif not device[source] or not device[source].getItemMeta then _G._debug("IMPORT: DEVICE? : " .. source) else + -- get the metadata from the device and add to db itemDB:add(device[source].getItemMeta(slot)) end end @@ -374,7 +391,7 @@ function Storage:trash(source, slot, count) local trashcan = Util.find(self.nodes, 'mtype', 'trashcan') if trashcan and trashcan.adapter and trashcan.adapter.online then -_G._debug('TRA: %s[%d] (%d)', sn(source), slot, count or 64) + _G._debug('TRA: %s[%d] (%d)', sn(source), slot, count or 64) return trashcan.adapter.pullItems(source, slot, count) end diff --git a/milo/plugins/exportTask.lua b/milo/plugins/exportTask.lua index 3fa5958..ef00d3f 100644 --- a/milo/plugins/exportTask.lua +++ b/milo/plugins/exportTask.lua @@ -11,64 +11,71 @@ local function filter(a) end function ExportTask:cycle(context) - for machine in context.storage:filterActive('machine', filter) do - for _, entry in pairs(machine.exports) do + for node in context.storage:filterActive('machine', filter) do + for _, entry in pairs(node.exports) do - local function exportSlot(list, slotNo, item, count) - local slot = list[slotNo] or { count = 0 } + if not entry.filter then + -- exports must have a filter + -- TODO: validate in exportView + break + end - if slot.count == 0 or - (slot.name == item.name and - slot.damage == item.damage and - slot.nbtHash == item.nbtHash) then + local function exportSingleSlot() + local slot = node.adapter.getItemMeta(entry.slot) - local maxCount = itemDB:getMaxCount(item) - count = math.min(maxCount - slot.count, count) + if slot and slot.count == slot.maxCount then + return + end - if count > 0 then --- _debug('attempting to export %s %d into slot %d', item.name, count, slotNo) - count = context.storage:export(machine.name, slotNo, count, item) + if slot then + -- something is in the slot, find what we can export + for key in pairs(entry.filter) do + local filterItem = Milo:splitKey(key) + if (slot.name == filterItem.name and + entry.ignoreDamage or slot.damage == filterItem.damage and + entry.ignoreNbtHash or slot.nbtHash == filterItem.nbtHash) then - if count > 0 then - item.count = item.count - count - list[slotNo] = { - name = item.name, - damage = item.damage, - nbtHash = item.nbtHash, - count = count + slot.count, - } - return true + local items = Milo:getMatches(filterItem, entry) + local _, item = next(items) + if item then + local count = math.min(item.count, slot.maxCount - slot.count) + context.storage:export(node.name, entry.slot, count, item) + end + break end end + return + end + + -- slot is empty - export first matching item we have in storage + for key in pairs(entry.filter) do + local items = Milo:getMatches(Milo:splitKey(key), entry) + local _, item = next(items) + if item then + local count = math.min(item.count, itemDB:getMaxCount(item)) + context.storage:export(node.name, entry.slot, count, item) + break + end end end - local list - local function getLazyList() - if not list then - list = machine.adapter.list() - end - return list - end - - for key in pairs(entry.filter or { }) do - local items = Milo:getMatches(Milo:listItems(), itemDB:splitKey(key), entry.ignoreDamage, entry.ignoreNbtHash) - for _,item in pairs(items) do - if item and item.count > 0 then - if type(entry.slot) == 'number' then - if exportSlot(getLazyList(), entry.slot, item, item.count) then - break - end - else --- _debug('attempting to export %s %d', item.name, item.count) --- TODO: always going to try and export even if the chest is full - if context.storage:export(machine.name, nil, item.count, item) == 0 then - break - end + local function exportItems() + for key in pairs(entry.filter) do + local items = Milo:getMatches(itemDB:splitKey(key), entry) + for _,item in pairs(items) do + if context.storage:export(node.name, nil, item.count, item) == 0 then + -- TODO: really shouldn't break here as there may be room in other slots + -- leaving for now for performance reasons + break end end end end + if type(entry.slot) == 'number' then + exportSingleSlot() + else + exportItems() + end end end end diff --git a/milo/plugins/importTask.lua b/milo/plugins/importTask.lua index 059ba89..12517ca 100644 --- a/milo/plugins/importTask.lua +++ b/milo/plugins/importTask.lua @@ -10,8 +10,8 @@ local function filter(a) end function ImportTask:cycle(context) - for inventory in context.storage:filterActive('machine', filter) do - for _, entry in pairs(inventory.imports) do + for node in context.storage:filterActive('machine', filter) do + for _, entry in pairs(node.imports) do local function itemMatchesFilter(item) if not entry.ignoreDamage and not entry.ignoreNbtHash then @@ -41,16 +41,16 @@ function ImportTask:cycle(context) end local function importSlot(slotNo) - local item = inventory.adapter.getItemMeta(slotNo) + local item = node.adapter.getItemMeta(slotNo) if item and matchesFilter(item) then - context.storage:import(inventory.name, slotNo, item.count, item) + context.storage:import(node.name, slotNo, item.count, item) end end if type(entry.slot) == 'number' then importSlot(entry.slot) else - for i = 1, inventory.adapter.size() do + for i in pairs(node.adapter.list()) do importSlot(i) end end diff --git a/milo/plugins/limitTask.lua b/milo/plugins/limitTask.lua index 30a5270..ec072d4 100644 --- a/milo/plugins/limitTask.lua +++ b/milo/plugins/limitTask.lua @@ -9,16 +9,21 @@ function LimitTask:cycle(context) local trashcan = context.storage:filterActive('trashcan')() if trashcan then - for k,res in pairs(context.resources) do + for key,res in pairs(context.resources) do if res.limit then --- TODO: change to export method of finding items (maybe) - local item, count = Milo:getItemWithQty(Milo:splitKey(k), res.ignoreDamage, res.ignoreNbtHash) - if item and count > res.limit then - context.storage:export( - trashcan.name, - nil, - count - res.limit, - item) + local items, count = Milo:getMatches(Milo:splitKey(key), res) + if count > res.limit then + local amount = count - res.limit + for _, item in pairs(items) do + amount = amount - context.storage:export( + trashcan.name, + nil, + math.min(amount, item.count), + item) + if amount <= 0 then + break + end + end end end end diff --git a/milo/plugins/replenishTask.lua b/milo/plugins/replenishTask.lua index 3a8c36c..ec8b5a2 100644 --- a/milo/plugins/replenishTask.lua +++ b/milo/plugins/replenishTask.lua @@ -1,4 +1,3 @@ -local itemDB = require('itemDB') local Milo = require('milo') local ReplenishTask = { @@ -9,30 +8,22 @@ local ReplenishTask = { function ReplenishTask:cycle(context) for k,res in pairs(context.resources) do if res.low then - local key = Milo:splitKey(k) - local item, count = Milo:getItemWithQty(key, res.ignoreDamage, res.ignoreNbtHash) - if not item then - item = { - damage = key.damage, - nbtHash = key.nbtHash, - name = key.name, - displayName = itemDB:getName(key), - count = 0 - } - end + local item = Milo:splitKey(k) + item.key = k + + local _, count = Milo:getMatches(item, res) if count < res.low then - local nbtHash = item.nbtHash - if res.ignoreNbtHash then - nbtHash = nil + local nbtHash + if not res.ignoreNbtHash then + nbtHash = item.nbtHash end Milo:requestCrafting({ + name = item.name, damage = res.ignoreDamage and 0 or item.damage, nbtHash = nbtHash, requested = res.low - count, count = count, - name = item.name, - displayName = item.displayName, replenish = true, }) else