239 lines
6.5 KiB
Lua
239 lines
6.5 KiB
Lua
local M = {}
|
|
|
|
local logger = require("libs.logger")
|
|
|
|
-- Optional external status setter (set via M.setStatusCallback)
|
|
local statusCallback = nil
|
|
function M.setStatusCallback(fn) statusCallback = fn end
|
|
|
|
-- Position tracking state for manual mode
|
|
local manualPos = { x = 0, y = 0, z = 0 }
|
|
local directions = { "north", "east", "south", "west" }
|
|
local facing = 1
|
|
|
|
-- GPS attempt
|
|
local function tryGPS()
|
|
local x, y, z = gps.locate(2) -- 2 second timeout
|
|
if x and y and z then
|
|
return { x = math.floor(x), y = math.floor(y), z = math.floor(z) }
|
|
end
|
|
return nil
|
|
end
|
|
|
|
-- Manual position update helpers
|
|
local function updatePositionOnMove(direction)
|
|
if direction == "forward" then
|
|
if directions[facing] == "north" then manualPos.z = manualPos.z - 1
|
|
elseif directions[facing] == "south" then manualPos.z = manualPos.z + 1
|
|
elseif directions[facing] == "east" then manualPos.x = manualPos.x + 1
|
|
elseif directions[facing] == "west" then manualPos.x = manualPos.x - 1 end
|
|
elseif direction == "back" then
|
|
if directions[facing] == "north" then manualPos.z = manualPos.z + 1
|
|
elseif directions[facing] == "south" then manualPos.z = manualPos.z - 1
|
|
elseif directions[facing] == "east" then manualPos.x = manualPos.x - 1
|
|
elseif directions[facing] == "west" then manualPos.x = manualPos.x + 1 end
|
|
elseif direction == "up" then manualPos.y = manualPos.y + 1
|
|
elseif direction == "down" then manualPos.y = manualPos.y - 1 end
|
|
end
|
|
|
|
local function updateFacingLeft()
|
|
facing = facing - 1
|
|
if facing < 1 then facing = 4 end
|
|
end
|
|
|
|
local function updateFacingRight()
|
|
facing = facing + 1
|
|
if facing > 4 then facing = 1 end
|
|
end
|
|
|
|
-- Public function to get current position (GPS or manual)
|
|
function M.getPosition()
|
|
local gpsPos = tryGPS()
|
|
if gpsPos then
|
|
return gpsPos.x, gpsPos.y, gpsPos.z, true
|
|
else
|
|
return manualPos.x, manualPos.y, manualPos.z, false
|
|
end
|
|
end
|
|
|
|
-- Minimum fuel required to proceed with one movement
|
|
local MIN_FUEL = 1
|
|
|
|
-- Attempt to refuel from inventory
|
|
local function refuelFromInventory(minRequired)
|
|
minRequired = minRequired or MIN_FUEL
|
|
local gained = 0
|
|
|
|
for slot = 1, 16 do
|
|
turtle.select(slot)
|
|
if turtle.getItemCount() > 0 and turtle.refuel(0) then
|
|
local before = turtle.getFuelLevel()
|
|
if turtle.refuel(1) then
|
|
local after = turtle.getFuelLevel()
|
|
local added = after - before
|
|
gained = gained + added
|
|
logger.log(string.format("Refueled +%d from slot %d", added, slot))
|
|
if after >= minRequired then break end
|
|
else
|
|
logger.log(string.format("Refuel failed from slot %d", slot))
|
|
end
|
|
end
|
|
end
|
|
|
|
return gained
|
|
end
|
|
|
|
-- Ensure fuel before doing anything
|
|
local function refuelIfNeeded()
|
|
local fuel = turtle.getFuelLevel()
|
|
if fuel == "unlimited" then return true end
|
|
|
|
if fuel < MIN_FUEL then
|
|
logger.log("Low fuel, attempting to refuel...")
|
|
local added = refuelFromInventory(MIN_FUEL)
|
|
fuel = turtle.getFuelLevel()
|
|
end
|
|
|
|
while fuel < MIN_FUEL do
|
|
|
|
local x, y, z, gpsActive = M.getPosition()
|
|
local posText = gpsActive and
|
|
string.format("GPS (%d,%d,%d)", x, y, z) or
|
|
string.format("Travelled: (%d,%d,%d)", x, y, z)
|
|
|
|
if statusCallback then
|
|
statusCallback("out_of_fuel - " .. posText)
|
|
end
|
|
|
|
logger.log("No fuel. Waiting for fuel... Location: " .. posText)
|
|
sleep(5)
|
|
|
|
local added = refuelFromInventory(MIN_FUEL)
|
|
fuel = turtle.getFuelLevel()
|
|
end
|
|
|
|
return true
|
|
end
|
|
|
|
-- Retry a movement or action with fuel awareness
|
|
local function try(actionFn, times, name)
|
|
times = times or 5
|
|
for i = 1, times do
|
|
if not refuelIfNeeded() then
|
|
sleep(2)
|
|
elseif actionFn() then
|
|
if name then logger.log("Action succeeded: " .. name) end
|
|
return true
|
|
end
|
|
if name then logger.log("Retrying: " .. name) end
|
|
sleep(0.5)
|
|
end
|
|
if name then logger.log("Gave up after retries: " .. name) end
|
|
return false
|
|
end
|
|
|
|
-- Movement wrappers that update manual position and use try()
|
|
function M.forward()
|
|
local function action() return turtle.forward() end
|
|
local result = try(action, 5, "forward")
|
|
if result then updatePositionOnMove("forward") end
|
|
return result
|
|
end
|
|
|
|
function M.back()
|
|
local function action() return turtle.back() end
|
|
local result = try(action, 5, "back")
|
|
if result then updatePositionOnMove("back") end
|
|
return result
|
|
end
|
|
|
|
function M.up()
|
|
local function action() return turtle.up() end
|
|
local result = try(action, 5, "up")
|
|
if result then updatePositionOnMove("up") end
|
|
return result
|
|
end
|
|
|
|
function M.down()
|
|
local function action() return turtle.down() end
|
|
local result = try(action, 5, "down")
|
|
if result then updatePositionOnMove("down") end
|
|
return result
|
|
end
|
|
|
|
-- Digging functions (not wrapped in try, but you can add if you want)
|
|
function M.digForward()
|
|
while turtle.detect() do
|
|
turtle.dig()
|
|
sleep(0.3)
|
|
logger.log("Dug block in front")
|
|
end
|
|
end
|
|
|
|
function M.digUp()
|
|
while turtle.detectUp() do
|
|
turtle.digUp()
|
|
sleep(0.3)
|
|
logger.log("Dug block above")
|
|
end
|
|
end
|
|
|
|
function M.digDown()
|
|
while turtle.detectDown() do
|
|
turtle.digDown()
|
|
sleep(0.3)
|
|
logger.log("Dug block below")
|
|
end
|
|
end
|
|
|
|
-- Move forward clearing blocks as needed
|
|
function M.moveUntilClearForward()
|
|
logger.log("Attempting to move forward (auto-clear)")
|
|
while not M.forward() do
|
|
if turtle.detect() then
|
|
M.digForward()
|
|
else
|
|
sleep(0.5)
|
|
end
|
|
end
|
|
logger.log("Moved forward")
|
|
end
|
|
|
|
-- Inspection
|
|
function M.inspectForward()
|
|
local success, data = turtle.inspect()
|
|
if success then return data else return nil end
|
|
end
|
|
|
|
function M.inspectUp()
|
|
local success, data = turtle.inspectUp()
|
|
if success then return data else return nil end
|
|
end
|
|
|
|
function M.inspectDown()
|
|
local success, data = turtle.inspectDown()
|
|
if success then return data else return nil end
|
|
end
|
|
|
|
-- Turning functions that update facing
|
|
function M.turnLeft()
|
|
turtle.turnLeft()
|
|
updateFacingLeft()
|
|
logger.log("Turned left")
|
|
end
|
|
|
|
function M.turnRight()
|
|
turtle.turnRight()
|
|
updateFacingRight()
|
|
logger.log("Turned right")
|
|
end
|
|
|
|
function M.turnAround()
|
|
turtle.turnLeft()
|
|
turtle.turnLeft()
|
|
updateFacingLeft()
|
|
updateFacingLeft()
|
|
logger.log("Turned around")
|
|
end
|
|
|
|
return M |