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 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)
|
||||
|
||||
@@ -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
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 Event = require('event')
|
||||
local Map = require('map')
|
||||
local Proxy = require('proxy')
|
||||
local Proxy = require('core.proxy')
|
||||
|
||||
local Swarm = class()
|
||||
function Swarm:init(args)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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
|
||||
====
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
--[[
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -3,4 +3,7 @@
|
||||
repository = 'kepler155c/opus-apps/{{OPUS_BRANCH}}/neural',
|
||||
description = [[ Applications using various plethora modules ]],
|
||||
licence = 'MIT',
|
||||
required = {
|
||||
'core',
|
||||
},
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
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 Util = require('util')
|
||||
local Point = require('point')
|
||||
local Proxy = require('proxy')
|
||||
local Proxy = require('core.proxy')
|
||||
|
||||
local os = _G.os
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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')
|
||||
|
||||
Reference in New Issue
Block a user