buffsovernexus

FarmBot v4.0.0

May 22nd, 2019
209
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 12.25 KB | None | 0 0
  1. --[[
  2.  
  3. FarmerBot v4.0.0
  4.  
  5. -- Banned Mods --
  6. Natura > This mod was not properly built in the sense that the bot cannot understand when crops are done growing.
  7. HarvestCraft > Now works normally with new script.
  8.  
  9. -- Instructions --
  10. 1) Place your bot on top of a chest, which is one space below the bottom-right of the farm.
  11. 2) Run this script.
  12. 3) Enter in how many rows there are (how many rows are to the left?)
  13. 4) Enter in how long each row is (how far does the bot have to go down the row)
  14. 5) Enter in what seed the bot will place on empty farmland.
  15.  
  16. -- Side Notes --
  17. ~ The bot will stop working properly if you do not give it more fuel.
  18. ~ The bot will dynamically learn new props from the mod list.
  19. ~ The bot will refuel automatically if it runs into a fuel source (like feeding it a lava bucket in a hopper) before it goes again.
  20. ~ This script will give detailed information on each newly learned crop.
  21. ~ If you enter in 0 for Seed ID, the bot will plant any seed it has in its inventory.
  22.  
  23.  
  24. -- Future Plans --
  25. ~ The bot will communicate with an outside service (a designated script called FBDS) to handle crop and remote functionality.
  26.  
  27. ]]--
  28.  
  29. -- This table is the "memory" of the bot.
  30. local botdata = {
  31. crops = {},
  32. cmds = {},
  33. mods = {},
  34. input = {},
  35. -- VERIFY: This is either true or false (true = success, false = fail)
  36. }
  37.  
  38. -- This table is meant to be sent to the DB.
  39. local botSendData = {
  40. learned = {},
  41. input = {},
  42. gps = {
  43. x = 0,
  44. y = 0,
  45. z = 0
  46. },
  47. request = "" -- This is the type of request for the DB to filter out (e.g. learn: Learned a new crop, now handle it.)
  48. }
  49.  
  50. --[[ handleModem()
  51.  
  52. Task: Allow the bot to remotely speak to a specific computer.
  53.  
  54. ]]--
  55. function handleModem()
  56. if rednet.isOpen("right") == false then
  57. rednet.open("right")
  58. end
  59. rednet.host("fbtpa", os.getComputerLabel())
  60. rednet.host("fbtp", os.getComputerLabel())
  61. end
  62.  
  63. handleModem()
  64.  
  65.  
  66. -- [[ START PLAYER INPUT ]]--
  67. local input = { rows = 0, length = 0, crop = 0, db = 0 }
  68.  
  69. function getUserInput()
  70. term.write("Enter number of rows (left): ")
  71. input.rows = tonumber(read())
  72. term.write("Enter in length of row (forward): ")
  73. input.length = tonumber(read())
  74. for k,v in pairs (botdata.crops) do
  75. print("#", v.id," - ", v.label)
  76. end
  77. term.write("Enter crop ID (or 0) for seeding: ")
  78. input.crop = tonumber(read())
  79. botdata.input = input
  80.  
  81. -- Send User Data to DB.
  82. botSendData.input = botdata.input
  83. botSendData.request = "input_send"
  84. rednet.send(input.db, textutils.serialize(botSendData), "fbtp")
  85. end
  86.  
  87. term.write("Enter in FarmBotDB ID: ")
  88. input.db = tonumber(read())
  89. botSendData.request = "input_ask"
  90. rednet.send(input.db, textutils.serialize(botSendData), "fbtp")
  91.  
  92. local senderId, response, protocol = rednet.receive("fbtp")
  93. response = textutils.unserialize(response)
  94.  
  95. -- Determine if previous instructions exist.
  96. if response.verify.isSuccess then
  97. term.clear()
  98. print(" Previous Task")
  99. print("---------------------------------------")
  100. print("Rows: " .. response.input.rows)
  101. print("Length: " .. response.input.length)
  102. print("Crop Seed ID: " .. response.input.crop)
  103. print(" ")
  104. term.write("Use this (y/n)? ")
  105. local answer = read()
  106. if string.lower(answer) == "y" then
  107. input = response.input
  108. botdata.input = response.input
  109. print("SUCCESS: Using previous task.")
  110. else
  111. getUserInput()
  112. end
  113. else
  114. getUserInput()
  115. end
  116. -- [[ END PLAYER INPUT ]]--
  117.  
  118. -- [[ SEND GPS COORDINATES ]]--
  119. local x, y, z = gps.locate()
  120.  
  121. -- Ensure the GPS location worked.
  122. if not x then
  123. print("ERROR: GPS location not found. Try again.")
  124. else
  125. botSendData.gps.x = x
  126. botSendData.gps.y = y
  127. botSendData.gps.z = z
  128. botSendData.request = "gps_send"
  129.  
  130. -- Send to DB.
  131. rednet.send(botdata.input.db, textutils.serialize(botSendData), "fbtp")
  132.  
  133. -- Wait for DB to respond.
  134. local senderId, response, protocol = rednet.receive("fbtp")
  135. response = textutils.unserialize(response)
  136. if response.verify.isSuccess then
  137. print("SUCCESS: Sending GPS location.")
  138. else
  139. print("ERROR: Unable to save GPS location.")
  140. end
  141. end
  142. --[[ END SEND GPS COORDINATES ]]--
  143.  
  144. --[[ getLatestCropList()
  145.  
  146. Task: Get the latest crop list from the DB.
  147.  
  148. ]]--
  149. function getLatestCropList()
  150. botSendData.request = "latest"
  151. rednet.send(botdata.input.db, textutils.serialize(botSendData), "fbtp")
  152. local senderId, response, protocol = rednet.receive("fbtp")
  153. response = textutils.unserialize(response)
  154. botdata.crops = response.crops
  155. botdata.mods = response.mods
  156. end
  157.  
  158. --[[ refuel()
  159.  
  160. Task: To check for any fuel in the slots and consume it.
  161.  
  162. ]]--
  163. function refuel()
  164. for i = 16,1,-1 do
  165. turtle.select(i)
  166. turtle.refuel( math.ceil(turtle.getItemCount()) )
  167. end
  168. end
  169.  
  170. --[[ dropItems()
  171.  
  172. Task: Select each item and put the item into the chest below.
  173.  
  174. ]]--
  175. function dropItems()
  176. for i = 16,1,-1 do
  177. turtle.select(i)
  178. turtle.dropDown()
  179. end
  180. end
  181.  
  182. --[[ fixBlock()
  183.  
  184. Task: Place a seed crop based on <input.crop>, or any seed if no specific crop.
  185.  
  186. ]]--
  187. function fixBlock()
  188. turtle.digDown()
  189. -- If the crop is 0, then the user wants the bot to place any seeds in the inventory.
  190. if input.crop == 0 then
  191. for k,v in pairs(botdata.crops) do
  192. if hasSeeds(v.id) then
  193. turtle.placeDown()
  194. break
  195. end
  196. end
  197. else
  198. -- The user has selected a specific crop.
  199. if hasSeeds(input.crop) then
  200. turtle.placeDown()
  201. end
  202. end
  203. end
  204.  
  205. -- 3.0 Function: Have the bot learn crops instead of manually entering them.
  206. function learnCrop(cropBlock)
  207. -- Determine if the block is in any of the mods we listed.
  208. for i = 1, getSize(botdata.mods) do
  209. if string.match( string.lower(cropBlock.name) , string.lower(botdata.mods[i]) ) then
  210. -- Step 1: Get the current list of crops and make the ID.
  211. local id = getSize(botdata.crops) + 1
  212. local cropName = cropBlock.name
  213.  
  214. -- Step 1b: Learn the maturity...
  215. local maturity = 7
  216. local metadata = 0
  217. if cropBlock ~= nil then metadata = cropBlock.metadata end
  218.  
  219. -- Step 2: Break the block to find the seed.
  220. turtle.digDown()
  221. -- Bug: Wait for all of the inventories.
  222. os.sleep(5);
  223. local unknown = {}
  224. for i = 1, 16 do
  225. local data = turtle.getItemDetail(i)
  226. --Look through each inventory space to find the unknown crop
  227. local isKnown = false
  228. for k,v in pairs(botdata.crops) do
  229. if data ~= nil then
  230. -- The crop is known, therefore skip it.
  231. if data.name == v.seed then
  232. isKnown = true
  233. end
  234. end
  235. end
  236.  
  237. -- If we do not know, then continue
  238. if isKnown == false then
  239. local checkDuplicates = false
  240. -- Check if data is already in unknown (no duplicates)
  241. if data ~= nil then
  242. for j=1, getSize(unknown) do
  243. if unknown[j].name == data.name then
  244. checkDuplicates = true
  245. end
  246. end
  247. end
  248.  
  249. if checkDuplicates == false then
  250. unknown[getSize(unknown) + 1] = data
  251. end
  252. end
  253. end
  254.  
  255. -- Step 3: Find the seed using the unknown blocks in the turtle.
  256. -- Quick Logic: If only one new item is found, then that is the seed.
  257. -- Other quick logic: If more than one (probably 2 at most) then check for 'seed' in text.
  258. local seedName = ""
  259. -- I don't know why it's here, but we'll keep it.
  260. getSize(unknown);
  261. if getSize(unknown) == 1 then
  262. seedName = unknown[1].name
  263. else
  264. for i=1,getSize(unknown) do
  265. if string.match( string.lower(unknown[i].name) , string.lower("%seed%") ) then
  266. seedName = unknown[i].name
  267. break
  268. end
  269. end
  270. end
  271.  
  272. -- Bug? Make sure seedName is filled. Otherwise, get the last thing to be added and call it a day.
  273. if string.len( seedName ) == 0 then
  274. seedName = unknown[getSize(unknown) - 1];
  275. end
  276.  
  277. -- Step 4: Enter in new crop to list of crops.
  278. local crop = { id = id, mature = maturity, name = cropName, seed = seedName, label = cropName, metadata = metadata }
  279.  
  280. -- Step 5: Add crop to cropdata.
  281. botSendData.learned = crop
  282. botSendData.request = "learn"
  283. rednet.send(input.db, textutils.serialize(botSendData), "fbtp")
  284.  
  285. -- Step 6: Wait for updated list from DB.
  286. local senderId, response, protocol = rednet.receive("fbtp")
  287. response = textutils.unserialize(response)
  288.  
  289. -- Step 7: Update the list to our bot.
  290. botdata.crops = response.crops
  291.  
  292. if response.verify.isSuccess then
  293. print(">> NEW CROP <<")
  294. print("Crop: ", crop.name)
  295. print("Seed:" , crop.seed)
  296. print("Maturity: ", crop.mature)
  297. else
  298. print(">> FAILED CROP <<")
  299. print("Crop: ", crop.name)
  300. end
  301.  
  302. -- Step 5: Replace seed.
  303. if hasSeeds(id) then
  304. turtle.placeDown()
  305. end
  306.  
  307. unknown = {};
  308. end
  309. end
  310.  
  311. end
  312.  
  313. --[[ Helper Functions ]]--
  314. function getSize(tbl)
  315. local count = 0
  316. if tbl == nil then return count end
  317. for _ in pairs(tbl) do count = count + 1 end
  318. return count
  319. end
  320. function isGrown(row, length, current, expected)
  321. if current == expected then
  322. return true
  323. end
  324. return false
  325. end
  326. function hasSeeds(id)
  327. for k,v in pairs(botdata.crops) do
  328. if v.id == id then
  329. for i = 1, 16 do
  330. local data = turtle.getItemDetail(i)
  331. if data ~= nil then
  332. if data.name == v.seed then
  333. turtle.select(i)
  334. return true
  335. end
  336. end
  337. end
  338. end
  339. end
  340. return false
  341. end
  342. --[[ End Helper Functions ]]--
  343. function handleFarming()
  344. --[[ START FARMING TASK ]]--
  345.  
  346. -- Adjust bot placement.
  347. os.sleep(1)
  348. if turtle.detectDown() then
  349. print("WARN: Fixing orientation.")
  350. turtle.up()
  351. os.sleep(1)
  352. turtle.forward()
  353. os.sleep(1)
  354. end
  355.  
  356. -- Make sure the bot has a list to grab from.
  357. getLatestCropList()
  358.  
  359.  
  360. while true do
  361. for i = 1, input.rows do
  362. for j = 1, input.length do
  363. -- Determine if there is a crop below the bot.
  364. if turtle.detectDown() then
  365. local success, data = turtle.inspectDown()
  366. if success then
  367. -- Bot AI: Determine if the crop is known, or if its even a crop.
  368. local isKnown = false
  369. if data.name ~= "minecraft:cobblestone" or data.name ~= "minecraft:water" or data.name ~= "minecraft:cobblestone_slab" then
  370. for k,v in pairs(botdata.crops) do
  371. if data.name == v.name then
  372. isKnown = true
  373. if isGrown(i,j,data.metadata,v.mature) then
  374. -- The crop is fully matured. Need to break crop and replace with seed.
  375. turtle.digDown()
  376. turtle.suckDown()
  377. local curpos = turtle.getSelectedSlot();
  378. if hasSeeds(v.id) then
  379. turtle.placeDown()
  380. end
  381. -- Legend: "Reset the positioning of the selected slot so bot can stack crops properly."
  382. turtle.select(curpos)
  383. end
  384. end
  385. end
  386. -- If the crop is unknown, have the bot attempt to learn the crop.
  387. if isKnown == false then
  388. learnCrop(data)
  389. end
  390. end
  391. end
  392. else
  393. -- The block below does not have a crop. Attempt to remedy this.
  394. fixBlock()
  395. end
  396.  
  397. -- Go forward one to continue.
  398. if j < input.length then
  399. turtle.forward()
  400. end
  401. end
  402.  
  403. -- Done reviewing the row. Now move to new row.
  404. local isEven = i % 2 == 0
  405. if isEven == false then
  406. turtle.turnLeft()
  407. turtle.forward()
  408. turtle.turnLeft()
  409. else
  410. turtle.turnRight()
  411. turtle.forward()
  412. turtle.turnRight()
  413. end
  414. end
  415.  
  416. -- Goal: Attempt to go back to start.
  417.  
  418. -- Logic: If the number of rows to the left are even, then the bot will end up on a different side.
  419. if input.rows % 2 == 1 then
  420. for k = 1, input.length do
  421. turtle.forward()
  422. end
  423. else
  424. turtle.turnLeft()
  425. turtle.turnLeft()
  426. turtle.forward()
  427. end
  428. turtle.turnLeft()
  429. for l = 1, input.rows do
  430. turtle.forward()
  431. end
  432. turtle.turnLeft()
  433.  
  434. -- Drop items in hopper below.
  435. turtle.down()
  436.  
  437. -- Attempt to refuel if refueling is setup.
  438. os.sleep(2)
  439. refuel()
  440. -- Drop all items in the inventory into chest below.
  441. dropItems()
  442. -- Wait for crops to grow a bit.
  443. os.sleep(300)
  444.  
  445. -- 3.0.0: Grab the latest crop list.
  446. getLatestCropList()
  447.  
  448. -- Reset bot position for next harvest.
  449. turtle.up()
  450. turtle.forward()
  451. end
  452. --[[ END FARMING TASK ]]--
  453. end
  454.  
  455. function handleCommands()
  456.  
  457. while true do
  458. local senderId, response, protocol = rednet.receive("fbtpa")
  459.  
  460. response = textutils.unserialize(response)
  461.  
  462. -- Check if any pending commands.
  463. if getSize(response.cmds) > 0 then
  464. -- Run the command.
  465. for i=1,getSize(response.cmds) do
  466. shell.run(response.cmds[i])
  467. end
  468. end
  469. end
  470.  
  471. end
  472.  
  473. handleFarming()
Add Comment
Please, Sign In to add comment