diff --git a/sys/apis/event.lua b/sys/apis/event.lua index 6b9276e..8aa2d9c 100644 --- a/sys/apis/event.lua +++ b/sys/apis/event.lua @@ -1,121 +1,153 @@ local Util = require('util') local Event = { - uid = 1, -- unique id for handlers - routines = { }, - handlers = { namedTimers = { } }, + uid = 1, -- unique id for handlers + routines = { }, -- coroutines + types = { }, -- event handlers + timers = { }, -- named timers terminate = false, } -function Event.addHandler(type, f) - local event = Event.handlers[type] +local Routine = { } + +function Routine:isDead() + if not self.co then + return true + end + return coroutine.status(self.co) == 'dead' +end + +function Routine:terminate() + if self.co then + self:resume('terminate') + end +end + +function Routine:resume(event, ...) + + if not self.co then + debug(event) + debug(self) + debug(getfenv(1)) + error('Cannot resume a dead routine') + end + + if not self.filter or self.filter == event or event == "terminate" then + local s, m = coroutine.resume(self.co, event, ...) + + if coroutine.status(self.co) == 'dead' then + self.co = nil + self.filter = nil + Event.routines[self.uid] = nil + else + self.filter = m + end + + if not s and event ~= 'terminate' then + debug({s, m}) + debug(self) + debug(getfenv(1)) + error('\n' .. (m or 'Error processing event')) + end + + return s, m + end + + return true, self.filter +end + +local function nextUID() + Event.uid = Event.uid + 1 + return Event.uid - 1 +end + +function Event.on(type, fn) + local event = Event.types[type] if not event then - event = { handlers = { } } - Event.handlers[type] = event + event = { } + Event.types[type] = event end local handler = { - uid = Event.uid, + uid = nextUID(), event = type, - f = f, + fn = fn, } - Event.uid = Event.uid + 1 - event.handlers[handler.uid] = handler + event[handler.uid] = handler + setmetatable(handler, { __index = Routine }) return handler end -function Event.removeHandler(h) +function Event.off(h) if h and h.event then - Event.handlers[h.event].handlers[h.uid] = nil + Event.types[h.event][h.uid] = nil end end -function Event.queueTimedEvent(name, timeout, event, args) - Event.addNamedTimer(name, timeout, false, - function() - os.queueEvent(event, args) +local function addTimer(interval, recurring, fn) + + local timerId = os.startTimer(interval) + + return Event.on('timer', function(t, id) + if timerId == id then + fn(t, id) + if recurring then + timerId = os.startTimer(interval) + else + Event.off(t) + end end - ) + end) end -function Event.addNamedTimer(name, interval, recurring, f) +function Event.onInterval(interval, fn) + return addTimer(interval, true, fn) +end + +function Event.onTimeout(timeout, fn) + return addTimer(timeout, false, fn) +end + +function Event.addNamedTimer(name, interval, recurring, fn) Event.cancelNamedTimer(name) - Event.handlers.namedTimers[name] = Event.addTimer(interval, recurring, f) -end - -function Event.getNamedTimer(name) - return Event.handlers.namedTimers[name] + Event.timers[name] = addTimer(interval, recurring, fn) end function Event.cancelNamedTimer(name) - local timer = Event.getNamedTimer(name) + local timer = Event.timers[name] if timer then - timer.enabled = false - Event.removeHandler(timer) + Event.off(timer) end end -function Event.addTimer(interval, recurring, f) - local timer = Event.addHandler('timer', - function(t, id) - if t.timerId ~= id then - return - end - if t.enabled then - t.fired = true - t.cf(t, id) - end - if t.recurring then - t.fired = false - t.timerId = os.startTimer(t.interval) - else - Event.removeHandler(t) - end - end - ) - timer.cf = f - timer.interval = interval - timer.recurring = recurring - timer.enabled = true - timer.timerId = os.startTimer(interval) - - return timer -end - -function Event.onInterval(interval, f) - return Event.addTimer(interval, true, f) -end - -function Event.onTimeout(timeout, f) - return Event.addTimer(timeout, false, f) -end - function Event.waitForEvent(event, timeout) local timerId = os.startTimer(timeout) repeat - local e, p1, p2, p3, p4 = os.pullEvent() - if e == event then - return e, p1, p2, p3, p4 + local e = { os.pullEvent() } + if e[1] == event then + return table.unpack(e) end - until e == 'timer' and p1 == timerId + until e[1] == 'timer' and e[2] == timerId end -function Event.addRoutine(routine) - local r = { co = coroutine.create(routine) } - local s, m = coroutine.resume(r.co) - if not s then - error(m or 'Error processing routine') - end - Event.routines[r] = true - r.filter = m +function Event.addRoutine(fn) + local r = { + co = coroutine.create(fn), + uid = nextUID() + } + setmetatable(r, { __index = Routine }) + Event.routines[r.uid] = r + + r:resume() + return r end function Event.pullEvents(...) - for _, r in ipairs({ ... }) do - Event.addRoutine(r) + for _, fn in ipairs({ ... }) do + Event.addRoutine(fn) end repeat @@ -128,28 +160,43 @@ function Event.exitPullEvents() os.sleep(0) end +local function processHandlers(e, ...) + + local event = Event.types[e] + if event then + + local keys = Util.keys(event) + for _,key in pairs(keys) do + + local h = event[key] + if h and not h.co then + -- callbacks are single threaded (only 1 co per handler) + h.co = coroutine.create(h.fn) + Event.routines[h.uid] = h + h:resume(h, ...) + end + end + end +end + +local function processRoutines(...) + local keys = Util.keys(Event.routines) + for _,key in ipairs(keys) do + local r = Event.routines[key] + if r then + r:resume(...) + end + end +end + function Event.pullEvent(eventType) while true do local e = { os.pullEventRaw() } - local routines = Util.keys(Event.routines) - for _, r in ipairs(routines) do - if not r.filter or r.filter == e[1] then - local s, m = coroutine.resume(r.co, table.unpack(e)) - if not s and e[1] ~= 'terminate' then - debug({s, m}) - debug(r) - error(m or 'Error processing event') - end - if coroutine.status(r.co) == 'dead' then - r.co = nil - Event.routines[r] = nil - else - r.filter = m - end - end - end - Event.processEvent(e) + + processHandlers(table.unpack(e)) + processRoutines(table.unpack(e)) + if Event.terminate or e[1] == 'terminate' then Event.terminate = false return { 'terminate' } @@ -161,37 +208,4 @@ function Event.pullEvent(eventType) end end -function Event.processEvent(pe) - - local e, p1, p2, p3, p4, p5 = unpack(pe) - - local event = Event.handlers[e] - if event then - local keys = Util.keys(event.handlers) - for _,key in pairs(keys) do - local h = event.handlers[key] - if h and not h.co then - local co = coroutine.create(function() - h.f(h, p1, p2, p3, p4, p5) - end) - local s, m = coroutine.resume(co) - if not s then - debug({s, m}) - debug(h) - error(m or 'Error processing ' .. e) - elseif coroutine.status(co) ~= 'dead' then - h.co = co - h.filter = m - Event.routines[h] = true - end - end - end - end - - return e, p1, p2, p3, p4, p5 -end - -Event.on = Event.addHandler -Event.off = Event.removeHandler - return Event diff --git a/sys/apis/message.lua b/sys/apis/message.lua index 1fd2546..fd38ed1 100644 --- a/sys/apis/message.lua +++ b/sys/apis/message.lua @@ -18,7 +18,7 @@ if device and device.wireless_modem then Message.enable() end -Event.addHandler('device_attach', function(event, deviceName) +Event.on('device_attach', function(event, deviceName) if deviceName == 'wireless_modem' then Message.enable() end @@ -41,7 +41,7 @@ function Message.removeHandler(h) end end -Event.addHandler('modem_message', +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 diff --git a/sys/apis/ui.lua b/sys/apis/ui.lua index 4a0d9c4..38e01db 100644 --- a/sys/apis/ui.lua +++ b/sys/apis/ui.lua @@ -66,8 +66,20 @@ function Manager:init(args) local shift = false local mouseDragged = false local pages = { } + local running = false - Event.on('term_resize', function(h, side) + -- single thread all input events + local function singleThread(event, fn) + Event.on(event, function(...) + if not running then + running = true + fn(...) + running = false + end + end) + end + + singleThread('term_resize', function(h, side) if self.currentPage then -- the parent doesn't have any children set... -- that's why we have to resize both the parent and the current page @@ -81,7 +93,7 @@ function Manager:init(args) end end) - Event.on('mouse_scroll', function(h, direction, x, y) + singleThread('mouse_scroll', function(h, direction, x, y) if self.target then local event = self:pointToChild(self.target, x, y) local directions = { @@ -97,7 +109,7 @@ function Manager:init(args) end) -- this should be moved to the device ! - Event.on('monitor_touch', function(h, side, x, y) + singleThread('monitor_touch', function(h, side, x, y) if self.currentPage then if self.currentPage.parent.device.side == side then self:click(1, x, y) @@ -105,7 +117,7 @@ function Manager:init(args) end end) - Event.on('mouse_click', function(h, button, x, y) + singleThread('mouse_click', function(h, button, x, y) mouseDragged = false if button == 1 and shift and control then -- debug hack @@ -123,7 +135,7 @@ function Manager:init(args) end end) - Event.on('mouse_up', function(h, button, x, y) + singleThread('mouse_up', function(h, button, x, y) if self.currentPage and not mouseDragged then if not self.currentPage.parent.device.side then @@ -132,7 +144,7 @@ function Manager:init(args) end end) - Event.on('mouse_drag', function(h, button, x, y) + singleThread('mouse_drag', function(h, button, x, y) mouseDragged = true if self.target then @@ -146,7 +158,7 @@ function Manager:init(args) end end) - Event.on('paste', function(h, text) + singleThread('paste', function(h, text) if clipboard.isInternal() then text = clipboard.getData() end @@ -156,7 +168,7 @@ function Manager:init(args) end end) - Event.on('char', function(h, ch) + singleThread('char', function(h, ch) control = false if self.currentPage then self:inputEvent(self.currentPage.focused, { type = 'key', key = ch }) @@ -164,7 +176,7 @@ function Manager:init(args) end end) - Event.on('key_up', function(h, code) + singleThread('key_up', function(h, code) if code == keys.leftCtrl or code == keys.rightCtrl then control = false elseif code == keys.leftShift or code == keys.rightShift then @@ -172,7 +184,7 @@ function Manager:init(args) end end) - Event.on('key', function(h, code) + singleThread('key', function(h, code) local ch = keys.getName(code) if not ch then return @@ -337,6 +349,9 @@ function Manager:click(button, x, y) button = 3 self.doubleClickTimer = nil else +if self.doubleClickTimer then +debug(c - self.doubleClickTimer) +end self.doubleClickTimer = c self.doubleClickX = x self.doubleClickY = y diff --git a/sys/apps/Events.lua b/sys/apps/Events.lua index 9e6c534..525a2be 100644 --- a/sys/apps/Events.lua +++ b/sys/apps/Events.lua @@ -103,7 +103,7 @@ function page.grid:draw() UI.Grid.draw(self) end -function eventLoop() +Event.addRoutine(function() while true do local e = { os.pullEvent() } @@ -124,8 +124,7 @@ function eventLoop() page:sync() end end -end +end) UI:setPage(page) -Event.pullEvents(eventLoop) -UI.term:reset() +UI:pullEvents() diff --git a/sys/apps/Help.lua b/sys/apps/Help.lua index ab2f75c..1ac0132 100644 --- a/sys/apps/Help.lua +++ b/sys/apps/Help.lua @@ -50,9 +50,11 @@ function page:eventHandler(event) Event.exitPullEvents() elseif event.type == 'key' and event.key == 'enter' then - showHelp(self.grid:getSelected().name) - self:setFocus(self.filter) - self:draw() + if self.grid:getSelected() then + showHelp(self.grid:getSelected().name) + self:setFocus(self.filter) + self:draw() + end elseif event.type == 'grid_select' then showHelp(event.selected.name) @@ -80,5 +82,4 @@ function page:eventHandler(event) end UI:setPage(page) -Event.pullEvents() -UI.term:reset() +UI:pullEvents() diff --git a/sys/apps/Network.lua b/sys/apps/Network.lua index fadc339..c7ecc42 100644 --- a/sys/apps/Network.lua +++ b/sys/apps/Network.lua @@ -141,5 +141,4 @@ if not device.wireless_modem then end UI:setPage(page) -Event.pullEvents() -UI.term:reset() +UI:pullEvents() diff --git a/sys/apps/Overview.lua b/sys/apps/Overview.lua index 00fb107..2f4cb72 100644 --- a/sys/apps/Overview.lua +++ b/sys/apps/Overview.lua @@ -476,7 +476,7 @@ UI:setPages({ main = page, }) -Event.addHandler('os_register_app', function() +Event.on('os_register_app', function() loadApplications() page:refresh() page:draw() diff --git a/sys/apps/Peripherals.lua b/sys/apps/Peripherals.lua index 0a59df2..5f58a69 100644 --- a/sys/apps/Peripherals.lua +++ b/sys/apps/Peripherals.lua @@ -201,11 +201,11 @@ function methodsPage.viewportConsole:draw() c.ymax = c.cursorY + 1 end -Event.addHandler('peripheral', function() +Event.on('peripheral', function() peripheralsPage:updatePeripherals() end) -Event.addHandler('peripheral_detach', function() +Event.on('peripheral_detach', function() peripheralsPage:updatePeripherals() end) @@ -215,5 +215,4 @@ UI:setPages({ methods = methodsPage, }) -Event.pullEvents() -UI.term:reset() +UI:pullEvents() diff --git a/sys/apps/Tabs.lua b/sys/apps/Tabs.lua index 7fabe27..4762ec2 100644 --- a/sys/apps/Tabs.lua +++ b/sys/apps/Tabs.lua @@ -62,12 +62,11 @@ function page.grid:getDisplayValues(row) return row end -Event.addTimer(1, true, function() +Event.onInterval(1, function() page.grid:update() page.grid:draw() page:sync() end) UI:setPage(page) -Event.pullEvents() -UI.term:reset() +UI:pullEvents() diff --git a/sys/apps/Turtles.lua b/sys/apps/Turtles.lua index 8af2b22..14a4df6 100644 --- a/sys/apps/Turtles.lua +++ b/sys/apps/Turtles.lua @@ -1,4 +1,5 @@ require = requireInjector(getfenv(1)) +local Event = require('event') local UI = require('ui') local Socket = require('socket') local Terminal = require('terminal') @@ -320,20 +321,6 @@ function page:enable() -- self.tabs:activateTab(page.tabs.turtles) end -local function updateThread() - - while true do - if page.turtle then - local t = _G.network[page.turtle.id] - page.turtle = t - page:draw() - page:sync() - end - - os.sleep(1) - end -end - if not Util.getOptions(options, { ... }, true) then return end @@ -348,9 +335,17 @@ if options.turtle.value >= 0 then end end +Event.onInterval(1, function() + if page.turtle then + local t = _G.network[page.turtle.id] + page.turtle = t + page:draw() + page:sync() + end +end) + UI:setPage(page) page.tabs:activateTab(page.tabs[options.tab.value]) -UI:pullEvents(updateThread) -UI.term:reset() +UI:pullEvents() diff --git a/sys/apps/builder.lua b/sys/apps/builder.lua index 0601096..257a5b2 100644 --- a/sys/apps/builder.lua +++ b/sys/apps/builder.lua @@ -475,7 +475,7 @@ function Builder:getSupplies() return t end -Event.addHandler('build', function() +Event.on('build', function() Builder:build() end) diff --git a/sys/apps/chestManager.lua b/sys/apps/chestManager.lua index 1ffa026..042fc6b 100644 --- a/sys/apps/chestManager.lua +++ b/sys/apps/chestManager.lua @@ -999,32 +999,29 @@ jobMonitor() jobListGrid:draw() jobListGrid:sync() -local function craftingThread() +Event.onInterval(5, function() - while true do - os.sleep(5) - if not craftingPaused then - local items = chestProvider:listItems() - if Util.size(items) == 0 then - jobListGrid.parent:clear() - jobListGrid.parent:centeredWrite(math.ceil(jobListGrid.parent.height/2), 'No items in system') - jobListGrid:sync() + if not craftingPaused then + local items = chestProvider:listItems() + if Util.size(items) == 0 then + jobListGrid.parent:clear() + jobListGrid.parent:centeredWrite(math.ceil(jobListGrid.parent.height/2), 'No items in system') + jobListGrid:sync() - else - local craftList = watchResources(items) - jobListGrid:setValues(craftList) - --jobListGrid:draw() - --jobListGrid:sync() - craftItems(craftList, items) - jobListGrid:update() - jobListGrid:draw() - jobListGrid:sync() - craftList = getAutocraftItems(items) -- autocrafted items don't show on job monitor - craftItems(craftList, items) - end + else + local craftList = watchResources(items) + jobListGrid:setValues(craftList) + --jobListGrid:draw() + --jobListGrid:sync() + craftItems(craftList, items) + jobListGrid:update() + jobListGrid:draw() + jobListGrid:sync() + craftList = getAutocraftItems(items) -- autocrafted items don't show on job monitor + craftItems(craftList, items) end end -end +end) -UI:pullEvents(craftingThread) +UI:pullEvents() jobListGrid.parent:reset() diff --git a/sys/apps/pickup.lua b/sys/apps/pickup.lua index d62d92e..e24456b 100644 --- a/sys/apps/pickup.lua +++ b/sys/apps/pickup.lua @@ -4,7 +4,7 @@ local Socket = require('socket') local MEProvider = require('meProvider') local Logger = require('logger') local Point = require('point') -local process = require('process') +local Event = require('event') if not device.wireless_modem then error('Modem is required') @@ -16,14 +16,6 @@ if not turtle then error('Can only be run on a turtle') end -turtle.clearMoveCallback() - -local gps = GPS.getPointAndHeading() -if not gps then - error('could not get gps location') -end -turtle.setPoint(gps) - local blocks = { } local meProvider = MEProvider() local items = { } @@ -50,7 +42,7 @@ turtle.setMoveCallback(function(action, pt) for _,slot in pairs(slots) do if turtle.getItemCount(slot.index) ~= slot.qty then printError('Slots changed') - process:terminate() + Event.exitPullEvents() end end end @@ -109,7 +101,8 @@ function gotoPoint(pt, doDetect) end if doDetect and not turtle.detectDown() then - error('Missing target') + printError('Missing target') + Event.exitPullEvents() end end @@ -254,14 +247,14 @@ local function pickupHost(socket) end end -process:newThread('pickup', function() +Event.addRoutine(function() while true do print('waiting for connection on port 5222') local socket = Socket.server(5222) print('pickup: connection from ' .. socket.dhost) - process:newThread('pickup_connection', function() pickupHost(socket) end) + Event.addRoutine(function() pickupHost(socket) end) end end) @@ -304,10 +297,7 @@ local function eachClosestEntry(t, fn) end end -refuel() -turtle.abort = false - -local deliveryThread = process:newThread('deliveries', function() +Event.addRoutine(function() while true do if chestPt then @@ -327,17 +317,17 @@ local deliveryThread = process:newThread('deliveries', function() end os.sleep(60) end + + Event.exitPullEvents() end) -turtle.run(function() +turtle.run(function() - while true do - local e = process:pullEvent() - if e == 'terminate' or deliveryThread:isDead() then - break - end + if not turtle.enableGPS() then + error('turtle: No GPS found') end -end) + refuel() + Event.pullEvents() -process:threadEvent('terminate') +end) diff --git a/sys/apps/shell b/sys/apps/shell index c76368c..e1af945 100644 --- a/sys/apps/shell +++ b/sys/apps/shell @@ -612,7 +612,7 @@ while not bExit do term.setTextColour(_colors.textColor) if #sLine > 0 then local result, err = shell.run( sLine ) - if not result then + if not result and err then printError(err) end end diff --git a/sys/apps/storageActivity.lua b/sys/apps/storageActivity.lua index d65714e..e2b3637 100644 --- a/sys/apps/storageActivity.lua +++ b/sys/apps/storageActivity.lua @@ -164,11 +164,10 @@ function changedPage:refresh() self.grid:draw() end -Event.addTimer(5, true, function() +Event.onInterval(5, function() changedPage:refresh() changedPage:sync() end) UI:setPage(changedPage) UI:pullEvents() -UI.term:reset() diff --git a/sys/apps/storageManager.lua b/sys/apps/storageManager.lua index fe612e0..859d734 100644 --- a/sys/apps/storageManager.lua +++ b/sys/apps/storageManager.lua @@ -896,4 +896,4 @@ Event.onInterval(5, function() end) UI:pullEvents() -jobListGrid.parent:reset() \ No newline at end of file +jobListGrid.parent:reset() diff --git a/sys/apps/supplier.lua b/sys/apps/supplier.lua index 19a81ec..0ae0472 100644 --- a/sys/apps/supplier.lua +++ b/sys/apps/supplier.lua @@ -375,7 +375,7 @@ Message.addHandler('finished', Builder:finish() end) -Event.addHandler('turtle_abort', +Event.on('turtle_abort', function() turtle.abort = false turtle.status = 'aborting' diff --git a/sys/apps/telnet.lua b/sys/apps/telnet.lua index 09d2f44..39666d4 100644 --- a/sys/apps/telnet.lua +++ b/sys/apps/telnet.lua @@ -30,7 +30,6 @@ end local w, h = ct.getSize() socket:write({ - type = 'termInfo', width = w, height = h, isColor = ct.isColor(), @@ -70,7 +69,7 @@ while true do if filter[event] then - if not socket:write({ type = 'shellRemote', event = e }) then + if not socket:write(e) then socket:close() break end diff --git a/sys/boot/multishell.boot b/sys/boot/multishell.boot index 14efaaa..127547c 100644 --- a/sys/boot/multishell.boot +++ b/sys/boot/multishell.boot @@ -1,4 +1,4 @@ -print('\nStarting multishell..') +print('\nStarting Opus..') LUA_PATH = '/sys/apis' diff --git a/sys/etc/scripts/follow b/sys/etc/scripts/follow index 287e8ee..cf17a1d 100644 --- a/sys/etc/scripts/follow +++ b/sys/etc/scripts/follow @@ -2,8 +2,8 @@ local function follow(id) require = requireInjector(getfenv(1)) local Socket = require('socket') - local Point = require('point') - local process = require('process') + local Point = require('point') + local Event = require('event') turtle.status = 'follow ' .. id @@ -20,90 +20,86 @@ local function follow(id) local lastPoint local following = false - local followThread = process:newThread('follower', function() - while true do + Event.on('turtle_follow', function(_, pt) - local function getRemotePoint() - if not turtle.abort then - if socket:write({ type = 'gps' }) then - return socket:read(3) - end + local pts = { + { x = pt.x + 2, z = pt.z, y = pt.y }, + { x = pt.x - 2, z = pt.z, y = pt.y }, + { x = pt.x, z = pt.z + 2, y = pt.y }, + { x = pt.x, z = pt.z - 2, y = pt.y }, + } + + local cpt = Point.closest(turtle.point, pts) + + local blocks = { } + + local function addBlocks(tpt) + table.insert(blocks, tpt) + local apts = Point.adjacentPoints(tpt) + for _,apt in pairs(apts) do + table.insert(blocks, apt) + end + end + + -- don't run into player + addBlocks(pt) + addBlocks({ x = pt.x, z = pt.z, y = pt.y + 1 }) + + if turtle.pathfind(cpt, blocks) then + turtle.headTowards(pt) + end + following = false + end) + + Event.onInterval(.5, function() + + local function getRemotePoint() + if not turtle.abort then + if socket:write({ type = 'gps' }) then + return socket:read(3) end end + end - -- sometimes gps will fail if moving - local pt, d + -- sometimes gps will fail if moving + local pt, d - for i = 1, 3 do - pt, d = getRemotePoint() - if pt then - break - end - os.sleep(.5) + for i = 1, 3 do + pt, d = getRemotePoint() + if pt then + break end - - if not pt or turtle.abort then - error('Did not receive GPS location') - end - - if not lastPoint or (lastPoint.x ~= pt.x or lastPoint.y ~= pt.y or lastPoint.z ~= pt.z) then - - if following then - turtle.abort = true - while following do - os.sleep(.1) - end - turtle.abort = false - end - - -- check if gps is inaccurate (player moving too fast) - if d < Point.pythagoreanDistance(turtle.point, pt) + 10 then - lastPoint = Point.copy(pt) - following = true - process:newThread('turtle_follow', function() - - local pts = { - { x = pt.x + 2, z = pt.z, y = pt.y }, - { x = pt.x - 2, z = pt.z, y = pt.y }, - { x = pt.x, z = pt.z + 2, y = pt.y }, - { x = pt.x, z = pt.z - 2, y = pt.y }, - } - - local cpt = Point.closest(turtle.point, pts) - - local blocks = { } - - local function addBlocks(tpt) - table.insert(blocks, tpt) - local apts = Point.adjacentPoints(tpt) - for _,apt in pairs(apts) do - table.insert(blocks, apt) - end - end - - -- don't run into player - addBlocks(pt) - addBlocks({ x = pt.x, z = pt.z, y = pt.y + 1 }) - - if turtle.pathfind(cpt, blocks) then - turtle.headTowards(pt) - end - following = false - end) - end - end - os.sleep(.5) end + + if not pt or turtle.abort then + error('Did not receive GPS location') + end + + if not lastPoint or (lastPoint.x ~= pt.x or lastPoint.y ~= pt.y or lastPoint.z ~= pt.z) then + + if following then + turtle.abort = true + while following do + os.sleep(.1) + end + turtle.abort = false + end + + -- check if gps is inaccurate (player moving too fast) + if d < Point.pythagoreanDistance(turtle.point, pt) + 10 then + lastPoint = Point.copy(pt) + following = true + os.queueEvent('turtle_follow', pt) + end + end end) - while true do - local e = process:pullEvent() - if e == 'terminate' or followThread:isDead() or e =='turtle_abort' then - process:threadEvent('terminate') - break - end - end + Event.on('turtle_abort', function() + Event.exitPullEvents() + end) + + Event.pullEvents() socket:close() @@ -114,4 +110,3 @@ local s, m = turtle.run(function() follow({COMPUTER_ID}) end) if not s and m then error(m) end - diff --git a/sys/network/telnet.lua b/sys/network/telnet.lua index 8c1e045..37a7339 100644 --- a/sys/network/telnet.lua +++ b/sys/network/telnet.lua @@ -1,7 +1,10 @@ local Socket = require('socket') local process = require('process') -local function wrapTerm(socket, termInfo) +local function telnetHost(socket, termInfo) + + require = requireInjector(getfenv(1)) + local Event = require('event') local methods = { 'clear', 'clearLine', 'setCursorPos', 'write', 'blit', 'setTextColor', 'setTextColour', 'setBackgroundColor', 'setBackgroundColour', 'scroll', 'setCursorBlink', } @@ -11,10 +14,15 @@ local function wrapTerm(socket, termInfo) for _,k in pairs(methods) do socket.term[k] = function(...) + if not socket.queue then socket.queue = { } - os.startTimer(0) + Event.onTimeout(0, function() + socket:write(socket.queue) + socket.queue = nil + end) end + table.insert(socket.queue, { f = k, args = { ... }, @@ -26,54 +34,28 @@ local function wrapTerm(socket, termInfo) socket.term.getSize = function() return termInfo.width, termInfo.height end -end -local function telnetHost(socket, termInfo) - - require = requireInjector(getfenv(1)) - local process = require('process') - - wrapTerm(socket, termInfo) - - local shellThread = process:newThread('shell_wrapper', function() + local shellThread = Event.addRoutine(function() os.run(getfenv(1), 'sys/apps/shell') - socket:close() + Event.exitPullEvents() end) - process:newThread('telnet_read', function() + Event.addRoutine(function() while true do local data = socket:read() if not data then + Event.exitPullEvents() break end - if data.type == 'shellRemote' then - local event = table.remove(data.event, 1) - shellThread:resume(event, unpack(data.event)) - end + shellThread:resume(table.unpack(data)) end end) - while true do - local e = process:pullEvent('timer') - - if e == 'terminate' then - break - end - if not socket.connected then - break - end - if socket.queue then - if not socket:write(socket.queue) then - print('telnet: connection lost to ' .. socket.dhost) - break - end - socket.queue = nil - end - end + Event.pullEvents() socket:close() - process:threadEvent('terminate') + shellThread:terminate() end process:newThread('telnet_server', function()