Replace process.api with Event

This commit is contained in:
kepler155c@gmail.com 2017-07-28 19:01:59 -04:00
parent f8bcf90a6b
commit be51935662
21 changed files with 326 additions and 343 deletions

View File

@ -1,121 +1,153 @@
local Util = require('util') local Util = require('util')
local Event = { local Event = {
uid = 1, -- unique id for handlers uid = 1, -- unique id for handlers
routines = { }, routines = { }, -- coroutines
handlers = { namedTimers = { } }, types = { }, -- event handlers
timers = { }, -- named timers
terminate = false, terminate = false,
} }
function Event.addHandler(type, f) local Routine = { }
local event = Event.handlers[type]
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 if not event then
event = { handlers = { } } event = { }
Event.handlers[type] = event Event.types[type] = event
end end
local handler = { local handler = {
uid = Event.uid, uid = nextUID(),
event = type, event = type,
f = f, fn = fn,
} }
Event.uid = Event.uid + 1 event[handler.uid] = handler
event.handlers[handler.uid] = handler setmetatable(handler, { __index = Routine })
return handler return handler
end end
function Event.removeHandler(h) function Event.off(h)
if h and h.event then if h and h.event then
Event.handlers[h.event].handlers[h.uid] = nil Event.types[h.event][h.uid] = nil
end end
end end
function Event.queueTimedEvent(name, timeout, event, args) local function addTimer(interval, recurring, fn)
Event.addNamedTimer(name, timeout, false,
function() local timerId = os.startTimer(interval)
os.queueEvent(event, args)
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)
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.cancelNamedTimer(name)
Event.handlers.namedTimers[name] = Event.addTimer(interval, recurring, f) Event.timers[name] = addTimer(interval, recurring, fn)
end
function Event.getNamedTimer(name)
return Event.handlers.namedTimers[name]
end end
function Event.cancelNamedTimer(name) function Event.cancelNamedTimer(name)
local timer = Event.getNamedTimer(name) local timer = Event.timers[name]
if timer then if timer then
timer.enabled = false Event.off(timer)
Event.removeHandler(timer)
end end
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) function Event.waitForEvent(event, timeout)
local timerId = os.startTimer(timeout) local timerId = os.startTimer(timeout)
repeat repeat
local e, p1, p2, p3, p4 = os.pullEvent() local e = { os.pullEvent() }
if e == event then if e[1] == event then
return e, p1, p2, p3, p4 return table.unpack(e)
end end
until e == 'timer' and p1 == timerId until e[1] == 'timer' and e[2] == timerId
end end
function Event.addRoutine(routine) function Event.addRoutine(fn)
local r = { co = coroutine.create(routine) } local r = {
local s, m = coroutine.resume(r.co) co = coroutine.create(fn),
if not s then uid = nextUID()
error(m or 'Error processing routine') }
end setmetatable(r, { __index = Routine })
Event.routines[r] = true Event.routines[r.uid] = r
r.filter = m
r:resume()
return r return r
end end
function Event.pullEvents(...) function Event.pullEvents(...)
for _, r in ipairs({ ... }) do for _, fn in ipairs({ ... }) do
Event.addRoutine(r) Event.addRoutine(fn)
end end
repeat repeat
@ -128,28 +160,43 @@ function Event.exitPullEvents()
os.sleep(0) os.sleep(0)
end 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) function Event.pullEvent(eventType)
while true do while true do
local e = { os.pullEventRaw() } local e = { os.pullEventRaw() }
local routines = Util.keys(Event.routines)
for _, r in ipairs(routines) do processHandlers(table.unpack(e))
if not r.filter or r.filter == e[1] then processRoutines(table.unpack(e))
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)
if Event.terminate or e[1] == 'terminate' then if Event.terminate or e[1] == 'terminate' then
Event.terminate = false Event.terminate = false
return { 'terminate' } return { 'terminate' }
@ -161,37 +208,4 @@ function Event.pullEvent(eventType)
end end
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 return Event

View File

