Skip to content

Commit 5febc14

Browse files
authored
fix(pathfinder): Implement robust forward insertion sort for PathfindCell::putOnSortedOpenList() (TheSuperHackers#2432)
1 parent 44b99c7 commit 5febc14

2 files changed

Lines changed: 66 additions & 10 deletions

File tree

Core/GameEngine/Include/GameLogic/AIPathfind.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -326,6 +326,14 @@ class PathfindCell
326326

327327
UnsignedInt costSoFar( PathfindCell *parent );
328328

329+
#if RETAIL_COMPATIBLE_PATHFINDING
330+
// Forward insertion sort that is 100% retail compatible
331+
void forwardInsertionSortRetailCompatible(PathfindCellList& list);
332+
#endif
333+
334+
// Forward insertion sort, in ascending cost order
335+
void forwardInsertionSort(PathfindCellList& list);
336+
329337
/// put self on "open" list in ascending cost order
330338
void putOnSortedOpenList( PathfindCellList &list );
331339

Core/GameEngine/Source/GameLogic/AI/AIPathfind.cpp

Lines changed: 58 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1680,8 +1680,9 @@ Bool PathfindCell::removeObstacle( Object *obstacle )
16801680
return true;
16811681
}
16821682

1683-
/// put self on "open" list in ascending cost order, return new list
1684-
void PathfindCell::putOnSortedOpenList( PathfindCellList &list )
1683+
#if RETAIL_COMPATIBLE_PATHFINDING
1684+
// Retail compatible insertion sort
1685+
void PathfindCell::forwardInsertionSortRetailCompatible(PathfindCellList& list)
16851686
{
16861687
DEBUG_ASSERTCRASH(m_info, ("Has to have info."));
16871688
DEBUG_ASSERTCRASH(m_info->m_closed == FALSE && m_info->m_open == FALSE, ("Serious error - Invalid flags. jba"));
@@ -1701,18 +1702,10 @@ void PathfindCell::putOnSortedOpenList( PathfindCellList &list )
17011702
// insertion sort
17021703
PathfindCell* currentCell = list.m_head;
17031704
PathfindCell* previousCell = nullptr;
1704-
#if RETAIL_COMPATIBLE_PATHFINDING
1705-
// TheSuperHackers @bugfix In the retail compatible pathfinding, on rare occasions, we get stuck in an infinite loop
1706-
// External code should pickup on the bad behaviour and cleanup properly, but we need to explicitly break out here
1707-
// The fixed pathfinding does not have this issue due to the proper cleanup of pathfindCells and their pathfindCellInfos
17081705
UnsignedInt cellCount = 0;
17091706
while (currentCell && cellCount < PATHFIND_CELLS_PER_FRAME && currentCell->m_info->m_totalCost <= m_info->m_totalCost)
17101707
{
17111708
cellCount++;
1712-
#else
1713-
while (currentCell && currentCell->m_info->m_totalCost <= m_info->m_totalCost)
1714-
{
1715-
#endif
17161709
previousCell = currentCell;
17171710
currentCell = currentCell->getNextOpen();
17181711
}
@@ -1739,6 +1732,61 @@ void PathfindCell::putOnSortedOpenList( PathfindCellList &list )
17391732
m_info->m_nextOpen = nullptr;
17401733
}
17411734
}
1735+
#endif
1736+
1737+
// Forward insertion sort, returns early if the list is being initialised or we are prepending the list
1738+
void PathfindCell::forwardInsertionSort(PathfindCellList& list)
1739+
{
1740+
DEBUG_ASSERTCRASH(m_info, ("Has to have info."));
1741+
DEBUG_ASSERTCRASH(m_info->m_closed == FALSE && m_info->m_open == FALSE, ("Serious error - Invalid flags. jba"));
1742+
1743+
// mark the new cell as being on the open list
1744+
m_info->m_open = true;
1745+
m_info->m_closed = false;
1746+
1747+
if (list.m_head == nullptr) {
1748+
m_info->m_prevOpen = nullptr;
1749+
m_info->m_nextOpen = nullptr;
1750+
list.m_head = this;
1751+
return;
1752+
}
1753+
1754+
// If the node needs inserting before the current list head
1755+
if (m_info->m_totalCost < list.m_head->m_info->m_totalCost) {
1756+
m_info->m_prevOpen = nullptr;
1757+
list.m_head->m_info->m_prevOpen = this->m_info;
1758+
m_info->m_nextOpen = list.m_head->m_info;
1759+
list.m_head = this;
1760+
return;
1761+
}
1762+
1763+
// Traverse the list to find correct position
1764+
PathfindCell* current = list.m_head;
1765+
while (current->m_info->m_nextOpen && current->m_info->m_nextOpen->m_totalCost <= m_info->m_totalCost) {
1766+
current = current->getNextOpen();
1767+
}
1768+
1769+
// Insert the new node in the correct position
1770+
m_info->m_nextOpen = current->m_info->m_nextOpen;
1771+
if (current->m_info->m_nextOpen != nullptr) {
1772+
current->m_info->m_nextOpen->m_prevOpen = this->m_info;
1773+
}
1774+
current->m_info->m_nextOpen = this->m_info;
1775+
m_info->m_prevOpen = current->m_info;
1776+
}
1777+
1778+
/// put self on "open" list in ascending cost order, return new list
1779+
void PathfindCell::putOnSortedOpenList( PathfindCellList &list )
1780+
{
1781+
#if RETAIL_COMPATIBLE_PATHFINDING
1782+
if (!s_useFixedPathfinding) {
1783+
forwardInsertionSortRetailCompatible(list);
1784+
return;
1785+
}
1786+
#endif
1787+
1788+
forwardInsertionSort(list);
1789+
}
17421790

17431791
/// remove self from "open" list
17441792
void PathfindCell::removeFromOpenList( PathfindCellList &list )

0 commit comments

Comments
 (0)