Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- if not turtle and not commands then
- error("The map scanner must be run with a turtle or command computer.", 0)
- end
- local args = {...}
- if #args ~= 2 and #args ~= 3 then
- print("Usage: mapscan <y-limit> <radius> <fill>")
- 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.")
- print("Radius is the horizontal distance from the start position the turtle will scan.")
- print("Fill should be 'fill' if you only want it to scan missing blocks.")
- return
- end
- local yLimit = tonumber(args[1])
- if not yLimit or yLimit <= 1 or yLimit > 256 then
- 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.")
- return
- end
- local radius = tonumber(args[2])
- if not radius or radius < 1 then
- print("Radius is the horizontal distance from the start position the turtle will scan.")
- return
- end
- local isFill = args[3] == "fill"
- if isFill then
- print("Scanning only missing blocks...")
- end
- local DAPPER_SCAN_DATA_CHANNEL = 4263
- local DAPPER_SCAN_ACKNOWLEDGE_CHANNEL = 4264
- local DAPPER_SCAN_NEXT_REQUEST_CHANNEL = 4265
- local DAPPER_SCAN_NEXT_REPLY_CHANNEL = 4266
- print("Dapper Mapper Scanner by oeed")
- local modem = peripheral.find("modem")
- if not modem or not modem.isWireless() then
- error("Please connect a wireless modem and re-run the program.", 0)
- end
- modem.open(DAPPER_SCAN_DATA_CHANNEL)
- modem.open(DAPPER_SCAN_ACKNOWLEDGE_CHANNEL)
- modem.open(DAPPER_SCAN_NEXT_REQUEST_CHANNEL)
- modem.open(DAPPER_SCAN_NEXT_REPLY_CHANNEL)
- os.setComputerLabel("Dapper Mapper Scanner")
- if turtle then
- print("WARNING: This program will use a TON of fuel. You should fill the ENTIRE turtle inventory with fuel if possible.")
- print("Press any key once fuel is loaded.")
- os.pullEvent("key")
- end
- local function location()
- local x, y, z = gps.locate(2)
- if not x or not y or not z then
- print("Unable to locate self using GPS... trying again in 5 seconds...")
- sleep(5)
- return location()
- end
- return x, y, z
- end
- local function checkFuel(amount)
- amount = amount or 1
- if turtle.getFuelLevel() < amount then
- local slot = 1
- repeat
- turtle.select(slot)
- slot = slot + 1
- until turtle.refuel(1) or slot > 16
- if turtle.getFuelLevel() < amount then
- print("Turtle is out of fuel, enter more and press any key.")
- os.pullEvent("key")
- return checkFuel()
- end
- end
- end
- local function toY(destY)
- local currX, currY, currZ = location()
- local diffY = destY - currY
- if diffY >= 1 then
- -- We need to go up
- checkFuel(diffY)
- for i = 1, diffY do
- turtle.up()
- end
- elseif diffY <= -1 then
- -- We need to go down
- checkFuel(math.abs(diffY))
- for i = -1, diffY, -1 do
- turtle.down()
- end
- end
- end
- local directions = {
- X_POS = 1,
- X_NEG = 2,
- Z_POS = 3,
- Z_NEG = 4,
- }
- local currentDirection
- local function toAxis(axis)
- if axis == "x" then
- if currentDirection == directions.X_POS then
- return 1
- elseif currentDirection == directions.X_NEG then
- return -1
- elseif currentDirection == directions.Z_NEG then
- turtle.turnRight()
- currentDirection = directions.X_POS
- return 1
- elseif currentDirection == directions.Z_POS then
- turtle.turnLeft()
- currentDirection = directions.X_POS
- return 1
- end
- elseif axis == "z" then
- if currentDirection == directions.Z_POS then
- return 1
- elseif currentDirection == directions.Z_NEG then
- return -1
- elseif currentDirection == directions.X_NEG then
- turtle.turnLeft()
- currentDirection = directions.Z_POS
- return 1
- elseif currentDirection == directions.X_POS then
- turtle.turnRight()
- currentDirection = directions.Z_POS
- return 1
- end
- end
- end
- local function toX(destX)
- local currX, currY, currZ = location()
- local diffX = (destX - currX) * toAxis("x")
- if diffX >= 1 then
- -- We need to go up
- checkFuel(diffX)
- for i = 1, diffX do
- turtle.forward()
- end
- elseif diffX <= -1 then
- -- We need to go down
- checkFuel(math.abs(diffX))
- for i = -1, diffX, -1 do
- turtle.back()
- end
- end
- end
- local function toZ(destZ)
- local currX, currY, currZ = location()
- local diffZ = (destZ - currZ) * toAxis("z")
- if diffZ >= 1 then
- -- We need to go up
- checkFuel(diffZ)
- for i = 1, diffZ do
- turtle.forward()
- end
- elseif diffZ <= -1 then
- -- We need to go down
- checkFuel(math.abs(diffZ))
- for i = -1, diffZ, -1 do
- turtle.back()
- end
- end
- end
- local unsentScans = {}
- local function sendScans()
- print("Sending " .. #unsentScans .. " scans...")
- modem.transmit(DAPPER_SCAN_DATA_CHANNEL, DAPPER_SCAN_ACKNOWLEDGE_CHANNEL, unsentScans)
- parallel.waitForAny(function()
- while #unsentScans > 0 do
- local event, side, senderChannel, replyChannel, message, distance = os.pullEvent("modem_message")
- if senderChannel == DAPPER_SCAN_ACKNOWLEDGE_CHANNEL and type(message) == "table" then
- for _, messageScan in ipairs(message) do
- -- loop through all our unsent scans and remove any with the same coordinates
- for i, scan in ipairs(unsentScans) do
- if messageScan.x == scan.x and messageScan.z == scan.z then
- unsentScans[i] = nil
- end
- end
- end
- end
- end
- end, function()
- sleep(1)
- end)
- end
- local function scanDown()
- local hit, block
- repeat
- checkFuel()
- turtle.down()
- hit, block = turtle.inspectDown()
- until hit
- local x, y, z = location()
- print("Found the block: " .. x .. ", " .. y .. ", " .. z)
- block.y = y
- table.insert(unsentScans, {x = x, z = z, block = block})
- sendScans()
- end
- local homeX, homeY, homeZ = location()
- if turtle then
- print("Determining direction...")
- checkFuel()
- turtle.forward()
- local newX, newY, newZ = location()
- print(newX, newY, newZ)
- print(homeX, homeY, homeZ )
- turtle.back()
- if newX > homeX then
- currentDirection = directions.X_POS
- elseif newX < homeX then
- currentDirection = directions.X_NEG
- elseif newZ > homeZ then
- currentDirection = directions.Z_POS
- elseif newZ < homeZ then
- currentDirection = directions.Z_NEG
- else
- error("Failed to determine turtle direction (it probably couldn't move forward).", 0)
- end
- end
- local xStart, xStop = homeX - radius, homeX + radius
- local zStart, zStop = homeZ - radius, homeZ + radius
- if turtle then
- toY(yLimit)
- if not isFill then
- for x = xStart, xStop, 1 do
- toX(x)
- for z = zStart, zStop, 1 do
- toZ(z)
- scanDown()
- toY(yLimit)
- end
- end
- else
- local nextX, nextZ
- repeat
- print("Requesting next block...")
- modem.transmit(DAPPER_SCAN_NEXT_REQUEST_CHANNEL, DAPPER_SCAN_NEXT_REPLY_CHANNEL, {
- xStart = xStart,
- xStop = xStop,
- zStart = zStart,
- zStop = zStop,
- })
- parallel.waitForAny(function()
- while true do
- local event, side, senderChannel, replyChannel, message, distance = os.pullEvent("modem_message")
- if senderChannel == DAPPER_SCAN_NEXT_REPLY_CHANNEL and type(message) == "table" then
- nextX = message.x
- nextZ = message.z
- break
- end
- end
- end, function()
- sleep(5)
- print("Timeout, going home.")
- nextX, nextZ = nil, nil
- end)
- if nextX and nextZ then
- toX(nextX)
- toZ(nextZ)
- scanDown()
- toY(yLimit)
- end
- until not nextX or not nextZ
- end
- print("Scan complete, returning home.")
- toX(homeX)
- toZ(homeZ)
- toY(homeY)
- else
- print("Scanning blocks...")
- local BLOCK_COUNT_LIMIT = 4096
- local xBlockCount, zBlockCount, yBlockCount = xStop - xStart + 1, zStop - zStart + 1, yLimit
- print("B count: " .. xBlockCount)
- local minSegmentCount = math.ceil((xBlockCount * zBlockCount * yBlockCount) / BLOCK_COUNT_LIMIT)
- local xSegmentSize = math.ceil(xBlockCount / math.sqrt(minSegmentCount))
- local xSegmentCount = math.ceil(xBlockCount / xSegmentSize)
- local zSegmentSize = math.floor(zBlockCount / math.ceil((minSegmentCount / xSegmentCount)))
- local zSegmentCount = math.ceil(zBlockCount / zSegmentSize)
- local totalSegmentCount = xSegmentCount * zSegmentCount
- local currentSegment = 1
- for xSegment = 0, xSegmentCount - 1 do
- local xSegmentStart = xStart + xSegment * xSegmentSize
- local xSegmentStop = math.min(xSegmentStart + xSegmentSize, xStop) - 1
- for zSegment = 0, zSegmentCount - 1 do
- local zSegmentStart = zStart + zSegment * zSegmentSize
- local zSegmentStop = math.min(zSegmentStart + zSegmentSize, zStop) - 1
- print("Scanning (" .. math.floor(100 * (currentSegment / totalSegmentCount) + 0.5) .. "%): X: " .. xSegmentStart .. ", Z: " .. zSegmentStart .. " - X:" .. xSegmentStop .. ", Z: " .. zSegmentStop)
- local xSize, zSize, ySize = xSegmentStop - xSegmentStart + 1, zSegmentStop - zSegmentStart + 1, yLimit
- local segmentBlocks = commands.getBlockInfos(xSegmentStart, 1, zSegmentStart, xSegmentStop, yLimit, zSegmentStop)
- for x = 1, xSize do
- for z = 0, zSize - 1 do
- for y = yLimit - 1, 0, -1 do
- local block = segmentBlocks[x + z * xSize + y * xSize * zSize]
- if block.name ~= "minecraft:air" then
- table.insert(unsentScans, {x = x + xSegmentStart - 1, z = z + zSegmentStart, block = block})
- break
- end
- end
- end
- end
- currentSegment = currentSegment + 1
- end
- end
- print("Scan complete, sending scans...")
- sendScans()
- print("Complete!")
- end
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement