Advertisement
blunty666

netNav

Dec 23rd, 2015
130
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 7.73 KB | None | 0 0
  1. if not remoteMap then
  2.     if not os.loadAPI("remoteMap") then
  3.         error("could not load remoteMap API")
  4.     end
  5. end
  6. if not aStar then
  7.     if not os.loadAPI("aStar") then
  8.         error("could not load aStar API")
  9.     end
  10. end
  11. if not location then
  12.     if not os.loadAPI("location") then
  13.         error("could not load location API")
  14.     end
  15. end
  16.  
  17. local position
  18.  
  19. local SESSION_COORD_CLEAR = 1
  20. local SESSION_COORD_BLOCKED = 2
  21.  
  22. local UPDATE_COORD_CLEAR = -1
  23. local UPDATE_COORD_BLOCKED = 1
  24.  
  25. local sessionMap
  26. local serverMap
  27.  
  28. local function distanceFunc(a, b)
  29.     local sessionMapA, sessionMapB = sessionMap:get(a), sessionMap:get(b)
  30.     if sessionMapA == SESSION_COORD_BLOCKED or sessionMapB == SESSION_COORD_BLOCKED then
  31.         return math.huge -- we have found one of these coords to be blocked during this session
  32.     elseif sessionMapA == SESSION_COORD_CLEAR and sessionMapB == SESSION_COORD_CLEAR then
  33.         return aStar.distance(a, b) -- we have found both of these coords to be clear during this session
  34.     else
  35.         local serverMapA, serverMapB = serverMap:get(a), serverMap:get(b)
  36.         if serverMapA or serverMapB then
  37.             serverMapA = serverMapA and 2^(serverMapA + 1) or 1
  38.             serverMapB = serverMapB and 2^(serverMapB + 1) or 1
  39.             return math.max(serverMapA, serverMapB) -- the remote server map is indicating one of these coords may be blocked
  40.         end
  41.     end
  42.     return aStar.distance(a, b) -- we dont know anything useful so just calc the distance
  43. end
  44.  
  45. local directions = {
  46.     [vector.new(0, 0, 1)] = 0,
  47.     [vector.new(-1, 0, 0)] = 1,
  48.     [vector.new(0, 0, -1)] = 2,
  49.     [vector.new(1, 0, 0)] = 3,
  50.     [vector.new(0, 1, 0)] = 4,
  51.     [vector.new(0, -1, 0)] = 5,
  52. }
  53.  
  54. local function deltaToDirection(delta)
  55.     for vec, dir in pairs(directions) do
  56.         if aStar.vectorEquals(delta, vec) then
  57.             return dir
  58.         end
  59.     end
  60. end
  61.  
  62. local function tryMove()
  63.     for i = 1, 4 do
  64.         if turtle.forward() then
  65.             return true
  66.         end
  67.         turtle.turnRight()
  68.     end
  69.     return false
  70. end
  71.  
  72. local function findPosition()
  73.     local move = turtle.up
  74.     while not tryMove() do
  75.         if not move() then
  76.             if move == turtle.up then
  77.                 move = turtle.down
  78.                 move()
  79.             else
  80.                 error("trapped in a ridiculous place")
  81.             end
  82.         end
  83.     end
  84.    
  85.     local p1 = {gps.locate()}
  86.     if #p1 == 3 then
  87.         p1 = vector.new(unpack(p1))
  88.     else
  89.         error("no gps signal - phase 1")
  90.     end
  91.    
  92.     if not turtle.back() then
  93.         error("couldn't move to determine direction")
  94.     end
  95.    
  96.     local p2 = {gps.locate()}
  97.     if #p2 == 3 then
  98.         p2 = vector.new(unpack(p2))
  99.     else
  100.         error("no gps signal - phase 2")
  101.     end
  102.    
  103.     local direction = deltaToDirection(p1 - p2)
  104.     if direction and direction < 4 then
  105.         return location.new(p2.x, p2.y, p2.z, direction)
  106.     else
  107.         return false
  108.     end
  109. end
  110.  
  111. local function detect(currPos, adjPos)
  112.     local direction = deltaToDirection(adjPos - currPos)
  113.     if direction then
  114.         position:setHeading(direction)
  115.         if direction == 4 then
  116.             return turtle.detectUp()
  117.         elseif direction == 5 then
  118.             return turtle.detectDown()
  119.         else
  120.             return turtle.detect()
  121.         end
  122.     end
  123.     return false
  124. end
  125.  
  126. local function inspect(currPos, adjPos)
  127.     local direction = deltaToDirection(adjPos - currPos)
  128.     if direction then
  129.         position:setHeading(direction)
  130.         if direction == 4 then
  131.             return turtle.inspectUp()
  132.         elseif direction == 5 then
  133.             return turtle.inspectDown()
  134.         else
  135.             return turtle.inspect()
  136.         end
  137.     end
  138.     return false
  139. end
  140.  
  141. local function updateCoord(coord, isBlocked)
  142.     if isBlocked then
  143.         sessionMap:set(coord, SESSION_COORD_BLOCKED)
  144.         serverMap:set(coord, UPDATE_COORD_BLOCKED)
  145.     else
  146.         sessionMap:set(coord, SESSION_COORD_CLEAR)
  147.         serverMap:set(coord, UPDATE_COORD_CLEAR)
  148.     end
  149. end
  150.  
  151. local function detectAll(currPos)
  152.     for _, pos in ipairs(aStar.adjacent(currPos)) do -- better order of checking directions
  153.         updateCoord(pos, detect(currPos, pos))
  154.     end
  155. end
  156.  
  157. local function findSensor()
  158.     for _, side in ipairs(peripheral.getNames()) do
  159.         if peripheral.getType(side) == "turtlesensorenvironment" then
  160.             return side
  161.         end
  162.     end
  163.     return false
  164. end
  165.  
  166. local function scan(currPos)
  167.     local sensorSide = findSensor()
  168.     if sensorSide then
  169.         local rawBlockInfo = peripheral.call(sensorSide, "sonicScan")
  170.         local sortedBlockInfo = aStar.newMap()
  171.         for _, blockInfo in ipairs(rawBlockInfo) do
  172.             sortedBlockInfo:set(currPos + vector.new(blockInfo.x, blockInfo.y, blockInfo.z), blockInfo)
  173.         end
  174.         local toCheckQueue = {}
  175.         for _, pos in ipairs(aStar.adjacent(currPos)) do
  176.             if sortedBlockInfo:get(pos) then
  177.                 table.insert(toCheckQueue, pos)
  178.             end
  179.         end
  180.         while toCheckQueue[1] do
  181.             local pos = table.remove(toCheckQueue, 1)
  182.             local blockInfo = sortedBlockInfo:get(pos)
  183.             if blockInfo.type == "AIR" then
  184.                 for _, pos2 in ipairs(aStar.adjacent(pos)) do
  185.                     local blockInfo2 = sortedBlockInfo:get(pos2)
  186.                     if blockInfo2 and not blockInfo2.checked then
  187.                         table.insert(toCheckQueue, pos2)
  188.                     end
  189.                 end
  190.                 updateCoord(pos, false)
  191.             else
  192.                 updateCoord(pos, true)
  193.             end
  194.             blockInfo.checked = true
  195.         end
  196.     else
  197.         detectAll(currPos)
  198.     end
  199. end
  200.  
  201. local function move(currPos, adjPos)
  202.     local direction = deltaToDirection(adjPos - currPos)
  203.     if direction then
  204.         position:setHeading(direction)
  205.         if direction == 4 then
  206.             return position:up()
  207.         elseif direction == 5 then
  208.             return position:down()
  209.         else
  210.             return position:forward()
  211.         end
  212.     end
  213.     return false
  214. end
  215.  
  216. function goto(x, y, z)
  217.     if not serverMap then
  218.         error("serverMap has not been specified")
  219.     end
  220.     if turtle.getFuelLevel() == 0 then
  221.         return false, "ran out of fuel"
  222.     end
  223.     if not position then
  224.         position = findPosition()
  225.         if not position then
  226.             return false, "couldn't determine location"
  227.         end
  228.     end
  229.    
  230.     local goal = vector.new(tonumber(x), tonumber(y), tonumber(z))
  231.    
  232.     serverMap:check() -- remove timed out data we have received from server
  233.     sessionMap = aStar.newMap() -- reset the sessionMap
  234.    
  235.     local path = aStar.compute(distanceFunc, position, goal)
  236.     if not path then
  237.         return false, "no known path to goal"
  238.     end
  239.    
  240.     while not aStar.vectorEquals(position, goal) do
  241.         local movePos = table.remove(path)
  242.         while not move(position, movePos) do
  243.             local blockPresent, blockData = inspect(position, movePos)
  244.             local recalculate, isTurtle = false, false
  245.             if blockPresent and (blockData.name == "ComputerCraft:CC-TurtleAdvanced" or blockData.name == "ComputerCraft:CC-Turtle") then -- there is a turtle in the way
  246.                 sleep(math.random(0, 3))
  247.                 local blockPresent2, blockData2 = inspect(position, movePos)
  248.                 if blockPresent2 and (blockData2.name == "ComputerCraft:CC-TurtleAdvanced" or blockData2.name == "ComputerCraft:CC-Turtle") then -- the turtle is still there
  249.                     recalculate, isTurtle = true, true
  250.                 end
  251.             elseif blockPresent then
  252.                 recalculate = true
  253.             elseif turtle.getFuelLevel() == 0 then
  254.                 return false, "ran out of fuel"
  255.             else
  256.                 sleep(1)
  257.             end
  258.             if recalculate then
  259.                 scan(position)
  260.                 serverMap:check()
  261.                 serverMap:pushUpdates()
  262.                 if sessionMap:get(goal) == SESSION_COORD_BLOCKED then return false, "goal is blocked" end
  263.                 path = aStar.compute(distanceFunc, position, goal)
  264.                 if not path then
  265.                     return false, "no known path to goal"
  266.                 end
  267.                 if isTurtle then
  268.                     sessionMap:set(movePos, nil)
  269.                 end
  270.                 movePos = table.remove(path)
  271.             end
  272.         end
  273.         if serverMap:get(movePos) then
  274.             serverMap:set(movePos, UPDATE_COORD_CLEAR)
  275.         end
  276.     end
  277.    
  278.     serverMap:check()
  279.     serverMap:pushUpdates(true)
  280.    
  281.     return true
  282. end
  283.  
  284. function setMap(mapName, mapTimeout)
  285.     if type(mapName) ~= "string" then
  286.         error("mapName must be string")
  287.     end
  288.     if type(mapTimeout) ~= "number" or mapTimeout < 0 then
  289.         error("timeout must be positive number")
  290.     end
  291.     serverMap = remoteMap.new(mapName, mapTimeout)
  292. end
  293.  
  294. function getMap()
  295.     return serverMap
  296. end
  297.  
  298. function getPosition()
  299.     if position then
  300.         return position:value()
  301.     end
  302. end
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement