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
This commit is contained in:
blunty666 2016-12-04 19:40:35 +00:00
parent 72aef91397
commit 718c324bf3
2 changed files with 87 additions and 14 deletions

View File

@ -16,18 +16,27 @@ end
local position local position
local SESSION_MAX_DISTANCE_DEFAULT = 32
local SESSION_COORD_CLEAR = 1 local SESSION_COORD_CLEAR = 1
local SESSION_COORD_BLOCKED = 2 local SESSION_COORD_BLOCKED = 2
local UPDATE_COORD_CLEAR = -1 local UPDATE_COORD_CLEAR = -1
local UPDATE_COORD_BLOCKED = 1 local UPDATE_COORD_BLOCKED = 1
local sessionMidPoint
local sessionMaxDistance
local sessionMap local sessionMap
local serverMap local serverMap
local function distanceFunc(a, b) local function distanceFunc(a, b)
local sessionMapA, sessionMapB = sessionMap:get(a), sessionMap:get(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 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 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 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 end
blockInfo.checked = true blockInfo.checked = true
end 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 else
detectAll(currPos) detectAll(currPos)
end end
serverMap:check()
serverMap:pushUpdates()
end end
local function move(currPos, adjPos) local function move(currPos, adjPos)
@ -213,7 +235,9 @@ local function move(currPos, adjPos)
return false return false
end end
function goto(x, y, z) local exit = false
local function _goto(x, y, z, maxDistance)
exit = false
if not serverMap then if not serverMap then
error("serverMap has not been specified") error("serverMap has not been specified")
end end
@ -231,13 +255,16 @@ function goto(x, y, z)
serverMap:check() -- remove timed out data we have received from server serverMap:check() -- remove timed out data we have received from server
sessionMap = aStar.newMap() -- reset the sessionMap 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) local path = aStar.compute(distanceFunc, position, goal)
if not path then if not path then
return false, "no known path to goal" return false, "no known path to goal"
end end
while not aStar.vectorEquals(position, goal) do while not (exit or aStar.vectorEquals(position, goal)) do
local movePos = table.remove(path) local movePos = table.remove(path)
while not move(position, movePos) do while not move(position, movePos) do
local blockPresent, blockData = inspect(position, movePos) local blockPresent, blockData = inspect(position, movePos)
@ -257,8 +284,6 @@ function goto(x, y, z)
end end
if recalculate then if recalculate then
scan(position) scan(position)
serverMap:check()
serverMap:pushUpdates()
if sessionMap:get(goal) == SESSION_COORD_BLOCKED then return false, "goal is blocked" end if sessionMap:get(goal) == SESSION_COORD_BLOCKED then return false, "goal is blocked" end
path = aStar.compute(distanceFunc, position, goal) path = aStar.compute(distanceFunc, position, goal)
if not path then if not path then
@ -278,7 +303,28 @@ function goto(x, y, z)
serverMap:check() serverMap:check()
serverMap:pushUpdates(true) 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 end
function setMap(mapName, mapTimeout) function setMap(mapName, mapTimeout)

View File

@ -27,18 +27,15 @@ local MAIN_COORD_DISTANCE = 1024
local sessionMidPoint local sessionMidPoint
local sessionMaxDistance local sessionMaxDistance
local sessionMap local sessionMap
local mainMap 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 function distanceFunc(a, b)
local sessionMapA, sessionMapB = sessionMap:get(a), sessionMap:get(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 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 return SESSION_COORD_DISTANCE -- second coord is outside the search region
elseif sessionMapA == SESSION_COORD_BLOCKED or sessionMapB == SESSION_COORD_BLOCKED then 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 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 end
blockInfo.checked = true blockInfo.checked = true
end 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 else
detectAll(currPos) detectAll(currPos)
end end
@ -222,7 +230,7 @@ local function move(currPos, adjPos)
return false return false
end end
function goto(x, y, z, maxDistance) local function _goto(x, y, z, maxDistance)
if not mainMap then if not mainMap then
error("mainMap has not been specified") error("mainMap has not been specified")
end end
@ -240,12 +248,13 @@ function goto(x, y, z, maxDistance)
sessionMap = aStar.newMap() 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)) 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) local path = aStar.compute(distanceFunc, position, goal)
if not path then if not path then
return false, "no known path to goal" return false, "no known path to goal"
end end
while not aStar.vectorEquals(position, goal) do while not aStar.vectorEquals(position, goal) do
local movePos = table.remove(path) local movePos = table.remove(path)
while not move(position, movePos) do while not move(position, movePos) do
@ -281,9 +290,27 @@ function goto(x, y, z, maxDistance)
mainMap:set(movePos, MAIN_COORD_CLEAR) mainMap:set(movePos, MAIN_COORD_CLEAR)
end end
end end
mainMap:saveAll()
return true return true
end 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) function setMap(mapName)
if type(mapName) ~= "string" then if type(mapName) ~= "string" then
error("mapName must be string") error("mapName must be string")