diff --git a/netNav/netNav.lua b/netNav/netNav.lua index a48f505..1577b25 100644 --- a/netNav/netNav.lua +++ b/netNav/netNav.lua @@ -16,18 +16,27 @@ end local position +local SESSION_MAX_DISTANCE_DEFAULT = 32 + local SESSION_COORD_CLEAR = 1 local SESSION_COORD_BLOCKED = 2 local UPDATE_COORD_CLEAR = -1 local UPDATE_COORD_BLOCKED = 1 +local sessionMidPoint +local sessionMaxDistance + local sessionMap local serverMap local function distanceFunc(a, b) local sessionMapA, sessionMapB = sessionMap:get(a), sessionMap:get(b) - if sessionMapA == SESSION_COORD_BLOCKED or sessionMapB == SESSION_COORD_BLOCKED then + if aStar.distance(a, sessionMidPoint) > sessionMaxDistance then + return math.huge -- first coord is outside the search region + elseif aStar.distance(b, sessionMidPoint) > sessionMaxDistance then + return math.huge -- second coord is outside the search region + elseif sessionMapA == SESSION_COORD_BLOCKED or sessionMapB == SESSION_COORD_BLOCKED then return math.huge -- we have found one of these coords to be blocked during this session elseif sessionMapA == SESSION_COORD_CLEAR and sessionMapB == SESSION_COORD_CLEAR then return aStar.distance(a, b) -- we have found both of these coords to be clear during this session @@ -193,9 +202,22 @@ local function scan(currPos) end blockInfo.checked = true end + for _, blockInfo in ipairs(rawBlockInfo) do + local pos = currPos + vector.new(blockInfo.x, blockInfo.y, blockInfo.z) + local blockInfo = sortedBlockInfo:get(pos) + if not blockInfo.checked then + if blockInfo.type == "AIR" then + sessionMap:set(pos, SESSION_COORD_CLEAR) + else + sessionMap:set(pos, SESSION_COORD_BLOCKED) + end + end + end else detectAll(currPos) end + serverMap:check() + serverMap:pushUpdates() end local function move(currPos, adjPos) @@ -213,7 +235,9 @@ local function move(currPos, adjPos) return false end -function goto(x, y, z) +local exit = false +local function _goto(x, y, z, maxDistance) + exit = false if not serverMap then error("serverMap has not been specified") end @@ -231,13 +255,16 @@ function goto(x, y, z) serverMap:check() -- remove timed out data we have received from server sessionMap = aStar.newMap() -- reset the sessionMap + + sessionMidPoint = vector.new(math.floor((goal.x + position.x)/2), math.floor((goal.y + position.y)/2), math.floor((goal.z + position.z)/2)) + sessionMaxDistance = (type(maxDistance) == "number" and maxDistance) or math.max(2*aStar.distance(sessionMidPoint, goal), SESSION_MAX_DISTANCE_DEFAULT) local path = aStar.compute(distanceFunc, position, goal) if not path then return false, "no known path to goal" end - while not aStar.vectorEquals(position, goal) do + while not (exit or aStar.vectorEquals(position, goal)) do local movePos = table.remove(path) while not move(position, movePos) do local blockPresent, blockData = inspect(position, movePos) @@ -257,8 +284,6 @@ function goto(x, y, z) end if recalculate then scan(position) - serverMap:check() - serverMap:pushUpdates() if sessionMap:get(goal) == SESSION_COORD_BLOCKED then return false, "goal is blocked" end path = aStar.compute(distanceFunc, position, goal) if not path then @@ -278,7 +303,28 @@ function goto(x, y, z) serverMap:check() serverMap:pushUpdates(true) - return true + return aStar.vectorEquals(position, goal) +end + +local isRunning = false +function goto(...) + if isRunning then + return false, "already running" + end + isRunning = true + local passback = {pcall(_goto, ...)} + isRunning = false + if not passback[1] then + printError(passback[2]) + return false + end + return unpack(passback, 2) +end + +function stop() + if isRunning then + exit = true + end end function setMap(mapName, mapTimeout) diff --git a/starNav/starNav.lua b/starNav/starNav.lua index 12aa4ec..c25dbe3 100644 --- a/starNav/starNav.lua +++ b/starNav/starNav.lua @@ -27,18 +27,15 @@ local MAIN_COORD_DISTANCE = 1024 local sessionMidPoint local sessionMaxDistance + local sessionMap local mainMap -local function sup_norm(a, b) - return math.max(math.abs(a.x - b.x), math.abs(a.y - b.y), math.abs(a.z - b.z)) -end - local function distanceFunc(a, b) local sessionMapA, sessionMapB = sessionMap:get(a), sessionMap:get(b) - if sup_norm(a, sessionMidPoint) > sessionMaxDistance then + if aStar.distance(a, sessionMidPoint) > sessionMaxDistance then return SESSION_COORD_DISTANCE -- first coord is outside the search region - elseif sup_norm(b, sessionMidPoint) > sessionMaxDistance then + elseif aStar.distance(b, sessionMidPoint) > sessionMaxDistance then return SESSION_COORD_DISTANCE -- second coord is outside the search region elseif sessionMapA == SESSION_COORD_BLOCKED or sessionMapB == SESSION_COORD_BLOCKED then return SESSION_COORD_DISTANCE -- one of the coords has been found to be blocked this during this session @@ -201,6 +198,17 @@ local function scan(currPos) end blockInfo.checked = true end + for _, blockInfo in ipairs(rawBlockInfo) do + local pos = currPos + vector.new(blockInfo.x, blockInfo.y, blockInfo.z) + local blockInfo = sortedBlockInfo:get(pos) + if not blockInfo.checked then + if blockInfo.type == "AIR" then + sessionMap:set(pos, SESSION_COORD_CLEAR) + else + sessionMap:set(pos, SESSION_COORD_BLOCKED) + end + end + end else detectAll(currPos) end @@ -222,7 +230,7 @@ local function move(currPos, adjPos) return false end -function goto(x, y, z, maxDistance) +local function _goto(x, y, z, maxDistance) if not mainMap then error("mainMap has not been specified") end @@ -240,12 +248,13 @@ function goto(x, y, z, maxDistance) sessionMap = aStar.newMap() sessionMidPoint = vector.new(math.floor((goal.x + position.x)/2), math.floor((goal.y + position.y)/2), math.floor((goal.z + position.z)/2)) - sessionMaxDistance = (type(maxDistance) == "number" and maxDistance) or math.max(2*sup_norm(sessionMidPoint, goal), SESSION_MAX_DISTANCE_DEFAULT) + sessionMaxDistance = (type(maxDistance) == "number" and maxDistance) or math.max(2*aStar.distance(sessionMidPoint, goal), SESSION_MAX_DISTANCE_DEFAULT) local path = aStar.compute(distanceFunc, position, goal) if not path then return false, "no known path to goal" end + while not aStar.vectorEquals(position, goal) do local movePos = table.remove(path) while not move(position, movePos) do @@ -281,9 +290,27 @@ function goto(x, y, z, maxDistance) mainMap:set(movePos, MAIN_COORD_CLEAR) end end + + mainMap:saveAll() + return true end +local isRunning = false +function goto(...) + if isRunning then + return false, "already running" + end + isRunning = true + local passback = {pcall(_goto, ...)} + isRunning = false + if not passback[1] then + printError(passback[2]) + return false + end + return unpack(passback, 2) +end + function setMap(mapName) if type(mapName) ~= "string" then error("mapName must be string")