ccminingturtle/mineleader.lua

533 lines
14 KiB
Lua

--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 QUARRY = "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 true
elseif vectorEqual(v, right) then
return attemptMoveRight()
elseif vectorEqual(v, -right) then
return attemptMoveLeft()
else
return attemptMoveRight() and attemptMoveRight()
end
return false
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
if not attemptMoveForward() then
sendLog(FAILED, "Unable to move forward.")
return
end
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
if not attemptMoveForward() then
sendLog(FAILED, "Unable to move forward.")
return
end
end
end
if delta.y > 0 then
sendLog(MOVEBY, "Moving on y axis by: " .. delta.y)
for y=1,delta.y do
if not attemptMoveUp() then
sendLog(FAILED, "Unable to move up.")
return
end
end
elseif delta.y < 0 then
sendLog(MOVEBY, "Moving on y axis by: " .. delta.y)
for y=1,math.abs(delta.y) do
if not attemptMoveDown() then
sendLog(FAILED, "Unable to move down.")
return
end
end
end
end
local function moveTo(dest)
dest = vector.new(math.floor(dest.x), math.floor(dest.y), math.floor(dest.z))
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.")
return
end
local xBlocked, yBlocked, zBlocked = false, false, false
local oldPos = nil
while not vectorEqual(dest, position) do
if oldPos ~= nil and vectorEqual(oldPos, position) then
sendLog(FAILED, "Cannot proceed to due obstacle. XYZ being blocked: " .. xBlocked .. "," .. yBlocked .. "," .. zBlocked)
break
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):normalize(), heading, rightAxis) then
sendLog(FAILED, "Unable to orient for X axis.")
return
end
xblocked = attemptMoveForward()
end
if position.y ~= dest.y then
if dest.y - position.y > 0 then
yBlocked = attemptMoveUp()
else
yBlocked = attemptMoveDown()
end
end
if position.z ~= dest.z then
if not orient(vector.new(0, 0, dest.z - position.z):normalize(), heading, rightAxis) then
sendLog(FAILED, "Unable to orient for Z axis.")
return
end
zBlocked = attemptMoveForward()
end
end
end
local function quarry(x, y, z, forward, right, pattern)
x = tonumber(x)
y = tonumber(y)
z = tonumber(z)
sendLog(QUARRY, "Starting quarry of (x length,depth,z length): " .. x .. "," .. y .. "," .. z)
for yDelta=1,math.abs(y) do
for xDelta=1,math.abs(x) do
for zDelta=1,math.abs(z) do
orient(vector.new(0, 0, z), forward, right)
attemptBreakUp(pattern)
attemptBreakDown(pattern)
attemptBreakFront(pattern)
attemptMoveForward()
end
orient(vector.new(x, 0, 0), forward, right)
attemptMoveForward()
end
if (y > 0) then
attemptMoveUp();
else
if not attemptMoveDown() then
sendLog(FAILED, "Unable to move further down for quarrying.")
end
end
end
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 = nil
if not pcall(function() data = textutils.unserialise(serialized) end) then
print("Message already table, not deserializing.")
data = serialized
end
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
if heading ~= nil then
quarry(data["content"][1], data["content"][2], data["content"][3], heading, rightAxis)
sendLog(QUARRY, "Using actual position for quarrying.")
else
sendLog(QUARRY, "Using relative position for quarrying.")
quarry(data["content"][1], data["content"][2], data["content"][3], relHeading, relRightAxis)
end
end
end
end
end
parallel.waitForAll(listen, executeTasks)