Sv443

ComputerCraft Turtle Sugarcane Farm

Nov 27th, 2023 (edited)
49
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 17.50 KB | Gaming | 0 0
  1. -- Maximum forward position, 1-indexed
  2. -- This is the width of the farm + 1, starting from the front side of the turtle, including the refuel station
  3. DISTANCE_X = 13
  4. -- Maximum right position, 1-indexed
  5. -- This is the length of the farm, starting from the right side of the turtle, including the refuel station
  6. DISTANCE_Y = 9
  7.  
  8. -- Turtle will refuel at the refueling station until it reaches this level
  9. -- Don't set this too low or it might get stuck mid-cycle
  10. -- To find out how much it uses per cycle, see the stats that are printed after each cycle
  11. -- 1 item smelted equals 10 fuel points, so one coal is 80, a blaze rod is 120, etc.
  12. TARGET_FUEL_LEVEL = 800
  13.  
  14. -- Delay between harvest cycles in seconds, has to be a multiple of 0.05 (1 game tick)
  15. DELAY_BETWEEN_HARVESTS = 60 * 4
  16.  
  17. -- Whether to path back to the home position using GPS after a reboot
  18. -- This requires an ender modem and a GPS tower to be present and in loaded chunks
  19. -- This feature is useful for singleplayer or if a multiplayer server restarts often
  20. -- as the turtle will just stop in the middle of a harvest cycle and not know where it is anymore
  21. -- To reset the home position, run 'rm home_coords.txt' then 'reboot'
  22. USE_GPS_HOME = true
  23. -- How many blocks to move upwards while returning to the home position
  24. -- so the turtle doesn't run into anything - 0 to disable
  25. GPS_SAFETY_HEIGHT = 2
  26. -- Timeout for GPS operations in seconds - increase if the GPS tower is far away
  27. GPS_TIMEOUT = 5
  28.  
  29. -- File path where statistics are stored
  30. STATS_PATH = "/farm_stats.txt"
  31. -- File path where the home position is stored
  32. HOME_COORDS_PATH = "/home_coords.txt"
  33.  
  34.  
  35.  
  36. -- DO NOT EDIT OR TURTLE GETS ANGY >:(
  37. local xPos = 1
  38. local yPos = 1
  39. local fuelBeforeCycle = nil
  40. local fuelPerCycle = 0
  41.  
  42. -- #SECTION refuel
  43.  
  44. -- grab fuel from inventory below, to fill first slot to 64
  45. function grabFuel()
  46.     turtle.select(1)
  47.     local itemDet = turtle.getItemDetail(1)
  48.     local fuelNeeded = 64
  49.     if itemDet ~= nil then
  50.         fuelNeeded = 64 - itemDet.count
  51.     end
  52.     if fuelNeeded > 0 then
  53.         if turtle.suckDown(fuelNeeded) then
  54.             itemDet = turtle.getItemDetail(1)
  55.             print("* Restocked "..tostring(itemDet.count).." fuel item"..(itemDet.count == 1 and "" or "s"))
  56.             return true
  57.         else
  58.             return false
  59.         end
  60.     end
  61. end
  62.  
  63. -- refuel until target fuel level is reached
  64. function refuel()
  65.     grabFuel()
  66.     local itemDet = turtle.getItemDetail(1)
  67.     while itemDet == nil do
  68.         print("! Waiting for fuel...")
  69.         os.sleep(1)
  70.         while not grabFuel() and turtle.getFuelLevel() < TARGET_FUEL_LEVEL do
  71.             os.sleep(0.5)
  72.         end
  73.         itemDet = turtle.getItemDetail(1)
  74.     end
  75.     while turtle.getFuelLevel() < TARGET_FUEL_LEVEL do
  76.         turtle.refuel(1)
  77.         local itemDet = turtle.getItemDetail(1)
  78.         if itemDet ~= nil then
  79.             if itemDet.count < 5 then
  80.                 grabFuel()
  81.             end
  82.         else
  83.             print("! Waiting for fuel...")
  84.             os.sleep(1)
  85.             grabFuel()
  86.             itemDet = turtle.getItemDetail(1)
  87.         end
  88.     end
  89.     grabFuel()
  90. end
  91.  
  92. -- move from item dropoff to refuel station
  93. function moveRefuel()
  94.     turtle.forward()
  95.     yPos = yPos - 1
  96.     turtle.turnRight()
  97.     fuelPerCycle = fuelBeforeCycle - turtle.getFuelLevel()
  98. end
  99.  
  100. -- #SECTION drop items
  101.  
  102. -- drops off all items into inventory below
  103. -- returns the amount of dropped off items
  104. function dropItems()
  105.     local curSlot = 2
  106.     local itemsAmt = 0;
  107.     local slotDetail = turtle.getItemDetail(curSlot)
  108.     while slotDetail ~= nil do
  109.         turtle.select(curSlot)
  110.         turtle.dropDown()
  111.         itemsAmt = itemsAmt + slotDetail.count
  112.         curSlot = curSlot + 1
  113.         slotDetail = turtle.getItemDetail(curSlot)
  114.     end
  115.     turtle.select(1)
  116.     print("* Dropped off "..tostring(itemsAmt).." item"..(itemsAmt == 1 and "" or "s"))
  117.     return itemsAmt
  118. end
  119.  
  120. -- returns to the dropoff inventory after the harvest cycle is complete
  121. function returnToDropoff()
  122.     print("* Cycle finished, returning to dropoff")
  123.     if DISTANCE_Y % 2 ~= 0 then
  124.         turtle.turnRight()
  125.         turtle.turnRight()
  126.         for x=1, DISTANCE_X - 1, 1 do
  127.             turtle.forward()
  128.             xPos = xPos - 1
  129.         end
  130.         turtle.turnRight()
  131.     else
  132.         turtle.forward()
  133.         xPos = xPos - 1
  134.         turtle.turnRight()
  135.     end
  136.     for y=1, DISTANCE_Y - 2, 1 do
  137.         turtle.forward()
  138.         yPos = yPos - 1
  139.     end
  140.     turtle.down()
  141. end
  142.  
  143. -- #SECTION harvest
  144.  
  145. -- runs through the entire harvesting cycle, starting from the refuel station and ending up on the dropoff station
  146. function harvest()
  147.     fuelBeforeCycle = turtle.getFuelLevel()
  148.  
  149.     turtle.up()
  150.     turtle.forward()
  151.     xPos = xPos + 1
  152.  
  153.     local turnCycle = 1
  154.     local xDir = 1
  155.  
  156.     for y=1, DISTANCE_Y, 1 do
  157.         for x=1, DISTANCE_X - 2, 1 do
  158.             turtle.dig()
  159.             turtle.digDown()
  160.             turtle.forward()
  161.             xPos = xPos + xDir
  162.         end
  163.         if yPos == DISTANCE_Y then
  164.             turtle.digDown()
  165.             returnToDropoff()
  166.             return
  167.         end
  168.         if turnCycle == 1 then
  169.             xPos = xPos + 1
  170.             turtle.turnRight()
  171.             turtle.dig()
  172.             turtle.digDown()
  173.             turtle.forward()
  174.             turtle.turnRight()
  175.             turtle.dig()
  176.             turtle.digDown()
  177.             turnCycle = 2
  178.             xDir = -1
  179.         else
  180.             xPos = xPos - 1
  181.             turtle.turnLeft()
  182.             turtle.dig()
  183.             turtle.digDown()
  184.             turtle.forward()
  185.             turtle.turnLeft()
  186.             turtle.dig()
  187.             turtle.digDown()
  188.             turnCycle = 1
  189.             xDir = 1
  190.         end
  191.         yPos = yPos + 1
  192.     end
  193.  
  194.     turtle.down()
  195. end
  196.  
  197. -- #SECTION gps
  198.  
  199. ORIENTATIONS = { "N", "E", "S", "W" }
  200.  
  201. -- paths back to the home position using GPS
  202. function gpsGoHome(orient)
  203.     local homeX, homeY, homeZ, homeOrient = gpsGetHomePos()
  204.     if homeX == nil then
  205.         print("\n! Error: Home position not set!")
  206.         return false
  207.     end
  208.     local curX, curY, curZ = gps.locate(GPS_TIMEOUT)
  209.     local curOrient = orient and orient or gpsDetermineOrientation()
  210.  
  211.     if curX == nil then
  212.         print("\n! Error: No GPS signal!\n! Either set USE_GPS_HOME to false\n! or provide a GPS tower and ender modem\n")
  213.         return false
  214.     end
  215.  
  216.     if homeX == curX and homeY == curY and homeZ == curZ and homeOrient == curOrient then
  217.         return true
  218.     end
  219.  
  220.     print("\n! Starting in unexpected position.\n! Returning to refueling station...")
  221.  
  222.     local xDiff = homeX - curX
  223.     local yDiff = homeY - curY
  224.     local zDiff = homeZ - curZ
  225.     local orientDiff = homeOrient - curOrient
  226.     if orientDiff < 0 then
  227.         orientDiff = orientDiff + 4
  228.     end
  229.  
  230.     -- Determine the directions to move
  231.     local xDir = xDiff < 0 and -1 or xDiff == 0 and 0 or 1 -- 1 for east, -1 for west
  232.     local yDir = yDiff < 0 and -1 or yDiff == 0 and 0 or 1 -- 1 for up, -1 for down
  233.     local zDir = zDiff < 0 and -1 or zDiff == 0 and 0 or 1 -- 1 for south, -1 for north
  234.  
  235.     -- Determine the amounts to move
  236.     local xAmount = math.abs(xDiff)
  237.     local yAmount = math.abs(yDiff)
  238.     local zAmount = math.abs(zDiff)
  239.  
  240.     -- Face towards the x axis
  241.  
  242.     local turnTimes = 0
  243.     if curOrient == 1 then -- Facing North
  244.         if xDir == 1 then -- Want to face East
  245.             turnTimes = 1 -- Turn right once
  246.         elseif xDir == -1 then -- Want to face West
  247.             turnTimes = -1 -- Turn left once
  248.         end
  249.     elseif curOrient == 2 then -- Facing East
  250.         if xDir == -1 then -- Want to face West
  251.             turnTimes = 2 -- Turn twice
  252.         end
  253.     elseif curOrient == 3 then -- Facing South
  254.         if xDir == 1 then -- Want to face East
  255.             turnTimes = -1 -- Turn left once
  256.         elseif xDir == -1 then -- Want to face West
  257.             turnTimes = 1 -- Turn right once
  258.         end
  259.     elseif curOrient == 4 then -- Facing West
  260.         if xDir == 1 then -- Want to face East
  261.             turnTimes = 2 -- Turn twice
  262.         end
  263.     end
  264.  
  265.     for i=1, math.abs(turnTimes), 1 do
  266.         if turnTimes > 0 then
  267.             turtle.turnRight()
  268.             curOrient = curOrient + 1
  269.         elseif turnTimes < 0 then
  270.             turtle.turnLeft()
  271.             curOrient = curOrient - 1
  272.         end
  273.     end
  274.  
  275.     if curOrient > 4 then
  276.         curOrient = curOrient - 4
  277.     elseif curOrient < 1 then
  278.         curOrient = curOrient + 4
  279.     end
  280.  
  281.     -- Move up for safety
  282.  
  283.     local upHeight = GPS_SAFETY_HEIGHT
  284.     if yDiff > 0 then
  285.         upHeight = upHeight + yDiff
  286.     end
  287.  
  288.     for i=1, upHeight, 1 do
  289.         if not turtle.up() then
  290.             return false
  291.         end
  292.     end
  293.  
  294.     -- Move in the x axis
  295.  
  296.     for i=1, xAmount, 1 do
  297.         if not turtle.forward() then
  298.             return false
  299.         end
  300.         goHomeTryRefuel();
  301.     end
  302.  
  303.     -- Face towards the z axis
  304.  
  305.     turnTimes = 0
  306.     if curOrient == 1 then -- Facing North
  307.         if zDir == 1 then -- Want to face South
  308.             turnTimes = 2 -- Turn twice
  309.         end
  310.     elseif curOrient == 2 then -- Facing East
  311.         if zDir == 1 then -- Want to face South
  312.             turnTimes = 1 -- Turn right once
  313.         elseif zDir == -1 then -- Want to face North
  314.             turnTimes = -1 -- Turn left once
  315.         end
  316.     elseif curOrient == 3 then -- Facing South
  317.         if zDir == -1 then -- Want to face North
  318.             turnTimes = 2 -- Turn twice
  319.         end
  320.     elseif curOrient == 4 then -- Facing West
  321.         if zDir == 1 then -- Want to face South
  322.             turnTimes = -1 -- Turn left once
  323.         elseif zDir == -1 then -- Want to face North
  324.             turnTimes = 1 -- Turn right once
  325.         end
  326.     end
  327.  
  328.     for i=1, math.abs(turnTimes), 1 do
  329.         if turnTimes > 0 then
  330.             turtle.turnRight()
  331.             curOrient = curOrient + 1
  332.         elseif turnTimes < 0 then
  333.             turtle.turnLeft()
  334.             curOrient = curOrient - 1
  335.         end
  336.     end
  337.  
  338.     if curOrient > 4 then
  339.         curOrient = curOrient - 4
  340.     elseif curOrient < 1 then
  341.         curOrient = curOrient + 4
  342.     end
  343.  
  344.     -- Move in the z axis
  345.  
  346.     for i=1, zAmount, 1 do
  347.         if not turtle.forward() then
  348.             return false
  349.         end
  350.         goHomeTryRefuel();
  351.     end
  352.  
  353.     -- Move back down
  354.  
  355.     local downHeight = GPS_SAFETY_HEIGHT
  356.     if yDiff < 0 then
  357.         downHeight = downHeight + math.abs(yDiff)
  358.     end
  359.  
  360.     for i=1, downHeight, 1 do
  361.         if not turtle.down() then
  362.             return false
  363.         end
  364.     end
  365.  
  366.     -- Face the home orientation
  367.  
  368.     turnTimes = curOrient - homeOrient
  369.     if turnTimes < 0 then
  370.         turnTimes = turnTimes + 4
  371.     end
  372.  
  373.     for i=1, turnTimes, 1 do
  374.         turtle.turnLeft()
  375.     end
  376.  
  377.     return true
  378. end
  379.  
  380. -- Tries to refuel while going home if the level is low
  381. function goHomeTryRefuel()
  382.     local itemDet = turtle.getItemDetail(1)
  383.     if itemDet == nil then
  384.         return
  385.     end
  386.     turtle.select(1)
  387.     while turtle.getFuelLevel() < TARGET_FUEL_LEVEL do
  388.         turtle.refuel(1)
  389.         itemDet = turtle.getItemDetail(1)
  390.         if itemDet == nil then
  391.             break
  392.         end
  393.     end
  394. end
  395.  
  396. -- Returns the home position of the turtle as a table
  397. -- Contents: x, y, z, orientation
  398. -- Returns all nil if the home position doesn't exist
  399. function gpsGetHomePos()
  400.     if not fs.exists(HOME_COORDS_PATH) then
  401.         return nil, nil, nil, nil
  402.     end
  403.     local file = fs.open(HOME_COORDS_PATH, "r")
  404.     local x = file.readLine()
  405.     local y = file.readLine()
  406.     local z = file.readLine()
  407.     local orientation = file.readLine()
  408.     file.close()
  409.     return tonumber(x), tonumber(y), tonumber(z), tonumber(orientation)
  410. end
  411.  
  412. function gpsPromptSetHomePos()
  413.     local x, y, z = gps.locate(GPS_TIMEOUT)
  414.     if x ~= nil then
  415.         print("\nCurrent position: "..tostring(x)..", "..tostring(y)..", "..tostring(z))
  416.         term.write("Set as home position? (Y/n): ")
  417.         local setHomePos = nil
  418.         while true do
  419.             setHomePos = read()
  420.             if setHomePos ~= nil then
  421.                 break
  422.             end
  423.         end
  424.         if setHomePos == "y" or setHomePos == "Y" or setHomePos == "" then
  425.             if turtle.getFuelLevel() < TARGET_FUEL_LEVEL then
  426.                 refuel()
  427.             end
  428.  
  429.             print("\nDetermining facing...")
  430.             local orientation = gpsDetermineOrientation()
  431.             if orientation == nil then
  432.                 print("\nTurtle is stuck or out of fuel!\nPlease make sure at least one adjacent block is air and enough fuel is present.\n")
  433.                 return
  434.             end
  435.  
  436.             if fs.exists(HOME_COORDS_PATH) then
  437.                 fs.delete(HOME_COORDS_PATH)
  438.             end
  439.  
  440.             local file = fs.open(HOME_COORDS_PATH, "w")
  441.             file.write(tostring(x).."\n"..tostring(y).."\n"..tostring(z).."\n"..tostring(orientation).."\n")
  442.             file.close()
  443.  
  444.             print("\nHome position set successfully!\n")
  445.             return true
  446.         end
  447.         return false
  448.     else
  449.         print("\nError: GPS not available!\n")
  450.         return false
  451.     end
  452. end
  453.  
  454. -- Determines the cardinal direction the turtle is oriented in
  455. -- by trying to move in any available direction and then back to
  456. -- the original position without breaking any adjacent blocks
  457. function gpsDetermineOrientation()
  458.     print("* Determining turtle facing...")
  459.     local x1, y1, z1 = gps.locate(GPS_TIMEOUT)
  460.  
  461.     if x1 == nil then
  462.         return nil
  463.     end
  464.  
  465.     local turns = 0
  466.     if not turtle.forward() then
  467.         turtle.turnRight()
  468.         turns = turns + 1
  469.         if not turtle.forward() then
  470.             turtle.turnRight()
  471.             turns = turns + 1
  472.             if not turtle.forward() then
  473.                 turtle.turnRight()
  474.                 turns = turns + 1
  475.                 if not turtle.forward() then
  476.                     turtle.turnRight()
  477.                     return nil
  478.                 end
  479.             end
  480.         end
  481.     end
  482.  
  483.     local x2, y2, z2 = gps.locate(GPS_TIMEOUT)
  484.     turtle.back()
  485.  
  486.     for i=1, turns, 1 do
  487.         turtle.turnLeft()
  488.     end
  489.  
  490.     local orientation = nil
  491.     if x1 == x2 then
  492.         if z1 > z2 then
  493.             orientation = 1
  494.         else
  495.             orientation = 3
  496.         end
  497.     else
  498.         if x1 > x2 then
  499.             orientation = 4
  500.         else
  501.             orientation = 2
  502.         end
  503.     end
  504.     orientation = orientation - turns
  505.     if orientation <= 0 then
  506.         orientation = orientation + 4
  507.     end
  508.     return orientation
  509. end
  510.  
  511. -- #SECTION stats
  512.  
  513. -- Returns the stats as a table
  514. -- Contents: cyclesCompleted, totalItems
  515. -- Returns all nil if the stats file doesn't exist
  516. function loadStats()
  517.     if not fs.exists(STATS_PATH) then
  518.         return nil, nil
  519.     end
  520.     local file = fs.open(STATS_PATH, "r")
  521.     cyclesCompleted = tonumber(file.readLine())
  522.     totalItems = tonumber(file.readLine())
  523.     file.close()
  524.     return cyclesCompleted, totalItems
  525. end
  526.  
  527. -- Saves the passed stats to the turtle's stats file
  528. -- Values are added to the already recorded stats
  529. function addStats(cycles, items)
  530.     local cyclesCompleted, totalItems = loadStats()
  531.  
  532.     if cyclesCompleted == nil then
  533.         cyclesCompleted = 0
  534.         totalItems = 0
  535.     end
  536.  
  537.     cyclesCompleted = cyclesCompleted + cycles
  538.     totalItems = totalItems + items
  539.  
  540.     if fs.exists(STATS_PATH) then
  541.         fs.delete(STATS_PATH)
  542.     end
  543.  
  544.     local file = fs.open(STATS_PATH, "w")
  545.     file.write(tostring(cyclesCompleted).."\n"..tostring(totalItems).."\n")
  546.     file.close()
  547.  
  548.     return true
  549. end
  550.  
  551. -- Prints stats to the console
  552. function printStats()
  553.     local cyclesCompleted, totalItems = loadStats()
  554.     print("")
  555.     print("-> Turtle stats:")
  556.     print("   Current fuel level:    "..tostring(turtle.getFuelLevel()).." / "..tostring(TARGET_FUEL_LEVEL))
  557.     print("   Fuel usage last cycle: "..tostring(fuelPerCycle))
  558.     print("   Total harvests done:   "..tostring(cyclesCompleted))
  559.     print("   Total items offloaded: "..tostring(totalItems))
  560.     print("")
  561. end
  562.  
  563. -- #SECTION run
  564.  
  565. function run()
  566.     print("\n| SugarcaneFarm by Sv443\n")
  567.  
  568.     if USE_GPS_HOME then
  569.         local homeX, homeY, homeZ, homeOrient = gpsGetHomePos()
  570.         if homeX == nil then
  571.             if not gpsPromptSetHomePos() then
  572.                 print("\n! GPS home not set, exiting.\n")
  573.                 return
  574.             end
  575.         else
  576.             local x, y, z = gps.locate(GPS_TIMEOUT)
  577.             local orientation = gpsDetermineOrientation()
  578.             if x ~= homeX or y ~= homeY or z ~= homeZ or orientation ~= homeOrient then
  579.                 if not gpsGoHome(orientation) then
  580.                     print("\n! Couldn't return home :(\n")
  581.                     return
  582.                 else
  583.                     print("\n* Honey, I'm home!")
  584.                     os.sleep(2)
  585.                 end
  586.             end
  587.         end
  588.     end
  589.  
  590.     while true do
  591.         local cyclesCompleted = loadStats()
  592.  
  593.         xPos = 1
  594.         yPos = 1
  595.  
  596.         print("")
  597.         refuel()
  598.         print("* Starting cycle #"..tostring((cyclesCompleted or 0) + 1))
  599.         harvest()
  600.         local itemsDropped = dropItems()
  601.         moveRefuel()
  602.  
  603.         addStats(1, itemsDropped)
  604.         printStats()
  605.  
  606.         print("* Waiting "..tostring(DELAY_BETWEEN_HARVESTS).."s until next cycle")
  607.         os.sleep(DELAY_BETWEEN_HARVESTS)
  608.     end
  609. end
  610.  
  611. run()
Add Comment
Please, Sign In to add comment