--configurables local CHANNEL = 55555 local TOKEN = "LxdIjZPDLL2oZoayb7uR2Lbz7bnnbkxz" -- Constant local HOST = "HOST" local UNIT = "LEAD" local LUA_PREFIX = "?" -- Constant actions local MOVEBY = "moveby" local MOVETO = "moveto" local STATUS = "status" local POSITION = "position" local HEADING = "heading" local QUARRYCHUNK = "quarry" local TASK = "task" local FAILED = "failed" -- Constant messaging local LOG = "LOG" local REQUEST = "REQ" -- Constant requests local BLOCKED = "blocked" local ITEM = "item" -- avoid breaking pattern local notPattern = "^allthemodium" -- INIT SEQUENCE print("Initiating leader mining turtle.") running = true local task = nil local taskArgs = {} local modem = nil local heading = nil local position = nil local rightAxis = nil local relHeading = vector.new(1,0,0) local relativePos = vector.new(0,0,0) local relRightAxis = vector.new(0,0,1) do periphs = peripheral.find("modem") if not periphs then error("Modem peripheral not found.") else print("Modem found.") modem = periphs end end print("Opening channel: " .. CHANNEL) modem.open(CHANNEL) -- helpers local function getMessage(data) if string.find(data, TOKEN .. ":") == 1 then print("Validated data token.") local validated = string.sub(data, string.len(TOKEN) + 1 + 1) print("Validated sequence: " .. validated) if string.find(validated, UNIT .. ":") == 1 then print("Checking unit...") return string.sub(validated, string.len(UNIT) + 1 + 1) end end print("Data was unable to be parsed.") return nil end local function SendRequest(request, ...) print("Sending request: " .. request) reqData = { token=TOKEN, recipient=HOST, sender=UNIT, type=REQUEST, request=request, content=arg } modem.transmit(CHANNEL, CHANNEL, textutils.serialise(reqData)) end local function sendLog(log, ...) print("Sending message: " .. log) logData = { token=TOKEN, recipient=HOST, sender=UNIT, type=LOG, log=log, content=arg } modem.transmit(CHANNEL, CHANNEL, textutils.serialise(logData)) end local function captureString(str, seq) if seq == nil then seq = "([^%s]+)" end res = {} for i in string.gmatch(str, seq) do table.insert(res, i) end return res end local function findItem(str) for s=1,16 do if string.sub(str, -string.len(str)) == str then return s end end return 0 end local function refuel() local slot = findItem("coal") if slot == 0 then --TODO: request more coal end turtle.select(slot) turtle.refuel() end local function checkFuel() if turtle.getFuelLevel() > 0 then return false end refuel() return true; end local function vectorEqual(a, b) return a.x == b.x and a.y == b.y and a.z == b.z end local function attemptMove(movef) if not movef() then refuel() return movef(); end return true end local function attemptBreak(breakf, inspectf, notPattern) local exists, data = inspectf() if not exists then return false end if string.match(data.name, pattern) then return false end breakf() end local function locatePosition() local x, y, z = gps.locate() if x == nil then return false end position = vector.new(x, y, z) return true end local function attemptMoveUp() if attemptMove(turtle.up) then relativePos.y = relativePos.y + 1 if position ~= nil then position.y = position.y + 1 end return true end return false end local function attemptMoveDown() if attemptMove(turtle.down) then relativePos.y = relativePos.y - 1 if position ~= nil then position.y = position.y - 1 end return true end return false end local function attemptMoveForward() if attemptMove(turtle.forward) then relativePos = relativePos + relHeading if (position ~= nil) then if ( heading ~= nil ) then position = position + heading else locatePosition() end end return true end return false end local function attemptMoveBackward() if attemptMove(turtle.back) then relativePos = relativePos - relHeading if (position ~= nil) then if (heading ~= nil) then position = position - heading else locatePosition() end end return true end return false end local function attemptMoveLeft() if attemptMove(turtle.turnLeft) then local previousHeading = relHeading relHeading = -relRightAxis relRightAxis = previousHeading if heading ~= nil then local previousHeading = heading heading = -rightAxis rightAxis = previousHeading end return true end return false end local function attemptMoveRight() if attemptMove(turtle.turnRight) then local previousHeading = relHeading relHeading = relRightAxis relRightAxis = -previousHeading if heading ~= nil then local previousHeading = heading heading = rightAxis rightAxis = -previousHeading end return true end return true end local function attemptBreakUp(notPattern) return attemptBreak(turtle.digUp, turtle.inspectUp, notPattern); end local function attemptBreakFront(notPattern) return attemptBreak(turtle.dig, turtle.inspect, notPattern) end local function attemptBreakDown(notPattern) return attemptBreak(turtle.digDown, turtle.inspectDown, notPattern) end local function orient(v, forward, right) print("Attempting to orient such that " .. tostring(v) .. " == " .. tostring(forward) .. ".") if vectorEqual(v, forward) then return elseif vectorEqual(v, right) then attemptMoveRight() elseif vectorEqual(v, -right) then attemptMoveLeft() else attemptMoveRight() attemptMoveRight() end print("Orientation complete.") end local function attemptStartTask(name, f, ...) sendLog(TASK, "Attempting to start task.") if task ~= nil then sendLog(FAILED, "Unable to start task due to another task running.") return end task = {name=name, func=f, args=arg} taskArgs = arg end -- Actions local function determinePosition() if not locatePosition() then sendLog(FAILED, "Unable to obtain GPS based position.") return end sendLog(POSITION, "Position obtained: " .. tostring(position)) end local function determineHeading() sendLog(HEADING, "Calculating heading.") if position == nil and locatePosition() then sendLog(FAILED, "Unable to get current position.") return end local oldPos = vector.new(position.x, position.y, position.z) if not attemptMoveForward() then sendLog(FAILED, "Could not move to get delta.") return end local fDelta = position - oldPos if not attemptMoveBackward() then sendLog(FAILED, "Could not return to original position after first axis.") return end if not attemptMoveRight() then sendLog(FAILED, "Unable to rotate right.") return end if not attemptMoveForward() then sendLog(FAILED, "Unable to move forward after rotation.") return end local rDelta = position - oldPos if not attemptMoveBackward() then sendLog(FAILED, "Could not return to original position after second axis.") return end if not attemptMoveLeft() then sendLog(FAILED, "Unable to rotate left.") return end heading = fDelta rightAxis = rDelta sendLog(HEADING, "Heading obtained. \nForward: " .. textutils.serialiseJSON(heading) .. "\nRight direction: " .. textutils.serialiseJSON(rightAxis)) end local function moveBy(delta, forward, right) sendLog(MOVEBY, "Attempting to move by (" .. delta.x .. "," .. delta.y .. "," .. delta.z .. ") (x,y,z).") -- x first if delta.x ~= 0 then sendLog(MOVEBY, "Moving on x axis by: " .. delta.x) orient(vector.new(delta.x, 0, 0):normalize(), forward, right) for x=1,math.abs(delta.x) do attemptMoveForward() end end if delta.z ~= 0 then sendLog(MOVEBY, "Moving on z axis by: " .. delta.z) orient(vector.new(0, 0, delta.z):normalize(), forward, right) for z=1,math.abs(delta.z) do attemptMoveForward() end end if delta.y > 0 then sendLog(MOVEBY, "Moving on y axis by: " .. delta.y) for y=1,delta.y do attemptMoveUp() end elseif delta.y < 0 then sendLog(MOVEBY, "Moving on y axis by: " .. delta.y) for y=1,math.abs(delta.y) do attemptMoveDown() end end end local function moveTo(dest, range) sendLog(MOVETO, "Attempting to move by (" .. dest.x .. "," .. dest.y .. "," .. dest.z .. ") (x,y,z).") if position == nil or heading == nil then sendLog(FAILED, "Position or heading is invalid.") end local xBlocked, yBlocked, zBlocked = false, false, false local oldPos = nil while not vectorEqual(dest, position) do if vectorEqual(oldPos, position) then sendLog(FAILED, "Cannot proceed to due obstacle.") return end oldPos = vector.new(position.x, position.y, position.z); if position.x ~= dest.x then if not orient(vector.new(dest.x - position.x, 0, 0), heading, rightAxis) then sendLog(FAILED, "Unable to orient for X axis.") return end attemptMoveForward() end if position.y ~= dest.y then if dest.y - position.y > 0 then attemptMoveUp() else attemptMoveDown() end end if position.z ~= dest.z then if not orient(vector.new(0, 0, dest.z - position.z), heading, rightAxis) then sendLog(FAILED, "Unable to orient for Z axis.") return end attemptMoveForward() end end end local function quarry(a, b) sendLog(QUARRY, "Starting quarry task from positions " .. tostring(a) .. " to " .. tostring(b) ".") end local function executeTasks() while running do if task ~= nil then sendLog(TASK, "Executing task: " .. task["name"]) task["func"](unpack(task["args"])) task = nil end sleep(5) end end local function listen() while running do print("Listening for directives...") local event, side, sendChannel, replyChannel, serialized, distance = os.pullEvent("modem_message") print("Recieved data...") local data = textutils.unserialise(serialized) if data["token"] == TOKEN and data["recipient"] == UNIT and data["type"] == REQUEST then print("Got request: " .. data["request"]) if data["request"] == LUA_PREFIX then print("Executing: " .. data["content"][0]) local f = loadstring(luaScript) if f ~= nil then local freturn = f() if freturn ~= nil then sendLog(LUA_PREFIX, textutils.serialise(freturn)) end else printError("Unable to load lua string.") end elseif data["request"] == MOVETO then local x = data["content"][1] local y = data["content"][2] local z = data["content"][3] if heading ~= nil then print("Using actual coordinates.") sendLog(MOVETO, "Using actual coordinates to move.") attemptStartTask(MOVETO, moveTo, vector.new(x,y,z), heading, rightAxis) else print("Using relative coordinates.") sendLog(MOVETO, "Using relative coordinates to move.") attemptStartTask(MOVETO, moveTo, vector.new(x,y,z), relHeading, relRightAxis) end elseif data["request"] == MOVEBY then local x = data["content"][1] local y = data["content"][2] local z = data["content"][3] if heading ~= nil then print("Using actual coordinates.") sendLog(MOVEBY, "Using actual coordinates to move.") attemptStartTask(MOVEBY, moveBy, vector.new(x,y,z), heading, rightAxis) else print("Using relative coordinates.") sendLog(MOVEBY, "Using relative coordinates to move.") attemptStartTask(MOVEBY, moveBy, vector.new(x,y,z), relHeading, relRightAxis) end elseif data["request"] == STATUS then status = { relative_position = { coordinates=relativePos, forward=relHeading, right=relRightAxis }, position={ coordinates=position, forward=heading, right=rightAxis }, fuel=turtle.getFuelLevel(), task=(task and task["name"] or "nothing") } sendLog(STATUS, "Relative position: " .. textutils.serializeJSON(status["relative_position"]) .. "\nPosition: " .. (status["position"]["coordinates"] and textutils.serialiseJSON(status["position"]) or "not positioned.") .. "\nfuel: " .. tostring(status["fuel"]) .. "\ncurrent task: " .. status["task"], status) elseif data["request"] == POSITION then determinePosition() elseif data["request"] == HEADING then determineHeading() elseif data["request"] == QUARRY then end end end end parallel.waitForAll(listen, executeTasks)