From 718c324bf3838991bd429caf1ce2ba258e7145e4 Mon Sep 17 00:00:00 2001 From: blunty666 Date: Sun, 4 Dec 2016 19:40:35 +0000 Subject: [PATCH] Features and fixtures Added ability to stop pathfinding whilst in the middle of running Prevented more than one instance of pathfinding being run at once Added search area bounds to netNav (already existed in starNav) Other minor fixes --- netNav/netNav.lua | 58 ++++++++++++++++++++++++++++++++++++++++----- starNav/starNav.lua | 43 ++++++++++++++++++++++++++------- 2 files changed, 87 insertions(+), 14 deletions(-) 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")