spaces->tab, equipper improvements, supertreefarm rewrite, follow improvements, sensor cleanup, milo multiple items allowed in recipes, remote canvas access
This commit is contained in:
@@ -142,7 +142,7 @@ Builder:substituteBlocks(Util.throttle())
|
|||||||
local cn = neural.canvas3d().create()
|
local cn = neural.canvas3d().create()
|
||||||
local pos = neural.getMetaOwner().withinBlock
|
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
|
for i = 1, #Builder.schematic.blocks do
|
||||||
local b = Builder.schematic:getComputedBlock(i)
|
local b = Builder.schematic:getComputedBlock(i)
|
||||||
|
|||||||
@@ -15,14 +15,20 @@ local gpt = GPS.getPoint() or error('GPS not found')
|
|||||||
local pts, blocks
|
local pts, blocks
|
||||||
|
|
||||||
local page = UI.Page {
|
local page = UI.Page {
|
||||||
|
menuBar = UI.MenuBar {
|
||||||
|
buttons = {
|
||||||
|
{ text = 'Range', event = 'range' },
|
||||||
|
{ text = 'Stop', event = 'stop' },
|
||||||
|
},
|
||||||
mode = UI.Chooser {
|
mode = UI.Chooser {
|
||||||
x = 13, y = -1,
|
x = -16,
|
||||||
choices = {
|
choices = {
|
||||||
{ name = 'No breaking', value = 'digNone' },
|
{ name = 'No breaking', value = 'digNone' },
|
||||||
{ name = 'Destructive', value = 'turtleSafe' },
|
{ name = 'Destructive', value = 'turtleSafe' },
|
||||||
},
|
},
|
||||||
value = 'digNone',
|
value = 'digNone',
|
||||||
},
|
},
|
||||||
|
},
|
||||||
grid = UI.ScrollingGrid {
|
grid = UI.ScrollingGrid {
|
||||||
y = 2, ey = -2,
|
y = 2, ey = -2,
|
||||||
columns = {
|
columns = {
|
||||||
@@ -34,6 +40,32 @@ local page = UI.Page {
|
|||||||
sortColumn = 'distance',
|
sortColumn = 'distance',
|
||||||
autospace = true,
|
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)
|
function page.grid:getRowTextColor(row, selected)
|
||||||
@@ -80,7 +112,7 @@ local function follow(member)
|
|||||||
local turtle = member.turtle
|
local turtle = member.turtle
|
||||||
turtle.reset()
|
turtle.reset()
|
||||||
turtle.set({
|
turtle.set({
|
||||||
digPolicy = page.mode.value,
|
digPolicy = page.menuBar.mode.value,
|
||||||
status = 'Following',
|
status = 'Following',
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -140,6 +172,31 @@ function page:eventHandler(event)
|
|||||||
member.snmp:write({ type = 'scriptEx', args = script })
|
member.snmp:write({ type = 'scriptEx', args = script })
|
||||||
end
|
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
|
else
|
||||||
return UI.Page.eventHandler(self, event)
|
return UI.Page.eventHandler(self, event)
|
||||||
end
|
end
|
||||||
|
|||||||
45
common/canvasClient.lua
Normal file
45
common/canvasClient.lua
Normal 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
32
core/apis/proxy.lua
Normal 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
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
local class = require('class')
|
local class = require('class')
|
||||||
local Event = require('event')
|
local Event = require('event')
|
||||||
local Map = require('map')
|
local Map = require('map')
|
||||||
local Proxy = require('proxy')
|
local Proxy = require('core.proxy')
|
||||||
|
|
||||||
local Swarm = class()
|
local Swarm = class()
|
||||||
function Swarm:init(args)
|
function Swarm:init(args)
|
||||||
|
|||||||
@@ -18,12 +18,12 @@ local Runners = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Equipper.equipLeft('minecraft:diamond_sword')
|
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
|
local facing = scanner.getBlockMeta(0, 0, 0).state.facing
|
||||||
turtle.point.heading = Point.facings[facing].heading
|
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.setMovementStrategy('goto')
|
||||||
turtle.set({ attackPolicy = 'attack' })
|
turtle.set({ attackPolicy = 'attack' })
|
||||||
@@ -32,9 +32,9 @@ local function findChests()
|
|||||||
if chest then
|
if chest then
|
||||||
return { chest }
|
return { chest }
|
||||||
end
|
end
|
||||||
Equipper.equipRight('plethora:module:2', 'plethora:scanner')
|
Equipper.equipRight('plethora:scanner')
|
||||||
local chests = scanner.scan()
|
local chests = scanner.scan()
|
||||||
Equipper.equipRight('plethora:module:3', 'plethora:sensor')
|
Equipper.equipRight('plethora:sensor')
|
||||||
|
|
||||||
Util.filterInplace(chests, function(b)
|
Util.filterInplace(chests, function(b)
|
||||||
if b.name == 'minecraft:chest' or
|
if b.name == 'minecraft:chest' or
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ local FUEL = Util.transpose {
|
|||||||
'minecraft:blaze_rod:0',
|
'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 {
|
local crops = Util.readTable(CONFIG_FILE) or {
|
||||||
['minecraft:wheat'] =
|
['minecraft:wheat'] =
|
||||||
@@ -105,9 +105,12 @@ local function scan()
|
|||||||
if b.action == 'bump' then
|
if b.action == 'bump' then
|
||||||
return b.y == 0
|
return b.y == 0
|
||||||
end
|
end
|
||||||
return b.action == 'plant' and
|
if b.action == 'plant' and b.y == -1 then
|
||||||
b.metadata == crops[b.name].mature and
|
if not b.metadata then -- minecraft 1.10
|
||||||
b.y == -1
|
b = scanner.getBlockMeta(b.x, b.y, b.z)
|
||||||
|
end
|
||||||
|
return b.metadata == crops[b.name].mature
|
||||||
|
end
|
||||||
end)
|
end)
|
||||||
|
|
||||||
local harvestCount = 0
|
local harvestCount = 0
|
||||||
@@ -186,7 +189,7 @@ local function harvest(blocks)
|
|||||||
|
|
||||||
elseif b.action == 'bump' then
|
elseif b.action == 'bump' then
|
||||||
if turtle.faceAgainst(b) then
|
if turtle.faceAgainst(b) then
|
||||||
Equipper.equipRight('plethora:module:3', 'plethora:sensor')
|
Equipper.equipRight('plethora:sensor')
|
||||||
os.sleep(.5)
|
os.sleep(.5)
|
||||||
-- search the ground for the dropped cactus
|
-- search the ground for the dropped cactus
|
||||||
local sensed = peripheral.call('right', 'sense')
|
local sensed = peripheral.call('right', 'sense')
|
||||||
@@ -218,7 +221,7 @@ local function harvest(blocks)
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
end)
|
end)
|
||||||
Equipper.equipRight('plethora:module:2', 'plethora:scanner')
|
Equipper.equipRight('plethora:scanner')
|
||||||
end
|
end
|
||||||
|
|
||||||
local s, m = turtle.run(function()
|
local s, m = turtle.run(function()
|
||||||
|
|||||||
@@ -9,8 +9,9 @@ Requirements
|
|||||||
* Standard Modem
|
* Standard Modem
|
||||||
* Block Scanner
|
* Block Scanner
|
||||||
* Entity Sensor
|
* Entity Sensor
|
||||||
* Crafting Table
|
* Furnace
|
||||||
* Vanilla Chest
|
* Vanilla Chest
|
||||||
|
* Sapling
|
||||||
* GPS
|
* GPS
|
||||||
|
|
||||||
Setup
|
Setup
|
||||||
@@ -19,18 +20,20 @@ Setup
|
|||||||
> package install farms
|
> package install farms
|
||||||
> reboot
|
> 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.
|
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.
|
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:
|
To start the program, run:
|
||||||
|
|
||||||
> superTreefarm
|
> superTreefarm
|
||||||
A startup file is created automatically the first time the program is run (usr/autorun/superTreefarm.lua).
|
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
|
Tips
|
||||||
====
|
====
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ local ANIMALS = {
|
|||||||
local animal = ANIMALS[config.animal]
|
local animal = ANIMALS[config.animal]
|
||||||
|
|
||||||
Equipper.equipLeft('minecraft:diamond_sword')
|
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')
|
local chest = Adapter({ side = 'bottom', direction = 'up' }) or error('missing chest')
|
||||||
|
|
||||||
@@ -49,9 +49,15 @@ local function getAnimalCount()
|
|||||||
|
|
||||||
Util.filterInplace(blocks, function(v)
|
Util.filterInplace(blocks, function(v)
|
||||||
if v.name == config.animal then
|
if v.name == config.animal then
|
||||||
if v.y > -.5 then grown = grown + 1 end
|
local entity = sensor.getMetaByID(v.id)
|
||||||
if v.y < -.5 then babies = babies + 1 end
|
if entity then
|
||||||
return v.y > -.5
|
if entity.isChild then
|
||||||
|
babies = babies + 1
|
||||||
|
else
|
||||||
|
grown = grown + 1
|
||||||
|
end
|
||||||
|
return not entity.isChild
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end)
|
end)
|
||||||
|
|
||||||
@@ -69,7 +75,7 @@ local function butcher()
|
|||||||
turtle.turnRight()
|
turtle.turnRight()
|
||||||
turtle.attack()
|
turtle.attack()
|
||||||
end
|
end
|
||||||
Equipper.equipRight('plethora:module:3', 'plethora:sensor')
|
Equipper.equipRight('plethora:sensor')
|
||||||
|
|
||||||
turtle.eachFilledSlot(function(slot)
|
turtle.eachFilledSlot(function(slot)
|
||||||
if not retain[slot.name] then
|
if not retain[slot.name] then
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ local STARTUP_FILE = 'usr/autorun/spawner.lua'
|
|||||||
local mobTypes = { }
|
local mobTypes = { }
|
||||||
|
|
||||||
Equipper.equipLeft('minecraft:diamond_sword')
|
Equipper.equipLeft('minecraft:diamond_sword')
|
||||||
local scanner = Equipper.equipRight('plethora:module:2', 'plethora:scanner')
|
local scanner = Equipper.equipRight('plethora:scanner')
|
||||||
|
|
||||||
turtle.reset()
|
turtle.reset()
|
||||||
local facing = scanner.getBlockMeta(0, 0, 0).state.facing
|
local facing = scanner.getBlockMeta(0, 0, 0).state.facing
|
||||||
@@ -28,7 +28,7 @@ Util.filterInplace(data, function(b)
|
|||||||
end)
|
end)
|
||||||
local chest = Point.closest(spawner, data) or error('missing drop off chest')
|
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
|
if not fs.exists(STARTUP_FILE) then
|
||||||
Util.writeFile(STARTUP_FILE,
|
Util.writeFile(STARTUP_FILE,
|
||||||
|
|||||||
@@ -10,14 +10,16 @@ local turtle = _G.turtle
|
|||||||
|
|
||||||
local STARTUP_FILE = 'usr/autorun/superTreefarm.lua'
|
local STARTUP_FILE = 'usr/autorun/superTreefarm.lua'
|
||||||
|
|
||||||
local FUEL_BASE = 0
|
local FUEL_DIRE = 10
|
||||||
local FUEL_DIRE = FUEL_BASE + 10
|
local FUEL_GOOD = 1000
|
||||||
local FUEL_GOOD = FUEL_BASE + 2000
|
|
||||||
|
|
||||||
local MIN_CHARCOAL = 24
|
local MIN_CHARCOAL = 24
|
||||||
local MIN_SAPLINGS = 32
|
local MIN_SAPLINGS = 32
|
||||||
local MAX_SAPLINGS = 48
|
local MAX_SAPLINGS = 48
|
||||||
|
|
||||||
|
local RADIUS_X = 2
|
||||||
|
local RADIUS_Z = 3
|
||||||
|
|
||||||
local GRID = {
|
local GRID = {
|
||||||
TL = { x = 8, y = 0, z = -7 },
|
TL = { x = 8, y = 0, z = -7 },
|
||||||
TR = { x = 8, y = 0, z = 8 },
|
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 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 CHARCOAL = 'minecraft:coal:1'
|
||||||
local CHEST = 'minecraft:chest:0'
|
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 DIRT = 'minecraft:dirt:0'
|
||||||
|
local PICKAXE = 'minecraft:diamond_pickaxe'
|
||||||
local FURNACE = 'minecraft:furnace:0'
|
local FURNACE = 'minecraft:furnace:0'
|
||||||
local MODEM = 'computercraft:peripheral:1'
|
|
||||||
local LOG = 'minecraft:log'
|
local LOG = 'minecraft:log'
|
||||||
local LOG2 = 'minecraft:log2'
|
local LOG2 = 'minecraft:log2'
|
||||||
local OAK_LOG = 'minecraft:log:0'
|
|
||||||
local OAK_PLANK = 'minecraft:planks:0'
|
|
||||||
local OAK_SAPLING = 'minecraft:sapling:0'
|
local OAK_SAPLING = 'minecraft:sapling:0'
|
||||||
local SAPLING = 'minecraft:sapling'
|
local SAPLING = 'minecraft:sapling'
|
||||||
local SCANNER = 'plethora:module:2'
|
local SCANNER = 'plethora:module:2'
|
||||||
local SENSOR = 'plethora:module:3'
|
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,
|
||||||
local state = Util.readTable('usr/config/superTreefarm') or {
|
CHARCOAL,
|
||||||
trees = {
|
SAPLING,
|
||||||
{ x = 1, y = 0, z = 0 }
|
SCANNER,
|
||||||
}
|
SENSOR,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
local state = Util.readTable('usr/config/superTreefarm') or { }
|
||||||
|
|
||||||
local clock = os.clock()
|
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)
|
local function setState(key, value)
|
||||||
state[key] = value
|
state[key] = value
|
||||||
Util.writeTable('usr/config/superTreefarm', state)
|
Util.writeTable('usr/config/superTreefarm', state)
|
||||||
@@ -117,129 +61,17 @@ end
|
|||||||
local function refuel()
|
local function refuel()
|
||||||
if turtle.getFuelLevel() < FUEL_GOOD then
|
if turtle.getFuelLevel() < FUEL_GOOD then
|
||||||
local charcoal = turtle.getItemCount(CHARCOAL)
|
local charcoal = turtle.getItemCount(CHARCOAL)
|
||||||
if charcoal > 1 then
|
--if charcoal > 1 then
|
||||||
turtle.refuel(CHARCOAL, math.min(charcoal - 1, MIN_CHARCOAL / 2))
|
turtle.refuel(CHARCOAL, math.min(charcoal, MIN_CHARCOAL / 2))
|
||||||
print('fuel: ' .. turtle.getFuelLevel())
|
print('fuel: ' .. turtle.getFuelLevel())
|
||||||
|
--end
|
||||||
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
|
return true
|
||||||
end
|
end
|
||||||
|
|
||||||
local function makeCharcoal()
|
local function makeCharcoal()
|
||||||
|
|
||||||
local slots = turtle.getSummedInventory()
|
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 function getLogSlot()
|
||||||
local maxslot = { count = 0 }
|
local maxslot = { count = 0 }
|
||||||
for k,slot in pairs(slots) do
|
for k,slot in pairs(slots) do
|
||||||
@@ -252,126 +84,104 @@ local function makeCharcoal()
|
|||||||
return maxslot
|
return maxslot
|
||||||
end
|
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()
|
slots = turtle.getSummedInventory()
|
||||||
|
|
||||||
local charcoal = slots[CHARCOAL].count
|
|
||||||
local slot = getLogSlot(slots)
|
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
|
break
|
||||||
end
|
end
|
||||||
|
end
|
||||||
local toCook = math.min(charcoal, math.floor(slot.count / 8))
|
end
|
||||||
toCook = math.min(toCook, math.floor((MIN_CHARCOAL + 8 - charcoal) / 8))
|
end
|
||||||
toCook = toCook * 8
|
end
|
||||||
|
end)
|
||||||
cook(slot.key, toCook, CHARCOAL)
|
end
|
||||||
|
|
||||||
until charcoal + toCook >= MIN_CHARCOAL
|
|
||||||
|
|
||||||
return true
|
return true
|
||||||
end
|
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()
|
local function createFurnace()
|
||||||
if not state.furnace then
|
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
|
if not turtle.has(FURNACE) then
|
||||||
getCobblestone(8)
|
error('Turtle must have a furnace')
|
||||||
end
|
end
|
||||||
|
|
||||||
if turtle.has(FURNACE) or craftItem(FURNACE) then
|
print('Adding a furnace')
|
||||||
turtle.drop(COBBLESTONE)
|
local pt = Point.below(HOME_PT)
|
||||||
local furnacePt = { x = GRID.BL.x + 1, y = 1, z = GRID.BL.z + 1 }
|
if not turtle.placeDownAt(pt, FURNACE) then
|
||||||
turtle.placeAt(furnacePt, FURNACE)
|
error('Error placing furnace')
|
||||||
setState('furnace', furnacePt)
|
|
||||||
end
|
end
|
||||||
|
setState('furnace', pt)
|
||||||
end
|
end
|
||||||
turtle.addWorldBlock(state.furnace)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
local function createChests()
|
local function createChests()
|
||||||
if state.chest then
|
if not state.chest and turtle.getFuelLevel() > 1 then
|
||||||
return
|
if not turtle.has(CHEST) then
|
||||||
|
error('Turtle must have a chest')
|
||||||
end
|
end
|
||||||
if turtle.getFuelLevel() > FUEL_GOOD and
|
|
||||||
turtle.canCraft(CHEST, 4, turtle.getSummedInventory()) then
|
|
||||||
|
|
||||||
print('Adding storage')
|
print('Adding storage')
|
||||||
if turtle.has(CHEST, 2) or craftItem(CHEST, 2) then
|
|
||||||
|
|
||||||
local pt = Point.copy(GRID.BL)
|
local pt = Point.below(HOME_PT)
|
||||||
pt.x = pt.x + 1
|
pt.x = pt.x - 1
|
||||||
pt.y = pt.y - 1
|
|
||||||
|
|
||||||
pt.z = pt.z + 1
|
if not turtle.placeDownAt(pt, CHEST) then
|
||||||
|
error('Error placing chest')
|
||||||
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)
|
|
||||||
end
|
end
|
||||||
|
setState('chest', pt)
|
||||||
|
|
||||||
|
turtle.dropDown(DIRT)
|
||||||
end
|
end
|
||||||
return true
|
return true
|
||||||
end
|
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()
|
local slots = turtle.getSummedInventory()
|
||||||
|
|
||||||
if state.chest and
|
if state.chest and
|
||||||
@@ -382,24 +192,20 @@ local function dropOffItems()
|
|||||||
|
|
||||||
print('Storing logs')
|
print('Storing logs')
|
||||||
turtle.pathfind(Point.above(state.chest))
|
turtle.pathfind(Point.above(state.chest))
|
||||||
turtle.dropDown(LOG)
|
|
||||||
turtle.dropDown(LOG2)
|
|
||||||
|
|
||||||
for _, sapling in pairs(ALL_SAPLINGS) do
|
for k,v in pairs(turtle.getInventory()) do
|
||||||
if sapling.count > MAX_SAPLINGS then
|
if v.count > 0 and not retain[v.name] and not retain[v.key] then
|
||||||
turtle.dropDown(sapling.key, sapling.count - MAX_SAPLINGS)
|
turtle.select(k)
|
||||||
|
turtle.dropDown()
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
turtle.dropDown(APPLE)
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
return true
|
return true
|
||||||
end
|
end
|
||||||
|
|
||||||
local function eatSaplings()
|
local function eatSaplings()
|
||||||
Util.each(ALL_SAPLINGS, function(sapling)
|
Util.each(getSaplings(), function(sapling)
|
||||||
if sapling.count > MAX_SAPLINGS then
|
if sapling.count > MAX_SAPLINGS then
|
||||||
turtle.refuel(sapling.key, sapling.count - MAX_SAPLINGS)
|
turtle.refuel(sapling.key, sapling.count - MAX_SAPLINGS)
|
||||||
end
|
end
|
||||||
@@ -407,60 +213,11 @@ local function eatSaplings()
|
|||||||
return true
|
return true
|
||||||
end
|
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 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
|
if sapling.count > 0 then
|
||||||
sapling.count = sapling.count - 1
|
|
||||||
return sapling.key
|
return sapling.key
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -470,10 +227,10 @@ local function makeKey(b)
|
|||||||
end
|
end
|
||||||
|
|
||||||
local function findDroppedSaplings()
|
local function findDroppedSaplings()
|
||||||
Equipper.equipLeft(SENSOR, 'plethora:sensor')
|
local sensor = Equipper.equipLeft('plethora:sensor')
|
||||||
local raw = peripheral.call('left', 'sense')
|
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)
|
Point.rotate(b, state.home.heading)
|
||||||
b.x = Util.round(b.x) + turtle.point.x
|
b.x = Util.round(b.x) + turtle.point.x
|
||||||
b.y = math.ceil(b.y) + turtle.point.y
|
b.y = math.ceil(b.y) + turtle.point.y
|
||||||
@@ -484,15 +241,13 @@ local function findDroppedSaplings()
|
|||||||
end
|
end
|
||||||
return acc
|
return acc
|
||||||
end, { })
|
end, { })
|
||||||
|
|
||||||
return sensed
|
|
||||||
end
|
end
|
||||||
|
|
||||||
local function scan(pt, filter, blocks)
|
local function scan(pt, filter, blocks)
|
||||||
turtle.pathfind(pt)
|
turtle.pathfind(pt)
|
||||||
|
|
||||||
Equipper.equipLeft(SCANNER, 'plethora:scanner')
|
local scanner = Equipper.equipLeft('plethora:scanner')
|
||||||
local raw = peripheral.call('left', 'scan')
|
local raw = scanner.scan()
|
||||||
|
|
||||||
return Util.reduce(raw, function(acc, b)
|
return Util.reduce(raw, function(acc, b)
|
||||||
if b.y >= 0 then
|
if b.y >= 0 then
|
||||||
@@ -509,82 +264,96 @@ local function scan(pt, filter, blocks)
|
|||||||
end
|
end
|
||||||
|
|
||||||
local function getPlantLocations(blocks)
|
local function getPlantLocations(blocks)
|
||||||
countSaplings()
|
for _,sapling in pairs(state.trees) do
|
||||||
|
|
||||||
Util.each(state.trees, function(sapling)
|
|
||||||
local key = makeKey(sapling)
|
local key = makeKey(sapling)
|
||||||
local b = blocks[key]
|
local b = blocks[key]
|
||||||
if b then
|
if b then
|
||||||
if b.name == SAPLING then
|
if b.name == SAPLING then
|
||||||
blocks[key] = nil
|
blocks[key] = nil
|
||||||
else
|
else
|
||||||
b.plant = randomSapling()
|
b.plant = true
|
||||||
end
|
|
||||||
return
|
|
||||||
end
|
end
|
||||||
|
elseif turtle.getFuelLevel() > 100 or sapling.x == 1 and sapling.z == 0 then
|
||||||
b = Util.shallowCopy(sapling)
|
b = Util.shallowCopy(sapling)
|
||||||
b.plant = randomSapling()
|
b.plant = true
|
||||||
if b.plant then
|
|
||||||
blocks[key] = b
|
blocks[key] = b
|
||||||
end
|
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
|
end
|
||||||
|
|
||||||
local function fellTrees(blocks)
|
local function fellTrees(blocks)
|
||||||
local function desperateRefuel(min)
|
turtle.select(1)
|
||||||
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.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
|
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.y == 0 then
|
||||||
if pt.sapling then
|
if pt.sapling then
|
||||||
repeat until not turtle.suckDownAt(pt)
|
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)
|
turtle.digDownAt(pt)
|
||||||
if pt.plant then
|
end
|
||||||
turtle.placeDown(pt.plant)
|
if s then
|
||||||
|
turtle.placeDownAt(pt, s)
|
||||||
turtle.select(1)
|
turtle.select(1)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
turtle.digAt(pt)
|
turtle.digAt(pt)
|
||||||
end
|
end
|
||||||
|
os.queueEvent('canvas', {
|
||||||
|
type = 'canvas_remove',
|
||||||
|
data = { pt },
|
||||||
|
})
|
||||||
end
|
end
|
||||||
|
|
||||||
desperateRefuel(FUEL_BASE + 100)
|
turtle.pathfind(HOME_PT)
|
||||||
turtle.clearMoveCallback()
|
|
||||||
|
|
||||||
return true
|
return true
|
||||||
end
|
end
|
||||||
|
|
||||||
local function fell()
|
local function fell()
|
||||||
local function filter(b)
|
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
|
end
|
||||||
|
|
||||||
local fuel = turtle.getFuelLevel()
|
local fuel = turtle.getFuelLevel()
|
||||||
local sensed = { }
|
local sensed = { }
|
||||||
|
|
||||||
-- determine if we need saplings
|
-- 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
|
return sapling.count >= MIN_SAPLINGS
|
||||||
end) then
|
end) then
|
||||||
sensed = findDroppedSaplings()
|
sensed = findDroppedSaplings()
|
||||||
@@ -592,7 +361,6 @@ local function fell()
|
|||||||
|
|
||||||
-- low scan
|
-- low scan
|
||||||
local blocks = scan(HOME_PT, filter)
|
local blocks = scan(HOME_PT, filter)
|
||||||
|
|
||||||
local pt = Util.shallowCopy(HOME_PT)
|
local pt = Util.shallowCopy(HOME_PT)
|
||||||
while Util.any(blocks, function(b) return b.y > pt.y + 6 end) do
|
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
|
-- tree might be above low scan range, do a scan higher up
|
||||||
@@ -607,6 +375,11 @@ local function fell()
|
|||||||
getPlantLocations(blocks)
|
getPlantLocations(blocks)
|
||||||
|
|
||||||
Equipper.equipLeft(PICKAXE)
|
Equipper.equipLeft(PICKAXE)
|
||||||
|
|
||||||
|
os.queueEvent('canvas', {
|
||||||
|
type = 'canvas_update',
|
||||||
|
data = blocks,
|
||||||
|
})
|
||||||
if not Util.empty(blocks) then
|
if not Util.empty(blocks) then
|
||||||
print('Chopping')
|
print('Chopping')
|
||||||
|
|
||||||
@@ -618,49 +391,27 @@ local function fell()
|
|||||||
return true
|
return true
|
||||||
end
|
end
|
||||||
|
|
||||||
local function moreTrees()
|
local function setTrees()
|
||||||
if #state.trees > 1 then
|
if not state.trees 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]
|
|
||||||
|
|
||||||
state.trees = { }
|
state.trees = { }
|
||||||
for x = -2, 2, 1 do
|
for x = -RADIUS_X, RADIUS_X, 1 do
|
||||||
for z = -2, 2, 1 do
|
for z = -RADIUS_Z, RADIUS_Z, 1 do
|
||||||
if x ~= 0 or z ~= 0 then
|
if z ~= 0 or x > 0 then
|
||||||
local tree = { x = x, y = 0, z = z }
|
local tree = { x = x, y = 0, z = z }
|
||||||
table.insert(state.trees, tree)
|
table.insert(state.trees, tree)
|
||||||
turtle.addWorldBlock(tree)
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
turtle.digAt(singleTree)
|
|
||||||
|
|
||||||
setState('trees', state.trees)
|
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)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
local function findHome()
|
local function findHome()
|
||||||
local pt = GPS.getPoint(2) or error('GPS not found')
|
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
|
pt.heading = Point.facings[facing].heading
|
||||||
|
|
||||||
Equipper.equipLeft(PICKAXE)
|
Equipper.equipLeft(PICKAXE)
|
||||||
@@ -670,11 +421,14 @@ local function findHome()
|
|||||||
end
|
end
|
||||||
|
|
||||||
-- convert to relative coordinates
|
-- convert to relative coordinates
|
||||||
turtle.setPoint({
|
turtle.set({
|
||||||
|
point = {
|
||||||
x = pt.x - state.home.x,
|
x = pt.x - state.home.x,
|
||||||
y = pt.y - state.home.y,
|
y = pt.y - state.home.y,
|
||||||
z = pt.z - state.home.z,
|
z = pt.z - state.home.z,
|
||||||
heading = pt.heading,
|
heading = pt.heading,
|
||||||
|
},
|
||||||
|
reference = state.home,
|
||||||
})
|
})
|
||||||
|
|
||||||
Point.rotate(turtle.point, state.home.heading)
|
Point.rotate(turtle.point, state.home.heading)
|
||||||
@@ -689,12 +443,6 @@ local function findHome()
|
|||||||
ey = 32,
|
ey = 32,
|
||||||
ez = GRID.BR.z,
|
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
|
end
|
||||||
|
|
||||||
local function returnHome()
|
local function returnHome()
|
||||||
@@ -716,19 +464,24 @@ local function updateClock()
|
|||||||
return true
|
return true
|
||||||
end
|
end
|
||||||
|
|
||||||
|
local function setWorldBlocks()
|
||||||
|
turtle.setPersistent(true)
|
||||||
|
turtle.addWorldBlocks(state.trees)
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
|
||||||
local function startupCheck()
|
local function startupCheck()
|
||||||
Equipper.equipRight(MODEM, 'modem')
|
Equipper.equipModem('right')
|
||||||
Equipper.equipLeft(PICKAXE)
|
Equipper.equipLeft(PICKAXE)
|
||||||
|
|
||||||
local slots = turtle.getSummedInventory()
|
local slots = turtle.getSummedInventory()
|
||||||
|
|
||||||
if not slots[CHEST] or not slots[CRAFTING_TABLE] or not slots[SCANNER] or not slots[SENSOR] then
|
if not slots[SCANNER] or not slots[SENSOR] then
|
||||||
error([[
|
printError([[
|
||||||
Required:
|
Required:
|
||||||
* chest
|
|
||||||
* crafting table
|
|
||||||
* block scanner
|
* block scanner
|
||||||
* entity sensor]])
|
* entity sensor]])
|
||||||
|
error('Missing required item')
|
||||||
end
|
end
|
||||||
|
|
||||||
if not fs.exists(STARTUP_FILE) then
|
if not fs.exists(STARTUP_FILE) then
|
||||||
@@ -740,18 +493,15 @@ shell.openForegroundTab('superTreefarm.lua')]])
|
|||||||
end
|
end
|
||||||
|
|
||||||
local tasks = {
|
local tasks = {
|
||||||
|
{ desc = 'Setting trees', fn = setTrees },
|
||||||
{ desc = 'Startup check', fn = startupCheck },
|
{ desc = 'Startup check', fn = startupCheck },
|
||||||
{ desc = 'Finding home', fn = findHome },
|
{ desc = 'Finding home', fn = findHome },
|
||||||
|
{ desc = 'Set world blocks', fn = setWorldBlocks },
|
||||||
{ desc = 'Creating furnace', fn = createFurnace },
|
{ 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 = 'Chopping', fn = fell },
|
||||||
|
{ desc = 'Creating chest', fn = createChests },
|
||||||
{ desc = 'Snacking', fn = eatSaplings },
|
{ desc = 'Snacking', fn = eatSaplings },
|
||||||
{ desc = 'Making charcoal', fn = makeSingleCharcoal },
|
|
||||||
{ desc = 'Making charcoal', fn = makeCharcoal },
|
{ desc = 'Making charcoal', fn = makeCharcoal },
|
||||||
--{ desc = 'Placing torches', fn = placeTorches },
|
|
||||||
{ desc = 'Refueling', fn = refuel },
|
{ desc = 'Refueling', fn = refuel },
|
||||||
{ desc = 'Dropping off items', fn = dropOffItems },
|
{ desc = 'Dropping off items', fn = dropOffItems },
|
||||||
{ desc = 'Condensing', fn = turtle.condense },
|
{ desc = 'Condensing', fn = turtle.condense },
|
||||||
@@ -759,15 +509,14 @@ local tasks = {
|
|||||||
{ desc = 'Sleeping', fn = updateClock },
|
{ desc = 'Sleeping', fn = updateClock },
|
||||||
}
|
}
|
||||||
|
|
||||||
local s, m = turtle.run(function()
|
turtle.reset()
|
||||||
turtle.reset()
|
turtle.set({
|
||||||
require('farms.crafting')
|
|
||||||
--turtle.addFeatures('core.crafting')
|
|
||||||
turtle.set({
|
|
||||||
attackPolicy = 'attack',
|
attackPolicy = 'attack',
|
||||||
digPolicy = 'dig',
|
digPolicy = 'dig',
|
||||||
})
|
moveCallback = desperateRefuel,
|
||||||
|
})
|
||||||
|
|
||||||
|
local s, m = pcall(function()
|
||||||
while not turtle.isAborted() do
|
while not turtle.isAborted() do
|
||||||
print('fuel: ' .. turtle.getFuelLevel())
|
print('fuel: ' .. turtle.getFuelLevel())
|
||||||
for _,task in ipairs(Util.shallowCopy(tasks)) do
|
for _,task in ipairs(Util.shallowCopy(tasks)) do
|
||||||
@@ -781,6 +530,8 @@ local s, m = turtle.run(function()
|
|||||||
end
|
end
|
||||||
end)
|
end)
|
||||||
|
|
||||||
if not s then
|
turtle.reset()
|
||||||
error(m or 'Failed')
|
|
||||||
|
if not s and m then
|
||||||
|
error(m)
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ local GPS = require('gps')
|
|||||||
local Util = require('util')
|
local Util = require('util')
|
||||||
|
|
||||||
local args = { ... }
|
local args = { ... }
|
||||||
|
local colors = _G.colors
|
||||||
local fs = _G.fs
|
local fs = _G.fs
|
||||||
local gps = _G.gps
|
local gps = _G.gps
|
||||||
local os = _G.os
|
local os = _G.os
|
||||||
|
|||||||
@@ -35,6 +35,39 @@ local function makeRecipeKey(item)
|
|||||||
return table.concat({ item.name, item.damage or 0, item.nbtHash }, ':')
|
return table.concat({ item.name, item.damage or 0, item.nbtHash }, ':')
|
||||||
end
|
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)
|
function Craft.clearGrid(storage)
|
||||||
local success = true
|
local success = true
|
||||||
local tasks = Tasks()
|
local tasks = Tasks()
|
||||||
@@ -74,8 +107,9 @@ end
|
|||||||
function Craft.sumIngredients(recipe)
|
function Craft.sumIngredients(recipe)
|
||||||
-- produces { ['minecraft:planks:0'] = 8 }
|
-- produces { ['minecraft:planks:0'] = 8 }
|
||||||
local t = { }
|
local t = { }
|
||||||
for _,item in pairs(recipe.ingredients) do
|
for _,entry in pairs(recipe.ingredients) do
|
||||||
t[item] = (t[item] or 0) + 1
|
local item = convert(entry)
|
||||||
|
t[item.key] = (t[item.key] or 0) + item.count
|
||||||
end
|
end
|
||||||
return t
|
return t
|
||||||
end
|
end
|
||||||
@@ -108,12 +142,13 @@ local function machineCraft(recipe, storage, machineName, request, count, item)
|
|||||||
if count > 0 then
|
if count > 0 then
|
||||||
local xferred = { }
|
local xferred = { }
|
||||||
for k,v in pairs(recipe.ingredients) do
|
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] = {
|
xferred[k] = {
|
||||||
key = v,
|
key = entry.key,
|
||||||
count = provided,
|
count = provided,
|
||||||
}
|
}
|
||||||
if provided ~= count then
|
if provided ~= count * entry.count then
|
||||||
-- take back out whatever we put in
|
-- take back out whatever we put in
|
||||||
for k2,v2 in pairs(xferred) do
|
for k2,v2 in pairs(xferred) do
|
||||||
if v2.count > 0 then
|
if v2.count > 0 then
|
||||||
@@ -143,6 +178,9 @@ local function turtleCraft(recipe, storage, request, count)
|
|||||||
|
|
||||||
for k,v in pairs(recipe.ingredients) do
|
for k,v in pairs(recipe.ingredients) do
|
||||||
local item = splitKey(v)
|
local item = splitKey(v)
|
||||||
|
if recipe.craftingTools and recipe.craftingTools[v] then
|
||||||
|
item = getCraftingTool(storage, item)
|
||||||
|
end
|
||||||
tasks:add(function()
|
tasks:add(function()
|
||||||
if storage:export(storage.turtleInventory, k, count, item) ~= count then
|
if storage:export(storage.turtleInventory, k, count, item) ~= count then
|
||||||
request.status = 'rescan needed ?'
|
request.status = 'rescan needed ?'
|
||||||
@@ -185,7 +223,8 @@ local function turtleCraft(recipe, storage, request, count)
|
|||||||
end
|
end
|
||||||
|
|
||||||
function Craft.processPending(item, storage)
|
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]
|
local imported = storage.activity[key]
|
||||||
if imported then
|
if imported then
|
||||||
local amount = math.min(imported, count)
|
local amount = math.min(imported, count)
|
||||||
@@ -238,7 +277,6 @@ end
|
|||||||
|
|
||||||
function Craft.craftRecipeInternal(recipe, count, storage, origItem, path)
|
function Craft.craftRecipeInternal(recipe, count, storage, origItem, path)
|
||||||
local request = origItem.ingredients[recipe.result]
|
local request = origItem.ingredients[recipe.result]
|
||||||
|
|
||||||
--[[
|
--[[
|
||||||
if origItem.pending[recipe.result] then
|
if origItem.pending[recipe.result] then
|
||||||
request.status = 'processing'
|
request.status = 'processing'
|
||||||
@@ -425,23 +463,24 @@ function Craft.getCraftableAmount(inRecipe, inCount, items, missing)
|
|||||||
local canCraft = 0
|
local canCraft = 0
|
||||||
|
|
||||||
for _ = 1, count do
|
for _ = 1, count do
|
||||||
for _,item in pairs(recipe.ingredients) do
|
for _,entry in pairs(recipe.ingredients) do
|
||||||
local summedItem = summedItems[item] or Craft.getItemCount(items, item)
|
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
|
if irecipe and summedItem <= 0 then
|
||||||
local p = Util.shallowCopy(path)
|
local p = Util.shallowCopy(path)
|
||||||
p[irecipe.result] = true
|
p[irecipe.result] = true
|
||||||
summedItem = summedItem + sumItems(irecipe, summedItems, 1, p)
|
summedItem = summedItem + sumItems(irecipe, summedItems, item.count, p)
|
||||||
end
|
end
|
||||||
if summedItem <= 0 then
|
if summedItem <= 0 then
|
||||||
if missing and not irecipe then
|
if missing and not irecipe then
|
||||||
missing.name = item
|
missing.name = item.key
|
||||||
end
|
end
|
||||||
return canCraft
|
return canCraft
|
||||||
end
|
end
|
||||||
if not recipe.craftingTools or not recipe.craftingTools[item] then
|
if not recipe.craftingTools or not recipe.craftingTools[item.key] then
|
||||||
summedItems[item] = summedItem - 1
|
summedItems[item.key] = summedItem - item.count
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
canCraft = canCraft + recipe.count
|
canCraft = canCraft + recipe.count
|
||||||
|
|||||||
@@ -224,8 +224,8 @@ function Milo:eject(item, count)
|
|||||||
total = total + amount
|
total = total + amount
|
||||||
count = count - amount
|
count = count - amount
|
||||||
|
|
||||||
--Sound.play('ui.button.click')
|
Sound.play('ui.button.click')
|
||||||
Sound.play('entity.illusion_illager.death', .3)
|
--Sound.play('entity.illusion_illager.death', .3)
|
||||||
turtle.emptyInventory()
|
turtle.emptyInventory()
|
||||||
end
|
end
|
||||||
return total
|
return total
|
||||||
@@ -273,6 +273,7 @@ function Milo:learnRecipe()
|
|||||||
local tool = Util.shallowCopy(v2)
|
local tool = Util.shallowCopy(v2)
|
||||||
if tool.maxDamage > 0 then
|
if tool.maxDamage > 0 then
|
||||||
tool.damage = '*'
|
tool.damage = '*'
|
||||||
|
v2.damage = '*'
|
||||||
end
|
end
|
||||||
|
|
||||||
--[[
|
--[[
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ local recipeTab = UI.Tab {
|
|||||||
disableHeader = true,
|
disableHeader = true,
|
||||||
columns = {
|
columns = {
|
||||||
{ heading = 'Slot', key = 'slot', width = 2 },
|
{ heading = 'Slot', key = 'slot', width = 2 },
|
||||||
|
{ heading = 'Count', key = 'count', width = 2 },
|
||||||
{ heading = 'Key', key = 'key' },
|
{ heading = 'Key', key = 'key' },
|
||||||
},
|
},
|
||||||
sortColumn = 'slot',
|
sortColumn = 'slot',
|
||||||
@@ -36,10 +37,13 @@ function recipeTab:setItem(item)
|
|||||||
|
|
||||||
local t = { }
|
local t = { }
|
||||||
if self.recipe then
|
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, {
|
table.insert(t, {
|
||||||
slot = k,
|
slot = k,
|
||||||
key = v,
|
key = v.key,
|
||||||
|
count = v.count,
|
||||||
})
|
})
|
||||||
end
|
end
|
||||||
local key = itemDB:splitKey(self.recipe.result)
|
local key = itemDB:splitKey(self.recipe.result)
|
||||||
|
|||||||
@@ -111,7 +111,14 @@ function pages.confirmation:validate()
|
|||||||
}
|
}
|
||||||
|
|
||||||
for k,v in pairs(inventory) do
|
for k,v in pairs(inventory) do
|
||||||
|
if v.count == 1 then
|
||||||
recipe.ingredients[k] = itemDB:makeKey(v)
|
recipe.ingredients[k] = itemDB:makeKey(v)
|
||||||
|
else
|
||||||
|
recipe.ingredients[k] = {
|
||||||
|
key = itemDB:makeKey(v),
|
||||||
|
count = v.count,
|
||||||
|
}
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
Milo:saveMachineRecipe(recipe, result, machine.name)
|
Milo:saveMachineRecipe(recipe, result, machine.name)
|
||||||
|
|||||||
@@ -423,7 +423,7 @@ Unlocked Slots : %d of %d (%d%%)
|
|||||||
self:draw()
|
self:draw()
|
||||||
self:sync()
|
self:sync()
|
||||||
end)
|
end)
|
||||||
self.handle3 = Event.on('plethora_task', function()
|
self.handle3 = Event.on({ 'plethora_task', 'task_complete' }, function()
|
||||||
self.tasks = self.tasks + 1
|
self.tasks = self.tasks + 1
|
||||||
end)
|
end)
|
||||||
UI.Tab.enable(self)
|
UI.Tab.enable(self)
|
||||||
|
|||||||
@@ -317,7 +317,7 @@ local function collectDrops(suckAction)
|
|||||||
end
|
end
|
||||||
|
|
||||||
local function scan()
|
local function scan()
|
||||||
local scanner = Equipper.equipLeft('plethora:module:2', 'plethora:scanner')
|
local scanner = Equipper.equipLeft('plethora:scanner')
|
||||||
local blocks = scanner.scan()
|
local blocks = scanner.scan()
|
||||||
Equipper.equipLeft('minecraft:diamond_pickaxe')
|
Equipper.equipLeft('minecraft:diamond_pickaxe')
|
||||||
local throttle = Util.throttle()
|
local throttle = Util.throttle()
|
||||||
@@ -491,7 +491,7 @@ end
|
|||||||
|
|
||||||
-- in plethora code, we can override initialize with a scanner version
|
-- in plethora code, we can override initialize with a scanner version
|
||||||
turtle.initialize = function()
|
turtle.initialize = function()
|
||||||
Equipper.equipRight('computercraft:advanced_modem', 'modem')
|
Equipper.equipModem('right')
|
||||||
Equipper.equipLeft('minecraft:diamond_pickaxe')
|
Equipper.equipLeft('minecraft:diamond_pickaxe')
|
||||||
|
|
||||||
local function verify(item)
|
local function verify(item)
|
||||||
@@ -507,7 +507,7 @@ turtle.initialize = function()
|
|||||||
|
|
||||||
--os.sleep(5)
|
--os.sleep(5)
|
||||||
local pt = GPS.getPoint(2) or error('GPS not found')
|
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
|
local facing = scanner.getBlockMeta(0, 0, 0).state.facing
|
||||||
pt.heading = Point.facings[facing].heading
|
pt.heading = Point.facings[facing].heading
|
||||||
turtle.setPoint(pt, true)
|
turtle.setPoint(pt, true)
|
||||||
|
|||||||
@@ -3,4 +3,7 @@
|
|||||||
repository = 'kepler155c/opus-apps/{{OPUS_BRANCH}}/neural',
|
repository = 'kepler155c/opus-apps/{{OPUS_BRANCH}}/neural',
|
||||||
description = [[ Applications using various plethora modules ]],
|
description = [[ Applications using various plethora modules ]],
|
||||||
licence = 'MIT',
|
licence = 'MIT',
|
||||||
|
required = {
|
||||||
|
'core',
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ local Util = require('util')
|
|||||||
|
|
||||||
local device = _G.device
|
local device = _G.device
|
||||||
local gps = _G.gps
|
local gps = _G.gps
|
||||||
|
local multishell = _ENV.multishell
|
||||||
|
|
||||||
local glasses = device['plethora:glasses']
|
local glasses = device['plethora:glasses']
|
||||||
local scanner = device['plethora:scanner'] or
|
local scanner = device['plethora:scanner'] or
|
||||||
@@ -14,11 +15,13 @@ local projecting = { }
|
|||||||
|
|
||||||
local function getPoint()
|
local function getPoint()
|
||||||
local pt = { gps.locate() }
|
local pt = { gps.locate() }
|
||||||
|
if pt[1] then
|
||||||
return {
|
return {
|
||||||
x = pt[1],
|
x = pt[1],
|
||||||
y = pt[2],
|
y = pt[2],
|
||||||
z = pt[3],
|
z = pt[3],
|
||||||
}
|
}
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
local offset = getPoint()
|
local offset = getPoint()
|
||||||
@@ -60,7 +63,7 @@ local page = UI.Page {
|
|||||||
},
|
},
|
||||||
sortColumn = 'name',
|
sortColumn = 'name',
|
||||||
accelerators = {
|
accelerators = {
|
||||||
grid_select = 'noop',
|
grid_select = 'inspect',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -75,12 +78,15 @@ function page:scan()
|
|||||||
local entry = itemDB:get(table.concat({ b.name, b.metadata }, ':'))
|
local entry = itemDB:get(table.concat({ b.name, b.metadata }, ':'))
|
||||||
if not entry then
|
if not entry then
|
||||||
local meta = scanner.getBlockMeta(b.x, b.y, b.z)
|
local meta = scanner.getBlockMeta(b.x, b.y, b.z)
|
||||||
|
if meta.name == b.name and meta.metadata == b.metadata then
|
||||||
entry = itemDB:add({
|
entry = itemDB:add({
|
||||||
name = meta.name,
|
name = meta.name,
|
||||||
displayName = meta.displayName,
|
displayName = meta.displayName,
|
||||||
damage = meta.metadata,
|
damage = meta.metadata,
|
||||||
})
|
})
|
||||||
end
|
end
|
||||||
|
end
|
||||||
|
if entry then
|
||||||
b.key = entry.displayName
|
b.key = entry.displayName
|
||||||
if acc[b.key] then
|
if acc[b.key] then
|
||||||
acc[b.key].count = acc[b.key].count + 1
|
acc[b.key].count = acc[b.key].count + 1
|
||||||
@@ -91,6 +97,7 @@ function page:scan()
|
|||||||
entry.key = b.key
|
entry.key = b.key
|
||||||
acc[b.key] = entry
|
acc[b.key] = entry
|
||||||
end
|
end
|
||||||
|
end
|
||||||
throttle()
|
throttle()
|
||||||
return acc
|
return acc
|
||||||
end,
|
end,
|
||||||
@@ -121,6 +128,7 @@ function page.detail:show(blocks, entry)
|
|||||||
local scanned = scanner.scan()
|
local scanned = scanner.scan()
|
||||||
local pos = getPoint()
|
local pos = getPoint()
|
||||||
|
|
||||||
|
if pos and offset then
|
||||||
blocks = Util.reduce(scanned, function(acc, b)
|
blocks = Util.reduce(scanned, function(acc, b)
|
||||||
if b.name == t.name and b.metadata == t.damage then
|
if b.name == t.name and b.metadata == t.damage then
|
||||||
-- track block's world position
|
-- track block's world position
|
||||||
@@ -161,6 +169,7 @@ function page.detail:show(blocks, entry)
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
end
|
||||||
end)
|
end)
|
||||||
end
|
end
|
||||||
return UI.SlideOut.show(self)
|
return UI.SlideOut.show(self)
|
||||||
@@ -178,7 +187,14 @@ function page:eventHandler(event)
|
|||||||
elseif event.type == 'scan' then
|
elseif event.type == 'scan' then
|
||||||
self:scan()
|
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())
|
self.detail:show(self.blocks, self.grid:getSelected())
|
||||||
|
|
||||||
elseif event.type == 'cancel' then
|
elseif event.type == 'cancel' then
|
||||||
|
|||||||
@@ -18,22 +18,13 @@ local projecting = { }
|
|||||||
local offset
|
local offset
|
||||||
local canvas = glasses and intro and glasses.canvas3d().create()
|
local canvas = glasses and intro and glasses.canvas3d().create()
|
||||||
|
|
||||||
local config = Config.load('Sensor', {
|
local config = Config.load('Sensor')
|
||||||
ignore = { }
|
|
||||||
})
|
|
||||||
|
|
||||||
local page = UI.Page {
|
local page = UI.Page {
|
||||||
tabs = UI.Tabs {
|
tabs = UI.Tabs {
|
||||||
listing = UI.Tab {
|
listing = UI.Tab {
|
||||||
tabTitle = 'Listing',
|
tabTitle = 'Listing',
|
||||||
menuBar = UI.MenuBar {
|
|
||||||
buttons = {
|
|
||||||
{ text = 'Ignore', event = 'ignore' },
|
|
||||||
{ text = 'Details', event = 'detail' },
|
|
||||||
},
|
|
||||||
},
|
|
||||||
grid = UI.ScrollingGrid {
|
grid = UI.ScrollingGrid {
|
||||||
y = 2,
|
|
||||||
columns = {
|
columns = {
|
||||||
{ heading = 'Name', key = 'displayName' },
|
{ heading = 'Name', key = 'displayName' },
|
||||||
{ heading = 'X', key = 'x', width = 3, align = 'right' },
|
{ heading = 'X', key = 'x', width = 3, align = 'right' },
|
||||||
@@ -45,14 +36,7 @@ local page = UI.Page {
|
|||||||
},
|
},
|
||||||
summary = UI.Tab {
|
summary = UI.Tab {
|
||||||
tabTitle = 'Summary',
|
tabTitle = 'Summary',
|
||||||
menuBar = UI.MenuBar {
|
|
||||||
buttons = {
|
|
||||||
{ text = 'Projector', event = 'project' },
|
|
||||||
{ text = 'Ignore', event = 'ignore' },
|
|
||||||
},
|
|
||||||
},
|
|
||||||
grid = UI.ScrollingGrid {
|
grid = UI.ScrollingGrid {
|
||||||
y = 2,
|
|
||||||
columns = {
|
columns = {
|
||||||
{ heading = 'Name', key = 'displayName' },
|
{ heading = 'Name', key = 'displayName' },
|
||||||
{ heading = 'Count', key = 'count', width = 5, align = 'right' },
|
{ heading = 'Count', key = 'count', width = 5, align = 'right' },
|
||||||
@@ -134,13 +118,6 @@ local function project(entities)
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
local function ignoreEntity(entity)
|
|
||||||
if entity then
|
|
||||||
config.ignore[entity.name] = true
|
|
||||||
Config.update('Sensor', config)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
function detail:enable(entity)
|
function detail:enable(entity)
|
||||||
local function update()
|
local function update()
|
||||||
local t = { }
|
local t = { }
|
||||||
@@ -194,8 +171,6 @@ end
|
|||||||
function listing:enable()
|
function listing:enable()
|
||||||
self.handler = Event.onInterval(.5, function()
|
self.handler = Event.onInterval(.5, function()
|
||||||
local entities = sensor.sense()
|
local entities = sensor.sense()
|
||||||
Util.filterInplace(entities, function(e) return not config.ignore[e.name] end)
|
|
||||||
|
|
||||||
self.grid:setValues(entities)
|
self.grid:setValues(entities)
|
||||||
self.grid:draw()
|
self.grid:draw()
|
||||||
self:sync()
|
self:sync()
|
||||||
@@ -209,14 +184,11 @@ function listing:disable()
|
|||||||
end
|
end
|
||||||
|
|
||||||
function listing:eventHandler(event)
|
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()
|
local selected = self.grid:getSelected()
|
||||||
if selected then
|
if selected then
|
||||||
UI:setPage(detail, selected)
|
UI:setPage(detail, selected)
|
||||||
end
|
end
|
||||||
|
|
||||||
elseif event.type == 'ignore' then
|
|
||||||
ignoreEntity(self.grid:getSelected())
|
|
||||||
end
|
end
|
||||||
|
|
||||||
return UI.Tab.eventHandler(self, event)
|
return UI.Tab.eventHandler(self, event)
|
||||||
@@ -225,7 +197,6 @@ end
|
|||||||
function summary:enable()
|
function summary:enable()
|
||||||
self.handler = Event.onInterval(.5, function()
|
self.handler = Event.onInterval(.5, function()
|
||||||
local entities = sensor.sense()
|
local entities = sensor.sense()
|
||||||
Util.filterInplace(entities, function(e) return not config.ignore[e.name] end)
|
|
||||||
|
|
||||||
local t = { }
|
local t = { }
|
||||||
local highlight = { }
|
local highlight = { }
|
||||||
@@ -265,10 +236,7 @@ function summary.grid:getRowTextColor(row, selected)
|
|||||||
end
|
end
|
||||||
|
|
||||||
function summary:eventHandler(event)
|
function summary:eventHandler(event)
|
||||||
if event.type == 'ignore' then
|
if event.type == 'grid_select' then
|
||||||
ignoreEntity(self.grid:getSelected())
|
|
||||||
|
|
||||||
elseif event.type == 'project' or event.type == 'grid_select' then
|
|
||||||
local selected = self.grid:getSelected()
|
local selected = self.grid:getSelected()
|
||||||
if selected then
|
if selected then
|
||||||
self.target = selected.name
|
self.target = selected.name
|
||||||
|
|||||||
189
neural/canvasServer.lua
Normal file
189
neural/canvasServer.lua
Normal 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
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
local GPS = require('gps')
|
local GPS = require('gps')
|
||||||
local Util = require('util')
|
local Util = require('util')
|
||||||
local Point = require('point')
|
local Point = require('point')
|
||||||
local Proxy = require('proxy')
|
local Proxy = require('core.proxy')
|
||||||
|
|
||||||
local os = _G.os
|
local os = _G.os
|
||||||
|
|
||||||
|
|||||||
@@ -29,6 +29,9 @@ elseif not modules.scan then
|
|||||||
showRequirements('Scanner module')
|
showRequirements('Scanner module')
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- size of displayed block
|
||||||
|
local BLOCK_SIZE = .5
|
||||||
|
|
||||||
local function getPoint()
|
local function getPoint()
|
||||||
local pt = { gps.locate() }
|
local pt = { gps.locate() }
|
||||||
if pt[1] then
|
if pt[1] then
|
||||||
@@ -54,7 +57,10 @@ local targets = {
|
|||||||
}
|
}
|
||||||
local projecting = { }
|
local projecting = { }
|
||||||
local offset = getPoint() or showRequirements('GPS')
|
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()
|
local function update()
|
||||||
while true do
|
while true do
|
||||||
@@ -71,7 +77,10 @@ local function update()
|
|||||||
end
|
end
|
||||||
projecting = { }
|
projecting = { }
|
||||||
offset = pos
|
offset = pos
|
||||||
canvas.recenter()
|
canvas.recenter({
|
||||||
|
-(offset.x % 1) + .5,
|
||||||
|
-(offset.y % 1) + .5,
|
||||||
|
-(offset.z % 1) + .5 })
|
||||||
end
|
end
|
||||||
|
|
||||||
local blocks = { }
|
local blocks = { }
|
||||||
@@ -90,20 +99,18 @@ local function update()
|
|||||||
if not projecting[b.id] then
|
if not projecting[b.id] then
|
||||||
projecting[b.id] = b
|
projecting[b.id] = b
|
||||||
local target = targets[b.name]
|
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({
|
b.box = canvas.addFrame({ x, y, z })
|
||||||
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.setDepthTested(false)
|
b.box.setDepthTested(false)
|
||||||
b.box.addItem({ .25, .25 }, target[1], target[2], 2)
|
b.box.addItem({ .25, .25 }, target[1], target[2], 2)
|
||||||
--]]
|
--]]
|
||||||
b.box = canvas.addItem({
|
|
||||||
pos.x - offset.x + b.x + -(pos.x % 1) + .5,
|
b.box = canvas.addItem({ x, y, z }, target[1], target[2], BLOCK_SIZE)
|
||||||
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.setDepthTested(false)
|
b.box.setDepthTested(false)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -1,10 +1,22 @@
|
|||||||
|
local Config = require('config')
|
||||||
|
|
||||||
local peripheral = _G.peripheral
|
local peripheral = _G.peripheral
|
||||||
local turtle = _G.turtle
|
local turtle = _G.turtle
|
||||||
|
|
||||||
local Equipper = { }
|
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_EQUIPPED = 'plethora:scanner'
|
||||||
local SCANNER_INV = 'plethora:module:2'
|
local SCANNER_INV = equipmentList[SCANNER_EQUIPPED] or 'unknown'
|
||||||
|
|
||||||
local reversed = {
|
local reversed = {
|
||||||
left = 'right',
|
left = 'right',
|
||||||
@@ -68,7 +80,9 @@ function Equipper.unequip(side)
|
|||||||
error('No slots available')
|
error('No slots available')
|
||||||
end
|
end
|
||||||
turtle.equip(side)
|
turtle.equip(side)
|
||||||
|
if Equipper.equipped then
|
||||||
Equipper.equipped[side] = nil
|
Equipper.equipped[side] = nil
|
||||||
|
end
|
||||||
return turtle.getItemDetail(slot)
|
return turtle.getItemDetail(slot)
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -81,37 +95,53 @@ function Equipper.isEquipped(name)
|
|||||||
Equipper.equipped.right == name and 'right'
|
Equipper.equipped.right == name and 'right'
|
||||||
end
|
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
|
if not Equipper.equipped then
|
||||||
getEquipped()
|
getEquipped()
|
||||||
end
|
end
|
||||||
|
|
||||||
-- is it already equipped ?
|
-- 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)
|
return peripheral.getType(side) and peripheral.wrap(side)
|
||||||
end
|
end
|
||||||
|
|
||||||
-- is it equipped on other side ?
|
-- 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])
|
Equipper.unequip(reversed[side])
|
||||||
end
|
end
|
||||||
|
|
||||||
local s, m = turtle.equip(side, invName)
|
local s, m = turtle.equip(side, equipmentList[item] or item)
|
||||||
if not s then
|
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
|
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)
|
return peripheral.getType(side) and peripheral.wrap(side)
|
||||||
end
|
end
|
||||||
|
|
||||||
function Equipper.equipLeft(invName, equippedName)
|
function Equipper.equipLeft(item)
|
||||||
return Equipper.equip('left', invName, equippedName)
|
return Equipper.equip('left', item)
|
||||||
end
|
end
|
||||||
|
|
||||||
function Equipper.equipRight(invName, equippedName)
|
function Equipper.equipRight(item)
|
||||||
return Equipper.equip('right', invName, equippedName)
|
return Equipper.equip('right', item)
|
||||||
end
|
end
|
||||||
|
|
||||||
return Equipper
|
return Equipper
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ if not turtle.has('minecraft:bucket') then
|
|||||||
end
|
end
|
||||||
|
|
||||||
local swapSide = peripheral.getType('right') == 'modem' and 'left' or 'right'
|
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
|
if not turtle.select('minecraft:bucket') then
|
||||||
error('bucket required')
|
error('bucket required')
|
||||||
|
|||||||
Reference in New Issue
Block a user