gur111

Turtle Miner ComptuerCraft

Jun 1st, 2025 (edited)
214
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 18.50 KB | None | 0 0
  1. -- pastebin ID: LXSNkj5r
  2. -- URL: https://pastebin.com/LXSNkj5r
  3.  
  4. local logFilePath = "mine.log"
  5.  
  6. local noChest = false
  7. local startChest = true  -- Make startChest the default behavior
  8.  
  9. -- Precious blocks list - blocks to detect and avoid mining unless blocking path
  10. local preciousBlocks = {
  11.   "diamond",
  12.   "lapis",
  13.   "debris"
  14. }
  15.  
  16. -- Mainframe communication
  17. local MAINFRAME_ID = nil
  18. local modemSide = nil
  19. local detectionRunning = false
  20.  
  21.  
  22. -- Direction vectors: north (-Z), east (+X), south (+Z), west (-X)
  23. local dirs = {
  24.   [0] = {x = 0, z = -1}, -- North
  25.   [1] = {x = 1, z = 0},  -- East
  26.   [2] = {x = 0, z = 1},  -- South
  27.   [3] = {x = -1, z = 0}, -- West
  28. }
  29.  
  30. -- Initial state - use relative coordinates for movement
  31. local pos = {x = 0, y = 0, z = 0}
  32. local heading = 0  -- 0=north, 1=east, 2=south, 3=west
  33.  
  34.  
  35. -- Function to find and open modem
  36. function openModem()
  37.   if modemSide then return true end
  38.  
  39.   local sides = {"left", "right", "top", "bottom", "front", "back"}
  40.   for _, side in ipairs(sides) do
  41.     if peripheral.getType(side) == "modem" then
  42.       rednet.open(side)
  43.       modemSide = side
  44.       log("Modem opened on " .. side)
  45.       return true
  46.     end
  47.   end
  48.   log("No modem found for mainframe communication")
  49.   return false
  50. end
  51.  
  52. -- Function to discover mainframe ID via broadcast
  53. function discoverMainframe()
  54.   if MAINFRAME_ID then return MAINFRAME_ID end
  55.  
  56.   if not openModem() then
  57.     log("Cannot discover mainframe - no modem available")
  58.     return nil
  59.   end
  60.  
  61.   log("Broadcasting to discover mainframe...")
  62.   rednet.broadcast("discover_mainframe")
  63.  
  64.   -- Wait for responses for up to 3 seconds
  65.   local timeout = os.clock() + 3
  66.   while os.clock() < timeout do
  67.     local senderId, message = rednet.receive(0.1)
  68.     if senderId and message == "mainframe_here" then
  69.       MAINFRAME_ID = senderId
  70.       log("Discovered mainframe at ID: " .. MAINFRAME_ID)
  71.       return MAINFRAME_ID
  72.     end
  73.   end
  74.  
  75.   log("No mainframe found via broadcast")
  76.   return nil
  77. end
  78.  
  79. -- Function to report precious block to mainframe
  80. function reportPreciousBlock(blockName, x, y, z)
  81.   local mainframeId = discoverMainframe()
  82.   if mainframeId and openModem() then
  83.     local message = {
  84.       type = "precious",
  85.       blockName = blockName,
  86.       x = x,
  87.       y = y,
  88.       z = z
  89.     }
  90.     rednet.send(mainframeId, message)
  91.     log("Reported to mainframe " .. mainframeId .. ": " .. blockName .. " at (" .. x .. ", " .. y .. ", " .. z .. ")")
  92.   else
  93.     log("Cannot report precious block - mainframe not available")
  94.   end
  95. end
  96.  
  97. -- Function to report current GPS location to mainframe
  98. function reportLocationToMainframe()
  99.   local mainframeId = discoverMainframe()
  100.   if mainframeId and openModem() then
  101.     local gpsX, gpsY, gpsZ = gps.locate()
  102.     if gpsX and gpsY and gpsZ then
  103.       local message = {
  104.         type = "location",
  105.         x = gpsX,
  106.         y = gpsY,
  107.         z = gpsZ
  108.       }
  109.       rednet.send(mainframeId, message)
  110.       log("Reported location to mainframe " .. mainframeId .. ": (" .. gpsX .. ", " .. gpsY .. ", " .. gpsZ .. ")")
  111.     else
  112.       -- Fallback to relative coordinates if GPS not available
  113.       local absPos = getAbsolutePosition()
  114.       local message = {
  115.         type = "location",
  116.         x = absPos.x,
  117.         y = absPos.y,
  118.         z = absPos.z
  119.       }
  120.       rednet.send(mainframeId, message)
  121.       log("Reported relative location to mainframe " .. mainframeId .. ": (" .. absPos.x .. ", " .. absPos.y .. ", " .. absPos.z .. ")")
  122.     end
  123.   else
  124.     log("Cannot report location - mainframe not available")
  125.   end
  126. end
  127.  
  128. -- Function to scrub precious locations from mainframe for this turtle
  129. function scrubPreciousLocations()
  130.   local mainframeId = discoverMainframe()
  131.   if mainframeId and openModem() then
  132.     local myId = os.getComputerID()
  133.     local message = "scrub_precious " .. myId
  134.     rednet.send(mainframeId, message)
  135.     log("Requested mainframe " .. mainframeId .. " to scrub precious locations for turtle " .. myId)
  136.  
  137.     -- Wait for confirmation
  138.     local timeout = os.clock() + 2
  139.     while os.clock() < timeout do
  140.       local senderId, response = rednet.receive(0.1)
  141.       if senderId == mainframeId and type(response) == "string" and string.find(response, "Scrubbed") then
  142.         log("Mainframe confirmed: " .. response)
  143.         return true
  144.       end
  145.     end
  146.     log("No confirmation received from mainframe for scrub request")
  147.   else
  148.     log("Cannot scrub precious locations - mainframe not available")
  149.   end
  150.   return false
  151. end
  152.  
  153. -- Continuous precious block detection that runs in parallel
  154. function continuousDetection()
  155.   detectionRunning = true
  156.   log("Starting continuous precious block detection...")
  157.  
  158.   while detectionRunning do
  159.     -- Get current GPS coordinates directly
  160.     local gpsX, gpsY, gpsZ = gps.locate()
  161.     if not gpsX then
  162.       -- Fallback to relative coordinates if GPS not available
  163.       gpsX, gpsY, gpsZ = pos.x, pos.y, pos.z
  164.     end
  165.  
  166.     -- Check only forward, up, and down directions (no side inspection to avoid interfering with mining)
  167.     local directions = {
  168.       {name = "forward", detect = turtle.inspect},
  169.       {name = "up", detect = turtle.inspectUp},
  170.       {name = "down", detect = turtle.inspectDown}
  171.     }
  172.  
  173.     -- Check forward, up, down only
  174.     for _, dir in ipairs(directions) do
  175.       local success, data = dir.detect()
  176.       if success and data and data.name and isPreciousBlock(data.name) then
  177.         reportPreciousBlock(data.name, gpsX, gpsY, gpsZ)
  178.       end
  179.     end
  180.  
  181.     -- Sleep briefly to avoid overwhelming the system
  182.     sleep(0.5)
  183.   end
  184.  
  185.   log("Continuous precious block detection stopped")
  186. end
  187.  
  188. -- Function to stop continuous detection
  189. function stopDetection()
  190.   detectionRunning = false
  191. end
  192.  
  193. -- Function to log messages to a file
  194. function log(message)
  195.   local file = fs.open(logFilePath, "a")
  196.   print(message)
  197.   file.writeLine(message)
  198.   file.close()
  199. end
  200.  
  201. -- Function to clean block name by removing everything before ':'
  202. function cleanBlockName(blockName)
  203.   if not blockName then return "unknown" end
  204.   local colonPos = string.find(blockName, ":")
  205.   if colonPos then
  206.     return string.sub(blockName, colonPos + 1)
  207.   else
  208.     return blockName
  209.   end
  210. end
  211.  
  212. -- Function to check if a block name contains precious materials
  213. function isPreciousBlock(blockName)
  214.   if not blockName then return false end
  215.  
  216.   for _, precious in ipairs(preciousBlocks) do
  217.     if string.find(string.lower(blockName), precious) then
  218.       return true
  219.     end
  220.   end
  221.   return false
  222. end
  223.  
  224. -- Function to detect and log precious blocks in all directions
  225. function detectPreciousBlocks()
  226.   local directions = {
  227.     {name = "forward", detect = turtle.inspect, pos = "front"},
  228.     {name = "up", detect = turtle.inspectUp, pos = "above"},
  229.     {name = "down", detect = turtle.inspectDown, pos = "below"}
  230.   }
  231.  
  232.   for _, dir in ipairs(directions) do
  233.     local success, data = dir.detect()
  234.     if success and data and data.name then
  235.       if isPreciousBlock(data.name) then
  236.         log("PRECIOUS BLOCK DETECTED " .. dir.pos .. ": " .. data.name .. " at relative position (" .. pos.x .. ", " .. pos.y .. ", " .. pos.z .. ")")
  237.       end
  238.     end
  239.   end
  240. end
  241.  
  242. -- Function to get GPS coordinates for absolute positioning
  243. function getGPSPosition()
  244.   local x, y, z = gps.locate()
  245.   if x and y and z then
  246.     log("GPS coordinates obtained: (" .. x .. ", " .. y .. ", " .. z .. ")")
  247.     return {x = x, y = y, z = z}
  248.   else
  249.     log("WARNING: GPS not available, absolute coordinates will not be available")
  250.     return nil
  251.   end
  252. end
  253.  
  254. -- Get starting GPS position for absolute coordinate conversion
  255. local startGPS = getGPSPosition()
  256.  
  257. -- Function to get current absolute coordinates
  258. function getAbsolutePosition()
  259.   if startGPS then
  260.     return {
  261.       x = startGPS.x + pos.x,
  262.       y = startGPS.y + pos.y,
  263.       z = startGPS.z + pos.z
  264.     }
  265.   else
  266.     -- If GPS not available, return relative coordinates
  267.     return {x = pos.x, y = pos.y, z = pos.z}
  268.   end
  269. end
  270.  
  271.  
  272. -- Helpers
  273. function turnLeft()
  274.   turtle.turnLeft()
  275.   heading = (heading - 1 + 4) % 4 -- Ensure positive modulo result
  276. end
  277.  
  278. function turnRight()
  279.   turtle.turnRight()
  280.   heading = (heading + 1) % 4
  281. end
  282.  
  283. function moveForward()
  284.   while not turtle.forward() do
  285.     turtle.attack()
  286.     digForward()
  287.     sleep(0.5)
  288.   end
  289.   pos.x = pos.x + dirs[heading].x
  290.   pos.z = pos.z + dirs[heading].z
  291.   reportLocationToMainframe()
  292. end
  293.  
  294. function moveBackward()
  295.   turtle.back()
  296.   pos.x = pos.x - dirs[heading].x
  297.   pos.z = pos.z - dirs[heading].z
  298.   reportLocationToMainframe()
  299. end
  300.  
  301. function moveUp()
  302.   while not turtle.up() do
  303.     turtle.attackUp()
  304.     digUp()
  305.     sleep(0.5)
  306.   end
  307.   pos.y = pos.y + 1
  308.   reportLocationToMainframe()
  309. end
  310.  
  311. function moveDown()
  312.   while not turtle.down() do
  313.     turtle.attackDown()
  314.     digDown()
  315.     sleep(0.5)
  316.   end
  317.   pos.y = pos.y - 1
  318.   reportLocationToMainframe()
  319. end
  320.  
  321. function digForward()
  322.   while turtle.detect() do
  323.     turtle.dig()
  324.     sleep(0.3)
  325.   end
  326. end
  327.  
  328. function digUp()
  329.   while turtle.detectUp() do
  330.     turtle.digUp()
  331.     sleep(0.3)
  332.   end
  333. end
  334.  
  335. function digDown()
  336.   while turtle.detectDown() do
  337.     turtle.digDown()
  338.     sleep(0.3)
  339.   end
  340. end
  341.  
  342. function isInventoryFull()
  343.   for i = 1, 16 do
  344.     if turtle.getItemCount(i) == 0 then return false end
  345.   end
  346.   log("InventoryFull. startChest: " .. tostring(startChest) .. ", noChest: " .. tostring(noChest))
  347.   return true
  348. end
  349.  
  350. function refuelIfNeeded()
  351.   for i = 1, 16 do
  352.     turtle.select(i)
  353.     local itemDetail = turtle.getItemDetail()
  354.     if itemDetail and string.find(itemDetail.name, "coal") then
  355.       while turtle.getItemCount(i) > 0 do
  356.         turtle.refuel(1)
  357.       end
  358.       log("Refueled with " .. itemDetail.name .. " from slot " .. i)
  359.     end
  360.   end
  361.   turtle.select(1)
  362. end
  363.  
  364. function dumpJunk()
  365.   local junkItems = {
  366.     "cobblestone", "diorite", "gravel", "dirt", "tuff", "blackstone", "pebble", "polished blackstone wall",
  367.     "nether brick wall", "nether brick fence", "red nether brick", "nether brick staires", "cracked nether bricks",
  368.     "nether bricks",
  369.     "granite", "deepslate", "netherrack", "rhyolite", "schist", "pebble", "asphalt", "andesite"
  370.   }
  371.   for i = 1, 16 do
  372.     turtle.select(i)
  373.     local itemDetail = turtle.getItemDetail()
  374.     if itemDetail then
  375.       for _, junk in ipairs(junkItems) do
  376.         if string.find(itemDetail.name, junk) then
  377.           turtle.drop()
  378.           log("Dropped junk item: " .. itemDetail.name .. " from slot " .. i)
  379.           break
  380.         end
  381.       end
  382.     end
  383.   end
  384.   turtle.select(1)
  385. end
  386.  
  387. -- Safe digging functions for digTriplet - avoid precious blocks that aren't blocking movement
  388. function digForwardSafe()
  389.   while turtle.detect() do
  390.     local success, data = turtle.inspect()
  391.     if success and data and data.name and isPreciousBlock(data.name) then
  392.       local cleanedName = cleanBlockName(data.name)
  393.       log("AVOIDING precious block in front (not blocking path): " .. cleanedName .. " at position (" .. pos.x .. ", " .. pos.y .. ", " .. pos.z .. ")")
  394.       break -- Don't dig precious blocks when just clearing area
  395.     end
  396.     turtle.dig()
  397.     sleep(0.3)
  398.   end
  399. end
  400.  
  401. function digUpSafe()
  402.   while turtle.detectUp() do
  403.     local success, data = turtle.inspectUp()
  404.     if success and data and data.name and isPreciousBlock(data.name) then
  405.       local cleanedName = cleanBlockName(data.name)
  406.       log("AVOIDING precious block above (not blocking path): " .. cleanedName .. " at position (" .. pos.x .. ", " .. pos.y + 1 .. ", " .. pos.z .. ")")
  407.       break -- Don't dig precious blocks when just clearing area
  408.     end
  409.     turtle.digUp()
  410.     sleep(0.3)
  411.   end
  412. end
  413.  
  414. function digDownSafe()
  415.   while turtle.detectDown() do
  416.     local success, data = turtle.inspectDown()
  417.     if success and data and data.name and isPreciousBlock(data.name) then
  418.       local cleanedName = cleanBlockName(data.name)
  419.       log("AVOIDING precious block below (not blocking path): " .. cleanedName .. " at position (" .. pos.x .. ", " .. pos.y - 1 .. ", " .. pos.z .. ")")
  420.       break -- Don't dig precious blocks when just clearing area
  421.     end
  422.     turtle.digDown()
  423.     sleep(0.3)
  424.   end
  425. end
  426.  
  427. function digTriplet()
  428.   -- Detect precious blocks in all directions before mining
  429.   detectPreciousBlocks()
  430.  
  431.   digForwardSafe()  -- Use safe version - not actually moving forward here
  432.   moveForward()
  433.  
  434.   -- Detect precious blocks again after moving
  435.   detectPreciousBlocks()
  436.  
  437.   -- Use safe digging for up/down since turtle isn't moving in those directions
  438.   digUpSafe()
  439.   digDownSafe()
  440. end
  441.  
  442. function dig()
  443.   digTriplet()
  444.   if isInventoryFull() then
  445.     log("Checking where to drop the stuff. startChest: " .. tostring(startChest) .. ", noChest: " .. tostring(noChest))
  446.  
  447.     if noChest then
  448.       for i = 1, 16 do
  449.         turtle.select(i)
  450.         turtle.drop()
  451.       end
  452.     elseif startChest then
  453.       local currentPos = {x = pos.x, y = pos.y, z = pos.z, d = heading}
  454.       goTo(0, 0, 0, 2)
  455.       for i = 1, 16 do
  456.         turtle.select(i)
  457.         turtle.drop()
  458.       end
  459.       goTo(currentPos.x, currentPos.y, currentPos.z, currentPos.d) -- Return to the original position
  460.     else
  461.       placeChestAndUnload()
  462.     end
  463.   end
  464.   -- log("Dug block at position: (" .. pos.x .. ", " .. pos.y .. ", " .. pos.z .. ")")
  465. end
  466.  
  467. function placeChestAndUnload()
  468.   turtle.select(1) -- Select slot 1, assuming it's for the chest
  469.  
  470.   -- Loop until a chest is found in slot 1
  471.   local itemInSlot1 = turtle.getItemDetail(1)
  472.   while not itemInSlot1 or not string.find(itemInSlot1.name, "chest") do
  473.     log("Waiting for chest in slot 1. Current item: " .. (itemInSlot1 and itemInSlot1.name or "nil"))
  474.     print("Please place a chest in slot 1 to continue.")
  475.     sleep(2) -- Wait for 2 seconds before re-checking
  476.     itemInSlot1 = turtle.getItemDetail(1)
  477.   end
  478.  
  479.   -- Now that a chest is confirmed in slot 1, proceed with placing it
  480.   while not turtle.placeDown() do
  481.     log("Waiting to place chest. Please ensure the space below is clear.")
  482.     print("Waiting to place chest. Please ensure the space below is clear.")
  483.     sleep(2) -- Wait for 2 seconds before retrying
  484.   end
  485.   log("Placed chest below at position: (" .. pos.x .. ", " .. pos.y .. ", " .. pos.z .. ")")
  486.   for i = 2, 16 do -- Start from slot 2, assuming slot 1 is for the chest
  487.     turtle.select(i)
  488.     turtle.dropDown()
  489.   end
  490.   turtle.select(1) -- Re-select slot 1
  491. end
  492.  
  493. function digTunnel(x)
  494.   for i = 1, x do
  495.     dig()
  496.   end
  497.   refuelIfNeeded()
  498.   dumpJunk()
  499. end
  500.  
  501. function goTo(x, y, z, d)
  502.   while pos.y < y do moveUp() end
  503.   while pos.y > y do moveDown() end
  504.  
  505.   local dx = x - pos.x
  506.   if dx ~= 0 then
  507.     -- Determine target heading based on dx
  508.     local targetHeadingX = (dx > 0) and 1 or 3 -- East or West
  509.     faceDirection(targetHeadingX)
  510.     for i = 1, math.abs(dx) do digTriplet() end
  511.   end
  512.  
  513.   local dz = z - pos.z
  514.   if dz ~= 0 then
  515.     -- Determine target heading based on dz
  516.     local targetHeadingZ = (dz > 0) and 2 or 0 -- South or North
  517.     faceDirection(targetHeadingZ)
  518.     for i = 1, math.abs(dz) do digTriplet() end
  519.   end
  520.  
  521.   faceDirection(d)
  522. end
  523.  
  524. function faceDirection(dir)
  525.   while heading ~= dir do
  526.     turnRight()
  527.   end
  528. end
  529.  
  530. local args = { ... }
  531.  
  532. function digLayer(width, length, spacing)
  533.   tunnelLength =  width - 1
  534.   numTunnels = math.floor((length + spacing) / (1 + spacing))
  535.  
  536.  
  537.   log("Starting layer mining with tunnel length: " .. tunnelLength .. ", number of tunnels: " .. numTunnels .. ", spacing: " .. spacing)
  538.  
  539.   for _ = 1, math.floor(numTunnels / 2) do
  540.     -- Move to start of first tunnel (connecting segment)
  541.     digTunnel(1 + spacing)
  542.  
  543.     -- Turn into first main tunnel
  544.     turnLeft()
  545.     digTunnel(tunnelLength)
  546.  
  547.     -- Turn to move to next connecting segment
  548.     turnRight()
  549.     digTunnel(1 + spacing)
  550.  
  551.     -- Turn into second main tunnel
  552.     turnRight()
  553.     digTunnel(tunnelLength)
  554.  
  555.     -- Turn back to original orientation for next pair of tunnels
  556.     turnLeft()
  557.   end
  558.  
  559.   if numTunnels % 2 == 1 then
  560.     log("Warning: numTunnels is odd. The last tunnel might not follow the full zig-zag pattern.")
  561.   end
  562.  
  563.   if noChest then
  564.     log("No chest mode: Dropping items on the ground.")
  565.     for i = 1, 16 do
  566.       turtle.select(i)
  567.       turtle.drop()
  568.     end
  569.   elseif startChest then
  570.     log("Start chest mode: Returning to start to unload.")
  571.     goTo(0, 0, 0, 2)
  572.     for i = 1, 16 do
  573.       turtle.select(i)
  574.       turtle.drop()
  575.     end
  576.   end
  577. end
  578.  
  579. -- Mining function that runs the actual mining operations
  580. function runMining()
  581.   local width = tonumber(args[1])
  582.   local length = tonumber(args[2])
  583.   local tspacing = tonumber(args[3])
  584.   local layers = tonumber(args[4])
  585.   local lspacing = tonumber(args[5])
  586.  
  587.   for i = 1, layers do
  588.     log("Starting layer ".. i)
  589.     goTo(0, - (i - 1) * (3 + lspacing), 0, 0)
  590.     digLayer(width, length, tspacing)
  591.   end
  592.  
  593.   if noChest then
  594.     log("No chest mode: Dropping items on the ground.")
  595.     for i = 1, 16 do
  596.       turtle.select(i)
  597.       turtle.drop()
  598.     end
  599.   elseif startChest then
  600.     log("Start chest mode: Returning to start to unload.")
  601.     goTo(0, 0, 0, 2)
  602.     for i = 1, 16 do
  603.       turtle.select(i)
  604.       turtle.drop()
  605.     end
  606.   end
  607.  
  608.   goTo(0, 0, 0, 0)
  609.  
  610.   -- Stop continuous detection when mining is complete
  611.   stopDetection()
  612.   log("Mining complete.")
  613. end
  614.  
  615. function main()
  616.   if #args < 5 then
  617.     print("Usage: mine <width> <length> <tunnelSpacing> <numLayers> <layerSpacing> [--nochest | --nostartchest]")
  618.     return
  619.   end
  620.  
  621.   local width = tonumber(args[1])
  622.   local length = tonumber(args[2])
  623.   local tspacing = tonumber(args[3])
  624.   local layers = tonumber(args[4])
  625.   local lspacing = tonumber(args[5])
  626.  
  627.   -- Parse optional flags
  628.   for i = 6, #args do
  629.     if args[i] == "--nochest" then
  630.       log("Detected --nochest")
  631.       noChest = true
  632.       startChest = false  -- Override default when --nochest is specified
  633.     elseif args[i] == "--nostartchest" then
  634.       log("Detected --nostartchest")
  635.       startChest = false
  636.     end
  637.   end
  638.  
  639.   log("startChest: " .. tostring(startChest) .. ", noChest: " .. tostring(noChest))
  640.  
  641.   if not width or not length or not tspacing  or not layers  or not lspacing then
  642.     print("Invalid input.")
  643.     return
  644.   end
  645.  
  646.   -- Scrub previous precious locations when starting new mining operation
  647.   log("Starting new mining operation - scrubbing previous precious locations...")
  648.   scrubPreciousLocations()
  649.  
  650.   -- Report initial location to mainframe
  651.   reportLocationToMainframe()
  652.  
  653.   -- Run mining and continuous detection in parallel
  654.   parallel.waitForAll(runMining, continuousDetection)
  655. end
  656.  
  657. main()
  658.  
Advertisement
Add Comment
Please, Sign In to add comment