ccminingturtle/mineleader.lua
Harrison Deng d95cae9caf Calculating heading returns heading message on success.
Status request now displays previously hidden heading information.
2021-05-03 15:33:13 -05:00

398 lines
9.6 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"
-- 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 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 and heading ~= nil) then
position = position + heading
end
return true
end
return false
end
local function attemptMoveBackward()
if attemptMove(turtle.back) then
relativePos = relativePos - relHeading
if (position ~= nil and heading ~= nil) then
position = position - heading
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 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 locatePosition()
sendLog(POSITION, "Using GPS to determine position.")
local x, y, z = gps.locate()
if x == nil then sendLog(POSITION, "could not locate.") end
position = vector.new(x, y, z)
sendLog(POSITION, "Position obtained: " .. tostring(position))
end
local function determineHeading()
sendLog(HEADING, "Calculating heading.")
if position == nil then
sendLog(FAILED, "No 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
if position == nil then
sendLog(FAILED, "Could not locate.")
return
end
local fDelta = position - oldPos
if not attemptMoveRight() then
sendLog(FAILED, "Unable to rotate right.")
return
end
local oldPos = vector.new(position.x, position.y, position.z)
if not attemptMoveForward() then
sendLog(FAILED, "Unable to move forward after rotation.")
return
end
if not attemptMoveLeft() then
sendLog(FAILED, "Unable to rotate left.")
return
end
heading = fDelta
rightAxis = position - oldPos
sendLog(HEADING, "Heading obtained. \nForward: " .. heading .. "\nRight direction: " .. 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 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, status)
elseif data["request"] == POSITION then
locatePosition()
elseif data["request"] == HEADING then
determineHeading()
elseif data["request"] == QUARRY then
end
end
end
end
parallel.waitForAll(listen, executeTasks)