mirror of
https://github.com/s1lentq/ReGameDLL_CS.git
synced 2024-12-28 07:35:40 +03:00
CNavArea::ComputeApproachAreas()
: fix hang on *.nav
generating (#913)
This commit is contained in:
parent
9f66264562
commit
c08e6d0180
@ -4431,6 +4431,7 @@ inline bool IsAreaVisible(const Vector *pos, const CNavArea *area)
|
|||||||
// Determine the set of "approach areas".
|
// Determine the set of "approach areas".
|
||||||
// An approach area is an area representing a place where players
|
// An approach area is an area representing a place where players
|
||||||
// move into/out of our local neighborhood of areas.
|
// move into/out of our local neighborhood of areas.
|
||||||
|
// @todo Optimize by search from eye outward and modifying pathfinder to treat all links as bi-directional
|
||||||
void CNavArea::ComputeApproachAreas()
|
void CNavArea::ComputeApproachAreas()
|
||||||
{
|
{
|
||||||
m_approachCount = 0;
|
m_approachCount = 0;
|
||||||
@ -4452,95 +4453,132 @@ void CNavArea::ComputeApproachAreas()
|
|||||||
enum { MAX_PATH_LENGTH = 256 };
|
enum { MAX_PATH_LENGTH = 256 };
|
||||||
CNavArea *path[MAX_PATH_LENGTH];
|
CNavArea *path[MAX_PATH_LENGTH];
|
||||||
|
|
||||||
// In order to enumerate all of the approach areas, we need to
|
enum SearchType
|
||||||
// run the algorithm many times, once for each "far away" area
|
|
||||||
// and keep the union of the approach area sets
|
|
||||||
for (auto farArea : goodSizedAreaList)
|
|
||||||
{
|
{
|
||||||
BlockedIDCount = 0;
|
FROM_EYE, ///< start search from our eyepoint outward to farArea
|
||||||
|
TO_EYE, ///< start search from farArea beack towards our eye
|
||||||
|
SEARCH_FINISHED
|
||||||
|
};
|
||||||
|
|
||||||
// if we can see 'farArea', try again - the whole point is to go "around the bend", so to speak
|
// In order to *completely* enumerate all of the approach areas, we
|
||||||
if (IsAreaVisible(&eye, farArea))
|
// need to search from our eyepoint outward, as well as from outwards
|
||||||
continue;
|
// towards our eyepoint
|
||||||
|
for (int searchType = FROM_EYE; searchType != SEARCH_FINISHED; searchType++)
|
||||||
// make first path to far away area
|
{
|
||||||
ApproachAreaCost cost;
|
// In order to enumerate all of the approach areas, we need to
|
||||||
if (NavAreaBuildPath(this, farArea, nullptr, cost) == false)
|
// run the algorithm many times, once for each "far away" area
|
||||||
continue;
|
// and keep the union of the approach area sets
|
||||||
|
for (auto farArea : goodSizedAreaList)
|
||||||
//
|
|
||||||
// Keep building paths to farArea and blocking them off until we
|
|
||||||
// cant path there any more.
|
|
||||||
// As areas are blocked off, all exits will be enumerated.
|
|
||||||
//
|
|
||||||
while (m_approachCount < MAX_APPROACH_AREAS)
|
|
||||||
{
|
{
|
||||||
// find number of areas on path
|
BlockedIDCount = 0;
|
||||||
int count = 0;
|
|
||||||
CNavArea *area;
|
|
||||||
for (area = farArea; area; area = area->GetParent())
|
|
||||||
count++;
|
|
||||||
|
|
||||||
if (count > MAX_PATH_LENGTH)
|
// if we can see 'farArea', try again - the whole point is to go "around the bend", so to speak
|
||||||
count = MAX_PATH_LENGTH;
|
if (IsAreaVisible(&eye, farArea))
|
||||||
|
continue;
|
||||||
|
|
||||||
// build path in correct order - from eye outwards
|
ApproachAreaCost cost;
|
||||||
int i = count;
|
|
||||||
for (area = farArea; i && area; area = area->GetParent())
|
//
|
||||||
|
// Keep building paths to farArea and blocking them off until we
|
||||||
|
// cant path there any more.
|
||||||
|
// As areas are blocked off, all exits will be enumerated.
|
||||||
|
//
|
||||||
|
while (m_approachCount < MAX_APPROACH_AREAS)
|
||||||
{
|
{
|
||||||
path[--i] = area;
|
CNavArea *from, *to;
|
||||||
}
|
|
||||||
|
|
||||||
// traverse path to find first area we cannot see (skip the first area)
|
if (searchType == FROM_EYE)
|
||||||
for (i = 1; i < count; i++)
|
|
||||||
{
|
|
||||||
// if we see this area, continue on
|
|
||||||
if (IsAreaVisible(&eye, path[i]))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
// we can't see this area.
|
|
||||||
// mark this area as "blocked" and unusable by subsequent approach paths
|
|
||||||
if (BlockedIDCount == MAX_BLOCKED_AREAS)
|
|
||||||
{
|
{
|
||||||
CONSOLE_ECHO("Overflow computing approach areas for area #%d.\n", m_id);
|
// find another path *to* 'farArea'
|
||||||
return;
|
// we must pathfind from us in order to pick up one-way paths OUT OF our area
|
||||||
|
from = this;
|
||||||
|
to = farArea;
|
||||||
|
}
|
||||||
|
else // TO_EYE
|
||||||
|
{
|
||||||
|
// find another path *from* 'farArea'
|
||||||
|
// we must pathfind to us in order to pick up one-way paths INTO our area
|
||||||
|
from = farArea;
|
||||||
|
to = this;
|
||||||
}
|
}
|
||||||
|
|
||||||
// if the area to be blocked is actually farArea, block the one just prior
|
// build the actual path
|
||||||
// (blocking farArea will cause all subsequent pathfinds to fail)
|
if (NavAreaBuildPath(from, to, NULL, cost) == false)
|
||||||
int block = (path[i] == farArea) ? i - 1 : i;
|
|
||||||
|
|
||||||
BlockedID[BlockedIDCount++] = path[block]->GetID();
|
|
||||||
|
|
||||||
if (block == 0)
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
// store new approach area if not already in set
|
// find number of areas on path
|
||||||
int a;
|
int count = 0;
|
||||||
for (a = 0; a < m_approachCount; a++)
|
CNavArea *area;
|
||||||
if (m_approach[a].here.area == path[block - 1])
|
for (area = to; area; area = area->GetParent())
|
||||||
break;
|
count++;
|
||||||
|
|
||||||
if (a == m_approachCount)
|
if (count > MAX_PATH_LENGTH)
|
||||||
|
count = MAX_PATH_LENGTH;
|
||||||
|
|
||||||
|
// if the path is only two areas long, there can be no approach points
|
||||||
|
if (count <= 2)
|
||||||
|
break;
|
||||||
|
|
||||||
|
// build path starting from eye
|
||||||
|
int i = 0;
|
||||||
|
|
||||||
|
if (searchType == FROM_EYE)
|
||||||
{
|
{
|
||||||
m_approach[m_approachCount].prev.area = (block >= 2) ? path[block-2] : nullptr;
|
for(area = to; i < count && area; area = area->GetParent())
|
||||||
m_approach[m_approachCount].here.area = path[block - 1];
|
{
|
||||||
m_approach[m_approachCount].prevToHereHow = path[block - 1]->GetParentHow();
|
path[count - i - 1] = area;
|
||||||
m_approach[m_approachCount].next.area = path[block];
|
++i;
|
||||||
m_approach[m_approachCount].hereToNextHow = path[block]->GetParentHow();
|
}
|
||||||
m_approachCount++;
|
}
|
||||||
|
else // TO_EYE
|
||||||
|
{
|
||||||
|
for(area = to; i < count && area; area = area->GetParent())
|
||||||
|
path[i++] = area;
|
||||||
}
|
}
|
||||||
|
|
||||||
// we are done with this path
|
// traverse path to find first area we cannot see (skip the first area)
|
||||||
break;
|
for (i = 1; i < count; i++)
|
||||||
}
|
{
|
||||||
|
// if we see this area, continue on
|
||||||
|
if (IsAreaVisible(&eye, path[i]))
|
||||||
|
continue;
|
||||||
|
|
||||||
// find another path to 'farArea'
|
// we can't see this area.
|
||||||
ApproachAreaCost cost;
|
// mark this area as "blocked" and unusable by subsequent approach paths
|
||||||
if (NavAreaBuildPath(this, farArea, nullptr, cost) == false)
|
if (BlockedIDCount == MAX_BLOCKED_AREAS)
|
||||||
{
|
{
|
||||||
// can't find a path to 'farArea' means all exits have been already tested and blocked
|
CONSOLE_ECHO("Overflow computing approach areas for area #%d.\n", m_id);
|
||||||
break;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// if the area to be blocked is actually farArea, block the one just prior
|
||||||
|
// (blocking farArea will cause all subsequent pathfinds to fail)
|
||||||
|
int block = (path[i] == farArea) ? i - 1 : i;
|
||||||
|
|
||||||
|
if (block == 0)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
BlockedID[BlockedIDCount++] = path[block]->GetID();
|
||||||
|
|
||||||
|
// store new approach area if not already in set
|
||||||
|
int a;
|
||||||
|
for (a = 0; a < m_approachCount; a++)
|
||||||
|
if (m_approach[a].here.area == path[block-1])
|
||||||
|
break;
|
||||||
|
|
||||||
|
if (a == m_approachCount)
|
||||||
|
{
|
||||||
|
m_approach[m_approachCount].prev.area = (block >= 2) ? path[block-2] : nullptr;
|
||||||
|
m_approach[m_approachCount].here.area = path[block - 1];
|
||||||
|
m_approach[m_approachCount].prevToHereHow = path[block - 1]->GetParentHow();
|
||||||
|
m_approach[m_approachCount].next.area = path[block];
|
||||||
|
m_approach[m_approachCount].hereToNextHow = path[block]->GetParentHow();
|
||||||
|
m_approachCount++;
|
||||||
|
}
|
||||||
|
|
||||||
|
// we are done with this path
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user