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 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)

View File

@ -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")