From 4276ea533ffa82e00dc4d9b39b01ba6cddae21b4 Mon Sep 17 00:00:00 2001 From: "kepler155c@gmail.com" Date: Tue, 22 Jan 2019 15:50:37 -0500 Subject: [PATCH] Milo: remote learn + remove logger --- builder/supplier.lua | 5 - core/DiskCopy.lua | 8 +- core/apis/message.lua | 13 +- milo/MiloRemote.lua | 287 +++++++++++++---------------- milo/apis/milo.lua | 87 +++++++++ milo/plugins/remote.lua | 10 +- milo/plugins/remote/craft.lua | 26 +++ milo/plugins/remote/deposit.lua | 45 +++++ milo/plugins/remote/depositAll.lua | 5 +- milo/plugins/remoteCraft.lua | 57 ++++++ milo/plugins/turtleLearn.lua | 96 +--------- monitor/mirrorClient.lua | 3 - monitor/mirrorHost.lua | 3 - 13 files changed, 363 insertions(+), 282 deletions(-) create mode 100644 milo/plugins/remote/craft.lua create mode 100644 milo/plugins/remote/deposit.lua create mode 100644 milo/plugins/remoteCraft.lua diff --git a/builder/supplier.lua b/builder/supplier.lua index 58405f0..003d839 100644 --- a/builder/supplier.lua +++ b/builder/supplier.lua @@ -1,5 +1,4 @@ local Event = require('event') -local Logger = require('logger') local MEProvider = require('meProvider') local Message = require('message') local Point = require('point') @@ -31,9 +30,6 @@ if not device.wireless_modem then error('No wireless modem detected') end -Logger.filter('modem_send', 'event', 'ui') -Logger.setWirelessLogging() - local __BUILDER_ID = 6 local itemInfoDB @@ -130,7 +126,6 @@ function Builder:refuel() end function Builder:log(...) - Logger.log('supplier', ...) Util.print(...) end diff --git a/core/DiskCopy.lua b/core/DiskCopy.lua index b2bbe00..aab2691 100644 --- a/core/DiskCopy.lua +++ b/core/DiskCopy.lua @@ -68,7 +68,7 @@ local function isValid(drive) end local function needsLabel(drive) - return drive.isDiskPresent() and not drive.getMountPath() + return drive.isDiskPresent() and not drive.getMountPath() and not drive.getAudioTitle() end function page:drawInfo(drive, textArea) @@ -117,8 +117,7 @@ function page:copy(sdrive, tdrive) local function countFiles(source, target) if fs.isDir(source) then - local list = fs.list(source) - for _,f in pairs(list) do + for _,f in pairs(fs.list(source)) do countFiles(fs.combine(source, f), fs.combine(target, f)) end else @@ -133,8 +132,7 @@ function page:copy(sdrive, tdrive) if not fs.exists(target) then fs.makeDir(target) end - local list = fs.list(source) - for _,f in pairs(list) do + for _,f in pairs(fs.list(source)) do rawCopy(fs.combine(source, f), fs.combine(target, f)) end diff --git a/core/apis/message.lua b/core/apis/message.lua index fd38ed1..babe3fb 100644 --- a/core/apis/message.lua +++ b/core/apis/message.lua @@ -1,5 +1,4 @@ local Event = require('event') -local Logger = require('logger') local Message = { } @@ -45,8 +44,6 @@ Event.on('modem_message', function(event, side, sendChannel, replyChannel, msg, distance) if msg and msg.type then -- filter out messages from other systems local id = replyChannel - Logger.log('modem_receive', { id, msg.type }) - --Logger.log('modem_receive', msg.contents) for k,h in pairs(messageHandlers) do if h.type == msg.type then -- should provide msg.contents instead of message - type is already known @@ -63,12 +60,10 @@ function Message.send(id, msgType, contents) end if id then - Logger.log('modem_send', { tostring(id), msgType }) device.wireless_modem.transmit(id, os.getComputerID(), { type = msgType, contents = contents }) else - Logger.log('modem_send', { 'broadcast', msgType }) device.wireless_modem.transmit(60000, os.getComputerID(), { type = msgType, contents = contents }) @@ -81,8 +76,6 @@ function Message.broadcast(t, contents) end Message.send(nil, t, contents) --- Logger.log('rednet_send', { 'broadcast', t }) --- rednet.broadcast({ type = t, contents = contents }) end function Message.waitForMessage(msgType, timeout, fromId) @@ -94,13 +87,9 @@ function Message.waitForMessage(msgType, timeout, fromId) if not fromId or id == fromId then return e, id, msg, distance end - end + end end until e == 'timer' and side == timerId end -function Message.enableWirelessLogging() - Logger.setWirelessLogging() -end - return Message \ No newline at end of file diff --git a/milo/MiloRemote.lua b/milo/MiloRemote.lua index cb2c822..9d8642b 100644 --- a/milo/MiloRemote.lua +++ b/milo/MiloRemote.lua @@ -9,15 +9,14 @@ local Util = require('util') local colors = _G.colors local device = _G.device local fs = _G.fs -local os = _G.os local shell = _ENV.shell local string = _G.string -local SHIELD_SLOT = 2 local STARTUP_FILE = 'usr/autorun/miloRemote.lua' local context = { state = Config.load('miloRemote', { displayMode = 0, deposit = true }), + responseHandlers = { }, } local depositMode = { @@ -164,125 +163,6 @@ local function getPlayerName() end end -function page:setStatus(status) - self.menuBar.infoBar:setStatus(status) - self:sync() -end - -function page:processMessages(s) - Event.addRoutine(function() - repeat - local response = s:read() - if not response then - break - end - if response.type == 'received' then - Sound.play('entity.item.pickup') - local ritem = self.items[response.key] - if ritem then - ritem.count = response.count - if self.enabled then - self.grid:draw() - self:sync() - end - end - - elseif response.type == 'list' then - self.items = self:expandList(response.list) - self:applyFilter() - if self.enabled then - self.grid:draw() - self.grid:sync() - end - - elseif response.type == 'transfer' then - if response.count > 0 then - Sound.play('entity.item.pickup') - local item = self.items[response.key] - if item then - item.count = response.current - if self.enabled then - self.grid:draw() - self:sync() - end - end - end - if response.craft then - if response.craft > 0 then - self:setStatus(response.craft .. ' crafting ...') - elseif response.craft + response.count < response.requested then - if response.craft + response.count == 0 then - Sound.play('entity.villager.no') - end - self:setStatus((response.craft + response.count) .. ' available ...') - end - end - end - if response.msg then - self:setStatus(response.msg) - end - until not s.connected - - s:close() - s = nil - self:setStatus('disconnected ...') - Sound.play('entity.villager.no') - end) -end - -function page:sendRequest(data, statusMsg) - if not context.state.server then - self:setStatus('Invalid configuration') - return - end - - local player = getPlayerName() - if not player then - self:setStatus('Missing neural or introspection') - return - end - - local success - sync(self, function() - local msg - for _ = 1, 2 do - if not context.socket or not context.socket.connected then - self:setStatus('connecting ...') - context.socket, msg = Socket.connect(context.state.server, 4242) - if context.socket then - context.socket:write(player) - local r = context.socket:read(2) - if r and not r.msg then - self:setStatus('connected ...') - self:processMessages(context.socket) - else - msg = r and r.msg or 'Timed out' - context.socket:close() - context.socket = nil - end - end - end - if context.socket then - if statusMsg then - self:setStatus(statusMsg) - Event.onTimeout(2, function() - self:setStatus('') - end) - end - if context.socket:write(data) then - success = true - return - end - context.socket:close() - context.socket = nil - end - end - self:setStatus(msg or 'Failed to connect') - end) - - return success -end - function page.grid:getRowTextColor(row, selected) if row.is_craftable then return colors.yellow @@ -328,7 +208,7 @@ function page.grid:eventHandler(event) end function page:transfer(item, count, msg) - self:sendRequest({ request = 'transfer', item = item, count = count }, msg) + context:sendRequest({ request = 'transfer', item = item, count = count }, msg) end function page.setup:eventHandler(event) @@ -350,7 +230,7 @@ function page:eventHandler(event) context.state.deposit = not context.state.deposit Util.merge(self.statusBar.depositToggle, depositMode[context.state.deposit]) self.statusBar:draw() - self:setStatus(depositMode[context.state.deposit].help) + context:setStatus(depositMode[context.state.deposit].help) Config.update('miloRemote', context.state) elseif event.type == 'form_complete' then @@ -375,7 +255,7 @@ shell.openForegroundTab('packages/milo/MiloRemote')]]) self:setFocus(self.statusBar.filter) elseif event.type == 'focus_change' then - self.menuBar.infoBar:setStatus(event.focused.help) + context:setStatus(event.focused.help) elseif event.type == 'eject' or event.type == 'grid_select' then local item = self.grid:getSelected() @@ -404,7 +284,7 @@ shell.openForegroundTab('packages/milo/MiloRemote')]]) self:transfer(item, count, 'requesting ' .. count .. ' ...') else Sound.play('entity.villager.no') - self:setStatus('nope ...') + context:setStatus('nope ...') end elseif event.type == 'plugin' then @@ -431,7 +311,7 @@ shell.openForegroundTab('packages/milo/MiloRemote')]]) Util.merge(event.button, displayModes[context.state.displayMode]) event.button:draw() self:applyFilter() - self:setStatus(event.button.help) + context:setStatus(event.button.help) self.grid:draw() Config.update('miloRemote', context.state) @@ -490,7 +370,7 @@ function page:expandList(list) end function page:refresh(requestType) - self:sendRequest({ request = requestType }, 'refreshing...') + context:sendRequest({ request = requestType }, 'refreshing...') end function page:applyFilter() @@ -516,43 +396,89 @@ function page:applyFilter() self.grid:setValues(t) end -Event.addRoutine(function() - local lastTransfer - while true do - local sleepTime = 1.5 - if lastTransfer and os.clock() - lastTransfer < 3 then - sleepTime = .25 - end +context.page = page - os.sleep(context.socket and sleepTime or 5) - if context.state.deposit then - local neural = device.neuralInterface - local inv = context.state.useShield and 'getEquipment' or 'getInventory' - if not neural or not neural[inv] then - _G._debug('missing Introspection module') - elseif context.state.server and (context.state.useShield or context.state.slot) then - local s, m = pcall(function() - local method = neural[inv] - local item = method and method().list()[context.state.useShield and SHIELD_SLOT or context.state.slot] - if item then - if page:sendRequest({ - request = 'deposit', - slot = context.state.useShield and 'shield' or context.state.slot, - count = item.count, - }) then - lastTransfer = os.clock() - end +function context:setStatus(status) + page.menuBar.infoBar:setStatus(status) + page:sync() +end + +local function processMessages(s) + Event.addRoutine(function() + s.co = coroutine.running() + repeat + local response = s:read() + if not response then + break + end + local h = context.responseHandlers[response.type] + if h then + h(response) + end + if response.msg then + context:setStatus(response.msg) + end + until not s.connected + + s:close() + s = nil + context:setStatus('disconnected ...') + Sound.play('entity.villager.no') + end) +end + +function context:sendRequest(data, statusMsg) + if not context.state.server then + self:setStatus('Invalid configuration') + return + end + + local player = getPlayerName() + if not player then + self:setStatus('Missing neural or introspection') + return + end + + local success + sync(page, function() + local msg + for _ = 1, 2 do + if not context.socket or not context.socket.connected then + self:setStatus('connecting ...') + context.socket, msg = Socket.connect(context.state.server, 4242) + if context.socket then + context.socket:write(player) + local r = context.socket:read(2) + if r and not r.msg then + self:setStatus('connected ...') + processMessages(context.socket) + else + msg = r and r.msg or 'Timed out' + context.socket:close() + context.socket = nil end - end) - if not s and m then - _debug(m) end end + if context.socket then + if statusMsg then + self:setStatus(statusMsg) + Event.onTimeout(2, function() + self:setStatus('') + end) + end + if context.socket:write(data) then + success = true + return + end + context.socket:close() + context.socket = nil + end end - end -end) + self:setStatus(msg or 'Failed to connect') + end) -context.page = page + return success +end function context:getState(key) return self.state[key] @@ -563,6 +489,51 @@ function context:setState(key, value) Config.update('miloRemote', self.state) end +context.responseHandlers['received'] = function(response) + Sound.play('entity.item.pickup') + local ritem = page.items[response.key] + if ritem then + ritem.count = response.count + if page.enabled then + page.grid:draw() + page:sync() + end + end +end + +context.responseHandlers['list'] = function(response) + page.items = page:expandList(response.list) + page:applyFilter() + if page.enabled then + page.grid:draw() + page.grid:sync() + end +end + +context.responseHandlers['transfer'] = function(response) + if response.count > 0 then + Sound.play('entity.item.pickup') + local item = page.items[response.key] + if item then + item.count = response.current + if page.enabled then + page.grid:draw() + page:sync() + end + end + end + if response.craft then + if response.craft > 0 then + context:setStatus(response.craft .. ' crafting ...') + elseif response.craft + response.count < response.requested then + if response.craft + response.count == 0 then + Sound.play('entity.villager.no') + end + context:setStatus((response.craft + response.count) .. ' available ...') + end + end +end + local function loadDirectory(dir) local dropdown = { { text = 'Setup', event = 'setup' }, diff --git a/milo/apis/milo.lua b/milo/apis/milo.lua index d007ef4..8e17c98 100644 --- a/milo/apis/milo.lua +++ b/milo/apis/milo.lua @@ -222,6 +222,93 @@ function Milo:eject(item, count) return count end +function Milo:learnRecipe() + local ingredients = self:getTurtleInventory() + + if not ingredients then + return false, 'No recipe defined' + end + + turtle.select(1) + if not turtle.craft() then + return false, 'Failed to craft' + end + + local results = self:getTurtleInventory() + if not results or not results[1] then + return false, 'Failed to craft' + end + + local maxCount + local newRecipe = { + ingredients = ingredients, + } + + local numResults = 0 + for _,v in pairs(results) do + if v.count > 0 then + numResults = numResults + 1 + end + end + if numResults > 1 then + for _,v1 in pairs(results) do + for _,v2 in pairs(ingredients) do + if v1.name == v2.name and + v1.nbtHash == v2.nbtHash and + (v1.damage == v2.damage or + (v1.maxDamage > 0 and v2.maxDamage > 0 and + v1.damage ~= v2.damage)) then + if not newRecipe.crafingTools then + newRecipe.craftingTools = { } + end + local tool = Util.shallowCopy(v2) + if tool.maxDamage > 0 then + tool.damage = '*' + end + + --[[ + Turtles can only craft one item at a time using a tool :( + ]]-- + maxCount = 1 + + newRecipe.craftingTools[itemDB:makeKey(tool)] = true + v1.craftingTool = true + break + end + end + end + end + + local recipe + for _,v in pairs(results) do + if not v.craftingTool then + recipe = v + if maxCount then + recipe.maxCount = maxCount + end + break + end + end + + if not recipe then + return false, 'Unknown error' + end + + newRecipe.count = recipe.count + + local key = itemDB:makeKey(recipe) + if recipe.maxCount ~= 64 then + newRecipe.maxCount = recipe.maxCount + end + for k,ingredient in pairs(Util.shallowCopy(ingredients)) do + ingredients[k] = itemDB:makeKey(ingredient) + end + + self:updateRecipe(key, newRecipe) + + return recipe +end + function Milo:updateRecipe(result, recipe) -- save the recipe if recipe then diff --git a/milo/plugins/remote.lua b/milo/plugins/remote.lua index d449480..937feba 100644 --- a/milo/plugins/remote.lua +++ b/milo/plugins/remote.lua @@ -75,7 +75,7 @@ local function client(socket) if not data then break end ---_G._debug(data) +_G._debug(data) socket.co = coroutine.running() if data.request == 'scan' then -- full scan of all inventories @@ -163,6 +163,12 @@ local function client(socket) craft = request.craft, }) end + else + for _,v in pairs(context.plugins.remoteHandler or { }) do + if v.messages and v.messages[data.request] then + v.callback(user, data, socket) + end + end end until not socket.connected @@ -191,7 +197,7 @@ Event.on({ 'device_attach', 'device_detach' }, function(_, name) if handler then handler:terminate() handler = nil - _debug('REMOTE: wireless modem disconnected') + _G._debug('REMOTE: wireless modem disconnected') else listen() end diff --git a/milo/plugins/remote/craft.lua b/milo/plugins/remote/craft.lua new file mode 100644 index 0000000..d30aa62 --- /dev/null +++ b/milo/plugins/remote/craft.lua @@ -0,0 +1,26 @@ +local Sound = require('sound') + +local args = { ... } +local context = args[1] + +local function learn() + context:sendRequest({ + request = 'craft', + slot = 15, + }) +end + +context.responseHandlers['craft'] = function(response) + if response.success then + Sound.play('entity.item.pickup') + else + Sound.play('entity.villager.no') + end +end + +return { + menuItem = 'Learn Recipe', + callback = function() + learn() + end, +} diff --git a/milo/plugins/remote/deposit.lua b/milo/plugins/remote/deposit.lua new file mode 100644 index 0000000..bd0efdc --- /dev/null +++ b/milo/plugins/remote/deposit.lua @@ -0,0 +1,45 @@ +local Event = require('event') + +local device = _G.device +local os = _G.os + +local args = { ... } +local context = args[1] + +local SHIELD_SLOT = 2 + +Event.addRoutine(function() + local lastTransfer + while true do + local sleepTime = 1.5 + if lastTransfer and os.clock() - lastTransfer < 3 then + sleepTime = .25 + end + + os.sleep(context.socket and sleepTime or 5) + if context.state.deposit then + local neural = device.neuralInterface + local inv = context.state.useShield and 'getEquipment' or 'getInventory' + if not neural or not neural[inv] then + _G._debug('missing Introspection module') + elseif context.state.server and (context.state.useShield or context.state.slot) then + local s, m = pcall(function() + local method = neural[inv] + local item = method and method().list()[context.state.useShield and SHIELD_SLOT or context.state.slot] + if item then + if context:sendRequest({ + request = 'deposit', + slot = context.state.useShield and 'shield' or context.state.slot, + count = item.count, + }) then + lastTransfer = os.clock() + end + end + end) + if not s and m then + _G._debug(m) + end + end + end + end +end) diff --git a/milo/plugins/remote/depositAll.lua b/milo/plugins/remote/depositAll.lua index 41a284f..6ead2a8 100644 --- a/milo/plugins/remote/depositAll.lua +++ b/milo/plugins/remote/depositAll.lua @@ -81,7 +81,7 @@ function page:depositAll() for slot, item in pairs(inv) do if (context.state.depositAll.includeHotbar or slot > 9) and item.name ~= 'plethora:neuralconnector' then - context.page:sendRequest({ + context:sendRequest({ request = 'deposit', slot = slot, count = item.count, @@ -94,12 +94,15 @@ function page:eventHandler(event) if event.type == 'checkbox_change' and event.element.formKey == 'includeHotbar' then context.state.depositAll.includeHotbar = event.checked page:updateInventoryList() + elseif event.type == 'form_complete' then Config.update('miloRemote', context.state) page:depositAll() UI:setPreviousPage() + elseif event.type == 'form_cancel' then UI:setPreviousPage() + else return UI.Page.eventHandler(self, event) end diff --git a/milo/plugins/remoteCraft.lua b/milo/plugins/remoteCraft.lua new file mode 100644 index 0000000..ea2e8ad --- /dev/null +++ b/milo/plugins/remoteCraft.lua @@ -0,0 +1,57 @@ +local itemDB = require('itemDB') +local Milo = require('milo') + +local context = Milo:getContext() +local device = _G.device + +local function craftHandler(user, message, socket) + local function makeNode() + local devName = user .. ':inventory' + local adapter = device[devName] + if adapter then + return { + adapter = adapter, + name = devName, + } + end + end + + local function craft() + local slots = { + [1] = 1, [2] = 2, [3] = 3, + [5] = 10, [6] = 11, [7] = 12, + [9] = 19, [10] = 20, [11] = 21, + } + local node = makeNode() + if node then + for k, v in pairs(slots) do + node.adapter.pushItems(context.turtleInventory.name, v + message.slot - 1, 1, k) + end + local recipe, msg = Milo:learnRecipe() + if recipe then + socket:write({ + type = 'craft', + msg = 'Learned: ' .. itemDB:getName(recipe), + success = true, + }) + for k,v in pairs(context.turtleInventory.adapter.list()) do + node.adapter.pullItems(context.turtleInventory.name, k, v.count) + end + else + socket:write({ + type = 'craft', + msg = msg, + }) + for k, v in pairs(slots) do + node.adapter.pullItems(context.turtleInventory.name, k, 1, v + message.slot - 1) + end + end + end + end + + Milo:queueRequest({ }, craft) +end + +return { + remoteHandler = { callback = craftHandler, messages = { craft = true } } +} diff --git a/milo/plugins/turtleLearn.lua b/milo/plugins/turtleLearn.lua index 01f23ec..36a4063 100644 --- a/milo/plugins/turtleLearn.lua +++ b/milo/plugins/turtleLearn.lua @@ -1,102 +1,10 @@ local itemDB = require('itemDB') local Milo = require('milo') local UI = require('ui') -local Util = require('util') local colors = _G.colors local turtle = _G.turtle -local function learnRecipe() - local ingredients = Milo:getTurtleInventory() - - if not ingredients then - return false, 'No recipe defined' - end - - turtle.select(1) - if not turtle.craft() then - return false, 'Failed to craft' - end - - local results = Milo:getTurtleInventory() - if not results or not results[1] then - return false, 'Failed to craft' - end - - local maxCount - local newRecipe = { - ingredients = ingredients, - } - - local numResults = 0 - for _,v in pairs(results) do - if v.count > 0 then - numResults = numResults + 1 - end - end - if numResults > 1 then - for _,v1 in pairs(results) do - for _,v2 in pairs(ingredients) do - if v1.name == v2.name and - v1.nbtHash == v2.nbtHash and - (v1.damage == v2.damage or - (v1.maxDamage > 0 and v2.maxDamage > 0 and - v1.damage ~= v2.damage)) then - if not newRecipe.crafingTools then - newRecipe.craftingTools = { } - end - local tool = Util.shallowCopy(v2) - if tool.maxDamage > 0 then - tool.damage = '*' - end - - --[[ - Turtles can only craft one item at a time using a tool :( - ]]-- - maxCount = 1 - - newRecipe.craftingTools[itemDB:makeKey(tool)] = true - v1.craftingTool = true - break - end - end - end - end - - local recipe - for _,v in pairs(results) do - if not v.craftingTool then - recipe = v - if maxCount then - recipe.maxCount = maxCount - end - break - end - end - - if not recipe then - return false, 'Unknown error' - end - - newRecipe.count = recipe.count - - local key = itemDB:makeKey(recipe) - if recipe.maxCount ~= 64 then - newRecipe.maxCount = recipe.maxCount - end - for k,ingredient in pairs(Util.shallowCopy(ingredients)) do - if ingredient.maxDamage > 0 then - -- ingredient.damage = '*' -- I don't think this is right - end - ingredients[k] = itemDB:makeKey(ingredient) - end - - Milo:updateRecipe(key, newRecipe) - turtle.emptyInventory() - - return recipe -end - local pages = { turtleCraft = UI.Window { index = 2, @@ -110,11 +18,13 @@ local pages = { } function pages.turtleCraft:validate() - local recipe, msg = learnRecipe() + local recipe, msg = Milo:learnRecipe() if recipe then local displayName = itemDB:getName(recipe) + turtle.emptyInventory() + UI:setPage('listing', { filter = displayName, message = 'Learned: ' .. displayName, diff --git a/monitor/mirrorClient.lua b/monitor/mirrorClient.lua index 8e3bb74..25e55e0 100644 --- a/monitor/mirrorClient.lua +++ b/monitor/mirrorClient.lua @@ -1,13 +1,10 @@ local Event = require('event') -local Logger = require('logger') local Socket = require('socket') local Util = require('util') local multishell = _ENV.multishell local os = _G.os -Logger.setScreenLogging() - local remoteId local args = { ... } if #args == 1 then diff --git a/monitor/mirrorHost.lua b/monitor/mirrorHost.lua index ac3da52..daea661 100644 --- a/monitor/mirrorHost.lua +++ b/monitor/mirrorHost.lua @@ -1,12 +1,9 @@ local Event = require('event') -local Logger = require('logger') local Socket = require('socket') local colors = _G.colors local term = _G.term -Logger.setScreenLogging() - local mon = term.current() local args = { ... } if args[1] then