Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- --Fichier de sauvegarde des variables utiles au reboot :
- -- turtle.farm.dir: Orientation de la turtle 0,1,2,3 (N-E-S-W)
- -- turtle.farm.fuel: Niveau de fuel au d?part d'une boucle
- -- Si le fichier n'existe pas il sera cree
- local settingsFile = "/settings/TurtleFarm"
- --Fichier contenant les donnees a inscrire sur le moniteur
- -- N?cessairement sur un disk
- -- Si le mountPath est modifie, il sera corrige au premier disk drive trouve
- local dataFile = "/disk/FarmData"
- --Delai applique a chaque pas
- local delay=.1
- --Duree de la pause entre deux tours
- local pause=900 --15min
- --Multiplicateur
- -- passe a 10, la turtle prevoira assez de fuel pour 10 tours
- local fuelSupply=4 -- minimum 2 par securite
- --Soupape : nombre d'echecs successifs toleres dans une boucle while
- local limit=32
- -- Delai d'attente de confirmation pour reinitialiser au reboot
- -- Hard reboot: Placer un bloc de redstone sur le parcours de la turtle
- -- La turtle stoppe. Retirer le bloc, la turtle demande confirmation pour reinitialiser
- -- Sans confirmation passe le delai hardRebootCountDown, elle reprend sa course
- local hardRebootCountDown = 10
- --Liste des items bons a jeter (ne seront pas stockes)
- unwanted = {
- ["minecraft:poisonous_potato"]=1,
- --["minecraft:wheat_seeds"]=1, --NB: un stack de graines sera tout de meme conserve par la turtle pour replanter
- }
- --
- -- API
- --
- if not os.loadAPI("/apis/dbFarm") then
- error("Missing API: dbFarm\n> pastebin get k0bi24gr /apis/dbFarm")
- return
- end
- if not os.loadAPI("/apis/dbFuel") then
- error("Missing API: dbFuel\n> pastebin get 5g2DntXx /apis/dbFuel")
- return
- end
- --
- -- CONSTANTS
- --
- NORTH=0
- EAST=1
- SOUTH=2
- WEST=3
- sDir={"North","East","South","West"}
- plantAges = {
- ["minecraft:wheat"] =7,
- ["minecraft:carrots"] =7,
- ["minecraft:potatoes"] =7,
- ["minecraft:melon_block"]=7,
- ["minecraft:pumpkin"] =7,
- ["minecraft:reeds"] =7,
- ["minecraft:nether_wart"]=3, --/!\
- ["minecraft:beetroots"] =3, --/!\
- }
- --Bloc reference (see function walk() 263)
- --sBlockType = "minecraft:stained_hardened_clay"
- sBlockType = "minecraft:stained_glass"
- local function blockType_north(data)
- return data.name==sBlockType
- and data.state
- and data.state.color=="red"
- end
- local function blockType_east(data)
- return data.name==sBlockType
- and data.state
- and data.state.color=="orange"
- end
- local function blockType_south(data)
- return data.name==sBlockType
- and data.state
- and data.state.color=="yellow"
- end
- local function blockType_west(data)
- return data.name==sBlockType
- and data.state
- and data.state.color=="white"
- end
- local function isContainer(name)
- return name=="minecraft:chest"
- or name=="minecraft:trapped_chest"
- or name=="minecraft:dispenser"
- or name=="minecraft:hopper"
- or name=="minecraft:dropper"
- or name=="computercraft:CC-Turtle"
- or name=="computercraft:CC-TurtleExpanded"
- or name=="computercraft:CC-TurtleAdvanced"
- or name=="ironchest:BlockIronChest"
- end
- --
- -- GLOBALS
- --
- fuelSupply = math.max(2,fuelSupply)
- fuelUsed=0
- block={up={},down={}}
- tick = os.startTimer(.1)
- tFarmCrops,tFarmSeeds,tFarmBlocks = {},{},{}
- local _,v
- local _,_cropsList = dbFarm.query("crop")
- local _,_seedsList = dbFarm.query("seed")
- local _,_blocksList = dbFarm.query("block")
- for _,v in pairs(_cropsList) do tFarmCrops[v]=1 end
- for _,v in pairs(_seedsList) do tFarmSeeds[v]=1 end
- for _,v in pairs(_blocksList) do tFarmBlocks[v]=1 end
- --Demande l'orientation de la turtle (N-E-S-W)
- --Initialise le fichier de sauvegarde des settings
- init=function()
- local msg = ""
- local confirm=false
- while not confirm do
- term.setCursorPos(1,1)
- term.clear()
- print([[TurtleFarming
- Set Turtle current orientation
- 0:North
- 1:East
- 2:South
- 3:West]])
- print(msg)
- local d = read()
- if not tonumber(d) or (d~="0" and d~="1" and d~="2" and d~="3") then
- msg="Number: 0, 1, 2 ort 3"
- else
- settings.set("turtle.farm.dir",tonumber(d))
- settings.save(settingsFile)
- confirm=true
- break
- end
- end
- end
- --Charge les donnees stockees dans le fichier settings
- if not fs.exists(settingsFile) then init()
- else settings.load(settingsFile) end
- local dir = settings.get("turtle.farm.dir",init)
- --Statistiques par tour
- lap = {
- loop=0,
- chrono=0,
- crops=settings.get("turtle.farm.crops",0),
- fuel=settings.get("turtle.farm.fuel",turtle.getFuelLevel())
- }
- --Ecrit sur le terminal ? une ligne donn?e
- local function printLine(str,y)
- term.setCursorPos(1,y)
- term.clearLine()
- print(str)
- end
- --Hard reboot
- if rs.getInput("back") or rs.getInput("front")
- or rs.getInput("top") or rs.getInput("bottom")
- or rs.getInput("left") or rs.getInput("right") then
- print("Hard Reboot")
- os.pullEvent("redstone")
- local x,y = term.getCursorPos()
- local confirm,countdown,countdownTimer = false,hardRebootCountDown,os.startTimer(1)
- while not confirm and countdown>0 do
- printLine("Reset Turtle orientation ("..sDir[dir+1]..") ?",y)
- printLine("Press Y/N ("..countdown..")", y+1)
- local e,k = os.pullEvent()
- if e=="key" and k==keys.y then
- sleep(.3)
- init()
- confirm=true
- break
- elseif e=="key" and k==keys.n then
- sleep(.3)
- confirm=true
- break
- elseif e=="timer" then
- countdown=countdown-1
- countdownTimer = os.startTimer(1)
- end
- end
- end
- -- Panne de Fuel
- -- interrompt la turtle, en l'attente de ravitaillement en fuel
- local function waitManualyRefuel()
- printLine("Give some Fuel then press any key",8)
- while turtle.getFuelLevel()==0 do
- os.pullEvent("key")
- term.setCursorPos(1,9)
- term.clearLine()
- shell.run("refuel all")
- end
- printLine("",8)
- end
- -- Avance la turtle d'une case
- -- Recolte la canne a surcre si elle bloque le passage
- local function forward()
- local test = turtle.forward()
- if not test and turtle.detect() then
- local test,data=turtle.inspect()
- if test and data.name=="minecraft:reeds" then
- if turtle.dig() and turtle.forward() then
- lap.crops = lap.crops+1
- settings.set("turtle.farm.crops",lap.crops)
- settings.save(settingsFile)
- turtle.suckUp()
- turtle.suck()
- turtle.suckDown()
- return true
- end
- end
- error("Program stopped by a block forward\n"..textutils.serialize(data),-1) exit()
- end
- local count=1
- while not test and not turtle.detect() and turtle.getFuelLevel()>0 and count<limit do
- sleep(delay)
- count = count+1
- test = turtle.forward()
- end
- if not test then
- if turtle.getFuelLevel()==0 then
- waitManualyRefuel()
- else
- error("Program stopped. Can't go forward (tries:"..count..")",-1)
- exit()
- end
- end
- end
- -- Releve les donnees des blocs dessus/dessous
- local function inspect()
- local test,data
- test,data = turtle.inspectUp()
- block.up = test and data or false
- test,data = turtle.inspectDown()
- block.down = test and data or false
- end
- -- Aligne la turtle dans la direction indiquee
- -- Sauvegarde de la nouvelle direction dans le fichier settings
- local function turn(d)
- if dir ~= d then
- if d == NORTH then
- if dir==EAST then turtle.turnLeft()
- elseif dir==SOUTH then turtle.turnLeft() turtle.turnLeft()
- elseif dir==WEST then turtle.turnRight()
- end
- elseif d == EAST then
- if dir==NORTH then turtle.turnRight()
- elseif dir==SOUTH then turtle.turnLeft()
- elseif dir==WEST then turtle.turnLeft() turtle.turnLeft()
- end
- elseif d == SOUTH then
- if dir==NORTH then turtle.turnLeft() turtle.turnLeft()
- elseif dir==EAST then turtle.turnRight()
- elseif dir==WEST then turtle.turnLeft()
- end
- elseif d == WEST then
- if dir==NORTH then turtle.turnLeft()
- elseif dir==EAST then turtle.turnLeft() turtle.turnLeft()
- elseif dir==SOUTH then turtle.turnRight()
- end
- end
- dir = d
- settings.set("turtle.farm.dir",d)
- settings.save(settingsFile)
- end
- end
- -- Gere le mouvement de la turtle
- local function walk()
- printLine("",7)
- if block.up then
- if blockType_north(block.up) then
- printLine("North",7) turn(NORTH) forward()
- elseif blockType_east(block.up) then
- printLine("East",7) turn(EAST) forward()
- elseif blockType_south(block.up) then
- printLine("South",7) turn(SOUTH) forward()
- elseif blockType_west(block.up) then
- printLine("West",7) turn(WEST) forward()
- elseif isContainer(block.up.name) then
- printLine("Container",7) forward()
- else
- printLine(block.up.name,7)
- end
- end
- end
- -- Formate un nombre de secondes en dur?e lisible
- local function timeStr(sec)
- local d = math.floor(sec/86400) --24*60*60 sec
- local h = math.floor(sec/3600)%24 -- 60x60 sec
- local m = math.floor(sec/60)%60 -- 60sec
- local s = math.floor(sec%60) --Reste
- local str = ""
- if d>0 then str = d>1 and d.. "days " or "1 day " end
- if h>0 then str = str..h.."h" end
- if m>0 then str = str..(m>9 and m or "0"..m) end
- if h==0 then str = m>0 and str..":"..(s>9 and s or "0"..s) or s.."s" end
- return str
- end
- -- V?rifie que le repertoire racine de la disquette est bien present
- -- Sinon la variable est corrigee (au premier disk drive trouve)
- local function getMountedDisk()
- if fs.exists(dataFile) then return true end
- local _,name
- for _,name in pairs(peripheral.getNames()) do
- if peripheral.getType(name) == "drive" then
- if disk.hasData(name) then
- local mount = disk.getMountPath(name)
- local pattern = "^/?disk%d*/(.+)$"
- dataFile = string.gsub(dataFile, pattern, "/"..mount.."/%1")
- return true
- end
- end
- end
- return false
- end
- -- Sauvegarde les donnees statistiques dans une disquette
- -- a fin d'affichage sur un moniteur
- local function storeData()
- lap.loop=lap.loop+1
- if getMountedDisk() then --S'il y a bien une disquette disponible
- local sChrono,sFuel="",""
- if lap.chrono>0 then
- sChrono = " / "..math.floor(os.clock()-lap.chrono)
- end
- if lap.fuel>0 then
- sFuel = " / used: "..(lap.fuel - turtle.getFuelLevel())
- end
- local report = string.format([[Loops: %d
- Running until: %s%s
- Fuel level: %d%s
- Crops: %d]],
- lap.loop,
- timeStr(os.clock()), sChrono,
- turtle.getFuelLevel(),sFuel,
- lap.crops)
- local fh = fs.open(dataFile,"w")
- fh.write(report)
- fh.close()
- end
- lap.chrono = os.clock()
- lap.fuel = turtle.getFuelLevel()
- settings.set("turtle.farm.fuel",lap.fuel)
- settings.save(settingsFile)
- end
- -- Regroupe les items identiques dans l'inventaire
- local function compactInventory()
- printLine("Compact inventory",8)
- local i,j,d1,d2
- for i=1,16 do
- d1 = turtle.getItemDetail(i)
- if d1~=nil and turtle.getItemSpace(i)>0 then
- for j=i+1,16 do
- d2 = turtle.getItemDetail(j)
- if d2~=nil and d1.name==d2.name then
- turtle.select(j)
- turtle.transferTo(i)
- end
- end
- end
- end
- end
- --Renvoi le premier slot vide trouve
- --Renvoi false si linventaire est plein
- local function findFreeSlot()
- local i
- for i=1,16 do
- if turtle.getItemCount(i)==0 then
- return i
- end
- end
- return false
- end
- --Renvoi le premier slot contenant un combustible compatible
- --Renvoi false si aucun combustible n'est trouv?
- local function findFuelSlot()
- local i
- for i=1,16 do
- local data = turtle.getItemDetail(i)
- if data and dbFuel.isFuel(data.name) then
- return i
- end
- end
- return false
- end
- -- https://github.com/garrynewman/garrysmod/blob/master/garrysmod/lua/includes/extensions/table.lua#L93
- local function tableHasValue( t, val )
- for k, v in pairs( t ) do
- if ( v == val ) then return true end
- end
- return false
- end
- --Compare les quantites de chaque slot indiques par slotList
- --_v: Retourne le num?ro du slot le moins fourni
- --_k: Retourne la cl? correspondante de la table slotList
- local function getMinQtySlot(slotList)
- slotList = slotList or {1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16}
- local _min,k,v,_k,_v=64
- for k,v in pairs(fuelSlots) do
- if _min >= turtle.getItemCount(v) then
- _min = turtle.getItemCount(v)
- _k = k
- _v = v
- end
- end
- return _v,_k
- end
- --Vide les slots contenant des items inutiles
- -- drop : function (turtle.drop, turtle.dropUp, turtle.dropDown)
- -- n : nombre de slot ? lib?rer
- local function dumpUnwanted(drop,n)
- n = n or 16
- compactInventory()
- printLine("Dump unwanted",8)
- local i,farmSlots,fuelSlots=1,{},{},{}
- -- >global local tFarmCrops = dbFarm.query("crop")
- -- >global local tFarmSeeds = dbFarm.query("seed")
- for i=1,16 do
- local data = turtle.getItemDetail(i)
- if not data then
- n=n-1
- elseif dbFuel.isFuel(data.name) then
- table.insert(fuelSlots,i)
- elseif tFarmSeeds[data.name]~=nil then
- table.insert(farmSlots,i)
- elseif tFarmCrops[data.name]~=nil then
- table.insert(farmSlots,i)
- else
- turtle.select(i)
- drop(64)
- n=n-1
- end
- if n<=0 then return true end
- end
- while n>1 do
- if #fuelSlots > 0 then
- local slot,key = getMinQtySlot(fuelSlots)
- table.remove (fuelSlots, key)
- else
- local slot,key = getMinQtySlot(farmSlots)
- table.remove (farmSlots, key)
- end
- turtle.select(s)
- drop(64)
- n=n-1
- end
- return not n>1
- end
- -- Gestion automatique du fuel a la station
- local function autoRefuel()
- printLine("Auto refuel",8)
- if turtle.getFuelLevel()<fuelUsed*fuelSupply then
- compactInventory()
- slot = findFreeSlot()
- if not slot then slot=findFuelSlot() end
- if slot then
- turtle.select(slot)
- while turtle.getFuelLevel()<fuelUsed*fuelSupply do
- if not turtle.suckUp(1) then
- error("Fuel tank is empty...",-1)
- exit()
- end
- turtle.refuel()
- lap.fuel = turtle.getFuelLevel()+1 -- diff de la distance entre les stations storeData et autorefuel
- settings.set("turtle.farm.fuel",lap.fuel)
- settings.save(settingsFile)
- end
- end
- end
- end
- -- Trouve un slot contenant l'item indique
- -- Renvoi false s'il ne trouve rien
- local function findSlotItem(refName)
- local slot=1
- for slot=1,16 do
- local data = turtle.getItemDetail(slot)
- if data and data.name==refName then return slot end
- end
- return false
- end
- -- Ramasse et replante, dans la mesure du possible
- -- Renvoi false si la manoeuvre n'est pas parfaitement execut?e.
- local function crop()
- printLine("Crop manager",8)
- if block.down and block.down.state and block.down.state.age then
- local requiredAge = plantAges[block.down.name]
- printLine(block.down.name.." "..block.down.state.age.."/"..requiredAge,5)
- if block.down.state.age>=requiredAge then
- local test,result = dbFarm.query("block",block.down.name)
- if test and result["seed"] then
- local slot = findSlotItem(result["seed"])
- if not slot then slot = findFreeSlot() end
- if not slot and dumpUnwanted(turtle.dropDown,1) then slot = findFreeSlot() end
- if not slot then error("Inventory saturation..",-1) exit() end
- turtle.select(slot)
- if turtle.digDown() then
- lap.crops=lap.crops+1
- settings.set("turtle.farm.crops",lap.crops)
- settings.save(settingsFile)
- turtle.select(findSlotItem(result["seed"]))
- return turtle.placeDown()
- end
- end
- end
- end
- return false
- end
- local function storeCrops()
- if lap.crops>0 and isContainer(block.up.name) then
- local skip = {
- wheat_seeds = findSlotItem("minecraft:wheat_seeds"),
- potato = findSlotItem("minecraft:potato"),
- carrot = findSlotItem("minecraft:carrot"),
- nether_wart = findSlotItem("minecraft:nether_wart"),
- beetroot_seeds = findSlotItem("minecraft:beetroot_seeds"),
- }
- local slot
- for slot=1,16 do
- if slot ~= skip.wheat_seeds
- and slot ~= skip.potato
- and slot ~= skip.carrot
- and slot ~= skip.nether_wart
- and slot ~= skip.beetroot_seeds
- and turtle.getItemCount(slot)>0
- then
- turtle.select(slot)
- local data = turtle.getItemDetail(slot)
- if unwanted[data.name]~=nil then turtle.drop(64)
- else turtle.dropUp(64) end
- end
- end
- lap.crops = 0
- settings.set("turtle.farm.crops",lap.crops)
- settings.save(settingsFile)
- end
- end
- -- Gere les op?rations de la turtle
- local function step()
- printLine("",5)
- if block.down then
- --End loop
- if block.down.name=="computercraft:CC-Peripheral" then
- compactInventory()
- fuelUsed = lap.fuel - turtle.getFuelLevel()
- if block.down.state.variant=="disk_drive_full" then
- printLine("Disk-Drive",5)
- storeData()
- storeCrops()
- else
- printLine(block.down.name.." / "..block.down.state.variant,5)
- end
- --init pause delay
- settings.set("turtle.farm.pause",pause)
- settings.save(settingsFile)
- --Start Loop
- elseif block.down.name=="computercraft:CC-Computer" then
- autoRefuel()
- local computer = peripheral.wrap("bottom")
- if computer.isOn() then computer.reboot()
- else computer.turnOn() end
- --Pause
- settings.load(settingsFile)
- local pauseDelay = settings.get("turtle.farm.pause",pause)
- while pauseDelay>0 do
- printLine("Pause : "..timeStr(pauseDelay),5)
- --Sauvegarde le temps ?coul? toutes les secondes
- local pauseTimer = os.startTimer(1)
- local e = os.pullEvent("timer")
- pauseDelay=pauseDelay-1
- settings.set("turtle.farm.pause",pauseDelay)
- settings.save(settingsFile)
- end
- --Crops
- elseif block.down.name=="minecraft:pumpkin"
- or block.down.name=="minecraft:melon_block"
- or block.down.name=="minecraft:reeds" then
- local cropName = (block.down.name == "minecraft:pumpkin") and "minecraft:pumpkin" or "minecraft:melon"
- if block.down.name=="minecraft:reeds" then cropName="minecraft:reeds" end
- local slot = findSlotItem(cropName)
- if slot then turtle.select(slot) end
- if turtle.digDown() then
- lap.crops = lap.crops+1
- settings.set("turtle.farm.crops",lap.crops)
- settings.save(settingsFile)
- end
- elseif tFarmBlocks[block.down.name]==1 and block.down.name~="minecraft:reeds" then
- printLine(block.down.name,5)
- crop()
- else
- printLine(block.down.name.."*",5)
- end
- end
- printLine("Crops: "..lap.crops,3)
- printLine("",8)
- end
- -- Sequence des manoeuvres
- local function process()
- printLine("Reading blocks",2)
- inspect()
- printLine("Process step",4)
- step()
- printLine("Process walk",6)
- walk()
- end
- --Gestionaire principal
- function main()
- term.clear()
- term.setCursorPos(1,1)
- local continue=true
- tick=os.startTimer(delay)
- while continue do
- local e,k=os.pullEvent()
- if e=="redstone" then
- os.reboot()
- continue=false
- elseif e=="key" and k==keys.t then
- continue=false
- os.cancelTimer(tick)
- elseif e=="timer" then
- printLine("Process new step "..os.clock(),1)
- printLine("Fuel level is "..turtle.getFuelLevel(),9)
- process()
- tick=os.startTimer(delay)
- end
- end
- print("Terminate")
- ignoreReboot = false
- sleep(delay)
- end
- main()
Add Comment
Please, Sign In to add comment