------------------------------------------------------------ -- Advanced Chunk Miner (single-file) -- - Turtle starts in the SOUTH-WEST corner, facing NORTH. -- - Chest is directly SOUTH (behind the turtle) at (0, startY, 1). -- - Prompts for number of layers to mine (C option). -- Features: -- * Tag-based ore detection (forge:ores) with name fallback -- * Ore logging to "ore_log.txt" -- * Robust drop-off & refuel routine (returns to chest, dumps, returns) -- * State save/restore (resume) to "miner_state" -- * Optional torch placement every TORCH_INTERVAL steps (0 to disable) -- * Will attempt to bypass ore blocks (move up-forward-down) to preserve them ------------------------------------------------------------ -- ============ USER CONFIG ============= local WIDTH = 16 local LENGTH = 16 local TORCH_INTERVAL = 0 -- set >0 to place torch every N forward steps (placeUp) local AUTO_CHEST = false -- not implemented auto-place; left as future hook local STATE_FILE = "miner_state" local ORE_LOG = "ore_log.txt" local startY = 0 -- Turtle starts facing NORTH in SW corner -- Coordinates system: x increases East, z increases South, y increases up local x, y, z = 0, startY, 0 local dir = 0 -- 0 = north, 1 = east, 2 = south, 3 = west -- Chest is directly SOUTH behind start: (0, startY, 1) local chestX, chestY, chestZ = 0, startY, 1 local chestFaceDir = 0 -- to interact with chest we should face north (0) when at chest pos -- ============ UTIL: persistence & logging ============ local function saveState(t) local ok, err local f = fs.open(STATE_FILE, "w") if not f then print("Warning: can't open state file for writing.") return end f.write(textutils.serialize(t)) f.close() end local function loadState() if not fs.exists(STATE_FILE) then return nil end local f = fs.open(STATE_FILE, "r") if not f then return nil end local content = f.readAll() f.close() local ok, data = pcall(textutils.unserialize, content) if ok then return data end return nil end local function appendOreLog(s) local f = fs.open(ORE_LOG, "a") if not f then print("Warning: couldn't open ore log.") return end f.writeLine(s) f.close() end -- ============ MOVEMENT HELPERS (update x,y,z,dir) ============ local function turnRight() turtle.turnRight() dir = (dir + 1) % 4 end local function turnLeft() turtle.turnLeft() dir = (dir + 3) % 4 end local function faceDirection(target) while dir ~= target do turnRight() end end -- safer forward: tries to avoid digging ores by inspecting first. -- if blocked by ore, attempts up(); forward(); down() bypass. If bypass fails, will dig non-ore blocks. local function forwardSafe() -- quick attempt if turtle.forward() then if dir == 0 then z = z - 1 elseif dir == 1 then x = x + 1 elseif dir == 2 then z = z + 1 else x = x - 1 end return true end -- blocked: inspect the block ahead local ok, data = turtle.inspect() if ok then local function isOreByData(d) if not d then return false end if d.tags and d.tags["forge:ores"] == true then return true end if d.name and tostring(d.name):find("_ore") then return true end return false end if isOreByData(data) then -- try bypass: up, forward, down print("Bypassing ore at forward: " .. (data.name or "unknown")) if turtle.up() then y = y + 1 if turtle.forward() then if dir == 0 then z = z - 1 elseif dir == 1 then x = x + 1 elseif dir == 2 then z = z + 1 else x = x - 1 end -- attempt to go back down if turtle.down() then y = y - 1 return true else -- can't go down: try to continue (still okay) return true end else -- couldn't forward after up: try to dig non-ore above and retry local ok2, upData = turtle.inspectUp() if ok2 and not isOreByData(upData) then turtle.digUp() if turtle.up() then y = y + 1 if turtle.forward() then if dir == 0 then z = z - 1 elseif dir == 1 then x = x + 1 elseif dir == 2 then z = z + 1 else x = x - 1 end if turtle.down() then y = y - 1 end return true end end end end end -- fallback: do not dig the ore. signal blocked. return false else -- it's not an ore — dig until it's clear while not turtle.forward() do print("Digging non-ore forward...") turtle.dig() sleep(0.2) end if dir == 0 then z = z - 1 elseif dir == 1 then x = x + 1 elseif dir == 2 then z = z + 1 else x = x - 1 end return true end else -- couldn't inspect, try digging as last resort while not turtle.forward() do turtle.dig() sleep(0.2) end if dir == 0 then z = z - 1 elseif dir == 1 then x = x + 1 elseif dir == 2 then z = z + 1 else x = x - 1 end return true end end local function upSafe() while not turtle.up() do local ok, d = turtle.inspectUp() if ok and d then -- if ore above, do not dig it; attempt to move by forward-first if possible if (d.tags and d.tags["forge:ores"]) or (d.name and tostring(d.name):find("_ore")) then -- can't go up through ore; abort return false else turtle.digUp() end else turtle.digUp() end sleep(0.2) end y = y + 1 return true end local function downSafe() while not turtle.down() do local ok, d = turtle.inspectDown() if ok and d then if (d.tags and d.tags["forge:ores"]) or (d.name and tostring(d.name):find("_ore")) then return false else turtle.digDown() end else turtle.digDown() end sleep(0.2) end y = y - 1 return true end -- absolute goTo using safe moves (vertical first) local function goTo(tx, ty, tz) -- vertical while y < ty do if not upSafe() then error("Cannot move up while going to target") end end while y > ty do if not downSafe() then error("Cannot move down while going to target") end end -- X if x < tx then faceDirection(1) while x < tx do forwardSafe() end elseif x > tx then faceDirection(3) while x > tx do forwardSafe() end end -- Z if z < tz then faceDirection(2) while z < tz do forwardSafe() end elseif z > tz then faceDirection(0) while z > tz do forwardSafe() end end end -- ============ INVENTORY & FUEL ============ local function refuel() if turtle.getFuelLevel() == "unlimited" then return true end for i = 1, 16 do turtle.select(i) if turtle.refuel(0) then turtle.refuel(1) end end return turtle.getFuelLevel() > 0 end local function isInventoryFull() for i = 1, 16 do if turtle.getItemCount(i) == 0 then return false end end return true end local function dumpInventoryAtChest() -- assume we are at chest location and facing chest facing north for i = 1, 16 do turtle.select(i) turtle.drop() end end -- dropOff: saves current position, goes to chest, dumps, refuels, returns, restores dir local function dropOff() print("Inventory full — returning to chest.") local sx, sy, sz, sd = x, y, z, dir -- go to chest coordinates goTo(chestX, chestY, chestZ) -- face chest (chest is SOUTH of start, when at chestX,chestY,chestZ we face NORTH to access it) faceDirection(chestFaceDir) dumpInventoryAtChest() refuel() -- return to saved spot goTo(sx, sy, sz) faceDirection(sd) print("Returned to work location.") end -- ============ ORE DETECTION ============ local function isOreByData(d) if not d then return false end if d.tags and d.tags["forge:ores"] == true then return true end if d.name and tostring(d.name):find("_ore") then return true end return false end local function safeDigFrontAndLogIfOre() local ok, data = turtle.inspect() if ok and isOreByData(data) then local msg = string.format("ORE FOUND (front) @ %d,%d,%d name=%s", x, y, z, tostring(data.name)) print(msg) appendOreLog(msg) return false else turtle.dig() return true end end local function safeDigUpAndLogIfOre() local ok, data = turtle.inspectUp() if ok and isOreByData(data) then local msg = string.format("ORE FOUND (up) @ %d,%d,%d name=%s", x, y, z, tostring(data.name)) print(msg) appendOreLog(msg) return false else turtle.digUp() return true end end local function safeDigDownAndLogIfOre() local ok, data = turtle.inspectDown() if ok and isOreByData(data) then local msg = string.format("ORE FOUND (down) @ %d,%d,%d name=%s", x, y, z, tostring(data.name)) print(msg) appendOreLog(msg) return false else turtle.digDown() return true end end -- ============ MINING LOGIC ============ local stepCounter = 0 local function maybePlaceTorch() if TORCH_INTERVAL > 0 and (stepCounter % TORCH_INTERVAL) == 0 then -- place torches up if possible (user should have torches in selected slot) local ok, data = turtle.inspectUp() if not ok then turtle.placeUp() -- best-effort end end end local function mineLayer() -- assumes starting in the SW corner facing north, will mine WIDTH x LENGTH area for row = 1, WIDTH do for col = 1, LENGTH - 1 do if isInventoryFull() then dropOff() end refuel() -- dig the block in front unless it's an ore (we'll log ores) safeDigFrontAndLogIfOre() -- move forward safely (bypass ore if needed) local moved = forwardSafe() if not moved then -- if forward blocked by ore and bypass failed, attempt to step right-left route: -- try sidestep: right, forward, left. This is complex; we'll attempt one pattern. print("Attempting sidestep around obstacle...") turnRight() if forwardSafe() then turnLeft() -- now continue else -- revert turnLeft() -- try left then right turnLeft() if forwardSafe() then turnRight() else -- stuck: try to break non-ore blocks in front and continue turnRight() print("Stuck; attempting to dig forward (non-ore) until clear.") while not forwardSafe() do turtle.dig() sleep(0.2) end end end end stepCounter = stepCounter + 1 maybePlaceTorch() end -- end of row: move to next row if required if row < WIDTH then if (row % 2) == 1 then -- turned approach: currently facing north; to move one block east and turn south turnRight() safeDigFrontAndLogIfOre() forwardSafe() turnRight() else turnLeft() safeDigFrontAndLogIfOre() forwardSafe() turnLeft() end stepCounter = stepCounter + 1 maybePlaceTorch() end end end -- ============ MAIN CONTROL ============ -- Load saved state (if present) local saved = loadState() local targetLayers = nil local currentLayer = 1 if saved then -- saved may include: x,y,z,dir,currentLayer,targetLayers,stepCounter if saved.targetLayers then targetLayers = saved.targetLayers currentLayer = saved.currentLayer or 1 x = saved.x or x; y = saved.y or y; z = saved.z or z; dir = saved.dir or dir stepCounter = saved.stepCounter or stepCounter print("Resuming saved run. Current layer:", currentLayer, "Target layers:", targetLayers) else -- old save format: ignore and start fresh print("Found save but no target layers — starting fresh.") end end -- if no targetLayers yet, prompt user if not targetLayers then print("How many layers would you like to mine? (enter a number, e.g. 4)") local input = read() local n = tonumber(input) if n and n > 0 then targetLayers = math.floor(n) else print("Invalid input. Defaulting to 1 layer.") targetLayers = 1 end currentLayer = 1 end -- sanity check if targetLayers < 1 then targetLayers = 1 end print(string.format("Starting mining: %d layers (starting at layer %d).", targetLayers, currentLayer)) -- main loop: mine layer-by-layer local success = true while currentLayer <= targetLayers do print(string.format("Mining layer %d / %d at y=%d", currentLayer, targetLayers, y)) -- mine current layer mineLayer() -- after finishing layer, attempt to move down to next layer -- but first try safeDigDown — if it's an ore, we won't dig it and will try to bypass local downOk, downData = turtle.inspectDown() if downOk and isOreByData(downData) then -- if there's ore immediately below the turtle's current position, try move forward then down to find a clear spot print("Ore below turtle; attempting to find clear spot to descend...") -- try to move to a known clear adjacent position and descend local descended = false -- try north faceDirection(0) if forwardSafe() and downSafe() then descended = true else -- try east faceDirection(1) if forwardSafe() and downSafe() then descended = true else -- try south faceDirection(2) if forwardSafe() and downSafe() then descended = true else -- try west faceDirection(3) if forwardSafe() and downSafe() then descended = true end end end end if not descended then print("Unable to find safe descend spot. Attempting to dig down if non-ore.") if not safeDigDownAndLogIfOre() then -- blocked by ore and cannot bypass: stop print("Blocked by ore below and cannot bypass. Stopping.") success = false break else if not downSafe() then print("Could not move down after digging. Stopping.") success = false break end end end else -- no ore below — dig down and descend if not safeDigDownAndLogIfOre() then -- ore detected and logged, but safeDigDown returned false (we preserved ore) -- attempt bypass: move forward then down etc (attempt a direct down) if not downSafe() then print("Cannot move down. Stopping.") success = false break end else -- we dug down (or it was air) — now move down if not downSafe() then print("Can't move down; stopping.") success = false break end end end -- flip orientation to continue next layer in same pattern -- we want turtle to face same direction to start the next layer sweep; rotate 180 turnRight() turnRight() -- increment layer and save state currentLayer = currentLayer + 1 saveState{ x = x, y = y, z = z, dir = dir, currentLayer = currentLayer, targetLayers = targetLayers, stepCounter = stepCounter } end -- finished or aborted: save final state saveState{ x = x, y = y, z = z, dir = dir, currentLayer = currentLayer, targetLayers = targetLayers, stepCounter = stepCounter } if success then print("Mining complete for requested layers.") else print("Mining stopped prematurely. Check logs and environment.") end print("Final position:", x, y, z, "dir:", dir)