begin moving turtle specific code from opus into turtle package

This commit is contained in:
kepler155c@gmail.com
2019-02-18 02:57:01 -05:00
parent 20bb3d831f
commit 3564dff4fd
21 changed files with 331 additions and 134 deletions

6
turtle/.package Normal file
View File

@@ -0,0 +1,6 @@
{
title = 'Turtle programs and apis',
repository = 'kepler155c/opus-apps/{{OPUS_BRANCH}}/turtle',
description = [[Support programs and apis for turtles]],
licence = 'MIT',
}

42
turtle/apis/home.lua Normal file
View File

@@ -0,0 +1,42 @@
local Config = require('config')
local GPS = require('gps')
local turtle = _G.turtle
local Home = { }
function Home.go()
local config = { }
Config.load('gps', config)
if config.home then
if turtle.enableGPS() then
return turtle.pathfind(config.home)
end
end
end
function Home.set()
local config = { }
Config.load('gps', config)
local pt = GPS.getPoint()
if pt then
local originalHeading = turtle.point.heading
local heading = GPS.getHeading()
if heading then
local turns = (turtle.point.heading - originalHeading) % 4
pt.heading = (heading - turns) % 4
config.home = pt
Config.update('gps', config)
pt = GPS.getPoint()
pt.heading = heading
turtle.setPoint(pt, true)
turtle.go(config.home)
return config.home
end
end
end
return Home

72
turtle/apis/swarm.lua Normal file
View File

@@ -0,0 +1,72 @@
local Event = require('event')
local Socket = require('socket')
local Util = require('util')
local function hijackTurtle(remoteId)
local socket, msg = Socket.connect(remoteId, 188)
if not socket then
error(msg)
end
socket:write('turtle')
local methods = socket:read()
local hijack = { }
for _,method in pairs(methods) do
hijack[method] = function(...)
socket:write({ fn = method, args = { ... } })
local resp = socket:read()
if not resp then
error('timed out: ' .. method)
end
return table.unpack(resp)
end
end
return hijack, socket
end
local class = require('class')
local Swarm = class()
function Swarm:init(args)
self.pool = { }
Util.merge(self, args)
end
function Swarm:add(id, args)
local member = Util.shallowCopy(args)
member.id = id
self.pool[id] = member
end
function Swarm:run(fn)
for id, member in pairs(self.pool) do
Event.addRoutine(function()
local s, m = pcall(function()
member.turtle, member.socket = hijackTurtle(id)
fn(member)
end)
if member.socket then
member.socket:close()
member.socket = nil
end
self.pool[id] = nil
self:onRemove(member, s, m)
end)
end
end
function Swarm:shutdown()
for _, member in pairs(self.pool) do
if member.socket then
member.socket:close()
member.socket = nil
end
end
end
function Swarm:onRemove(member, success, msg)
print('removed from pool: ' .. member.id)
if not success then
_G.printError(msg)
end
end
return Swarm

43
turtle/autorun/gps.lua Normal file
View File

@@ -0,0 +1,43 @@
local modem = _G.device.wireless_modem
local turtle = _G.turtle
if turtle and modem then
local s, m = turtle.run(function()
_G.requireInjector(_ENV)
local Config = require('config')
local config = {
destructive = false,
}
Config.load('gps', config)
if config.home then
local s = turtle.enableGPS(2)
if not s then
s = turtle.enableGPS(2)
end
if not s and config.destructive then
turtle.set({ attackPolicy = 'attack', digPolicy = 'turtleSafe' })
s = turtle.enableGPS(2)
end
if not s then
error('Unable to get GPS position')
end
if config.destructive then
turtle.set({ attackPolicy = 'attack', digPolicy = 'turtleSafe' })
end
if not turtle.pathfind(config.home) then
error('Failed to return home')
end
end
end)
if not s and m then
error(m)
end
end

View File

@@ -0,0 +1,31 @@
local Util = require('util')
local device = _G.device
local fs = _G.fs
local turtle = _G.turtle
if turtle then
fs.mount('sys/apps/system/turtle.lua', 'linkfs', 'packages/turtle/system/turtle.lua')
function turtle.scan(blocks)
local pt = turtle.point
local scanner = device['plethora:scanner'] or error('Scanner not equipped')
if not blocks then
return Util.each(scanner:scan(), function(b)
b.x = pt.x + b.x
b.y = pt.y + b.y
b.z = pt.z + b.z
end)
end
return Util.filter(scanner:scan(), function(b)
if blocks[b.name] then
b.x = pt.x + b.x
b.y = pt.y + b.y
b.z = pt.z + b.z
return true
end
end)
end
end

