-- Lua script by nO_OnE
-- V2.1.2_2
-- This script was written to harvest a treefarm using a ComputerCraft-Miningturtle in Minecraft.
-- For more information visit: http://www.computercraft.info/forums2/index.php?/topic/6518-13-14-automatic-tree-farm-with-config/
-- DEFAULT SETTINGS SECTION
local slotAmount = 16 -- 9 for the old turtles, 16 for CC 1.4 or above
local chestOutput = true -- true if you want the turtle to put all items in a chest instead of dropping them
local saplingOffset = 2 -- 2 recommended (amount of blocks between two saplings)
local wallOffset = 2 -- 2 recommended (amount of blocks between the saplings and the wall)
local fullSaplings = false -- true: wait for 64 Saplings, false: wait for the amount the treefarm could possibly have
local throwSaplings = false -- true: throw away unnecessary saplings (only if fullSaplings = false)
local saplingMethod = "compare" -- "detect" or "compare" - compare works better but if you have 1.3 you should set it to detect to avoid bugs
local sleepTime = 0 -- set if you wish to make a break between farming runs
-- DEFAULT SETTINGS SECTION
local serverID, x, y -- leave blank! (serverID will be declared later when the first server answer comes)
function writeSettings ( ) --> write the current (default) settings in the file farmer.cfg
local file = fs.open ("farmer.cfg", "w")
file.writeLine (slotAmount)
file.writeLine (chestOutput)
file.writeLine (saplingOffset)
file.writeLine (wallOffset)
file.writeLine (fullSaplings)
file.writeLine (throwSaplings)
file.writeLine (saplingMethod)
file.writeLine (xTrees)
file.writeLine (yTrees)
file.writeLine (sleepTime)
file.close ( )
end
function readSettings ( ) --> replace the default values with the ones in the farmer.cfg
local file = fs.open ("farmer.cfg", "r")
slotAmount = tonumber (file.readLine ( ))
chestOutput = file.readLine ( ) == "true"
saplingOffset = tonumber (file.readLine ( ))
wallOffset = tonumber (file.readLine ( ))
fullSaplings = file.readLine ( ) == "true"
throwSaplings = file.readLine ( ) == "true"
saplingMethod = file.readLine ( )
xTrees = tonumber (file.readLine ( ))
yTrees = tonumber (file.readLine ( ))
sleepTime = tonumber (file.readLine ( ))
file.close ( )
end
function forward (value) --> func to move a amount of blocks forward even when a entity or block is blocking the way
for i = 1, value do
local forw = false
while not forw do
forw = turtle.forward ( )
if not forw and turtle.detect ( ) then
turtle.dig ( )
end
end
end
end
function up (value) --> func to move up (see forward)
for i = 1, value do
local upp = false
while not upp do
upp = turtle.up ( )
if not upp and turtle.detectUp ( ) then
turtle.digUp ( )
end
end
end
end
function down (value) --> func to move down (see forward)
for i = 1, value do
dow = false
while not dow do
dow = turtle.down ( )
if not dow and turtle.detectDown ( ) then
turtle.digDown ( )
end
end
end
end
function drop (value) --> func to drop evrything but slot 1 and slot 2 (value 0) or unnecessary saplings (value 1)
if (value == 1) and (turtle.getItemCount (1) - (xTrees * yTrees) > 1) then
turtle.select (1)
if chestOutput then
turn ("back")
if turtle.detect ( ) then turtle.drop (turtle.getItemCount (1) - (xTrees * yTrees) - 1) end
turn ("back")
end
turtle.drop (turtle.getItemCount (1) - (xTrees * yTrees) - 1)
else
if chestOutput then
turn ("back")
if turtle.detect ( ) then
for i = 3, slotAmount do
turtle.select (i)
if turtle.getItemCount (i) > 0 then turtle.drop ( ) end
end
end
turn ("back")
end
for i = 3, slotAmount do
turtle.select (i)
if turtle.getItemCount (i) > 0 then turtle.drop ( ) end
end
end
end
function turn (dir) --> easier turning func with a parameter or direction
if dir == "left" or dir == 0 then turtle.turnLeft() -- "left" or 0 for left
elseif dir == "right" or dir == 1 then turtle.turnRight() -- "right" or 1 for right
else turtle.turnLeft() turtle.turnLeft() end -- everything else (I am using "back") for turning around
end
function cutDown ( ) --> func to cut down a tree the turtle faces at height 2
turtle.select (3)
turtle.dig ( )
forward (1)
down (1)
turtle.select (2)
if not turtle.compareDown ( ) then
if turtle.detectDown ( ) then turtle.digDown ( ) end
turtle.placeDown ( )
end
up (1)
turtle.select (1)
turtle.placeDown ( )
turtle.select (3)
local height = 0
while turtle.compareUp ( ) do
up (1)
height = height + 1
end
down (height)
end
function tree ( ) --> return true if turtle faces a tree
if turtle.getItemCount (3) > 0 then
turtle.select (3)
local re = turtle.compare ( )
return (re)
else
return (turtle.detect ( ))
end
end
function farm ( ) --> doing a complete farming run
forward (1)
up (1)
turn ("right")
forward (wallOffset)
turn ("left")
forward (wallOffset - 1)
for j = 1, xTrees do
for i = 1, yTrees do
if i > 1 then
forward (saplingOffset)
end
if tree ( ) then
cutDown ( )
else
forward (1)
turtle.select (1)
if (not turtle.detectDown ( ) and saplingMethod == "detect") or (not turtle.compareDown ( ) and saplingMethod == "compare") then
down (1)
turtle.select (2)
if not turtle.compareDown ( ) then
if turtle.detectDown ( ) then turtle.digDown ( ) end
turtle.placeDown ( )
end
up (1)
turtle.select (1)
turtle.placeDown ( )
end
end
end
if j < xTrees then
forward (1)
turn (j % 2)
forward (saplingOffset + 1)
turn (j % 2)
end
end
if xTrees % 2 == 1 then
turn ("right")
forward (1)
turn ("right")
forward ((yTrees - 1) * (saplingOffset + 1) + wallOffset)
turn ("right")
forward (1)
else
forward (wallOffset)
turn ("right")
end
forward (((xTrees - 1) * (saplingOffset + 1)) + wallOffset)
down (1)
turn ("left")
forward (1)
turn ("back")
end
function waitForSaplings ( ) --> returning the amount of saplings that are needed to start farming
if not fullSaplings then return (xTrees * yTrees - turtle.getItemCount (1) + 1)
else return (64 - turtle.getItemCount (1)) end
sleep (1)
end
function handleRednet (message) --> processing a command received from rednet
local nBegin, nBeginn, nEnd, nEndd, command, attrib, n
nBegin, nEnd = string.find (message, " ")
command = message
attrib = { }
n = 0
if nBegin ~= nil then
command = string.sub (message, 1, nBegin - 1)
repeat
if n ~= 0 then nBegin, nEnd = string.find (message, " ", nBegin + 1) end
nBeginn, nEndd = string.find (message, " ", nBegin + 1)
n = n + 1
if nBeginn == nil then attrib[n] = string.sub (message, nBegin + 1)
else attrib[n] = string.sub (message, nBegin + 1, nBeginn - 1) end
until nBeginn == nil
end
if command == "stop" then
print ("\n")
error ("got stop command")
elseif command == "shutdown" then
print ("\n\nshutting down due to 'shutdown' command...")
sleep (1)
os.shutdown ( )
elseif command == "reboot" then
print ("\n\nrebooting due to 'reboot' command...")
sleep (1)
os.reboot ( )
elseif command == "change" then
if attrib[2] ~= nil then write ("\nchanging '"..attrib[1].."' to '"..attrib[2].."'...")
else write ("\nchanging '"..attrib[1].."' to '(empty)'...") end
readSettings ( )
if attrib[1] == "xTrees" then
xTrees = tonumber (attrib[2])
elseif attrib[1] == "yTrees" then
yTrees = tonumber (attrib[2])
elseif attrib[1] == "slotAmount" then
slotAmount = tonumber (attrib[2])
elseif attrib[1] == "saplingOffset" then
saplingOffset = tonumber (attrib[2])
elseif attrib[1] == "wallOffset" then
wallOffset = tonumber (attrib[2])
elseif attrib[1] == "saplingMethod" then
saplingMethod = attrib[2]
elseif attrib[1] == "throwSaplings" then
throwSaplings = attrib[2] == "true"
elseif attrib[1] == "fullSaplings" then
fullSaplings = attrib[2] == "true"
elseif attrib[1] == "chestOutput" then
chestOutput = attrib[2] == "true"
elseif attrib[1] == "sleepTime" then
sleepTime = tonumber (attrib[2])
else
write ("\n"..attrib[1].." is no valid parameter!")
end
writeSettings ( )
elseif command == "startup" then
if attrib[1] == nil and fs.exists ("startup") then
fs.delete ("startup")
elseif attrib[1] ~= nil then
file = fs.open ("startup", "w")
if attrib[2] == nil then
file.write ("shell.run (\""..attrib[1].."\")")
else
str = "shell.run (\""
for _, i in ipairs (attrib) do
str = str..i.."\", \""
end
str = string.sub (str, 1, string.len (str) - 3)..")"
file.write (str)
end
file.close ( )
end
end
end
function getRednet ( ) --> receiving all rednet commands which are in queue for this turtle if available
if serverID == nil then rednet.broadcast ("pull")
else rednet.send (serverID, "pull") end
repeat
serverID, message = rednet.receive (0.5)
until message ~= "pull" -- avoiding receiving commands from other turtles pulling
-- NOTE: this wont happen often because the first server answer will set a turtle to use the ID from this server as its sending ID
while serverID ~= nil and message ~= "end" do
handleRednet (message)
rednet.send (serverID, "pull")
repeat
serverID, message = rednet.receive (0.5)
until message ~= "pull"
end
end
function headline ( )
x, y = term.getCursorPos ( )
term.setCursorPos (1, 2)
term.clearLine ( )
term.setCursorPos (1, 1)
term.clearLine ( )
if turtle then
for i = 1, math.floor ((term.getSize ( ) - (25 + string.len (os.getComputerID ( )))) / 2) do write (" ") end -- looks more complicated than it is, only writes n times (" ") while n is the amount of empty digits after the headline devided by 2
print ("nO_OnEs Tree Farmer [ID "..os.getComputerID ( ).."]")
for i = 1, term.getSize ( ) do term.write ("-") end
else
for i = 1, math.floor ((term.getSize ( ) - 40) / 2) do write (" ") end -- looks more complicated than it is, only writes n times (" ") while n is the amount of empty digits after the headline devided by 2
print ("[Automatic Tree Farmer] Server Interface")
for i = 1, term.getSize ( ) do term.write ("-") end
end
term.setCursorPos (x, y)
end
function done ( ) --> writing '- done' at the end of the current line
x, y = term.getCursorPos ( )
if x > (term.getSize ( ) - 6) then y = y + 1 end -- if the current line is full yet
term.setCursorPos (term.getSize ( ) - 5, y)
term.write ("- done")
write ("\n")
headline ( )
end
function beServer ( )
rednet.open ("left")
rednet.open ("right")
rednet.open ("top")
headline ( )
write ("\n\n")
while true do
headline ( )
x, y = term.getCursorPos ( )
term.clearLine ( )
term.setCursorPos (1, y)
write ("Press any key")
event, one, two = os.pullEvent ( )
if event == "rednet_message" and two == "pull" then -- if 'pull' command received
x, y = term.getCursorPos ( )
term.clearLine ( )
term.setCursorPos (1, y)
if not fs.exists ("turtle "..one) then
fileWrite = fs.open ("turtle "..one, "w")
fileWrite.writeLine ("end")
fileWrite.close ( )
print ("new turtle registered (ID "..one..")")
end
fileRead = fs.open ("turtle "..one, "r")
i = 0
local text = { }
repeat
i = i + 1
line = fileRead.readLine ( )
text[i] = line
until text[i] == nil
fileRead.close ( )
rednet.send (one, text[1])
fileWrite = fs.open ("turtle "..one, "w")
i = 2
while text[i] ~= "end" and text[i] ~= nil do
fileWrite.writeLine (text[i])
i = i + 1
end
fileWrite.writeLine ("end")
fileWrite.close ( )
if text[1] ~= "end" then print ("sent '"..text[1].."' to turtle "..one)
else print ("no commands in queue for turtle "..one) end
elseif event == "char" then -- if key pressed
local turtles = { }
n = 1
for _, i in ipairs (fs.list ("")) do
if string.sub (i, 1, 7) == "turtle " and tonumber (string.sub (i, 8)) ~= nil then
turtles[n] = i
n = n + 1
end
end
if turtles[1] ~= nil then
term.clear ( )
term.setCursorPos (1, 1)
headline ( )
write ("\n\n")
print ("available turtles:")
for _, i in ipairs (turtles) do
print ("- "..i)
end
print ("")
print ("please enter the number of the turtle you want to send a command to or 'all' if you want to message every turtle (exit to abort)")
number = read ( )
while not (tonumber (number) ~= nil or number == "all" and tonumber (number) == nil) and number ~= "exit" do
print ("incorrect number")
headline ( )
number = read ( )
end
if number ~= "exit" then
print ("command: (type help to see command-list or exit to abort)")
headline ( )
message = read ( )
while message == "help" and message ~= "exit" do
term.clear ( )
term.setCursorPos (1, 1)
write ("\n\n")
headline ( )
print ("available commands: [attribute] (optional)")
print ("- change [xTrees | yTrees | saplingOffset | wallOffset | saplingMethod | fullSaplings | throwSaplings | sleepTime | slotAmount | chestOutput] [value]")
print ("- stop")
print ("- shutdown")
print ("- reboot")
print ("- startup (command) (atrribute1) (...)\n *leave command blank for no startup command")
print ("\ncommand: (type help to see command-list or exit to abort)")
message = read ( )
end
if message ~= "exit" then
if number == "all" then
for _, i in ipairs (turtles) do
fileNew = fs.open (i, "r")
file = fileNew.readAll ( )
fileNew.close ( )
fileNew = fs.open (i, "w")
fileNew.writeLine (message)
fileNew.write (file)
fileNew.close ( )
end
else
fileNew = fs.open ("turtle "..number, "r")
file = fileNew.readAll ( )
fileNew.close ( )
fileNew = fs.open ("turtle "..number, "w")
fileNew.writeLine (message)
fileNew.write (file)
fileNew.close ( )
end
end
end
term.clear ( )
term.setCursorPos (1, 2)
else
x, y = term.getCursorPos ( )
term.clearLine ( )
term.setCursorPos (1, y)
print ("No turtles available at the moment!")
end
end
end
end
term.clear ( )
term.setCursorPos (1, 1)
if not turtle then beServer ( ) end
while not fs.exists ("farmer.cfg") do --> writing default settings (while asking for the size of the Farm)
term.clear ( )
term.setCursorPos (1, 1)
textutils.slowPrint ("No configuration file found.")
sleep (0.25)
print ("")
print ("example with xTrees 4 and yTrees 3")
print ("+ + + + <-- sapling")
print ("+ + + +")
print ("+ + + +")
print ("o <-- logger facing up")
print ("")
print ("How many trees horizontally?\n(xTrees)")
xTrees = read ( )
print ("How many trees vertically?\n(yTrees)")
yTrees = read ( )
textutils.slowPrint ("Writing configuration-file")
print("")
writeSettings ( )
if fs.exists ("farmer.cfg") then
textutils.slowPrint ("farmer.cfg found, success!")
end
sleep (0.5)
term.clear ( )
term.setCursorPos (1, 1)
end
rednet.open ("right")
write ("\n\n")
headline ( )
while true do
write ("getting rednet commands...")
getRednet ( )
done ( )
write ("reading config...")
readSettings ( )
done ( )
write ("dropping Items...")
if not fullSaplings and throwSaplings then drop (1) end
drop (0)
done ( )
repeat
x, y = term.getCursorPos ( )
x = 1
term.setCursorPos (x, y)
saplings = waitForSaplings ( )
if saplings == 1 then write ("1 sapling remaining ...")
elseif saplings < 1 then write ("0 saplings remaining ...")
else write (saplings.." saplings remaining ...") end
sleep (1)
until saplings < 1
done ( )
for i = 0, sleepTime do
x, y = term.getCursorPos ( )
x = 1
term.setCursorPos (x, y)
write ("sleeping... ("..sleepTime-i.."sec left)")
sleep (1)
end
done ( )
write ("farming "..xTrees.." x "..yTrees.."...")
farm ( )
done ( )
end
-- Note: [removed]