diff --git a/apis/chestAdapter.lua b/apis/chestAdapter.lua index 71bffc9..ce879ba 100644 --- a/apis/chestAdapter.lua +++ b/apis/chestAdapter.lua @@ -110,7 +110,7 @@ function ChestAdapter:listItems(throttle) return items end else - debug(m) + _debug(m) end end diff --git a/apis/meAdapter.lua b/apis/meAdapter.lua index af7d1af..41d12bd 100644 --- a/apis/meAdapter.lua +++ b/apis/meAdapter.lua @@ -102,7 +102,7 @@ function MEAdapter:refresh() itemDB:flush() if not s and m then - debug(m) + _debug(m) end if s and not failed and hasItems and self.items and not Util.empty(self.items) then diff --git a/apis/refinedAdapter.lua b/apis/refinedAdapter.lua index 6739a74..b0d84c1 100644 --- a/apis/refinedAdapter.lua +++ b/apis/refinedAdapter.lua @@ -70,7 +70,7 @@ function RefinedAdapter:listItems(throttle) end) if not s and m then - debug(m) + _debug(m) end itemDB:flush() diff --git a/apps/chestManager.lua b/apps/chestManager.lua index a220956..384a4e9 100644 --- a/apps/chestManager.lua +++ b/apps/chestManager.lua @@ -1210,8 +1210,8 @@ local function learnRecipe(page) end if not recipe then - debug(results) - debug(newRecipe) + _debug(results) + _debug(newRecipe) error('Failed - view system log') end diff --git a/apps/debug.lua b/apps/debug.lua index 78b032e..6b9b34f 100644 --- a/apps/debug.lua +++ b/apps/debug.lua @@ -13,9 +13,9 @@ mon.clear() mon.setTextScale(.5) mon.setCursorPos(1, 1) -local oldDebug = _G.debug +local oldDebug = _G._debug -_G.debug = function(...) +_G._debug = function(...) local oldTerm = term.redirect(mon) Util.print(...) term.redirect(oldTerm) @@ -30,4 +30,4 @@ repeat end until e == 'terminate' -_G.debug = oldDebug +_G._debug = oldDebug diff --git a/milo/Milo.lua b/milo/Milo.lua index c394fa1..31601ed 100644 --- a/milo/Milo.lua +++ b/milo/Milo.lua @@ -4,54 +4,17 @@ Using a turtle allows for crafting of items eliminating the need for AE/RS molecular assemblers / crafters. - Inventory setup: - Turtle/computer must be touching at least one type of inventory - - Generic inventory block such as: - Vanilla chest - RFTools modular storage - Storage drawers controller - and many others... - - Applied energistics - AE cable or interface (depending upon AE/MC version) - - Refined storage - TODO: add required block - Turtle crafting: 1. The turtle must have a crafting table equipped. 2. Equip the turtle with an introspection module. - Controller (optional): - Provides the ability to request crafting from AE / RS - - Applied Energistics - In versions 1.7x, AE can be used for both inventory access and crafting - requests. - - In versions 1.8+, AE can only be used to request crafting. - - Refined Storage - In versions 1.8x, inventory access works depending upon version. - - Turtle/computer must be touching an interface for inventory access. If only - requesting crafting, the controller must be either be touching or connected - via CC cables. - Configuration: Configuration file is usr/config/milo - monitor : valid options include: - type/monitor - will use the first monitor found - side/north - specify a direction (top/bottom/east/etc) - name/monitor_1 - specify the exact name of the peripheral - - - - -- Internal - Imports are at < 20 - + monitor : valid options include: + type/monitor - will use the first monitor found + side/north - specify a direction (top/bottom/east/etc) + name/monitor_1 - specify the exact name of the peripheral ]]-- _G.requireInjector(_ENV) @@ -137,9 +100,9 @@ table.sort(context.tasks, function(a, b) return a.priority < b.priority end) -debug('Tasks\n-----') +_debug('Tasks\n-----') for _, task in ipairs(context.tasks) do - debug('%d: %s', task.priority, task.name) + _debug('%d: %s', task.priority, task.name) end Milo:clearGrid() @@ -155,7 +118,8 @@ Event.onInterval(5, function() for _, task in ipairs(context.tasks) do local s, m = pcall(function() task:cycle(context) end) if not s and m then - Util.print(task.name) + _debug(task.name .. ' crashed') + Util.print(task.name .. ' crashed') error(m) end end diff --git a/milo/MiloRemote.lua b/milo/MiloRemote.lua index e7245fa..ebfaec0 100644 --- a/milo/MiloRemote.lua +++ b/milo/MiloRemote.lua @@ -301,48 +301,48 @@ end _G.p4 = Event -debug(options.slot) +_debug(options.slot) if options.slot.value then - debug('Transfer items initialized') + _debug('Transfer items initialized') Event.addRoutine(function() while true do -debug('sleeping') +_debug('sleeping') os.sleep(1.5) local neural = device.neuralInterface -debug(neural) +_debug(neural) if neural and neural.getInventory then local item = neural.getInventory().getItem(options.slot.value) if item then - debug('depositing') + _debug('depositing') page:sendRequest({ request = 'deposit', slot = options.slot.value }) -- local item = -- TODO: update count for this one item -- page.grid:draw() page:sync() else -debug('empty') +_debug('empty') end else - debug('missing Introspection module') + _debug('missing Introspection module') end end end) end if options.shield.value then - debug('Transfer items initialized') + _debug('Transfer items initialized') Event.onInterval(2, function() local neural = device.neuralInterface if neural and neural.getEquipment then local item = neural.getEquipment().getItem(SHIELD_SLOT) if item then - debug('depositing') + _debug('depositing') page:sendRequest({ request = 'deposit', slot = 'shield' }) -- local item = -- TODO: update count for this one item -- page.grid:draw() page:sync() end else - debug('missing Introspection module') + _debug('missing Introspection module') end end) end diff --git a/milo/apis/milo.lua b/milo/apis/milo.lua index be0dc36..2acc0fb 100644 --- a/milo/apis/milo.lua +++ b/milo/apis/milo.lua @@ -113,24 +113,50 @@ function Milo:getItemWithQty(res, ignoreDamage, ignoreNbtHash) return item end -function Milo:clearGrid() - local function clear() - turtle.eachFilledSlot(function(slot) - self.context.storage:import(self.context.localName, slot.index, slot.count, slot) - end) +function Milo:getMatches(items, item, ignoreDamage, ignoreNbtHash) + local t = { } - for i = 1, 16 do - if turtle.getItemCount(i) ~= 0 then - return false + if not ignoreDamage and not ignoreNbtHash then + local key = item.key or Milo:uniqueKey(item) + local e = items[key] + if e then + t[key] = Util.shallowCopy(e) + end + + else + for k,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 end end - return true end - return clear() or clear() + + return t +end + +function Milo:clearGrid() + turtle.eachFilledSlot(function(slot) + self.context.storage:import(self.context.localName, slot.index, slot.count, slot) + end) + + for i = 1, 16 do + if turtle.getItemCount(i) ~= 0 then + return false + end + end + return true end function Milo:getTurtleInventory() local list = { } + for i = 1,16 do local item = self.context.introspectionModule.getInventory().getItemMeta(i) if item then diff --git a/milo/apis/storage.lua b/milo/apis/storage.lua index 6d7d6d5..2a47fd0 100644 --- a/milo/apis/storage.lua +++ b/milo/apis/storage.lua @@ -26,12 +26,12 @@ listCount = 0, self.localName = modem.getNameLocal() Event.on({ 'device_attach', 'device_detach' }, function(e, dev) -debug('%s: %s', e, tostring(dev)) +_debug('%s: %s', e, tostring(dev)) self:initStorage() end) Event.onInterval(15, function() self:showStorage() - debug('STORAGE: cache: %d/%d', self.hits, self.misses) + _debug('STORAGE: cache: %d/%d', self.hits, self.misses) end) end @@ -44,11 +44,11 @@ function Storage:showStorage() end end if #t > 0 then - debug('Adapter:') + _debug('Adapter:') for _, k in pairs(t) do - debug(' offline: ' .. k) + _debug(' offline: ' .. k) end - debug('') + _debug('') end end @@ -56,7 +56,7 @@ function Storage:setOnline(online) if online ~= self.storageOnline then self.storageOnline = online os.queueEvent(self.storageOnline and 'storage_online' or 'storage_offline', online) - debug('Storage: %s', self.storageOnline and 'online' or 'offline') + _debug('Storage: %s', self.storageOnline and 'online' or 'offline') end end @@ -67,7 +67,7 @@ end function Storage:initStorage() local online = true - debug('Initializing storage') + _debug('Initializing storage') for k,v in pairs(self.remoteDefaults) do if v.adapter then v.adapter.online = not not device[k] @@ -136,7 +136,7 @@ end function Storage:refresh(throttle) self.dirty = true -debug('STORAGE: Forcing full refresh') +_debug('STORAGE: Forcing full refresh') for _, adapter in self:onlineAdapters() do adapter.dirty = true end @@ -149,9 +149,8 @@ function Storage:listItems(throttle) return self.items end self.listCount = self.listCount + 1 ---debug(self.listCount) +--_debug(self.listCount) - -- todo: only listItems from dirty remotes local ct = os.clock() local cache = { } local items = { } @@ -159,7 +158,7 @@ local ct = os.clock() for _, adapter in self:onlineAdapters() do if adapter.dirty then -debug('STORAGE: refresh: ' .. adapter.name) +_debug('STORAGE: refresh: ' .. adapter.name) adapter:listItems(throttle) adapter.dirty = false end @@ -180,7 +179,7 @@ debug('STORAGE: refresh: ' .. adapter.name) throttle() end end -debug('STORAGE: refresh in ' .. (os.clock() - ct)) +_debug('STORAGE: refresh in ' .. (os.clock() - ct)) self.dirty = false self.cache = cache @@ -201,7 +200,7 @@ function Storage:provide(item, qty, slot, direction) local amount = adapter:provide(item, qty, slot, direction or self.localName) if amount > 0 then self.hits = self.hits + 1 - debug('EXT: %s(%d): %s -> %s%s', + _debug('EXT: %s(%d): %s -> %s%s', item.name, amount, adapter.name, direction or self.localName, slot and string.format('[%d]', slot) or '') self.dirty = true @@ -215,13 +214,13 @@ function Storage:provide(item, qty, slot, direction) end end - debug('STORAGE: MISS: %s - %d', key, qty) + _debug('STORAGE: MISS: %s - %d', key, qty) self.misses = self.misses + 1 for _, adapter in self:onlineAdapters() do local amount = adapter:provide(item, qty, slot, direction or self.localName) if amount > 0 then -debug('EXT: %s(%d): %s -> %s%s', +_debug('EXT: %s(%d): %s -> %s%s', item.name, amount, adapter.name, direction or self.localName, slot and string.format('[%d]', slot) or '') self.dirty = true @@ -240,7 +239,7 @@ end function Storage:trash(source, slot, count) local trashcan = Util.find(self.remoteDefaults, 'mtype', 'trashcan') if trashcan and trashcan.adapter and trashcan.adapter.online then -debug('TRA: %s[%d] (%d)', source or self.localName, slot, count or 64) +_debug('TRA: %s[%d] (%d)', source or self.localName, slot, count or 64) return trashcan.adapter.pullItems(source or self.localName, slot, count) end return 0 @@ -267,7 +266,8 @@ function Storage:insert(slot, qty, toSlot, item, source) local function insert(adapter) local amount = adapter:insert(slot, qty, toSlot, source or self.localName) if amount > 0 then -debug('INS: %s(%d): %s[%d] -> %s', +-- TODO: change debug to _debug +_debug('INS: %s(%d): %s[%d] -> %s', item.name, amount, source or self.localName, slot, adapter.name) self.dirty = true @@ -300,8 +300,7 @@ debug('INS: %s(%d): %s[%d] -> %s', end if self.cache[key] then -- is this item in some chest - -- low to high priority if the chest already contains that item - for _, adapter in self:onlineAdapters(true --[[ reversed ]]) do + for _, adapter in self:onlineAdapters() do if qty <= 0 then break end diff --git a/milo/apis/turtle/craft.lua b/milo/apis/turtle/craft.lua index c531c7d..d031b86 100644 --- a/milo/apis/turtle/craft.lua +++ b/milo/apis/turtle/craft.lua @@ -105,10 +105,21 @@ local function machineCraft(recipe, inventoryAdapter, machineName, request, coun end end + local xferred = { } for k,v in pairs(recipe.ingredients) do - if inventoryAdapter:provide(splitKey(v), count, k, machineName) ~= count then - -- TODO: suck em back out - request.status = 'unknown error' + local provided = inventoryAdapter:provide(splitKey(v), count, k, machineName) + xferred[k] = { + key = v, + count = provided, + } + if provided ~= count then + -- take back out whatever we put in + for k2,v2 in pairs(xferred) do + if v2.count > 0 then + inventoryAdapter:import(machineName, k2, v2.count, splitKey(v2.key)) + end + end + request.status = 'Invalid recipe' request.statusCode = Craft.STATUS_ERROR return end @@ -175,11 +186,11 @@ function Craft.craftRecipe(recipe, count, inventoryAdapter, origItem) --end for _, request in pairs(origItem.ingredients) do + if request.crafted >= request.count then if request.pending then debug('??') debug(request) end - if request.crafted >= request.count then request.status = nil request.statusCode = Craft.STATUS_SUCCESS end diff --git a/milo/core/machines.lua b/milo/core/machines.lua index cb162c0..cf1e14f 100644 --- a/milo/core/machines.lua +++ b/milo/core/machines.lua @@ -7,9 +7,12 @@ local Util = require('util') local colors = _G.colors local device = _G.device +local turtle = _G.turtle local context = Milo:getContext() +-- TODO: no blacklist for export + local function saveConfig() local t = { } for k,v in pairs(context.config.remoteDefaults) do @@ -266,7 +269,14 @@ function machineWizard.filter:show(entry, callback, whitelistOnly) self.form[3].inactive = whitelistOnly UI.SlideOut.show(self) --- self:setFocus(self.filter) + self:setFocus(self.form.scan) + + Milo:pauseCrafting() +end + +function machineWizard.filter:hide() + UI.SlideOut.hide(self) + Milo:resumeCrafting() end function machineWizard.filter:resetGrid() @@ -295,6 +305,7 @@ function machineWizard.filter:eventHandler(event) self:resetGrid() self.grid:update() self.grid:draw() + turtle.emptyInventory() elseif event.type == 'remove_entry' then local row = self.grid:getSelected() @@ -411,13 +422,6 @@ function machineWizard:eventHandler(event) UI:setPreviousPage() elseif event.type == 'accept' then - -- todo: no need for calling this function - use validate instead - for _, v in pairs(self.wizard.pages) do - if v.save and v.index then -- only save if the page was valid for this mtype - v:save(self.machine) - end - end - Util.prune(self.machine, function(v) if type(v) == 'boolean' then return v diff --git a/milo/plugins/autocraftTask.lua b/milo/plugins/autocraftTask.lua deleted file mode 100644 index 50d2f9f..0000000 --- a/milo/plugins/autocraftTask.lua +++ /dev/null @@ -1,26 +0,0 @@ -local Milo = require('milo') -local Util = require('util') - -local Autocraft = { - name = 'autocraft', - priority = 100, -} - --- TODO: fix/test -function Autocraft:cycle(context) - local list = { } - - for _,res in pairs(context.resources) do - if res.auto then - res = Util.shallowCopy(res) - res.count = 256 - list[Milo:uniqueKey(res)] = res - end - end - - if not Util.empty(list) then - Milo:craftItems(list) - end -end - -Milo:registerTask(Autocraft) diff --git a/milo/plugins/exportTask.lua b/milo/plugins/exportTask.lua index 5d864d9..0f0bc80 100644 --- a/milo/plugins/exportTask.lua +++ b/milo/plugins/exportTask.lua @@ -13,29 +13,57 @@ end function ExportTask:cycle(context) for machine in context.storage:filterActive('machine', filter) do for _, entry in pairs(machine.exports) do - local slotNo = type(entry.slot) == 'number' and entry.slot or nil -- '*' indicates any slot - local slot = (slotNo and machine.adapter.getItemMeta(slotNo)) or { count = 0 } - for key in pairs(entry.filter or { }) do - local item = itemDB:splitKey(key) + local function exportSlot(list, slotNo, item, count) + local slot = list[slotNo] or { count = 0 } + + if slot.count == 0 or + (slot.name == item.name and + slot.damage == item.damage and + slot.nbtHash == item.nbtHash) then + + local maxCount = itemDB:getMaxCount(item) + count = math.min(maxCount - slot.count, count) - -- is something else is in this slot - if not slot.name or slot.name == item.name then - local maxCount = slot.maxCount or itemDB:getMaxCount(item) - local count = maxCount - slot.count - if not slotNo then - -- TODO: should we just execute export - - -- or scan all slots for space ?? - count = machine.adapter.size() * maxCount - slot.count - end if count > 0 then - item = Milo:getItemWithQty(item) - if item and count > 0 then - context.storage:export( - machine.name, - slotNo, - math.min(count, item.count), - item) +-- _debug('attempting to export %s %d into slot %d', item.name, count, slotNo) + count = context.storage:export(machine.name, slotNo, count, item) + + 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 + end + 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 + -- bad for perf to do listItems each time + 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 + context.storage:export(machine.name, nil, item.count, item) end end end diff --git a/milo/plugins/importTask.lua b/milo/plugins/importTask.lua index 0b27c52..4ef61b8 100644 --- a/milo/plugins/importTask.lua +++ b/milo/plugins/importTask.lua @@ -9,6 +9,8 @@ local function filter(a) return a.imports end +-- TODO: ignore damage/nbt + function ImportTask:cycle(context) for inventory in context.storage:filterActive('machine', filter) do for _, entry in pairs(inventory.imports) do diff --git a/milo/plugins/item.lua b/milo/plugins/item.lua index 4c98361..abb897c 100644 --- a/milo/plugins/item.lua +++ b/milo/plugins/item.lua @@ -270,7 +270,7 @@ function itemPage:eventHandler(event) filtered.count = nil Milo:saveResources() - +-- TODO: min not updated upon save until refresh UI:setPreviousPage() else diff --git a/milo/plugins/listing.lua b/milo/plugins/listing.lua index 1c8ed15..5b9b262 100644 --- a/milo/plugins/listing.lua +++ b/milo/plugins/listing.lua @@ -211,7 +211,7 @@ function listingPage:eventHandler(event) Util.writeTable(Craft.USER_RECIPES, context.userRecipes) Craft.loadRecipes() end - +--TODO: remove machine assoc if context.resources[key] then context.resources[key] = nil Milo:saveResources() @@ -242,7 +242,6 @@ function listingPage:enable() self:setFocus(self.statusBar.filter) self.timer = Event.onInterval(5, function() for _,v in pairs(self.allItems) do - if not v.key then debug(v) error('') end local c = context.storage.cache[v.key] v.count = c and c.count or 0 end @@ -273,6 +272,7 @@ function listingPage:applyFilter() end Event.on({ 'storage_offline', 'storage_online' }, function(e, isOnline) + -- TODO: Fix button listingPage.statusBar.storageStatus.text = isOnline and 'online' or 'offline' listingPage.statusBar.storageStatus.textColor = diff --git a/milo/plugins/machineLearn.lua b/milo/plugins/machineLearn.lua index 1a3bddd..2c31f5e 100644 --- a/milo/plugins/machineLearn.lua +++ b/milo/plugins/machineLearn.lua @@ -62,9 +62,6 @@ function pages.machines:enable() end function pages.machines:validate() - --- TODO: index number validation in wizard - local selected = self.grid:getSelected() if not selected then machineLearnWizard.notification:error('No machines configured') diff --git a/milo/plugins/redstoneTask.lua b/milo/plugins/redstoneTask.lua index f1f286f..6d4e841 100644 --- a/milo/plugins/redstoneTask.lua +++ b/milo/plugins/redstoneTask.lua @@ -13,7 +13,7 @@ function RedstoneTask:cycle(context) if v.redstone then local ri = device[v.redstone.integrator] if not ri or not v.adapter then - debug(v.redstone) + _debug(v.redstone) else local function conditionsSatisfied() return not not next(v.adapter.list()) diff --git a/milo/plugins/remote.lua b/milo/plugins/remote.lua index d15df2b..51e5a42 100644 --- a/milo/plugins/remote.lua +++ b/milo/plugins/remote.lua @@ -19,7 +19,7 @@ local function getManipulatorForUser(user) end local function client(socket) - debug('connection from ' .. socket.dhost) + _debug('connection from ' .. socket.dhost) local user = socket:read(2) if not user then @@ -36,7 +36,7 @@ local function client(socket) if not data then break end -debug('remote: ' .. data.request) +_debug('remote: ' .. data.request) if data.request == 'list' then local items = Milo:listItems() Milo:mergeResources(items) @@ -89,12 +89,12 @@ debug('remote: ' .. data.request) end until not socket.connected - debug('disconnected from ' .. socket.dhost) + _debug('disconnected from ' .. socket.dhost) end if device.wireless_modem then Event.addRoutine(function() - debug('Milo: listening on port 4242') + _debug('Milo: listening on port 4242') while true do local socket = Socket.server(4242) Event.addRoutine(function() diff --git a/milo/plugins/turtleLearn.lua b/milo/plugins/turtleLearn.lua index 0d0e49c..fb6df3e 100644 --- a/milo/plugins/turtleLearn.lua +++ b/milo/plugins/turtleLearn.lua @@ -77,8 +77,8 @@ local function learnRecipe() end if not recipe then - debug(results) - debug(newRecipe) + _debug(results) + _debug(newRecipe) error('Failed - view system log') end