Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- -- pastebin get Fue55B2k TreeFarmer
- local numberTrees = ...
- if numberTrees then
- numberTrees = tonumber(numberTrees)
- else
- numberTrees = 1
- end
- local turtlePos, direction
- local startPos, startDir
- local Settings = {
- horDiff = 5,
- vertDiff = 7, -- 9 for Spruce (8 + 1)
- vertDiffToCollector = 4
- }
- local function getGPSPosition()
- local x, y, z = gps.locate()
- if not x then print("Error: GPS not available") return nil end
- return {x = math.floor(x), y = math.floor(y), z = math.floor(z)}
- end
- local function negative(vec)
- return {x = -vec.x, y = -vec.y, z = -vec.z}
- end
- local function add(vec1, vec2)
- return {x = vec1.x + vec2.x, y = vec1.y + vec2.y, z = vec1.z + vec2.z}
- end
- local function sub(vec1, vec2)
- return add(vec1, negative(vec2))
- end
- local function multiply(s, vec)
- return {x = s * vec.x, y = s * vec.y, z = s * vec.z}
- end
- local function getSign(number)
- return number / math.abs(number)
- end
- local function isEqual(vec1, vec2)
- return vec1.x == vec2.x and vec1.y == vec2.y and vec1.z == vec2.z
- end
- -- === Basic Movement ===
- local function moveForward()
- if turtle.forward() then
- turtlePos = add(turtlePos, direction)
- return true
- end
- return false
- end
- local function moveUp()
- if turtle.up() then
- turtlePos.y = turtlePos.y + 1
- return true
- end
- return false
- end
- local function moveDown()
- if turtle.down() then
- turtlePos.y = turtlePos.y - 1
- return true
- end
- return false
- end
- local function forceMoveForward()
- while not moveForward() do turtle.dig() end
- end
- local function forceMoveUp()
- while not moveUp() do turtle.digUp() end
- end
- local function forceMoveDown()
- while not moveDown() do turtle.digDown() end
- end
- -- === Basic Turning ===
- local function turnInDirection(dir)
- if not direction then return end
- if dir == "left" then
- turtle.turnLeft()
- direction = {x = direction.z, y = 0, z = -direction.x}
- elseif dir == "right" then
- turtle.turnRight()
- direction = {x = -direction.z, y = 0, z = direction.x}
- elseif dir == "around" then
- turtle.turnLeft()
- turtle.turnLeft()
- direction = {x = -direction.x, y = 0, z = -direction.z}
- end
- end
- local function getTurnDirection(from, to)
- local function vectorsEqual(a, b)
- return a.x == b.x and a.z == b.z
- end
- if vectorsEqual(from, to) then return nil end
- local left = {x = from.z, y = 0, z = -from.x}
- local right = {x = -from.z, y = 0, z = from.x}
- local back = {x = -from.x, y = 0, z = -from.z}
- if vectorsEqual(to, left) then
- return "left"
- elseif vectorsEqual(to, right) then
- return "right"
- elseif vectorsEqual(to, back) then
- return "around"
- else
- error("Invalid target direction")
- end
- end
- local function getDirection()
- local pos1 = getGPSPosition()
- if not pos1 then error("GPS failure, cannot get direction") end
- for i = 1, 4 do
- if turtle.forward() then
- local pos2 = getGPSPosition()
- if not pos2 then error("GPS failure after move") end
- -- turtlePos = pos2
- -- Richtung berechnen
- direction = sub(pos2, pos1)
- -- zurück zur ursprünglichen Position
- turnInDirection("around")
- forceMoveForward()
- -- Sicherheitsprüfung
- local posBack = getGPSPosition()
- if not isEqual(pos1, posBack) then
- error("Warnung: Position hat sich beim Rückweg verschoben!")
- turtlePos = posBack -- explizit wieder auf GPS setzen
- else
- turtlePos = pos1
- end
- turnInDirection("around")
- return
- else
- turtle.turnLeft()
- end
- end
- error("Unable to move forward in any direction for direction detection")
- end
- -- === Positioning ===
- local function goToLift()
- local coord = add(startPos, startDir)
- local deltaX = coord.x - turtlePos.x
- local deltaZ = coord.z - turtlePos.z
- local dirX = startDir.x
- local dirZ = startDir.z
- local function moveToEqualX()
- while not (deltaX == 0) do
- turnInDirection(getTurnDirection(direction, {x = getSign(deltaX), y = 0, z = 0}))
- forceMoveForward()
- deltaX = coord.x - turtlePos.x
- end
- end
- local function moveToEqualZ()
- while not (deltaZ == 0) do
- turnInDirection(getTurnDirection(direction, {x = 0, y = 0, z = getSign(deltaZ)}))
- forceMoveForward()
- deltaZ = coord.z - turtlePos.z
- end
- end
- if dirX == 0 then
- moveToEqualX()
- moveToEqualZ()
- elseif dirZ == 0 then
- moveToEqualZ()
- moveToEqualX()
- end
- end
- local function goToPos(coord)
- local deltaX = coord.x - turtlePos.x
- local deltaY = coord.y - turtlePos.y
- local deltaZ = coord.z - turtlePos.z
- local dirX = startDir.x
- local dirZ = startDir.z
- local function moveToEqualX()
- while not (deltaX == 0) do
- turnInDirection(getTurnDirection(direction, {x = getSign(deltaX), y = 0, z = 0}))
- forceMoveForward()
- deltaX = coord.x - turtlePos.x
- end
- end
- local function moveToEqualZ()
- while not (deltaZ == 0) do
- turnInDirection(getTurnDirection(direction, {x = 0, y = 0, z = getSign(deltaZ)}))
- forceMoveForward()
- deltaZ = coord.z - turtlePos.z
- end
- end
- local function moveToEqualY()
- while not (deltaY == 0) do
- if deltaY > 0 then
- forceMoveUp()
- elseif deltaY < 0 then
- forceMoveDown()
- end
- deltaY = coord.y - turtlePos.y
- end
- end
- if not (deltaY == 0) then
- goToLift()
- moveToEqualY()
- deltaX = coord.x - turtlePos.x
- deltaZ = coord.z - turtlePos.z
- end
- if dirX == 0 then
- moveToEqualZ()
- moveToEqualX()
- elseif dirZ == 0 then
- moveToEqualX()
- moveToEqualZ()
- end
- end
- -- === Tasks ===
- local function isSapling(item)
- if not item or not item.name then return false end
- local saplingSuffix = "_sapling"
- return item.name:match(":.*" .. saplingSuffix .. "$") ~= nil
- end
- local function isBoneMeal(item)
- if not item or not item.name then return false end
- return item.name == "minecraft:bone_meal"
- end
- local function getSaplingsCount()
- local numSaplings = 0
- for i = 1, 16 do
- local item = turtle.getItemDetail(i)
- if isSapling(item) then
- numSaplings = numSaplings + turtle.getItemCount(i)
- end
- end
- return numSaplings
- end
- local function getBoneMealCount()
- local num = 0
- for i = 1, 16 do
- local item = turtle.getItemDetail(i)
- if isBoneMeal(item) then
- num = num + turtle.getItemCount(i)
- end
- end
- return num
- end
- local function selectSaplingSlot()
- for i = 1, 16 do
- local item = turtle.getItemDetail(i)
- if isSapling(item) then
- turtle.select(i)
- return true
- end
- end
- return false
- end
- local function selectBoneMealSlot()
- for i = 1, 16 do
- local item = turtle.getItemDetail(i)
- if isBoneMeal(item) then
- turtle.select(i)
- return true
- end
- end
- return false
- end
- local function plantSapling()
- if not selectSaplingSlot() then return false end
- if not turtle.place() then return false end
- return true
- end
- local function isLog(item)
- if not item or not item.name then return false end
- local saplingSuffix = "_log"
- return item.name:match(":.*" .. saplingSuffix .. "$") ~= nil
- end
- local function fellTree()
- local success, item = turtle.inspect()
- if success and isLog(item) then
- forceMoveForward()
- local cnt = 0
- while true do
- local suc, itemUp = turtle.inspectUp()
- if not isLog(itemUp) then
- break
- end
- forceMoveUp()
- cnt = cnt + 1
- end
- while cnt > 0 do
- forceMoveDown()
- cnt = cnt - 1
- end
- if not fellTree() then
- turnInDirection("right")
- fellTree()
- end
- return true
- end
- return false
- end
- local function fellAndPlantTree()
- local bNeedBoneMeal = true
- local prevPos = turtlePos
- local prevDirection = direction
- local bFelledOrPlanted = false
- if fellTree() then
- goToPos(prevPos)
- turnInDirection(getTurnDirection(direction, prevDirection))
- moveForward()
- if getSaplingsCount() >= 4 and plantSapling() then -- plant (1, 1)
- turnInDirection("right")
- moveForward()
- turnInDirection("left")
- plantSapling() -- plant (1, 2)
- turnInDirection("left")
- moveForward()
- turnInDirection("around")
- plantSapling() -- plant (2, 2)
- end
- turnInDirection(getTurnDirection(direction, negative(prevDirection)))
- moveForward()
- turnInDirection("around")
- bNeedBoneMeal = not plantSapling() -- plant (2, 1)
- bFelledOrPlanted = true
- elseif moveForward() then
- if getSaplingsCount() >= 4 and plantSapling() then -- plant (1, 1)
- turnInDirection("right")
- moveForward()
- turnInDirection("left")
- plantSapling() -- plant (1, 2)
- turnInDirection("left")
- moveForward()
- turnInDirection("around")
- plantSapling() -- plant (2, 2)
- end
- turnInDirection(getTurnDirection(direction, negative(prevDirection)))
- moveForward()
- turnInDirection("around")
- bNeedBoneMeal = not plantSapling() -- plant (2, 1)
- bFelledOrPlanted = true
- end
- local cnt1 = 0
- while selectBoneMealSlot() and bNeedBoneMeal and cnt1 < 5 do
- if not turtle.place() then
- if fellTree() then
- goToPos(prevPos)
- turnInDirection(getTurnDirection(direction, prevDirection))
- moveForward()
- if getSaplingsCount() >= 4 and plantSapling() then -- plant (1, 1)
- turnInDirection("right")
- moveForward()
- turnInDirection("left")
- plantSapling() -- plant (1, 2)
- turnInDirection("left")
- moveForward()
- turnInDirection("around")
- plantSapling() -- plant (2, 2)
- end
- turnInDirection(getTurnDirection(direction, negative(prevDirection)))
- moveForward()
- turnInDirection("around")
- plantSapling() -- plant (2, 1)
- bFelledOrPlanted = true
- end
- break
- end
- cnt1 = cnt1 + 1
- end
- return bFelledOrPlanted
- end
- -- === Inventory Management ===
- local function compactInventory()
- for i = 1, 16 do
- local itemI = turtle.getItemDetail(i)
- if itemI and itemI.count < 64 then
- for j = i + 1, 16 do
- local itemJ = turtle.getItemDetail(j)
- if itemJ and itemJ.name == itemI.name then
- turtle.select(j)
- turtle.transferTo(i)
- -- Aktuellen Slot updaten
- itemI = turtle.getItemDetail(i)
- if not itemI or itemI.count == 64 then
- break
- end
- end
- end
- end
- end
- turtle.select(1) -- zum Standard zurückkehren
- end
- local function pullAllFromChest()
- local success, chest = pcall(peripheral.call, "front", "list")
- if not success or not chest then
- print("No chest found or cannot read from chest.")
- return true -- Treat as successful (no reason to return)
- end
- -- Step 1: Count item stacks BEFORE pulling
- local chestStacksBefore = 0
- for _, stack in pairs(chest) do
- if stack and stack.count > 0 then
- chestStacksBefore = chestStacksBefore + 1
- end
- end
- -- Step 2: Count free slots BEFORE pulling
- local freeSlotsBefore = 0
- for i = 1, 16 do
- if turtle.getItemDetail(i) == nil then
- freeSlotsBefore = freeSlotsBefore + 1
- end
- end
- -- Step 3: Pull items (use all empty slots)
- for i = 1, 16 do
- if turtle.getItemDetail(i) == nil then
- turtle.select(i)
- turtle.suck()
- end
- end
- turtle.select(1)
- -- Step 4: Final decision
- if chestStacksBefore > freeSlotsBefore then
- return false -- Couldn’t fit everything
- else
- return true -- Everything fit
- end
- end
- -- Keep saplings
- local function dumpInventoryKeepSaplings(n)
- local success, chest = turtle.inspect()
- while not (success and chest.name == "minecraft:chest") do
- print("No chest found. Pls place one in front.")
- print("Press enter to continue.")
- read()
- success, chest = turtle.inspect()
- end
- local saplingsKept = 0
- for slot = 1, 16 do
- local item = turtle.getItemDetail(slot)
- if item then
- turtle.select(slot)
- if isSapling(item) and saplingsKept < n then
- local keep = math.min(item.count, n - saplingsKept)
- local drop = item.count - keep
- if drop > 0 then
- turtle.drop(drop)
- end
- saplingsKept = saplingsKept + keep
- elseif not isBoneMeal(item) then
- turtle.drop()
- end
- end
- end
- turtle.select(1)
- end
- local function emptyCollectorChest(posCollector)
- goToPos(posCollector)
- while not pullAllFromChest() do
- goToPos(startPos)
- turnInDirection(getTurnDirection(direction, negative(startDir)))
- dumpInventoryKeepSaplings(2 * numberTrees)
- turnInDirection(getTurnDirection(direction, startDir))
- goToPos(posCollector)
- end
- -- collects BoneMeal
- compactInventory()
- local success, chest = turtle.inspectDown()
- if success and chest.name == "minecraft:chest" and getBoneMealCount() == 0 then
- turtle.suckDown()
- end
- goToPos(startPos)
- turnInDirection(getTurnDirection(direction, negative(startDir)))
- dumpInventoryKeepSaplings(math.max(2 * numberTrees, 4))
- turnInDirection(getTurnDirection(direction, startDir))
- end
- local function turtleNeedsFuel()
- local fuelLevel = turtle.getFuelLevel()
- if fuelLevel < 1000 then
- if not isEqual(startPos, turtlePos) then
- goToPos(startPos)
- end
- print("Turtle needs more fuel")
- return true
- end
- return false
- end
- -- === Initialization ===
- local function saveStartingParameters()
- local parameterList = {pos = turtlePos, dir = direction, numTrees = numberTrees}
- local file = fs.open("startingParameters.txt", "w")
- file.write(textutils.serialize(parameterList))
- file.close()
- end
- local function loadStartingParameters()
- if not fs.exists("startingParameters.txt") then return false end
- local file = fs.open("startingParameters.txt", "r")
- local data = textutils.unserialize(file.readAll())
- file.close()
- startPos = data.pos
- startDir = data.dir
- numberTrees = data.numTrees
- return true
- end
- local function initProgram()
- turtlePos = getGPSPosition()
- if not turtlePos then error("GPS failure, cannot run the program") end
- getDirection()
- if not loadStartingParameters() then
- startPos = turtlePos
- startDir = direction
- saveStartingParameters()
- end
- end
- local function main()
- if turtleNeedsFuel() then
- return
- end
- local dirUp = {x = 0, y = 1, z = 0}
- local posTree_XZ = add(startPos, multiply(Settings.horDiff, startDir))
- local posCollector = sub(posTree_XZ, multiply(Settings.vertDiffToCollector, dirUp))
- local numSaplings = getSaplingsCount()
- if numSaplings < math.max(numberTrees, 4) then
- emptyCollectorChest(posCollector)
- numSaplings = getSaplingsCount()
- while numSaplings < numberTrees and numSaplings < 4 do
- print("Not enough saplings. Please put at least " .. tostring(math.max(numberTrees, 4)) .. " in the inventory.")
- read()
- numSaplings = getSaplingsCount()
- end
- end
- while true do
- local bCollect = false
- if turtleNeedsFuel() then
- return
- end
- numSaplings = getSaplingsCount()
- local bFirstLoop = true
- while numSaplings < numberTrees and numSaplings < 4 do
- emptyCollectorChest(posCollector)
- numSaplings = getSaplingsCount()
- if numSaplings < numberTrees and numSaplings < 4 then
- if bFirstLoop then
- bFirstLoop = false
- print("Not enough Saplings. Waiting for more.")
- end
- sleep(30)
- elseif not bFirstLoop then
- print("Found enough Saplings, continuing work.\n")
- end
- end
- for cnt = 0, numberTrees - 1 do
- local posNextTree = add(posTree_XZ, multiply(cnt * Settings.vertDiff, dirUp))
- goToPos(posNextTree)
- turnInDirection(getTurnDirection(direction, startDir))
- if fellAndPlantTree() then
- bCollect = true
- end
- end
- if bCollect then
- emptyCollectorChest(posCollector)
- else
- goToPos(startPos)
- turnInDirection(getTurnDirection(direction, startDir))
- end
- if not (getBoneMealCount() > 0) then
- sleep(60)
- else
- sleep(30)
- end
- end
- end
- initProgram()
- main()
Add Comment
Please, Sign In to add comment