turtle/libs/turtleutils.lua
2025-06-27 15:21:08 +01:00

236 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
if statusCallback then statusCallback("out_of_fuel") end
local x, y, z, gpsActive = M.getPosition()
local posText = gpsActive and
string.format("GPS (%d,%d,%d)", x, y, z) or
string.format("Manual (%d,%d,%d)", x, y, z)
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