local M = {} local logger = require("libs.logger") -- Optional external status setter (set via M.setStatusCallback) -- Status callback 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 -- you can raise this if you want a safety margin -- 🔋 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 logger.log("No fuel. Waiting for fuel...") sleep(5) -- Try to refuel again 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 function M.forward() if turtle.forward() then updatePositionOnMove("forward") return true else return false end end function M.back() if turtle.back() then updatePositionOnMove("back") return true else return false end end function M.up() if turtle.up() then updatePositionOnMove("up") return true else return false end end function M.down() if turtle.down() then updatePositionOnMove("down") return true else return false end end -- Digging with movement function M.digForward() while turtle.detect() do turtle.dig() sleep(0.3) end end function M.digUp() while turtle.detectUp() do turtle.digUp() sleep(0.3) end end function M.digDown() while turtle.detectDown() do turtle.digDown() sleep(0.3) end end -- Move forward, clearing blocks if necessary function M.moveUntilClearForward() while not turtle.forward() do if turtle.detect() then turtle.dig() else sleep(0.5) end end 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 direction function M.turnLeft() turtle.turnLeft() updateFacingLeft() end function M.turnRight() turtle.turnRight() updateFacingRight() end function M.turnAround() turtle.turnLeft() turtle.turnLeft() updateFacingLeft() updateFacingLeft() end return M