bit of everything

This commit is contained in:
kepler155c@gmail.com 2017-07-23 22:37:07 -04:00
parent 027f386ed1
commit f8bcf90a6b
30 changed files with 866 additions and 502 deletions

View File

@ -14,7 +14,6 @@ local keys = Util.transpose({
})
function ChestProvider:init(args)
local defaults = {
items = { },
name = 'chest',
@ -43,12 +42,10 @@ function ChestProvider:getCachedItemDetails(item, k)
if not detail then
return
end
-- NOT SUFFICIENT
if detail.name ~= item.name then
return
end
if detail.maxDamage and detail.maxDamage > 0 and detail.damage > 0 then
detail.displayName = detail.displayName .. ' (damaged)'
end
for _,k in ipairs(Util.keys(detail)) do
if not keys[k] then
@ -135,8 +132,8 @@ function ChestProvider:provide(item, qty, slot, direction)
end
end
function ChestProvider:extract(slot, qty)
self.pushItems(self.direction, slot, qty)
function ChestProvider:extract(slot, qty, toSlot)
self.pushItems(self.direction, slot, qty, toSlot)
end
function ChestProvider:insert(slot, qty)

View File

@ -1,25 +1,17 @@
local Util = require('util')
local Process = require('process')
local Event = {
uid = 1, -- unique id for handlers
routines = { },
handlers = { namedTimers = { } },
terminate = false,
}
local eventHandlers = {
namedTimers = {}
}
-- debug purposes
function Event.getHandlers()
return eventHandlers
end
function Event.addHandler(type, f)
local event = eventHandlers[type]
local event = Event.handlers[type]
if not event then
event = {}
event.handlers = {}
eventHandlers[type] = event
event = { handlers = { } }
Event.handlers[type] = event
end
local handler = {
@ -35,7 +27,7 @@ end
function Event.removeHandler(h)
if h and h.event then
eventHandlers[h.event].handlers[h.uid] = nil
Event.handlers[h.event].handlers[h.uid] = nil
end
end
@ -49,11 +41,11 @@ end
function Event.addNamedTimer(name, interval, recurring, f)
Event.cancelNamedTimer(name)
eventHandlers.namedTimers[name] = Event.addTimer(interval, recurring, f)
Event.handlers.namedTimers[name] = Event.addTimer(interval, recurring, f)
end
function Event.getNamedTimer(name)
return eventHandlers.namedTimers[name]
return Event.handlers.namedTimers[name]
end
function Event.cancelNamedTimer(name)
@ -64,11 +56,6 @@ function Event.cancelNamedTimer(name)
end
end
function Event.isTimerActive(timer)
return timer.enabled and
os.clock() < timer.start + timer.interval
end
function Event.addTimer(interval, recurring, f)
local timer = Event.addHandler('timer',
function(t, id)
@ -81,7 +68,6 @@ function Event.addTimer(interval, recurring, f)
end
if t.recurring then
t.fired = false
t.start = os.clock()
t.timerId = os.startTimer(t.interval)
else
Event.removeHandler(t)
@ -91,103 +77,121 @@ function Event.addTimer(interval, recurring, f)
timer.cf = f
timer.interval = interval
timer.recurring = recurring
timer.start = os.clock()
timer.enabled = true
timer.timerId = os.startTimer(interval)
return timer
end
function Event.removeTimer(h)
Event.removeHandler(h)
function Event.onInterval(interval, f)
return Event.addTimer(interval, true, f)
end
function Event.blockUntilEvent(event, timeout)
return Event.waitForEvent(event, timeout, os.pullEvent)
function Event.onTimeout(timeout, f)
return Event.addTimer(timeout, false, f)
end
function Event.waitForEvent(event, timeout, pullEvent)
pullEvent = pullEvent or Event.pullEvent
function Event.waitForEvent(event, timeout)
local timerId = os.startTimer(timeout)
repeat
local e, p1, p2, p3, p4 = pullEvent()
local e, p1, p2, p3, p4 = os.pullEvent()
if e == event then
return e, p1, p2, p3, p4
end
until e == 'timer' and p1 == timerId
end
local exitPullEvents = false
local function _pullEvents()
while true do
local e = { os.pullEvent() }
Event.processEvent(e)
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
end
function Event.sleep(t)
local timerId = os.startTimer(t or 0)
repeat
local event, id = Event.pullEvent()
until event == 'timer' and id == timerId
end
function Event.addThread(fn)
return Process:addThread(fn)
Event.routines[r] = true
r.filter = m
return r
end
function Event.pullEvents(...)
local routines = { ... }
if #routines > 0 then
Process:addThread(_pullEvents)
for _, routine in ipairs(routines) do
Process:addThread(routine)
end
while true do
local e = Process:pullEvent()
if exitPullEvents or e == 'terminate' then
break
end
end
else
while true do
local e = { os.pullEventRaw() }
Event.processEvent(e)
if exitPullEvents or e[1] == 'terminate' then
break
end
end
for _, r in ipairs({ ... }) do
Event.addRoutine(r)
end
repeat
local e = Event.pullEvent()
until e[1] == 'terminate'
end
function Event.exitPullEvents()
exitPullEvents = true
Event.terminate = true
os.sleep(0)
end
function Event.pullEvent(eventType)
local e = { os.pullEventRaw(eventType) }
return Event.processEvent(e)
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)
if Event.terminate or e[1] == 'terminate' then
Event.terminate = false
return { 'terminate' }
end
if not eventType or e[1] == eventType then
return e
end
end
end
function Event.processEvent(pe)
local e, p1, p2, p3, p4, p5 = unpack(pe)
local event = eventHandlers[e]
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 then
h.f(h, p1, p2, p3, p4, p5)
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

View File

@ -12,9 +12,9 @@ local PASTEBIN_URL = 'http://pastebin.com/raw'
local GIT_URL = 'https://raw.githubusercontent.com'
local function standardSearcher(modname, env, shell)
if package.loaded[modname] then
if _G.package.loaded[modname] then
return function()
return package.loaded[modname]
return _G.package.loaded[modname]
end
end
end
@ -33,7 +33,7 @@ end
local function pathSearcher(modname, env, shell)
local fname = modname:gsub('%.', '/') .. '.lua'
for dir in string.gmatch(package.path, "[^:]+") do
for dir in string.gmatch(_G.package.path, "[^:]+") do
local path = fs.combine(dir, fname)
if fs.exists(path) and not fs.isDir(path) then
return loadfile(path, env)
@ -109,7 +109,7 @@ local function urlSearcher(modname, env, shell)
local fname = modname:gsub('%.', '/') .. '.lua'
if fname:sub(1, 1) ~= '/' then
for entry in string.gmatch(package.upath, "[^;]+") do
for entry in string.gmatch(_G.package.upath, "[^;]+") do
local url = entry .. '/' .. fname
local c = loadUrl(url)
if c then
@ -150,7 +150,7 @@ local function requireWrapper(env)
return loaded[modname]
end
for _,searcher in ipairs(package.loaders) do
for _,searcher in ipairs(_G.package.loaders) do
local fn, msg = searcher(modname, env, shell)
if fn then
local module, msg = fn(modname, env)

View File

@ -1,6 +1,6 @@
local TableDB = require('tableDB')
local itemDB = TableDB({ fileName = 'usr/config/items.db' })
local itemDB = TableDB({ fileName = 'usr/etc/items.db' })
function itemDB:get(key)
@ -13,6 +13,9 @@ function itemDB:get(key)
if key[2] ~= 0 then
item = TableDB.get(self, { key[1], 0, key[3] })
if item and item.maxDamage > 0 then
item = Util.shallowCopy(item)
item.damage = key[2]
item.displayName = string.format('%s (damage: %d)', item.displayName, item.damage)
return item
end
end

View File

@ -50,7 +50,12 @@ function Peripheral.addDevice(deviceList, side)
name = uniqueName
end
deviceList[name] = peripheral.wrap(side)
local s, m pcall(function() deviceList[name] = peripheral.wrap(side) end)
if not s and m then
printError('wrap failed')
printError(m)
end
if deviceList[name] then
Util.merge(deviceList[name], {
name = name,

View File

@ -4,13 +4,19 @@ function Point.copy(pt)
return { x = pt.x, y = pt.y, z = pt.z }
end
function Point.same(pta, ptb)
return pta.x == ptb.x and
pta.y == ptb.y and
pta.z == ptb.z
end
function Point.subtract(a, b)
a.x = a.x - b.x
a.y = a.y - b.y
a.z = a.z - b.z
end
-- real distance
-- Euclidian distance
function Point.pythagoreanDistance(a, b)
return math.sqrt(
math.pow(a.x - b.x, 2) +
@ -18,7 +24,7 @@ function Point.pythagoreanDistance(a, b)
math.pow(a.z - b.z, 2))
end
-- turtle distance
-- turtle distance (manhattan)
function Point.turtleDistance(a, b)
if a.y and b.y then
return math.abs(a.x - b.x) +
@ -40,6 +46,35 @@ function Point.calculateTurns(ih, oh)
return 1
end
function Point.calculateHeading(pta, ptb)
local heading
if (pta.heading % 2) == 0 and pta.z ~= ptb.z then
if ptb.z > pta.z then
heading = 1
else
heading = 3
end
elseif (pta.heading % 2) == 1 and pta.x ~= ptb.x then
if ptb.x > pta.x then
heading = 0
else
heading = 2
end
elseif pta.heading == 0 and pta.x > ptb.x then
heading = 2
elseif pta.heading == 2 and pta.x < ptb.x then
heading = 0
elseif pta.heading == 1 and pta.z > ptb.z then
heading = 3
elseif pta.heading == 3 and pta.z < ptb.z then
heading = 1
end
return heading or pta.heading
end
-- Calculate distance to location including turns
-- also returns the resulting heading
function Point.calculateMoves(pta, ptb, distance)
@ -88,6 +123,32 @@ function Point.closest(reference, pts)
return lpt
end
-- find the closest block
-- * favor same plane
-- * going backwards only if the dest is above or below
function Point.closest2(reference, pts)
local lpt, lm -- lowest
for _,pt in pairs(pts) do
local m = Point.turtleDistance(reference, pt)
local h = Point.calculateHeading(reference, pt)
local t = Point.calculateTurns(reference.heading, h)
if pt.y ~= reference.y then -- try and stay on same plane
m = m + .01
end
if t ~= 2 or pt.y == reference.y then
m = m + t
if t > 0 then
m = m + .01
end
end
if not lm or m < lm then
lpt = pt
lm = m
end
end
return lpt
end
function Point.adjacentPoints(pt)
local pts = { }

View File

@ -48,9 +48,6 @@ function RefinedProvider:getCachedItemDetails(item)
return
end
Util.merge(detail, meta)
if detail.maxDamage and detail.maxDamage > 0 and detail.damage > 0 then
detail.displayName = detail.displayName .. ' (damaged)'
end
detail.lname = detail.displayName:lower()
local t = { }

View File

@ -100,15 +100,15 @@ function Schematic:parse(a, h, containsName, spinner)
local i4 = h:readbyte(h)
local i = bit.blshift(i1, 24) + bit.blshift(i2, 16) + bit.blshift(i3, 8) + i4
if not self.length or not self.width then
self:discardBytes(h,i, spinner)
self.twopass = true
elseif name == "Blocks" then
if name == "Blocks" then
for i = 1, i do
local id = h:readbyte(h)
self:assignCoord(i, id)
if id > 0 then
table.insert(self.blocks, {
id = id,
index = i,
})
end
if (i % 1000) == 0 then
spinner:spin()
end
@ -269,15 +269,36 @@ function Schematic:loadpass(fh, spinner)
break
end
self:parse(a, fh, true, spinner)
if self.twopass and self.width and self.length then
break
end
spinner:spin()
end
fh:close()
print('Assigning coords ')
local index = 1
for _, b in ipairs(self.blocks) do
while index < b.index do
self.x = self.x + 1
if self.x >= self.width then
self.x = 0
self.z = self.z + 1
end
if self.z >= self.length then
self.z = 0
self.y = self.y + 1
end
if self.y >= self.height then
self.height = self.y + 1
end
index = index + 1
end
b.x = self.x
b.y = self.y
b.z = self.z
spinner:spin()
end
self:assignDamages(spinner)
self.damages = nil
@ -313,22 +334,9 @@ function Schematic:load(filename)
self:checkFileType(f)
print('Initial pass ')
print('Loading blocks ')
self:loadpass(f, spinner)
if self.twopass then
self.twopass = nil
self.blocks = { }
self.damages = { }
self.originalBlocks = { }
self.x, self.y, self.z = 0, 0, 0
self.height = 0
self.index = 1
print('Second pass ')
self:loadpass(f, spinner)
end
self.rowIndex = { }
for k,b in ipairs(self.blocks) do
local ri = self.rowIndex[b.y]
@ -342,42 +350,12 @@ function Schematic:load(filename)
self.cache = Util.readTable('usr/builder/' .. self.filename .. '.cache') or { }
end
function Schematic:assignCoord(i, id)
if id > 0 then
table.insert(self.blocks, {
id = id,
index = i,
x = self.x,
z = self.z,
y = self.y,
})
end
self.x = self.x + 1
if self.x >= self.width then
self.x = 0
self.z = self.z + 1
end
if self.z >= self.length then
self.z = 0
self.y = self.y + 1
end
if self.y >= self.height then
self.height = self.y + 1
end
end
function Schematic:assignDamages(spinner)
print('Assigning damages')
local i = 0
for _,b in pairs(self.blocks) do
b.dmg = self.damages[b.index] or 0
i = i + 1
if (i % 1000) == 0 then
spinner:spin()
end
spinner:spin()
end
end
@ -849,6 +827,7 @@ function Schematic:getComputedBlock(i)
-- has this level been computed ?
if not self.rowIndex[b.y].loaded then
-- compute each level up til this one (unless saved in cache)
for y = 0, b.y - 1 do
if not self.cache[y] then
self:determineBlockPlacement(y)
@ -858,7 +837,6 @@ function Schematic:getComputedBlock(i)
-- get the block now at the computed location
b = self.blocks[i]
end
return b
end

View File

@ -67,7 +67,7 @@ function Manager:init(args)
local mouseDragged = false
local pages = { }
Event.addHandler('term_resize', function(h, side)
Event.on('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 +81,7 @@ function Manager:init(args)
end
end)
Event.addHandler('mouse_scroll', function(h, direction, x, y)
Event.on('mouse_scroll', function(h, direction, x, y)
if self.target then
local event = self:pointToChild(self.target, x, y)
local directions = {
@ -97,7 +97,7 @@ function Manager:init(args)
end)
-- this should be moved to the device !
Event.addHandler('monitor_touch', function(h, side, x, y)
Event.on('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 +105,7 @@ function Manager:init(args)
end
end)
Event.addHandler('mouse_click', function(h, button, x, y)
Event.on('mouse_click', function(h, button, x, y)
mouseDragged = false
if button == 1 and shift and control then -- debug hack
@ -123,7 +123,7 @@ function Manager:init(args)
end
end)
Event.addHandler('mouse_up', function(h, button, x, y)
Event.on('mouse_up', function(h, button, x, y)
if self.currentPage and not mouseDragged then
if not self.currentPage.parent.device.side then
@ -132,7 +132,7 @@ function Manager:init(args)
end
end)
Event.addHandler('mouse_drag', function(h, button, x, y)
Event.on('mouse_drag', function(h, button, x, y)
mouseDragged = true
if self.target then
@ -146,7 +146,7 @@ function Manager:init(args)
end
end)
Event.addHandler('paste', function(h, text)
Event.on('paste', function(h, text)
if clipboard.isInternal() then
text = clipboard.getData()
end
@ -156,7 +156,7 @@ function Manager:init(args)
end
end)
Event.addHandler('char', function(h, ch)
Event.on('char', function(h, ch)
control = false
if self.currentPage then
self:inputEvent(self.currentPage.focused, { type = 'key', key = ch })
@ -164,7 +164,7 @@ function Manager:init(args)
end
end)
Event.addHandler('key_up', function(h, code)
Event.on('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 +172,7 @@ function Manager:init(args)
end
end)
Event.addHandler('key', function(h, code)
Event.on('key', function(h, code)
local ch = keys.getName(code)
if not ch then
return
@ -1282,6 +1282,8 @@ function UI.Device:runTransitions(transitions, canvas)
if Util.empty(transitions) then
break
end
os.sleep(0)
--[[
local timerId = os.startTimer(0)
while true do
local e = { os.pullEvent() }
@ -1290,10 +1292,11 @@ function UI.Device:runTransitions(transitions, canvas)
end
table.insert(queue, e)
end
--]]
end
for _, e in ipairs(queue) do
Event.processEvent(e)
end
-- for _, e in ipairs(queue) do
-- Event.processEvent(e)
-- end
end
function UI.Device:sync()

View File

@ -116,23 +116,20 @@ function page.grid:getDisplayValues(row)
return row
end
Event.addThread(function()
while true do
page.grid:update()
page.grid:draw()
page:sync()
os.sleep(1)
end
Event.onInterval(1, function()
page.grid:update()
page.grid:draw()
page:sync()
end)
Event.addHandler('device_attach', function(h, deviceName)
Event.on('device_attach', function(h, deviceName)
if deviceName == 'wireless_modem' then
page.notification:success('Modem connected')
page:sync()
end
end)
Event.addHandler('device_detach', function(h, deviceName)
Event.on('device_detach', function(h, deviceName)
if deviceName == 'wireless_modem' then
page.notification:error('Wireless modem not attached')
page:sync()

View File

@ -532,34 +532,30 @@ if not fs.exists(GROUPS_PATH) then
fs.makeDir(GROUPS_PATH)
end
Event.addHandler('network_attach', function()
Event.on('network_attach', function()
if mainPage.enabled then
mainPage:draw()
end
end)
Event.addHandler('network_detach', function()
Event.on('network_detach', function()
if mainPage.enabled then
mainPage:draw()
end
end)
function statusUpdate()
while true do
if mainPage.enabled then
local selected = mainPage.computers:getSelected()
if selected then
local computer = _G.network[selected.id]
mainPage.statusBar.values = { computer }
mainPage.statusBar:draw()
mainPage:sync()
end
Event.onInterval(1, function()
if mainPage.enabled then
local selected = mainPage.computers:getSelected()
if selected then
local computer = _G.network[selected.id]
mainPage.statusBar.values = { computer }
mainPage.statusBar:draw()
mainPage:sync()
end
os.sleep(1)
end
end
end)
UI:setPage(mainPage)
Event.pullEvents(statusUpdate)
UI:pullEvents()
UI.term:reset()

View File

@ -52,7 +52,7 @@ function page.grid:getDisplayValues(row)
if elapsed < 60 then
row.timestamp = string.format("%ds", math.floor(elapsed))
else
row.timestamp = string.format("%fm", math.floor(elapsed/6)/10)
row.timestamp = string.format("%sm", math.floor(elapsed/6)/10)
end
if row.isDead then
row.status = 'error'

View File

@ -2,7 +2,7 @@ require = requireInjector(getfenv(1))
local UI = require('ui')
local Socket = require('socket')
local Terminal = require('terminal')
local TableDB = require('tableDB')
local itemDB = require('itemDB')
multishell.setTitle(multishell.getCurrent(), 'Turtles')
UI.Button.defaults.focusIndicator = ' '
@ -31,12 +31,6 @@ local policies = {
{ label = 'turtleSafe' },
}
local itemInfoDB = TableDB({
fileName = 'items.db'
})
itemInfoDB:load()
local page = UI.Page {
--[[
policy = UI.Chooser {
@ -177,7 +171,7 @@ function page.coords:draw()
self:clear()
self:setCursorPos(1, 1)
local ind = 'GPS'
if t.coordSystem ~= 'GPS' then
if not t.point.gps then
ind = 'REL'
end
self:print(string.format('%s : %d,%d,%d\nFuel: %s\n',
@ -204,7 +198,7 @@ function page.tabs.inventory:draw()
v.selected = true
end
if v.id then
local item = itemInfoDB:get({ v.id, v.dmg })
local item = itemDB:get({ v.id, v.dmg })
if item then
v.id = item.displayName
else

View File

@ -41,6 +41,7 @@ local Builder = {
resourceSlots = 14,
facing = 'south',
confirmFacing = false,
wrenchSucks = false,
}
local pistonFacings
@ -95,6 +96,7 @@ function subDB:seedDB()
[ "minecraft:wall_banner:0" ] = "minecraft:banner:0",
[ "minecraft:standing_banner:0" ] = "minecraft:banner:0",
[ "minecraft:tripwire:0" ] = "minecraft:string:0",
[ "minecraft:pumpkin_stem:0" ] = "minecraft:pumpkin_seeds:0",
}
self.dirty = true
self:flush()
@ -266,7 +268,7 @@ function Builder:getAirResupplyList(blockIndex)
local fuel = subDB:getSubstitutedItem(Builder.fuelItem.id, Builder.fuelItem.dmg)
slots[15] = {
id = 'ironchest:BlockIronChest', -- 'minecraft:chest',
id = 'minecraft:chest', --'ironchest:BlockIronChest', --
dmg = 0,
qty = 0,
need = 1,
@ -821,6 +823,14 @@ function Builder:placePiston(b)
return
end
if self.wrenchSucks then
turtle.turnRight()
turtle.forward()
turtle.turnLeft()
turtle.forward()
turtle.turnLeft()
end
local success = self:wrenchBlock('forward', 'down', pistonFacings) --wrench piston to point downwards
rs.setOutput('front', true)
@ -830,6 +840,11 @@ function Builder:placePiston(b)
turtle.select(ps.index)
turtle.dig()
if not success and not self.wrenchSucks then
self.wrenchSucks = true
success = self:placePiston(b)
end
return success
end
@ -2029,12 +2044,9 @@ UI:setPages({
UI:setPage('start')
turtle.run(function()
local s, m = turtle.run(function()
turtle.setPolicy(turtle.policies.digAttack)
turtle.setPoint({ x = -1, z = -1, y = 0, heading = 0 })
turtle.getState().coordSystem = 'relative'
turtle.saveLocation('supplies')
Event.pullEvents()
UI:pullEvents()
end)
UI.term:reset()

View File

@ -5,16 +5,18 @@ local ChestProvider = require('chestProvider18')
local RefinedProvider = require('refinedProvider')
local itemDB = require('itemDB')
local Terminal = require('terminal')
local Peripheral = require('peripheral')
multishell.setTitle(multishell.getCurrent(), 'Resource Manager')
-- 3 wide monitor (any side of turtle)
-- Config location is /sys/config/chestManager
-- Config location is /sys/config/resourceManager
-- adjust directions in that file if needed
local config = {
trashDirection = 'up', -- trash /chest in relation to interface
turtleDirection = 'down', -- turtle in relation to interface
noCraftingStorage = 'false' -- no ME crafting (or ability to tell if powered - use with caution)
trashDirection = 'up', -- trash /chest in relation to chest
turtleDirection = 'down', -- turtle in relation to chest
}
Config.load('resourceManager', config)
@ -26,14 +28,34 @@ if not controller:isValid() then
end
local chestProvider = ChestProvider({ direction = 'west', wrapSide = 'back' })
local turtleChestProvider = ChestProvider({ direction = 'up', wrapSide = 'bottom' })
local RESOURCE_FILE = 'usr/etc/resources.db'
local RECIPES_FILE = 'usr/etc/recipes.db'
local jobListGrid
local craftingPaused = false
local recipes = Util.readTable('recipes') or { }
local recipes = Util.readTable(RECIPES_FILE) or { }
local resources = Util.readTable(RESOURCE_FILE) or { }
multishell.setTitle(multishell.getCurrent(), 'Resource Manager')
for _,r in pairs(resources) do
r.maxDamage = nil
r.displayName = nil
r.count = nil
r.lname = nil
r.has_recipe = nil
function getItem(items, inItem, ignoreDamage)
if not r.ignoreDamage then
r.ignoreDamage = nil
end
if not r.auto then
r.auto = nil
end
end
Util.writeTable(RESOURCE_FILE, resources)
local function getItem(items, inItem, ignoreDamage)
for _,item in pairs(items) do
if item.name == inItem.name then
if ignoreDamage then
@ -61,7 +83,7 @@ local function getItemDetails(items, item)
cItem = itemDB:get(itemDB:makeKey(item))
if cItem then
return { count = 0, maxCount = cItem.maxCount }
enditemDB:makeKey
end
return { count = 0, maxCount = 64 }
end
@ -69,7 +91,7 @@ local function uniqueKey(item)
return table.concat({ item.name, item.damage, item.nbtHash }, ':')
end
function getName(item)
local function getName(item)
local detail = itemDB:get(itemDB:makeKey(item))
if detail then
return detail.displayName
@ -77,60 +99,51 @@ function getName(item)
return item.name .. ':' .. item.damage
end
function mergeResources(t)
local resources = Util.readTable('resource.limits') or { }
local function mergeResources(t)
for _,v in pairs(resources) do
v.low = tonumber(v.low) -- backwards compatibility
local item = getItem(t, v)
if item then
item.low = v.low
item.limit = v.limit
item.auto = v.auto
item.ignoreDamage = v.ignoreDamage
item.rsControl = v.rsControl
item.rsDevice = v.rsDevice
item.rsSide = v.rsSide
Util.merge(item, v)
else
v.count = 0
table.insert(t, v)
item = Util.shallowCopy(v)
item.count = 0
table.insert(t, item)
end
end
for _,v in pairs(recipes) do
local item = getItem(t, v)
if item then
item.has_recipe = true
else
if not item then
item = Util.shallowCopy(v)
item.displayName = getName(item)
item.count = 0
item.has_recipe = true
table.insert(t, item)
end
item.has_recipe = true
end
for _,v in pairs(t) do
if not v.displayName then
v.displayName = getName(v)
end
v.lname = v.displayName:lower()
end
end
function filterItems(t, filter)
local r = {}
local function filterItems(t, filter)
if filter then
local r = {}
filter = filter:lower()
for k,v in pairs(t) do
if string.find(v.lname, filter) then
if string.find(v.lname, filter) then
table.insert(r, v)
end
end
else
return t
return r
end
return r
return t
end
function sumItems3(ingredients, items, summedItems, count)
local function sumItems3(ingredients, items, summedItems, count)
local canCraft = 0
for _,item in pairs(ingredients) do
@ -179,7 +192,7 @@ local function sumItems2(ingredients, items, summedItems, count)
return canCraft
end
function sumItems(items)
local function sumItems(items)
local t = {}
for _,item in pairs(items) do
@ -197,7 +210,7 @@ function sumItems(items)
return t
end
function isGridClear()
local function isGridClear()
for i = 1, 16 do
if turtle.getItemCount(i) ~= 0 then
return false
@ -219,22 +232,11 @@ local function clearGrid()
return true
end
function turtleCraft(recipe, originalItem, qty)
local function turtleCraft(recipe, originalItem, qty)
for k,v in pairs(recipe.ingredients) do
-- ugh
local dmg = v.damage
--FIX - LOOKUP IN ITEMS
if v.max_dmg and v.max_dmg > 0 then
local item = ME.getItemDetail({ id = v.id, nbt_hash = v.nbt_hash }, false)
if item then
dmg = item.dmg
end
end
chestProvider:provide({ id = v.name, dmg = dmg, nbt_hash = v.nbtHash }, v.count * qty, k)
chestProvider:provide({ id = v.name, dmg = v.damage, nbt_hash = v.nbtHash }, v.count * qty, k)
if turtle.getItemCount(k) ~= v.count * qty then
clearGrid()
originalItem.status = v.name .. ' (extract failed)'
@ -256,7 +258,7 @@ function turtleCraft(recipe, originalItem, qty)
return true
end
function addCraftingRequest(item, craftList, count)
local function addCraftingRequest(item, craftList, count)
local key = uniqueKey(item)
local request = craftList[key]
if not craftList[key] then
@ -267,9 +269,18 @@ function addCraftingRequest(item, craftList, count)
request.count = request.count + count
end
function craftRecipe(recipe, items, originalItem, count)
local function craftRecipe(recipe, items, originalItem, count)
local maxCount = 64
local maxCount = recipe.maxCount
if not maxCount then -- temporary
local cItem = itemDB:get(itemDB:makeKey(recipe))
if cItem then
maxCount = cItem.maxCount
else
maxCount = 1
end
end
local summedItems = sumItems(recipe.ingredients)
for key,ingredient in pairs(summedItems) do
@ -293,7 +304,7 @@ function craftRecipe(recipe, items, originalItem, count)
return true
end
function craftItem(recipe, items, originalItem, craftList, count)
local function craftItem(recipe, items, originalItem, craftList, count)
if craftingPaused or not device.workbench or not isGridClear() then
return
@ -305,12 +316,11 @@ function craftItem(recipe, items, originalItem, craftList, count)
if toCraft > 0 then
craftRecipe(recipe, items, originalItem, toCraft)
items = chestProvider:listItems()
end
count = count - toCraft
items = chestProvider:listItems()
local summedItems = { }
sumItems3(recipe.ingredients, items, summedItems, count)
@ -321,7 +331,7 @@ function craftItem(recipe, items, originalItem, craftList, count)
end
end
function craftItems(craftList, allItems)
local function craftItems(craftList, allItems)
for _,key in pairs(Util.keys(craftList)) do
local item = craftList[key]
@ -336,25 +346,29 @@ function craftItems(craftList, allItems)
for key,item in pairs(craftList) do
if controller and not recipes[key] then
if controller:isCrafting(item) then
item.status = '(crafting)'
if not recipes[key] then
if not controller then
item.status = '(no recipe)'
else
if controller:isCrafting(item) then
item.status = '(crafting)'
else
local count = item.count
while count >= 1 do -- try to request smaller quantities until successful
local s, m = pcall(function()
item.status = '(no recipe)'
if not controller:craft(item, count) then
item.status = '(missing ingredients)'
error('failed')
local count = item.count
while count >= 1 do -- try to request smaller quantities until successful
local s, m = pcall(function()
item.status = '(no recipe)'
if not controller:craft(item, count) then
item.status = '(missing ingredients)'
error('failed')
end
item.status = '(crafting)'
end)
if s then
break -- successfully requested crafting
end
item.status = '(crafting)'
end)
if s then
break -- successfully requested crafting
count = math.floor(count / 2)
end
count = math.floor(count / 2)
end
end
end
@ -363,11 +377,11 @@ end
local function jobMonitor(jobList)
local mon
local mon = Peripheral.getByType('monitor')
if device.monitor then
if mon then
mon = UI.Device({
deviceType = 'monitor',
device = mon,
textScale = .5,
})
else
@ -387,11 +401,10 @@ local function jobMonitor(jobList)
})
end
function getAutocraftItems()
local t = Util.readTable('resource.limits') or { }
local function getAutocraftItems()
local craftList = { }
for _,res in pairs(t) do
for _,res in pairs(resources) do
if res.auto then
res.count = 4 -- this could be higher to increase autocrafting speed
@ -426,19 +439,18 @@ local function getItemWithQty(items, res, ignoreDamage)
return item
end
function watchResources(items)
local function watchResources(items)
local craftList = { }
local t = Util.readTable('resource.limits') or { }
for k, res in pairs(t) do
for k, res in pairs(resources) do
local item = getItemWithQty(items, res, res.ignoreDamage)
if not item then
item = {
damage = res.damage,
nbtHash = res.nbtHash,
name = res.name,
displayName = res.displayName,
displayName = getName(res),
count = 0
}
end
@ -472,7 +484,7 @@ function watchResources(items)
return craftList
end
itemPage = UI.Page {
local itemPage = UI.Page {
backgroundColor = colors.lightGray,
titleBar = UI.TitleBar {
title = 'Limit Resource',
@ -481,10 +493,10 @@ itemPage = UI.Page {
backgroundColor = colors.green
},
displayName = UI.Window {
x = 5, y = 2, width = UI.term.width - 10, height = 3,
x = 2, y = 2, width = UI.term.width - 4, height = 3,
},
form = UI.Form {
x = 4, y = 4, height = 8, rex = -4,
x = 4, y = 5, height = 8, rex = -4,
[1] = UI.TextEntry {
width = 7,
backgroundColor = colors.gray,
@ -555,7 +567,7 @@ function itemPage.displayName:draw()
local item = self.parent.item
local str = string.format('Name: %s\nDamage: %d', item.displayName, item.damage)
if item.nbtHash then
str = str .. string.format('\nNBT: %s\n', item.nbtHash)
str = str .. string.format('\n%s', item.nbtHash)
end
self:setCursorPos(1, 1)
self:print(str)
@ -593,9 +605,8 @@ function itemPage:eventHandler(event)
elseif event.type == 'form_complete' then
local values = self.form.values
local t = Util.readTable('resource.limits') or { }
local keys = { 'name', 'displayName', 'auto', 'low', 'limit', 'damage',
'maxDamage', 'nbtHash', 'ignoreDamage',
local keys = { 'name', 'auto', 'low', 'limit', 'damage',
'nbtHash', 'ignoreDamage',
'rsControl', 'rsDevice', 'rsSide', }
local filtered = { }
@ -605,16 +616,26 @@ function itemPage:eventHandler(event)
filtered.low = tonumber(filtered.low)
filtered.limit = tonumber(filtered.limit)
filtered.ignoreDamage = filtered.ignoreDamage == true
filtered.auto = filtered.auto == true
filtered.rsControl = filtered.rsControl == true
--filtered.ignoreDamage = filtered.ignoreDamage == true
--filtered.auto = filtered.auto == true
--filtered.rsControl = filtered.rsControl == true
if filtered.ignoreDamage then
if filtered.auto ~= true then
filtered.auto = nil
end
if filtered.rsControl ~= true then
filtered.rsControl = nil
filtered.rsSide = nil
filtered.rsDevice = nil
end
if values.ignoreDamage == true then
filtered.damage = 0
end
t[uniqueKey(filtered)] = filtered
Util.writeTable('resource.limits', t)
resources[uniqueKey(filtered)] = filtered
Util.writeTable(RESOURCE_FILE, resources)
UI:setPreviousPage()
@ -624,11 +645,12 @@ function itemPage:eventHandler(event)
return true
end
listingPage = UI.Page {
local listingPage = UI.Page {
menuBar = UI.MenuBar {
buttons = {
{ text = 'Learn', event = 'learn' },
{ text = 'Forget', event = 'forget' },
{ text = 'Craft', event = 'craft' },
},
},
grid = UI.Grid {
@ -720,6 +742,9 @@ function listingPage:eventHandler(event)
self.statusBar.filter:focus()
elseif event.type == 'learn' then
UI:setPage('learn')
elseif event.type == 'craft' then
UI:setPage('craft')
elseif event.type == 'forget' then
@ -729,16 +754,12 @@ function listingPage:eventHandler(event)
if recipes[key] then
recipes[key] = nil
Util.writeTable('recipes', recipes)
Util.writeTable(RECIPES_FILE, recipes)
end
local resources = Util.readTable('resource.limits') or { }
for k,v in pairs(resources) do
if v.name == item.name and v.damage == item.damage then
resources[k] = nil
Util.writeTable('resource.limits', resources)
break
end
if resources[key] then
resources[key] = nil
Util.writeTable(RESOURCE_FILE, resources)
end
self.statusBar:timedStatus('Forgot: ' .. item.name, 3)
@ -779,7 +800,7 @@ function listingPage:applyFilter()
end
-- without duck antenna
local function getTurtleInventory()
local function getTurtleInventoryOld()
local inventory = { }
for i = 1,16 do
if turtle.getItemCount(i) > 0 then
@ -795,6 +816,20 @@ local function getTurtleInventory()
return inventory
end
local function getTurtleInventory()
local inventory = { }
for i = 1,16 do
local qty = turtle.getItemCount(i)
if qty > 0 then
turtleChestProvider:insert(i, qty)
local items = turtleChestProvider:listItems()
_, inventory[i] = next(items)
turtleChestProvider:extract(1, qty, i)
end
end
return inventory
end
local function filter(t, filter)
local keys = Util.keys(t)
for _,key in pairs(keys) do
@ -817,10 +852,10 @@ local function learnRecipe(page)
clearGrid()
filter(recipe, { 'name', 'damage', 'nbtHash', 'count' })
filter(recipe, { 'name', 'damage', 'nbtHash', 'count', 'maxCount' })
for _,ingredient in pairs(ingredients) do
filter(ingredient, { 'name', 'damage', 'nbtHash', 'count' })
filter(ingredient, { 'name', 'damage', 'nbtHash', 'count', 'maxCount' })
--if ingredient.max_dmg > 0 then -- let's try this...
-- ingredient.dmg = 0
--end
@ -829,7 +864,7 @@ local function learnRecipe(page)
recipes[key] = recipe
Util.writeTable('recipes', recipes)
Util.writeTable(RECIPES_FILE, recipes)
local displayName = getName(recipe)
@ -849,13 +884,10 @@ local function learnRecipe(page)
end
end
craftPage = UI.Dialog {
local learnPage = UI.Dialog {
height = 7, width = UI.term.width - 6,
backgroundColor = colors.lightGray,
titleBar = UI.TitleBar {
title = 'Learn Recipe',
previousPage = true,
},
title = 'Learn Recipe',
idField = UI.Text {
x = 5,
y = 3,
@ -875,6 +907,61 @@ craftPage = UI.Dialog {
}
}
function learnPage:enable()
craftingPaused = true
self:focusFirst()
UI.Dialog.enable(self)
end
function learnPage:disable()
craftingPaused = false
UI.Dialog.disable(self)
end
function learnPage:eventHandler(event)
if event.type == 'cancel' then
UI:setPreviousPage()
elseif event.type == 'accept' then
if learnRecipe(self) then
UI:setPreviousPage()
end
else
return UI.Dialog.eventHandler(self, event)
end
return true
end
local craftPage = UI.Dialog {
height = 6, width = UI.term.width - 10,
backgroundColor = colors.lightGray,
title = 'Enter amount to craft',
idField = UI.TextEntry {
x = 15,
y = 3,
width = 10,
limit = 6,
value = '1',
backgroundColor = colors.black,
backgroundFocusColor = colors.black,
},
accept = UI.Button {
rx = -7, ry = -1,
backgroundColor = colors.green,
text = '+', event = 'accept',
},
cancel = UI.Button {
rx = -3, ry = -1,
backgroundColor = colors.red,
backgroundFocusColor = colors.red,
text = '\215', event = 'cancel'
},
}
function craftPage:draw()
UI.Dialog.draw(self)
self:write(6, 3, 'Quantity')
end
function craftPage:enable()
craftingPaused = true
self:focusFirst()
@ -890,9 +977,7 @@ function craftPage:eventHandler(event)
if event.type == 'cancel' then
UI:setPreviousPage()
elseif event.type == 'accept' then
if learnRecipe(self) then
UI:setPreviousPage()
end
else
return UI.Dialog.eventHandler(self, event)
end
@ -902,6 +987,7 @@ end
UI:setPages({
listing = listingPage,
item = itemPage,
learn = learnPage,
craft = craftPage,
})
@ -913,15 +999,12 @@ jobMonitor()
jobListGrid:draw()
jobListGrid:sync()
function craftingThread()
local function craftingThread()
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')
@ -942,8 +1025,6 @@ function craftingThread()
end
end
end
--craftingThread()
UI:pullEvents(craftingThread)
UI.term:reset()
UI:pullEvents(craftingThread)
jobListGrid.parent:reset()

View File

@ -61,40 +61,37 @@ function getClient(id)
return ids[id]
end
local function logWriter()
while true do
os.pullEvent('logMessage')
local t = { }
while #messages > 0 do
local msg = messages[1]
table.remove(messages, 1)
local client = getClient(msg.id)
client.scrollingText:appendLine(string.format('%d %s', math.floor(os.clock()), msg.text))
t[msg.id] = client
end
for _,client in pairs(t) do
client.scrollingText:draw()
end
terminal:sync()
Event.on('logMessage', function()
local t = { }
while #messages > 0 do
local msg = messages[1]
table.remove(messages, 1)
local client = getClient(msg.id)
client.scrollingText:appendLine(string.format('%d %s', math.floor(os.clock()), msg.text))
t[msg.id] = client
end
end
for _,client in pairs(t) do
client.scrollingText:draw()
end
terminal:sync()
end)
Message.addHandler('log', function(h, id, msg)
table.insert(messages, { id = id, text = msg.contents })
os.queueEvent('logMessage')
end)
Event.addHandler('monitor_touch', function()
Event.on('monitor_touch', function()
terminal:reset()
ids = { }
end)
Event.addHandler('mouse_click', function()
Event.on('mouse_click', function()
terminal:reset()
ids = { }
end)
Event.addHandler('char', function()
Event.on('char', function()
Event.exitPullEvents()
end)

View File

@ -2,7 +2,7 @@ require = requireInjector(getfenv(1))
local Socket = require('socket')
local Terminal = require('terminal')
local Logger = require('logger')
local process = require('process')
local Event = require('event')
Logger.setScreenLogging()
@ -31,7 +31,12 @@ local function wrapTerm(socket)
socket.term[k] = function(...)
if not socket.queue then
socket.queue = { }
os.queueEvent('mirror_flush')
Event.onTimeout(0, function()
if socket.queue then
socket:write(socket.queue)
socket.queue = nil
end
end)
end
table.insert(socket.queue, {
f = k,
@ -61,17 +66,13 @@ while true do
os.queueEvent('term_resize')
while true do
local e = process:pullEvent('mirror_flush')
local e = Event.pullEvent()
if e == 'terminate' then
break
end
if not socket.connected then
break
end
if socket.queue then
socket:write(socket.queue)
socket.queue = nil
end
end
for k,v in pairs(socket.oldTerm) do

View File

@ -1,7 +1,7 @@
require = requireInjector(getfenv(1))
local Event = require('event')
local Socket = require('socket')
local Logger = require('logger')
local process = require('process')
Logger.setScreenLogging()
@ -20,7 +20,7 @@ while true do
print('mirror: connection from ' .. socket.dhost)
local updateThread = process:newThread('updateThread', function()
Event.addRoutine(function()
while true do
local data = socket:read()
if not data then
@ -33,18 +33,15 @@ while true do
end)
-- ensure socket is connected
process:newThread('pinger', function()
while true do
os.sleep(3)
if not socket:ping() then
break
end
Event.onInterval(3, function(h)
if not socket:ping() then
Event.off(h)
end
end)
while true do
process:pullEvent('modem_message')
if updateThread:isDead() then
Event.pullEvent()
if not socket.connected then
break
end
end

View File

@ -243,6 +243,159 @@ turtle.run(function()
end)
]]
local levelScript = [[
require = requireInjector(getfenv(1))
local Point = require('point')
local checkedNodes = { }
local nodes = { }
local box = { }
local function inBox(pt, box)
return pt.x >= box.x and
pt.y >= box.y and
pt.z >= box.z and
pt.x <= box.ex and
pt.y <= box.ey and
pt.z <= box.ez
end
local function toKey(pt)
return table.concat({ pt.x, pt.y, pt.z }, ':')
end
local function addNode(node)
for i = 0, 5 do
local hi = turtle.getHeadingInfo(i)
local testNode = { x = node.x + hi.xd, y = node.y + hi.yd, z = node.z + hi.zd }
if inBox(testNode, box) then
local key = toKey(testNode)
if not checkedNodes[key] then
nodes[key] = testNode
end
end
end
end
local function dig(action)
local directions = {
top = 'up',
bottom = 'down',
}
-- convert to up, down, north, south, east, west
local direction = directions[action.side] or
turtle.getHeadingInfo(turtle.point.heading).direction
local hi = turtle.getHeadingInfo(direction)
local node = { x = turtle.point.x + hi.xd, y = turtle.point.y + hi.yd, z = turtle.point.z + hi.zd }
if inBox(node, box) then
local key = toKey(node)
checkedNodes[key] = true
nodes[key] = nil
if action.dig() then
addNode(node)
repeat until not action.dig() -- sand, etc
return true
end
end
end
local function move(action)
if action == 'turn' then
dig(turtle.getAction('forward'))
elseif action == 'up' then
dig(turtle.getAction('up'))
elseif action == 'down' then
dig(turtle.getAction('down'))
elseif action == 'back' then
dig(turtle.getAction('up'))
dig(turtle.getAction('down'))
end
end
local function getAdjacentPoint(pt)
local t = { }
table.insert(t, pt)
for i = 0, 5 do
local hi = turtle.getHeadingInfo(i)
local heading
if i < 4 then
heading = (hi.heading + 2) % 4
end
table.insert(t, { x = pt.x + hi.xd, z = pt.z + hi.zd, y = pt.y + hi.yd, heading = heading })
end
return Point.closest2(turtle.getPoint(), t)
end
local function level()
box.x = math.min(data.startPt.x, data.endPt.x)
box.y = math.min(data.startPt.y, data.endPt.y)
box.z = math.min(data.startPt.z, data.endPt.z)
box.ex = math.max(data.startPt.x, data.endPt.x)
box.ey = math.max(data.startPt.y, data.endPt.y)
box.ez = math.max(data.startPt.z, data.endPt.z)
turtle.pathfind(data.firstPt)
turtle.setPolicy("attack", { dig = dig }, "assuredMove")
turtle.setMoveCallback(move)
repeat
local key = toKey(turtle.point)
checkedNodes[key] = true
nodes[key] = nil
dig(turtle.getAction('down'))
dig(turtle.getAction('up'))
dig(turtle.getAction('forward'))
print(string.format('%d nodes remaining', Util.size(nodes)))
if Util.size(nodes) == 0 then
break
end
local node = Point.closest2(turtle.point, nodes)
node = getAdjacentPoint(node)
if not turtle.gotoPoint(node) then
break
end
until turtle.abort
turtle.resetState()
end
local s, m = turtle.run(function()
turtle.status = 'Leveling'
if turtle.enableGPS() then
local pt = Util.shallowCopy(turtle.point)
local s, m = pcall(level)
turtle.pathfind(pt)
if not s and m then
error(m)
end
end
end)
if not s then
error(m)
end
]]
local data = Util.readTable('/usr/config/shapes') or { }
local page = UI.Page {
@ -251,6 +404,7 @@ local page = UI.Page {
startCoord = UI.Button { x = 2, y = 6, text = 'Start ', event = 'startCoord' },
endCoord = UI.Button { x = 2, y = 8, text = 'End ', event = 'endCoord' },
supplies = UI.Button { x = 2, y = 10, text = 'Supplies', event = 'supplies' },
first = UI.Button { x = 2, y = 11, text = 'First', event = 'firstCoord' },
cancel = UI.Button { rx = 2, ry = -2, text = 'Abort', event = 'cancel' },
begin = UI.Button { rx = -7, ry = -2, text = 'Begin', event = 'begin' },
accelerators = { q = 'quit' },
@ -286,6 +440,7 @@ end
function page:runFunction(id, script)
Util.writeFile('script.tmp', script)
self.notification:info('Connecting')
local fn, msg = loadstring(script, 'script')
if not fn then
@ -299,7 +454,6 @@ function page:runFunction(id, script)
self.notification:error('Unable to connect')
return
end
socket:write({ type = 'script', args = script })
socket:close()
@ -321,6 +475,13 @@ function page:eventHandler(event)
Util.writeTable('/usr/config/shapes', data)
end
self:draw()
elseif event.type == 'firstCoord' then
data.firstPt = self:getPoint()
if data.firstPt then
self.statusBar:setStatus('first point set')
Util.writeTable('/usr/config/shapes', data)
end
self:draw()
elseif event.type == 'supplies' then
data.suppliesPt = self:getPoint()
if data.suppliesPt then
@ -329,7 +490,7 @@ function page:eventHandler(event)
end
elseif event.type == 'begin' then
if data.startPt and data.endPt then
local s = 'local data = ' .. textutils.serialize(data) .. script
local s = 'local data = ' .. textutils.serialize(data) .. levelScript
self:runFunction(turtleId, s)
else
self.notification:error('Corners not set')

View File

@ -863,43 +863,37 @@ jobMonitor()
jobListGrid:draw()
jobListGrid:sync()
function craftingThread()
Event.onInterval(5, function()
while true do
os.sleep(5)
if not craftingPaused then
if not craftingPaused then
local items = ME.getAvailableItems()
if Util.size(items) == 0 then
jobListGrid.parent:clear()
jobListGrid.parent:centeredWrite(math.ceil(jobListGrid.parent.height/2), 'No items in system')
jobListGrid:sync()
elseif config.noCraftingStorage ~= 'true' and #ME.getCraftingCPUs() <= 0 then -- only way to determine if AE is online
jobListGrid.parent:clear()
jobListGrid.parent:centeredWrite(math.ceil(jobListGrid.parent.height/2), 'Power failure')
jobListGrid:sync()
local items = ME.getAvailableItems()
if Util.size(items) == 0 then
jobListGrid.parent:clear()
jobListGrid.parent:centeredWrite(math.ceil(jobListGrid.parent.height/2), 'No items in system')
jobListGrid:sync()
elseif config.noCraftingStorage ~= 'true' and #ME.getCraftingCPUs() <= 0 then -- only way to determine if AE is online
jobListGrid.parent:clear()
jobListGrid.parent:centeredWrite(math.ceil(jobListGrid.parent.height/2), 'Power failure')
jobListGrid:sync()
else
local itemList = watchResources(items)
jobListGrid:setValues(itemList)
jobListGrid:draw()
jobListGrid:sync()
craftItems(itemList)
jobListGrid:update()
jobListGrid:draw()
jobListGrid:sync()
else
local itemList = watchResources(items)
jobListGrid:setValues(itemList)
jobListGrid:draw()
jobListGrid:sync()
craftItems(itemList)
jobListGrid:update()
jobListGrid:draw()
jobListGrid:sync()
itemList = getAutocraftItems(items) -- autocrafted items don't show on job monitor
craftItems(itemList)
end
itemList = getAutocraftItems(items) -- autocrafted items don't show on job monitor
craftItems(itemList)
end
end
end
end)
Event.pullEvents(craftingThread)
UI.term:reset()
UI:pullEvents()
jobListGrid.parent:reset()

View File

@ -429,7 +429,6 @@ end
turtle.run(function()
turtle.setPoint({ x = -1, z = -2, y = -1, heading = 1 })
turtle.getState().coordSystem = 'relative'
turtle.saveLocation('supplies')

View File

@ -1,5 +1,5 @@
require = requireInjector(getfenv(1))
local process = require('process')
local Event = require('event')
local Socket = require('socket')
local Terminal = require('terminal')
@ -36,7 +36,7 @@ socket:write({
isColor = ct.isColor(),
})
process:newThread('telnet_read', function()
Event.addRoutine(function()
while true do
local data = socket:read()
if not data then
@ -57,7 +57,7 @@ local filter = Util.transpose({
})
while true do
local e = { process:pullEvent() }
local e = Event.pullEvent()
local event = e[1]
if not socket.connected then

View File

@ -1,5 +1,5 @@
require = requireInjector(getfenv(1))
local process = require('process')
local Event = require('event')
local Socket = require('socket')
local Terminal = require('terminal')
@ -39,7 +39,7 @@ if not ct.isColor() then
Terminal.toGrayscale(ct)
end
process:newThread('vnc_read', function()
Event.addRoutine(function()
while true do
local data = socket:read()
if not data then
@ -60,7 +60,7 @@ local filter = Util.transpose({
})
while true do
local e = { process:pullEvent() }
local e = Event.pullEvent()
local event = e[1]
if not socket.connected then

83
sys/etc/scripts/level Normal file
View File

@ -0,0 +1,83 @@
require = requireInjector(getfenv(1))
local Point = require('point')
local checkedNodes = { }
local nodes = { }
local box = { x = 65, ex = 69, y = 65, ey = 70, z = -23, ez = -19 }
local function inBox(pt, box)
return pt.x >= box.x and
pt.y >= box.y and
pt.z >= box.z and
pt.x <= box.ex and
pt.y <= box.ey and
pt.z <= box.ez
end
local function toKey(pt)
return table.concat({ pt.x, pt.y, pt.z }, ':')
end
local function addNode(node)
for i = 0, 5 do
local hi = turtle.getHeadingInfo(i)
local testNode = { x = node.x + hi.xd, y = node.y + hi.yd, z = node.z + hi.zd }
if inBox(testNode, box) then
local key = toKey(testNode)
if not checkedNodes[key] then
nodes[key] = testNode
end
end
end
end
local function dig(facing)
local direction = facing
if direction == 'forward' then
direction = turtle.getHeadingInfo(turtle.point.heading).direction
end
local hi = turtle.getHeadingInfo(direction)
local node = { x = turtle.point.x + hi.xd, y = turtle.point.y + hi.yd, z = turtle.point.z + hi.zd }
if inBox(node, box) then
if turtle.getAction(facing).dig() then
addNode(node)
end
end
end
local function level()
repeat
local node = { x = turtle.point.x, y = turtle.point.y, z = turtle.point.z }
local key = toKey(node)
checkedNodes[key] = true
nodes[key] = nil
dig('down')
dig('up')
dig('forward')
print(string.format('%d nodes remaining', Util.size(nodes)))
if Util.size(nodes) == 0 then
break
end
local node = Point.closest(turtle.point, nodes)
if not turtle.gotoPoint(node) then
break
end
until turtle.abort
end
local pt = Util.shallowCopy(turtle.point)
turtle.setPolicy(turtle.policies.none)
if turtle.pathfind({ x = 65, y = 70, z = -23 }) then
--turtle.reset()
turtle.setPolicy(turtle.policies.digOnly)
level()
end
turtle.pathfind(pt)
--local s, m = turtle.run(level)

View File

@ -7,7 +7,6 @@ local function summon(id)
turtle.status = 'GPSing'
turtle.setPoint({ x = 0, y = 0, z = 0, heading = 0 })
turtle.getState().coordSystem = 'relative'
local pts = {
[ 1 ] = { x = 0, z = 0, y = 0 },

View File

@ -6,15 +6,14 @@ require = requireInjector(getfenv(1))
local GPS = require('gps')
function turtle.enableGPS(timeout)
if turtle.getState().coordSystem == 'GPS' then
if turtle.point.gps == 'GPS' then
return turtle.point
end
local pt = GPS.getPointAndHeading(timeout)
if pt then
turtle.setPoint(pt)
turtle.getState().coordSystem = 'GPS'
return true
turtle.setPoint(pt, true)
return turtle.point
end
end

View File

@ -7,30 +7,40 @@ local function noop() end
turtle.point = { x = 0, y = 0, z = 0, heading = 0 }
turtle.status = 'idle'
turtle.abort = false
local state = { }
function turtle.getPoint()
return turtle.point
function turtle.getPoint() return turtle.point end
function turtle.getState() return state end
local function _defaultMove(action)
while not action.move() do
if not state.digPolicy(action) and not state.attackPolicy(action) then
return false
end
end
return true
end
local state = {
moveAttack = noop,
moveDig = noop,
moveCallback = noop,
locations = {},
coordSystem = 'relative', -- type of coordinate system being used
}
function turtle.getState()
return state
end
function turtle.setPoint(pt)
function turtle.setPoint(pt, isGPS)
turtle.point.x = pt.x
turtle.point.y = pt.y
turtle.point.z = pt.z
if pt.heading then
turtle.point.heading = pt.heading
end
turtle.point.gps = isGPS
return true
end
function turtle.resetState()
--turtle.abort = false -- should be part of state
--turtle.status = 'idle' -- should be part of state
state.attackPolicy = noop
state.digPolicy = noop
state.movePolicy = _defaultMove
state.moveCallback = noop
state.locations = { }
return true
end
@ -39,27 +49,16 @@ function turtle.reset()
turtle.point.y = 0
turtle.point.z = 0
turtle.point.heading = 0
turtle.point.gps = false
turtle.abort = false -- should be part of state
--turtle.status = 'idle' -- should be part of state
state.moveAttack = noop
state.moveDig = noop
state.moveCallback = noop
state.locations = {}
state.coordSystem = 'relative'
turtle.resetState()
return true
end
function turtle.resetState()
--turtle.abort = false -- should be part of state
--turtle.status = 'idle' -- should be part of state
state.moveAttack = noop
state.moveDig = noop
state.moveCallback = noop
state.locations = {}
return true
end
turtle.reset()
local actions = {
up = {
@ -116,12 +115,12 @@ end
-- [[ Heading data ]] --
local headings = {
[ 0 ] = { xd = 1, zd = 0, yd = 0, heading = 0, direction = 'east' },
[ 0 ] = { xd = 1, zd = 0, yd = 0, heading = 0, direction = 'east' },
[ 1 ] = { xd = 0, zd = 1, yd = 0, heading = 1, direction = 'south' },
[ 2 ] = { xd = -1, zd = 0, yd = 0, heading = 2, direction = 'west' },
[ 2 ] = { xd = -1, zd = 0, yd = 0, heading = 2, direction = 'west' },
[ 3 ] = { xd = 0, zd = -1, yd = 0, heading = 3, direction = 'north' },
[ 4 ] = { xd = 0, zd = 0, yd = 1, heading = 4, direction = 'up' },
[ 5 ] = { xd = 0, zd = 0, yd = -1, heading = 5, direction = 'down' }
[ 4 ] = { xd = 0, zd = 0, yd = 1, heading = 4, direction = 'up' },
[ 5 ] = { xd = 0, zd = 0, yd = -1, heading = 5, direction = 'down' }
}
local namedHeadings = {
@ -133,9 +132,7 @@ local namedHeadings = {
down = headings[5]
}
function turtle.getHeadings()
return headings
end
function turtle.getHeadings() return headings end
function turtle.getHeadingInfo(heading)
if heading and type(heading) == 'string' then
@ -181,8 +178,8 @@ local function _place(action, indexOrId)
if result[1] then
return true
end
if not state.moveDig(action) then
state.moveAttack(action)
if not state.digPolicy(action) then
state.attackPolicy(action)
end
return unpack(result)
end)
@ -267,48 +264,66 @@ turtle.digPolicies = {
end
}
turtle.policies = {
none = { dig = turtle.digPolicies.none, attack = turtle.attackPolicies.none },
digOnly = { dig = turtle.digPolicies.dig, attack = turtle.attackPolicies.none },
attackOnly = { dig = turtle.digPolicies.none, attack = turtle.attackPolicies.attack },
digAttack = { dig = turtle.digPolicies.dig, attack = turtle.attackPolicies.attack },
turtleSafe = { dig = turtle.digPolicies.turtleSafe, attack = turtle.attackPolicies.attack },
turtle.movePolicies = {
none = noop,
default = _defaultMove,
assured = function(action)
if not _defaultMove(action) then
if action.side == 'back' then
return false
end
local oldStatus = turtle.status
print('stuck')
turtle.status = 'stuck'
repeat
os.sleep(1)
until _defaultMove(action)
turtle.status = oldStatus
end
return true
end,
}
function turtle.setPolicy(policy)
if type(policy) == 'string' then
policy = turtle.policies[policy]
turtle.policies = {
none = { dig = turtle.digPolicies.none, attack = turtle.attackPolicies.none },
digOnly = { dig = turtle.digPolicies.dig, attack = turtle.attackPolicies.none },
attackOnly = { dig = turtle.digPolicies.none, attack = turtle.attackPolicies.attack },
digAttack = { dig = turtle.digPolicies.dig, attack = turtle.attackPolicies.attack },
turtleSafe = { dig = turtle.digPolicies.turtleSafe, attack = turtle.attackPolicies.attack },
attack = { attack = turtle.attackPolicies.attack },
defaultMove = { move = turtle.movePolicies.default },
assuredMove = { move = turtle.movePolicies.assured },
}
function turtle.setPolicy(...)
local args = { ... }
for _, policy in pairs(args) do
if type(policy) == 'string' then
policy = turtle.policies[policy]
end
if not policy then
error('Invalid policy')
-- return false, 'Invalid policy'
end
if policy.dig then
state.digPolicy = policy.dig
end
if policy.attack then
state.attackPolicy = policy.attack
end
if policy.move then
state.movePolicy = policy.move
end
end
if not policy then
return false, 'Invalid policy'
end
state.moveDig = policy.dig
state.moveAttack = policy.attack
return true
end
function turtle.setDigPolicy(policy)
state.moveDig = policy
end
function turtle.setAttackPolicy(policy)
state.moveAttack = policy
end
function turtle.setMoveCallback(cb)
state.moveCallback = cb
end
function turtle.clearMoveCallback()
state.moveCallback = noop
end
local function infoMoveCallback()
local pt = turtle.point
print(string.format('x:%d y:%d z:%d heading:%d', pt.x, pt.y, pt.z, pt.heading))
end
-- TESTING
--turtle.setMoveCallback(infoMoveCallback)
function turtle.setDigPolicy(policy) state.digPolicy = policy end
function turtle.setAttackPolicy(policy) state.attackPolicy = policy end
function turtle.setMoveCallback(cb) state.moveCallback = cb end
function turtle.clearMoveCallback() state.moveCallback = noop end
-- [[ Locations ]] --
function turtle.getLocation(name)
@ -364,6 +379,7 @@ function turtle.turnAround()
return turtle.point
end
-- combine with setHeading
function turtle.setNamedHeading(headingName)
local headingInfo = namedHeadings[headingName]
if headingInfo then
@ -432,17 +448,8 @@ function turtle.headTowards(pt)
end
-- [[ move ]] --
local function _move(action)
while not action.move() do
if not state.moveDig(action) and not state.moveAttack(action) then
return false
end
end
return true
end
function turtle.up()
if _move(actions.up) then
if state.movePolicy(actions.up) then
turtle.point.y = turtle.point.y + 1
state.moveCallback('up', turtle.point)
return true, turtle.point
@ -450,7 +457,7 @@ function turtle.up()
end
function turtle.down()
if _move(actions.down) then
if state.movePolicy(actions.down) then
turtle.point.y = turtle.point.y - 1
state.moveCallback('down', turtle.point)
return true, turtle.point
@ -458,7 +465,7 @@ function turtle.down()
end
function turtle.forward()
if _move(actions.forward) then
if state.movePolicy(actions.forward) then
turtle.point.x = turtle.point.x + headings[turtle.point.heading].xd
turtle.point.z = turtle.point.z + headings[turtle.point.heading].zd
state.moveCallback('forward', turtle.point)
@ -467,7 +474,7 @@ function turtle.forward()
end
function turtle.back()
if _move(actions.back) then
if state.movePolicy(actions.back) then
turtle.point.x = turtle.point.x - headings[turtle.point.heading].xd
turtle.point.z = turtle.point.z - headings[turtle.point.heading].zd
state.moveCallback('back', turtle.point)

View File

@ -129,7 +129,6 @@ local function sendInfo()
info.status = turtle.status
info.point = turtle.point
info.inventory = turtle.getInventory()
info.coordSystem = turtle.getState().coordSystem
info.slotIndex = turtle.getSelectedSlot()
end
device.wireless_modem.transmit(999, os.getComputerID(), info)

View File

@ -75,9 +75,9 @@ process:newThread('vnc_server', function()
local termInfo = socket:read(5)
if termInfo then
-- no new process - only 1 connection allowed
-- due to term size issues
vncHost(socket, termInfo)
-- no new process - only 1 connection allowed
-- due to term size issues
vncHost(socket, termInfo)
else
socket:close()
end

View File

@ -12,7 +12,7 @@ if not term.isColor() then
detachColor = colors.lightGray
end
Event.addHandler('peripheral', function(event, side)
Event.on('peripheral', function(event, side)
if side then
local dev = Peripheral.addDevice(device, side)
if dev then
@ -23,7 +23,7 @@ Event.addHandler('peripheral', function(event, side)
end
end)
Event.addHandler('peripheral_detach', function(event, side)
Event.on('peripheral_detach', function(event, side)
if side then
local dev = Util.find(device, 'side', side)
if dev then