AutoMine: Add recall mode and switch to rednet

This commit is contained in:
Jack O'Sullivan 2024-01-16 22:47:14 +00:00
parent e1e4ec871b
commit 50027f90b1
3 changed files with 190 additions and 168 deletions

120
mine.lua
View File

@ -321,7 +321,8 @@ local BLACKLIST = Set{
"advancedperipherals:chunk_controller", "advancedperipherals:chunk_controller",
} }
local FUEL = "minecraft:coal" local FUEL = "minecraft:coal"
local CHANNEL = 1337 local PROTOCOL = "automine"
local PROTOCOL_CTRL = "automineCtrl"
settings.define("mine.name", { settings.define("mine.name", {
description = "Miner name", description = "Miner name",
@ -365,8 +366,7 @@ function Miner.new()
self.scanner = peripheral.wrap("right") self.scanner = peripheral.wrap("right")
self:equip("computercraft:wireless_modem_advanced", "right") self:equip("computercraft:wireless_modem_advanced", "right")
self.modem = peripheral.wrap("right") rednet.open("right")
self.modem.open(CHANNEL)
self.pos = vector.new(0, 0, 0) self.pos = vector.new(0, 0, 0)
self:doGPS(true) self:doGPS(true)
@ -391,10 +391,11 @@ end
function Miner:sendMessage(type, msg) function Miner:sendMessage(type, msg)
self:equip("computercraft:wireless_modem_advanced", "right") self:equip("computercraft:wireless_modem_advanced", "right")
rednet.open("right")
msg["type"] = type msg["type"] = type
msg["name"] = self.name msg["name"] = self.name
msg["pos"] = self.absolutePos msg["pos"] = self.absolutePos
self.modem.transmit(CHANNEL, CHANNEL, msg) rednet.broadcast(msg, PROTOCOL)
end end
function Miner:dig(dir) function Miner:dig(dir)
@ -552,6 +553,22 @@ function Miner:navigateThrough(path)
end end
end end
function Miner:checkRecall()
local sender, msg = rednet.receive(PROTOCOL_CTRL, 0.5)
if sender and msg.type == "recall" then
-- HACK: Seems like we need this so the monitor can pick up the ack...
sleep(0.5)
self:sendMessage("ackRecall", msg)
local to = vector.new(msg.to.x, msg.to.y, msg.to.z)
print("Recalling to " .. to:tostring())
self:navigateThrough({self.pos + (to - self.absolutePos)})
return true
end
return false
end
function Miner:mineOres(radius) function Miner:mineOres(radius)
local startingDir = self.dir local startingDir = self.dir
self.pos = vector.new(0, 0, 0) self.pos = vector.new(0, 0, 0)
@ -590,6 +607,9 @@ function Miner:mineOres(radius)
oreCount = #ores, oreCount = #ores,
veins = veinsSummary, veins = veinsSummary,
}) })
if self:checkRecall() then
return false
end
for pi, i in ipairs(veinsPath) do for pi, i in ipairs(veinsPath) do
self:xchgItems() self:xchgItems()
@ -631,97 +651,21 @@ function Miner:mineOres(radius)
oreType = vein.type, oreType = vein.type,
oreCount = #vein.blocks, oreCount = #vein.blocks,
}) })
if self:checkRecall() then
return false
end
self:navigateThrough(veinPath) self:navigateThrough(veinPath)
end end
self:navigateThrough({veinsPoints[2]}) self:navigateThrough({veinsPoints[2]})
self:faceDir(startingDir) self:faceDir(startingDir)
self.i = self.i + 1 self.i = self.i + 1
return true
end end
local miner = Miner.new() local miner = Miner.new()
while true do local shouldRun = true
miner:mineOres(16) while shouldRun do
shouldRun = miner:mineOres(16)
end 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))

View File

@ -1,4 +1,4 @@
local CHANNEL = 1337 local PROTOCOL = "automine"
local TARGET = "devplayer0" local TARGET = "devplayer0"
local ICON_BASE = "https://p.nul.ie/cc/icon/" local ICON_BASE = "https://p.nul.ie/cc/icon/"
local ORE_ICONS = { local ORE_ICONS = {
@ -41,11 +41,6 @@ function oreIcon(t)
return ICON_BASE .. "ore-" .. i .. ".png" return ICON_BASE .. "ore-" .. i .. ".png"
end end
local modem = peripheral.find("modem")
-- local monitor = peripheral.find("monitor")
local chat = peripheral.find("chatBox")
local cartographer = peripheral.find("cartographer")
function vecToStr(v) function vecToStr(v)
return v.x .. "," .. v.y .. "," .. v.z return v.x .. "," .. v.y .. "," .. v.z
end end
@ -54,18 +49,60 @@ function markerSet(msg)
return "autominer_" .. msg.name return "autominer_" .. msg.name
end end
function setPosMarker(msg) Chat = {}
function Chat.new(prefix)
local self = setmetatable({}, { __index = Chat })
self.chat = peripheral.find("chatBox")
self.prefix = prefix
self.lastSend = 0
return self
end
function Chat:send(msg, target)
local delta = os.clock() - self.lastSend
if delta < 1 then
local amount = 1 - delta + 0.1
sleep(amount)
end
local msgJSON = textutils.serializeJSON(msg)
-- print(msgJSON)
if target then
assert(self.chat.sendFormattedMessageToPlayer(msgJSON, target, self.prefix))
else
assert(self.chat.sendFormattedMessage(msgJSON, self.prefix))
end
self.lastSend = os.clock()
end
MineMonitor = {}
function MineMonitor.new(chat)
local self = setmetatable({}, { __index = MineMonitor })
self.chat = chat
self.cart = peripheral.find("cartographer")
self.cart.refreshIntegrations()
peripheral.find("modem", rednet.open)
return self
end
function MineMonitor:setPosMarker(msg)
local id = markerSet(msg) local id = markerSet(msg)
local mId = id .. "_pos" local mId = id .. "_pos"
cartographer.removeMarker(id, mId) self.cart.removeMarker(id, mId)
cartographer.addPOIMarker( self.cart.addPOIMarker(
id, mId, msg.name, msg.name .. "'s position", id, mId, msg.name, msg.name .. "'s position",
msg.pos.x, msg.pos.y, msg.pos.z, msg.pos.x, msg.pos.y, msg.pos.z,
ICON_BASE .. "turtle.png") ICON_BASE .. "turtle.png")
end end
function handleStart(msg) function MineMonitor:handleStart(msg)
local cMsg = { self.chat:send({
{text = msg.name, color = "green"}, {text = msg.name, color = "green"},
{text = " @ ", color = "white"}, {text = " @ ", color = "white"},
{text = vecToStr(msg.pos), color = "aqua"}, {text = vecToStr(msg.pos), color = "aqua"},
@ -76,33 +113,33 @@ function handleStart(msg)
{text = " veins) on iteration ", color = "white"}, {text = " veins) on iteration ", color = "white"},
{text = tostring(msg.i), color = "green"}, {text = tostring(msg.i), color = "green"},
{text = "!", color = "white"}, {text = "!", color = "white"},
} })
local msgJSON = textutils.serializeJSON(cMsg)
chat.sendFormattedMessage(msgJSON, "AutoMine")
local id = markerSet(msg) local id = markerSet(msg)
cartographer.addMarkerSet(id, "AutoMiner " .. msg.name) self.cart.addMarkerSet(id, "AutoMiner " .. msg.name)
cartographer.clearMarkerSet(id) self.cart.clearMarkerSet(id)
setPosMarker(msg) self:setPosMarker(msg)
local orePoints = {} local veinPoints = {}
for i, v in ipairs(msg.veins) do for i, v in ipairs(msg.veins) do
table.insert(orePoints, v.pos) table.insert(veinPoints, v.pos)
cartographer.addPOIMarker( self.cart.addPOIMarker(
id, id .. "_vein_" .. i, v.count .. " " .. v.type, "Vein of " .. v.count .. " " .. v.type, id, id .. "_vein_" .. i, v.count .. " " .. v.type, "Vein of " .. v.count .. " " .. v.type,
v.pos.x, v.pos.y, v.pos.z, v.pos.x, v.pos.y, v.pos.z,
oreIcon(v.type)) oreIcon(v.type))
end end
cartographer.addLineMarker( if #veinPoints >= 2 then
id, id .. "_vein_path", "Mining path #" .. msg.i, "Current mining path", self.cart.addLineMarker(
"#FF00FF", 0.7, 3, id, id .. "_vein_path", "Mining path #" .. msg.i, "Current mining path",
orePoints) "#FF00FF", 0.7, 3,
veinPoints)
end
end end
function handleVein(msg) function MineMonitor:handleVein(msg)
local cMsg = { self.chat:send({
{text = msg.name, color = "green"}, {text = msg.name, color = "green"},
{text = " @ ", color = "white"}, {text = " @ ", color = "white"},
{text = vecToStr(msg.pos), color = "aqua"}, {text = vecToStr(msg.pos), color = "aqua"},
@ -115,71 +152,67 @@ function handleVein(msg)
{text = " / ", color = "white"}, {text = " / ", color = "white"},
{text = tostring(msg.total), color = "red"}, {text = tostring(msg.total), color = "red"},
{text = ")!", color = "white"}, {text = ")!", color = "white"},
} }, TARGET)
local msgJSON = textutils.serializeJSON(cMsg)
chat.sendFormattedMessageToPlayer(msgJSON, TARGET, "AutoMine")
local id = markerSet(msg) local id = markerSet(msg)
setPosMarker(msg) self:setPosMarker(msg)
if msg.i ~= 1 then if msg.i ~= 1 then
cartographer.removeMarker(id, id .. "_vein_" .. (msg.i - 1)) self.cart.removeMarker(id, id .. "_vein_" .. (msg.i - 1))
end end
end end
cartographer.refreshIntegrations() function MineMonitor:handleRecall(msg)
self.chat:send({
{text = msg.name, color = "green"},
{text = " @ ", color = "white"},
{text = vecToStr(msg.pos), color = "aqua"},
{text = " is recalling to ", color = "white"},
{text = vecToStr(msg.to), color = "green"},
{text = "!", color = "white"},
})
modem.open(CHANNEL) local id = markerSet(msg)
self.cart.addMarkerSet(id, "AutoMiner " .. msg.name)
self.cart.clearMarkerSet(id)
-- handleStart({ self:setPosMarker({
-- i = 69, name = msg.name,
-- oreCount = 1337, pos = msg.to,
-- veins = { })
-- { end
-- 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 function MineMonitor:loop()
local event, side, channel, replyChannel, msg, distance = os.pullEvent("modem_message") while true do
if channel == CHANNEL then local _, sender, msg = os.pullEvent("mine_monitor_message")
local handler = nil
if msg.type == "iterationStart" then if msg.type == "iterationStart" then
handleStart(msg) handler = self.handleStart
-- 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 elseif msg.type == "veinStart" then
handleVein(msg) handler = self.handleVein
-- sendChat(msg.name.." is mining "..msg.count.." "..msg.oreType.." (vein "..msg.i..") @ "..msg.pos.x..", "..msg.pos.y..", "..msg.pos.z) elseif msg.type == "ackRecall" then
handler = self.handleRecall
end
if handler then
handler(self, msg)
end end
end end
end end
function MineMonitor:netLoop()
while true do
local sender, msg = rednet.receive(PROTOCOL)
os.queueEvent("mine_monitor_message", sender, msg)
end
end
function MineMonitor:run()
parallel.waitForAll(
function() self:loop() end,
function() self:netLoop() end
)
end
local chat = Chat.new("AutoMine")
local mineMon = MineMonitor.new(chat)
mineMon:run()

45
mineRemote.lua Normal file
View File

@ -0,0 +1,45 @@
local PROTOCOL = "automine"
local PROTOCOL_CTRL = "automineCtrl"
function Set(list)
local set = {}
for _, l in ipairs(list) do set[l] = true end
return set
end
function awaitMessage(types, target)
while true do
local targetId, msg = rednet.receive(PROTOCOL)
if types[msg.type] and msg.name == target then
return targetId, msg
end
end
end
function run(target)
local x, y, z = gps.locate()
assert(x, "Couldn't run GPS")
local to = vector.new(math.floor(x), math.floor(y), math.floor(z))
print(target .. " will recall to " .. to:tostring())
print("Waiting for " .. target .. "...")
local targetId, msg = awaitMessage(Set{"iterationStart", "veinStart"}, target)
assert(targetId)
print("Sending recall request")
rednet.send(targetId, {
type = "recall",
to = to,
}, PROTOCOL_CTRL)
local _, msg = awaitMessage(Set{"ackRecall"}, target)
assert(msg)
print("Received confirmation of recall from " .. target )
end
if arg[1] then
rednet.open("back")
run(arg[1])
else
print("usage: " .. arg[0] .. " <target>")
end