8
turtle/etc/apps.db Normal file
View File

@@ -0,0 +1,8 @@
{
[ "47b3d6dc1170faf4ae496fff3db374817bf32e2f" ] = {
title = "Refuel",
category = "Apps",
run = "lavaRefuel.lua",
requires = 'turtle',
},
}

66
turtle/lavaRefuel.lua Normal file
View File

@@ -0,0 +1,66 @@
local Point = require('point')
local device = _G.device
local turtle = _G.turtle
local MAX_FUEL = turtle.getFuelLimit()
if turtle.getFuelLevel() == 0 then
error('Need some fuel to begin')
end
if not turtle.has('minecraft:bucket') then
error('bucket required')
end
local scanner = device['plethora:scanner'] or
turtle.equip('right', 'plethora:module:2') and device['plethora:scanner'] or
error('Plethora scanner required')
if not turtle.select('minecraft:bucket') then
error('bucket required')
end
local s, m = turtle.run(function()
turtle.setMovementStrategy('goto')
local facing = scanner.getBlockMeta(0, 0, 0).state.facing
turtle.setPoint({ x = 0, y = 0, z = 0, heading = Point.facings[facing].heading })
local blocks = scanner.scan()
local first, last = blocks[#blocks].y, blocks[1].y
for y = first, last, -1 do
if turtle.getFuelLevel() >= (MAX_FUEL - 1000) then
print('I am full')
break
end
local t = { }
for _,v in pairs(blocks) do
if v.y == y then
if (v.name == 'minecraft:lava' and v.metadata == 0) or
(v.name == 'minecraft:flowing_lava' and v.metadata == 0) then
table.insert(t, v)
end
end
end
Point.eachClosest(turtle.point, t, function(b)
if turtle.getFuelLevel() >= (MAX_FUEL - 1000) then
return true
end
turtle.placeDownAt(b)
turtle.refuel()
print(turtle.getFuelLevel())
end)
end
end)
turtle.gotoY(0)
turtle.go({ x = 0, y = 0, z = 0 })
turtle.unequip('right')
print('Fuel: ' .. turtle.getFuelLevel())
if not s and m then
error(m)
end

106
turtle/obsidian.lua Normal file
View File

@@ -0,0 +1,106 @@
local Point = require('point')
local Util = require('util')
local os = _G.os
local turtle = _G.turtle
local checkedNodes, nodes
local function addNode(node)
for i = 0, 3 do
local hi = turtle.getHeadingInfo(i)
local testNode = { x = node.x + hi.xd, z = node.z + hi.zd }
local key = table.concat({ testNode.x, testNode.z }, ':')
if not checkedNodes[key] then
nodes[key] = testNode
end
end
end
local function findObsidian()
repeat
local node = { x = turtle.point.x, z = turtle.point.z }
local key = table.concat({ node.x, node.z }, ':')
checkedNodes[key] = true
nodes[key] = nil
local _,b = turtle.inspectDown()
if b and (b.name == 'minecraft:lava' or b.name == 'minecraft:flowing_lava') then
if turtle.select('minecraft:water_bucket') then
while true do
if turtle.up() then
break
end
print('stuck')
end
turtle.placeDown()
os.sleep(2)
turtle.placeDown()
turtle.down()
turtle.select(1)
_, b = turtle.inspectDown()
end
end
if turtle.getItemCount(16) > 0 then
print('Inventory full')
print('Enter to continue...')
_G.read()
end
if b and b.name == 'minecraft:obsidian' then
turtle.digDown()
addNode(node)
else
turtle.digDown()
end
print(string.format('%d nodes remaining', Util.size(nodes)))
if Util.size(nodes) == 0 then
break
end
node = Point.closest(turtle.point, nodes)
if not turtle.go(node) then
break
end
until turtle.isAborted()
end
turtle.run(function()
turtle.reset()
turtle.set({ digPolicy = 'dig' })
local s, m = pcall(function()
repeat
checkedNodes = { }
nodes = { }
local _,b = turtle.inspectDown()
if not b or b.name ~= 'minecraft:obsidian' then
break
end
findObsidian()
if not turtle.select('minecraft:water_bucket') then
break
end
turtle.go({ x = 0, z = 0 })
turtle.placeDown()
os.sleep(2)
turtle.placeDown()
turtle.down()
turtle.select(1)
until turtle.isAborted()
end)
if not s and m then
error(m)
end
turtle.go({ x = 0, y = 0, z = 0, heading = 0 })
end)

63
turtle/system/turtle.lua Normal file
View File

@@ -0,0 +1,63 @@
local Config = require('config')
local UI = require('ui')
local fs = _G.fs
local turtle = _G.turtle
if turtle then
local Home = require('turtle.home')
local values = { }
Config.load('gps', values.home and { values.home } or { })
local gpsTab = UI.Tab {
tabTitle = 'GPS',
labelText = UI.Text {
x = 3, y = 2,
value = 'On restart, return to this location'
},
grid = UI.Grid {
x = 3, ex = -3, y = 4,
height = 2,
values = values,
inactive = true,
columns = {
{ heading = 'x', key = 'x' },
{ heading = 'y', key = 'y' },
{ heading = 'z', key = 'z' },
},
},
button1 = UI.Button {
x = 3, y = 7,
text = 'Set home',
event = 'gps_set',
},
button2 = UI.Button {
ex = -3, y = 7, width = 7,
text = 'Clear',
event = 'gps_clear',
},
}
function gpsTab:eventHandler(event)
if event.type == 'gps_set' then
self:emit({ type = 'info_message', message = 'Determining location' })
self:sync()
if Home.set() then
Config.load('gps', values)
self.grid:setValues(values.home and { values.home } or { })
self.grid:draw()
self:emit({ type = 'success_message', message = 'Location set' })
else
self:emit({ type = 'error_message', message = 'Unable to determine location' })
end
return true
elseif event.type == 'gps_clear' then
fs.delete('usr/config/gps')
self.grid:setValues({ })
self.grid:draw()
return true
end
end
return gpsTab
end

93
turtle/t.lua Normal file
View File

@@ -0,0 +1,93 @@
local turtle = _G.turtle
local function doCommand(command, moves)
local function format(value)
if type(value) == 'boolean' then
if value then return 'true' end
return 'false'
end
if type(value) ~= 'table' then
return value
end
local str
for k,v in pairs(value) do
if not str then
str = '{ '
else
str = str .. ', '
end
str = str .. k .. '=' .. tostring(v)
end
if str then
str = str .. ' }'
else
str = '{ }'
end
return str
end
local function runCommand(fn, arg)
local r = { fn(arg) }
if r[2] then
print(format(r[1]) .. ': ' .. format(r[2]))
elseif r[1] then
print(format(r[1]))
end
return r[1]
end
local cmds = {
[ 's' ] = turtle.select,
[ 'rf' ] = turtle.refuel,
[ 'gh' ] = function() turtle.pathfind({ x = 0, y = 0, z = 0, heading = 0}) end,
}
local repCmds = {
[ 'u' ] = turtle.up,
[ 'd' ] = turtle.down,
[ 'f' ] = turtle.forward,
[ 'r' ] = turtle.turnRight,
[ 'l' ] = turtle.turnLeft,
[ 'ta' ] = turtle.turnAround,
[ 'el' ] = turtle.equipLeft,
[ 'er' ] = turtle.equipRight,
[ 'DD' ] = turtle.digDown,
[ 'DU' ] = turtle.digUp,
[ 'D' ] = turtle.dig,
[ 'p' ] = turtle.place,
[ 'pu' ] = turtle.placeUp,
[ 'pd' ] = turtle.placeDown,
[ 'b' ] = turtle.back,
[ 'gfl' ] = turtle.getFuelLevel,
[ 'gp' ] = turtle.getPoint,
[ 'R' ] = function() turtle.setPoint({x = 0, y = 0, z = 0, heading = 0}) return turtle.point end
}
if cmds[command] then
runCommand(cmds[command], moves)
elseif repCmds[command] then
for _ = 1, moves do
if not runCommand(repCmds[command]) then
break
end
end
end
end
local args = {...}
if #args > 0 then
doCommand(args[1], args[2] or 1)
else
print('Enter command (q to quit):')
while true do
local cmd = _G.read()
if cmd == 'q' then break
end
args = { }
cmd:gsub('%w+', function(w) table.insert(args, w) end)
doCommand(args[1], args[2] or 1)
end
end