Initial commit

This commit is contained in:
Jack O'Sullivan 2024-01-15 13:14:17 +00:00
commit e1e4ec871b
27 changed files with 1352 additions and 0 deletions

232
PriorityQueue.lua Normal file
View 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
View 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

Binary file not shown.

1
datapack/.gitignore vendored Normal file
View File

@ -0,0 +1 @@
*.zip

View File

@ -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
View File

@ -0,0 +1,6 @@
{
"pack": {
"pack_format": 15,
"description": "Enchanted pickaxe for ComputerCraft"
}
}

BIN
icon/ore-coal.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 623 B

BIN
icon/ore-copper.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 653 B

BIN
icon/ore-diamond.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 625 B

BIN
icon/ore-ds-coal.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 613 B

BIN
icon/ore-ds-copper.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 636 B

BIN
icon/ore-ds-diamond.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 641 B

BIN
icon/ore-ds-emerald.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 636 B

BIN
icon/ore-ds-gold.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 615 B

BIN
icon/ore-ds-iron.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 624 B

BIN
icon/ore-ds-lapis.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 661 B

BIN
icon/ore-ds-redstone.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 715 B

BIN
icon/ore-emerald.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 634 B

BIN
icon/ore-generic.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

BIN
icon/ore-gold.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 633 B

BIN
icon/ore-iron.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 615 B

BIN
icon/ore-lapis.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 676 B

BIN
icon/ore-redstone.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 644 B

BIN
icon/turtle.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.5 KiB

727
mine.lua Normal file
View 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
View 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
View 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