spaces->tab, equipper improvements, supertreefarm rewrite, follow improvements, sensor cleanup, milo multiple items allowed in recipes, remote canvas access

This commit is contained in:
kepler155c@gmail.com
2019-06-18 15:23:20 -04:00
parent 3b9b509429
commit 045b32884f
162 changed files with 20448 additions and 20286 deletions

View File

@@ -15,18 +15,18 @@ local REGISTRY_DIR = 'usr/.registry'
-- FIX SOMEDAY
local function registerApp(app, key)
app.key = SHA1.sha1(key)
Util.writeTable(fs.combine(REGISTRY_DIR, app.key), app)
os.queueEvent('os_register_app')
app.key = SHA1.sha1(key)
Util.writeTable(fs.combine(REGISTRY_DIR, app.key), app)
os.queueEvent('os_register_app')
end
local function unregisterApp(key)
local filename = fs.combine(REGISTRY_DIR, SHA1.sha1(key))
if fs.exists(filename) then
fs.delete(filename)
os.queueEvent('os_register_app')
end
local filename = fs.combine(REGISTRY_DIR, SHA1.sha1(key))
if fs.exists(filename) then
fs.delete(filename)
os.queueEvent('os_register_app')
end
end
@@ -40,366 +40,366 @@ local APP_DIR = 'usr/apps'
local sources = {
{ text = "STD Default",
event = 'source',
url = "http://pastebin.com/raw/zVws7eLq" }, --stock
{ text = "STD Default",
event = 'source',
url = "http://pastebin.com/raw/zVws7eLq" }, --stock
--[[
{ text = "Discover",
event = 'source',
generateName = true,
url = "http://pastebin.com/raw/9bXfCz6M" }, --owned by dannysmc95
{ text = "Discover",
event = 'source',
generateName = true,
url = "http://pastebin.com/raw/9bXfCz6M" }, --owned by dannysmc95
{ text = "Opus",
event = 'source',
url = "http://pastebin.com/raw/ajQ91Rmn" },
{ text = "Opus",
event = 'source',
url = "http://pastebin.com/raw/ajQ91Rmn" },
]]
}
shell.setDir(APP_DIR)
local function downloadApp(app)
local h
local h
if type(app.url) == "table" then
h = contextualGet(app.url[1])
else
h = http.get(app.url)
end
if type(app.url) == "table" then
h = contextualGet(app.url[1])
else
h = http.get(app.url)
end
if h then
local contents = h.readAll()
h:close()
return contents
end
if h then
local contents = h.readAll()
h:close()
return contents
end
end
local function runApp(app, checkExists, ...)
local path, fn
local args = { ... }
local path, fn
local args = { ... }
if checkExists and fs.exists(fs.combine(APP_DIR, app.name)) then
path = fs.combine(APP_DIR, app.name)
else
local program = downloadApp(app)
if checkExists and fs.exists(fs.combine(APP_DIR, app.name)) then
path = fs.combine(APP_DIR, app.name)
else
local program = downloadApp(app)
fn = function()
fn = function()
if not program then
error('Failed to download')
end
if not program then
error('Failed to download')
end
local fn = loadstring(program, app.name)
local fn = loadstring(program, app.name)
if not fn then
error('Failed to download')
end
if not fn then
error('Failed to download')
end
setfenv(fn, sandboxEnv)
fn(unpack(args))
end
end
setfenv(fn, sandboxEnv)
fn(unpack(args))
end
end
multishell.openTab({
title = app.name,
env = sandboxEnv,
path = path,
fn = fn,
focused = true,
})
multishell.openTab({
title = app.name,
env = sandboxEnv,
path = path,
fn = fn,
focused = true,
})
return true, 'Running program'
return true, 'Running program'
end
local installApp = function(app)
local program = downloadApp(app)
if not program then
return false, "Failed to download"
end
local program = downloadApp(app)
if not program then
return false, "Failed to download"
end
local fullPath = fs.combine(APP_DIR, app.name)
Util.writeFile(fullPath, program)
return true, 'Installed as ' .. fullPath
local fullPath = fs.combine(APP_DIR, app.name)
Util.writeFile(fullPath, program)
return true, 'Installed as ' .. fullPath
end
local viewApp = function(app)
local program = downloadApp(app)
if not program then
return false, "Failed to download"
end
local program = downloadApp(app)
if not program then
return false, "Failed to download"
end
Util.writeFile('/.source', program)
shell.openForegroundTab('edit /.source')
fs.delete('/.source')
return true
Util.writeFile('/.source', program)
shell.openForegroundTab('edit /.source')
fs.delete('/.source')
return true
end
local getSourceListing = function(source)
local contents = http.get(source.url)
if contents then
local contents = http.get(source.url)
if contents then
local fn = loadstring(contents.readAll(), source.text)
contents.close()
local fn = loadstring(contents.readAll(), source.text)
contents.close()
local env = { std = { } }
setmetatable(env, { __index = _G })
setfenv(fn, env)
fn()
local env = { std = { } }
setmetatable(env, { __index = _G })
setfenv(fn, env)
fn()
if env.contextualGet then
contextualGet = env.contextualGet
end
if env.contextualGet then
contextualGet = env.contextualGet
end
source.storeURLs = env.std.storeURLs
source.storeCatagoryNames = env.std.storeCatagoryNames
source.storeURLs = env.std.storeURLs
source.storeCatagoryNames = env.std.storeCatagoryNames
if source.storeURLs and source.storeCatagoryNames then
for k,v in pairs(source.storeURLs) do
if source.generateName then
v.name = v.title:match('(%w+)')
if not v.name or #v.name == 0 then
v.name = tostring(k)
else
v.name = v.name:lower()
end
else
v.name = k
end
v.categoryName = source.storeCatagoryNames[v.catagory]
v.ltitle = v.title:lower()
end
end
end
if source.storeURLs and source.storeCatagoryNames then
for k,v in pairs(source.storeURLs) do
if source.generateName then
v.name = v.title:match('(%w+)')
if not v.name or #v.name == 0 then
v.name = tostring(k)
else
v.name = v.name:lower()
end
else
v.name = k
end
v.categoryName = source.storeCatagoryNames[v.catagory]
v.ltitle = v.title:lower()
end
end
end
end
local appPage = UI.Page {
menuBar = UI.MenuBar {
menuBar = UI.MenuBar {
-- showBackButton = not pocket,
buttons = {
{ text = '\027', event = 'back' },
{ text = 'Install', event = 'install' },
{ text = 'Run', event = 'run' },
{ text = 'View', event = 'view' },
{ text = 'Remove', event = 'uninstall', name = 'removeButton' },
},
},
container = UI.Window {
x = 2, y = 3, ex = -2, ey = -3,
viewport = UI.Viewport(),
},
notification = UI.Notification(),
accelerators = {
q = 'back',
backspace = 'back',
},
buttons = {
{ text = '\027', event = 'back' },
{ text = 'Install', event = 'install' },
{ text = 'Run', event = 'run' },
{ text = 'View', event = 'view' },
{ text = 'Remove', event = 'uninstall', name = 'removeButton' },
},
},
container = UI.Window {
x = 2, y = 3, ex = -2, ey = -3,
viewport = UI.Viewport(),
},
notification = UI.Notification(),
accelerators = {
q = 'back',
backspace = 'back',
},
}
function appPage.container.viewport:draw()
local app = self.parent.parent.app
local str = string.format(
'%s \nBy: %s \nCategory: %s\nFile name: %s\n\n%s',
Ansi.yellow .. app.title .. Ansi.reset,
app.creator,
app.categoryName, app.name,
Ansi.yellow .. app.description .. Ansi.reset)
local app = self.parent.parent.app
local str = string.format(
'%s \nBy: %s \nCategory: %s\nFile name: %s\n\n%s',
Ansi.yellow .. app.title .. Ansi.reset,
app.creator,
app.categoryName, app.name,
Ansi.yellow .. app.description .. Ansi.reset)
self:clear()
self:setCursorPos(1, 1)
self:print(str)
self.ymax = self.cursorY
self:clear()
self:setCursorPos(1, 1)
self:print(str)
self.ymax = self.cursorY
if appPage.notification.enabled then
appPage.notification:draw()
end
if appPage.notification.enabled then
appPage.notification:draw()
end
end
function appPage:enable(source, app)
self.source = source
self.app = app
UI.Page.enable(self)
self.source = source
self.app = app
UI.Page.enable(self)
self.container.viewport:setScrollPosition(0)
if fs.exists(fs.combine(APP_DIR, app.name)) then
self.menuBar.removeButton:enable('Remove')
else
self.menuBar.removeButton:disable('Remove')
end
self.container.viewport:setScrollPosition(0)
if fs.exists(fs.combine(APP_DIR, app.name)) then
self.menuBar.removeButton:enable('Remove')
else
self.menuBar.removeButton:disable('Remove')
end
end
function appPage:eventHandler(event)
if event.type == 'back' then
UI:setPreviousPage()
if event.type == 'back' then
UI:setPreviousPage()
elseif event.type == 'run' then
self.notification:info('Running program', 3)
self:sync()
runApp(self.app, true)
elseif event.type == 'run' then
self.notification:info('Running program', 3)
self:sync()
runApp(self.app, true)
elseif event.type == 'view' then
self.notification:info('Downloading program', 3)
self:sync()
viewApp(self.app)
elseif event.type == 'view' then
self.notification:info('Downloading program', 3)
self:sync()
viewApp(self.app)
elseif event.type == 'uninstall' then
if self.app.runOnly then
runApp(self.app, false, 'uninstall')
else
fs.delete(fs.combine(APP_DIR, self.app.name))
self.notification:success("Uninstalled " .. self.app.name, 3)
self:focusFirst(self)
self.menuBar.removeButton:disable('Remove')
self.menuBar:draw()
elseif event.type == 'uninstall' then
if self.app.runOnly then
runApp(self.app, false, 'uninstall')
else
fs.delete(fs.combine(APP_DIR, self.app.name))
self.notification:success("Uninstalled " .. self.app.name, 3)
self:focusFirst(self)
self.menuBar.removeButton:disable('Remove')
self.menuBar:draw()
unregisterApp(self.app.creator .. '.' .. self.app.name)
end
unregisterApp(self.app.creator .. '.' .. self.app.name)
end
elseif event.type == 'install' then
self.notification:info("Installing", 3)
self:sync()
local s, m
if self.app.runOnly then
s,m = runApp(self.app, false)
else
s,m = installApp(self.app)
end
if s then
self.notification:success(m, 3)
elseif event.type == 'install' then
self.notification:info("Installing", 3)
self:sync()
local s, m
if self.app.runOnly then
s,m = runApp(self.app, false)
else
s,m = installApp(self.app)
end
if s then
self.notification:success(m, 3)
if not self.app.runOnly then
self.menuBar.removeButton:enable('Remove')
self.menuBar:draw()
if not self.app.runOnly then
self.menuBar.removeButton:enable('Remove')
self.menuBar:draw()
local category = 'Apps'
if self.app.catagoryName == 'Game' then
category = 'Games'
end
local category = 'Apps'
if self.app.catagoryName == 'Game' then
category = 'Games'
end
registerApp({
run = fs.combine(APP_DIR, self.app.name),
title = self.app.title,
category = category,
icon = self.app.icon,
}, self.app.creator .. '.' .. self.app.name)
end
else
self.notification:error(m, 3)
end
else
return UI.Page.eventHandler(self, event)
end
return true
registerApp({
run = fs.combine(APP_DIR, self.app.name),
title = self.app.title,
category = category,
icon = self.app.icon,
}, self.app.creator .. '.' .. self.app.name)
end
else
self.notification:error(m, 3)
end
else
return UI.Page.eventHandler(self, event)
end
return true
end
local categoryPage = UI.Page {
menuBar = UI.MenuBar {
buttons = {
{ text = 'Catalog', dropdown = sources },
{ text = 'Category', name = 'categoryButton', dropdown = { } },
},
},
grid = UI.ScrollingGrid {
y = 2, ey = -2,
columns = {
{ heading = 'Title', key = 'title' },
},
sortColumn = 'title',
},
statusBar = UI.StatusBar(),
accelerators = {
l = 'lua',
q = 'quit',
},
menuBar = UI.MenuBar {
buttons = {
{ text = 'Catalog', dropdown = sources },
{ text = 'Category', name = 'categoryButton', dropdown = { } },
},
},
grid = UI.ScrollingGrid {
y = 2, ey = -2,
columns = {
{ heading = 'Title', key = 'title' },
},
sortColumn = 'title',
},
statusBar = UI.StatusBar(),
accelerators = {
l = 'lua',
q = 'quit',
},
}
function categoryPage:setCategory(source, name, index)
self.grid.values = { }
for _,v in pairs(source.storeURLs) do
if index == 0 or index == v.catagory then
table.insert(self.grid.values, v)
end
end
self.statusBar:setStatus(string.format('%s: %s', source.text, name))
self.grid:update()
self.grid:setIndex(1)
self.grid.values = { }
for _,v in pairs(source.storeURLs) do
if index == 0 or index == v.catagory then
table.insert(self.grid.values, v)
end
end
self.statusBar:setStatus(string.format('%s: %s', source.text, name))
self.grid:update()
self.grid:setIndex(1)
end
function categoryPage:setSource(source)
if not source.categoryMenu then
if not source.categoryMenu then
self.statusBar:setStatus('Loading...')
self.statusBar:draw()
self:sync()
self.statusBar:setStatus('Loading...')
self.statusBar:draw()
self:sync()
getSourceListing(source)
getSourceListing(source)
if not source.storeURLs then
error('Unable to download application list')
end
if not source.storeURLs then
error('Unable to download application list')
end
local buttons = { }
for k,v in Util.spairs(source.storeCatagoryNames,
function(a, b) return a:lower() < b:lower() end) do
local buttons = { }
for k,v in Util.spairs(source.storeCatagoryNames,
function(a, b) return a:lower() < b:lower() end) do
if v ~= 'Operating System' then
table.insert(buttons, {
text = v,
event = 'category',
index = k,
})
end
end
if v ~= 'Operating System' then
table.insert(buttons, {
text = v,
event = 'category',
index = k,
})
end
end
source.categoryMenu = UI.DropMenu({
buttons = buttons,
})
source.index, source.name = Util.first(source.storeCatagoryNames)
source.categoryMenu = UI.DropMenu({
buttons = buttons,
})
source.index, source.name = Util.first(source.storeCatagoryNames)
categoryPage.menuBar.categoryButton:add({
categoryMenu = source.categoryMenu
})
end
categoryPage.menuBar.categoryButton:add({
categoryMenu = source.categoryMenu
})
end
self.source = source
self.menuBar.categoryButton.dropmenu = source.categoryMenu
categoryPage:setCategory(source, source.name, source.index)
self.source = source
self.menuBar.categoryButton.dropmenu = source.categoryMenu
categoryPage:setCategory(source, source.name, source.index)
end
function categoryPage.grid:sortCompare(a, b)
return a.ltitle < b.ltitle
return a.ltitle < b.ltitle
end
function categoryPage.grid:getRowTextColor(row, selected)
if fs.exists(fs.combine(APP_DIR, row.name)) then
return colors.orange
end
return UI.Grid:getRowTextColor(row, selected)
if fs.exists(fs.combine(APP_DIR, row.name)) then
return colors.orange
end
return UI.Grid:getRowTextColor(row, selected)
end
function categoryPage:eventHandler(event)
if event.type == 'grid_select' or event.type == 'select' then
UI:setPage(appPage, self.source, self.grid:getSelected())
if event.type == 'grid_select' or event.type == 'select' then
UI:setPage(appPage, self.source, self.grid:getSelected())
elseif event.type == 'category' then
self:setCategory(self.source, event.button.text, event.button.index)
self:setFocus(self.grid)
self:draw()
elseif event.type == 'category' then
self:setCategory(self.source, event.button.text, event.button.index)
self:setFocus(self.grid)
self:draw()
elseif event.type == 'source' then
self:setFocus(self.grid)
self:setSource(event.button)
self:draw()
elseif event.type == 'source' then
self:setFocus(self.grid)
self:setSource(event.button)
self:draw()
elseif event.type == 'quit' then
UI:exitPullEvents()
elseif event.type == 'quit' then
UI:exitPullEvents()
else
return UI.Page.eventHandler(self, event)
end
return true
else
return UI.Page.eventHandler(self, event)
end
return true
end
print("Retrieving catalog list")

