Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- --[[
- ===================================
- DRONES
- ===================================
- Originally created by Pooslice <[email protected]> (replace underscore with dot)
- Previous version: http://pastebin.com/AEqwuC5b
- What does it do?
- * Clears a whole chunk (16x16 blocks) down to bedrock.
- Features:
- * Automatically refuels from drone inventory or refuel station.
- * Usually clears a chunk in less than 30 minutes using a total of 17 wireless mining turtles.
- * User interaction is required only at setup.
- * Immune against lava, water, mobs and any combination of those.
- * All collected blocks are placed in chests at the top.
- * Has some cleverness to save on fuel.
- Restrictions:
- * Water, lava and mobs will still slow down the mining process.
- * Will leave out blocks that are located in a vertical gap between bedrock blocks.
- * Will leave some cobblestone blocks when lava and water merge after a drone has already passed by.
- * Needs a clear starting area of 16x16x1 blocks as well as one block behind the starting block.
- * Will only work with iron chests or any other inventory that can be placed next to each other in a direct horizontal line.
- * Does not check for full chests on drop.
- * Not logoff- and server-shutdown-proof
- * My first real lua project. So the coding style is kind of sloppy and there are redundancies. Feel free to refactor and edit.
- Usage:
- Demonstration video: http://youtu.be/ehAHqZEZ66A
- * Place a wireless mining turtle somewhere. The area that will be digged out will be 15 blocks forward and to the right of this turtle. There should be no blocks on the turtle's level (y coordinate) in this area.
- * Start the program with 'drone setup'
- * Follow the instructions. You will need 16 wireless mining turtles, 16 iron (or better) chests, one disk drive, one floppy disk and some fuel. I recommend at least three stacks of coal for one chunk.
- * Grab a coffee and watch the magic :)
- The code is published with no rights reserved. If and how you make use of it is your own decision and I will not be held responsible. Also note that I do not have the time to make updates or regularly check the forums for comments. It was a fun little project to get used to some lua and I am releasing this to the community with the hope that it might be of use to someone.
- I DO like feedback and will enjoy reading some posts occassionally. Credits are also always appreciated if you use any of this code in your own projects :)
- ]]--
- STARTUPTIME = os.clock()
- -- get call parameters
- local tArgs = { ... }
- -- constants
- REFUELTHRESHOLD = 96 * 4 -- 4 coal per turtle -> one stack of coal initially plus one coal for the floppy setup
- DEBUGMODE = false
- LOGFILENAME = nil
- function debug(message)
- if DEBUGMODE then print(message) end
- if LOGFILENAME then
- local fp = fs.open(LOGFILENAME, "a")
- if fp then
- fp.writeLine(message)
- fp.close()
- end
- end
- end
- debug("Startup-Time: " .. STARTUPTIME)
- -- compensate for fuelless mode
- if turtle.getFuelLevel() == "unlimited" then
- turtle.getFuelLevel = function()
- return 2 + REFUELTHRESHOLD
- end
- end
- -- don't care where
- rednet.open("right")
- rednet.open("left")
- rednet.open("top")
- rednet.open("bottom")
- rednet.open("front")
- rednet.open("back")
- -- try to clear the space above the turtle
- -- this cannot be done 100% reliably, because dig() on water returns 'true', but detect() on water returns 'false' and water regenerates
- function clearUp()
- debug("clearUp()")
- if turtle.detectUp() then
- if turtle.digUp() then
- sleep(1)
- turtle.digUp()
- end
- end
- while turtle.attackUp() do end
- return not turtle.detectUp()
- end
- -- see clearUp()
- function clearDown()
- debug("clearDown()")
- if turtle.detectDown() then
- turtle.digDown()
- end
- while turtle.attackDown() do end
- return not turtle.detectDown()
- end
- -- as clearUp(), but also tries to move up after digging
- function tryUp()
- debug("tryUp()")
- if turtle.detectUp() then
- turtle.digUp()
- end
- while turtle.attackUp() do end
- return turtle.up()
- end
- -- see tryUp()
- function tryDown()
- debug("tryDown()")
- if turtle.detectDown() then
- turtle.digDown()
- end
- while turtle.attackDown() do end
- return turtle.down()
- end
- -- see tryUp()
- -- with our digging strategy a maximum of 2 blocks must be digged out (one normal and one if it is falling sand or gravel)
- function tryForward()
- debug("tryForward()")
- if turtle.detect() then
- if turtle.dig() then
- sleep(1)
- if turtle.dig() then
- sleep(1)
- turtle.dig()
- end
- end
- end
- while turtle.attack() do end
- return turtle.forward()
- end
- -- return to our chest, drop everything there and refuel if necessary
- -- returns new x, y, z and face which should be the same as when calling the function
- function maintenance(refuelId, x, y, z, face)
- debug("maintenance(" .. refuelId .. ", " .. x .. ", " .. y .. ", " .. z .. ", ??)")
- local dx, dy, dz, dface = x, y, z, face
- -- move below our chest
- while y > 4 do
- if tryUp() then
- y = y - 1
- end
- end
- -- could come across other turtles -> no digging
- while y > 0 do
- while not turtle.up() do sleep(1) end
- y = y - 1
- end
- if face then
- turtle.turnRight()
- turtle.turnRight()
- end
- while x > 0 do
- while not turtle.forward() do sleep(5) end
- x = x - 1
- end
- turtle.turnRight()
- turtle.turnRight()
- -- Try to refuel from inventory if necessary
- if turtle.getFuelLevel() < REFUELTHRESHOLD then
- debug("Refuel needed: " .. turtle.getFuelLevel() .. " < " .. REFUELTHRESHOLD)
- debug("Trying to refuel from inventory")
- for i = 1, 16 do
- turtle.select(i)
- repeat
- local fl = turtle.getFuelLevel()
- turtle.refuel(1)
- local fl2 = turtle.getFuelLevel()
- until fl == fl2 or fl2 > REFUELTHRESHOLD
- if turtle.getFuelLevel() >= REFUELTHRESHOLD then
- debug("Refuelling from inventory was successful: " .. turtle.getFuelLevel())
- break
- end
- end
- end
- -- drop all into the chest - overflow is ignored
- for i = 1, 16 do
- turtle.select(i)
- turtle.dropUp()
- end
- -- refuel from station if still necessary
- if turtle.getFuelLevel() < REFUELTHRESHOLD then
- debug("Going to refuel at the station")
- -- go to fuel station
- -- from now on we could cross other turtles' lanes and will therefore only move, not dig
- while not turtle.forward() do sleep(1) end
- turtle.turnRight()
- while z > 0 do
- while not turtle.forward() do sleep(5) end
- z = z - 1
- end
- turtle.turnRight()
- turtle.turnRight()
- while not turtle.up() do sleep(5) end
- while not turtle.up() do sleep(5) end
- -- refuel
- while true do
- -- refuel all and send fuel level until > REFUELTHRESHOLD
- for i = 1, 16 do
- turtle.select(i)
- turtle.refuel()
- end
- local message = {}
- message["message"] = "fuelLevel"
- message["fuelLevel"] = turtle.getFuelLevel()
- rednet.send(refuelId, textutils.serialize(message))
- if message["fuelLevel"] > REFUELTHRESHOLD then
- break
- end
- end
- debug("Refuelling at station successful. Returning to lane.")
- -- go back to lane
- if dz == 0 then
- turtle.turnRight()
- while not turtle.forward() do sleep(5) end
- while not turtle.down() do sleep(5) end
- while not turtle.down() do sleep(5) end
- while not turtle.down() do sleep(5) end
- while not turtle.back() do sleep(5) end
- while not turtle.back() do sleep(5) end
- x = 0
- y = 1
- z = 0
- else
- while z < dz do
- while not turtle.forward() do sleep(5) end
- z = z + 1
- end
- turtle.turnRight()
- while not turtle.down() do sleep(5) end
- while not turtle.down() do sleep(5) end
- y = 0
- while not turtle.back() do sleep(1) end
- x = 0
- end
- end
- face = true
- -- go back to old position
- debug("Returning to old position before maintenance-call.")
- while x < dx do
- while not turtle.forward() do sleep(5) end
- x = x + 1
- end
- if face ~= dface then
- turtle.turnRight()
- turtle.turnRight()
- face = dface
- end
- while y < dy do
- while not turtle.down() do sleep(1) end
- y = y + 1
- end
- return x, y, z, face
- end
- function isInventoryFull()
- debug("isInventoryFull()")
- for i = 1, 16 do
- if turtle.getItemCount(i) == 0 then
- return false
- end
- end
- return true
- end
- function diglane(lane, refuelId)
- debug("digLane(" .. lane .. ", " .. refuelId .. ")")
- -- x is forward (lane direction), y is depth below start (positive int), z is lane, true means facing in positive x direction
- local x, y, z, face = 1, 0, lane, true
- -- near bedrock we switch the digging strategy to vertical shafts instead of horizontal tunnels
- local digVertical = false
- -- big loop with many if-statements that magically does the right next step
- while true do
- -- required fuel back to station
- -- back up + back zu x0 + one forward + to lane 0 + two up
- local distToRefuelStation = y + x + 1 + z + 2
- debug("Digging ... distToRefuelStation: " .. distToRefuelStation .. ", Fuel: " .. turtle.getFuelLevel())
- if turtle.getFuelLevel() - distToRefuelStation < 10 then -- some safety margin that was chosen arbitrarily
- debug("Trying to refuel from inventory.")
- -- try to refuel from inventory
- local fuelLevel = turtle.getFuelLevel()
- for i = 1, 16 do
- turtle.select(i)
- repeat
- local fl = turtle.getFuelLevel()
- turtle.refuel(1)
- local fl2 = turtle.getFuelLevel()
- until fl2 > REFUELTHRESHOLD or fl == fl2
- end
- if turtle.getFuelLevel() <= fuelLevel then
- debug("Inventory was not enough. Starting maintenance routine.")
- -- did not work or was not enough -> start maintenance routine
- x, y, z, face = maintenance(refuelId, x, y, z, face)
- end
- elseif isInventoryFull() then
- debug("Inventory is full. Starting maintenance routine.")
- x, y, z, face = maintenance(refuelId, x, y, z, face)
- else
- -- dig
- if not digVertical then
- if y % 3 > 0 then
- if tryDown() then
- y = y + 1
- else
- debug("Hit the ground. Will go to vertical mode.")
- digVertical = "start"
- end
- else
- if not clearUp() then
- debug("Seems, we moved one too far. Going back.")
- -- can only be the case if we accidently moved into a bedrock "gap"
- turtle.back()
- if face then
- x = x - 1
- else
- x = x + 1
- end
- if tryUp() then
- y = y - 1
- end
- debug("And starting vertical mode.")
- digVertical = "start"
- else
- if (not clearDown()) or (not tryForward()) then
- debug("Could not clear down or go forward. Starting vertical mode.")
- digVertical = "start"
- else
- if face then
- x = x + 1
- else
- x = x - 1
- end
- clearUp()
- if x == 0 or x == 15 then
- turtle.turnRight()
- turtle.turnRight()
- face = not face
- if not tryDown() then
- debug("At a border and could not go down. Starting vertical mode.")
- digVertical = "start"
- else
- y = y + 1
- end
- end
- end
- end
- end
- else
- if digVertical == "start" then
- -- make next step towards x15 with face towards x0
- if not face then
- turtle.turnRight()
- turtle.turnRight()
- face = not face
- end
- if x < 15 then
- debug("Moving towards the end of the lane.")
- if not tryForward() then
- if tryUp() then
- y = y - 1
- else
- -- need to backtrack
- debug("Moved into a gap. Backtracking ...")
- turtle.turnRight()
- turtle.turnRight()
- if tryForward() then
- x = x - 1
- end
- if tryUp() then
- y = y - 1
- end
- turtle.turnRight()
- turtle.turnRight()
- end
- else
- x = x + 1
- end
- else
- debug("In position for vertical digging")
- digVertical = "digVertical"
- turtle.turnRight()
- turtle.turnRight()
- face = not face
- end
- elseif digVertical == "digVertical" then
- if tryDown() then
- y = y + 1
- else
- if x > 0 then
- debug("At the bottom. Going to next field.")
- -- bedrock has 5 layers at most
- while not tryUp() do sleep(1) end
- while not tryUp() do sleep(1) end
- while not tryUp() do sleep(1) end
- while not tryUp() do sleep(1) end
- y = y - 4
- while not tryForward() do sleep(1) end
- x = x - 1
- else
- debug("Cleared the last block. Returning now.")
- break
- end
- end
- end
- end
- end
- end
- -- we should be at x0. so we go up and drop everything to our chest
- while y > 4 do
- while not tryUp() do sleep(1) end
- y = y - 1
- end
- -- could cross other turtles' paths -> no digging
- while y > 0 do
- while not turtle.up() do sleep(1) end
- y = y - 1
- end
- debug("Placing everything into the chest.")
- for i = 1, 16 do
- turtle.select(i)
- turtle.dropUp()
- end
- turtle.turnRight()
- turtle.turnRight()
- face = not face
- -- send finished to control
- local m = {}
- m["message"] = "laneFinished"
- rednet.send(refuelId, textutils.serialize(m))
- end
- function setuplane()
- local lane, refuelId
- while true do
- -- say hello
- local broadcast = {}
- broadcast["message"] = "hello"
- rednet.broadcast(textutils.serialize(broadcast))
- -- get welcome with our lane number
- local id, message, distance = rednet.receive(5)
- if message and distance < 2 then
- local m = {}
- m = textutils.unserialize(message)
- if m["message"] == "welcome" and m["lane"] > -1 then
- lane = m["lane"] + 0
- refuelId = id
- break
- end
- end
- end
- -- send fuel level, then get and use one fuel
- for i = 1, 16 do
- if turtle.getItemCount(i) == 0 then
- turtle.select(i)
- break
- end
- end
- local message = {}
- message["message"] = "fuelLevel"
- message["fuelLevel"] = turtle.getFuelLevel()
- message["lane"] = lane
- rednet.send(refuelId, textutils.serialize(message))
- local chestSlot
- while true do
- -- refuel all and send fuel level until > REFUELTHRESHOLD
- for i = 1, 16 do
- local fl = turtle.getFuelLevel()
- turtle.select(i)
- turtle.refuel()
- if turtle.getFuelLevel() > fl then
- break
- end
- end
- -- select lowest empty slot (to detect chest placement later on)
- for i = 1, 16 do
- if turtle.getItemCount(i) == 0 then
- chestSlot = i
- break
- end
- end
- message["fuelLevel"] = turtle.getFuelLevel()
- rednet.send(refuelId, textutils.serialize(message))
- if message["fuelLevel"] > REFUELTHRESHOLD then
- break
- end
- end
- -- get chest
- while turtle.getItemCount(chestSlot) < 1 do sleep(1) end
- -- only the first turtle needs to clear a path
- if lane == 15 then
- while not tryDown() do sleep(1) end
- else
- while not turtle.down() do sleep(1) end
- end
- -- dig/go to our lane
- for i = 1, lane do
- if lane == 15 then
- while not tryForward() do sleep(1) end
- else
- while not turtle.forward() do sleep(1) end
- end
- end
- turtle.turnRight()
- -- place chest
- turtle.select(chestSlot)
- clearUp()
- clearDown()
- turtle.placeUp()
- while not tryForward() do sleep(1) end
- -- dig lane
- shell.run("drone", "diglane", lane, refuelId)
- end
- function refuelStation(workers)
- debug("refuelStation: " .. textutils.serialize(workers))
- workers = workers or {}
- turtle.turnRight()
- print("Waiting for refuel requests. Will automatically exit if all lanes are complete. Press SPACE to exit early.")
- print()
- while true do
- if #workers < 1 then
- print("All lanes are done.")
- break
- end
- local event, id, message, distance = os.pullEvent()
- if event == "rednet_message" and distance < 2 and message then
- local m = {}
- m = textutils.unserialize(message)
- if m["message"] == "fuelLevel" and m["fuelLevel"] <= REFUELTHRESHOLD then
- for i = 5, 16 do
- if turtle.getItemCount(i) > 0 then
- turtle.select(i)
- turtle.drop(1)
- break
- end
- end
- end
- elseif event == "rednet_message" and message then
- local m = {}
- m = textutils.unserialize(message)
- if m["message"] == "laneFinished" then
- for i = 1, 16 do
- if workers[i] == id then
- workers[i] = nil
- break
- end
- end
- end
- elseif event == "key" and id == 57 then
- break
- end
- end
- turtle.turnLeft()
- end
- function setup()
- print("Please put ...")
- print("... 16 wireless mining turtles in slot 1.")
- print("... 16 iron or better chests in slot 2.")
- print("... a floppy disk in slot 3.")
- print("... a disk drive in slot 4.")
- print("... fuel of any kind in slots 5-16.")
- print()
- print("Press RETURN to start or SPACE to exit.")
- print()
- while true do
- local event, id, message = os.pullEvent()
- if event == "key" and id == 28 then
- break
- elseif event == "key" and id == 57 then
- return
- end
- end
- -- need 2 fuel to place the floppy
- while turtle.getFuelLevel() < 2 do
- for i = 1, 16 do
- turtle.select(i)
- turtle.refuel(1)
- if turtle.getFuelLevel() > 1 then
- break
- end
- end
- sleep(1)
- end
- -- need some space below me
- if not tryDown() then
- print("No space below me")
- return
- end
- -- place the disk drive and insert floppy
- turtle.turnRight()
- turtle.turnRight()
- if turtle.detect() and (not turtle.dig()) then
- print("Could not clear the space for the disk drive.")
- return
- end
- turtle.select(4)
- while not turtle.place() do sleep(5) end
- turtle.select(3)
- while not turtle.drop() do sleep(5) end
- -- write startup file to floppy
- local fp = fs.open("disk/startup", "w")
- fp.writeLine("shell.run(\"drone\", \"setuplane\")")
- fp.close()
- -- move back to our position
- while not tryUp() do sleep(5) end
- turtle.turnRight()
- turtle.turnRight()
- -- list of worker computerIDs
- local workers = {}
- -- place, refuel and send off 16 drones
- for i = 0, 15 do
- print("Placing drone " .. i + 1 .. " of 16.")
- print()
- -- place the drone
- turtle.select(1)
- while turtle.detectDown() do sleep(1) end
- turtle.placeDown()
- -- boot the drone, thanks to dustpuppy for reminding me about the peripheral API
- peripheral.call("bottom", "turnOn")
- -- wait for announce, send lane number, wait for confirmation
- -- the drone id is stored in the workers table
- while true do
- local id, message, distance = rednet.receive(5)
- local m = {}
- if message then
- m = textutils.unserialize(message)
- end
- if m["message"] == "hello" and distance < 2 then
- local answer = {}
- answer["message"] = "welcome"
- answer["lane"] = 15 - i
- rednet.send(id, textutils.serialize(answer))
- elseif m and m["message"] == "fuelLevel" and m["lane"] == 15 - i then
- workers[15 - i] = id
- break
- end
- end
- -- refuel drone to at least the threshold
- while true do
- for j = 5, 16 do
- if turtle.getItemCount(j) > 0 then
- turtle.select(j)
- turtle.dropDown(1)
- break
- end
- end
- local id, message, distance = rednet.receive(5)
- local m = {}
- if message then
- m = textutils.unserialize(message)
- end
- if m["message"] == "fuelLevel" and m["fuelLevel"] > REFUELTHRESHOLD then
- break
- end
- end
- -- place chest in drone inventory
- turtle.select(2)
- turtle.dropDown(1)
- end
- -- All drones placed. We switch to refuelling mode
- shell.run("drone", "refuelstation", textutils.serialize(workers))
- end
- function printUsage()
- print("Usage of drone command:")
- print()
- print("drone setup|setuplane|diglane <laneNo> <refuelId>|refuelstation <serializedIdList>")
- print()
- end
- -- =========================================
- -- MAIN
- -- =========================================
- if tArgs[1] == "setup" then
- setup()
- elseif tArgs[1] == "setuplane" then
- setuplane()
- elseif tArgs[1] == "diglane" and tArgs[2] and tArgs[3] and tArgs[2] + 0 > -1 and tArgs[3] + 0 > -1 then
- diglane(tArgs[2] + 0, tArgs[3] + 0)
- elseif tArgs[1] == "refuelstation" and tArgs[2] then
- refuelStation(textutils.unserialize(tArgs[2]))
- else
- printUsage()
- end
- rednet.close("right")
- rednet.close("left")
- rednet.close("top")
- rednet.close("bottom")
- rednet.close("front")
- rednet.close("back")
- ENDTIME = os.clock()
- debug("Starttime:" .. STARTUPTIME)
- debug("Endtime: " .. ENDTIME)
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement