Advertisement
Oeed

Dapper Map Scanner

Jun 24th, 2016
474
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 9.26 KB | None | 0 0
  1. if not turtle and not commands then
  2.     error("The map scanner must be run with a turtle or command computer.", 0)
  3. end
  4.  
  5. local args = {...}
  6. if #args ~= 2 and #args ~= 3 then
  7.     print("Usage: mapscan <y-limit> <radius> <fill>")
  8.     print("Y-Limit should be the maximum Y coordinate (1 - 256) that the turtle scans from. This should be just a bit above the height of the landscape.")
  9.     print("Radius is the horizontal distance from the start position the turtle will scan.")
  10.     print("Fill should be 'fill' if you only want it to scan missing blocks.")
  11.     return
  12. end
  13. local yLimit = tonumber(args[1])
  14. if not yLimit or yLimit <= 1 or yLimit > 256 then
  15.     print("Y-Limit should be the maximum Y coordinate (1 - 256) that the turtle scans from. This should be just a bit above the height of the landscape.")
  16.     return
  17. end
  18. local radius = tonumber(args[2])
  19. if not radius or radius < 1 then
  20.     print("Radius is the horizontal distance from the start position the turtle will scan.")
  21.     return
  22. end
  23. local isFill = args[3] == "fill"
  24. if isFill then
  25.     print("Scanning only missing blocks...")
  26. end
  27.  
  28. local DAPPER_SCAN_DATA_CHANNEL = 4263
  29. local DAPPER_SCAN_ACKNOWLEDGE_CHANNEL = 4264
  30. local DAPPER_SCAN_NEXT_REQUEST_CHANNEL = 4265
  31. local DAPPER_SCAN_NEXT_REPLY_CHANNEL = 4266
  32.  
  33. print("Dapper Mapper Scanner by oeed")
  34. local modem = peripheral.find("modem")
  35. if not modem or not modem.isWireless() then
  36.     error("Please connect a wireless modem and re-run the program.", 0)
  37. end
  38. modem.open(DAPPER_SCAN_DATA_CHANNEL)
  39. modem.open(DAPPER_SCAN_ACKNOWLEDGE_CHANNEL)
  40. modem.open(DAPPER_SCAN_NEXT_REQUEST_CHANNEL)
  41. modem.open(DAPPER_SCAN_NEXT_REPLY_CHANNEL)
  42.  
  43. os.setComputerLabel("Dapper Mapper Scanner")
  44. if turtle then
  45.     print("WARNING: This program will use a TON of fuel. You should fill the ENTIRE turtle inventory with fuel if possible.")
  46.     print("Press any key once fuel is loaded.")
  47.     os.pullEvent("key")
  48. end
  49.  
  50. local function location()
  51.     local x, y, z = gps.locate(2)
  52.     if not x or not y or not z then
  53.         print("Unable to locate self using GPS... trying again in 5 seconds...")
  54.         sleep(5)
  55.         return location()
  56.     end
  57.     return x, y, z
  58. end
  59.  
  60. local function checkFuel(amount)
  61.     amount = amount or 1
  62.     if turtle.getFuelLevel() < amount then
  63.         local slot = 1
  64.         repeat
  65.             turtle.select(slot)
  66.             slot = slot + 1
  67.         until turtle.refuel(1) or slot > 16
  68.         if turtle.getFuelLevel() < amount then
  69.             print("Turtle is out of fuel, enter more and press any key.")
  70.             os.pullEvent("key")
  71.             return checkFuel()
  72.         end
  73.     end
  74. end
  75.  
  76. local function toY(destY)
  77.     local currX, currY, currZ = location()
  78.     local diffY = destY - currY
  79.     if diffY >= 1 then
  80.         -- We need to go up
  81.         checkFuel(diffY)
  82.         for i = 1, diffY do
  83.             turtle.up()
  84.         end
  85.     elseif diffY <= -1 then
  86.         -- We need to go down
  87.         checkFuel(math.abs(diffY))
  88.         for i = -1, diffY, -1 do
  89.             turtle.down()
  90.         end
  91.     end
  92. end
  93.  
  94. local directions = {
  95.     X_POS = 1,
  96.     X_NEG = 2,
  97.     Z_POS = 3,
  98.     Z_NEG = 4,
  99. }
  100. local currentDirection
  101.  
  102. local function toAxis(axis)
  103.     if axis == "x" then
  104.         if currentDirection == directions.X_POS then
  105.             return 1
  106.         elseif currentDirection == directions.X_NEG then
  107.             return -1
  108.         elseif currentDirection == directions.Z_NEG then
  109.             turtle.turnRight()
  110.             currentDirection = directions.X_POS
  111.             return 1
  112.         elseif currentDirection == directions.Z_POS then
  113.             turtle.turnLeft()
  114.             currentDirection = directions.X_POS
  115.             return 1
  116.         end
  117.     elseif axis == "z" then
  118.         if currentDirection == directions.Z_POS then
  119.             return 1
  120.         elseif currentDirection == directions.Z_NEG then
  121.             return -1
  122.         elseif currentDirection == directions.X_NEG then
  123.             turtle.turnLeft()
  124.             currentDirection = directions.Z_POS
  125.             return 1
  126.         elseif currentDirection == directions.X_POS then
  127.             turtle.turnRight()
  128.             currentDirection = directions.Z_POS
  129.             return 1
  130.         end
  131.     end
  132. end
  133.  
  134. local function toX(destX)
  135.     local currX, currY, currZ = location()
  136.     local diffX = (destX - currX) * toAxis("x")
  137.     if diffX >= 1 then
  138.         -- We need to go up
  139.         checkFuel(diffX)
  140.         for i = 1, diffX do
  141.             turtle.forward()
  142.         end
  143.     elseif diffX <= -1 then
  144.         -- We need to go down
  145.         checkFuel(math.abs(diffX))
  146.         for i = -1, diffX, -1 do
  147.             turtle.back()
  148.         end
  149.     end
  150. end
  151.  
  152. local function toZ(destZ)
  153.     local currX, currY, currZ = location()
  154.     local diffZ = (destZ - currZ) * toAxis("z")
  155.     if diffZ >= 1 then
  156.         -- We need to go up
  157.         checkFuel(diffZ)
  158.         for i = 1, diffZ do
  159.             turtle.forward()
  160.         end
  161.     elseif diffZ <= -1 then
  162.         -- We need to go down
  163.         checkFuel(math.abs(diffZ))
  164.         for i = -1, diffZ, -1 do
  165.             turtle.back()
  166.         end
  167.     end
  168. end
  169.  
  170. local unsentScans = {}
  171.  
  172. local function sendScans()
  173.     print("Sending " .. #unsentScans .. " scans...")
  174.     modem.transmit(DAPPER_SCAN_DATA_CHANNEL, DAPPER_SCAN_ACKNOWLEDGE_CHANNEL, unsentScans)
  175.     parallel.waitForAny(function()
  176.         while #unsentScans > 0 do
  177.             local event, side, senderChannel, replyChannel, message, distance = os.pullEvent("modem_message")
  178.             if senderChannel == DAPPER_SCAN_ACKNOWLEDGE_CHANNEL and type(message) == "table" then
  179.                 for _, messageScan in ipairs(message) do
  180.                     -- loop through all our unsent scans and remove any with the same coordinates
  181.                     for i, scan in ipairs(unsentScans) do
  182.                         if messageScan.x == scan.x and messageScan.z == scan.z then
  183.                             unsentScans[i] = nil
  184.                         end
  185.                     end
  186.                 end
  187.             end
  188.         end
  189.     end, function()
  190.         sleep(1)
  191.     end)
  192. end
  193.  
  194. local function scanDown()
  195.     local hit, block
  196.     repeat
  197.         checkFuel()
  198.         turtle.down()
  199.         hit, block = turtle.inspectDown()  
  200.     until hit
  201.     local x, y, z = location()
  202.     print("Found the block: " .. x .. ", " .. y .. ", " .. z)
  203.     block.y = y
  204.     table.insert(unsentScans, {x = x, z = z, block = block})
  205.     sendScans()
  206. end
  207.  
  208. local homeX, homeY, homeZ = location()
  209. if turtle then
  210.     print("Determining direction...")
  211.     checkFuel()
  212.     turtle.forward()
  213.     local newX, newY, newZ = location()
  214.     print(newX, newY, newZ)
  215.     print(homeX, homeY, homeZ )
  216.     turtle.back()
  217.     if newX > homeX then
  218.         currentDirection = directions.X_POS
  219.     elseif newX < homeX then
  220.         currentDirection = directions.X_NEG
  221.     elseif newZ > homeZ then
  222.         currentDirection = directions.Z_POS
  223.     elseif newZ < homeZ then
  224.         currentDirection = directions.Z_NEG
  225.     else
  226.         error("Failed to determine turtle direction (it probably couldn't move forward).", 0)
  227.     end
  228. end
  229.  
  230.  
  231. local xStart, xStop = homeX - radius, homeX + radius
  232. local zStart, zStop = homeZ - radius, homeZ + radius
  233. if turtle then
  234.     toY(yLimit)
  235.     if not isFill then
  236.         for x = xStart, xStop, 1 do
  237.             toX(x)
  238.             for z = zStart, zStop, 1 do
  239.                 toZ(z)
  240.                 scanDown()
  241.                 toY(yLimit)
  242.             end
  243.         end
  244.     else
  245.         local nextX, nextZ
  246.         repeat
  247.             print("Requesting next block...")
  248.             modem.transmit(DAPPER_SCAN_NEXT_REQUEST_CHANNEL, DAPPER_SCAN_NEXT_REPLY_CHANNEL, {
  249.                 xStart = xStart,
  250.                 xStop = xStop,
  251.                 zStart = zStart,
  252.                 zStop = zStop,
  253.             })
  254.             parallel.waitForAny(function()
  255.                 while true do
  256.                     local event, side, senderChannel, replyChannel, message, distance = os.pullEvent("modem_message")
  257.                     if senderChannel == DAPPER_SCAN_NEXT_REPLY_CHANNEL and type(message) == "table" then
  258.                         nextX = message.x
  259.                         nextZ = message.z
  260.                         break
  261.                     end
  262.                 end
  263.             end, function()
  264.                 sleep(5)
  265.                 print("Timeout, going home.")
  266.                 nextX, nextZ = nil, nil
  267.             end)
  268.             if nextX and nextZ then
  269.                 toX(nextX)
  270.                 toZ(nextZ)
  271.                 scanDown()
  272.                 toY(yLimit)
  273.             end
  274.         until not nextX or not nextZ
  275.     end
  276.  
  277.     print("Scan complete, returning home.")
  278.     toX(homeX)
  279.     toZ(homeZ)
  280.     toY(homeY)
  281. else
  282.     print("Scanning blocks...")
  283.     local BLOCK_COUNT_LIMIT = 4096
  284.     local xBlockCount, zBlockCount, yBlockCount = xStop - xStart + 1, zStop - zStart + 1, yLimit
  285.     print("B count: " .. xBlockCount)
  286.     local minSegmentCount = math.ceil((xBlockCount * zBlockCount * yBlockCount) / BLOCK_COUNT_LIMIT)
  287.     local xSegmentSize = math.ceil(xBlockCount / math.sqrt(minSegmentCount))
  288.     local xSegmentCount = math.ceil(xBlockCount / xSegmentSize)
  289.     local zSegmentSize = math.floor(zBlockCount / math.ceil((minSegmentCount / xSegmentCount)))
  290.     local zSegmentCount = math.ceil(zBlockCount / zSegmentSize)
  291.     local totalSegmentCount = xSegmentCount * zSegmentCount
  292.     local currentSegment = 1
  293.     for xSegment = 0, xSegmentCount - 1 do
  294.         local xSegmentStart = xStart + xSegment * xSegmentSize
  295.         local xSegmentStop = math.min(xSegmentStart + xSegmentSize, xStop) - 1
  296.         for zSegment = 0, zSegmentCount - 1 do
  297.             local zSegmentStart = zStart + zSegment * zSegmentSize
  298.             local zSegmentStop = math.min(zSegmentStart + zSegmentSize, zStop) - 1
  299.             print("Scanning (" .. math.floor(100 * (currentSegment / totalSegmentCount) + 0.5) .. "%): X: " .. xSegmentStart .. ", Z: " .. zSegmentStart .. " - X:" .. xSegmentStop .. ", Z: " .. zSegmentStop)
  300.             local xSize, zSize, ySize = xSegmentStop - xSegmentStart + 1, zSegmentStop - zSegmentStart + 1, yLimit
  301.             local segmentBlocks = commands.getBlockInfos(xSegmentStart, 1, zSegmentStart, xSegmentStop, yLimit, zSegmentStop)
  302.             for x = 1, xSize do
  303.                 for z = 0, zSize - 1 do
  304.                     for y = yLimit - 1, 0, -1 do
  305.                         local block = segmentBlocks[x + z * xSize + y * xSize * zSize]
  306.                         if block.name ~= "minecraft:air" then
  307.                             table.insert(unsentScans, {x = x + xSegmentStart - 1, z = z + zSegmentStart, block = block})
  308.                             break
  309.                         end
  310.                     end
  311.                 end
  312.             end
  313.             currentSegment = currentSegment + 1
  314.         end
  315.     end
  316.     print("Scan complete, sending scans...")
  317.     sendScans()
  318.     print("Complete!")
  319. end
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement