From 50027f90b11bc750ae3406c5499fd2d77d2f1b7d Mon Sep 17 00:00:00 2001 From: Jack O'Sullivan Date: Tue, 16 Jan 2024 22:47:14 +0000 Subject: [PATCH] AutoMine: Add recall mode and switch to rednet --- mine.lua | 120 ++++++++---------------------- mineMonitor.lua | 193 ++++++++++++++++++++++++++++-------------------- mineRemote.lua | 45 +++++++++++ 3 files changed, 190 insertions(+), 168 deletions(-) create mode 100644 mineRemote.lua diff --git a/mine.lua b/mine.lua index 5ce3764..4c30432 100644 --- a/mine.lua +++ b/mine.lua @@ -321,7 +321,8 @@ local BLACKLIST = Set{ "advancedperipherals:chunk_controller", } local FUEL = "minecraft:coal" -local CHANNEL = 1337 +local PROTOCOL = "automine" +local PROTOCOL_CTRL = "automineCtrl" settings.define("mine.name", { description = "Miner name", @@ -365,8 +366,7 @@ function Miner.new() self.scanner = peripheral.wrap("right") self:equip("computercraft:wireless_modem_advanced", "right") - self.modem = peripheral.wrap("right") - self.modem.open(CHANNEL) + rednet.open("right") self.pos = vector.new(0, 0, 0) self:doGPS(true) @@ -391,10 +391,11 @@ end function Miner:sendMessage(type, msg) self:equip("computercraft:wireless_modem_advanced", "right") + rednet.open("right") msg["type"] = type msg["name"] = self.name msg["pos"] = self.absolutePos - self.modem.transmit(CHANNEL, CHANNEL, msg) + rednet.broadcast(msg, PROTOCOL) end function Miner:dig(dir) @@ -552,6 +553,22 @@ function Miner:navigateThrough(path) 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) local startingDir = self.dir self.pos = vector.new(0, 0, 0) @@ -590,6 +607,9 @@ function Miner:mineOres(radius) oreCount = #ores, veins = veinsSummary, }) + if self:checkRecall() then + return false + end for pi, i in ipairs(veinsPath) do self:xchgItems() @@ -631,97 +651,21 @@ function Miner:mineOres(radius) oreType = vein.type, oreCount = #vein.blocks, }) + if self:checkRecall() then + return false + end + self:navigateThrough(veinPath) end self:navigateThrough({veinsPoints[2]}) self:faceDir(startingDir) self.i = self.i + 1 + return true end local miner = Miner.new() -while true do - miner:mineOres(16) +local shouldRun = true +while shouldRun do + shouldRun = 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)) diff --git a/mineMonitor.lua b/mineMonitor.lua index 37e347d..fbab231 100644 --- a/mineMonitor.lua +++ b/mineMonitor.lua @@ -1,4 +1,4 @@ -local CHANNEL = 1337 +local PROTOCOL = "automine" local TARGET = "devplayer0" local ICON_BASE = "https://p.nul.ie/cc/icon/" local ORE_ICONS = { @@ -41,11 +41,6 @@ function oreIcon(t) 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 @@ -54,18 +49,60 @@ function markerSet(msg) return "autominer_" .. msg.name 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 mId = id .. "_pos" - cartographer.removeMarker(id, mId) - cartographer.addPOIMarker( + self.cart.removeMarker(id, mId) + self.cart.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 = { +function MineMonitor:handleStart(msg) + self.chat:send({ {text = msg.name, color = "green"}, {text = " @ ", color = "white"}, {text = vecToStr(msg.pos), color = "aqua"}, @@ -76,33 +113,33 @@ function handleStart(msg) {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) + self.cart.addMarkerSet(id, "AutoMiner " .. msg.name) + self.cart.clearMarkerSet(id) - setPosMarker(msg) + self:setPosMarker(msg) - local orePoints = {} + local veinPoints = {} for i, v in ipairs(msg.veins) do - table.insert(orePoints, v.pos) - cartographer.addPOIMarker( + table.insert(veinPoints, v.pos) + self.cart.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) + if #veinPoints >= 2 then + self.cart.addLineMarker( + id, id .. "_vein_path", "Mining path #" .. msg.i, "Current mining path", + "#FF00FF", 0.7, 3, + veinPoints) + end end -function handleVein(msg) - local cMsg = { +function MineMonitor:handleVein(msg) + self.chat:send({ {text = msg.name, color = "green"}, {text = " @ ", color = "white"}, {text = vecToStr(msg.pos), color = "aqua"}, @@ -115,71 +152,67 @@ function handleVein(msg) {text = " / ", color = "white"}, {text = tostring(msg.total), color = "red"}, {text = ")!", color = "white"}, - } - local msgJSON = textutils.serializeJSON(cMsg) - chat.sendFormattedMessageToPlayer(msgJSON, TARGET, "AutoMine") + }, TARGET) local id = markerSet(msg) - setPosMarker(msg) + self:setPosMarker(msg) if msg.i ~= 1 then - cartographer.removeMarker(id, id .. "_vein_" .. (msg.i - 1)) + self.cart.removeMarker(id, id .. "_vein_" .. (msg.i - 1)) 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({ --- 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) + self:setPosMarker({ + name = msg.name, + pos = msg.to, + }) +end -while true do - local event, side, channel, replyChannel, msg, distance = os.pullEvent("modem_message") - if channel == CHANNEL then +function MineMonitor:loop() + while true do + local _, sender, msg = os.pullEvent("mine_monitor_message") + local handler = nil 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 + handler = self.handleStart 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) + handler = self.handleVein + elseif msg.type == "ackRecall" then + handler = self.handleRecall + end + + if handler then + handler(self, msg) 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() diff --git a/mineRemote.lua b/mineRemote.lua new file mode 100644 index 0000000..7e524b8 --- /dev/null +++ b/mineRemote.lua @@ -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] .. " ") +end