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

@@ -142,7 +142,7 @@ Builder:substituteBlocks(Util.throttle())
local cn = neural.canvas3d().create()
local pos = neural.getMetaOwner().withinBlock
cn.recenter({-(pos.x + .5), -(pos.y + 2) + .5, -(pos.z + .5) })
cn.recenter({-pos.x + .5, -(pos.y + 2) + .5, -pos.z + .5 })
for i = 1, #Builder.schematic.blocks do
local b = Builder.schematic:getComputedBlock(i)

View File

@@ -15,14 +15,20 @@ local gpt = GPS.getPoint() or error('GPS not found')
local pts, blocks
local page = UI.Page {
menuBar = UI.MenuBar {
buttons = {
{ text = 'Range', event = 'range' },
{ text = 'Stop', event = 'stop' },
},
mode = UI.Chooser {
x = 13, y = -1,
x = -16,
choices = {
{ name = 'No breaking', value = 'digNone' },
{ name = 'Destructive', value = 'turtleSafe' },
},
value = 'digNone',
},
},
grid = UI.ScrollingGrid {
y = 2, ey = -2,
columns = {
@@ -34,6 +40,32 @@ local page = UI.Page {
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)
@@ -80,7 +112,7 @@ local function follow(member)
local turtle = member.turtle
turtle.reset()
turtle.set({
digPolicy = page.mode.value,
digPolicy = page.menuBar.mode.value,
status = 'Following',
})
@@ -140,6 +172,31 @@ function page:eventHandler(event)
member.snmp:write({ type = 'scriptEx', args = script })
end
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

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

32
core/apis/proxy.lua Normal file
View File

@@ -0,0 +1,32 @@
local Socket = require('socket')
local Proxy = { }
function Proxy.create(remoteId, uri)
local socket, msg = Socket.connect(remoteId, 188)
if not socket then
error(msg)
end
socket.co = coroutine.running()
socket:write(uri)
local methods = socket:read(2) or error('Timed out')
local hijack = { }
for _,method in pairs(methods) do
hijack[method] = function(...)
socket:write({ method, ... })
local resp = socket:read()
if not resp then
error('timed out: ' .. method)
end
return table.unpack(resp)
end
end
return hijack, socket
end
return Proxy

View File

@@ -1,7 +1,7 @@
local class = require('class')
local Event = require('event')
local Map = require('map')
local Proxy = require('proxy')
local Proxy = require('core.proxy')
local Swarm = class()
function Swarm:init(args)

View File

@@ -18,12 +18,12 @@ local Runners = {
}
Equipper.equipLeft('minecraft:diamond_sword')
local scanner = Equipper.equipRight('plethora:module:2', 'plethora:scanner')
local scanner = Equipper.equipRight('plethora:scanner')
local facing = scanner.getBlockMeta(0, 0, 0).state.facing
turtle.point.heading = Point.facings[facing].heading
local sensor = Equipper.equipRight('plethora:module:3', 'plethora:sensor')
local sensor = Equipper.equipRight('plethora:sensor')
turtle.setMovementStrategy('goto')
turtle.set({ attackPolicy = 'attack' })
@@ -32,9 +32,9 @@ local function findChests()
if chest then
return { chest }
end
Equipper.equipRight('plethora:module:2', 'plethora:scanner')
Equipper.equipRight('plethora:scanner')
local chests = scanner.scan()
Equipper.equipRight('plethora:module:3', 'plethora:sensor')
Equipper.equipRight('plethora:sensor')
Util.filterInplace(chests, function(b)
if b.name == 'minecraft:chest' or

View File

@@ -17,7 +17,7 @@ local FUEL = Util.transpose {
'minecraft:blaze_rod:0',
}
local scanner = Equipper.equipRight('plethora:module:2', 'plethora:scanner')
local scanner = Equipper.equipRight('plethora:scanner')
local crops = Util.readTable(CONFIG_FILE) or {
['minecraft:wheat'] =
@@ -105,9 +105,12 @@ local function scan()
if b.action == 'bump' then
return b.y == 0
end
return b.action == 'plant' and
b.metadata == crops[b.name].mature and
b.y == -1
if b.action == 'plant' and b.y == -1 then
if not b.metadata then -- minecraft 1.10
b = scanner.getBlockMeta(b.x, b.y, b.z)
end
return b.metadata == crops[b.name].mature
end
end)
local harvestCount = 0
@@ -186,7 +189,7 @@ local function harvest(blocks)
elseif b.action == 'bump' then
if turtle.faceAgainst(b) then
Equipper.equipRight('plethora:module:3', 'plethora:sensor')
Equipper.equipRight('plethora:sensor')
os.sleep(.5)
-- search the ground for the dropped cactus
local sensed = peripheral.call('right', 'sense')
@@ -218,7 +221,7 @@ local function harvest(blocks)
end
end
end)
Equipper.equipRight('plethora:module:2', 'plethora:scanner')
Equipper.equipRight('plethora:scanner')
end
local s, m = turtle.run(function()

View File

@@ -9,8 +9,9 @@ Requirements
* Standard Modem
* Block Scanner
* Entity Sensor
* Crafting Table
* Furnace
* Vanilla Chest
* Sapling
* GPS
Setup
@@ -19,18 +20,20 @@ Setup
> package install farms
> reboot
The turtle will need some fuel initially.
The tree farm fits exactly in one chunk. It's best to have a mostly level ground around the center of the farming area as the turtle will only collect saplings that have fallen to the same level as the turtle.
To align the turtle perfectly in one chunk, position the turtle 8 blocks diagonally from the bottom left corner.
Place a sapling directly in front of the turtle and place all the required items into the inventory.
Place all the required items into the inventory.
To start the program, run:
> superTreefarm
A startup file is created automatically the first time the program is run (usr/autorun/superTreefarm.lua).
If the turtle does not get any saplings from the initial tree, place down another sapling in front of the turtle.
If the turtle does not get any saplings from the initial tree, another sapling in the turtle.
Tips
====

View File

@@ -30,7 +30,7 @@ local ANIMALS = {
local animal = ANIMALS[config.animal]
Equipper.equipLeft('minecraft:diamond_sword')
local sensor = Equipper.equipRight('plethora:module:3', 'plethora:sensor')
local sensor = Equipper.equipRight('plethora:sensor')
local chest = Adapter({ side = 'bottom', direction = 'up' }) or error('missing chest')
@@ -49,9 +49,15 @@ local function getAnimalCount()
Util.filterInplace(blocks, function(v)
if v.name == config.animal then
if v.y > -.5 then grown = grown + 1 end
if v.y < -.5 then babies = babies + 1 end
return v.y > -.5
local entity = sensor.getMetaByID(v.id)
if entity then
if entity.isChild then
babies = babies + 1
else
grown = grown + 1
end
return not entity.isChild
end
end
end)
@@ -69,7 +75,7 @@ local function butcher()
turtle.turnRight()
turtle.attack()
end
Equipper.equipRight('plethora:module:3', 'plethora:sensor')
Equipper.equipRight('plethora:sensor')
turtle.eachFilledSlot(function(slot)
if not retain[slot.name] then

View File

@@ -11,7 +11,7 @@ local STARTUP_FILE = 'usr/autorun/spawner.lua'
local mobTypes = { }
Equipper.equipLeft('minecraft:diamond_sword')
local scanner = Equipper.equipRight('plethora:module:2', 'plethora:scanner')
local scanner = Equipper.equipRight('plethora:scanner')
turtle.reset()
local facing = scanner.getBlockMeta(0, 0, 0).state.facing
@@ -28,7 +28,7 @@ Util.filterInplace(data, function(b)
end)
local chest = Point.closest(spawner, data) or error('missing drop off chest')
local sensor = Equipper.equipRight('plethora:module:3', 'plethora:sensor')
local sensor = Equipper.equipRight('plethora:sensor')
if not fs.exists(STARTUP_FILE) then
Util.writeFile(STARTUP_FILE,

View File

@@ -10,14 +10,16 @@ local turtle = _G.turtle
local STARTUP_FILE = 'usr/autorun/superTreefarm.lua'
local FUEL_BASE = 0
local FUEL_DIRE = FUEL_BASE + 10
local FUEL_GOOD = FUEL_BASE + 2000
local FUEL_DIRE = 10
local FUEL_GOOD = 1000
local MIN_CHARCOAL = 24
local MIN_SAPLINGS = 32
local MAX_SAPLINGS = 48
local RADIUS_X = 2
local RADIUS_Z = 3
local GRID = {
TL = { x = 8, y = 0, z = -7 },
TR = { x = 8, y = 0, z = 8 },
@@ -27,88 +29,30 @@ local GRID = {
local HOME_PT = { x = 0, y = 0, z = 0, heading = 0 }
local DIG_BLACKLIST = {
[ 'minecraft:furnace' ] = true,
[ 'minecraft:lit_furnace' ] = true,
[ 'minecraft:chest' ] = true,
}
local APPLE = 'minecraft:apple:0'
local CHARCOAL = 'minecraft:coal:1'
local CHEST = 'minecraft:chest:0'
local COBBLESTONE = 'minecraft:cobblestone:0'
local CRAFTING_TABLE = 'minecraft:crafting_table:0'
local PICKAXE = 'minecraft:diamond_pickaxe'
local DIRT = 'minecraft:dirt:0'
local PICKAXE = 'minecraft:diamond_pickaxe'
local FURNACE = 'minecraft:furnace:0'
local MODEM = 'computercraft:peripheral:1'
local LOG = 'minecraft:log'
local LOG2 = 'minecraft:log2'
local OAK_LOG = 'minecraft:log:0'
local OAK_PLANK = 'minecraft:planks:0'
local OAK_SAPLING = 'minecraft:sapling:0'
local SAPLING = 'minecraft:sapling'
local SCANNER = 'plethora:module:2'
local SENSOR = 'plethora:module:3'
local STICK = 'minecraft:stick:0'
local STONE = 'minecraft:stone:0'
local TORCH = 'minecraft:torch:0'
local ALL_SAPLINGS = { }
local retain = Util.transpose {
PICKAXE,
CHARCOAL,
SAPLING,
SCANNER,
SENSOR,
}
local state = Util.readTable('usr/config/superTreefarm') or {
trees = {
{ x = 1, y = 0, z = 0 }
}
}
local state = Util.readTable('usr/config/superTreefarm') or { }
local clock = os.clock()
local function equip(side, item, rawName)
-- is it already equipped on the correct side?
local equipped = peripheral.getType(side)
if equipped == item then
return true
end
-- is it equipped on the opposite side?
-- will not work for non-peripheral items :(
local osides = { left = 'right', right = 'left' }
if peripheral.getType(osides[side]) == item then
if not turtle.selectSlotWithQuantity(0) then
error('No slots available')
end
turtle.equip(osides[side])
elseif not turtle.has(rawName or item) then
-- don't have the item - unequip that side to see if it's the correct item
if not turtle.selectSlotWithQuantity(0) then
error('No slots available')
end
turtle.equip(side)
end
-- TODO: if the non-peripheral item was equipped on the other side, then this will not work
if not turtle.has(rawName or item) then
error('Missing ' .. (rawName or item))
end
if not turtle.equip(side, rawName or item) then
error('Unable to equip ' .. (rawName or item))
end
turtle.select(1)
end
local function inspect(fn)
local s, item = fn()
if s and item then
return item.name .. ':' .. item.metadata
end
return 'minecraft:air:0'
end
local function setState(key, value)
state[key] = value
Util.writeTable('usr/config/superTreefarm', state)
@@ -117,129 +61,17 @@ end
local function refuel()
if turtle.getFuelLevel() < FUEL_GOOD then
local charcoal = turtle.getItemCount(CHARCOAL)
if charcoal > 1 then
turtle.refuel(CHARCOAL, math.min(charcoal - 1, MIN_CHARCOAL / 2))
--if charcoal > 1 then
turtle.refuel(CHARCOAL, math.min(charcoal, MIN_CHARCOAL / 2))
print('fuel: ' .. turtle.getFuelLevel())
--end
end
end
return true
end
local function safePlaceBlock(item)
if turtle.placeUp(item) then
return true
end
local s, m = turtle.inspectUp()
if s and not DIG_BLACKLIST[m.name] then
turtle.digUp()
return turtle.placeUp(item)
end
turtle.forward()
return turtle.placeUp(item)
end
local function craftItem(item, qty)
local success, msg
if safePlaceBlock(CHEST) then
os.sleep(.2) -- needed for minecraft 1.12
Util.print('Crafting %d %s', (qty or 1), item)
success, msg = turtle.craftItem(item, qty or 1, {
side = 'top',
direction = 'down',
})
repeat until not turtle.suckUp()
if not success then
print(msg)
end
turtle.digUp()
end
return success
end
local function emptyFurnace()
if state.cooking then
print('Emptying furnace')
turtle.suckDownAt(state.furnace)
turtle.suckForwardAt(state.furnace)
turtle.suckUpAt(state.furnace)
setState('cooking')
end
end
local function cook(item, count, result, fuel, fuelCount)
emptyFurnace()
setState('cooking', true)
fuel = fuel or CHARCOAL
fuelCount = fuelCount or math.ceil(count / 8)
Util.print('Making %d %s', count, result)
turtle.dropForwardAt(state.furnace, fuel, fuelCount)
turtle.dropDownAt(state.furnace, item, count)
count = count + turtle.getItemCount(result)
turtle.select(1)
turtle.pathfind(Point.below(state.furnace))
local lastSuck = os.clock()
repeat
os.sleep(1)
if turtle.suckUp() then
lastSuck = os.clock()
end
if os.clock() - lastSuck > 10 then
-- sponge bug
Util.print('Timed out waiting for furnace')
return
end
until turtle.getItemCount(result) >= count
setState('cooking')
end
local function makeSingleCharcoal()
local slots = turtle.getSummedInventory()
if not state.furnace or
slots[CHARCOAL] or
not slots[OAK_LOG] or
slots[OAK_LOG].count < 2 then
return true
end
turtle.faceAgainst(state.furnace)
if craftItem(OAK_PLANK) then
cook(OAK_LOG, 1, CHARCOAL, OAK_PLANK, 1)
turtle.refuel(OAK_PLANK)
end
return true
end
local function makeCharcoal()
local slots = turtle.getSummedInventory()
if not state.furnace or
not slots[CHARCOAL] or
slots[CHARCOAL].count >= MIN_CHARCOAL then
return true
end
local function getLogSlot()
local maxslot = { count = 0 }
for k,slot in pairs(slots) do
@@ -252,126 +84,104 @@ local function makeCharcoal()
return maxslot
end
repeat
if turtle.pathfind(Point.above(state.furnace)) then
pcall(function()
local f = peripheral.wrap('bottom')
local inv = f.list()
if inv[3] and
(not slots[CHARCOAL] or
slots[CHARCOAL].count < MIN_CHARCOAL) then
f.pushItems('up', 3, 24)
end
if turtle.has(CHARCOAL) and turtle.getFuelLevel() > 100 then
local count = inv[2] and inv[2].count or 0
if count < 8 then
f.pullItems('up', turtle.getSlot(CHARCOAL).index, 8-count, 2)
end
else
slots = turtle.getSummedInventory()
local charcoal = slots[CHARCOAL].count
local slot = getLogSlot(slots)
if slot.count > 0 then
local s = turtle.getSlot(slot.key)
f.pullItems('up', s.index, 1, 2)
end
end
if slot.count < 8 then
local count = inv[1] and inv[1].count or 0
if count < 32 then
for key, slot in pairs(turtle.getSummedInventory()) do
if string.match(key, 'minecraft:log') then
if turtle.dropDown(key, 32-count) then
count = count + slot.count
if count >= 32 then
break
end
local toCook = math.min(charcoal, math.floor(slot.count / 8))
toCook = math.min(toCook, math.floor((MIN_CHARCOAL + 8 - charcoal) / 8))
toCook = toCook * 8
cook(slot.key, toCook, CHARCOAL)
until charcoal + toCook >= MIN_CHARCOAL
end
end
end
end
end)
end
return true
end
local function getCobblestone(count)
local slots = turtle.getSummedInventory()
if not slots[COBBLESTONE] or slots[COBBLESTONE].count < count then
print('Collecting cobblestone')
slots[COBBLESTONE] = true
slots[DIRT] = true
local pt = Point.copy(GRID.BR)
pt.x = GRID.BR.x + 2
pt.z = GRID.BR.z - 2
turtle.pathfind(pt)
repeat
turtle.select(1)
turtle.digDown()
turtle.down()
for _ = 1, 4 do
if inspect(turtle.inspect) == STONE then
turtle.dig()
end
turtle.turnRight()
end
for item in pairs(turtle.getSummedInventory()) do
if not slots[item] then
turtle.drop(item)
end
end
until turtle.getItemCount(COBBLESTONE) >= count
turtle.go(pt)
turtle.placeDown(DIRT)
turtle.drop(DIRT)
end
end
local function createFurnace()
if not state.furnace then
if turtle.getFuelLevel() < FUEL_BASE + 100 then
return true -- try again later
end
print('Adding a furnace')
if not turtle.has(FURNACE) then
getCobblestone(8)
error('Turtle must have a furnace')
end
if turtle.has(FURNACE) or craftItem(FURNACE) then
turtle.drop(COBBLESTONE)
local furnacePt = { x = GRID.BL.x + 1, y = 1, z = GRID.BL.z + 1 }
turtle.placeAt(furnacePt, FURNACE)
setState('furnace', furnacePt)
print('Adding a furnace')
local pt = Point.below(HOME_PT)
if not turtle.placeDownAt(pt, FURNACE) then
error('Error placing furnace')
end
setState('furnace', pt)
end
turtle.addWorldBlock(state.furnace)
end
local function createChests()
if state.chest then
return
if not state.chest and turtle.getFuelLevel() > 1 then
if not turtle.has(CHEST) then
error('Turtle must have a chest')
end
if turtle.getFuelLevel() > FUEL_GOOD and
turtle.canCraft(CHEST, 4, turtle.getSummedInventory()) then
print('Adding storage')
if turtle.has(CHEST, 2) or craftItem(CHEST, 2) then
local pt = Point.copy(GRID.BL)
pt.x = pt.x + 1
pt.y = pt.y - 1
local pt = Point.below(HOME_PT)
pt.x = pt.x - 1
pt.z = pt.z + 1
turtle.digDownAt(pt)
turtle.placeDown(CHEST)
pt.z = pt.z + 1
turtle.digDownAt(pt)
turtle.placeDown(CHEST)
setState('chest', Util.shallowCopy(pt))
turtle.drop(DIRT)
turtle.refuel(OAK_PLANK)
if not turtle.placeDownAt(pt, CHEST) then
error('Error placing chest')
end
setState('chest', pt)
turtle.dropDown(DIRT)
end
return true
end
local function dropOffItems()
local function getSaplings()
local slots = turtle.getSummedInventory()
local saplings = { }
if state.chest then
for _, slot in pairs(slots) do
if slot.name == SAPLING then
table.insert(saplings, slot)
end
end
if #saplings == 0 then
table.insert(saplings, { name = OAK_SAPLING, count = 0 })
end
return saplings
end
local function dropOffItems()
local slots = turtle.getSummedInventory()
if state.chest and
@@ -382,24 +192,20 @@ local function dropOffItems()
print('Storing logs')
turtle.pathfind(Point.above(state.chest))
turtle.dropDown(LOG)
turtle.dropDown(LOG2)
for _, sapling in pairs(ALL_SAPLINGS) do
if sapling.count > MAX_SAPLINGS then
turtle.dropDown(sapling.key, sapling.count - MAX_SAPLINGS)
for k,v in pairs(turtle.getInventory()) do
if v.count > 0 and not retain[v.name] and not retain[v.key] then
turtle.select(k)
turtle.dropDown()
end
end
turtle.dropDown(APPLE)
end
end
return true
end
local function eatSaplings()
Util.each(ALL_SAPLINGS, function(sapling)
Util.each(getSaplings(), function(sapling)
if sapling.count > MAX_SAPLINGS then
turtle.refuel(sapling.key, sapling.count - MAX_SAPLINGS)
end
@@ -407,60 +213,11 @@ local function eatSaplings()
return true
end
local function placeTorches()
if state.torches then
return
end
local slots = turtle.getSummedInventory()
if turtle.getFuelLevel() > 100 and
slots[CHARCOAL] and
slots[CHARCOAL].count >= MIN_CHARCOAL and
turtle.canCraft(TORCH, 4, slots) then
print('Placing torches')
if turtle.has(TORCH, 4) or craftItem(TORCH, 4) then
local pts = { }
for x = -4, 4, 8 do
for z = -4, 4, 8 do
table.insert(pts, { x = x, y = 0, z = z })
end
end
turtle.addWorldBlocks(pts)
Point.eachClosest(turtle.point, pts, function(pt)
turtle.placeDownAt(pt, TORCH)
end)
turtle.refuel(STICK)
turtle.refuel(OAK_PLANK)
setState('torches', pts)
end
end
return true
end
local function countSaplings()
local slots = turtle.getSummedInventory()
ALL_SAPLINGS = { }
for _, slot in pairs(slots) do
if slot.name == SAPLING then
table.insert(ALL_SAPLINGS, slot)
end
end
if #ALL_SAPLINGS == 0 then
table.insert(ALL_SAPLINGS, { name = OAK_SAPLING, count = 0 })
end
return true
end
local function randomSapling()
local sapling = ALL_SAPLINGS[math.random(1, #ALL_SAPLINGS)]
local saplings = getSaplings()
local sapling = saplings[math.random(1, #saplings)]
if sapling.count > 0 then
sapling.count = sapling.count - 1
return sapling.key
end
end
@@ -470,10 +227,10 @@ local function makeKey(b)
end
local function findDroppedSaplings()
Equipper.equipLeft(SENSOR, 'plethora:sensor')
local raw = peripheral.call('left', 'sense')
local sensor = Equipper.equipLeft('plethora:sensor')
local raw = sensor.sense()
local sensed = Util.reduce(raw, function(acc, b)
return Util.reduce(raw, function(acc, b)
Point.rotate(b, state.home.heading)
b.x = Util.round(b.x) + turtle.point.x
b.y = math.ceil(b.y) + turtle.point.y
@@ -484,15 +241,13 @@ local function findDroppedSaplings()
end
return acc
end, { })
return sensed
end
local function scan(pt, filter, blocks)
turtle.pathfind(pt)
Equipper.equipLeft(SCANNER, 'plethora:scanner')
local raw = peripheral.call('left', 'scan')
local scanner = Equipper.equipLeft('plethora:scanner')
local raw = scanner.scan()
return Util.reduce(raw, function(acc, b)
if b.y >= 0 then
@@ -509,82 +264,96 @@ local function scan(pt, filter, blocks)
end
local function getPlantLocations(blocks)
countSaplings()
Util.each(state.trees, function(sapling)
for _,sapling in pairs(state.trees) do
local key = makeKey(sapling)
local b = blocks[key]
if b then
if b.name == SAPLING then
blocks[key] = nil
else
b.plant = randomSapling()
end
return
b.plant = true
end
elseif turtle.getFuelLevel() > 100 or sapling.x == 1 and sapling.z == 0 then
b = Util.shallowCopy(sapling)
b.plant = randomSapling()
if b.plant then
b.plant = true
blocks[key] = b
end
end)
end
end
local function desperateRefuel()
local fuels = { CHARCOAL, LOG, LOG2 }
if turtle.getFuelLevel() < FUEL_DIRE then
while true do
for _, fuel in pairs(fuels) do
if turtle.has(fuel) then
turtle.refuel(fuel, 1)
print('fuel: ' .. turtle.getFuelLevel())
turtle.select(1)
break
end
end
if turtle.getFuelLevel() > 0 then
break
end
print('Out of fuel')
print('Add logs or charcoal to turtle')
os.pullEvent('turtle_inventory')
end
end
end
local function fellTrees(blocks)
local function desperateRefuel(min)
if turtle.getFuelLevel() < min then
local logs = turtle.getItemCount(OAK_LOG)
if logs > 0 then
if craftItem(OAK_PLANK, math.min(8, logs * 4)) then
turtle.refuel(OAK_PLANK)
print('fuel: ' .. turtle.getFuelLevel())
end
end
end
end
turtle.select(1)
turtle.setMoveCallback(function() desperateRefuel(FUEL_DIRE) end)
desperateRefuel(FUEL_DIRE)
if turtle.point.y == 0 then
if #state.trees == 1 and turtle.getFuelLevel() == 0 then
turtle.dig()
end
turtle.up()
end
for pt in Point.iterateClosest(turtle.point, blocks) do
-- initial tree
if turtle.getFuelLevel() == 0 then
if not turtle.digAt(pt) then
break
end
desperateRefuel()
end
if pt.y == 0 then
if pt.sapling then
repeat until not turtle.suckDownAt(pt)
else
elseif pt.plant then
local s = randomSapling()
if pt.name and pt.name ~= SAPLING then
turtle.digDownAt(pt)
if pt.plant then
turtle.placeDown(pt.plant)
end
if s then
turtle.placeDownAt(pt, s)
turtle.select(1)
end
end
else
turtle.digAt(pt)
end
os.queueEvent('canvas', {
type = 'canvas_remove',
data = { pt },
})
end
desperateRefuel(FUEL_BASE + 100)
turtle.clearMoveCallback()
turtle.pathfind(HOME_PT)
return true
end
local function fell()
local function filter(b)
return b.y >= 0 and (b.name == LOG or b.name == LOG2 or b.name == SAPLING)
return b.name == LOG or b.name == LOG2 or b.name == SAPLING
end
local fuel = turtle.getFuelLevel()
local sensed = { }
-- determine if we need saplings
if not Util.every(ALL_SAPLINGS, function(sapling)
if not Util.every(getSaplings(), function(sapling)
return sapling.count >= MIN_SAPLINGS
end) then
sensed = findDroppedSaplings()
@@ -592,7 +361,6 @@ local function fell()
-- low scan
local blocks = scan(HOME_PT, filter)
local pt = Util.shallowCopy(HOME_PT)
while Util.any(blocks, function(b) return b.y > pt.y + 6 end) do
-- tree might be above low scan range, do a scan higher up
@@ -607,6 +375,11 @@ local function fell()
getPlantLocations(blocks)
Equipper.equipLeft(PICKAXE)
os.queueEvent('canvas', {
type = 'canvas_update',
data = blocks,
})
if not Util.empty(blocks) then
print('Chopping')
@@ -618,49 +391,27 @@ local function fell()
return true
end
local function moreTrees()
if #state.trees > 1 then
return
end
if not state.chest or turtle.getItemCount(OAK_SAPLING) < 2 then
return true
end
print('Adding more trees')
local singleTree = state.trees[1]
local function setTrees()
if not state.trees then
state.trees = { }
for x = -2, 2, 1 do
for z = -2, 2, 1 do
if x ~= 0 or z ~= 0 then
for x = -RADIUS_X, RADIUS_X, 1 do
for z = -RADIUS_Z, RADIUS_Z, 1 do
if z ~= 0 or x > 0 then
local tree = { x = x, y = 0, z = z }
table.insert(state.trees, tree)
turtle.addWorldBlock(tree)
end
end
end
turtle.digAt(singleTree)
setState('trees', state.trees)
countSaplings()
Point.eachClosest(turtle.point, state.trees, function(pt)
local sapling = randomSapling()
if sapling then
turtle.placeDownAt(pt, sapling)
end
end)
end
local function findHome()
local pt = GPS.getPoint(2) or error('GPS not found')
Equipper.equipLeft(SCANNER, 'plethora:scanner')
local scanner = Equipper.equipLeft('plethora:scanner')
local facing = peripheral.call('left', 'getBlockMeta', 0, 0, 0).state.facing
local facing = scanner.getBlockMeta(0, 0, 0).state.facing
pt.heading = Point.facings[facing].heading
Equipper.equipLeft(PICKAXE)
@@ -670,11 +421,14 @@ local function findHome()
end
-- convert to relative coordinates
turtle.setPoint({
turtle.set({
point = {
x = pt.x - state.home.x,
y = pt.y - state.home.y,
z = pt.z - state.home.z,
heading = pt.heading,
},
reference = state.home,
})
Point.rotate(turtle.point, state.home.heading)
@@ -689,12 +443,6 @@ local function findHome()
ey = 32,
ez = GRID.BR.z,
})
turtle.setPersistent(true)
turtle.addWorldBlocks(state.trees)
if state.torches and type(state.torches) == 'table' then
turtle.addWorldBlocks(state.trees)
end
end
local function returnHome()
@@ -716,19 +464,24 @@ local function updateClock()
return true
end
local function setWorldBlocks()
turtle.setPersistent(true)
turtle.addWorldBlocks(state.trees)
return true
end
local function startupCheck()
Equipper.equipRight(MODEM, 'modem')
Equipper.equipModem('right')
Equipper.equipLeft(PICKAXE)
local slots = turtle.getSummedInventory()
if not slots[CHEST] or not slots[CRAFTING_TABLE] or not slots[SCANNER] or not slots[SENSOR] then
error([[
if not slots[SCANNER] or not slots[SENSOR] then
printError([[
Required:
* chest
* crafting table
* block scanner
* entity sensor]])
error('Missing required item')
end
if not fs.exists(STARTUP_FILE) then
@@ -740,18 +493,15 @@ shell.openForegroundTab('superTreefarm.lua')]])
end
local tasks = {
{ desc = 'Setting trees', fn = setTrees },
{ desc = 'Startup check', fn = startupCheck },
{ desc = 'Finding home', fn = findHome },
{ desc = 'Set world blocks', fn = setWorldBlocks },
{ desc = 'Creating furnace', fn = createFurnace },
{ desc = 'Creating chest', fn = createChests },
{ desc = 'Counting saplings', fn = countSaplings },
{ desc = 'Adding trees', fn = moreTrees },
{ desc = 'Emptying furnace', fn = emptyFurnace },
{ desc = 'Chopping', fn = fell },
{ desc = 'Creating chest', fn = createChests },
{ desc = 'Snacking', fn = eatSaplings },
{ desc = 'Making charcoal', fn = makeSingleCharcoal },
{ desc = 'Making charcoal', fn = makeCharcoal },
--{ desc = 'Placing torches', fn = placeTorches },
{ desc = 'Refueling', fn = refuel },
{ desc = 'Dropping off items', fn = dropOffItems },
{ desc = 'Condensing', fn = turtle.condense },
@@ -759,15 +509,14 @@ local tasks = {
{ desc = 'Sleeping', fn = updateClock },
}
local s, m = turtle.run(function()
turtle.reset()
require('farms.crafting')
--turtle.addFeatures('core.crafting')
turtle.set({
attackPolicy = 'attack',
digPolicy = 'dig',
moveCallback = desperateRefuel,
})
local s, m = pcall(function()
while not turtle.isAborted() do
print('fuel: ' .. turtle.getFuelLevel())
for _,task in ipairs(Util.shallowCopy(tasks)) do
@@ -781,6 +530,8 @@ local s, m = turtle.run(function()
end
end)
if not s then
error(m or 'Failed')
turtle.reset()
if not s and m then
error(m)
end

View File

@@ -3,6 +3,7 @@ local GPS = require('gps')
local Util = require('util')
local args = { ... }
local colors = _G.colors
local fs = _G.fs
local gps = _G.gps
local os = _G.os

View File

@@ -35,6 +35,39 @@ local function makeRecipeKey(item)
return table.concat({ item.name, item.damage or 0, item.nbtHash }, ':')
end
local function convert(ingredient)
return type(ingredient) == 'table' and ingredient or {
key = ingredient,
count = 1,
}
end
local function getCraftingTool(storage, item)
local items = storage:listItems()
for _,v in pairs(items) do
if item.name == v.name and
(not item.damage or item.damage == v.damage) and
(not item.nbtHash or item.nbtHash == v.nbtHash) then
return v
end
end
return item
end
function Craft.ingedients(recipe)
local i = 0
local keys = Util.keys(recipe.ingredients)
return function()
i = i + 1
local a = keys[i]
if a then
return a, convert(recipe.ingredients[a])
end
end
end
function Craft.clearGrid(storage)
local success = true
local tasks = Tasks()
@@ -74,8 +107,9 @@ end
function Craft.sumIngredients(recipe)
-- produces { ['minecraft:planks:0'] = 8 }
local t = { }
for _,item in pairs(recipe.ingredients) do
t[item] = (t[item] or 0) + 1
for _,entry in pairs(recipe.ingredients) do
local item = convert(entry)
t[item.key] = (t[item.key] or 0) + item.count
end
return t
end
@@ -108,12 +142,13 @@ local function machineCraft(recipe, storage, machineName, request, count, item)
if count > 0 then
local xferred = { }
for k,v in pairs(recipe.ingredients) do
local provided = storage:export(machine, k, count, splitKey(v))
local entry = convert(v)
local provided = storage:export(machine, k, count * entry.count, splitKey(entry.key))
xferred[k] = {
key = v,
key = entry.key,
count = provided,
}
if provided ~= count then
if provided ~= count * entry.count then
-- take back out whatever we put in
for k2,v2 in pairs(xferred) do
if v2.count > 0 then
@@ -143,6 +178,9 @@ local function turtleCraft(recipe, storage, request, count)
for k,v in pairs(recipe.ingredients) do
local item = splitKey(v)
if recipe.craftingTools and recipe.craftingTools[v] then
item = getCraftingTool(storage, item)
end
tasks:add(function()
if storage:export(storage.turtleInventory, k, count, item) ~= count then
request.status = 'rescan needed ?'
@@ -185,7 +223,8 @@ local function turtleCraft(recipe, storage, request, count)
end
function Craft.processPending(item, storage)
for key, count in pairs(item.pending) do
for _, key in pairs(Util.keys(item.pending)) do
local count = item.pending[key]
local imported = storage.activity[key]
if imported then
local amount = math.min(imported, count)
@@ -238,7 +277,6 @@ end
function Craft.craftRecipeInternal(recipe, count, storage, origItem, path)
local request = origItem.ingredients[recipe.result]
--[[
if origItem.pending[recipe.result] then
request.status = 'processing'
@@ -425,23 +463,24 @@ function Craft.getCraftableAmount(inRecipe, inCount, items, missing)
local canCraft = 0
for _ = 1, count do
for _,item in pairs(recipe.ingredients) do
local summedItem = summedItems[item] or Craft.getItemCount(items, item)
for _,entry in pairs(recipe.ingredients) do
local item = convert(entry)
local summedItem = summedItems[item.key] or Craft.getItemCount(items, item.key)
local irecipe = findValidRecipe(item, path)
local irecipe = findValidRecipe(item.key, path)
if irecipe and summedItem <= 0 then
local p = Util.shallowCopy(path)
p[irecipe.result] = true
summedItem = summedItem + sumItems(irecipe, summedItems, 1, p)
summedItem = summedItem + sumItems(irecipe, summedItems, item.count, p)
end
if summedItem <= 0 then
if missing and not irecipe then
missing.name = item
missing.name = item.key
end
return canCraft
end
if not recipe.craftingTools or not recipe.craftingTools[item] then
summedItems[item] = summedItem - 1
if not recipe.craftingTools or not recipe.craftingTools[item.key] then
summedItems[item.key] = summedItem - item.count
end
end
canCraft = canCraft + recipe.count

View File

@@ -224,8 +224,8 @@ function Milo:eject(item, count)
total = total + amount
count = count - amount
--Sound.play('ui.button.click')
Sound.play('entity.illusion_illager.death', .3)
Sound.play('ui.button.click')
--Sound.play('entity.illusion_illager.death', .3)
turtle.emptyInventory()
end
return total
@@ -273,6 +273,7 @@ function Milo:learnRecipe()
local tool = Util.shallowCopy(v2)
if tool.maxDamage > 0 then
tool.damage = '*'
v2.damage = '*'
end
--[[

View File

@@ -14,6 +14,7 @@ local recipeTab = UI.Tab {
disableHeader = true,
columns = {
{ heading = 'Slot', key = 'slot', width = 2 },
{ heading = 'Count', key = 'count', width = 2 },
{ heading = 'Key', key = 'key' },
},
sortColumn = 'slot',
@@ -36,10 +37,13 @@ function recipeTab:setItem(item)
local t = { }
if self.recipe then
for k, v in pairs(self.recipe.ingredients) do
for k, v in Craft.ingedients(self.recipe) do
_syslog(k)
_syslog(v)
table.insert(t, {
slot = k,
key = v,
key = v.key,
count = v.count,
})
end
local key = itemDB:splitKey(self.recipe.result)

View File

@@ -111,7 +111,14 @@ function pages.confirmation:validate()
}
for k,v in pairs(inventory) do
if v.count == 1 then
recipe.ingredients[k] = itemDB:makeKey(v)
else
recipe.ingredients[k] = {
key = itemDB:makeKey(v),
count = v.count,
}
end
end
Milo:saveMachineRecipe(recipe, result, machine.name)

View File

@@ -423,7 +423,7 @@ Unlocked Slots : %d of %d (%d%%)
self:draw()
self:sync()
end)
self.handle3 = Event.on('plethora_task', function()
self.handle3 = Event.on({ 'plethora_task', 'task_complete' }, function()
self.tasks = self.tasks + 1
end)
UI.Tab.enable(self)

View File

@@ -317,7 +317,7 @@ local function collectDrops(suckAction)
end
local function scan()
local scanner = Equipper.equipLeft('plethora:module:2', 'plethora:scanner')
local scanner = Equipper.equipLeft('plethora:scanner')
local blocks = scanner.scan()
Equipper.equipLeft('minecraft:diamond_pickaxe')
local throttle = Util.throttle()
@@ -491,7 +491,7 @@ end
-- in plethora code, we can override initialize with a scanner version
turtle.initialize = function()
Equipper.equipRight('computercraft:advanced_modem', 'modem')
Equipper.equipModem('right')
Equipper.equipLeft('minecraft:diamond_pickaxe')
local function verify(item)
@@ -507,7 +507,7 @@ turtle.initialize = function()
--os.sleep(5)
local pt = GPS.getPoint(2) or error('GPS not found')
local scanner = Equipper.equipLeft('plethora:module:2', 'plethora:scanner')
local scanner = Equipper.equipLeft('plethora:scanner')
local facing = scanner.getBlockMeta(0, 0, 0).state.facing
pt.heading = Point.facings[facing].heading
turtle.setPoint(pt, true)

View File

@@ -3,4 +3,7 @@
repository = 'kepler155c/opus-apps/{{OPUS_BRANCH}}/neural',
description = [[ Applications using various plethora modules ]],
licence = 'MIT',
required = {
'core',
},
}

View File

@@ -5,6 +5,7 @@ local Util = require('util')
local device = _G.device
local gps = _G.gps
local multishell = _ENV.multishell
local glasses = device['plethora:glasses']
local scanner = device['plethora:scanner'] or
@@ -14,12 +15,14 @@ local projecting = { }
local function getPoint()
local pt = { gps.locate() }
if pt[1] then
return {
x = pt[1],
y = pt[2],
z = pt[3],
}
end
end
local offset = getPoint()
local canvas = glasses and glasses.canvas3d().create()
@@ -60,7 +63,7 @@ local page = UI.Page {
},
sortColumn = 'name',
accelerators = {
grid_select = 'noop',
grid_select = 'inspect',
},
},
},
@@ -75,12 +78,15 @@ function page:scan()
local entry = itemDB:get(table.concat({ b.name, b.metadata }, ':'))
if not entry then
local meta = scanner.getBlockMeta(b.x, b.y, b.z)
if meta.name == b.name and meta.metadata == b.metadata then
entry = itemDB:add({
name = meta.name,
displayName = meta.displayName,
damage = meta.metadata,
})
end
end
if entry then
b.key = entry.displayName
if acc[b.key] then
acc[b.key].count = acc[b.key].count + 1
@@ -91,6 +97,7 @@ function page:scan()
entry.key = b.key
acc[b.key] = entry
end
end
throttle()
return acc
end,
@@ -121,6 +128,7 @@ function page.detail:show(blocks, entry)
local scanned = scanner.scan()
local pos = getPoint()
if pos and offset then
blocks = Util.reduce(scanned, function(acc, b)
if b.name == t.name and b.metadata == t.damage then
-- track block's world position
@@ -161,6 +169,7 @@ function page.detail:show(blocks, entry)
end
end
end
end
end)
end
return UI.SlideOut.show(self)
@@ -178,7 +187,14 @@ function page:eventHandler(event)
elseif event.type == 'scan' then
self:scan()
elseif event.type == 'grid_select' and event.element == page.grid then
elseif event.type == 'grid_select' and event.element == self.detail.grid then
multishell.openTab({
path = 'sys/apps/Lua.lua',
args = { event.selected },
focused = true,
})
elseif event.type == 'grid_select' and event.element == self.grid then
self.detail:show(self.blocks, self.grid:getSelected())
elseif event.type == 'cancel' then

View File

@@ -18,22 +18,13 @@ local projecting = { }
local offset
local canvas = glasses and intro and glasses.canvas3d().create()
local config = Config.load('Sensor', {
ignore = { }
})
local config = Config.load('Sensor')
local page = UI.Page {
tabs = UI.Tabs {
listing = UI.Tab {
tabTitle = 'Listing',
menuBar = UI.MenuBar {
buttons = {
{ text = 'Ignore', event = 'ignore' },
{ text = 'Details', event = 'detail' },
},
},
grid = UI.ScrollingGrid {
y = 2,
columns = {
{ heading = 'Name', key = 'displayName' },
{ heading = 'X', key = 'x', width = 3, align = 'right' },
@@ -45,14 +36,7 @@ local page = UI.Page {
},
summary = UI.Tab {
tabTitle = 'Summary',
menuBar = UI.MenuBar {
buttons = {
{ text = 'Projector', event = 'project' },
{ text = 'Ignore', event = 'ignore' },
},
},
grid = UI.ScrollingGrid {
y = 2,
columns = {
{ heading = 'Name', key = 'displayName' },
{ heading = 'Count', key = 'count', width = 5, align = 'right' },
@@ -134,13 +118,6 @@ local function project(entities)
end
end
local function ignoreEntity(entity)
if entity then
config.ignore[entity.name] = true
Config.update('Sensor', config)
end
end
function detail:enable(entity)
local function update()
local t = { }
@@ -194,8 +171,6 @@ end
function listing:enable()
self.handler = Event.onInterval(.5, function()
local entities = sensor.sense()
Util.filterInplace(entities, function(e) return not config.ignore[e.name] end)
self.grid:setValues(entities)
self.grid:draw()
self:sync()
@@ -209,14 +184,11 @@ function listing:disable()
end
function listing:eventHandler(event)
if event.type == 'detail' or event.type == 'grid_select' then
if event.type == 'grid_select' then
local selected = self.grid:getSelected()
if selected then
UI:setPage(detail, selected)
end
elseif event.type == 'ignore' then
ignoreEntity(self.grid:getSelected())
end
return UI.Tab.eventHandler(self, event)
@@ -225,7 +197,6 @@ end
function summary:enable()
self.handler = Event.onInterval(.5, function()
local entities = sensor.sense()
Util.filterInplace(entities, function(e) return not config.ignore[e.name] end)
local t = { }
local highlight = { }
@@ -265,10 +236,7 @@ function summary.grid:getRowTextColor(row, selected)
end
function summary:eventHandler(event)
if event.type == 'ignore' then
ignoreEntity(self.grid:getSelected())
elseif event.type == 'project' or event.type == 'grid_select' then
if event.type == 'grid_select' then
local selected = self.grid:getSelected()
if selected then
self.target = selected.name

189
neural/canvasServer.lua Normal file
View File

@@ -0,0 +1,189 @@
local neural = require('neural.interface')
local device = _G.device
local gps = _G.gps
local os = _G.os
local parallel = _G.parallel
neural.assertModules({
'plethora:glasses',
'plethora:introspection',
'plethora:sensor',
})
local function getPoint()
local pt = { gps.locate() }
if pt[1] then
return {
x = pt[1],
y = pt[2],
z = pt[3],
}
end
end
local projecting = { }
local offset = getPoint() or error('GPS not found')
local canvas = neural.canvas3d().create({
-(offset.x % 1),
-(offset.y % 1),
-(offset.z % 1)
})
local function update(scanned)
for _, b in pairs(scanned) do
if not projecting[b.id] then
local box
local x = b.x - math.floor(offset.x)
local y = b.y - math.floor(offset.y)
local z = b.z - math.floor(offset.z)
-- items are centered at the mid-point of the cube
-- boxes are aligned to the top corner - sigh
if b.path then
box = canvas.addBox(x + .4, y + .4, z + .4, .2, .2, .2, 0xa0902080)
elseif b.name then
pcall(function()
box = canvas.addItem({ x + .5, y + .5, z + .5 }, b.name, b.damage or b.metadata, .5)
end)
end
if not box then
box = canvas.addBox(x, y, z, 1, 1, 1, 0x8080ff30)
end
if box then
box.setDepthTested(false)
end
projecting[b.id] = box
end
end
for id, box in pairs(projecting) do
if not scanned[id] then
box.remove()
projecting[id] = nil
end
end
end
local scanned = { }
local dirty
local function processMessage(msg)
if msg.type == 'canvas_clear' then
scanned = { }
projecting = { }
canvas.clear()
elseif msg.type == 'canvas_remove' then
for _, v in pairs(msg.data) do
v.id = table.concat({ v.x, v.y, v.z }, ':')
scanned[v.id] = nil
end
dirty = true
elseif msg.type == 'canvas_update' then
scanned = { }
for _, v in pairs(msg.data) do
v.id = table.concat({ v.x, v.y, v.z }, ':')
scanned[v.id] = v
end
dirty = true
elseif msg.type == 'canvas_barrier' then
for _, v in pairs(msg.data) do
v.id = table.concat({ v.x, v.y, v.z }, ':')
if projecting[v.id] then
projecting[v.id].remove()
projecting[v.id] = nil
end
v.name = 'minecraft:barrier'
v.damage = 0
scanned[v.id] = v
end
dirty = true
elseif msg.type == 'canvas_path' then
for k, v in pairs(scanned or { }) do
if v.path then
scanned[k] = nil
end
end
for _, v in pairs(msg.data) do
v.path = true
v.id = table.concat({ v.x, v.y, v.z }, ':')
scanned[v.id] = v
end
dirty = true
end
end
local function recenter()
while true do
os.sleep(3)
local pos = getPoint()
if pos then
if math.abs(pos.x - offset.x) +
math.abs(pos.y - offset.y) +
math.abs(pos.z - offset.z) > 64 then
for _, box in pairs(projecting) do
box.remove()
end
projecting = { }
offset = pos
canvas.recenter({
-(offset.x % 1),
-(offset.y % 1),
-(offset.z % 1)
})
update(scanned)
end
end
end
end
local function queueListener()
while true do
local _, msg = os.pullEvent('canvas_message')
processMessage(msg)
end
end
local function modemListener()
device.wireless_modem.open(3773)
while true do
local _, _, dport, _, msg = os.pullEvent('modem_message')
if dport == 3773 and type(msg) == 'table' then
processMessage(msg)
end
end
end
local s, m = pcall(function()
parallel.waitForAny(
queueListener,
modemListener,
recenter,
function()
while true do
if dirty then
dirty = false
update(scanned)
end
os.sleep(1)
end
end
)
end)
canvas.clear()
device.wireless_modem.close(3773)
if not s and m then
_G.printError(m)
end

View File

@@ -1,7 +1,7 @@
local GPS = require('gps')
local Util = require('util')
local Point = require('point')
local Proxy = require('proxy')
local Proxy = require('core.proxy')
local os = _G.os

View File

@@ -29,6 +29,9 @@ elseif not modules.scan then
showRequirements('Scanner module')
end
-- size of displayed block
local BLOCK_SIZE = .5
local function getPoint()
local pt = { gps.locate() }
if pt[1] then
@@ -54,7 +57,10 @@ local targets = {
}
local projecting = { }
local offset = getPoint() or showRequirements('GPS')
local canvas = modules.canvas3d().create()
local canvas = modules.canvas3d().create({
-(offset.x % 1) + .5,
-(offset.y % 1) + .5,
-(offset.z % 1) + .5 })
local function update()
while true do
@@ -71,7 +77,10 @@ local function update()
end
projecting = { }
offset = pos
canvas.recenter()
canvas.recenter({
-(offset.x % 1) + .5,
-(offset.y % 1) + .5,
-(offset.z % 1) + .5 })
end
local blocks = { }
@@ -90,20 +99,18 @@ local function update()
if not projecting[b.id] then
projecting[b.id] = b
local target = targets[b.name]
local x = b.x - math.floor(offset.x) + math.floor(pos.x)
local y = b.y - math.floor(offset.y) + math.floor(pos.y)
local z = b.z - math.floor(offset.z) + math.floor(pos.z)
--[[
b.box = canvas.addFrame({
pos.x - offset.x + b.x + -(pos.x % 1),
pos.y - offset.y + b.y + -(pos.y % 1),
pos.z - offset.z + b.z + -(pos.z % 1),
})
b.box = canvas.addFrame({ x, y, z })
b.box.setDepthTested(false)
b.box.addItem({ .25, .25 }, target[1], target[2], 2)
--]]
b.box = canvas.addItem({
pos.x - offset.x + b.x + -(pos.x % 1) + .5,
pos.y - offset.y + b.y + -(pos.y % 1) + .5,
pos.z - offset.z + b.z + -(pos.z % 1) + .5,
}, target[1], target[2], .5)
b.box = canvas.addItem({ x, y, z }, target[1], target[2], BLOCK_SIZE)
b.box.setDepthTested(false)
end
end

View File

@@ -1,10 +1,22 @@
local Config = require('config')
local peripheral = _G.peripheral
local turtle = _G.turtle
local Equipper = { }
local equipmentList = Config.load('equipment', {
[ 'plethora:scanner' ] = 'plethora:module:2',
[ 'plethora:sensor' ] = 'plethora:module:3',
[ 'plethora:laser' ] = 'plethora:module:1',
[ 'plethora:introspection' ] = 'plethora:module:0',
[ 'plethora:kinetic' ] = 'plethora:module:4',
[ 'advanced_modem' ] = 'computercraft:advanced_modem:0',
[ 'standard_modem' ] = 'computercraft:peripheral:1',
})
local SCANNER_EQUIPPED = 'plethora:scanner'
local SCANNER_INV = 'plethora:module:2'
local SCANNER_INV = equipmentList[SCANNER_EQUIPPED] or 'unknown'
local reversed = {
left = 'right',
@@ -68,7 +80,9 @@ function Equipper.unequip(side)
error('No slots available')
end
turtle.equip(side)
if Equipper.equipped then
Equipper.equipped[side] = nil
end
return turtle.getItemDetail(slot)
end
@@ -81,37 +95,53 @@ function Equipper.isEquipped(name)
Equipper.equipped.right == name and 'right'
end
function Equipper.equip(side, invName, equippedName)
-- so convoluted - needs it's own function
function Equipper.equipModem(side)
if peripheral.getType(side) ~= 'modem' then
if peripheral.getType(reversed[side]) then
Equipper.unequip(reversed[side])
end
if turtle.has(equipmentList['advanced_modem']) then
return Equipper.equip(side, equipmentList['advanced_modem'])
end
if turtle.has(equipmentList['standard_modem']) then
return Equipper.equip(side, equipmentList['standard_modem'])
end
error('Missing modem')
end
end
function Equipper.equip(side, item)
if not Equipper.equipped then
getEquipped()
end
-- is it already equipped ?
if matches(Equipper.equipped[side], equippedName or invName) then
if matches(Equipper.equipped[side], item) then
return peripheral.getType(side) and peripheral.wrap(side)
end
-- is it equipped on other side ?
if matches(Equipper.equipped[reversed[side]], equippedName or invName) then
if matches(Equipper.equipped[reversed[side]], item) then
Equipper.unequip(reversed[side])
end
local s, m = turtle.equip(side, invName)
local s, m = turtle.equip(side, equipmentList[item] or item)
if not s then
error(string.format('Unable to equip %s\n%s', (equippedName or invName), m))
error(string.format('Unable to equip %s\n%s', item, m))
end
Equipper.equipped[side] = peripheral.getType(side) or invName
Equipper.equipped[side] = peripheral.getType(side) or item
return peripheral.getType(side) and peripheral.wrap(side)
end
function Equipper.equipLeft(invName, equippedName)
return Equipper.equip('left', invName, equippedName)
function Equipper.equipLeft(item)
return Equipper.equip('left', item)
end
function Equipper.equipRight(invName, equippedName)
return Equipper.equip('right', invName, equippedName)
function Equipper.equipRight(item)
return Equipper.equip('right', item)
end
return Equipper

View File

@@ -15,7 +15,7 @@ if not turtle.has('minecraft:bucket') then
end
local swapSide = peripheral.getType('right') == 'modem' and 'left' or 'right'
local scanner = Equipper.equip(swapSide, 'plethora:module:2', 'plethora:scanner')
local scanner = Equipper.equip(swapSide, 'plethora:scanner')
if not turtle.select('minecraft:bucket') then
error('bucket required')