View File

@@ -10,196 +10,196 @@ local peripheral = _G.peripheral
--[[ -- PeripheralsPage -- ]] --
local peripheralsPage = UI.Page {
grid = UI.ScrollingGrid {
ey = -2,
columns = {
{ heading = 'Type', key = 'type' },
{ heading = 'Side', key = 'side' },
},
sortColumn = 'type',
autospace = true,
},
statusBar = UI.StatusBar {
values = 'Select peripheral',
},
accelerators = {
q = 'quit',
},
grid = UI.ScrollingGrid {
ey = -2,
columns = {
{ heading = 'Type', key = 'type' },
{ heading = 'Side', key = 'side' },
},
sortColumn = 'type',
autospace = true,
},
statusBar = UI.StatusBar {
values = 'Select peripheral',
},
accelerators = {
q = 'quit',
},
}
function peripheralsPage.grid:draw()
local sides = peripheral.getNames()
local sides = peripheral.getNames()
Util.clear(self.values)
for _,side in pairs(sides) do
table.insert(self.values, {
type = peripheral.getType(side),
side = side
})
end
self:update()
self:adjustWidth()
UI.Grid.draw(self)
Util.clear(self.values)
for _,side in pairs(sides) do
table.insert(self.values, {
type = peripheral.getType(side),
side = side
})
end
self:update()
self:adjustWidth()
UI.Grid.draw(self)
end
function peripheralsPage:updatePeripherals()
if UI:getCurrentPage() == self then
self.grid:draw()
self:sync()
end
if UI:getCurrentPage() == self then
self.grid:draw()
self:sync()
end
end
function peripheralsPage:eventHandler(event)
if event.type == 'quit' then
Event.exitPullEvents()
if event.type == 'quit' then
Event.exitPullEvents()
elseif event.type == 'grid_select' then
UI:setPage('methods', event.selected)
elseif event.type == 'grid_select' then
UI:setPage('methods', event.selected)
end
return UI.Page.eventHandler(self, event)
end
return UI.Page.eventHandler(self, event)
end
--[[ -- MethodsPage -- ]] --
local methodsPage = UI.Page {
backgroundColor = colors.black,
doc = UI.TextArea {
backgroundColor = colors.black,
x = 2, y = 2, ex = -1, ey = -7,
},
grid = UI.ScrollingGrid {
y = -6, ey = -2,
columns = {
{ heading = 'Name', key = 'name', width = UI.term.width }
},
sortColumn = 'name',
},
statusBar = UI.StatusBar {
status = 'q to return',
},
accelerators = {
q = 'back',
backspace = 'back',
},
backgroundColor = colors.black,
doc = UI.TextArea {
backgroundColor = colors.black,
x = 2, y = 2, ex = -1, ey = -7,
},
grid = UI.ScrollingGrid {
y = -6, ey = -2,
columns = {
{ heading = 'Name', key = 'name', width = UI.term.width }
},
sortColumn = 'name',
},
statusBar = UI.StatusBar {
status = 'q to return',
},
accelerators = {
q = 'back',
backspace = 'back',
},
}
function methodsPage:enable(p)
self.peripheral = p or self.peripheral
self.peripheral = p or self.peripheral
p = peripheral.wrap(self.peripheral.side)
if p.getDocs then
-- plethora
self.grid.values = { }
for k,v in pairs(p.getDocs()) do
table.insert(self.grid.values, {
name = k,
doc = v,
})
end
elseif not p.getAdvancedMethodsData then
-- computercraft
self.grid.values = { }
for name in pairs(p) do
table.insert(self.grid.values, {
name = name,
noext = true,
})
end
else
-- open peripherals
self.grid.values = p.getAdvancedMethodsData()
for name,f in pairs(self.grid.values) do
f.name = name
end
end
p = peripheral.wrap(self.peripheral.side)
if p.getDocs then
-- plethora
self.grid.values = { }
for k,v in pairs(p.getDocs()) do
table.insert(self.grid.values, {
name = k,
doc = v,
})
end
elseif not p.getAdvancedMethodsData then
-- computercraft
self.grid.values = { }
for name in pairs(p) do
table.insert(self.grid.values, {
name = name,
noext = true,
})
end
else
-- open peripherals
self.grid.values = p.getAdvancedMethodsData()
for name,f in pairs(self.grid.values) do
f.name = name
end
end
self.grid:update()
self.grid:setIndex(1)
self.grid:update()
self.grid:setIndex(1)
self.doc:setText(self:getDocumentation())
self.doc:setText(self:getDocumentation())
self.statusBar:setStatus(self.peripheral.type)
UI.Page.enable(self)
self.statusBar:setStatus(self.peripheral.type)
UI.Page.enable(self)
self:setFocus(self.grid)
self:setFocus(self.grid)
end
function methodsPage:eventHandler(event)
if event.type == 'back' then
UI:setPage(peripheralsPage)
return true
elseif event.type == 'grid_focus_row' then
self.doc:setText(self:getDocumentation())
end
return UI.Page.eventHandler(self, event)
if event.type == 'back' then
UI:setPage(peripheralsPage)
return true
elseif event.type == 'grid_focus_row' then
self.doc:setText(self:getDocumentation())
end
return UI.Page.eventHandler(self, event)
end
function methodsPage:getDocumentation()
local method = self.grid:getSelected()
local method = self.grid:getSelected()
if method.noext then -- computercraft docs
return 'No documentation'
end
if method.noext then -- computercraft docs
return 'No documentation'
end
if method.doc then -- plethora docs
return Ansi.yellow .. method.doc
end
if method.doc then -- plethora docs
return Ansi.yellow .. method.doc
end
-- open peripherals docs
local sb = { }
if method.description then
table.insert(sb, method.description .. '\n\n')
end
-- open peripherals docs
local sb = { }
if method.description then
table.insert(sb, method.description .. '\n\n')
end
if method.returnTypes ~= '()' then
table.insert(sb, Ansi.yellow .. method.returnTypes .. ' ')
end
table.insert(sb, Ansi.blue .. method.name .. Ansi.reset .. '(')
if method.returnTypes ~= '()' then
table.insert(sb, Ansi.yellow .. method.returnTypes .. ' ')
end
table.insert(sb, Ansi.blue .. method.name .. Ansi.reset .. '(')
for k,arg in ipairs(method.args) do
if arg.optional then
table.insert(sb, Ansi.orange .. string.format('[%s]', arg.name))
else
table.insert(sb, Ansi.green .. arg.name)
end
if k < #method.args then
table.insert(sb, ',')
end
end
table.insert(sb, Ansi.reset .. ')')
for k,arg in ipairs(method.args) do
if arg.optional then
table.insert(sb, Ansi.orange .. string.format('[%s]', arg.name))
else
table.insert(sb, Ansi.green .. arg.name)
end
if k < #method.args then
table.insert(sb, ',')
end
end
table.insert(sb, Ansi.reset .. ')')
Util.filterInplace(method.args, function(a) return #a.description > 0 end)
if #method.args > 0 then
table.insert(sb, '\n\n')
for k,arg in ipairs(method.args) do
if arg.optional then
table.insert(sb, Ansi.orange)
else
table.insert(sb, Ansi.green)
end
table.insert(sb, arg.name .. Ansi.reset .. ': ' .. arg.description)
if k ~= #method.args then
table.insert(sb, '\n\n')
end
end
end
return table.concat(sb)
Util.filterInplace(method.args, function(a) return #a.description > 0 end)
if #method.args > 0 then
table.insert(sb, '\n\n')
for k,arg in ipairs(method.args) do
if arg.optional then
table.insert(sb, Ansi.orange)
else
table.insert(sb, Ansi.green)
end
table.insert(sb, arg.name .. Ansi.reset .. ': ' .. arg.description)
if k ~= #method.args then
table.insert(sb, '\n\n')
end
end
end
return table.concat(sb)
end
Event.on('peripheral', function()
peripheralsPage:updatePeripherals()
peripheralsPage:updatePeripherals()
end)
Event.on('peripheral_detach', function()
peripheralsPage:updatePeripherals()
peripheralsPage:updatePeripherals()
end)
UI:setPage(peripheralsPage)
UI:setPages({
methods = methodsPage,
methods = methodsPage,
})
UI:pullEvents()

View File

@@ -10,230 +10,230 @@ local peripheral = _G.peripheral
local drives = { }
peripheral.find('drive', function(n, v)
if not drives.left then
drives.left = Util.shallowCopy(v)
drives.left.name = n
else
drives.right = Util.shallowCopy(v)
drives.right.name = n
end
if not drives.left then
drives.left = Util.shallowCopy(v)
drives.left.name = n
else
drives.right = Util.shallowCopy(v)
drives.right.name = n
end
end)
if not (drives.left and drives.right) then
error('Two drives are required')
error('Two drives are required')
end
local COPY_LEFT = 1
local COPY_RIGHT = 2
local directions = {
[ COPY_LEFT ] = { text = '-->>' },
[ COPY_RIGHT ] = { text = '<<--' },
[ COPY_LEFT ] = { text = '-->>' },
[ COPY_RIGHT ] = { text = '<<--' },
}
local config = Config.load('DiskCopy', {
eject = true,
automatic = false,
copyDir = COPY_LEFT
eject = true,
automatic = false,
copyDir = COPY_LEFT
})
local page = UI.Page {
linfo = UI.Window {
x = 2, y = 2, ey = 5, width = 18,
},
rinfo = UI.Window {
x = -19, y = 2, ey = 5, width = 18,
},
dir = UI.Button {
x = 17, y = 7, width = 6,
event = 'change_dir',
},
progress = UI.ProgressBar {
x = 2, ex = -2, y = -4,
backgroundColor = colors.black,
},
ejectText = UI.Text {
x = 2, y = -2,
value = 'Eject'
},
eject = UI.Checkbox {
x = 8, y = -2,
},
automaticText = UI.Text {
x = 12, y = -2,
value = 'Copy automatically'
},
automatic = UI.Checkbox {
x = 31, y = -2,
},
copyButton = UI.Button {
x = -7, y = -2,
text = 'Copy',
event = 'copy',
inactive = true,
},
warning = UI.Text {
x = 2, ex = -2, y = -5,
align = 'center',
textColor = colors.orange,
},
notification = UI.Notification { },
linfo = UI.Window {
x = 2, y = 2, ey = 5, width = 18,
},
rinfo = UI.Window {
x = -19, y = 2, ey = 5, width = 18,
},
dir = UI.Button {
x = 17, y = 7, width = 6,
event = 'change_dir',
},
progress = UI.ProgressBar {
x = 2, ex = -2, y = -4,
backgroundColor = colors.black,
},
ejectText = UI.Text {
x = 2, y = -2,
value = 'Eject'
},
eject = UI.Checkbox {
x = 8, y = -2,
},
automaticText = UI.Text {
x = 12, y = -2,
value = 'Copy automatically'
},
automatic = UI.Checkbox {
x = 31, y = -2,
},
copyButton = UI.Button {
x = -7, y = -2,
text = 'Copy',
event = 'copy',
inactive = true,
},
warning = UI.Text {
x = 2, ex = -2, y = -5,
align = 'center',
textColor = colors.orange,
},
notification = UI.Notification { },
}
function page:enable()
Util.merge(self.dir, directions[config.copyDir])
Util.merge(self.dir, directions[config.copyDir])
self.eject.value = config.eject
self.automatic.value = config.automatic
self.eject.value = config.eject
self.automatic.value = config.automatic
self.dir.x = math.floor((self.width / 2) - 3) + 1
self.dir.x = math.floor((self.width / 2) - 3) + 1
UI.Page.enable(self)
UI.Page.enable(self)
end
local function isValid(drive)
return drive.isDiskPresent() and drive.getMountPath()
return drive.isDiskPresent() and drive.getMountPath()
end
local function needsLabel(drive)
return drive.isDiskPresent() and not drive.getMountPath() and not drive.getAudioTitle()
return drive.isDiskPresent() and not drive.getMountPath() and not drive.getAudioTitle()
end
function page:drawInfo(drive, textArea)
local function getLabel()
return not drive.isDiskPresent() and 'empty' or
not drive.getMountPath() and 'invalid' or
drive.getDiskLabel() or 'unlabeled'
end
local function getLabel()
return not drive.isDiskPresent() and 'empty' or
not drive.getMountPath() and 'invalid' or
drive.getDiskLabel() or 'unlabeled'
end
local function getUsed()
return isValid(drive) and fs.getSize(drive.getMountPath(), true) or 0
end
local function getUsed()
return isValid(drive) and fs.getSize(drive.getMountPath(), true) or 0
end
local function getFree()
return isValid(drive) and fs.getFreeSpace(drive.getMountPath()) or 0
end
local function getFree()
return isValid(drive) and fs.getFreeSpace(drive.getMountPath()) or 0
end
textArea:setCursorPos(1, 1)
textArea:print(string.format('Drive: %s%s%s\nLabel: %s%s%s\nUsed: %s%s%s\nFree: %s%s%s',
Ansi.yellow, drive.name, Ansi.reset,
isValid(drive) and Ansi.yellow or Ansi.orange, getLabel():sub(1, 10), Ansi.reset,
Ansi.yellow, Util.toBytes(getUsed()), Ansi.reset,
Ansi.yellow, Util.toBytes(getFree()), Ansi.reset))
textArea:setCursorPos(1, 1)
textArea:print(string.format('Drive: %s%s%s\nLabel: %s%s%s\nUsed: %s%s%s\nFree: %s%s%s',
Ansi.yellow, drive.name, Ansi.reset,
isValid(drive) and Ansi.yellow or Ansi.orange, getLabel():sub(1, 10), Ansi.reset,
Ansi.yellow, Util.toBytes(getUsed()), Ansi.reset,
Ansi.yellow, Util.toBytes(getFree()), Ansi.reset))
end
function page:scan()
local showWarning = needsLabel(drives.left) or needsLabel(drives.right)
local valid = isValid(drives.left) and isValid(drives.right)
local showWarning = needsLabel(drives.left) or needsLabel(drives.right)
local valid = isValid(drives.left) and isValid(drives.right)
self.warning.value = showWarning and 'Computers must be labeled'
self.copyButton.inactive = not valid
self.warning.value = showWarning and 'Computers must be labeled'
self.copyButton.inactive = not valid
self:draw()
self.progress:centeredWrite(1, 'Analyzing Disks..')
self.progress:sync()
self:draw()
self.progress:centeredWrite(1, 'Analyzing Disks..')
self.progress:sync()
self:drawInfo(drives.left, self.linfo)
self:drawInfo(drives.right, self.rinfo)
self:drawInfo(drives.left, self.linfo)
self:drawInfo(drives.right, self.rinfo)
self.progress:clear()
self.progress:clear()
end
function page:copy()
local sdrive = config.copyDir == COPY_LEFT and drives.left or drives.right
local tdrive = config.copyDir == COPY_LEFT and drives.right or drives.left
local sdrive = config.copyDir == COPY_LEFT and drives.left or drives.right
local tdrive = config.copyDir == COPY_LEFT and drives.right or drives.left
local throttle = Util.throttle()
local sourceFiles, targetFiles = { }, { }
local throttle = Util.throttle()
local sourceFiles, targetFiles = { }, { }
local function getListing(mountPath, path, files)
for _,f in pairs(fs.list(path)) do
local file = fs.combine(path, f)
if not fs.isReadOnly(file) then
files[string.sub(file, #mountPath + 1)] = true
if fs.isDir(file) then
getListing(mountPath, file, files)
end
end
end
throttle()
end
local function getListing(mountPath, path, files)
for _,f in pairs(fs.list(path)) do
local file = fs.combine(path, f)
if not fs.isReadOnly(file) then
files[string.sub(file, #mountPath + 1)] = true
if fs.isDir(file) then
getListing(mountPath, file, files)
end
end
end
throttle()
end
self.progress:centeredWrite(1, 'Computing..')
self.progress:sync()
self.progress:centeredWrite(1, 'Computing..')
self.progress:sync()
getListing(sdrive.getMountPath(), sdrive.getMountPath(), sourceFiles)
getListing(tdrive.getMountPath(), tdrive.getMountPath(), targetFiles)
getListing(sdrive.getMountPath(), sdrive.getMountPath(), sourceFiles)
getListing(tdrive.getMountPath(), tdrive.getMountPath(), targetFiles)
local copied = 0
local totalFiles = Util.size(sourceFiles)
local copied = 0
local totalFiles = Util.size(sourceFiles)
local function rawCopy(source, target)
if fs.isDir(source) then
copied = copied + 1
if not fs.exists(target) then
fs.makeDir(target)
end
for _,f in pairs(fs.list(source)) do
rawCopy(fs.combine(source, f), fs.combine(target, f))
end
local function rawCopy(source, target)
if fs.isDir(source) then
copied = copied + 1
if not fs.exists(target) then
fs.makeDir(target)
end
for _,f in pairs(fs.list(source)) do
rawCopy(fs.combine(source, f), fs.combine(target, f))
end
else
if fs.exists(target) then
fs.delete(target)
end
else
if fs.exists(target) then
fs.delete(target)
end
fs.copy(source, target)
copied = copied + 1
self.progress.value = copied * 100 / totalFiles
self.progress:draw()
self.progress:sync()
end
throttle()
end
fs.copy(source, target)
copied = copied + 1
self.progress.value = copied * 100 / totalFiles
self.progress:draw()
self.progress:sync()
end
throttle()
end
local function cleanup()
for k in pairs(targetFiles) do
if not sourceFiles[k] then
fs.delete(fs.combine(tdrive.getMountPath(), k))
end
end
end
local function cleanup()
for k in pairs(targetFiles) do
if not sourceFiles[k] then
fs.delete(fs.combine(tdrive.getMountPath(), k))
end
end
end
self.progress:clear()
rawCopy(sdrive.getMountPath(), tdrive.getMountPath())
cleanup()
self.progress:centeredWrite(1, 'Copy Complete', colors.lime, colors.black)
self.progress:sync()
self.progress:clear()
rawCopy(sdrive.getMountPath(), tdrive.getMountPath())
cleanup()
self.progress:centeredWrite(1, 'Copy Complete', colors.lime, colors.black)
self.progress:sync()
self.progress.value = 0
self.progress:clear()
self.progress.value = 0
self.progress:clear()
self:scan()
self:scan()
if config.eject then
tdrive.ejectDisk()
end
if config.eject then
tdrive.ejectDisk()
end
end
function page:eventHandler(event)
if event.type == 'change_dir' then
config.copyDir = (config.copyDir) % 2 + 1
Util.merge(self.dir, directions[config.copyDir])
Config.update('DiskCopy', config)
self.dir:draw()
if event.type == 'change_dir' then
config.copyDir = (config.copyDir) % 2 + 1
Util.merge(self.dir, directions[config.copyDir])
Config.update('DiskCopy', config)
self.dir:draw()
elseif event.type == 'copy' then
self:copy()
elseif event.type == 'copy' then
self:copy()
elseif event.type == 'checkbox_change' then
if event.element == self.eject then
config.eject = not not event.checked
elseif event.element == self.automatic then
config.automatic = not not event.checked
end
elseif event.type == 'checkbox_change' then
if event.element == self.eject then
config.eject = not not event.checked
elseif event.element == self.automatic then
config.automatic = not not event.checked
end
Config.update('DiskCopy', config)
event.element:draw()
Config.update('DiskCopy', config)
event.element:draw()
else
return UI.Page.eventHandler(self, event)
@@ -242,22 +242,22 @@ function page:eventHandler(event)
end
Event.on("disk", function()
page:scan()
page:sync()
page:scan()
page:sync()
if config.automatic and not page.copyButton.inactive then
page:copy()
end
if config.automatic and not page.copyButton.inactive then
page:copy()
end
end)
Event.on("disk_eject", function()
page:scan()
page:sync()
page:scan()
page:sync()
end)
Event.onTimeout(.2, function()
page:scan()
page:sync()
page:scan()
page:sync()
end)
UI:setPage(page)

View File

@@ -8,131 +8,131 @@ local os = _G.os
UI:configure('Events', ...)
local page = UI.Page {
menuBar = UI.MenuBar {
buttons = {
{ text = 'Filter', event = 'filter' },
{ text = 'Reset', event = 'reset' },
{ text = 'Pause ', event = 'toggle', name = 'pauseButton' },
},
},
grid = UI.Grid {
y = 2,
columns = {
{ key = 'event' },
{ key = 'p1' },
{ key = 'p2' },
{ key = 'p3' },
{ key = 'p4' },
{ key = 'p5' },
},
autospace = true,
disableHeader = true,
},
accelerators = {
f = 'filter',
p = 'toggle',
r = 'reset',
c = 'clear',
q = 'quit',
},
filtered = { },
menuBar = UI.MenuBar {
buttons = {
{ text = 'Filter', event = 'filter' },
{ text = 'Reset', event = 'reset' },
{ text = 'Pause ', event = 'toggle', name = 'pauseButton' },
},
},
grid = UI.Grid {
y = 2,
columns = {
{ key = 'event' },
{ key = 'p1' },
{ key = 'p2' },
{ key = 'p3' },
{ key = 'p4' },
{ key = 'p5' },
},
autospace = true,
disableHeader = true,
},
accelerators = {
f = 'filter',
p = 'toggle',
r = 'reset',
c = 'clear',
q = 'quit',
},
filtered = { },
}
function page:eventHandler(event)
if event.type == 'filter' then
local entry = self.grid:getSelected()
self.filtered[entry.event] = true
if event.type == 'filter' then
local entry = self.grid:getSelected()
self.filtered[entry.event] = true
elseif event.type == 'toggle' then
self.paused = not self.paused
if self.paused then
self.menuBar.pauseButton.text = 'Resume'
else
self.menuBar.pauseButton.text = 'Pause '
end
self.menuBar:draw()
elseif event.type == 'toggle' then
self.paused = not self.paused
if self.paused then
self.menuBar.pauseButton.text = 'Resume'
else
self.menuBar.pauseButton.text = 'Pause '
end
self.menuBar:draw()
elseif event.type == 'grid_select' then
multishell.openTab({
path = 'sys/apps/Lua.lua',
args = { event.selected },
focused = true,
})
elseif event.type == 'grid_select' then
multishell.openTab({
path = 'sys/apps/Lua.lua',
args = { event.selected },
focused = true,
})
elseif event.type == 'reset' then
self.filtered = { }
self.grid:setValues({ })
self.grid:draw()
if self.paused then
self:emit({ type = 'toggle' })
end
elseif event.type == 'reset' then
self.filtered = { }
self.grid:setValues({ })
self.grid:draw()
if self.paused then
self:emit({ type = 'toggle' })
end
elseif event.type == 'clear' then
self.grid:setValues({ })
self.grid:draw()
elseif event.type == 'clear' then
self.grid:setValues({ })
self.grid:draw()
elseif event.type == 'quit' then
UI:exitPullEvents()
elseif event.type == 'quit' then
UI:exitPullEvents()
--[[
elseif event.type == 'focus_change' then
if event.focused == self.grid then
if not self.paused then
self:emit({ type = 'toggle' })
end
end
--]]
--[[
elseif event.type == 'focus_change' then
if event.focused == self.grid then
if not self.paused then
self:emit({ type = 'toggle' })
end
end
--]]
else
return UI.Page.eventHandler(self, event)
end
return true
else
return UI.Page.eventHandler(self, event)
end
return true
end
function page.grid:getDisplayValues(row)
row = Util.shallowCopy(row)
row = Util.shallowCopy(row)
local function tovalue(s)
if type(s) == 'table' then
return 'table'
end
return s
end
local function tovalue(s)
if type(s) == 'table' then
return 'table'
end
return s
end
for k,v in pairs(row) do
row[k] = tovalue(v)
end
for k,v in pairs(row) do
row[k] = tovalue(v)
end
return row
return row
end
function page.grid:draw()
self:adjustWidth()
UI.Grid.draw(self)
self:adjustWidth()
UI.Grid.draw(self)
end
Event.addRoutine(function()
while true do
local e = { os.pullEvent() }
if not page.paused and not page.filtered[e[1]] then
table.insert(page.grid.values, 1, {
event = e[1],
p1 = e[2],
p2 = e[3],
p3 = e[4],
p4 = e[5],
p5 = e[6],
})
if #page.grid.values > page.grid.height then
table.remove(page.grid.values, #page.grid.values)
end
page.grid:update()
page.grid:draw()
page:sync()
end
end
while true do
local e = { os.pullEvent() }
if not page.paused and not page.filtered[e[1]] then
table.insert(page.grid.values, 1, {
event = e[1],
p1 = e[2],
p2 = e[3],
p3 = e[4],
p4 = e[5],
p5 = e[6],
})
if #page.grid.values > page.grid.height then
table.remove(page.grid.values, #page.grid.values)
end
page.grid:update()
page.grid:draw()
page:sync()
end
end
end)
UI:setPage(page)

View File

@@ -15,32 +15,64 @@ local gpt = GPS.getPoint() or error('GPS not found')
local pts, blocks
local page = UI.Page {
mode = UI.Chooser {
x = 13, y = -1,
choices = {
{ name = 'No breaking', value = 'digNone' },
{ name = 'Destructive', value = 'turtleSafe' },
},
value = 'digNone',
},
grid = UI.ScrollingGrid {
y = 2, ey = -2,
columns = {
{ heading = 'Label', key = 'label' },
{ heading = 'Dist', key = 'distance' },
{ heading = 'Status', key = 'status' },
{ heading = 'Fuel', key = 'fuel' },
},
sortColumn = 'distance',
autospace = true,
},
menuBar = UI.MenuBar {
buttons = {
{ text = 'Range', event = 'range' },
{ text = 'Stop', event = 'stop' },
},
mode = UI.Chooser {
x = -16,
choices = {
{ name = 'No breaking', value = 'digNone' },
{ name = 'Destructive', value = 'turtleSafe' },
},
value = 'digNone',
},
},
grid = UI.ScrollingGrid {
y = 2, ey = -2,
columns = {
{ heading = 'Label', key = 'label' },
{ heading = 'Dist', key = 'distance' },
{ heading = 'Status', key = 'status' },
{ heading = 'Fuel', key = 'fuel' },
},
sortColumn = 'distance',
autospace = true,
},
range = UI.SlideOut {
y = -7, height = 7,
backgroundColor = colors.cyan,
titleBar = UI.TitleBar {
event = 'cancel',
title = 'Enter range',
},
notice = UI.TextArea {
x = 2, ex = -2, y = 3, ey = 4,
value =
[[Select all turtles within a specified range]],
},
entry = UI.TextEntry {
y = 6, x = 2, ex = 10,
limit = 4,
shadowText = 'range',
accelerators = {
enter = 'select_range',
},
},
button = UI.Button {
x = 12, y = 6,
text = 'Apply',
event = 'select_range',
}
},
}
function page.grid:getRowTextColor(row, selected)
if swarm.pool[row.id] then
return colors.yellow
end
return UI.ScrollingGrid.getRowTextColor(self, row, selected)
if swarm.pool[row.id] then
return colors.yellow
end
return UI.ScrollingGrid.getRowTextColor(self, row, selected)
end
function page.grid:getDisplayValues(row)
@@ -55,130 +87,155 @@ function page.grid:getDisplayValues(row)
end
function page:enable()
local function update()
local t = { }
for _,v in pairs(network) do
if v.fuel and v.active and v.fuel > 0 and v.distance then
table.insert(t, v)
end
end
self.grid:setValues(t)
end
local function update()
local t = { }
for _,v in pairs(network) do
if v.fuel and v.active and v.fuel > 0 and v.distance then
table.insert(t, v)
end
end
self.grid:setValues(t)
end
Event.onInterval(3, function()
update()
self.grid:draw()
self:sync()
end)
Event.onInterval(3, function()
update()
self.grid:draw()
self:sync()
end)
update()
update()
UI.Page.enable(self)
UI.Page.enable(self)
end
local function follow(member)
local turtle = member.turtle
turtle.reset()
turtle.set({
digPolicy = page.mode.value,
status = 'Following',
})
local turtle = member.turtle
turtle.reset()
turtle.set({
digPolicy = page.menuBar.mode.value,
status = 'Following',
})
if not turtle.enableGPS(nil, true) then
error('turtle: No GPS found')
end
if not turtle.enableGPS(nil, true) then
error('turtle: No GPS found')
end
member.snmp = Socket.connect(member.id, 161)
member.snmp.co = coroutine.running()
member.snmp = Socket.connect(member.id, 161)
member.snmp.co = coroutine.running()
local pt
local pt
while true do
while pt and Point.same(gpt, pt) do
os.sleep(.5)
end
pt = Point.copy(gpt)
while true do
while pt and Point.same(gpt, pt) do
os.sleep(.5)
end
pt = Point.copy(gpt)
local cpt = Point.closest(turtle.getPoint(), pts)
local cpt = Point.closest(turtle.getPoint(), pts)
turtle.abort(false)
if turtle.pathfind(cpt, { blocks = blocks }) then
turtle.headTowards(pt)
end
end
turtle.abort(false)
if turtle.pathfind(cpt, { blocks = blocks }) then
turtle.headTowards(pt)
end
end
end
function swarm:onRemove(member, status, message)
if member.socket then
pcall(function()
member.turtle.set({ status = 'idle' })
member.turtle.abort(true)
end)
end
if member.snmp then
member.snmp:close()
member.snmp = nil
end
if not status then
_G._syslog(message)
end
if member.socket then
pcall(function()
member.turtle.set({ status = 'idle' })
member.turtle.abort(true)
end)
end
if member.snmp then
member.snmp:close()
member.snmp = nil
end
if not status then
_G._syslog(message)
end
end
function page:eventHandler(event)
if event.type == 'grid_select' then
if not swarm.pool[event.selected.id] then
swarm:add(event.selected.id)
swarm:run(follow)
else
swarm:remove(event.selected.id)
end
self.grid:draw()
if event.type == 'grid_select' then
if not swarm.pool[event.selected.id] then
swarm:add(event.selected.id)
swarm:run(follow)
else
swarm:remove(event.selected.id)
end
self.grid:draw()
elseif event.type == 'choice_change' then
local script = string.format('turtle.set({ digPolicy = "%s"})', event.value)
for _, member in pairs(swarm.pool) do
member.snmp:write({ type = 'scriptEx', args = script })
end
elseif event.type == 'choice_change' then
local script = string.format('turtle.set({ digPolicy = "%s"})', event.value)
for _, member in pairs(swarm.pool) do
member.snmp:write({ type = 'scriptEx', args = script })
end
else
return UI.Page.eventHandler(self, event)
end
return true
elseif event.type == 'stop' then
for id in pairs(swarm.pool) do
swarm:remove(id)
end
elseif event.type == 'range' then
self.range:show()
elseif event.type == 'cancel' then
self.range:hide()
elseif event.type == 'select_range' then
local range = tonumber(self.range.entry.value)
if range and range > 0 then
for id, v in pairs(network) do
if not swarm.pool[id] then
if v.fuel and v.active and v.fuel > 0 and v.distance and v.distance <= range then
swarm:add(id)
end
end
end
swarm:run(follow)
self.range:hide()
end
else
return UI.Page.eventHandler(self, event)
end
return true
end
Event.addRoutine(function()
while true do
local pt = GPS.getPoint()
if not pts or (pt and not Point.same(pt, gpt)) then
gpt = pt
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 },
}
blocks = { }
while true do
local pt = GPS.getPoint()
if not pts or (pt and not Point.same(pt, gpt)) then
gpt = pt
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 },
}
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
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(Point.above(pt))
-- don't run into player
addBlocks(pt)
addBlocks(Point.above(pt))
for _, member in pairs(swarm.pool) do
if member.snmp then
member.snmp:write({ type = 'scriptEx', args = 'turtle.abort(true)' })
end
end
end
os.sleep(1)
end
for _, member in pairs(swarm.pool) do
if member.snmp then
member.snmp:write({ type = 'scriptEx', args = 'turtle.abort(true)' })
end
end
end
os.sleep(1)
end
end)
UI:setPage(page)

View File

@@ -21,12 +21,12 @@ local config = { }
Config.load('Turtles', config)
local options = {
turtle = { arg = 'i', type = 'number', value = config.id or -1,
desc = 'Turtle ID' },
tab = { arg = 's', type = 'string', value = config.tab or 'Sel',
desc = 'Selected tab to display' },
help = { arg = 'h', type = 'flag', value = false,
desc = 'Displays the options' },
turtle = { arg = 'i', type = 'number', value = config.id or -1,
desc = 'Turtle ID' },
tab = { arg = 's', type = 'string', value = config.tab or 'Sel',
desc = 'Selected tab to display' },
help = { arg = 'h', type = 'flag', value = false,
desc = 'Displays the options' },
}
local SCRIPTS_PATH = 'packages/common/etc/scripts'
@@ -35,343 +35,343 @@ local nullTerm = Terminal.getNullTerm(term.current())
local socket
local page = UI.Page {
coords = UI.Window {
backgroundColor = colors.black,
height = 3,
},
tabs = UI.Tabs {
x = 1, y = 4, ey = -2,
scripts = UI.ScrollingGrid {
tabTitle = 'Run',
backgroundColor = colors.cyan,
columns = {
{ heading = '', key = 'label' },
},
disableHeader = true,
sortColumn = 'label',
autospace = true,
},
turtles = UI.ScrollingGrid {
tabTitle = 'Select',
backgroundColor = colors.cyan,
columns = {
{ heading = 'label', key = 'label' },
{ heading = 'Dist', key = 'distance' },
{ heading = 'Status', key = 'status' },
{ heading = 'Fuel', key = 'fuel' },
},
disableHeader = true,
sortColumn = 'label',
autospace = true,
},
inventory = UI.ScrollingGrid {
backgroundColor = colors.cyan,
tabTitle = 'Inv',
columns = {
{ heading = '', key = 'index', width = 2 },
{ heading = '', key = 'qty', width = 2 },
{ heading = 'Inventory', key = 'id', width = UI.term.width - 7 },
},
disableHeader = true,
sortColumn = 'index',
},
coords = UI.Window {
backgroundColor = colors.black,
height = 3,
},
tabs = UI.Tabs {
x = 1, y = 4, ey = -2,
scripts = UI.ScrollingGrid {
tabTitle = 'Run',
backgroundColor = colors.cyan,
columns = {
{ heading = '', key = 'label' },
},
disableHeader = true,
sortColumn = 'label',
autospace = true,
},
turtles = UI.ScrollingGrid {
tabTitle = 'Select',
backgroundColor = colors.cyan,
columns = {
{ heading = 'label', key = 'label' },
{ heading = 'Dist', key = 'distance' },
{ heading = 'Status', key = 'status' },
{ heading = 'Fuel', key = 'fuel' },
},
disableHeader = true,
sortColumn = 'label',
autospace = true,
},
inventory = UI.ScrollingGrid {
backgroundColor = colors.cyan,
tabTitle = 'Inv',
columns = {
{ heading = '', key = 'index', width = 2 },
{ heading = '', key = 'qty', width = 2 },
{ heading = 'Inventory', key = 'id', width = UI.term.width - 7 },
},
disableHeader = true,
sortColumn = 'index',
},
--[[
policy = UI.ScrollingGrid {
tabTitle = 'Mod',
backgroundColor = UI.TabBar.defaults.selectedBackgroundColor,
columns = {
{ heading = 'label', key = 'label' },
},
values = policies,
disableHeader = true,
sortColumn = 'label',
autospace = true,
},
]]
action = UI.Window {
tabTitle = 'Action',
backgroundColor = colors.cyan,
moveUp = UI.Button {
x = 5, y = 2,
text = 'up',
fn = 'turtle.up',
},
moveDown = UI.Button {
x = 5, y = 4,
text = 'dn',
fn = 'turtle.down',
},
moveForward = UI.Button {
x = 9, y = 3,
text = 'f',
fn = 'turtle.forward',
},
moveBack = UI.Button {
x = 2, y = 3,
text = 'b',
fn = 'turtle.back',
},
turnLeft = UI.Button {
x = 2, y = 6,
text = 'lt',
fn = 'turtle.turnLeft',
},
turnRight = UI.Button {
x = 8, y = 6,
text = 'rt',
fn = 'turtle.turnRight',
},
info = UI.TextArea {
x = 15, y = 2,
inactive = true,
}
},
},
statusBar = UI.StatusBar {
values = { },
columns = {
{ key = 'status' },
{ key = 'distance', width = 6 },
{ key = 'fuel', width = 6 },
},
},
notification = UI.Notification(),
accelerators = {
q = 'quit',
},
policy = UI.ScrollingGrid {
tabTitle = 'Mod',
backgroundColor = UI.TabBar.defaults.selectedBackgroundColor,
columns = {
{ heading = 'label', key = 'label' },
},
values = policies,
disableHeader = true,
sortColumn = 'label',
autospace = true,
},
]]
action = UI.Window {
tabTitle = 'Action',
backgroundColor = colors.cyan,
moveUp = UI.Button {
x = 5, y = 2,
text = 'up',
fn = 'turtle.up',
},
moveDown = UI.Button {
x = 5, y = 4,
text = 'dn',
fn = 'turtle.down',
},
moveForward = UI.Button {
x = 9, y = 3,
text = 'f',
fn = 'turtle.forward',
},
moveBack = UI.Button {
x = 2, y = 3,
text = 'b',
fn = 'turtle.back',
},
turnLeft = UI.Button {
x = 2, y = 6,
text = 'lt',
fn = 'turtle.turnLeft',
},
turnRight = UI.Button {
x = 8, y = 6,
text = 'rt',
fn = 'turtle.turnRight',
},
info = UI.TextArea {
x = 15, y = 2,
inactive = true,
}
},
},
statusBar = UI.StatusBar {
values = { },
columns = {
{ key = 'status' },
{ key = 'distance', width = 6 },
{ key = 'fuel', width = 6 },
},
},
notification = UI.Notification(),
accelerators = {
q = 'quit',
},
}
function page:enable(turtle)
self.turtle = turtle
UI.Page.enable(self)
self.turtle = turtle
UI.Page.enable(self)
end
function page:runFunction(script, nowrap)
for _ = 1, 2 do
if not socket then
socket = Socket.connect(self.turtle.id, 161)
end
for _ = 1, 2 do
if not socket then
socket = Socket.connect(self.turtle.id, 161)
end
if socket then
if not nowrap then
script = 'turtle.run(' .. script .. ')'
end
if socket:write({ type = 'scriptEx', args = script }) then
local t = socket:read(3)
if t then
return table.unpack(t)
end
return false, 'Socket timeout'
end
end
socket = nil
end
self.notification:error('Unable to connect')
if socket then
if not nowrap then
script = 'turtle.run(' .. script .. ')'
end
if socket:write({ type = 'scriptEx', args = script }) then
local t = socket:read(3)
if t then
return table.unpack(t)
end
return false, 'Socket timeout'
end
end
socket = nil
end
self.notification:error('Unable to connect')
end
function page:runScript(scriptName)
if self.turtle then
self.notification:info('Connecting')
self:sync()
if self.turtle then
self.notification:info('Connecting')
self:sync()
local cmd = string.format('Script %d %s', self.turtle.id, scriptName)
local ot = term.redirect(nullTerm)
pcall(function() shell.run(cmd) end)
term.redirect(ot)
self.notification:success('Sent')
end
local cmd = string.format('Script %d %s', self.turtle.id, scriptName)
local ot = term.redirect(nullTerm)
pcall(function() shell.run(cmd) end)
term.redirect(ot)
self.notification:success('Sent')
end
end
function page.coords:draw()
local t = self.parent.turtle
self:clear()
if t then
self:setCursorPos(2, 2)
local ind = 'GPS'
if not t.point.gps then
ind = 'REL'
end
self:print(string.format('%s : %d,%d,%d',
ind, t.point.x, t.point.y, t.point.z))
end
local t = self.parent.turtle
self:clear()
if t then
self:setCursorPos(2, 2)
local ind = 'GPS'
if not t.point.gps then
ind = 'REL'
end
self:print(string.format('%s : %d,%d,%d',
ind, t.point.x, t.point.y, t.point.z))
end
end
--[[ Inventory Tab ]]--
function page.tabs.inventory:getRowTextColor(row, selected)
if page.turtle and row.selected then
return colors.yellow
end
return UI.ScrollingGrid.getRowTextColor(self, row, selected)
if page.turtle and row.selected then
return colors.yellow
end
return UI.ScrollingGrid.getRowTextColor(self, row, selected)
end
function page.tabs.inventory:draw()
local t = page.turtle
Util.clear(self.values)
if t then
for _,v in ipairs(t.inventory) do
if v.qty > 0 then
table.insert(self.values, v)
if v.index == t.slotIndex then
v.selected = true
end
if v.id then
v.id = itemDB:getName(v)
end
end
end
end
self:adjustWidth()
self:update()
UI.ScrollingGrid.draw(self)
local t = page.turtle
Util.clear(self.values)
if t then
for _,v in ipairs(t.inventory) do
if v.qty > 0 then
table.insert(self.values, v)
if v.index == t.slotIndex then
v.selected = true
end
if v.id then
v.id = itemDB:getName(v)
end
end
end
end
self:adjustWidth()
self:update()
UI.ScrollingGrid.draw(self)
end
function page.tabs.inventory:eventHandler(event)
if event.type == 'grid_select' then
local fn = string.format('turtle.select(%d)', event.selected.index)
page:runFunction(fn)
else
return UI.ScrollingGrid.eventHandler(self, event)
end
return true
if event.type == 'grid_select' then
local fn = string.format('turtle.select(%d)', event.selected.index)
page:runFunction(fn)
else
return UI.ScrollingGrid.eventHandler(self, event)
end
return true
end
function page.tabs.scripts:draw()
Util.clear(self.values)
local files = fs.list(SCRIPTS_PATH)
for _,path in pairs(files) do
table.insert(self.values, { label = path, path = fs.combine(SCRIPTS_PATH, path) })
end
self:update()
UI.ScrollingGrid.draw(self)
Util.clear(self.values)
local files = fs.list(SCRIPTS_PATH)
for _,path in pairs(files) do
table.insert(self.values, { label = path, path = fs.combine(SCRIPTS_PATH, path) })
end
self:update()
UI.ScrollingGrid.draw(self)
end
function page.tabs.scripts:eventHandler(event)
if event.type == 'grid_select' then
page:runScript(event.selected.label)
else
return UI.ScrollingGrid.eventHandler(self, event)
end
return true
if event.type == 'grid_select' then
page:runScript(event.selected.label)
else
return UI.ScrollingGrid.eventHandler(self, event)
end
return true
end
function page.tabs.turtles:getDisplayValues(row)
row = Util.shallowCopy(row)
if row.fuel then
row.fuel = Util.toBytes(row.fuel)
end
if row.distance then
row.distance = Util.round(row.distance, 1)
end
return row
row = Util.shallowCopy(row)
if row.fuel then
row.fuel = Util.toBytes(row.fuel)
end
if row.distance then
row.distance = Util.round(row.distance, 1)
end
return row
end
function page.tabs.turtles:draw()
Util.clear(self.values)
for _,v in pairs(network) do
if v.fuel then
table.insert(self.values, v)
end
end
self:update()
UI.ScrollingGrid.draw(self)
Util.clear(self.values)
for _,v in pairs(network) do
if v.fuel then
table.insert(self.values, v)
end
end
self:update()
UI.ScrollingGrid.draw(self)
end
function page.tabs.turtles:eventHandler(event)
if event.type == 'grid_select' then
page.turtle = event.selected
config.id = event.selected.id
Config.update('Turtles', config)
multishell.setTitle(multishell.getCurrent(), page.turtle.label)
if socket then
socket:close()
socket = nil
end
else
return UI.ScrollingGrid.eventHandler(self, event)
end
return true
if event.type == 'grid_select' then
page.turtle = event.selected
config.id = event.selected.id
Config.update('Turtles', config)
multishell.setTitle(multishell.getCurrent(), page.turtle.label)
if socket then
socket:close()
socket = nil
end
else
return UI.ScrollingGrid.eventHandler(self, event)
end
return true
end
function page.statusBar:draw()
local t = self.parent.turtle
if t then
self.values.status = t.status
self.values.distance = Util.round(t.distance, 2)
self.values.fuel = Util.toBytes(t.fuel)
end
UI.StatusBar.draw(self)
local t = self.parent.turtle
if t then
self.values.status = t.status
self.values.distance = Util.round(t.distance, 2)
self.values.fuel = Util.toBytes(t.fuel)
end
UI.StatusBar.draw(self)
end
function page:showBlocks()
local script = [[
local function inspect(direction)
local s,b = turtle['inspect' .. (direction or '')]()
if not s then
return 'minecraft:air:0'
end
return string.format('%s:%d', b.name, b.metadata)
end
local script = [[
local function inspect(direction)
local s,b = turtle['inspect' .. (direction or '')]()
if not s then
return 'minecraft:air:0'
end
return string.format('%s:%d', b.name, b.metadata)
end
local bu, bf, bd = inspect('Up'), inspect(), inspect('Down')
return string.format('%s\n%s\n%s', bu, bf, bd)
]]
local bu, bf, bd = inspect('Up'), inspect(), inspect('Down')
return string.format('%s\n%s\n%s', bu, bf, bd)
]]
local s, m = self:runFunction(script, true)
self.tabs.action.info:setText(s or m)
local s, m = self:runFunction(script, true)
self.tabs.action.info:setText(s or m)
end
function page:eventHandler(event)
if event.type == 'quit' then
UI:exitPullEvents()
if event.type == 'quit' then
UI:exitPullEvents()
elseif event.type == 'tab_select' then
config.tab = event.button.text
Config.update('Turtles', config)
elseif event.type == 'tab_select' then
config.tab = event.button.text
Config.update('Turtles', config)
elseif event.type == 'button_press' then
if event.button.fn then
self:runFunction(event.button.fn, event.button.nowrap)
self:showBlocks()
elseif event.button.script then
self:runScript(event.button.script)
end
else
return UI.Page.eventHandler(self, event)
end
return true
elseif event.type == 'button_press' then
if event.button.fn then
self:runFunction(event.button.fn, event.button.nowrap)
self:showBlocks()
elseif event.button.script then
self:runScript(event.button.script)
end
else
return UI.Page.eventHandler(self, event)
end
return true
end
function page:enable()
UI.Page.enable(self)
UI.Page.enable(self)
-- self.tabs:activateTab(page.tabs.turtles)
end
if not Util.getOptions(options, { ... }, true) then
return
return
end
if options.turtle.value >= 0 then
for _ = 1, 10 do
page.turtle = _G.network[options.turtle.value]
if page.turtle then
break
end
os.sleep(1)
end
for _ = 1, 10 do
page.turtle = _G.network[options.turtle.value]
if page.turtle then
break
end
os.sleep(1)
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
if page.turtle then
local t = _G.network[page.turtle.id]
page.turtle = t
page:draw()
page:sync()
end
end)
if config.tab then
page.tabs.tabBar:selectTab(config.tab)
page.tabs.tabBar:selectTab(config.tab)
end
UI:setPage(page)

View File

@@ -1,7 +1,7 @@
local c = function(shell, nIndex, sText)
if nIndex == 1 then
return _G.fs.complete(sText, shell.dir(), true, false)
end
if nIndex == 1 then
return _G.fs.complete(sText, shell.dir(), true, false)
end
end
_ENV.shell.setCompletionFunction("packages/common/edit.lua", c)

45
common/canvasClient.lua Normal file
View File

@@ -0,0 +1,45 @@
local Point = require('point')
local Util = require('util')
local device = _G.device
local os = _G.os
local turtle = _G.turtle
local function convert(blocks, reference)
if not reference then
return blocks
end
local rotated = {
[0] = 0,
[1] = 3,
[2] = 2,
[3] = 1,
}
return Util.reduce(blocks, function(acc, b)
local c = Util.shallowCopy(b)
Point.rotate(c, rotated[reference.heading])
c.x = c.x + reference.x
c.y = c.y + reference.y
c.z = c.z + reference.z
table.insert(acc, c)
return acc
end, { })
end
local function broadcast(blocks, displayType, source)
if device.wireless_modem then
device.wireless_modem.transmit(3773, os.getComputerID(), {
type = displayType,
data = convert(blocks, source),
})
end
end
while true do
local _, msg = os.pullEvent('canvas')
local reference = turtle and turtle.getState().reference
broadcast(msg.data, msg.type, reference)
end

File diff suppressed because it is too large Load Diff

View File

@@ -22,37 +22,37 @@ local scanner = device['plethora:scanner'] or
-- hud
local canvas = glasses and glasses.canvas()
if canvas then
local lh
local lh
local function addText(x, y, text, color)
local th = canvas.group.addText({ x, y }, text, color or 0xa0a0a0FF)
lh = lh or th.getLineHeight()
th.setShadow(true)
th.setScale(.75)
return th
end
local function addText(x, y, text, color)
local th = canvas.group.addText({ x, y }, text, color or 0xa0a0a0FF)
lh = lh or th.getLineHeight()
th.setShadow(true)
th.setScale(.75)
return th
end
canvas.group = canvas.addGroup({ 4, 90 })
canvas.group.bg = canvas.group.addRectangle(0, 0, 80, 10, 0x40404080)
canvas.group.addLines(
{ 0, 0 },
{ 80, 0 },
{ 80, 10 },
{ 0, 10 },
{ 0, 0 },
0x202020FF,
2)
addText(20, 2, 'Swarm Miner', 0xc0c0c0FF)
canvas.group = canvas.addGroup({ 4, 90 })
canvas.group.bg = canvas.group.addRectangle(0, 0, 80, 10, 0x40404080)
canvas.group.addLines(
{ 0, 0 },
{ 80, 0 },
{ 80, 10 },
{ 0, 10 },
{ 0, 0 },
0x202020FF,
2)
addText(20, 2, 'Swarm Miner', 0xc0c0c0FF)
local y = 15
addText(3, y, 'Turtles')
canvas.turtles = addText(60, y, '')
canvas.group.addLine({ 0, y + lh - 2 }, { 80, y + lh - 2 }, 0x404040FF, 4)
local y = 15
addText(3, y, 'Turtles')
canvas.turtles = addText(60, y, '')
canvas.group.addLine({ 0, y + lh - 2 }, { 80, y + lh - 2 }, 0x404040FF, 4)
y = y + lh + 5
addText(3, y, 'Queue')
canvas.queue = addText(60, y, '')
canvas.group.addLine({ 0, y + lh - 2 }, { 80, y + lh - 2 }, 0x404040FF, 4)
y = y + lh + 5
addText(3, y, 'Queue')
canvas.queue = addText(60, y, '')
canvas.group.addLine({ 0, y + lh - 2 }, { 80, y + lh - 2 }, 0x404040FF, 4)
end
-- container
@@ -62,19 +62,19 @@ local box, offset
local paused = false
local function inBox(pt)
if not box or not box.ex then
return true
end
return Point.inBox(pt, box)
if not box or not box.ex then
return true
end
return Point.inBox(pt, box)
end
local function locate()
for _ = 1, 3 do
local pt = GPS.getPoint()
if pt then
return pt
end
end
for _ = 1, 3 do
local pt = GPS.getPoint()
if pt then
return pt
end
end
end
local spt = GPS.getPoint() or error('GPS failure')
@@ -88,7 +88,7 @@ local abort
local function hijackTurtle(remoteId)
local socket, msg = Socket.connect(remoteId, 188)
if not socket then
if not socket then
error(msg)
end
@@ -111,240 +111,240 @@ local function hijackTurtle(remoteId)
end
local function getNextPoint(turtle)
if not paused then
local pt = Point.closest(turtle.getPoint(), queue)
if pt then
turtle.pt = pt
queue[pt.pkey] = nil
return pt
end
end
if not paused then
local pt = Point.closest(turtle.getPoint(), queue)
if pt then
turtle.pt = pt
queue[pt.pkey] = nil
return pt
end
end
end
local function run(member, point)
Event.addRoutine(function()
local turtle, socket
local _, m = pcall(function()
member.active = true
turtle, socket = hijackTurtle(member.id)
Event.addRoutine(function()
local turtle, socket
local _, m = pcall(function()
member.active = true
turtle, socket = hijackTurtle(member.id)
local function emptySlots(retain, pt)
local slots = turtle.getFilledSlots()
for _,slot in pairs(slots) do
if not retain[slot.key] then
turtle.select(slot.index)
if pt then
turtle.dropAt(pt, 64)
else
turtle.dropUp(64)
end
end
end
end
local function emptySlots(retain, pt)
local slots = turtle.getFilledSlots()
for _,slot in pairs(slots) do
if not retain[slot.key] then
turtle.select(slot.index)
if pt then
turtle.dropAt(pt, 64)
else
turtle.dropUp(64)
end
end
end
end
local function dropOff()
-- go to 2 above chest
local topPoint = Point.copy(chestPoint)
topPoint.y = topPoint.y + 2
turtle.gotoY(topPoint.y)
while not turtle.go(topPoint) do
os.sleep(.5)
end
local function dropOff()
-- go to 2 above chest
local topPoint = Point.copy(chestPoint)
topPoint.y = topPoint.y + 2
turtle.gotoY(topPoint.y)
while not turtle.go(topPoint) do
os.sleep(.5)
end
-- path to chest
local box = Point.makeBox(
{ x = chestPoint.x - 3, y = chestPoint.y + 3, z = chestPoint.z - 3 },
{ x = chestPoint.x + 3, y = chestPoint.y, z = chestPoint.z + 3 }
)
turtle.set({
movementStrategy = 'pathing',
pathingBox = Point.normalizeBox(box),
digPolicy = 'digNone',
})
while not turtle.moveAgainst(chestPoint) do
os.sleep(.5)
end
emptySlots({ }, chestPoint)
-- path to chest
local box = Point.makeBox(
{ x = chestPoint.x - 3, y = chestPoint.y + 3, z = chestPoint.z - 3 },
{ x = chestPoint.x + 3, y = chestPoint.y, z = chestPoint.z + 3 }
)
turtle.set({
movementStrategy = 'pathing',
pathingBox = Point.normalizeBox(box),
digPolicy = 'digNone',
})
while not turtle.moveAgainst(chestPoint) do
os.sleep(.5)
end
emptySlots({ }, chestPoint)
-- path to 3 above chest
turtle.pathfind(Point.above(topPoint))
turtle.set({
movementStrategy = 'goto',
digPolicy = 'blacklist',
})
end
-- path to 3 above chest
turtle.pathfind(Point.above(topPoint))
turtle.set({
movementStrategy = 'goto',
digPolicy = 'blacklist',
})
end
if turtle then
turtles[member.id] = turtle
if turtle then
turtles[member.id] = turtle
turtle.reset()
turtle.set({
attackPolicy = 'attack',
digPolicy = 'blacklist',
blacklist = {
'turtle',
'chest',
'shulker',
},
movementStrategy = 'goto',
point = point,
})
turtle.select(1)
turtle.reset()
turtle.set({
attackPolicy = 'attack',
digPolicy = 'blacklist',
blacklist = {
'turtle',
'chest',
'shulker',
},
movementStrategy = 'goto',
point = point,
})
turtle.select(1)
repeat
local pt = getNextPoint(turtle)
if pt then
member.status = 'digging'
repeat
local pt = getNextPoint(turtle)
if pt then
member.status = 'digging'
if blockTypes[pt.key] == true then
if turtle.moveAgainst(pt) then
local index = turtle.selectOpenSlot()
if turtle.digAt(pt, pt.name) then
local slot = turtle.getSlot(index)
if slot.count > 0 then
blockTypes[pt.key] = slot.key
if slot.key ~= pt.key then
blockTypes[slot.key] = true
end
end
end
end
turtle.select(1)
else
turtle.digAt(pt, pt.name)
end
if blockTypes[pt.key] == true then
if turtle.moveAgainst(pt) then
local index = turtle.selectOpenSlot()
if turtle.digAt(pt, pt.name) then
local slot = turtle.getSlot(index)
if slot.count > 0 then
blockTypes[pt.key] = slot.key
if slot.key ~= pt.key then
blockTypes[slot.key] = true
end
end
end
end
turtle.select(1)
else
turtle.digAt(pt, pt.name)
end
if turtle.getItemCount(15) > 0 then
member.status = 'ejecting trash'
emptySlots(blockTypes)
turtle.condense()
if turtle.getItemCount(15) > 0 then
member.status = 'dropping off'
if not chestPoint then
member.abort = true
member.status = 'full'
else
dropOff()
end
end
turtle.select(1)
end
else
member.status = 'waiting'
os.sleep(1)
end
if member.fuel < 100 then
member.status = 'out of fuel'
break
end
until member.abort
end
if turtle.getItemCount(15) > 0 then
member.status = 'ejecting trash'
emptySlots(blockTypes)
turtle.condense()
if turtle.getItemCount(15) > 0 then
member.status = 'dropping off'
if not chestPoint then
member.abort = true
member.status = 'full'
else
dropOff()
end
end
turtle.select(1)
end
else
member.status = 'waiting'
os.sleep(1)
end
if member.fuel < 100 then
member.status = 'out of fuel'
break
end
until member.abort
end
emptySlots(blockTypes)
emptySlots(blockTypes)
if chestPoint then
dropOff()
while not turtle.go(Point.above(spt)) do
os.sleep(.5)
end
--if turtle.selectSlotWithQuantity(0) then
--turtle.set({ digPolicy = 'dig' })
--end
while not turtle.go(spt) do
os.sleep(.5)
end
else
turtle.gotoY(spt.y)
while not turtle.go(spt) do
os.sleep(.5)
end
end
end)
if chestPoint then
dropOff()
while not turtle.go(Point.above(spt)) do
os.sleep(.5)
end
--if turtle.selectSlotWithQuantity(0) then
--turtle.set({ digPolicy = 'dig' })
--end
while not turtle.go(spt) do
os.sleep(.5)
end
else
turtle.gotoY(spt.y)
while not turtle.go(spt) do
os.sleep(.5)
end
end
end)
turtles[member.id] = nil
member.status = m
member.active = false
if socket then
socket:close()
end
end)
turtles[member.id] = nil
member.status = m
member.active = false
if socket then
socket:close()
end
end)
end
local function drawContainer(pos)
if canvas3d then
canvas3d.clear()
if canvas3d then
canvas3d.clear()
local function addBox(b)
canvas3d.addBox(
b.x - offset.x + .25,
b.y - offset.y + .25 ,
b.z - offset.z + .25 ,
.5, .5, .5).setDepthTested(false)
end
if box and box.ex then
addBox({ x = box.x, y = box.y, z = box.z })
addBox({ x = box.x, y = box.y, z = box.ez })
addBox({ x = box.ex, y = box.y, z = box.z })
addBox({ x = box.ex, y = box.y, z = box.ez })
addBox({ x = box.x, y = box.ey, z = box.z })
addBox({ x = box.x, y = box.ey, z = box.ez })
addBox({ x = box.ex, y = box.ey, z = box.z })
addBox({ x = box.ex, y = box.ey, z = box.ez })
elseif box then
canvas3d.recenter({ -(pos.x % 1), -(pos.y % 1), -(pos.z % 1) })
addBox(box)
end
end
local function addBox(b)
canvas3d.addBox(
b.x - offset.x + .25,
b.y - offset.y + .25 ,
b.z - offset.z + .25 ,
.5, .5, .5).setDepthTested(false)
end
if box and box.ex then
addBox({ x = box.x, y = box.y, z = box.z })
addBox({ x = box.x, y = box.y, z = box.ez })
addBox({ x = box.ex, y = box.y, z = box.z })
addBox({ x = box.ex, y = box.y, z = box.ez })
addBox({ x = box.x, y = box.ey, z = box.z })
addBox({ x = box.x, y = box.ey, z = box.ez })
addBox({ x = box.ex, y = box.ey, z = box.z })
addBox({ x = box.ex, y = box.ey, z = box.ez })
elseif box then
canvas3d.recenter({ -(pos.x % 1), -(pos.y % 1), -(pos.z % 1) })
addBox(box)
end
end
end
local pauseResume = {
{ text = 'Pause', event = 'pause' },
{ text = 'Resume', event = 'resume' },
{ text = 'Pause', event = 'pause' },
{ text = 'Resume', event = 'resume' },
}
local containerText = {
[[Set a corner to contain mining area]],
[[Set ending corner]],
[[Set again to clear]],
[[Set a corner to contain mining area]],
[[Set ending corner]],
[[Set again to clear]],
}
local containTab = UI.Tab {
tabTitle = 'Contain',
button = UI.Button {
x = 2, y = 2,
text = 'Set corner',
event = 'contain'
},
textArea = UI.TextArea {
x = 2, y = 4,
value = containerText[1],
},
tabTitle = 'Contain',
button = UI.Button {
x = 2, y = 2,
text = 'Set corner',
event = 'contain'
},
textArea = UI.TextArea {
x = 2, y = 4,
value = containerText[1],
},
}
local blocksTab = UI.Tab {
tabTitle = 'Blocks',
grid = UI.ScrollingGrid {
y = 1,
columns = {
{ heading = 'Count', key = 'count', width = 6, align = 'right' },
{ heading = 'Name', key = 'displayName' },
},
sortColumn = 'displayName',
},
tabTitle = 'Blocks',
grid = UI.ScrollingGrid {
y = 1,
columns = {
{ heading = 'Count', key = 'count', width = 6, align = 'right' },
{ heading = 'Name', key = 'displayName' },
},
sortColumn = 'displayName',
},
}
local turtlesTab = UI.Tab {
tabTitle = 'Turtles',
grid = UI.ScrollingGrid {
y = 1,
values = pool,
columns = {
{ heading = 'ID', key = 'id', width = 5, },
{ heading = ' Fuel', key = 'fuel', width = 5, align = 'right' },
{ heading = ' Dist', key = 'distance', width = 5, align = 'right' },
{ heading = 'Status', key = 'status' },
},
sortColumn = 'label',
},
tabTitle = 'Turtles',
grid = UI.ScrollingGrid {
y = 1,
values = pool,
columns = {
{ heading = 'ID', key = 'id', width = 5, },
{ heading = ' Fuel', key = 'fuel', width = 5, align = 'right' },
{ heading = ' Dist', key = 'distance', width = 5, align = 'right' },
{ heading = 'Status', key = 'status' },
},
sortColumn = 'label',
},
}
local page = UI.Page {
@@ -354,264 +354,264 @@ local page = UI.Page {
{ text = 'Abort', event = 'abort' },
pauseResume[1],
},
},
tabs = UI.Tabs {
y = 2, ey = -2,
[1] = blocksTab,
[2] = turtlesTab,
[3] = containTab,
},
info = UI.Window {
y = -1,
backgroundColor = colors.blue,
}
},
tabs = UI.Tabs {
y = 2, ey = -2,
[1] = blocksTab,
[2] = turtlesTab,
[3] = containTab,
},
info = UI.Window {
y = -1,
backgroundColor = colors.blue,
}
}
function page.info:draw()
self:clear()
self:write(2, 1, 'Turtles: ' .. Util.size(turtles))
if not chestPoint then
self:write(16, 1, 'No chest')
end
self:write(28, 1, 'Queue: ' .. Util.size(queue))
self:clear()
self:write(2, 1, 'Turtles: ' .. Util.size(turtles))
if not chestPoint then
self:write(16, 1, 'No chest')
end
self:write(28, 1, 'Queue: ' .. Util.size(queue))
end
function turtlesTab.grid:getDisplayValues(row)
row = Util.shallowCopy(row)
row.distance = row.distance and Util.round(row.distance, 1)
row.fuel = row.fuel and row.fuel > 0 and Util.toBytes(row.fuel) or ''
return row
row.distance = row.distance and Util.round(row.distance, 1)
row.fuel = row.fuel and row.fuel > 0 and Util.toBytes(row.fuel) or ''
return row
end
function page:scan()
local gpt = GPS.getPoint()
if not gpt then
return
end
local rawBlocks = scanner:scan()
local candidates = { }
local gpt = GPS.getPoint()
if not gpt then
return
end
local rawBlocks = scanner:scan()
local candidates = { }
self.totals = Util.reduce(rawBlocks,
function(acc, b)
b.key = table.concat({ b.name, b.metadata }, ':')
local entry = acc[b.key]
if not entry then
b.displayName = itemDB:getName(b.key)
b.count = 1
acc[b.key] = b
self.totals = Util.reduce(rawBlocks,
function(acc, b)
b.key = table.concat({ b.name, b.metadata }, ':')
local entry = acc[b.key]
if not entry then
b.displayName = itemDB:getName(b.key)
b.count = 1
acc[b.key] = b
else
entry.count = entry.count + 1
end
entry.count = entry.count + 1
end
if b.name == 'computercraft:turtle_advanced' or
b.name == 'computercraft:turtle_expanded' or
b.name == 'computercraft:turtle' then
table.insert(candidates, b)
end
if b.name == 'computercraft:turtle_advanced' or
b.name == 'computercraft:turtle_expanded' or
b.name == 'computercraft:turtle' then
table.insert(candidates, b)
end
if b.name == 'minecraft:chest' or b.name:find('shulker') then
chestPoint = b
end
if b.name == 'minecraft:chest' or b.name:find('shulker') then
chestPoint = b
end
-- add relevant blocks to queue
b.x = gpt.x + b.x
b.y = gpt.y + b.y
b.z = gpt.z + b.z
b.pkey = table.concat({ b.x, b.y, b.z }, ':')
if blockTypes[b.key] and inBox(b) then
if not Util.any(turtles, function(t)
return t.pt and t.pt.pkey == b.pkey
end) then
queue[b.pkey] = b
end
else
queue[b.pkey] = nil
end
return acc
-- add relevant blocks to queue
b.x = gpt.x + b.x
b.y = gpt.y + b.y
b.z = gpt.z + b.z
b.pkey = table.concat({ b.x, b.y, b.z }, ':')
if blockTypes[b.key] and inBox(b) then
if not Util.any(turtles, function(t)
return t.pt and t.pt.pkey == b.pkey
end) then
queue[b.pkey] = b
end
else
queue[b.pkey] = nil
end
return acc
end,
{ })
{ })
for _, b in pairs(candidates) do
local v = scanner.getBlockMeta(b.x - gpt.x, b.y - gpt.y, b.z - gpt.z)
if v and v.computer then
local member = pool[v.computer.id]
if not member then
member = {
id = v.computer.id,
label = v.computer.label,
}
pool[v.computer.id] = member
end
for _, b in pairs(candidates) do
local v = scanner.getBlockMeta(b.x - gpt.x, b.y - gpt.y, b.z - gpt.z)
if v and v.computer then
local member = pool[v.computer.id]
if not member then
member = {
id = v.computer.id,
label = v.computer.label,
}
pool[v.computer.id] = member
end
member.fuel = v.turtle.fuel
member.distance = 0
member.fuel = v.turtle.fuel
member.distance = 0
if not v.computer.isOn then
member.status = 'Powered off'
elseif v.turtle.fuel < 100 and not member.active then
member.status = 'Not enough fuel'
elseif not member.active and not member.abort then
local pt = Point.copy(b)
pt.heading = Point.facings[v.state.facing].heading
run(member, pt)
end
end
end
if not v.computer.isOn then
member.status = 'Powered off'
elseif v.turtle.fuel < 100 and not member.active then
member.status = 'Not enough fuel'
elseif not member.active and not member.abort then
local pt = Point.copy(b)
pt.heading = Point.facings[v.state.facing].heading
run(member, pt)
end
end
end
end
function blocksTab.grid:getDisplayValues(row)
row = Util.shallowCopy(row)
row.count = Util.toBytes(row.count) .. ' '
return row
return row
end
function blocksTab.grid:getRowTextColor(row, selected)
return blockTypes[row.key] and
colors.yellow or
UI.Grid.getRowTextColor(self, row, selected)
return blockTypes[row.key] and
colors.yellow or
UI.Grid.getRowTextColor(self, row, selected)
end
function blocksTab:eventHandler(event)
if event.type == 'grid_select' then
local key = event.selected.key
if blockTypes[key] then
for k,v in pairs(queue) do
if v.key == key then
queue[k] = nil
end
end
blockTypes[key] = nil
else
blockTypes[key] = true
end
self.grid:draw()
end
local key = event.selected.key
if blockTypes[key] then
for k,v in pairs(queue) do
if v.key == key then
queue[k] = nil
end
end
blockTypes[key] = nil
else
blockTypes[key] = true
end
self.grid:draw()
end
end
function page:eventHandler(event)
if event.type == 'scan' then
blocksTab.grid:setValues(self.totals)
blocksTab.grid:draw()
self.tabs:selectTab(blocksTab)
if event.type == 'scan' then
blocksTab.grid:setValues(self.totals)
blocksTab.grid:draw()
self.tabs:selectTab(blocksTab)
elseif event.type == 'pause' then
paused = true
Util.merge(event.button, pauseResume[2])
event.button:draw()
elseif event.type == 'pause' then
paused = true
Util.merge(event.button, pauseResume[2])
event.button:draw()
elseif event.type == 'resume' then
paused = false
Util.merge(event.button, pauseResume[1])
event.button:draw()
elseif event.type == 'resume' then
paused = false
Util.merge(event.button, pauseResume[1])
event.button:draw()
elseif event.type == 'contain' then
local pt = { gps.locate() }
local pos = {
x = pt[1],
y = pt[2],
z = pt[3],
}
elseif event.type == 'contain' then
local pt = { gps.locate() }
local pos = {
x = pt[1],
y = pt[2],
z = pt[3],
}
if not box then
offset = {
x = math.floor(pos.x),
y = math.floor(pos.y),
z = math.floor(pos.z),
}
box = {
x = math.floor(pos.x),
y = math.floor(pos.y) - 1,
z = math.floor(pos.z),
}
containTab.textArea.value = containerText[2]
elseif not box.ex then
box.ex = math.floor(pos.x)
box.ey = math.floor(pos.y) - 1
box.ez = math.floor(pos.z)
box = Point.normalizeBox(box)
containTab.textArea.value = containerText[3]
else
box = nil
containTab.textArea.value = containerText[1]
end
if not box then
offset = {
x = math.floor(pos.x),
y = math.floor(pos.y),
z = math.floor(pos.z),
}
box = {
x = math.floor(pos.x),
y = math.floor(pos.y) - 1,
z = math.floor(pos.z),
}
containTab.textArea.value = containerText[2]
elseif not box.ex then
box.ex = math.floor(pos.x)
box.ey = math.floor(pos.y) - 1
box.ez = math.floor(pos.z)
box = Point.normalizeBox(box)
containTab.textArea.value = containerText[3]
else
box = nil
containTab.textArea.value = containerText[1]
end
containTab.textArea:draw()
drawContainer(pos)
containTab.textArea:draw()
drawContainer(pos)
elseif event.type == 'abort' then
for _, v in pairs(pool) do
v.abort = true
v.status = 'aborting'
end
spt = Point.above(locate())
abort = true
end
elseif event.type == 'abort' then
for _, v in pairs(pool) do
v.abort = true
v.status = 'aborting'
end
spt = Point.above(locate())
abort = true
end
UI.Page.eventHandler(self, event)
end
Event.onInterval(5, function()
if not abort and not paused then
if not abort and not paused then
--local meta = scanner.getMetaOwner()
--if meta.isSneaking then
page:scan()
-- Sound.play('entity.bobber.throw', .6)
--end
end
--local meta = scanner.getMetaOwner()
--if meta.isSneaking then
page:scan()
-- Sound.play('entity.bobber.throw', .6)
--end
end
end)
Event.onInterval(1, function()
for id,v in pairs(network) do
if v.fuel then
if pool[id] then
pool[id].fuel = v.fuel
pool[id].distance = v.distance
end
end
end
for id,v in pairs(network) do
if v.fuel then
if pool[id] then
pool[id].fuel = v.fuel
pool[id].distance = v.distance
end
end
end
if abort and Util.size(turtles) == 0 then
Event.exitPullEvents()
end
if abort and Util.size(turtles) == 0 then
Event.exitPullEvents()
end
if turtlesTab.enabled then
turtlesTab.grid:update()
turtlesTab.grid:draw()
end
if turtlesTab.enabled then
turtlesTab.grid:update()
turtlesTab.grid:draw()
end
page.info:draw()
page.info:sync()
page.info:draw()
page.info:sync()
if canvas then
canvas.turtles.setText(tostring(Util.size(turtles)))
canvas.queue.setText(tostring(Util.size(queue)))
end
if canvas then
canvas.turtles.setText(tostring(Util.size(turtles)))
canvas.queue.setText(tostring(Util.size(queue)))
end
end)
Event.onTimeout(.1, function()
page:scan()
blocksTab.grid:setValues(page.totals)
blocksTab.grid:draw()
page:sync()
page:scan()
blocksTab.grid:setValues(page.totals)
blocksTab.grid:draw()
page:sync()
end)
UI:setPage(page)
--[[
Event.onTerminate(function()
spt = Point.above(locate())
for _, v in pairs(pool) do
v.status = 'aborting'
v.abort = true
end
abort = true
spt = Point.above(locate())
for _, v in pairs(pool) do
v.status = 'aborting'
v.abort = true
end
abort = true
end)
]]
Event.pullEvents()
if canvas then
canvas3d.clear()
canvas.group.remove()
canvas3d.clear()
canvas.group.remove()
end