naschorr

ultiminer

May 20th, 2017
119
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 13.44 KB | None | 0 0
  1. -- Consts
  2. local ARGS = {...}
  3. local DOWN_SQUARE = 0
  4. local UP_SQUARE = 1
  5. local SQUARE_HEIGHT = 3
  6. local LIGHT_RIGHT = 0
  7. local LIGHT_LEFT = 1
  8. local TURTLE_INV_SIZE = 16
  9. -- End Consts
  10.  
  11. -- Config
  12. local CLEAN_INV_ENABLE = true
  13. local CLEAN_INV_AFTER_DISTANCE = 9
  14. local CHEST_SUBSTRINGS = {"chest"}
  15. local LIQUID_BLOCKS = {"water", "flowing_water", "lava", "flowing_lava"}
  16. local GRAVITY_BLOCKS = {"sand", "gravel"}
  17. local LIGHT_BLOCKS = {"torch", "glowstone", "lit_pumpkin"}
  18. local PLACE_SUBSTRINGS = {"stone", "dirt", "ore"}
  19. local DROP_BLOCKS = {"cobblestone", "stone", "dirt", "sand", "gravel"}
  20. local LIGHT_ENABLE = true
  21. local LIGHT_DISTANCE = 6
  22. local LIGHT_ALTERNATE = false
  23. -- End Config
  24.  
  25. -- Utility functions
  26. -- Get name from inspect()'s data table
  27. local function getBlockName(data)
  28. if(not data) then
  29. return nil
  30. elseif(not data.name) then
  31. return nil
  32. end
  33.  
  34. return data.name:match(":(.+)"):lower()
  35. end
  36.  
  37. -- Check if any of a str table's indeces are substrings of a given string
  38. local function isTableSubstring(string, strTable)
  39. if(type(strTable) ~= "table" or not string) then
  40. return false
  41. end
  42.  
  43. for index, str in pairs(strTable) do
  44. if(string:find(str)) then
  45. return true
  46. end
  47. end
  48. return false
  49. end
  50.  
  51. -- Check if any of a str table's indeces match the given string
  52. local function isTableMatch(string, strTable)
  53. if(type(strTable) ~= "table" or not string) then
  54. return false
  55. end
  56.  
  57. for index, str in pairs(strTable) do
  58. if(str == string) then
  59. return true
  60. end
  61. end
  62. return false
  63. end
  64. -- End Utility functions4mT1Gsr
  65.  
  66. -- MinerTurtle class
  67. local MinerTurtle = {}
  68. MinerTurtle.__index = MinerTurtle
  69. setmetatable(MinerTurtle, {
  70. __call = function(cls, ...)
  71. return cls.init(...)
  72. end,
  73. })
  74.  
  75. -- Drops non-fuel, non-light inventory items into a chest
  76. function MinerTurtle.depositInv(self)
  77. -- Determine if the front block is a chest
  78. local function isChest(chestSubstrings)
  79. local status, data = turtle.inspect()
  80.  
  81. if(not isTableSubstring(getBlockName(data), chestSubstrings)) then
  82. print("No chest available")
  83. return false
  84. end
  85.  
  86. return true
  87. end
  88.  
  89. -- Dont empty items into a non-chest
  90. if(not isChest(self.chestSubstrings)) then
  91. return false
  92. end
  93.  
  94. -- Dump non-fuel and non-light items into the chest
  95. for index=1, self.invSize do
  96. turtle.select(index)
  97. local item = turtle.getItemDetail()
  98. if(not turtle.refuel(0) and not isTableMatch(getBlockName(item), self.lightBlocks)) then
  99. turtle.drop()
  100. end
  101. end
  102. end
  103.  
  104. -- Drops inventory items found in DROP_BLOCKS
  105. function MinerTurtle.cleanInv(self)
  106. for index=1, self.invSize do
  107. turtle.select(index)
  108. local item = turtle.getItemDetail()
  109. if(isTableMatch(getBlockName(item), self.dropBlocks)) then
  110. turtle.drop()
  111. end
  112. end
  113. end
  114.  
  115. -- Refuel the turtle
  116. -- Return true if refuel successful or already fuelled / false if unsuccessful
  117. function MinerTurtle.refuel(self, amount)
  118. -- Args
  119. local amount = amount or 1
  120.  
  121. -- Don't bother with refuelling if the current fuel level is high enough
  122. if(turtle.getFuelLevel() >= amount) then
  123. return true
  124. end
  125.  
  126. local index = 1
  127. local hasRefueled = false
  128. while(index <= self.invSize and not hasRefueled) do
  129. turtle.select(index)
  130. local isRefueling = true
  131. while(isRefueling) do
  132. if(turtle.refuel(0)) then
  133. if(turtle.getFuelLevel() < amount) then
  134. turtle.refuel(1)
  135. else
  136. isRefueling = false
  137. hasRefueled = true
  138. end
  139. else
  140. isRefueling = false
  141. end
  142. end
  143. index = index + 1
  144. end
  145.  
  146. return hasRefueled
  147. end
  148.  
  149. -- Place wrapper
  150. function MinerTurtle.placeBlock(self, direction)
  151. -- Tries to select placeable blocks in the turtle's inventor (see PLACE_SUBSTRINGS)
  152. local function selectBlock()
  153. local index = 1
  154. local isPlaceable = false
  155. while(index <= self.invSize and not isPlaceable) do
  156. turtle.select(index)
  157. local item = turtle.getItemDetail()
  158. if(isTableSubstring(getBlockName(item), self.placeSubstrings)) then
  159. isPlaceable = true
  160. end
  161. index = index + 1
  162. end
  163.  
  164. return isPlaceable
  165. end
  166.  
  167. -- Handle block selection
  168. local result = selectBlock()
  169. if(not result) then
  170. return false -- Unable to select a block to place
  171. end
  172.  
  173. -- Handle placement
  174. if(direction == "up") then
  175. result = turtle.placeUp()
  176. elseif(direction == "down") then
  177. result = turtle.placeDown()
  178. elseif(direction == "forward" or nil) then
  179. result = turtle.place()
  180. else
  181. print("placeBlock(): arg direction", direction, "isn't valid")
  182. return false
  183. end
  184.  
  185. return result
  186. end
  187.  
  188. -- Turn wrapper
  189. function MinerTurtle.turn(self, direction, turns)
  190. -- Args
  191. local turns = tonumber(turns) or 1
  192.  
  193. -- Handle turning
  194. if(direction == "right") then
  195. self.orientation = (self.orientation + 1) % 4
  196. turtle.turnRight()
  197. elseif(direction == "left") then
  198. self.orientation = (self.orientation - 1) % 4
  199. turtle.turnLeft()
  200. else
  201. print("turn(): arg direction", direction, "isn't valid")
  202. return false
  203. end
  204.  
  205. -- Turn multiple times if necessary
  206. if(turns > 1) then
  207. return self:turn(direction, turns - 1)
  208. else
  209. return true
  210. end
  211. end
  212.  
  213. -- Dig wrapper
  214. function MinerTurtle.dig(self, direction)
  215. -- Handle digging
  216. local result, status, data
  217. if(direction == "up") then
  218. result = turtle.digUp()
  219. status, data = turtle.inspectUp()
  220. elseif(direction == "down") then
  221. result = turtle.digDown()
  222. status, data = turtle.inspectDown()
  223. elseif(direction == "forward" or direction == nil) then
  224. result = turtle.dig()
  225. status, data = turtle.inspect()
  226. else
  227. print("dig(): arg direction", direction, "isn't valid movement")
  228. return false
  229. end
  230.  
  231. if(status and not isTableMatch(getBlockName(data), self.liquidBlocks)) then
  232. return self:dig(direction)
  233. else
  234. return true
  235. end
  236. end
  237.  
  238. -- Move wrapper
  239. function MinerTurtle.move(self, direction, distance)
  240. -- Args
  241. local distance = tonumber(distance) or 1
  242.  
  243. self:refuel()
  244.  
  245. -- Handle movement (and failure to move)
  246. local result
  247. if(direction == "up") then
  248. result = turtle.up()
  249. if(result) then
  250. self.height = self.height + 1
  251. else
  252. return self:digMove("up")
  253. end
  254.  
  255. elseif(direction == "down") then
  256. result = turtle.down()
  257. if(result) then
  258. self.height = self.height - 1
  259. else
  260. return self:digMove("down")
  261. end
  262.  
  263. elseif(direction == "forward") then
  264. result = turtle.forward()
  265. if(result) then
  266. self.distance = self.distance + 1
  267. else
  268. return self:digMove("forward")
  269. end
  270.  
  271. elseif(direction == "back") then
  272. result = turtle.back()
  273. if(result) then
  274. self.distance = self.distance - 1
  275. else
  276. self:turn("left", 2)
  277. self:dig("forward")
  278. self:turn("left", 2)
  279. return self:move("back")
  280. end
  281.  
  282. else
  283. print("move(): arg direction", direction, "isn't valid movement")
  284. return false
  285. end
  286.  
  287. -- Move multiple times if necessary
  288. if(distance > 1) then
  289. return self:move(direction, distance - 1)
  290. else
  291. return true
  292. end
  293. end
  294.  
  295. -- Combine dig and move operations
  296. function MinerTurtle.digMove(self, direction, distance)
  297. -- Args
  298. local distance = tonumber(distance) or 1
  299.  
  300. -- Handle digging and movement
  301. local status
  302. if(direction == "up") then
  303. self:dig("up")
  304. status = self:move("up")
  305. elseif(direction == "down") then
  306. self:dig("down")
  307. status = self:move("down")
  308. elseif(direction == "forward") then
  309. self:dig("forward")
  310. status = self:move("forward")
  311. else
  312. print("digMove(): arg direction", direction, "isn't valid movement")
  313. return false
  314. end
  315.  
  316. -- DigMove multiple times if necessary
  317. if(distance > 1) then
  318. return self:digMove(direction, distance - 1)
  319. else
  320. return true
  321. end
  322. end
  323.  
  324. -- Places a torch found in LIGHT_BLOCKS
  325. function MinerTurtle.placeTorch(self)
  326. local index = 1
  327. local hasTorched = false
  328. while(index <= self.invSize and not hasTorched) do
  329. turtle.select(index)
  330. local item = turtle.getItemDetail()
  331. if(isTableMatch(getBlockName(item), self.lightBlocks)) then
  332. hasTorched = turtle.place()
  333. end
  334. index = index + 1
  335. end
  336.  
  337. return hasTorched
  338. end
  339.  
  340. -- Orients the turtle then places a torch before returning to top-middle of the square
  341. -- TODO check for failures and correct (if-chain?)
  342. function MinerTurtle.orientPlaceTorch(self)
  343. -- Get to top of square
  344. if(self.squareType == DOWN_SQUARE) then
  345. self:move("up", 2)
  346. end
  347.  
  348. -- Approach torch position
  349. if(self.lightSide == LIGHT_RIGHT) then
  350. self:turn("right")
  351. else
  352. self:turn("left")
  353. end
  354.  
  355. -- Make sure the torch has a block to be placed on
  356. self:move("forward")
  357. if(not turtle.inspect()) then
  358. self:placeBlock("forward")
  359. end
  360. self:move("back")
  361.  
  362. self:placeTorch()
  363.  
  364. -- Face forward
  365. if(self.lightSide == LIGHT_RIGHT) then
  366. self:turn("left")
  367. else
  368. self:turn("right")
  369. end
  370.  
  371. -- Change lightSide if necessary
  372. if(self.lightAlternate) then
  373. if(self.lightSide == LIGHT_RIGHT) then
  374. self.lightSide = LIGHT_LEFT
  375. else
  376. self.lightSide = LIGHT_RIGHT
  377. end
  378. end
  379.  
  380. -- Change to UP_SQUARE to avoid extra movements
  381. self.squareType = UP_SQUARE
  382.  
  383. return result
  384. end
  385.  
  386. -- Tunnel out a 3x3 vertical square over a distance
  387. function MinerTurtle.tunnel3x3(self, distance)
  388. -- Tries to stop liquid blocks in front of and above the turtle
  389. local function attemptStopLiquid()
  390. local status, data = turtle.inspectUp() -- above
  391. if(isTableMatch(getBlockName(data), self.liquidBlocks)) then
  392. self:placeBlock("up")
  393. end
  394.  
  395. status, data = turtle.inspectDown() -- below
  396. if(isTableMatch(getBlockName(data), self.liquidBlocks)) then
  397. self:placeBlock("down")
  398. end
  399.  
  400. status, data = turtle.inspect() -- forward
  401. if(isTableMatch(getBlockName(data), self.liquidBlocks)) then
  402. -- Try to patch forward and above blocks if they're liquid as well
  403. self:move("forward")
  404.  
  405. status, data = turtle.inspectDown() -- below
  406. if(isTableMatch(getBlockName(data), self.liquidBlocks)) then
  407. self:placeBlock("down")
  408. end
  409.  
  410. status, data = turtle.inspect() -- forward-most
  411. if(isTableMatch(getBlockName(data), self.liquidBlocks)) then
  412. self:placeBlock("forward")
  413. end
  414.  
  415. status, data = turtle.inspectUp() -- above
  416. if(isTableMatch(getBlockName(data), self.liquidBlocks)) then
  417. self:placeBlock("up")
  418. end
  419.  
  420. self:move("back")
  421. end
  422. end
  423.  
  424. -- Digs out the adjacent left and right blocks
  425. local function digAdjacentLR()
  426. self:turn("left")
  427. self:dig()
  428. attemptStopLiquid()
  429.  
  430. self:turn("left", 2)
  431. self:dig()
  432. attemptStopLiquid()
  433.  
  434. self:turn("left")
  435. end
  436.  
  437. -- Args
  438. local distance = tonumber(distance) or 0
  439.  
  440. -- Make sure theres a distance to traverse
  441. if(distance < 1) then
  442. return false
  443. end
  444.  
  445. self:digMove("forward")
  446.  
  447. -- Make sure there isn't any gravel or sand above
  448. if(self.squareType == UP_SQUARE) then
  449. local status, data = turtle.inspectUp()
  450. if(isTableMatch(getBlockName(data), self.gravityBlocks)) then
  451. self:dig("up")
  452. end
  453. end
  454.  
  455. -- Start digging it out
  456. for row=1, SQUARE_HEIGHT do
  457. digAdjacentLR()
  458. if(row < SQUARE_HEIGHT) then
  459. if(self.squareType == DOWN_SQUARE) then
  460. self:digMove("up")
  461. else
  462. self:digMove("down")
  463. end
  464. end
  465. end
  466.  
  467. -- Swap square types
  468. if(self.squareType == DOWN_SQUARE) then
  469. self.squareType = UP_SQUARE
  470. else
  471. self.squareType = DOWN_SQUARE
  472. end
  473.  
  474. -- Place torch if necessary
  475. if(self.lightEnable and (self.distance % self.lightDistance) == 0) then
  476. self:orientPlaceTorch()
  477. end
  478.  
  479. -- Clear out unneeded blocks from the inventory
  480. if(self.cleanInvEnable and (self.distance % self.cleanInvAfterDistance) == 0) then
  481. self:cleanInv()
  482. end
  483.  
  484. -- Continue tunnelling
  485. self:tunnel3x3(distance - 1)
  486. end
  487.  
  488. -- Init the MinerTurtle class
  489. function MinerTurtle.init()
  490. local self = setmetatable({}, MinerTurtle)
  491.  
  492. self.height = 0 -- Height relative turtle's starting position.
  493. self.distance = 0 -- Distance travelled so far (in all orientations)
  494. self.orientation = 0 -- 0 refers to forward when placed, 1, 2, 3 refer to right, back, left.
  495. self.squareType = DOWN_SQUARE
  496. self.cleanInvEnable = CLEAN_INV_ENABLE
  497. self.cleanInvAfterDistance = CLEAN_INV_AFTER_DISTANCE
  498. self.chestSubstrings = CHEST_SUBSTRINGS
  499. self.placeSubstrings = PLACE_SUBSTRINGS
  500. self.gravityBlocks = GRAVITY_BLOCKS
  501. self.dropBlocks = DROP_BLOCKS
  502. self.liquidBlocks = LIQUID_BLOCKS
  503. self.invSize = TURTLE_INV_SIZE
  504. self.lightEnable = LIGHT_ENABLE
  505. self.lightBlocks = LIGHT_BLOCKS
  506. self.lightDistance = LIGHT_DISTANCE
  507. self.lightAlternate = LIGHT_ALTERNATE
  508. self.lightSide = LIGHT_RIGHT
  509.  
  510. if(not self:refuel()) then
  511. print("No fuel available")
  512. return false
  513. end
  514.  
  515. return self
  516. end
  517. -- End MinerTurtle Class
  518.  
  519. -- Main
  520. local function main(distance, skipDistance)
  521. -- Args
  522. local distance = tonumber(distance) or 0
  523. local skipDistance = tonumber(skipDistance) or 0
  524.  
  525. -- Start mining
  526. local minerTurtle = MinerTurtle()
  527. if(not minerTurtle) then
  528. return
  529. end
  530.  
  531. if(skipDistance > 0) then
  532. minerTurtle:move("forward", skipDistance)
  533. end
  534.  
  535. minerTurtle:tunnel3x3(distance)
  536. minerTurtle:turn("left", 2)
  537. minerTurtle:move("forward", distance + skipDistance)
  538.  
  539. if(minerTurtle.height > 1) then
  540. minerTurtle:move("down", minerTurtle.height)
  541. end
  542.  
  543. minerTurtle:turn("left")
  544. minerTurtle:depositInv()
  545. minerTurtle:turn("left")
  546. end
  547.  
  548. main(unpack(ARGS))
Advertisement
Add Comment
Please, Sign In to add comment