@ -18,7 +18,7 @@ if device and device.wireless_modem then
Message.enable() Message.enable()
end end
Event.addHandler('device_attach', function(event, deviceName) Event.on('device_attach', function(event, deviceName)
if deviceName == 'wireless_modem' then if deviceName == 'wireless_modem' then
Message.enable() Message.enable()
end end
@ -41,7 +41,7 @@ function Message.removeHandler(h)
end end
end end
Event.addHandler('modem_message', Event.on('modem_message',
function(event, side, sendChannel, replyChannel, msg, distance) function(event, side, sendChannel, replyChannel, msg, distance)
if msg and msg.type then -- filter out messages from other systems if msg and msg.type then -- filter out messages from other systems
local id = replyChannel local id = replyChannel

View File

@ -66,8 +66,20 @@ function Manager:init(args)
local shift = false local shift = false
local mouseDragged = false local mouseDragged = false
local pages = { } 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 if self.currentPage then
-- the parent doesn't have any children set... -- the parent doesn't have any children set...
-- that's why we have to resize both the parent and the current page -- that's why we have to resize both the parent and the current page
@ -81,7 +93,7 @@ function Manager:init(args)
end end
end) end)
Event.on('mouse_scroll', function(h, direction, x, y) singleThread('mouse_scroll', function(h, direction, x, y)
if self.target then if self.target then
local event = self:pointToChild(self.target, x, y) local event = self:pointToChild(self.target, x, y)
local directions = { local directions = {
@ -97,7 +109,7 @@ function Manager:init(args)
end) end)
-- this should be moved to the device ! -- 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 then
if self.currentPage.parent.device.side == side then if self.currentPage.parent.device.side == side then
self:click(1, x, y) self:click(1, x, y)
@ -105,7 +117,7 @@ function Manager:init(args)
end end
end) end)
Event.on('mouse_click', function(h, button, x, y) singleThread('mouse_click', function(h, button, x, y)
mouseDragged = false mouseDragged = false
if button == 1 and shift and control then -- debug hack if button == 1 and shift and control then -- debug hack
@ -123,7 +135,7 @@ function Manager:init(args)
end end
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 self.currentPage and not mouseDragged then
if not self.currentPage.parent.device.side then if not self.currentPage.parent.device.side then
@ -132,7 +144,7 @@ function Manager:init(args)
end end
end) end)
Event.on('mouse_drag', function(h, button, x, y) singleThread('mouse_drag', function(h, button, x, y)
mouseDragged = true mouseDragged = true
if self.target then if self.target then
@ -146,7 +158,7 @@ function Manager:init(args)
end end
end) end)
Event.on('paste', function(h, text) singleThread('paste', function(h, text)
if clipboard.isInternal() then if clipboard.isInternal() then
text = clipboard.getData() text = clipboard.getData()
end end
@ -156,7 +168,7 @@ function Manager:init(args)
end end
end) end)
Event.on('char', function(h, ch) singleThread('char', function(h, ch)
control = false control = false
if self.currentPage then if self.currentPage then
self:inputEvent(self.currentPage.focused, { type = 'key', key = ch }) self:inputEvent(self.currentPage.focused, { type = 'key', key = ch })
@ -164,7 +176,7 @@ function Manager:init(args)
end end
end) end)
Event.on('key_up', function(h, code) singleThread('key_up', function(h, code)
if code == keys.leftCtrl or code == keys.rightCtrl then if code == keys.leftCtrl or code == keys.rightCtrl then
control = false control = false
elseif code == keys.leftShift or code == keys.rightShift then elseif code == keys.leftShift or code == keys.rightShift then
@ -172,7 +184,7 @@ function Manager:init(args)
end end
end) end)
Event.on('key', function(h, code) singleThread('key', function(h, code)
local ch = keys.getName(code) local ch = keys.getName(code)
if not ch then if not ch then
return return
@ -337,6 +349,9 @@ function Manager:click(button, x, y)
button = 3 button = 3
self.doubleClickTimer = nil self.doubleClickTimer = nil
else else
if self.doubleClickTimer then
debug(c - self.doubleClickTimer)
end
self.doubleClickTimer = c self.doubleClickTimer = c
self.doubleClickX = x self.doubleClickX = x
self.doubleClickY = y self.doubleClickY = y

View File

@ -103,7 +103,7 @@ function page.grid:draw()
UI.Grid.draw(self) UI.Grid.draw(self)
end end
function eventLoop() Event.addRoutine(function()
while true do while true do
local e = { os.pullEvent() } local e = { os.pullEvent() }
@ -124,8 +124,7 @@ function eventLoop()
page:sync() page:sync()
end end
end end
end end)
UI:setPage(page) UI:setPage(page)
Event.pullEvents(eventLoop) UI:pullEvents()
UI.term:reset()

View File

@ -50,9 +50,11 @@ function page:eventHandler(event)
Event.exitPullEvents() Event.exitPullEvents()
elseif event.type == 'key' and event.key == 'enter' then elseif event.type == 'key' and event.key == 'enter' then
showHelp(self.grid:getSelected().name) if self.grid:getSelected() then
self:setFocus(self.filter) showHelp(self.grid:getSelected().name)
self:draw() self:setFocus(self.filter)
self:draw()
end
elseif event.type == 'grid_select' then elseif event.type == 'grid_select' then
showHelp(event.selected.name) showHelp(event.selected.name)
@ -80,5 +82,4 @@ function page:eventHandler(event)
end end
UI:setPage(page) UI:setPage(page)
Event.pullEvents() UI:pullEvents()
UI.term:reset()

View File

@ -141,5 +141,4 @@ if not device.wireless_modem then
end end
UI:setPage(page) UI:setPage(page)
Event.pullEvents() UI:pullEvents()
UI.term:reset()

View File

@ -476,7 +476,7 @@ UI:setPages({
main = page, main = page,
}) })
Event.addHandler('os_register_app', function() Event.on('os_register_app', function()
loadApplications() loadApplications()
page:refresh() page:refresh()
page:draw() page:draw()

View File

@ -201,11 +201,11 @@ function methodsPage.viewportConsole:draw()
c.ymax = c.cursorY + 1 c.ymax = c.cursorY + 1
end end
Event.addHandler('peripheral', function() Event.on('peripheral', function()
peripheralsPage:updatePeripherals() peripheralsPage:updatePeripherals()
end) end)
Event.addHandler('peripheral_detach', function() Event.on('peripheral_detach', function()
peripheralsPage:updatePeripherals() peripheralsPage:updatePeripherals()
end) end)
@ -215,5 +215,4 @@ UI:setPages({
methods = methodsPage, methods = methodsPage,
}) })
Event.pullEvents() UI:pullEvents()
UI.term:reset()

View File

@ -62,12 +62,11 @@ function page.grid:getDisplayValues(row)
return row return row
end end
Event.addTimer(1, true, function() Event.onInterval(1, function()
page.grid:update() page.grid:update()
page.grid:draw() page.grid:draw()
page:sync() page:sync()
end) end)
UI:setPage(page) UI:setPage(page)
Event.pullEvents() UI:pullEvents()
UI.term:reset()

View File

@ -1,4 +1,5 @@
require = requireInjector(getfenv(1)) require = requireInjector(getfenv(1))
local Event = require('event')
local UI = require('ui') local UI = require('ui')
local Socket = require('socket') local Socket = require('socket')
local Terminal = require('terminal') local Terminal = require('terminal')
@ -320,20 +321,6 @@ function page:enable()
-- self.tabs:activateTab(page.tabs.turtles) -- self.tabs:activateTab(page.tabs.turtles)
end 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 if not Util.getOptions(options, { ... }, true) then
return return
end end
@ -348,9 +335,17 @@ if options.turtle.value >= 0 then
end end
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) UI:setPage(page)
page.tabs:activateTab(page.tabs[options.tab.value]) page.tabs:activateTab(page.tabs[options.tab.value])
UI:pullEvents(updateThread) UI:pullEvents()
UI.term:reset()

View File

@ -475,7 +475,7 @@ function Builder:getSupplies()
return t return t
end end
Event.addHandler('build', function() Event.on('build', function()
Builder:build() Builder:build()
end) end)

View File

@ -999,32 +999,29 @@ jobMonitor()
jobListGrid:draw() jobListGrid:draw()
jobListGrid:sync() jobListGrid:sync()
local function craftingThread() Event.onInterval(5, function()
while true do if not craftingPaused then
os.sleep(5) local items = chestProvider:listItems()
if not craftingPaused then if Util.size(items) == 0 then
local items = chestProvider:listItems() jobListGrid.parent:clear()
if Util.size(items) == 0 then jobListGrid.parent:centeredWrite(math.ceil(jobListGrid.parent.height/2), 'No items in system')
jobListGrid.parent:clear() jobListGrid:sync()
jobListGrid.parent:centeredWrite(math.ceil(jobListGrid.parent.height/2), 'No items in system')
jobListGrid:sync()
else else
local craftList = watchResources(items) local craftList = watchResources(items)
jobListGrid:setValues(craftList) jobListGrid:setValues(craftList)
--jobListGrid:draw() --jobListGrid:draw()
--jobListGrid:sync() --jobListGrid:sync()
craftItems(craftList, items) craftItems(craftList, items)
jobListGrid:update() jobListGrid:update()
jobListGrid:draw() jobListGrid:draw()
jobListGrid:sync() jobListGrid:sync()
craftList = getAutocraftItems(items) -- autocrafted items don't show on job monitor craftList = getAutocraftItems(items) -- autocrafted items don't show on job monitor
craftItems(craftList, items) craftItems(craftList, items)
end
end end
end end
end end)
UI:pullEvents(craftingThread) UI:pullEvents()
jobListGrid.parent:reset() jobListGrid.parent:reset()

View File

@ -4,7 +4,7 @@ local Socket = require('socket')
local MEProvider = require('meProvider') local MEProvider = require('meProvider')
local Logger = require('logger') local Logger = require('logger')
local Point = require('point') local Point = require('point')
local process = require('process') local Event = require('event')
if not device.wireless_modem then if not device.wireless_modem then
error('Modem is required') error('Modem is required')
@ -16,14 +16,6 @@ if not turtle then
error('Can only be run on a turtle') error('Can only be run on a turtle')
end end
turtle.clearMoveCallback()
local gps = GPS.getPointAndHeading()
if not gps then
error('could not get gps location')
end
turtle.setPoint(gps)
local blocks = { } local blocks = { }
local meProvider = MEProvider() local meProvider = MEProvider()
local items = { } local items = { }
@ -50,7 +42,7 @@ turtle.setMoveCallback(function(action, pt)
for _,slot in pairs(slots) do for _,slot in pairs(slots) do
if turtle.getItemCount(slot.index) ~= slot.qty then if turtle.getItemCount(slot.index) ~= slot.qty then
printError('Slots changed') printError('Slots changed')
process:terminate() Event.exitPullEvents()
end end
end end
end end
@ -109,7 +101,8 @@ function gotoPoint(pt, doDetect)
end end
if doDetect and not turtle.detectDown() then if doDetect and not turtle.detectDown() then
error('Missing target') printError('Missing target')
Event.exitPullEvents()
end end
end end
@ -254,14 +247,14 @@ local function pickupHost(socket)
end end
end end
process:newThread('pickup', function() Event.addRoutine(function()
while true do while true do
print('waiting for connection on port 5222') print('waiting for connection on port 5222')
local socket = Socket.server(5222) local socket = Socket.server(5222)
print('pickup: connection from ' .. socket.dhost) print('pickup: connection from ' .. socket.dhost)
process:newThread('pickup_connection', function() pickupHost(socket) end) Event.addRoutine(function() pickupHost(socket) end)
end end
end) end)
@ -304,10 +297,7 @@ local function eachClosestEntry(t, fn)
end end
end end
refuel() Event.addRoutine(function()
turtle.abort = false
local deliveryThread = process:newThread('deliveries', function()
while true do while true do
if chestPt then if chestPt then
@ -327,17 +317,17 @@ local deliveryThread = process:newThread('deliveries', function()
end end
os.sleep(60) os.sleep(60)
end end
Event.exitPullEvents()
end) end)
turtle.run(function() turtle.run(function()
while true do if not turtle.enableGPS() then
local e = process:pullEvent() error('turtle: No GPS found')
if e == 'terminate' or deliveryThread:isDead() then
break
end
end end
end) refuel()
Event.pullEvents()
process:threadEvent('terminate') end)

View File

@ -612,7 +612,7 @@ while not bExit do
term.setTextColour(_colors.textColor) term.setTextColour(_colors.textColor)
if #sLine > 0 then if #sLine > 0 then
local result, err = shell.run( sLine ) local result, err = shell.run( sLine )
if not result then if not result and err then
printError(err) printError(err)
end end
end end

View File

@ -164,11 +164,10 @@ function changedPage:refresh()
self.grid:draw() self.grid:draw()
end end
Event.addTimer(5, true, function() Event.onInterval(5, function()
changedPage:refresh() changedPage:refresh()
changedPage:sync() changedPage:sync()
end) end)
UI:setPage(changedPage) UI:setPage(changedPage)
UI:pullEvents() UI:pullEvents()
UI.term:reset()

View File

@ -896,4 +896,4 @@ Event.onInterval(5, function()
end) end)
UI:pullEvents() UI:pullEvents()
jobListGrid.parent:reset() jobListGrid.parent:reset()

View File

@ -375,7 +375,7 @@ Message.addHandler('finished',
Builder:finish() Builder:finish()
end) end)
Event.addHandler('turtle_abort', Event.on('turtle_abort',
function() function()
turtle.abort = false turtle.abort = false
turtle.status = 'aborting' turtle.status = 'aborting'

View File

@ -30,7 +30,6 @@ end
local w, h = ct.getSize() local w, h = ct.getSize()
socket:write({ socket:write({
type = 'termInfo',
width = w, width = w,
height = h, height = h,
isColor = ct.isColor(), isColor = ct.isColor(),
@ -70,7 +69,7 @@ while true do
if filter[event] then if filter[event] then
if not socket:write({ type = 'shellRemote', event = e }) then if not socket:write(e) then
socket:close() socket:close()
break break
end end

View File

@ -1,4 +1,4 @@
print('\nStarting multishell..') print('\nStarting Opus..')
LUA_PATH = '/sys/apis' LUA_PATH = '/sys/apis'

View File

@ -2,8 +2,8 @@ local function follow(id)
require = requireInjector(getfenv(1)) require = requireInjector(getfenv(1))
local Socket = require('socket') local Socket = require('socket')
local Point = require('point') local Point = require('point')
local process = require('process') local Event = require('event')
turtle.status = 'follow ' .. id turtle.status = 'follow ' .. id
@ -20,90 +20,86 @@ local function follow(id)
local lastPoint local lastPoint
local following = false local following = false
local followThread = process:newThread('follower', function() Event.on('turtle_follow', function(_, pt)
while true do
local function getRemotePoint() local pts = {
if not turtle.abort then { x = pt.x + 2, z = pt.z, y = pt.y },
if socket:write({ type = 'gps' }) then { x = pt.x - 2, z = pt.z, y = pt.y },
return socket:read(3) { x = pt.x, z = pt.z + 2, y = pt.y },
end { 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 end
end
-- sometimes gps will fail if moving -- sometimes gps will fail if moving
local pt, d local pt, d
for i = 1, 3 do for i = 1, 3 do
pt, d = getRemotePoint() pt, d = getRemotePoint()
if pt then if pt then
break break
end
os.sleep(.5)
end 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) os.sleep(.5)
end 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) end)
while true do Event.on('turtle_abort', function()
local e = process:pullEvent() Event.exitPullEvents()
if e == 'terminate' or followThread:isDead() or e =='turtle_abort' then end)
process:threadEvent('terminate')
break Event.pullEvents()
end
end
socket:close() socket:close()
@ -114,4 +110,3 @@ local s, m = turtle.run(function() follow({COMPUTER_ID}) end)
if not s and m then if not s and m then
error(m) error(m)
end end

View File

@ -1,7 +1,10 @@
local Socket = require('socket') local Socket = require('socket')
local process = require('process') 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', local methods = { 'clear', 'clearLine', 'setCursorPos', 'write', 'blit',
'setTextColor', 'setTextColour', 'setBackgroundColor', 'setTextColor', 'setTextColour', 'setBackgroundColor',
'setBackgroundColour', 'scroll', 'setCursorBlink', } 'setBackgroundColour', 'scroll', 'setCursorBlink', }
@ -11,10 +14,15 @@ local function wrapTerm(socket, termInfo)
for _,k in pairs(methods) do for _,k in pairs(methods) do
socket.term[k] = function(...) socket.term[k] = function(...)
if not socket.queue then if not socket.queue then
socket.queue = { } socket.queue = { }
os.startTimer(0) Event.onTimeout(0, function()
socket:write(socket.queue)
socket.queue = nil
end)
end end
table.insert(socket.queue, { table.insert(socket.queue, {
f = k, f = k,
args = { ... }, args = { ... },
@ -26,54 +34,28 @@ local function wrapTerm(socket, termInfo)
socket.term.getSize = function() socket.term.getSize = function()
return termInfo.width, termInfo.height return termInfo.width, termInfo.height
end end
end
local function telnetHost(socket, termInfo) local shellThread = Event.addRoutine(function()
require = requireInjector(getfenv(1))
local process = require('process')
wrapTerm(socket, termInfo)
local shellThread = process:newThread('shell_wrapper', function()
os.run(getfenv(1), 'sys/apps/shell') os.run(getfenv(1), 'sys/apps/shell')
socket:close() Event.exitPullEvents()
end) end)
process:newThread('telnet_read', function() Event.addRoutine(function()
while true do while true do
local data = socket:read() local data = socket:read()
if not data then if not data then
Event.exitPullEvents()
break break
end end
if data.type == 'shellRemote' then shellThread:resume(table.unpack(data))
local event = table.remove(data.event, 1)
shellThread:resume(event, unpack(data.event))
end
end end
end) end)
while true do Event.pullEvents()
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
socket:close() socket:close()
process:threadEvent('terminate') shellThread:terminate()
end end
process:newThread('telnet_server', function() process:newThread('telnet_server', function()