Initial commit
232
PriorityQueue.lua
Normal file
@ -0,0 +1,232 @@
|
||||
--[[
|
||||
|
||||
PriorityQueue - v1.0.1 - public domain Lua priority queue
|
||||
implemented with indirect binary heap
|
||||
no warranty implied; use at your own risk
|
||||
|
||||
based on binaryheap library (github.com/iskolbin/binaryheap)
|
||||
|
||||
author: Ilya Kolbin (iskolbin@gmail.com)
|
||||
url: github.com/iskolbin/priorityqueue
|
||||
|
||||
See documentation in README file.
|
||||
|
||||
COMPATIBILITY
|
||||
|
||||
Lua 5.1, 5.2, 5.3, LuaJIT 1, 2
|
||||
|
||||
LICENSE
|
||||
|
||||
This software is dual-licensed to the public domain and under the following
|
||||
license: you are granted a perpetual, irrevocable license to copy, modify,
|
||||
publish, and distribute this file as you see fit.
|
||||
|
||||
--]]
|
||||
|
||||
local floor, setmetatable = math.floor, setmetatable
|
||||
|
||||
local function siftup( self, from )
|
||||
local items, priorities, indices, higherpriority = self, self._priorities, self._indices, self._higherpriority
|
||||
local index = from
|
||||
local parent = floor( index / 2 )
|
||||
while index > 1 and higherpriority( priorities[index], priorities[parent] ) do
|
||||
priorities[index], priorities[parent] = priorities[parent], priorities[index]
|
||||
items[index], items[parent] = items[parent], items[index]
|
||||
indices[items[index]], indices[items[parent]] = index, parent
|
||||
index = parent
|
||||
parent = floor( index / 2 )
|
||||
end
|
||||
return index
|
||||
end
|
||||
|
||||
local function siftdown( self, limit )
|
||||
local items, priorities, indices, higherpriority, size = self, self._priorities, self._indices, self._higherpriority, self._size
|
||||
for index = limit, 1, -1 do
|
||||
local left = index + index
|
||||
local right = left + 1
|
||||
while left <= size do
|
||||
local smaller = left
|
||||
if right <= size and higherpriority( priorities[right], priorities[left] ) then
|
||||
smaller = right
|
||||
end
|
||||
if higherpriority( priorities[smaller], priorities[index] ) then
|
||||
items[index], items[smaller] = items[smaller], items[index]
|
||||
priorities[index], priorities[smaller] = priorities[smaller], priorities[index]
|
||||
indices[items[index]], indices[items[smaller]] = index, smaller
|
||||
else
|
||||
break
|
||||
end
|
||||
index = smaller
|
||||
left = index + index
|
||||
right = left + 1
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local PriorityQueueMt
|
||||
|
||||
local PriorityQueue = {}
|
||||
|
||||
local function minishigher( a, b )
|
||||
return a < b
|
||||
end
|
||||
|
||||
local function maxishigher( a, b )
|
||||
return a > b
|
||||
end
|
||||
|
||||
function PriorityQueue.new( priority_or_array )
|
||||
local t = type( priority_or_array )
|
||||
local higherpriority = minishigher
|
||||
|
||||
if t == 'table' then
|
||||
higherpriority = priority_or_array.higherpriority or higherpriority
|
||||
elseif t == 'function' or t == 'string' then
|
||||
higherpriority = priority_or_array
|
||||
elseif t ~= 'nil' then
|
||||
local msg = 'Wrong argument type to PriorityQueue.new, it must be table or function or string, has: %q'
|
||||
error( msg:format( t ))
|
||||
end
|
||||
|
||||
if type( higherpriority ) == 'string' then
|
||||
if higherpriority == 'min' then
|
||||
higherpriority = minishigher
|
||||
elseif higherpriority == 'max' then
|
||||
higherpriority = maxishigher
|
||||
else
|
||||
local msg = 'Wrong string argument to PriorityQueue.new, it must be "min" or "max", has: %q'
|
||||
error( msg:format( tostring( higherpriority )))
|
||||
end
|
||||
end
|
||||
|
||||
local self = setmetatable( {
|
||||
_priorities = {},
|
||||
_indices = {},
|
||||
_size = 0,
|
||||
_higherpriority = higherpriority or minishigher
|
||||
}, PriorityQueueMt )
|
||||
|
||||
if t == 'table' then
|
||||
self:batchenq( priority_or_array )
|
||||
end
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
function PriorityQueue:enqueue( item, priority )
|
||||
local items, priorities, indices = self, self._priorities, self._indices
|
||||
if indices[item] ~= nil then
|
||||
error( 'Item ' .. tostring(indices[item]) .. ' is already in the heap' )
|
||||
end
|
||||
local size = self._size + 1
|
||||
self._size = size
|
||||
items[size], priorities[size], indices[item] = item, priority, size
|
||||
siftup( self, size )
|
||||
return self
|
||||
end
|
||||
|
||||
function PriorityQueue:remove( item )
|
||||
local index = self._indices[item]
|
||||
if index ~= nil then
|
||||
local size = self._size
|
||||
local items, priorities, indices = self, self._priorities, self._indices
|
||||
indices[item] = nil
|
||||
if size == index then
|
||||
items[size], priorities[size] = nil, nil
|
||||
self._size = size - 1
|
||||
else
|
||||
local lastitem = items[size]
|
||||
items[index], priorities[index] = items[size], priorities[size]
|
||||
items[size], priorities[size] = nil, nil
|
||||
indices[lastitem] = index
|
||||
size = size - 1
|
||||
self._size = size
|
||||
if size > 1 then
|
||||
siftdown( self, siftup( self, index ))
|
||||
end
|
||||
end
|
||||
return true
|
||||
else
|
||||
return false
|
||||
end
|
||||
end
|
||||
|
||||
function PriorityQueue:contains( item )
|
||||
return self._indices[item] ~= nil
|
||||
end
|
||||
|
||||
function PriorityQueue:update( item, priority )
|
||||
local ok = self:remove( item )
|
||||
if ok then
|
||||
self:enqueue( item, priority )
|
||||
return true
|
||||
else
|
||||
return false
|
||||
end
|
||||
end
|
||||
|
||||
function PriorityQueue:dequeue()
|
||||
local size = self._size
|
||||
|
||||
assert( size > 0, 'Heap is empty' )
|
||||
|
||||
local items, priorities, indices = self, self._priorities, self._indices
|
||||
local item, priority = items[1], priorities[1]
|
||||
indices[item] = nil
|
||||
|
||||
if size > 1 then
|
||||
local newitem = items[size]
|
||||
items[1], priorities[1] = newitem, priorities[size]
|
||||
items[size], priorities[size] = nil, nil
|
||||
indices[newitem] = 1
|
||||
size = size - 1
|
||||
self._size = size
|
||||
siftdown( self, 1 )
|
||||
else
|
||||
items[1], priorities[1] = nil, nil
|
||||
self._size = 0
|
||||
end
|
||||
|
||||
return item, priority
|
||||
end
|
||||
|
||||
function PriorityQueue:peek()
|
||||
return self[1], self._priorities[1]
|
||||
end
|
||||
|
||||
function PriorityQueue:len()
|
||||
return self._size
|
||||
end
|
||||
|
||||
function PriorityQueue:empty()
|
||||
return self._size <= 0
|
||||
end
|
||||
|
||||
function PriorityQueue:batchenq( iparray )
|
||||
local items, priorities, indices = self, self._priorities, self._indices
|
||||
local size = self._size
|
||||
for i = 1, #iparray, 2 do
|
||||
local item, priority = iparray[i], iparray[i+1]
|
||||
if indices[item] ~= nil then
|
||||
error( 'Item ' .. tostring(indices[item]) .. ' is already in the heap' )
|
||||
end
|
||||
size = size + 1
|
||||
items[size], priorities[size] = item, priority
|
||||
indices[item] = size
|
||||
end
|
||||
self._size = size
|
||||
if size > 1 then
|
||||
siftdown( self, floor( size / 2 ))
|
||||
end
|
||||
end
|
||||
|
||||
PriorityQueueMt = {
|
||||
__index = PriorityQueue,
|
||||
__len = PriorityQueue.len,
|
||||
}
|
||||
|
||||
return setmetatable( PriorityQueue, {
|
||||
__call = function( _, ... )
|
||||
return PriorityQueue.new( ... )
|
||||
end
|
||||
} )
|
61
alarm.lua
Normal file
@ -0,0 +1,61 @@
|
||||
local dfpwm = require("cc.audio.dfpwm")
|
||||
|
||||
local speaker = peripheral.find("speaker")
|
||||
local monitor = peripheral.find("monitor")
|
||||
local chat = peripheral.find("chatBox")
|
||||
local detector = peripheral.find("playerDetector")
|
||||
|
||||
local distance = 20
|
||||
local target = "OROURKEIRE"
|
||||
--local target = "devplayer0"
|
||||
|
||||
function klaxon()
|
||||
local decoder = dfpwm.make_decoder()
|
||||
for chunk in io.lines("data/danger.dfpwm", 16 * 1024) do
|
||||
local buffer = decoder(chunk)
|
||||
|
||||
while not speaker.playAudio(buffer) do
|
||||
os.pullEvent("speaker_audio_empty")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function showWarning()
|
||||
monitor.clear()
|
||||
monitor.setTextScale(2)
|
||||
--[[local w, h = monitor.getSize()
|
||||
local tw = string.len("WARNING")
|
||||
for i = 1, 3 do
|
||||
monitor.setCursorPos(w/2 - tw/2, (h/3)*i)
|
||||
monitor.write("WARNING")
|
||||
end]]
|
||||
monitor.setCursorPos(8, 3)
|
||||
monitor.write("WARNING")
|
||||
monitor.setCursorPos(8, 5)
|
||||
monitor.write("WARNING")
|
||||
monitor.setCursorPos(8, 8)
|
||||
monitor.write("WARNING")
|
||||
end
|
||||
|
||||
function broadcastWarning()
|
||||
local msg = {
|
||||
{text = "WARNING", color = "red"},
|
||||
{text = ": Kevin is ", color = "white"},
|
||||
{text = "IN THE BASE", color = "yellow"},
|
||||
{text = "!"},
|
||||
}
|
||||
local msgJSON = textutils.serializeJSON(msg)
|
||||
chat.sendFormattedMessage(msgJSON)
|
||||
end
|
||||
|
||||
while true do
|
||||
if detector.isPlayerInRange(25, target) then
|
||||
showWarning()
|
||||
broadcastWarning()
|
||||
klaxon()
|
||||
else
|
||||
monitor.clear()
|
||||
end
|
||||
|
||||
sleep(1)
|
||||
end
|
BIN
danger.dfpwm
Normal file
1
datapack/.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
||||
*.zip
|
@ -0,0 +1,6 @@
|
||||
{
|
||||
"type": "computercraft:tool",
|
||||
"item": "minecraft:diamond_pickaxe",
|
||||
"adjective": "upgrade.minecraft.diamond_pickaxe.adjective",
|
||||
"allowEnchantments": true
|
||||
}
|
6
datapack/pack.mcmeta
Normal file
@ -0,0 +1,6 @@
|
||||
{
|
||||
"pack": {
|
||||
"pack_format": 15,
|
||||
"description": "Enchanted pickaxe for ComputerCraft"
|
||||
}
|
||||
}
|
BIN
icon/ore-coal.png
Normal file
After Width: | Height: | Size: 623 B |
BIN
icon/ore-copper.png
Normal file
After Width: | Height: | Size: 653 B |
BIN
icon/ore-diamond.png
Normal file
After Width: | Height: | Size: 625 B |
BIN
icon/ore-ds-coal.png
Normal file
After Width: | Height: | Size: 613 B |
BIN
icon/ore-ds-copper.png
Normal file
After Width: | Height: | Size: 636 B |
BIN
icon/ore-ds-diamond.png
Normal file
After Width: | Height: | Size: 641 B |
BIN
icon/ore-ds-emerald.png
Normal file
After Width: | Height: | Size: 636 B |
BIN
icon/ore-ds-gold.png
Normal file
After Width: | Height: | Size: 615 B |
BIN
icon/ore-ds-iron.png
Normal file
After Width: | Height: | Size: 624 B |
BIN
icon/ore-ds-lapis.png
Normal file
After Width: | Height: | Size: 661 B |
BIN
icon/ore-ds-redstone.png
Normal file
After Width: | Height: | Size: 715 B |
BIN
icon/ore-emerald.png
Normal file
After Width: | Height: | Size: 634 B |
BIN
icon/ore-generic.png
Normal file
After Width: | Height: | Size: 12 KiB |
BIN
icon/ore-gold.png
Normal file
After Width: | Height: | Size: 633 B |
BIN
icon/ore-iron.png
Normal file
After Width: | Height: | Size: 615 B |
BIN
icon/ore-lapis.png
Normal file
After Width: | Height: | Size: 676 B |
BIN
icon/ore-redstone.png
Normal file
After Width: | Height: | Size: 644 B |
BIN
icon/turtle.png
Normal file
After Width: | Height: | Size: 8.5 KiB |
727
mine.lua
Normal file
@ -0,0 +1,727 @@
|
||||
package.path = "/mod/?.lua;" .. package.path
|
||||
local PriorityQueue = require "PriorityQueue"
|
||||
|
||||
function Set(list)
|
||||
local set = {}
|
||||
for _, l in ipairs(list) do set[l] = true end
|
||||
return set
|
||||
end
|
||||
|
||||
local yieldTime = 0
|
||||
function yield()
|
||||
if os.clock() - yieldTime > 2 then
|
||||
sleep(0)
|
||||
yieldTime = os.clock()
|
||||
end
|
||||
end
|
||||
|
||||
function arr(n, init)
|
||||
local a = {}
|
||||
for _ = 1, n do
|
||||
table.insert(a, init)
|
||||
end
|
||||
return a
|
||||
end
|
||||
function arr2(x, y, init)
|
||||
local a = {}
|
||||
for _ = 1, y do
|
||||
table.insert(a, arr(x, init))
|
||||
end
|
||||
return a
|
||||
end
|
||||
|
||||
local dirMap = {
|
||||
["0,-1"] = 0,
|
||||
["0,1"] = 0.5,
|
||||
["1,0"] = 0.25,
|
||||
["-1,0"] = -0.25,
|
||||
}
|
||||
function direction(v)
|
||||
local d = dirMap[v.x..","..v.z]
|
||||
assert(d)
|
||||
return d
|
||||
end
|
||||
|
||||
function findDistances(points)
|
||||
local dist = arr2(#points, #points, math.huge)
|
||||
-- local prev = arr2(#points, #points)
|
||||
|
||||
for i = 1, #points do
|
||||
for j = 1, #points do
|
||||
if i ~= j then
|
||||
dist[i][j] = (points[i] - points[j]):length()
|
||||
-- prev[i][j] = i
|
||||
end
|
||||
end
|
||||
end
|
||||
for i = 1, #points do
|
||||
dist[i][i] = 0
|
||||
-- prev[i][i] = i
|
||||
end
|
||||
|
||||
return dist
|
||||
end
|
||||
|
||||
function groupOres(ores, dist, offset)
|
||||
if not offset then
|
||||
offset = 0
|
||||
end
|
||||
|
||||
local groups = {}
|
||||
for i, o in ipairs(ores) do
|
||||
table.insert(groups, {
|
||||
["type"] = o.name,
|
||||
["blocks"] = {
|
||||
[i] = vector.new(o.x, o.y, o.z),
|
||||
},
|
||||
})
|
||||
end
|
||||
|
||||
local didJoin = true
|
||||
while didJoin do
|
||||
didJoin = false
|
||||
for i, io in pairs(groups) do
|
||||
for x, a in pairs(io.blocks) do
|
||||
for j, jo in pairs(groups) do
|
||||
if i ~= j and jo.type == io.type then
|
||||
for y, b in pairs(jo.blocks) do
|
||||
-- yield()
|
||||
assert(a ~= b)
|
||||
if dist[offset + x][offset + y] == 1 then
|
||||
for z, p in pairs(jo.blocks) do
|
||||
io.blocks[z] = p
|
||||
end
|
||||
groups[j] = nil
|
||||
didJoin = true
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local retGroups = {}
|
||||
for _, g in pairs(groups) do
|
||||
local v = vector.new(0, 0, 0)
|
||||
local retBlocks = {}
|
||||
for _, p in pairs(g.blocks) do
|
||||
v = v + p
|
||||
table.insert(retBlocks, p)
|
||||
end
|
||||
g.blocks = retBlocks
|
||||
g.center = v / #g.blocks
|
||||
assert(g.center)
|
||||
table.insert(retGroups, g)
|
||||
end
|
||||
|
||||
return retGroups
|
||||
end
|
||||
|
||||
function pathThrough(points, dist, s, e)
|
||||
-- local n = #points
|
||||
|
||||
-- dist[s][n] = 0
|
||||
-- dist[n][s] = 0
|
||||
-- dist[e][n] = 0
|
||||
-- dist[n][e] = 0
|
||||
|
||||
-- for k = 1, #points do
|
||||
-- for i = 1, #points do
|
||||
-- for j = 1, #points do
|
||||
-- if dist[i][j] > dist[i][k] + dist[k][j] then
|
||||
-- dist[i][j] = dist[i][k] + dist[k][j]
|
||||
-- prev[i][j] = prev[k][j]
|
||||
-- end
|
||||
-- end
|
||||
-- yield()
|
||||
-- end
|
||||
-- end
|
||||
|
||||
-- local path = {e}
|
||||
-- while s ~= e do
|
||||
-- e = prev[s][e]
|
||||
-- table.insert(path, 1, e)
|
||||
-- end
|
||||
|
||||
-- return path
|
||||
|
||||
-- nearest neighbour
|
||||
local unvisited = {}
|
||||
local ui = nil
|
||||
for i = 1, #points do
|
||||
if not e or i ~= e then
|
||||
table.insert(unvisited, i)
|
||||
end
|
||||
if i == s then
|
||||
ui = #unvisited
|
||||
end
|
||||
end
|
||||
assert(ui)
|
||||
|
||||
local visited = {}
|
||||
local route = {}
|
||||
while #unvisited ~= 1 do
|
||||
local u = unvisited[ui]
|
||||
table.remove(unvisited, ui)
|
||||
|
||||
local cDist = math.huge
|
||||
local closest = nil
|
||||
for ii = 1, #unvisited do
|
||||
local i = unvisited[ii]
|
||||
assert(i ~= u)
|
||||
if dist[u][i] < cDist then
|
||||
cDist = dist[u][i]
|
||||
closest = ii
|
||||
end
|
||||
end
|
||||
assert(closest)
|
||||
table.insert(route, unvisited[closest])
|
||||
ui = closest
|
||||
end
|
||||
if e then
|
||||
table.insert(route, e)
|
||||
end
|
||||
|
||||
return route
|
||||
end
|
||||
|
||||
-- A*
|
||||
function findPath(s, e)
|
||||
local points = {}
|
||||
function addPoint(p)
|
||||
local k = p:tostring()
|
||||
if not points[k] then
|
||||
points[k] = p
|
||||
end
|
||||
return k
|
||||
end
|
||||
s = addPoint(s)
|
||||
e = addPoint(e)
|
||||
|
||||
function h(i)
|
||||
return (points[e] - points[i]):length()
|
||||
end
|
||||
|
||||
function neighbors(k)
|
||||
local p = points[k]
|
||||
local ns = {
|
||||
p + vector.new( 1, 0, 0),
|
||||
p + vector.new( 0, 1, 0),
|
||||
p + vector.new( 0, 0, 1),
|
||||
p + vector.new(-1, 0, 0),
|
||||
p + vector.new( 0, -1, 0),
|
||||
p + vector.new( 0, 0, -1),
|
||||
}
|
||||
|
||||
for i, n in ipairs(ns) do
|
||||
ns[i] = addPoint(n)
|
||||
end
|
||||
return ns
|
||||
end
|
||||
|
||||
local gScoreT = {}
|
||||
gScoreT[s] = 0
|
||||
function gScore(i)
|
||||
if gScoreT[i] then
|
||||
return gScoreT[i]
|
||||
else
|
||||
return math.huge
|
||||
end
|
||||
end
|
||||
|
||||
local fScoreT = {}
|
||||
fScoreT[s] = h(s)
|
||||
function fScore(i)
|
||||
if fScoreT[i] then
|
||||
return fScoreT[i]
|
||||
else
|
||||
return math.huge
|
||||
end
|
||||
end
|
||||
|
||||
local openSet = PriorityQueue(function(a, b)
|
||||
return fScore(a) < fScore(b)
|
||||
end)
|
||||
openSet:enqueue(s, s)
|
||||
|
||||
local prev = {}
|
||||
local found = false
|
||||
while not openSet:empty() do
|
||||
local current = openSet:dequeue()
|
||||
if current == e then
|
||||
found = true
|
||||
break
|
||||
end
|
||||
|
||||
local ns = neighbors(current)
|
||||
for _, n in ipairs(ns) do
|
||||
tentativeG = gScore(current) + 1
|
||||
if tentativeG < gScore(n) then
|
||||
prev[n] = current
|
||||
gScoreT[n] = tentativeG
|
||||
fScoreT[n] = tentativeG + h(n)
|
||||
if not openSet:contains(n) then
|
||||
openSet:enqueue(n, n)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
assert(found)
|
||||
|
||||
local path = {points[e]}
|
||||
local current = e
|
||||
while prev[current] do
|
||||
current = prev[current]
|
||||
table.insert(path, 1, points[current])
|
||||
end
|
||||
return path
|
||||
end
|
||||
|
||||
local ORES = Set{
|
||||
"minecraft:coal_ore",
|
||||
"minecraft:deepslate_coal_ore",
|
||||
"minecraft:iron_ore",
|
||||
"minecraft:deepslate_iron_ore",
|
||||
"minecraft:copper_ore",
|
||||
"minecraft:deepslate_copper_ore",
|
||||
"minecraft:gold_ore",
|
||||
"minecraft:deepslate_gold_ore",
|
||||
"minecraft:redstone_ore",
|
||||
"minecraft:deepslate_redstone_ore",
|
||||
"minecraft:emerald_ore",
|
||||
"minecraft:deepslate_emerald_ore",
|
||||
"minecraft:lapis_ore",
|
||||
"minecraft:deepslate_lapis_ore",
|
||||
"minecraft:diamond_ore",
|
||||
"minecraft:deepslate_diamond_ore",
|
||||
|
||||
"create:ochrum",
|
||||
"create:zinc_ore",
|
||||
"create:deepslate_zinc_ore",
|
||||
"create_new_age:thorium_ore",
|
||||
|
||||
"powah:deepslate_uraninite_ore_poor",
|
||||
"powah:deepslate_uraninite_ore",
|
||||
"powah:deepslate_uraninite_ore_dense",
|
||||
"powah:uraninite_ore_poor",
|
||||
"powah:uraninite_ore",
|
||||
"powah:uraninite_ore_dense",
|
||||
|
||||
-- "minecraft:diamond_ore",
|
||||
-- "minecraft:netherrack",
|
||||
}
|
||||
local BLACKLIST = Set{
|
||||
"minecraft:diamond_pickaxe",
|
||||
"computercraft:wireless_modem_advanced",
|
||||
"advancedperipherals:geo_scanner",
|
||||
"enderchests:ender_chest",
|
||||
"functionalstorage:ender_drawer",
|
||||
"advancedperipherals:chunk_controller",
|
||||
}
|
||||
local FUEL = "minecraft:coal"
|
||||
local CHANNEL = 1337
|
||||
|
||||
settings.define("mine.name", {
|
||||
description = "Miner name",
|
||||
default = "DiggyBoi",
|
||||
type = "string",
|
||||
})
|
||||
|
||||
function selectItem(item, nbt)
|
||||
for i = 1, 16 do
|
||||
info = turtle.getItemDetail(i)
|
||||
if (not item and not info) or (info and info.name == item and (not nbt or item.nbt == nbt)) then
|
||||
turtle.select(i)
|
||||
return i
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
Miner = {}
|
||||
function Miner.new()
|
||||
local self = setmetatable({}, { __index = Miner })
|
||||
self.name = settings.get("mine.name")
|
||||
self.equipped = {
|
||||
["left"] = {
|
||||
["last"] = "NONE",
|
||||
["lastNbt"] = nil,
|
||||
["fun"] = turtle.equipLeft,
|
||||
},
|
||||
["right"] = {
|
||||
["last"] = "NONE",
|
||||
["lastNbt"] = nil,
|
||||
["fun"] = turtle.equipRight,
|
||||
},
|
||||
}
|
||||
|
||||
-- Get upgrades to a known state by "equipping" nothing
|
||||
self:equip(nil, "left")
|
||||
self:equip(nil, "right")
|
||||
|
||||
self:equip("advancedperipherals:geo_scanner", "right")
|
||||
self.scanner = peripheral.wrap("right")
|
||||
|
||||
self:equip("computercraft:wireless_modem_advanced", "right")
|
||||
self.modem = peripheral.wrap("right")
|
||||
self.modem.open(CHANNEL)
|
||||
|
||||
self.pos = vector.new(0, 0, 0)
|
||||
self:doGPS(true)
|
||||
|
||||
self:equip("advancedperipherals:chunk_controller", "left")
|
||||
|
||||
self.i = 1
|
||||
return self
|
||||
end
|
||||
|
||||
function Miner:equip(item, side, nbt)
|
||||
local e = self.equipped[side]
|
||||
if item == e.last and nbt == e.lastNbt then
|
||||
return
|
||||
end
|
||||
|
||||
assert(selectItem(item, nbt))
|
||||
e.fun()
|
||||
e.last = item
|
||||
e.lastNbt = nbt
|
||||
end
|
||||
|
||||
function Miner:sendMessage(type, msg)
|
||||
self:equip("computercraft:wireless_modem_advanced", "right")
|
||||
msg["type"] = type
|
||||
msg["name"] = self.name
|
||||
msg["pos"] = self.absolutePos
|
||||
self.modem.transmit(CHANNEL, CHANNEL, msg)
|
||||
end
|
||||
|
||||
function Miner:dig(dir)
|
||||
self:equip("minecraft:diamond_pickaxe", "right")
|
||||
if dir == "up" then
|
||||
assert(turtle.digUp())
|
||||
elseif dir == "forward" then
|
||||
assert(turtle.dig())
|
||||
elseif dir == "down" then
|
||||
assert(turtle.digDown())
|
||||
end
|
||||
end
|
||||
|
||||
function Miner:xchgItems()
|
||||
local slots = {}
|
||||
local emptySlots = 0
|
||||
for i = 1, 16 do
|
||||
local info = turtle.getItemDetail(i)
|
||||
if info then
|
||||
assert(info.name)
|
||||
if not BLACKLIST[info.name] then
|
||||
slots[i] = info
|
||||
end
|
||||
else
|
||||
emptySlots = emptySlots + 1
|
||||
end
|
||||
end
|
||||
|
||||
if emptySlots >= 2 and turtle.getFuelLevel() >= 1000 then
|
||||
return
|
||||
end
|
||||
|
||||
if turtle.detectDown() then
|
||||
self:dig("down")
|
||||
end
|
||||
|
||||
if emptySlots < 2 then
|
||||
selectItem("enderchests:ender_chest")
|
||||
assert(turtle.placeDown())
|
||||
|
||||
for i, info in pairs(slots) do
|
||||
assert(turtle.select(i))
|
||||
assert(turtle.dropDown())
|
||||
end
|
||||
self:dig("down")
|
||||
end
|
||||
|
||||
if turtle.getFuelLevel() < 1000 then
|
||||
selectItem("functionalstorage:ender_drawer")
|
||||
assert(turtle.placeDown())
|
||||
assert(turtle.suckDown())
|
||||
assert(turtle.refuel())
|
||||
self:dig("down")
|
||||
end
|
||||
end
|
||||
|
||||
function Miner:safeMove(dir)
|
||||
if dir == "up" then
|
||||
while turtle.detectUp() do
|
||||
self:dig("up")
|
||||
end
|
||||
assert(turtle.up())
|
||||
elseif dir == "forward" then
|
||||
while turtle.detect() do
|
||||
self:dig("forward")
|
||||
end
|
||||
assert(turtle.forward())
|
||||
else
|
||||
if turtle.detectDown() then
|
||||
self:dig("down")
|
||||
end
|
||||
assert(turtle.down())
|
||||
end
|
||||
end
|
||||
|
||||
function Miner:doGPS(orientation)
|
||||
local x, y, z = gps.locate()
|
||||
assert(x)
|
||||
self.absolutePos = vector.new(x, y, z)
|
||||
|
||||
if orientation then
|
||||
assert(turtle.forward())
|
||||
x, y, z = gps.locate()
|
||||
assert(x)
|
||||
self.dir = vector.new(x, y, z) - self.absolutePos
|
||||
assert(turtle.back())
|
||||
end
|
||||
end
|
||||
|
||||
function Miner:findOres(radius)
|
||||
self:equip("advancedperipherals:geo_scanner", "right")
|
||||
local info, err = self.scanner.scan(radius)
|
||||
assert(info, err)
|
||||
|
||||
local found = {}
|
||||
for _, b in ipairs(info) do
|
||||
-- only ores and avoid bedrock
|
||||
if ORES[b.name] and self.absolutePos.y + b.y >= -58 then
|
||||
table.insert(found, b)
|
||||
end
|
||||
end
|
||||
return found
|
||||
end
|
||||
|
||||
function Miner:faceDir(newDir)
|
||||
local deltaDir = direction(newDir) - direction(self.dir)
|
||||
if deltaDir == 0.25 or deltaDir == -0.75 then
|
||||
assert(turtle.turnRight())
|
||||
self.dir = newDir
|
||||
elseif deltaDir == -0.25 or deltaDir == 0.75 then
|
||||
assert(turtle.turnLeft())
|
||||
self.dir = newDir
|
||||
elseif deltaDir == 0.5 or deltaDir == -0.5 then
|
||||
assert(turtle.turnRight())
|
||||
assert(turtle.turnRight())
|
||||
self.dir = newDir
|
||||
elseif deltaDir == 0 then
|
||||
-- nothing to do :)
|
||||
else
|
||||
assert(false, "invalid delta dir "..deltaDir)
|
||||
end
|
||||
end
|
||||
|
||||
function Miner:navigateThrough(path)
|
||||
for _, p in ipairs(path) do
|
||||
-- print("move from to", self.pos, p)
|
||||
local delta = p - self.pos
|
||||
assert(delta:length() ~= 0)
|
||||
-- print("doing", delta)
|
||||
if delta:length() ~= 1 then
|
||||
-- print("path finding between points")
|
||||
local path = findPath(self.pos, p)
|
||||
table.remove(path, 1)
|
||||
table.remove(path, #path)
|
||||
assert(#path ~= 0)
|
||||
|
||||
self:navigateThrough(path)
|
||||
delta = p - self.pos
|
||||
end
|
||||
assert(delta:length() == 1)
|
||||
|
||||
local moveDir = nil
|
||||
if delta.y == 1 then
|
||||
moveDir = "up"
|
||||
elseif delta.y == -1 then
|
||||
moveDir = "down"
|
||||
else
|
||||
self:faceDir(delta)
|
||||
moveDir = "forward"
|
||||
end
|
||||
|
||||
self:safeMove(moveDir)
|
||||
self.pos = p
|
||||
self.absolutePos = self.absolutePos + delta
|
||||
end
|
||||
end
|
||||
|
||||
function Miner:mineOres(radius)
|
||||
local startingDir = self.dir
|
||||
self.pos = vector.new(0, 0, 0)
|
||||
|
||||
local ores = self:findOres(radius)
|
||||
local orePoints = {}
|
||||
for _, b in ipairs(ores) do
|
||||
table.insert(orePoints, vector.new(b.x, b.y, b.z))
|
||||
end
|
||||
local veins = groupOres(ores, findDistances(orePoints))
|
||||
print("Found "..#ores.." ores ("..#veins.." veins)")
|
||||
|
||||
local veinsPoints = {
|
||||
self.pos,
|
||||
self.dir * radius * 2,
|
||||
}
|
||||
for _, v in ipairs(veins) do
|
||||
table.insert(veinsPoints, v.center)
|
||||
end
|
||||
|
||||
local veinsPath = pathThrough(veinsPoints, findDistances(veinsPoints), 1, 2)
|
||||
-- strip out end point
|
||||
table.remove(veinsPath, #veinsPath)
|
||||
|
||||
local veinsSummary = {}
|
||||
for _, i in ipairs(veinsPath) do
|
||||
local v = veins[i - 2]
|
||||
table.insert(veinsSummary, {
|
||||
pos = self.absolutePos + v.center,
|
||||
type = v.type,
|
||||
count = #v.blocks,
|
||||
})
|
||||
end
|
||||
self:sendMessage("iterationStart", {
|
||||
i = self.i,
|
||||
oreCount = #ores,
|
||||
veins = veinsSummary,
|
||||
})
|
||||
|
||||
for pi, i in ipairs(veinsPath) do
|
||||
self:xchgItems()
|
||||
|
||||
local vein = veins[i - 2]
|
||||
local closest = nil
|
||||
local cDist = math.huge
|
||||
for _, b in ipairs(vein.blocks) do
|
||||
local d = (b - self.pos):length()
|
||||
if d < cDist then
|
||||
closest = b
|
||||
cDist = d
|
||||
end
|
||||
end
|
||||
assert(closest)
|
||||
|
||||
local pathToStart = findPath(self.pos, closest)
|
||||
table.remove(pathToStart, 1)
|
||||
table.remove(pathToStart, #pathToStart)
|
||||
|
||||
print("Moving to vein of " .. #vein.blocks .. " " .. vein.type .. " " .. cDist .. " blocks away starting at", closest)
|
||||
self:navigateThrough(pathToStart)
|
||||
|
||||
local veinPoints = {self.pos}
|
||||
for _, b in ipairs(vein.blocks) do
|
||||
table.insert(veinPoints, b)
|
||||
end
|
||||
|
||||
local veinPathI = pathThrough(veinPoints, findDistances(veinPoints), 1)
|
||||
local veinPath = {}
|
||||
for _, i in ipairs(veinPathI) do
|
||||
table.insert(veinPath, veinPoints[i])
|
||||
end
|
||||
|
||||
print("Digging through vein (" .. #vein.blocks .. " blocks)")
|
||||
self:sendMessage("veinStart", {
|
||||
i = pi,
|
||||
total = #veins,
|
||||
oreType = vein.type,
|
||||
oreCount = #vein.blocks,
|
||||
})
|
||||
self:navigateThrough(veinPath)
|
||||
end
|
||||
|
||||
self:navigateThrough({veinsPoints[2]})
|
||||
self:faceDir(startingDir)
|
||||
self.i = self.i + 1
|
||||
end
|
||||
|
||||
local miner = Miner.new()
|
||||
while true do
|
||||
miner:mineOres(16)
|
||||
end
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
-- test code, please ignore
|
||||
assert(false)
|
||||
|
||||
-- local f, err = fs.open("points.csv", "w")
|
||||
-- assert(f, err)
|
||||
|
||||
local points = {
|
||||
vector.new(0, 0, 0),
|
||||
vector.new(0, 0, -16),
|
||||
}
|
||||
for _, b in ipairs(ores) do
|
||||
-- print("found " .. b.name .. " at " .. b.x .. ", " .. b.y .. ", " .. b.z)
|
||||
table.insert(points, vector.new(b.x, b.y, b.z))
|
||||
end
|
||||
print("found "..#ores.." ores")
|
||||
|
||||
local dist = findDistances(points)
|
||||
local groups = groupOres(ores, dist, 2)
|
||||
|
||||
for _, g in ipairs(groups) do
|
||||
print("group of "..#g.blocks.." "..g.type.." at", g.center)
|
||||
end
|
||||
print(#groups, "groups of ore found")
|
||||
|
||||
local gPoints = {
|
||||
vector.new(0, 0, 0),
|
||||
vector.new(0, 0, -16),
|
||||
}
|
||||
for _, g in ipairs(groups) do
|
||||
table.insert(gPoints, g.center)
|
||||
end
|
||||
|
||||
local gDist = findDistances(gPoints)
|
||||
local gPath = pathThrough(gPoints, gDist, 1, 2)
|
||||
for _, i in ipairs(gPath) do
|
||||
local p = gPoints[i]
|
||||
f.write(p.x..","..p.y..","..p.z.."\n")
|
||||
end
|
||||
|
||||
f.write("MARK\n")
|
||||
|
||||
-- print(points[1], gPoints[gPath[1]])
|
||||
-- local pathTo = findPath(points[1], gPoints[gPath[1]])
|
||||
-- for _, p in ipairs(pathTo) do
|
||||
-- -- local p = pathTo[i]
|
||||
-- -- print(p)
|
||||
-- f.write(p.x..","..p.y..","..p.z.."\n")
|
||||
-- end
|
||||
|
||||
miner:mineOres(groups)
|
||||
|
||||
-- table.remove(pathTo, 1)
|
||||
-- table.remove(pathTo, #pathTo)
|
||||
-- miner:navigateThrough(pathTo)
|
||||
|
||||
-- f.write("MARK\n")
|
||||
|
||||
-- local allPath = pathThrough(points, dist, 1, 2)
|
||||
-- for _, i in ipairs(allPath) do
|
||||
-- local p = points[i]
|
||||
-- -- print(points[i])
|
||||
-- f.write(p.x..","..p.y..","..p.z.."\n")
|
||||
-- end
|
||||
|
||||
f.close()
|
||||
|
||||
-- local f = vector.new(1, 0, 0)
|
||||
-- local p = vector.new(0, -1, 7)
|
||||
-- local t = vector.new(-1, -1, 7)
|
||||
|
||||
-- print(direction(t - p) - direction(f))
|
185
mineMonitor.lua
Normal file
@ -0,0 +1,185 @@
|
||||
local CHANNEL = 1337
|
||||
local TARGET = "devplayer0"
|
||||
local ICON_BASE = "https://p.nul.ie/cc/icon/"
|
||||
local ORE_ICONS = {
|
||||
["minecraft:coal_ore"] = "coal",
|
||||
["minecraft:deepslate_coal_ore"] = "ds-coal",
|
||||
["minecraft:iron_ore"] = "iron",
|
||||
["minecraft:deepslate_iron_ore"] = "ds-iron",
|
||||
["minecraft:copper_ore"] = "copper",
|
||||
["minecraft:deepslate_copper_ore"] = "ds-copper",
|
||||
["minecraft:gold_ore"] = "gold",
|
||||
["minecraft:deepslate_gold_ore"] = "ds-gold",
|
||||
["minecraft:redstone_ore"] = "redstone",
|
||||
["minecraft:deepslate_redstone_ore"] = "ds-redstone",
|
||||
["minecraft:emerald_ore"] = "emerald",
|
||||
["minecraft:deepslate_emerald_ore"] = "ds-emerald",
|
||||
["minecraft:lapis_ore"] = "lapis",
|
||||
["minecraft:deepslate_lapis_ore"] = "ds-lapis",
|
||||
["minecraft:diamond_ore"] = "diamond",
|
||||
["minecraft:deepslate_diamond_ore"] = "ds-diamond",
|
||||
|
||||
-- ["create:ochrum"] =,
|
||||
-- ["create:zinc_ore"] =,
|
||||
-- ["create:deepslate_zinc_ore"] =,
|
||||
-- ["create_new_age:thorium_ore"] =,
|
||||
|
||||
-- ["powah:deepslate_uraninite_ore_poor"] =,
|
||||
-- ["powah:deepslate_uraninite_ore"] =,
|
||||
-- ["powah:deepslate_uraninite_ore_dense"] =,
|
||||
-- ["powah:uraninite_ore_poor"] =,
|
||||
-- ["powah:uraninite_ore"] =,
|
||||
-- ["powah:uraninite_ore_dense"] =,
|
||||
}
|
||||
|
||||
function oreIcon(t)
|
||||
local i = "generic"
|
||||
if ORE_ICONS[t] then
|
||||
i = ORE_ICONS[t]
|
||||
end
|
||||
|
||||
return ICON_BASE .. "ore-" .. i .. ".png"
|
||||
end
|
||||
|
||||
local modem = peripheral.find("modem")
|
||||
-- local monitor = peripheral.find("monitor")
|
||||
local chat = peripheral.find("chatBox")
|
||||
local cartographer = peripheral.find("cartographer")
|
||||
|
||||
function vecToStr(v)
|
||||
return v.x .. "," .. v.y .. "," .. v.z
|
||||
end
|
||||
|
||||
function markerSet(msg)
|
||||
return "autominer_" .. msg.name
|
||||
end
|
||||
|
||||
function setPosMarker(msg)
|
||||
local id = markerSet(msg)
|
||||
local mId = id .. "_pos"
|
||||
cartographer.removeMarker(id, mId)
|
||||
cartographer.addPOIMarker(
|
||||
id, mId, msg.name, msg.name .. "'s position",
|
||||
msg.pos.x, msg.pos.y, msg.pos.z,
|
||||
ICON_BASE .. "turtle.png")
|
||||
end
|
||||
|
||||
function handleStart(msg)
|
||||
local cMsg = {
|
||||
{text = msg.name, color = "green"},
|
||||
{text = " @ ", color = "white"},
|
||||
{text = vecToStr(msg.pos), color = "aqua"},
|
||||
{text = " found ", color = "white"},
|
||||
{text = tostring(msg.oreCount), color = "red"},
|
||||
{text = " ores (", color = "white"},
|
||||
{text = tostring(#msg.veins), color = "red"},
|
||||
{text = " veins) on iteration ", color = "white"},
|
||||
{text = tostring(msg.i), color = "green"},
|
||||
{text = "!", color = "white"},
|
||||
}
|
||||
local msgJSON = textutils.serializeJSON(cMsg)
|
||||
chat.sendFormattedMessage(msgJSON, "AutoMine")
|
||||
|
||||
local id = markerSet(msg)
|
||||
cartographer.addMarkerSet(id, "AutoMiner " .. msg.name)
|
||||
cartographer.clearMarkerSet(id)
|
||||
|
||||
setPosMarker(msg)
|
||||
|
||||
local orePoints = {}
|
||||
for i, v in ipairs(msg.veins) do
|
||||
table.insert(orePoints, v.pos)
|
||||
cartographer.addPOIMarker(
|
||||
id, id .. "_vein_" .. i, v.count .. " " .. v.type, "Vein of " .. v.count .. " " .. v.type,
|
||||
v.pos.x, v.pos.y, v.pos.z,
|
||||
oreIcon(v.type))
|
||||
end
|
||||
|
||||
cartographer.addLineMarker(
|
||||
id, id .. "_vein_path", "Mining path #" .. msg.i, "Current mining path",
|
||||
"#FF00FF", 0.7, 3,
|
||||
orePoints)
|
||||
end
|
||||
|
||||
function handleVein(msg)
|
||||
local cMsg = {
|
||||
{text = msg.name, color = "green"},
|
||||
{text = " @ ", color = "white"},
|
||||
{text = vecToStr(msg.pos), color = "aqua"},
|
||||
{text = " is mining ", color = "white"},
|
||||
{text = tostring(msg.oreCount), color = "red"},
|
||||
{text = " ", color = "white"},
|
||||
{text = msg.oreType, color = "dark_purple"},
|
||||
{text = " (vein ", color = "white"},
|
||||
{text = tostring(msg.i), color = "red"},
|
||||
{text = " / ", color = "white"},
|
||||
{text = tostring(msg.total), color = "red"},
|
||||
{text = ")!", color = "white"},
|
||||
}
|
||||
local msgJSON = textutils.serializeJSON(cMsg)
|
||||
chat.sendFormattedMessageToPlayer(msgJSON, TARGET, "AutoMine")
|
||||
|
||||
local id = markerSet(msg)
|
||||
setPosMarker(msg)
|
||||
if msg.i ~= 1 then
|
||||
cartographer.removeMarker(id, id .. "_vein_" .. (msg.i - 1))
|
||||
end
|
||||
end
|
||||
|
||||
cartographer.refreshIntegrations()
|
||||
|
||||
modem.open(CHANNEL)
|
||||
|
||||
-- handleStart({
|
||||
-- i = 69,
|
||||
-- oreCount = 1337,
|
||||
-- veins = {
|
||||
-- {
|
||||
-- pos = {x = 297, y = 124, z = 1935},
|
||||
-- type = "minecraft:coal_ore",
|
||||
-- count = 12,
|
||||
-- },
|
||||
-- {
|
||||
-- pos = {x = 297, y = 134, z = 1935},
|
||||
-- type = "minecraft:iron_ore",
|
||||
-- count = 7,
|
||||
-- },
|
||||
-- {
|
||||
-- pos = {x = 400, y = 134, z = 1935},
|
||||
-- type = "minecraft:diamond_ore",
|
||||
-- count = 2,
|
||||
-- },
|
||||
-- {
|
||||
-- pos = {x = 400, y = 134, z = 1975},
|
||||
-- type = "minecraft:sussy_ore",
|
||||
-- count = 7,
|
||||
-- }
|
||||
-- },
|
||||
-- name = "test",
|
||||
-- pos = {x = 297, y = 154, z = 1935},
|
||||
-- })
|
||||
-- handleVein({
|
||||
-- i = 2,
|
||||
-- total = 69,
|
||||
-- oreCount = 1337,
|
||||
-- oreType = "minecraft:yeet",
|
||||
-- name = "test",
|
||||
-- pos = {x = 1, y = 2, z = 3},
|
||||
-- })
|
||||
-- assert(false)
|
||||
|
||||
while true do
|
||||
local event, side, channel, replyChannel, msg, distance = os.pullEvent("modem_message")
|
||||
if channel == CHANNEL then
|
||||
if msg.type == "iterationStart" then
|
||||
handleStart(msg)
|
||||
-- sendChat(msg.name.." found "..msg.oreCount.." ores ("..msg.veinCount.." veins)")
|
||||
-- for _, v in ipairs(msg.path) do
|
||||
-- print("vein path "..v.x..", "..v.y..", "..v.z)
|
||||
-- end
|
||||
elseif msg.type == "veinStart" then
|
||||
handleVein(msg)
|
||||
-- sendChat(msg.name.." is mining "..msg.count.." "..msg.oreType.." (vein "..msg.i..") @ "..msg.pos.x..", "..msg.pos.y..", "..msg.pos.z)
|
||||
end
|
||||
end
|
||||
end
|
134
tree.lua
Normal file
@ -0,0 +1,134 @@
|
||||
local dirt = "minecraft:dirt"
|
||||
local sapling = "minecraft:oak_sapling"
|
||||
local meal = "minecraft:bone_meal"
|
||||
local log = "minecraft:oak_log"
|
||||
local apple = "minecraft:apple"
|
||||
local stick = "minecraft:stick"
|
||||
local items = {
|
||||
sapling, meal, log, apple, stick
|
||||
}
|
||||
|
||||
local mealCount = 16
|
||||
|
||||
function selectItem(item)
|
||||
for i = 1, 16 do
|
||||
info = turtle.getItemDetail(i)
|
||||
if info and info.name == item then
|
||||
turtle.select(i)
|
||||
return i
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
Farmer = {}
|
||||
function Farmer:new(invName)
|
||||
local t = setmetatable({}, { __index = Farmer })
|
||||
t.invName = invName
|
||||
return t
|
||||
end
|
||||
|
||||
function Farmer:connectInv()
|
||||
local m = peripheral.find("modem")
|
||||
self.mName= m.getNameLocal()
|
||||
self.inv = peripheral.wrap(self.invName)
|
||||
end
|
||||
|
||||
function Farmer:unload(item)
|
||||
for i = 1, 16 do
|
||||
info = turtle.getItemDetail(i)
|
||||
if info and info.name == item then
|
||||
-- print(item, self.mName, i)
|
||||
self.inv.pullItems(self.mName, i)
|
||||
sleep(0.5)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function Farmer:yoink(item, count)
|
||||
for i, info in pairs(self.inv.list()) do
|
||||
if info.name == item then
|
||||
if info.count >= count then
|
||||
self.inv.pushItems(self.mName, i, count)
|
||||
sleep(0.5)
|
||||
return true
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
return false
|
||||
end
|
||||
|
||||
function Farmer:farmTree(noMeal)
|
||||
assert(turtle.turnRight())
|
||||
assert(turtle.turnRight())
|
||||
assert(turtle.forward())
|
||||
assert(turtle.forward())
|
||||
assert(turtle.down())
|
||||
|
||||
assert(selectItem(dirt))
|
||||
assert(turtle.place())
|
||||
assert(turtle.up())
|
||||
assert(selectItem(sapling))
|
||||
assert(turtle.place())
|
||||
|
||||
if noMeal then
|
||||
while true do
|
||||
local present, info = turtle.inspect()
|
||||
assert(present)
|
||||
if info.name == log then
|
||||
break
|
||||
end
|
||||
sleep(20)
|
||||
end
|
||||
else
|
||||
assert(selectItem(meal))
|
||||
local grown = false
|
||||
for i = 1, mealCount do
|
||||
turtle.place()
|
||||
sleep(1)
|
||||
local present, info = turtle.inspect()
|
||||
assert(present)
|
||||
if info.name == log then
|
||||
grown = true
|
||||
break
|
||||
end
|
||||
end
|
||||
if not grown then
|
||||
assert(false, "failed to grow tree")
|
||||
end
|
||||
end
|
||||
|
||||
turtle.select(1)
|
||||
assert(turtle.dig())
|
||||
assert(turtle.down())
|
||||
assert(turtle.dig())
|
||||
assert(turtle.up())
|
||||
sleep(5)
|
||||
assert(turtle.down())
|
||||
for i = 1, 8 do
|
||||
sleep(0.5)
|
||||
turtle.suck()
|
||||
end
|
||||
|
||||
assert(turtle.up())
|
||||
assert(turtle.turnRight())
|
||||
assert(turtle.turnRight())
|
||||
assert(turtle.forward())
|
||||
assert(turtle.forward())
|
||||
sleep(0.5)
|
||||
end
|
||||
|
||||
function Farmer:xchgItems()
|
||||
self:connectInv()
|
||||
for _, i in pairs(items) do
|
||||
self:unload(i)
|
||||
end
|
||||
assert(self:yoink(sapling, 1))
|
||||
return self:yoink(meal, mealCount)
|
||||
end
|
||||
|
||||
local f = Farmer:new("ae2:interface_0")
|
||||
while true do
|
||||
local noMeal = not f:xchgItems()
|
||||
f:farmTree(noMeal)
|
||||
end
|