Advertisement
kreezxil

self-resuming turtle mining program

Sep 23rd, 2024 (edited)
85
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 13.11 KB | Gaming | 0 0
  1. -- quarry.lua
  2.  
  3. -- Load the serialization library from https://pastebin.com/aYBdRqXm
  4.  
  5. -- Function to fetch and load the serialization library if it doesn't exist
  6. local function fetchSerializationLibrary()
  7.     if not fs.exists("serialization") then
  8.         print("Fetching serialization library from Pastebin...")
  9.         shell.run("pastebin get aYBdRqXm serialization")
  10.     end
  11. end
  12.  
  13. -- Fetch the serialization library if needed
  14. fetchSerializationLibrary()
  15.  
  16. -- Load the serialization library
  17. local serialization = require("serialization")
  18.  
  19. -- Log file configuration
  20. local LOG_FILE = "turtle_log.txt"
  21.  
  22. -- Function to write messages to the log file
  23. local function logMessage(message)
  24.     local file = fs.open(LOG_FILE, "a")
  25.     file.writeLine(os.date("[%Y-%m-%d %H:%M:%S] ") .. message)
  26.     file.close()
  27. end
  28.  
  29. -- Get command-line arguments
  30. local args = { ... }
  31.  
  32. -- Function to prompt the user for a number input, with validation
  33. local function promptUser(prompt, default, min, max)
  34.     while true do
  35.         print(prompt)
  36.         local input = read()
  37.         if input == "" and default ~= nil then
  38.             return default
  39.         end
  40.         local num = tonumber(input)
  41.         if num and (not min or num >= min) and (not max or num <= max) then
  42.             return num
  43.         else
  44.             print("Invalid input. Please enter a number between " .. (min or "-∞") .. " and " .. (max or "∞") .. ".")
  45.         end
  46.     end
  47. end
  48.  
  49. -- Function to prompt the user for a yes/no input
  50. local function promptYesNo(prompt)
  51.     while true do
  52.         print(prompt .. " (yes/no): ")
  53.         local input = read():lower()
  54.         if input == "yes" or input == "y" then
  55.             return true
  56.         elseif input == "no" or input == "n" then
  57.             return false
  58.         else
  59.             print("Invalid input. Please enter 'yes' or 'no'.")
  60.         end
  61.     end
  62. end
  63.  
  64. -- Configuration
  65. local STATE_FILE = "resume.us"
  66. local STARTUP_FILE = "startup.lua"
  67. local STATE_BACKUP = "stateFile" -- Optional state backup
  68.  
  69. -- List of blocks to ignore while mining
  70. local ignoredBlocks = {
  71.     ["minecraft:stone"] = true,
  72.     ["minecraft:granite"] = true,
  73.     ["minecraft:diorite"] = true,
  74.     ["minecraft:andesite"] = true,
  75.     ["minecraft:gravel"] = true,
  76.     ["minecraft:sand"] = true,
  77.     ["minecraft:dirt"] = true,
  78.     ["minecraft:bedrock"] = true,
  79.     ["minecraft:cobblestone"] = true,
  80.     ["minecraft:chest"] = true -- Ignoring chests
  81. }
  82.  
  83. -- Function to create the startup script
  84. local function createStartupScript()
  85.     if not fs.exists(STARTUP_FILE) then
  86.         local startup = [[
  87. -- Startup Script for Quarry Turtle
  88. -- Automatically runs quarry.lua with resume.us
  89.  
  90. shell.run("quarry.lua", "resume")
  91.         ]]
  92.         local file = fs.open(STARTUP_FILE, "w")
  93.         file.write(startup)
  94.         file.close()
  95.     end
  96. end
  97.  
  98. -- Function to save the turtle's current position and state
  99. local function saveState(state)
  100.     local success, err = serialization.saveTableToFile(state, STATE_FILE)
  101.     if success then
  102.         logMessage("State saved successfully.")
  103.     else
  104.         logMessage("Error saving state: " .. err)
  105.     end
  106. end
  107.  
  108. -- Function to load the turtle's current position and state
  109. local function loadState()
  110.     local state, err = serialization.loadTableFromFile(STATE_FILE)
  111.     if state then
  112.         -- Check and set default values if missing
  113.         state.width = state.width or 5
  114.         state.length = state.length or 5
  115.         state.height = state.height or 30
  116.         state.currentX = state.currentX or 1
  117.         state.currentY = state.currentY or 1
  118.         state.currentZ = state.currentZ or 1
  119.         state.direction = state.direction or 0 -- 0: Initial Direction
  120.         return state
  121.     else
  122.         logMessage("Error loading state: " .. err)
  123.         return nil
  124.     end
  125. end
  126.  
  127. -- Function to initialize the cuboid grid and starting position
  128. local function initializeState()
  129.     print("=== Quarry Configuration ===")
  130.     local width = promptUser("Enter the width of the cuboid grid (X dimension): ", 5, 1, 10)
  131.     local length = promptUser("Enter the length of the cuboid grid (Y dimension): ", 5, 1, 10)
  132.     local height = promptUser("Enter the height of the shafts (Z dimension): ", 30, 1, 256)
  133.     local spacing = promptUser("Enter the spacing between shafts (default 3): ", 3, 0, 10)
  134.     local coverShafts = promptYesNo("Should the top of the shaft be covered when it leaves the shaft?")
  135.  
  136.     local state = {
  137.         width = width,
  138.         length = length,
  139.         height = height,
  140.         spacing = spacing,
  141.         coverShafts = coverShafts,
  142.         currentX = 1,
  143.         currentY = 1,
  144.         currentZ = 1,
  145.         direction = 0, -- 0: Initial Direction
  146.         mining = true
  147.     }
  148.  
  149.     saveState(state)
  150.     createStartupScript()
  151.  
  152.     logMessage("Initialization complete. Turtle starting at position (1,1).")
  153.  
  154.     return state
  155. end
  156.  
  157. -- Function to ensure the turtle moves forward, dealing with obstacles
  158. local function moveForward(steps)
  159.     for i = 1, steps do
  160.         while not turtle.forward() do
  161.             turtle.dig()
  162.             sleep(0.5) -- Wait a bit before trying again
  163.         end
  164.     end
  165. end
  166.  
  167. -- Function to turn the turtle to a specific direction
  168. local function turnToDirection(state, desiredTurn)
  169.     if desiredTurn == "left" then
  170.         turtle.turnLeft()
  171.         if state and state.direction ~= nil then
  172.             state.direction = (state.direction - 1) % 4
  173.         end
  174.     elseif desiredTurn == "right" then
  175.         turtle.turnRight()
  176.         if state and state.direction ~= nil then
  177.             state.direction = (state.direction + 1) % 4
  178.         end
  179.     elseif desiredTurn == "around" then
  180.         turtle.turnLeft()
  181.         turtle.turnLeft()
  182.         if state and state.direction ~= nil then
  183.             state.direction = (state.direction + 2) % 4
  184.         end
  185.     end
  186. end
  187.  
  188. -- Function to detect if the program is run by startup.lua
  189. local function isStartup()
  190.     for _, v in ipairs(args) do
  191.         if v == "resume" then
  192.             return true
  193.         end
  194.     end
  195.     return false
  196. end
  197.  
  198. -- Function to delete state files if run by the player
  199. local function deleteStateFilesOnPlayerRun()
  200.     if not isStartup() then
  201.         if fs.exists(STATE_FILE) then
  202.             fs.delete(STATE_FILE)
  203.             logMessage(STATE_FILE .. " deleted on player run.")
  204.         end
  205.         if fs.exists(STATE_BACKUP) then
  206.             fs.delete(STATE_BACKUP)
  207.             logMessage(STATE_BACKUP .. " deleted on player run.")
  208.         end
  209.     end
  210. end
  211.  
  212. -- Function to mine adjacent blocks if they are not in the ignore list
  213. local function mineAdjacent()
  214.     -- Check forward
  215.     local success, data = turtle.inspect()
  216.     if success and not ignoredBlocks[data.name] then
  217.         turtle.dig()
  218.     end
  219.  
  220.     -- Check up
  221.     success, data = turtle.inspectUp()
  222.     if success and not ignoredBlocks[data.name] then
  223.         turtle.digUp()
  224.     end
  225.  
  226.     -- Check down
  227.     success, data = turtle.inspectDown()
  228.     if success and not ignoredBlocks[data.name] then
  229.         turtle.digDown()
  230.     end
  231.  
  232.     -- Check left
  233.     turtle.turnLeft()
  234.     success, data = turtle.inspect()
  235.     if success and not ignoredBlocks[data.name] then
  236.         turtle.dig()
  237.     end
  238.     turtle.turnRight() -- Return to original orientation
  239.  
  240.     -- Check right
  241.     turtle.turnRight()
  242.     success, data = turtle.inspect()
  243.     if success and not ignoredBlocks[data.name] then
  244.         turtle.dig()
  245.     end
  246.     turtle.turnLeft() -- Return to original orientation
  247.  
  248.     -- Check back
  249.     turtle.turnLeft()
  250.     turtle.turnLeft()
  251.     success, data = turtle.inspect()
  252.     if success and not ignoredBlocks[data.name] then
  253.         turtle.dig()
  254.     end
  255.     turtle.turnLeft()
  256.     turtle.turnLeft() -- Return to original orientation
  257. end
  258.  
  259. -- Function to mine a shaft at the current grid position
  260. local function mineShaft(state)
  261.     local depth = 0
  262.     while depth < state.height do
  263.         -- Check for bedrock
  264.         if turtle.detectDown() then
  265.             local success, data = turtle.inspectDown()
  266.             if success and data.name == "minecraft:bedrock" then
  267.                 logMessage("Bedrock reached at depth " .. depth)
  268.                 break
  269.             end
  270.         end
  271.  
  272.         -- Mine adjacent blocks
  273.         mineAdjacent()
  274.  
  275.         -- Dig down
  276.         if not turtle.down() then
  277.             turtle.digDown()
  278.             if not turtle.down() then
  279.                 logMessage("Cannot move down further at depth " .. depth)
  280.                 break
  281.             end
  282.         end
  283.  
  284.         depth = depth + 1
  285.         saveState(state)  -- Save state after each movement
  286.     end
  287.  
  288.     -- Return to surface
  289.     while depth > 0 do
  290.         if not turtle.up() then
  291.             turtle.digUp()
  292.             if not turtle.up() then
  293.                 logMessage("Cannot move up")
  294.                 break
  295.             end
  296.         end
  297.         depth = depth - 1
  298.     end
  299.  
  300.     -- Optionally cover the top of the shaft
  301.     if state.coverShafts then
  302.         turtle.select(1) -- Assuming slot 1 has the covering block
  303.         turtle.placeDown()
  304.     end
  305. end
  306.  
  307. -- Function to delete the state and resume files upon completion
  308. local function deleteStateFiles()
  309.     if fs.exists(STATE_FILE) then
  310.         fs.delete(STATE_FILE)
  311.         logMessage(STATE_FILE .. " deleted.")
  312.     end
  313.     if fs.exists(STATE_BACKUP) then
  314.         fs.delete(STATE_BACKUP)
  315.         logMessage(STATE_BACKUP .. " deleted.")
  316.     end
  317. end
  318.  
  319. -- Function to check if the inventory is full
  320. local function isInventoryFull()
  321.     for i = 1, 16 do
  322.         if turtle.getItemCount(i) == 0 then
  323.             return false
  324.         end
  325.     end
  326.     return true
  327. end
  328.  
  329. -- Function to unload items into a chest behind the starting position
  330. local function unloadItems(state)
  331.     logMessage("Unloading items...")
  332.     -- Move back to starting position
  333.     local stepsX = state.currentX - 1
  334.     local stepsY = state.currentY - 1
  335.  
  336.     -- Turn around to face back
  337.     turnToDirection(state, "around")
  338.     moveForward(stepsX * (state.spacing + 1))
  339.  
  340.     -- Turn left to face starting Y direction
  341.     turnToDirection(state, "left")
  342.     moveForward(stepsY * (state.spacing + 1))
  343.  
  344.     -- Face the chest (assuming it's behind the starting position)
  345.     turnToDirection(state, "around")
  346.     for i = 1, 16 do
  347.         turtle.select(i)
  348.         turtle.drop()
  349.     end
  350.     turtle.select(1)
  351.  
  352.     -- Return to current position
  353.     -- Move back along Y-axis
  354.     turnToDirection(state, "around")
  355.     moveForward(stepsY * (state.spacing + 1))
  356.  
  357.     -- Turn right to face original direction
  358.     turnToDirection(state, "right")
  359.     moveForward(stepsX * (state.spacing + 1))
  360.  
  361.     -- Turn around to face the original mining direction
  362.     turnToDirection(state, "around")
  363.  
  364.     logMessage("Finished unloading items.")
  365. end
  366.  
  367. -- Main mining loop that resumes or starts the quarrying operation
  368. local function main()
  369.     -- Delete state files if run by the player
  370.     deleteStateFilesOnPlayerRun()
  371.  
  372.     -- Load existing state or initialize
  373.     local state = loadState()
  374.     if not state then
  375.         state = initializeState()
  376.         -- Assume the initial direction is the way the turtle is facing
  377.         state.direction = 0
  378.         saveState(state)
  379.     else
  380.         logMessage("Resuming quarry operation.")
  381.     end
  382.  
  383.     -- Perform the mining operation
  384.     for y = state.currentY, state.length do
  385.         local startX, endX, stepX
  386.         if (y % 2 == 1) then
  387.             -- Moving forward
  388.             startX = state.currentX
  389.             endX = state.width
  390.             stepX = 1
  391.         else
  392.             -- Moving backward
  393.             startX = state.currentX
  394.             endX = 1
  395.             stepX = -1
  396.         end
  397.  
  398.         for x = startX, endX, stepX do
  399.             -- Mine shaft at current position
  400.             logMessage("Mining at X: " .. x .. " Y: " .. y)
  401.             mineShaft(state)
  402.             saveState(state)
  403.  
  404.             -- Check if inventory is full
  405.             if isInventoryFull() then
  406.                 unloadItems(state)
  407.             end
  408.  
  409.             -- Move to next shaft position
  410.             if x ~= endX then
  411.                 moveForward(state.spacing + 1)
  412.             end
  413.  
  414.             -- Update current X position
  415.             state.currentX = x + stepX
  416.         end
  417.  
  418.         -- At the end of the row, move to the next row if needed
  419.         if y < state.length then
  420.             -- Turn to next row
  421.             if (y % 2 == 1) then
  422.                 turnToDirection(state, "right")
  423.                 moveForward(state.spacing + 1)
  424.                 turnToDirection(state, "right")
  425.             else
  426.                 turnToDirection(state, "left")
  427.                 moveForward(state.spacing + 1)
  428.                 turnToDirection(state, "left")
  429.             end
  430.             state.currentY = y + 1
  431.             -- Update current X position for the new row
  432.             state.currentX = endX
  433.             saveState(state)
  434.         end
  435.     end
  436.  
  437.     logMessage("Mining operation completed.")
  438.     state.mining = false
  439.     saveState(state)
  440.  
  441.     -- Clean up files when the operation is done
  442.     deleteStateFiles()
  443. end
  444.  
  445. -- Execute the main function
  446. main()
  447.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement