Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- local version = 20240209.0730
- --[[
- https://pastebin.com/8F5LrfZi
- installation:
- pastebin get 8F5LrfZi startup.lua
- This version harvests a rectangular dirt field covered in bamboo
- The turtle travels across the feild cutting bamboo leaving 1 block below
- It then travels to the side wall and finds the double chest
- It sits on the double chest facing the field
- bamboo is crafted to planks and placed in the double chest
- Turtle then observes the space in front waiting for a buried piston to push dirt up or modem to receive message "complete"
- The farming process starts, with constant checks on bamboo quantity, which is crafted to blocks
- ]]
- local config = nil
- local sourceSlots = {4,8,12,13,14,15,16}
- local craftSlots = {1,2,3,5,6,7,9,10,11}
- local storage = ""
- local border = ""
- local function clear()
- term.clear() -- clear display
- term.setCursorPos(1,1) -- reset cursor
- end
- local function getBlockType(direction)
- --[[ turtle.inspect() returns two values
- 1) boolean (true/false) success
- 2) table with two or more values:
- .name
- .state {axis = "y"}
- .tags (["minecraft:logs"] = true, ["minecraft:logs_that_burn"] = true, ["minecraft:oak_logs"] = true}
- ]]
- local blockType = "" -- initialise blockType
- local success = false
- local data = nil -- initialise empty table variable
- local inspect = turtle.inspect -- assign inspect() function to a variable
- if direction == "up" then
- inspect = turtle.inspectUp -- inspect re-assigned to inspectUp
- elseif direction == "down" then
- inspect = turtle.inspectDown -- inspect re-assigned to inspectDown
- end
- success, data = inspect() -- store information about the block below in a table
- if success then -- block found
- blockType = data.name -- eg "minecraft:log"
- end
- return blockType, data -- eg "minecraft:oak_log" , data table OR "", nil if empty
- end
- local function values(t) -- general diy iterator
- local i = 0
- return function()
- i = i + 1
- return t[i]
- end
- end
- local function move(direction, steps, cut)
- local move = turtle.forward
- local dig = turtle.dig
- if direction == "up" then
- move = turtle.up
- dig = turtle.digUp
- elseif direction == "down" then
- move = turtle.down
- dig = turtle.digDown
- elseif direction == "back" then
- move = turtle.back
- end
- local moves = 0
- for i = 1, steps do
- if cut then -- cut = true so dig
- dig()
- end
- if move() then -- if move successful
- moves = moves + 1
- else
- return false, moves -- unable to move further
- end
- end
- return true, moves
- end
- local function down(steps, cut)
- steps = steps or 1 -- if called without parameters, set default 1
- cut = cut or false -- if called without parameters, set default false
- return move("down", steps, cut)
- end
- local function up(steps, cut)
- steps = steps or 1
- cut = cut or false
- return move("up", steps, cut)
- end
- local function forward(steps, cut)
- steps = steps or 1
- cut = cut or false
- return move("forward", steps, cut)
- end
- local function back(steps)
- steps = steps or 1
- cut = cut or false -- if called without parameters, set default false
- return move("back", steps, cut)
- end
- local function turnLeft(steps)
- steps = steps or 1
- for i = 1, steps do
- turtle.turnLeft()
- end
- return true
- end
- local function turnRight(steps)
- steps = steps or 1
- for i = 1, steps do
- turtle.turnRight()
- end
- return true
- end
- local function getItemSlot(item)
- for i = 1, 16 do
- local data = turtle.getItemDetail(i)
- if data ~= nil then
- if item:find(":") == nil then -- find partial match
- if data.name:find(item) ~= nil then
- return i
- end
- else
- if data.name == item then -- find exact match
- return i
- end
- end
- end
- end
- return 0
- end
- local function getBambooCount(blockType)
- -- count bamboo, bamboo blocks or bamboo planks
- -- parameters are "", _block, _planks
- blockType = blockType or ""
- local count = 0
- for i = 1, 16 do
- data = turtle.getItemDetail(i)
- if data ~= nil then
- if data.name == "minecraft:bamboo".. blockType then
- count = count + data.count
- end
- end
- end
- return count
- end
- local function go(path)
- local commandList = {}
- local command = ""
- local direction = {"up", "forward", "down"}
- path = path:gsub(" ", "") -- remove spaces from path
- -- make a list of commands from path string eg "x0F12U1" = x0, F12, U1
- for i = 1, #path do
- local character = path:sub(i, i) -- examine each character in the string
- if tonumber(character) == nil then -- char is NOT a number
- if command ~= "" then -- command is NOT empty eg "x0"
- table.insert(commandList, command) -- add to table eg "x0"
- end
- command = character:upper() -- replace command with new character eg "F"
- else -- char IS a number
- command = command..character:upper() -- add eg 1 to F = F1, 2 to F1 = F12
- if i == #path then -- last character in the string
- table.insert(commandList, command)
- end
- end
- end
- -- R# L# F# B# U# D# = Right, Left, Forward, Back, Up, Down
- -- dig: X0,X1,X2 (up/fwd/down)
- for cmd in values(commandList) do -- eg F12 or x1
- local move = (cmd:sub(1, 1)):upper()
- local modifier = tonumber(cmd:sub(2))
- if move == "B" then
- back(modifier)
- elseif move == "D" then
- down(modifier)
- elseif move == "F" then
- forward(modifier)
- elseif move == "U" then
- up(modifier)
- elseif move == "R" then
- turnRight(modifier)
- elseif move == "L" then
- turnLeft(modifier)
- elseif move == "X" then
- if modifier == 0 then
- turtle.digUp()
- elseif modifier == 1 then
- turtle.dig()
- elseif modifier == 2 then
- turtle.digDown()
- end
- end
- end
- end
- local function place(blockType, direction)
- direction = direction or "forward"
- local success = false
- -- assign place methods according to direction
- local Place = turtle.place
- if direction == "up" then
- Place = turtle.placeUp
- elseif direction == "down" then
- Place = turtle.placeDown
- end
- local slot = getItemSlot(blockType)
- if slot > 0 then -- item to place found
- turtle.select(slot)
- if Place() then
- success = true
- end
- end
- turtle.select(1) -- restore selected to 1
- return success, slot
- end
- local function isItemOfType(direction, itemTable)
- -- check if item next to turtle is a specific type
- local success, data = false, nil
- if direction == "up" then
- success, data = turtle.inspectUp() -- check block above
- elseif direction == "down" then
- success, data = turtle.inspectDown() -- check block below
- else
- success, data = turtle.inspect() -- check if anything in front
- end
- if success then -- a block is in front
- if type(itemTable) == "table" then -- Are we checking for multiple items eg {"chest", "barrel"} ?
- for _, item in ipairs(itemTable) do -- iterate items
- if data.name:find(item) ~= nil then -- match found
- return true, item
- end
- end
- elseif type(itemTable) == "string" then -- checking for single item eg "dirt"
- if data.name:find(itemTable) ~= nil then -- match found
- return true, item
- end
- end
- end
- return false, "" -- no match
- end
- local function placeStorage()
- -- used before crafting to place onboard chest/barrel
- local lib = {}
- function lib.turn()
- local turns = 0
- while turtle.detect() do
- turnRight(1)
- turns = turns + 1
- if turns == 4 then
- turns = 0
- break
- end
- end
- turtle.dig()
- place(storage, "forward")
- return turns
- end
- local dig = turtle.dig
- local drop = turtle.drop
- local suck = turtle.suck
- local turns = 0
- if isItemOfType("down", "chest") then
- turns = lib.turn()
- else
- if not turtle.detectUp() then
- dig = turtle.digUp
- drop = turtle.dropUp
- suck = turtle.suckUp
- place(storage, "up")
- elseif not turtle.detectDown() then
- dig = turtle.digDown
- drop = turtle.dropDown
- suck = turtle.suckDown
- place(storage, "down")
- else
- turns = lib.turn()
- end
- end
- return dig, drop, suck, turns -- return turtle methods appropriate to direction + no of turns
- end
- local function craftPlanks()
- -- only called when above main storage chest
- local count = getBambooCount("_block") -- how many bamboo blocks
- if count > 0 then
- local dig, drop, suck, turns = placeStorage() -- place onboard chest/barrel
- repeat
- for i = 1, 16 do -- drop all bamboo planks into main storage, blocks into temp first
- local data = turtle.getItemDetail(i)
- if data ~= nil then
- if data.name == "minecraft:bamboo_block" then
- turtle.select(i)
- drop() -- put blocks into craft storage
- elseif data.name == "minecraft:bamboo_planks" then
- turtle.select(i)
- turtle.dropDown() -- put planks into main storage
- end
- end
- end
- for i = 1, 16 do -- drop any remaining bamboo last
- turtle.select(i) -- makes sure blocks will be removed first
- drop()
- end
- turtle.select(1) -- select slot 1
- suck(32) -- attempt so retrieve 32 blocks
- local data = turtle.getItemDetail(1) -- get detail of current slot 1 contents
- local nomore = false -- initialise flag
- if data ~= nil then -- nil result used as loop terminator
- if data.name == "minecraft:bamboo_block" then
- if data.count > 32 then -- if count > 32
- drop(data.count - 32) -- return excess back to craft storage
- end -- saves having to drop crafted planks from multiple locations
- if turtle.craft() then -- attempt to craft 64 planks
- turtle.select(1) -- success
- turtle.dropDown() -- drop into main storage
- end
- else -- did not get blocks, so assume there are no more
- nomore = true
- end
- end
- until data == nil or nomore -- loop exit if bamboo block NOT found or chest is empty
- while suck() do end -- empty craft storage
- dig() -- collect craft storage
- if turns > 0 then -- return to starting position
- turnLeft(turns)
- end
- end
- end
- local function craftBamboo(threshold)
- -- large amounts of bamboo collected while harvesting. convert to blocks to reduce volume by factor of 9
- if threshold == nil then -- no threshold supplied
- threshold = 256 -- craft if > 256 bamboo
- end
- local count = getBambooCount() -- how much bamboo onboard?
- if count >= threshold then -- crafting required
- local dig, drop, suck, turns = placeStorage() -- place onboard chest/barrel
- repeat
- for i = 1, 16 do -- drop all bamboo into storage first
- local data = turtle.getItemDetail(i)
- if data ~= nil then
- if data.name == "minecraft:bamboo" then
- turtle.select(i)
- drop()
- end
- end
- end
- local perSlot = math.floor(count / 9) -- calculate crafting ratio (9 bamboo = 1 block)
- if perSlot > 32 then -- ensure max of 32 blocks crafted at once
- perSlot = 32
- end
- for i = 1, 16 do -- drop all other items back into storage
- turtle.select(i)
- drop()
- end
- for _, slot in ipairs(craftSlots) do -- load all 9 crafting slots
- turtle.select(slot)
- suck(perSlot)
- local received = turtle.getItemCount(slot) -- suck() currently broken, does not always work correctly
- if received > perSlot then -- got more thean required
- drop(received - perSlot) -- return excess
- elseif received < perSlot then -- got less then required
- suck(perSlot - received) -- try again
- end
- end
- turtle.select(1) -- craft 32 planks into slot 1
- turtle.craft()
- turtle.select(1)
- local fuel = turtle.getFuelLevel() -- check if refuel needed
- if fuel < 400 then
- turtle.craft() -- craft all 32 blocks into 64 planks
- turtle.select(1)
- turtle.refuel() -- refuel with 64 planks (64 * 15 = 960)
- end
- while suck() do end -- empty crafting chest
- count = getBambooCount() -- re-calculate bamboo remaining
- until count < 9 -- exit loop if < 9 bamboo
- dig() -- recover storage
- if turns > 0 then -- return to original position
- turnLeft(turns)
- end
- end
- end
- local function wait()
- -- wait for bamboo to grow approx 10 - 15 mins for full growth to level 10
- -- wall / piston mechanism pushes dirt block upwards OR turtle/modem
- local time = 0
- local waitTime = 5
- if config.detector == "N" then
- rednet.open("back")
- end
- while true do
- clear()
- -- following code for display purposes only so min/mins and sec/secs is correct
- local mins = math.floor(time / 60)
- local secs = time % 60
- local output = "Waiting for bamboo growth:\n"..time.." seconds ("..mins.." minute"
- if mins ~= 1 then output = output.."s" end
- output = output..", "..secs.." second"
- if secs ~= 1 then output = output.."s" end
- output = output..")"
- print(output)
- sleep(waitTime) -- sleep for 5 secs
- if config.detector == "P" then
- if turtle.detect() then -- dirt block has appeared, pushed up by piston below the field
- clear()
- return -- waiting finished
- end
- elseif config.detector == "N" then
- local id, message = rednet.receive()
- if message == "complete" then
- clear()
- return -- waiting finished
- end
- end
- time = time + waitTime
- end
- end
- local function findBorder(direction)
- -- used if auto-starting in unknown position
- direction = direction or config.layout
- while turtle.down() do end -- over border or non-planted field
- local blockType = getBlockType("down")
- if blockType:find("bamboo") ~= nil then -- still over planted area
- repeat -- dig until reach non-planted area
- turtle.dig()
- turtle.suck()
- turtle.forward()
- turtle.suckDown()
- until not isItemOfType("down", {"bamboo"})
- while turtle.down() do end -- go down to field
- while isItemOfType("down", {"dirt", "grass"}) do -- while on dirt or grass move forward
- turtle.forward()
- end -- will now be over border wall
- else -- over air / dirt / grass / border
- if blockType == "" then -- over air
- turtle.back() -- move back onto border
- elseif isItemOfType("down", {"dirt", "grass"}) then -- over dirt/grass
- while isItemOfType("down", {"dirt", "grass"}) do-- go forward while dirt below
- turtle.forward()
- end
- end
- end
- blockType = getBlockType("down") -- check below
- if blockType == "" then -- on air so go back
- turtle.back()
- else
- border = blockType -- on border
- end
- go(direction.."1") -- turn to continue along border
- end
- local function followBorder()
- local lib = {}
- function lib.follow()
- -- travel along border blocks until either hit outer wall/block or no longer on border
- while isItemOfType("down", {border}) do
- if not turtle.forward() then
- break
- end
- end
- end
- function lib.corner()
- go("B1L1F1") -- try left turn first
- blockType = getBlockType("down") -- is block below?
- if blockType == "" then -- air below: wrong direction
- go("B2R2") -- go other direction
- end
- return getBlockType("down") -- return block below name
- end
- local inPosition = false
- repeat
- lib.follow()
- blockType = getBlockType("down")
- if turtle.detect() then -- corner blocks or outer wall present
- --turnLeft(1)
- go(config.turn.."1")
- else
- -- now over chest / or air. Over chest dirt is to the left
- if blockType == "" then
- if lib.corner() == "minecraft:chest" then
- go("F1"..config.layout.."1") -- turn corner in calculated direction
- inPosition = true
- break
- end
- end
- end
- until blockType == "minecraft:chest"
- if not inPosition then
- --turnLeft(1)
- go(config.turn.."1")
- end
- end
- local function checkStorageLevel()
- -- use peripheral and inventory apis to detemine storage contents
- local chest = peripheral.wrap("bottom")
- local count = 0
- for slot, item in pairs(chest.list()) do
- count = count + item.count
- end
- return count, chest.size()
- end
- local function farm()
- --traverse field in circular motion, digging bamboo in front
- local lib = {}
- function lib.suck()
- turtle.select(1)
- turtle.suckUp()
- turtle.suckDown()
- turtle.suck()
- end
- function lib.clear(size)
- for i = 1, size do
- lib.suck()
- if turtle.dig() then
- lib.suck()
- end
- while not turtle.forward() do
- turtle.dig()
- end
- end
- end
- function lib.reposition(moves)
- -- turn left and move forward moves x
- -- turn left again
- go(config.turn.."1")
- for move = 1, moves do
- while not turtle.forward() do
- turtle.dig()
- end
- lib.suck()
- end
- go(config.turn.."1")
- end
- local outward = true -- set direction flag
- local steps = ((config.width + config.border) * 2) - 1
- for col = 1, steps do
- lib.clear(config.length + (config.border * 2) - 1)
- craftBamboo()
- if col < steps then
- if outward then
- lib.reposition(2) -- go over recently harvested row to collect fallen bamboo
- else
- lib.reposition(3) -- start new column
- end
- outward = not outward -- flip flag status
- end
- end
- if outward then
- findBorder(config.turn)
- else
- findBorder(config.layout)
- end
- followBorder()
- end
- local function gotoFarm()
- -- assume currently on main storage chest, facing farm
- turtle.dig() -- if using network detection no effect
- turtle.forward()
- place("minecraft:dirt", "down")
- -- move to edge of the field, facing bamboo eg "U1F2 L1B1"
- go("U1F"..tostring(config.border)..config.turn.."1B"..(config.border - 1))
- end
- local function orientate()
- -- turn until facing field with chest below, wall or modem behind
- if isItemOfType("forward", {"dirt", "grass"}) then
- return
- end
- local turns = 0
- for i = 1, 4 do
- if isItemOfType("forward", {"wall", "modem"}) then
- break
- end
- turnRight(1)
- turns = turns + 1
- end
- if turns > 0 then
- turnLeft(turns)
- end
- end
- local function goHome(startOn)
- -- a, b, f (air, bamboo, field)
- findBorder(config.layout)
- followBorder()
- end
- local function isHome()
- -- home is above storage chest. If double then use one furthest from the corner
- if isItemOfType("down", {"chest", "barrel"}) then -- already on storage chest / barrel
- return "c"
- else
- local blockType = getBlockType("down")
- if blockType == "" then -- air. could be anywhere on the farm
- return "a"
- elseif isItemOfType("down", {"dirt", "grass"}) then -- on field
- return "f"
- elseif blockType:find("bamboo") ~= nil then -- at start position, waiting for bamboo
- return "b"
- else
- return ""
- end
- end
- end
- local function createConfig()
- config = {}
- local response = nil
- repeat
- clear()
- write("How wide is the growing area?\n(Count bamboo directly in front) ")
- response = tonumber(read())
- until response ~= nil
- config.width = response
- repeat
- clear()
- write("How long is the growing area?\n(Count bamboo to right or left) ")
- response = tonumber(read())
- until response ~= nil
- config.length = response
- repeat
- clear()
- write("How wide is the dirt/grass border?\n(Between bamboo and outer wall) ")
- response = tonumber(read())
- until response ~= nil
- config.border = response
- repeat
- clear()
- write("Position of storage chest (R/L)?\n(Relative to player at farm border")
- response = read()
- response = response:upper()
- until response == "R" or response == "L"
- config.layout = response
- if response == "R" then
- config.turn = "L"
- else
- config.turn = "R"
- end
- repeat
- clear()
- write("Growth detection with wall/piston or modem/network system (P / N)?")
- response = read()
- response = response:upper()
- until response == "P" or response == "N"
- config.detector = response
- end
- local function writeConfig()
- local h = fs.open("config.lua", "w")
- h.writeLine("return")
- h.writeLine(textutils.serialise(config))
- h.close()
- print("Config.lua file written")
- end
- local function checkForChest()
- -- should be a barrel or chest in inventory
- -- it may be placed externally
- local slot = getItemSlot("minecraft:chest")
- if slot == 0 then
- slot = getItemSlot("minecraft:barrel")
- if slot > 0 then
- storage = "minecraft:barrel"
- end
- else
- storage = "minecraft:chest"
- end
- if storage == "" then -- not found internally
- local success, item = isItemOfType("up", {"chest", "barrel"})
- if success then -- found above
- while turtle.suckUp() do end -- empty and retreive it
- turtle.digUp()
- storage = item
- else
- success, item = isItemOfType("forward", {"chest", "barrel"})
- if success then -- found in front
- while turtle.suck() do end
- turtle.dig()
- storage = item
- end
- end
- end
- return storage
- end
- local function main()
- clear() -- clear terminal
- --[[
- return -- config.lua
- {
- width = 13,
- length = 13,
- border = 2,
- layout = "R",
- turn = "L",
- detector = "P"
- }
- ]]
- if fs.exists("config.lua") then
- config = require("config")
- else
- createConfig()
- writeConfig()
- end
- if checkForChest() == "" then
- print("Unable to find onboard chest or barrel\nAdd to inventory and reboot")
- return
- end
- craftBamboo()
- local startOn = isHome() -- c = home, a = air, b = bamboo, f = field
- if startOn == "" then
- print("Unable to determine position\nMove to start and reboot")
- return
- elseif startOn ~= "c" then -- check if starting in correct position
- goHome(startOn) -- find starting position on barrel
- end
- orientate() -- assume on top of storage barrel. look for facing double chest
- while true do
- craftBamboo(9) -- deal with any bamboo previously harvested
- craftPlanks()
- local count, size = checkStorageLevel()
- if count / 64 > size * 0.8 then
- print("Storage at 80%. Farm disabled")
- return
- end
- wait()
- gotoFarm()
- farm()
- if turtle.detect() then
- turtle.dig()
- turtle.forward()
- place("dirt", "down")
- turtle.back()
- end
- end
- end
- main()
Add Comment
Please, Sign In to add comment