diff --git a/Generals/Code/GameEngine/Include/GameLogic/AIPathfind.h b/Generals/Code/GameEngine/Include/GameLogic/AIPathfind.h index d147c9650c5..e2c6cd32856 100644 --- a/Generals/Code/GameEngine/Include/GameLogic/AIPathfind.h +++ b/Generals/Code/GameEngine/Include/GameLogic/AIPathfind.h @@ -247,6 +247,24 @@ class PathfindCellInfo UnsignedInt m_closed:1; ///< place for marking this cell as on the closed list }; +// TheSuperHackers @info The PathfindCellList class acts as a new management class for the pathfindcell open and closed lists +class PathfindCellList +{ + friend class PathfindCell; + +public: + PathfindCellList() : m_head(nullptr) {} + + void reset(PathfindCell* newHead = nullptr) { m_head = newHead; } + + PathfindCell* getHead() const { return m_head; } + + Bool empty() const { return m_head == nullptr; } + +private: + PathfindCell* m_head; +}; + /** * This represents one cell in the pathfinding grid. * These cells categorize the world into idealized cellular states, @@ -307,23 +325,23 @@ class PathfindCell UnsignedInt costSoFar( PathfindCell *parent ); - /// put self on "open" list in ascending cost order, return new list - PathfindCell *putOnSortedOpenList( PathfindCell *list ); + /// put self on "open" list in ascending cost order + void putOnSortedOpenList( PathfindCellList &list ); /// remove self from "open" list - PathfindCell *removeFromOpenList( PathfindCell *list ); + void removeFromOpenList( PathfindCellList &list ); /// put self on "closed" list, return new list - PathfindCell *putOnClosedList( PathfindCell *list ); + void putOnClosedList( PathfindCellList &list ); /// remove self from "closed" list - PathfindCell *removeFromClosedList( PathfindCell *list ); + void removeFromClosedList( PathfindCellList &list ); /// remove all cells from closed list. - static Int releaseClosedList( PathfindCell *list ); + static Int releaseClosedList( PathfindCellList &list ); /// remove all cells from closed list. - static Int releaseOpenList( PathfindCell *list ); + static Int releaseOpenList( PathfindCellList &list ); inline PathfindCell *getNextOpen(void) {return m_info->m_nextOpen?m_info->m_nextOpen->m_cell: nullptr;} @@ -848,8 +866,8 @@ class Pathfinder : PathfindServicesInterface, public Snapshot IRegion2D m_extent; ///< Grid extent limits IRegion2D m_logicalExtent; ///< Logical grid extent limits - PathfindCell *m_openList; ///< Cells ready to be explored - PathfindCell *m_closedList; ///< Cells already explored + PathfindCellList m_openList; ///< Cells ready to be explored + PathfindCellList m_closedList; ///< Cells already explored Bool m_isMapReady; ///< True if all cells of map have been classified Bool m_isTunneling; ///< True if path started in an obstacle diff --git a/Generals/Code/GameEngine/Source/GameLogic/AI/AIPathfind.cpp b/Generals/Code/GameEngine/Source/GameLogic/AI/AIPathfind.cpp index 2e2dc8822cd..f74387efb0e 100644 --- a/Generals/Code/GameEngine/Source/GameLogic/AI/AIPathfind.cpp +++ b/Generals/Code/GameEngine/Source/GameLogic/AI/AIPathfind.cpp @@ -1117,8 +1117,8 @@ void Pathfinder::forceCleanCells() TheAudio->addAudioEvent(&TheAudio->getMiscAudio()->m_allCheerSound); PathfindCellInfo::forceCleanPathFindCellInfos(); - m_openList = nullptr; - m_closedList = nullptr; + m_openList.reset(); + m_closedList.reset(); for (int j = 0; j <= m_extent.hi.y; ++j) { for (int i = 0; i <= m_extent.hi.x; ++i) { @@ -1665,13 +1665,13 @@ void PathfindCell::removeObstacle( Object *obstacle ) } /// put self on "open" list in ascending cost order, return new list -PathfindCell *PathfindCell::putOnSortedOpenList( PathfindCell *list ) +void PathfindCell::putOnSortedOpenList( PathfindCellList &list ) { DEBUG_ASSERTCRASH(m_info, ("Has to have info.")); DEBUG_ASSERTCRASH(m_info->m_closed==FALSE && m_info->m_open==FALSE, ("Serious error - Invalid flags. jba")); - if (list == nullptr) + if (list.m_head == nullptr) { - list = this; + list.m_head = this; m_info->m_prevOpen = nullptr; m_info->m_nextOpen = nullptr; } @@ -1684,11 +1684,11 @@ PathfindCell *PathfindCell::putOnSortedOpenList( PathfindCell *list ) // External code should pickup on the bad behaviour and cleanup properly, but we need to explicitly break out here // The fixed pathfinding does not have this issue due to the proper cleanup of pathfindCells and their pathfindCellInfos UnsignedInt cellCount = 0; - for (c = list; c && cellCount < PATHFIND_CELLS_PER_FRAME; c = c->getNextOpen()) + for (c = list.m_head; c && cellCount < PATHFIND_CELLS_PER_FRAME; c = c->getNextOpen()) { cellCount++; #else - for (c = list; c; c = c->getNextOpen()) + for (c = list.m_head; c; c = c->getNextOpen()) { #endif if (c->m_info->m_totalCost > m_info->m_totalCost) @@ -1703,7 +1703,7 @@ PathfindCell *PathfindCell::putOnSortedOpenList( PathfindCell *list ) if (c->m_info->m_prevOpen) c->m_info->m_prevOpen->m_nextOpen = this->m_info; else - list = this; + list.m_head = this; m_info->m_prevOpen = c->m_info->m_prevOpen; c->m_info->m_prevOpen = this->m_info; @@ -1724,11 +1724,10 @@ PathfindCell *PathfindCell::putOnSortedOpenList( PathfindCell *list ) m_info->m_open = true; m_info->m_closed = false; - return list; } /// remove self from "open" list -PathfindCell *PathfindCell::removeFromOpenList( PathfindCell *list ) +void PathfindCell::removeFromOpenList( PathfindCellList &list ) { DEBUG_ASSERTCRASH(m_info, ("Has to have info.")); DEBUG_ASSERTCRASH(m_info->m_closed==FALSE && m_info->m_open==TRUE, ("Serious error - Invalid flags. jba")); @@ -1738,25 +1737,24 @@ PathfindCell *PathfindCell::removeFromOpenList( PathfindCell *list ) if (m_info->m_prevOpen) m_info->m_prevOpen->m_nextOpen = m_info->m_nextOpen; else - list = getNextOpen(); + list.m_head = getNextOpen(); m_info->m_open = false; m_info->m_nextOpen = nullptr; m_info->m_prevOpen = nullptr; - return list; } /// remove all cells from "open" list -Int PathfindCell::releaseOpenList( PathfindCell *list ) +Int PathfindCell::releaseOpenList( PathfindCellList &list ) { Int count = 0; - while (list) { + while (list.m_head) { count++; - DEBUG_ASSERTCRASH(list->m_info, ("Has to have info.")); - DEBUG_ASSERTCRASH(list->m_info->m_closed==FALSE && list->m_info->m_open==TRUE, ("Serious error - Invalid flags. jba")); - PathfindCell *cur = list; - PathfindCellInfo *curInfo = list->m_info; + DEBUG_ASSERTCRASH(list.m_head->m_info, ("Has to have info.")); + DEBUG_ASSERTCRASH(list.m_head->m_info->m_closed==FALSE && list.m_head->m_info->m_open==TRUE, ("Serious error - Invalid flags. jba")); + PathfindCell *cur = list.m_head; + PathfindCellInfo *curInfo = list.m_head->m_info; #if RETAIL_COMPATIBLE_PATHFINDING // TheSuperHackers @info This is only here to catch a crash point in the retail compatible pathfinding @@ -1770,9 +1768,9 @@ Int PathfindCell::releaseOpenList( PathfindCell *list ) #endif if (curInfo->m_nextOpen) { - list = curInfo->m_nextOpen->m_cell; + list.m_head = curInfo->m_nextOpen->m_cell; } else { - list = nullptr; + list.m_head = nullptr; } DEBUG_ASSERTCRASH(cur == curInfo->m_cell, ("Bad backpointer in PathfindCellInfo")); curInfo->m_nextOpen = nullptr; @@ -1784,15 +1782,15 @@ Int PathfindCell::releaseOpenList( PathfindCell *list ) } /// remove all cells from "closed" list -Int PathfindCell::releaseClosedList( PathfindCell *list ) +Int PathfindCell::releaseClosedList( PathfindCellList &list ) { Int count = 0; - while (list) { + while (list.m_head) { count++; - DEBUG_ASSERTCRASH(list->m_info, ("Has to have info.")); - DEBUG_ASSERTCRASH(list->m_info->m_closed==TRUE && list->m_info->m_open==FALSE, ("Serious error - Invalid flags. jba")); - PathfindCell *cur = list; - PathfindCellInfo *curInfo = list->m_info; + DEBUG_ASSERTCRASH(list.m_head->m_info, ("Has to have info.")); + DEBUG_ASSERTCRASH(list.m_head->m_info->m_closed==TRUE && list.m_head->m_info->m_open==FALSE, ("Serious error - Invalid flags. jba")); + PathfindCell *cur = list.m_head; + PathfindCellInfo *curInfo = list.m_head->m_info; #if RETAIL_COMPATIBLE_PATHFINDING // TheSuperHackers @info This is only here to catch a crash point in the retail compatible pathfinding // One crash mode is where a cell has no PathfindCellInfo, resulting in a nullptr access and a crash. @@ -1805,9 +1803,9 @@ Int PathfindCell::releaseClosedList( PathfindCell *list ) #endif if (curInfo->m_nextOpen) { - list = curInfo->m_nextOpen->m_cell; + list.m_head = curInfo->m_nextOpen->m_cell; } else { - list = nullptr; + list.m_head = nullptr; } DEBUG_ASSERTCRASH(cur == curInfo->m_cell, ("Bad backpointer in PathfindCellInfo")); curInfo->m_nextOpen = nullptr; @@ -1819,7 +1817,7 @@ Int PathfindCell::releaseClosedList( PathfindCell *list ) } /// put self on "closed" list, return new list -PathfindCell *PathfindCell::putOnClosedList( PathfindCell *list ) +void PathfindCell::putOnClosedList( PathfindCellList &list ) { DEBUG_ASSERTCRASH(m_info, ("Has to have info.")); DEBUG_ASSERTCRASH(m_info->m_closed==FALSE && m_info->m_open==FALSE, ("Serious error - Invalid flags. jba")); @@ -1830,18 +1828,17 @@ PathfindCell *PathfindCell::putOnClosedList( PathfindCell *list ) m_info->m_closed = TRUE; m_info->m_prevOpen = nullptr; - m_info->m_nextOpen = list?list->m_info:nullptr; - if (list) - list->m_info->m_prevOpen = this->m_info; + m_info->m_nextOpen = list.m_head ? list.m_head->m_info : nullptr; + if (list.m_head) + list.m_head->m_info->m_prevOpen = this->m_info; - list = this; + list.m_head = this; } - return list; } /// remove self from "closed" list -PathfindCell *PathfindCell::removeFromClosedList( PathfindCell *list ) +void PathfindCell::removeFromClosedList( PathfindCellList &list ) { DEBUG_ASSERTCRASH(m_info, ("Has to have info.")); DEBUG_ASSERTCRASH(m_info->m_closed==TRUE && m_info->m_open==FALSE, ("Serious error - Invalid flags. jba")); @@ -1851,13 +1848,12 @@ PathfindCell *PathfindCell::removeFromClosedList( PathfindCell *list ) if (m_info->m_prevOpen) m_info->m_prevOpen->m_nextOpen = m_info->m_nextOpen; else - list = getNextOpen(); + list.m_head = getNextOpen(); m_info->m_closed = false; m_info->m_nextOpen = nullptr; m_info->m_prevOpen = nullptr; - return list; } /** @@ -3654,8 +3650,8 @@ void Pathfinder::reset( void ) // reset the pathfind grid m_extent.lo.x=m_extent.lo.y=m_extent.hi.x=m_extent.hi.y=0; m_logicalExtent.lo.x=m_logicalExtent.lo.y=m_logicalExtent.hi.x=m_logicalExtent.hi.y=0; - m_openList = nullptr; - m_closedList = nullptr; + m_openList.reset(); + m_closedList.reset(); m_ignoreObstacleID = INVALID_ID; m_isTunneling = false; @@ -4351,7 +4347,7 @@ void Pathfinder::debugShowSearch( Bool pathFound ) addIcon(nullptr, 0, 0, color); // erase. } - for( s = m_openList; s; s=s->getNextOpen() ) + for( s = m_openList.getHead(); s; s=s->getNextOpen() ) { // create objects to show path - they decay RGBColor color; @@ -4365,7 +4361,7 @@ void Pathfinder::debugShowSearch( Bool pathFound ) addIcon(&pos, PATHFIND_CELL_SIZE_F*.6f, 200, color); } - for( s = m_closedList; s; s=s->getNextOpen() ) + for( s = m_closedList.getHead(); s; s=s->getNextOpen() ) { // create objects to show path - they decay RGBColor color; @@ -4454,9 +4450,9 @@ Bool Pathfinder::validMovementTerrain( PathfindLayerEnum layer, const Locomotor* // void Pathfinder::cleanOpenAndClosedLists(void) { Int count = 0; - if (m_openList) { + if (!m_openList.empty()) { count += PathfindCell::releaseOpenList(m_openList); - m_openList = nullptr; + m_openList.reset(); } #if RETAIL_COMPATIBLE_PATHFINDING @@ -4469,9 +4465,9 @@ void Pathfinder::cleanOpenAndClosedLists(void) { } #endif - if (m_closedList) { + if (!m_closedList.empty()) { count += PathfindCell::releaseClosedList(m_closedList); - m_closedList = nullptr; + m_closedList.reset(); } #if RETAIL_COMPATIBLE_PATHFINDING @@ -5579,7 +5575,7 @@ void Pathfinder::checkChangeLayers(PathfindCell *parentCell) newCell->setCostSoFar(parentCell->getCostSoFar()); // same as parent cost newCell->setTotalCost(parentCell->getTotalCost()); // insert newCell in open list such that open list is sorted, smallest total path cost first - m_openList = newCell->putOnSortedOpenList( m_openList ); + newCell->putOnSortedOpenList( m_openList ); } bool Pathfinder::checkCellOutsideExtents(ICoord2D& cell) { @@ -5678,14 +5674,14 @@ struct ExamineCellsStruct // if to was on closed list, remove it from the list if (to->getClosed()) - d->thePathfinder->m_closedList = to->removeFromClosedList( d->thePathfinder->m_closedList ); + to->removeFromClosedList( d->thePathfinder->m_closedList ); // if the to was already on the open list, remove it so it can be re-inserted in order if (to->getOpen()) - d->thePathfinder->m_openList = to->removeFromOpenList( d->thePathfinder->m_openList ); + to->removeFromOpenList( d->thePathfinder->m_openList ); // insert to in open list such that open list is sorted, smallest total path cost first - d->thePathfinder->m_openList = to->putOnSortedOpenList( d->thePathfinder->m_openList ); + to->putOnSortedOpenList( d->thePathfinder->m_openList ); } return 0; // keep going @@ -5912,14 +5908,14 @@ Int Pathfinder::examineNeighboringCells(PathfindCell *parentCell, PathfindCell * // if newCell was on closed list, remove it from the list if (newCell->getClosed()) - m_closedList = newCell->removeFromClosedList( m_closedList ); + newCell->removeFromClosedList( m_closedList ); // if the newCell was already on the open list, remove it so it can be re-inserted in order if (newCell->getOpen()) - m_openList = newCell->removeFromOpenList( m_openList ); + newCell->removeFromOpenList( m_openList ); // insert newCell in open list such that open list is sorted, smallest total path cost first - m_openList = newCell->putOnSortedOpenList( m_openList ); + newCell->putOnSortedOpenList( m_openList ); } return cellCount; } @@ -5985,7 +5981,7 @@ Path *Pathfinder::internalFindPath( Object *obj, const LocomotorSet& locomotorSe DEBUG_LOG(("Attempting pathfind to 0,0, generally a bug.")); return nullptr; } - DEBUG_ASSERTCRASH(m_openList== nullptr && m_closedList == nullptr, ("Dangling lists.")); + DEBUG_ASSERTCRASH(m_openList.empty() && m_closedList.empty(), ("Dangling lists.")); if (m_isMapReady == false) { return nullptr; } @@ -6097,10 +6093,19 @@ Path *Pathfinder::internalFindPath( Object *obj, const LocomotorSet& locomotorSe parentCell->startPathfind(goalCell); // initialize "open" list to contain start cell - m_openList = parentCell; +#if RETAIL_COMPATIBLE_PATHFINDING + if (!s_useFixedPathfinding) { + m_openList.reset(parentCell); + } + else +#endif + { + m_openList.reset(); + parentCell->putOnSortedOpenList(m_openList); + } // "closed" list is initially empty - m_closedList = nullptr; + m_closedList.reset(); Int cellCount = 0; @@ -6108,11 +6113,11 @@ Path *Pathfinder::internalFindPath( Object *obj, const LocomotorSet& locomotorSe // Continue search until "open" list is empty, or // until goal is found. // - while( m_openList != nullptr ) + while( !m_openList.empty() ) { // take head cell off of open list - it has lowest estimated total path cost - parentCell = m_openList; - m_openList = parentCell->removeFromOpenList(m_openList); + parentCell = m_openList.getHead(); + parentCell->removeFromOpenList(m_openList); if (parentCell == goalCell) { @@ -6155,7 +6160,7 @@ Path *Pathfinder::internalFindPath( Object *obj, const LocomotorSet& locomotorSe } // put parent cell onto closed list - its evaluation is finished - m_closedList = parentCell->putOnClosedList( m_closedList ); + parentCell->putOnClosedList( m_closedList ); // Check to see if we can change layers in this cell. checkChangeLayers(parentCell); @@ -6491,7 +6496,7 @@ struct GroundCellsStruct to->setTotalCost(to->getCostSoFar() + costRemaining) ; // insert to in open list such that open list is sorted, smallest total path cost first - d->thePathfinder->m_openList = to->putOnSortedOpenList( d->thePathfinder->m_openList ); + to->putOnSortedOpenList( d->thePathfinder->m_openList ); } return 0; // keep going @@ -6527,7 +6532,7 @@ Path *Pathfinder::findGroundPath( const Coord3D *from, DEBUG_LOG(("Attempting pathfind to 0,0, generally a bug.")); return nullptr; } - DEBUG_ASSERTCRASH(m_openList== nullptr && m_closedList == nullptr, ("Dangling lists.")); + DEBUG_ASSERTCRASH(m_openList.empty() && m_closedList.empty(), ("Dangling lists.")); if (m_isMapReady == false) { return nullptr; } @@ -6620,10 +6625,19 @@ Path *Pathfinder::findGroundPath( const Coord3D *from, parentCell->startPathfind(goalCell); // initialize "open" list to contain start cell - m_openList = parentCell; +#if RETAIL_COMPATIBLE_PATHFINDING + if (!s_useFixedPathfinding) { + m_openList.reset(parentCell); + } + else +#endif + { + m_openList.reset(); + parentCell->putOnSortedOpenList(m_openList); + } // "closed" list is initially empty - m_closedList = nullptr; + m_closedList.reset(); // TheSuperHackers @fix helmutbuhler This was originally uninitialized and in the loop below. #if RETAIL_COMPATIBLE_CRC @@ -6635,11 +6649,11 @@ Path *Pathfinder::findGroundPath( const Coord3D *from, // until goal is found. // Int cellCount = 0; - while( m_openList != nullptr ) + while( !m_openList.empty() ) { // take head cell off of open list - it has lowest estimated total path cost - parentCell = m_openList; - m_openList = parentCell->removeFromOpenList(m_openList); + parentCell = m_openList.getHead(); + parentCell->removeFromOpenList(m_openList); if (parentCell == goalCell) { @@ -6672,7 +6686,7 @@ Path *Pathfinder::findGroundPath( const Coord3D *from, } // put parent cell onto closed list - its evaluation is finished - m_closedList = parentCell->putOnClosedList( m_closedList ); + parentCell->putOnClosedList( m_closedList ); // Check to see if we can change layers in this cell. checkChangeLayers(parentCell); @@ -6807,14 +6821,14 @@ Path *Pathfinder::findGroundPath( const Coord3D *from, // if newCell was on closed list, remove it from the list if (newCell->getClosed()) - m_closedList = newCell->removeFromClosedList( m_closedList ); + newCell->removeFromClosedList( m_closedList ); // if the newCell was already on the open list, remove it so it can be re-inserted in order if (newCell->getOpen()) - m_openList = newCell->removeFromOpenList( m_openList ); + newCell->removeFromOpenList( m_openList ); // insert newCell in open list such that open list is sorted, smallest total path cost first - m_openList = newCell->putOnSortedOpenList( m_openList ); + newCell->putOnSortedOpenList( m_openList ); } } // failure - goal cannot be reached @@ -6932,14 +6946,14 @@ void Pathfinder::processHierarchicalCell( const ICoord2D &scanCell, const ICoord if (!s_useFixedPathfinding) { if (!newCell->getClosed() && !newCell->getOpen()) { - m_closedList = newCell->putOnClosedList(m_closedList); + newCell->putOnClosedList(m_closedList); } } else #endif { if (newCell->hasInfo() && !newCell->getClosed() && !newCell->getOpen()) { - m_closedList = newCell->putOnClosedList(m_closedList); + newCell->putOnClosedList(m_closedList); } } @@ -6958,7 +6972,7 @@ void Pathfinder::processHierarchicalCell( const ICoord2D &scanCell, const ICoord adjNewCell->setTotalCost(adjNewCell->getCostSoFar()+remCost); adjNewCell->setParentCellHierarchical(parentCell); // insert newCell in open list such that open list is sorted, smallest total path cost first - m_openList = adjNewCell->putOnSortedOpenList( m_openList ); + adjNewCell->putOnSortedOpenList( m_openList ); } } @@ -7003,7 +7017,7 @@ Path *Pathfinder::internal_findHierarchicalPath( Bool isHuman, const LocomotorSu DEBUG_LOG(("Attempting pathfind to 0,0, generally a bug.")); return nullptr; } - DEBUG_ASSERTCRASH(m_openList== nullptr && m_closedList == nullptr, ("Dangling lists.")); + DEBUG_ASSERTCRASH(m_openList.empty() && m_closedList.empty(), ("Dangling lists.")); if (m_isMapReady == false) { return nullptr; } @@ -7060,7 +7074,7 @@ Path *Pathfinder::internal_findHierarchicalPath( Bool isHuman, const LocomotorSu parentCell->startPathfind(goalCell); // "closed" list is initially empty - m_closedList = nullptr; + m_closedList.reset(); Int cellCount = 0; @@ -7079,7 +7093,16 @@ Path *Pathfinder::internal_findHierarchicalPath( Bool isHuman, const LocomotorSu } // initialize "open" list to contain start cell - m_openList = parentCell; +#if RETAIL_COMPATIBLE_PATHFINDING + if (!s_useFixedPathfinding) { + m_openList.reset(parentCell); + } + else +#endif + { + m_openList.reset(); + parentCell->putOnSortedOpenList(m_openList); + } if (parentCell->getLayer()!=LAYER_GROUND) { PathfindLayerEnum layer = parentCell->getLayer(); @@ -7092,8 +7115,8 @@ Path *Pathfinder::internal_findHierarchicalPath( Bool isHuman, const LocomotorSu PathfindCell *startCell = getCell(LAYER_GROUND, ndx.x, ndx.y); if (cell && startCell) { // Close parent cell; - m_openList = parentCell->removeFromOpenList(m_openList); - m_closedList = parentCell->putOnClosedList(m_closedList); + parentCell->removeFromOpenList(m_openList); + parentCell->putOnClosedList(m_closedList); if (!startCell->allocateInfo(ndx)) { // TheSuperHackers @info We need to forcefully cleanup dangling pathfinding cells if this failure condition is hit in retail // Retail clients will crash beyond this point, but we attempt to recover by performing a full cleanup then enabling the fixed pathfinding codepath @@ -7118,7 +7141,7 @@ Path *Pathfinder::internal_findHierarchicalPath( Bool isHuman, const LocomotorSu startCell->setTotalCost(remCost); startCell->setParentCellHierarchical(parentCell); // insert newCell in open list such that open list is sorted, smallest total path cost first - m_openList = startCell->putOnSortedOpenList( m_openList ); + startCell->putOnSortedOpenList( m_openList ); cellCount++; if(!cell->allocateInfo(toNdx)) { @@ -7143,7 +7166,7 @@ Path *Pathfinder::internal_findHierarchicalPath( Bool isHuman, const LocomotorSu cell->setTotalCost(remCost); cell->setParentCellHierarchical(parentCell); // insert newCell in open list such that open list is sorted, smallest total path cost first - m_openList = cell->putOnSortedOpenList( m_openList ); + cell->putOnSortedOpenList( m_openList ); } } @@ -7154,11 +7177,11 @@ Path *Pathfinder::internal_findHierarchicalPath( Bool isHuman, const LocomotorSu // Continue search until "open" list is empty, or // until goal is found. // - while( m_openList != nullptr ) + while( !m_openList.empty() ) { // take head cell off of open list - it has lowest estimated total path cost - parentCell = m_openList; - m_openList = parentCell->removeFromOpenList(m_openList); + parentCell = m_openList.getHead(); + parentCell->removeFromOpenList(m_openList); zoneStorageType parentZone; if (parentCell->getLayer()==LAYER_GROUND) { @@ -7242,7 +7265,7 @@ Path *Pathfinder::internal_findHierarchicalPath( Bool isHuman, const LocomotorSu } startCell->setParentCellHierarchical(parentCell); if (!startCell->getClosed() && !startCell->getOpen()) { - m_closedList = startCell->putOnClosedList(m_closedList); + startCell->putOnClosedList(m_closedList); } } if(!cell->allocateInfo(toNdx)) { @@ -7271,7 +7294,7 @@ Path *Pathfinder::internal_findHierarchicalPath( Bool isHuman, const LocomotorSu cell->setTotalCost(cell->getCostSoFar()+remCost); cell->setParentCellHierarchical(startCell); // insert newCell in open list such that open list is sorted, smallest total path cost first - m_openList = cell->putOnSortedOpenList( m_openList ); + cell->putOnSortedOpenList( m_openList ); } } @@ -7340,7 +7363,7 @@ Path *Pathfinder::internal_findHierarchicalPath( Bool isHuman, const LocomotorSu } // put parent cell onto closed list - its evaluation is finished - m_closedList = parentCell->putOnClosedList( m_closedList ); + parentCell->putOnClosedList( m_closedList ); Int i; zoneStorageType examinedZones[PathfindZoneManager::ZONE_BLOCK_SIZE]; @@ -7711,7 +7734,7 @@ Bool Pathfinder::pathDestination( Object *obj, const LocomotorSet& locomotorSet Coord3D adjustTo = *groupDest; Coord3D *to = &adjustTo; - DEBUG_ASSERTCRASH(m_openList== nullptr && m_closedList == nullptr, ("Dangling lists.")); + DEBUG_ASSERTCRASH(m_openList.empty() && m_closedList.empty(), ("Dangling lists.")); // create unique "mark" values for open and closed cells for this pathfind invocation Bool isCrusher = obj ? obj->getCrusherLevel() > 0 : false; @@ -7774,24 +7797,33 @@ Bool Pathfinder::pathDestination( Object *obj, const LocomotorSet& locomotorSet parentCell->startPathfind(goalCell); // initialize "open" list to contain start cell - m_openList = parentCell; +#if RETAIL_COMPATIBLE_PATHFINDING + if (!s_useFixedPathfinding) { + m_openList.reset(parentCell); + } + else +#endif + { + m_openList.reset(); + parentCell->putOnSortedOpenList(m_openList); + } // "closed" list is initially empty - m_closedList = nullptr; + m_closedList.reset(); // // Continue search until "open" list is empty, or // until goal is found. // - while( m_openList != nullptr ) + while( !m_openList.empty() ) { // take head cell off of open list - it has lowest estimated total path cost - parentCell = m_openList; - m_openList = parentCell->removeFromOpenList(m_openList); + parentCell = m_openList.getHead(); + parentCell->removeFromOpenList(m_openList); Coord3D pos; // put parent cell onto closed list - its evaluation is finished - m_closedList = parentCell->putOnClosedList( m_closedList ); + parentCell->putOnClosedList( m_closedList ); if (checkForAdjust(obj, locomotorSet, isHuman, parentCell->getXIndex(), parentCell->getYIndex(), parentCell->getLayer(), radius, center, &pos, groupDest)) { Int dx = IABS(goalCell->getXIndex()-parentCell->getXIndex()); @@ -7908,14 +7940,14 @@ Bool Pathfinder::pathDestination( Object *obj, const LocomotorSet& locomotorSet // if newCell was on closed list, remove it from the list if (newCell->getClosed()) - m_closedList = newCell->removeFromClosedList( m_closedList ); + newCell->removeFromClosedList( m_closedList ); // if the newCell was already on the open list, remove it so it can be re-inserted in order if (newCell->getOpen()) - m_openList = newCell->removeFromOpenList( m_openList ); + newCell->removeFromOpenList( m_openList ); // insert newCell in open list such that open list is sorted, smallest total path cost first - m_openList = newCell->putOnSortedOpenList( m_openList ); + newCell->putOnSortedOpenList( m_openList ); } } @@ -8005,7 +8037,7 @@ Int Pathfinder::checkPathCost(Object *obj, const LocomotorSet& locomotorSet, con Coord3D adjustTo = *rawTo; Coord3D *to = &adjustTo; - DEBUG_ASSERTCRASH(m_openList== nullptr && m_closedList == nullptr, ("Dangling lists.")); + DEBUG_ASSERTCRASH(m_openList.empty() && m_closedList.empty(), ("Dangling lists.")); // create unique "mark" values for open and closed cells for this pathfind invocation Bool isCrusher = obj ? obj->getCrusherLevel() > 0 : false; @@ -8050,25 +8082,34 @@ Int Pathfinder::checkPathCost(Object *obj, const LocomotorSet& locomotorSet, con parentCell->startPathfind(goalCell); // initialize "open" list to contain start cell - m_openList = parentCell; +#if RETAIL_COMPATIBLE_PATHFINDING + if (!s_useFixedPathfinding) { + m_openList.reset(parentCell); + } + else +#endif + { + m_openList.reset(); + parentCell->putOnSortedOpenList(m_openList); + } // "closed" list is initially empty - m_closedList = nullptr; + m_closedList.reset(); // // Continue search until "open" list is empty, or // until goal is found. // - while( m_openList != nullptr ) + while( !m_openList.empty() ) { // take head cell off of open list - it has lowest estimated total path cost - parentCell = m_openList; - m_openList = parentCell->removeFromOpenList(m_openList); + parentCell = m_openList.getHead(); + parentCell->removeFromOpenList(m_openList); // put parent cell onto closed list - its evaluation is finished - Retail compatible behaviour #if RETAIL_COMPATIBLE_PATHFINDING if (!s_useFixedPathfinding) { - m_closedList = parentCell->putOnClosedList( m_closedList ); + parentCell->putOnClosedList( m_closedList ); } #endif @@ -8090,7 +8131,7 @@ Int Pathfinder::checkPathCost(Object *obj, const LocomotorSet& locomotorSet, con if (s_useFixedPathfinding) #endif { - m_closedList = parentCell->putOnClosedList( m_closedList ); + parentCell->putOnClosedList( m_closedList ); } if (cellCount > MAX_CELL_COUNT) { @@ -8193,16 +8234,16 @@ Int Pathfinder::checkPathCost(Object *obj, const LocomotorSet& locomotorSet, con // if newCell was on closed list, remove it from the list if (newCell->getClosed()) - m_closedList = newCell->removeFromClosedList( m_closedList ); + newCell->removeFromClosedList( m_closedList ); // if the newCell was already on the open list, remove it so it can be re-inserted in order if (newCell->getOpen()) - m_openList = newCell->removeFromOpenList( m_openList ); + newCell->removeFromOpenList( m_openList ); #if RETAIL_COMPATIBLE_PATHFINDING // TheSuperHacker @info This is here to catch a retail pathfinding crash point and to recover from it // A cell has gotten onto the open list without pathfinding info due to a danling m_open pointer on the previous listed cell so we need to force a cleanup - if (!s_useFixedPathfinding && m_openList && !m_openList->hasInfo()) { + if (!s_useFixedPathfinding && m_openList.getHead() && !m_openList.getHead()->hasInfo()) { s_useFixedPathfinding = true; forceCleanCells(); return MAX_COST; @@ -8210,7 +8251,7 @@ Int Pathfinder::checkPathCost(Object *obj, const LocomotorSet& locomotorSet, con #endif // insert newCell in open list such that open list is sorted, smallest total path cost first - m_openList = newCell->putOnSortedOpenList( m_openList ); + newCell->putOnSortedOpenList( m_openList ); } } @@ -8274,7 +8315,7 @@ Path *Pathfinder::findClosestPath( Object *obj, const LocomotorSet& locomotorSet adjustTo.x += PATHFIND_CELL_SIZE_F/2; adjustTo.y += PATHFIND_CELL_SIZE_F/2; } - DEBUG_ASSERTCRASH(m_openList== nullptr && m_closedList == nullptr, ("Dangling lists.")); + DEBUG_ASSERTCRASH(m_openList.empty() && m_closedList.empty(), ("Dangling lists.")); // create unique "mark" values for open and closed cells for this pathfind invocation Bool isCrusher = obj ? obj->getCrusherLevel() > 0 : false; @@ -8379,23 +8420,32 @@ Path *Pathfinder::findClosestPath( Object *obj, const LocomotorSet& locomotorSet Real closestDistScreenSqr = FLT_MAX; // initialize "open" list to contain start cell - m_openList = parentCell; +#if RETAIL_COMPATIBLE_PATHFINDING + if (!s_useFixedPathfinding) { + m_openList.reset(parentCell); + } + else +#endif + { + m_openList.reset(); + parentCell->putOnSortedOpenList(m_openList); + } // "closed" list is initially empty - m_closedList = nullptr; + m_closedList.reset(); Int count = 0; // // Continue search until "open" list is empty, or // until goal is found. // - while( m_openList != nullptr ) + while( !m_openList.empty() ) { Real dx; Real dy; Real distSqr; // take head cell off of open list - it has lowest estimated total path cost - parentCell = m_openList; - m_openList = parentCell->removeFromOpenList(m_openList); + parentCell = m_openList.getHead(); + parentCell->removeFromOpenList(m_openList); if (parentCell == goalCell) { @@ -8411,7 +8461,7 @@ Path *Pathfinder::findClosestPath( Object *obj, const LocomotorSet& locomotorSet #ifdef INTENSE_DEBUG Int count = 0; PathfindCell *cur; - for (cur = m_closedList; cur; cur=cur->getNextOpen()) { + for (cur = m_closedList.getHead(); cur; cur=cur->getNextOpen()) { count++; } if (count>1000) { @@ -8448,7 +8498,7 @@ Path *Pathfinder::findClosestPath( Object *obj, const LocomotorSet& locomotorSet return path; } // put parent cell onto closed list - its evaluation is finished - m_closedList = parentCell->putOnClosedList( m_closedList ); + parentCell->putOnClosedList( m_closedList ); if (!m_isTunneling && checkDestination(obj, parentCell->getXIndex(), parentCell->getYIndex(), parentCell->getLayer(), radius, centerInCell)) { if (!startedStuck || validMovementPosition( isCrusher, locomotorSet.getValidSurfaces(), parentCell )) { dx = IABS(goalCell->getXIndex()-parentCell->getXIndex()); @@ -9849,7 +9899,7 @@ Path *Pathfinder::getMoveAwayFromPath(Object* obj, Object *otherObj, Int radius; getRadiusAndCenter(obj, radius, centerInCell); - DEBUG_ASSERTCRASH(m_openList== nullptr && m_closedList == nullptr, ("Dangling lists.")); + DEBUG_ASSERTCRASH(m_openList.empty() && m_closedList.empty(), ("Dangling lists.")); // determine start cell ICoord2D startCellNdx; @@ -9890,10 +9940,19 @@ Path *Pathfinder::getMoveAwayFromPath(Object* obj, Object *otherObj, parentCell->startPathfind(nullptr); // initialize "open" list to contain start cell - m_openList = parentCell; +#if RETAIL_COMPATIBLE_PATHFINDING + if (!s_useFixedPathfinding) { + m_openList.reset(parentCell); + } + else +#endif + { + m_openList.reset(); + parentCell->putOnSortedOpenList(m_openList); + } // "closed" list is initially empty - m_closedList = nullptr; + m_closedList.reset(); // // Continue search until "open" list is empty, or @@ -9905,11 +9964,11 @@ Path *Pathfinder::getMoveAwayFromPath(Object* obj, Object *otherObj, boxHalfWidth += otherRadius*PATHFIND_CELL_SIZE_F; if (otherCenter) boxHalfWidth+=PATHFIND_CELL_SIZE_F/2; - while( m_openList != nullptr ) + while( !m_openList.empty() ) { // take head cell off of open list - it has lowest estimated total path cost - parentCell = m_openList; - m_openList = parentCell->removeFromOpenList(m_openList); + parentCell = m_openList.getHead(); + parentCell->removeFromOpenList(m_openList); Region2D bounds; Coord3D cellCenter; @@ -9975,7 +10034,7 @@ Path *Pathfinder::getMoveAwayFromPath(Object* obj, Object *otherObj, return newPath; } // put parent cell onto closed list - its evaluation is finished - m_closedList = parentCell->putOnClosedList( m_closedList ); + parentCell->putOnClosedList( m_closedList ); // Check to see if we can change layers in this cell. checkChangeLayers(parentCell); @@ -10026,7 +10085,7 @@ Path *Pathfinder::patchPath( const Object *obj, const LocomotorSet& locomotorSet m_zoneManager.setAllPassable(); - DEBUG_ASSERTCRASH(m_openList== nullptr && m_closedList == nullptr, ("Dangling lists.")); + DEBUG_ASSERTCRASH(m_openList.empty() && m_closedList.empty(), ("Dangling lists.")); enum {CELL_LIMIT = 2000}; // max cells to examine. Int cellCount = 0; @@ -10057,10 +10116,19 @@ Path *Pathfinder::patchPath( const Object *obj, const LocomotorSet& locomotorSet parentCell->startPathfind( nullptr); // initialize "open" list to contain start cell - m_openList = parentCell; +#if RETAIL_COMPATIBLE_PATHFINDING + if (!s_useFixedPathfinding) { + m_openList.reset(parentCell); + } + else +#endif + { + m_openList.reset(); + parentCell->putOnSortedOpenList(m_openList); + } // "closed" list is initially empty - m_closedList = nullptr; + m_closedList.reset(); // // Continue search until "open" list is empty, or @@ -10141,11 +10209,11 @@ Path *Pathfinder::patchPath( const Object *obj, const LocomotorSet& locomotorSet return nullptr; } - while( m_openList != nullptr ) + while( !m_openList.empty() ) { // take head cell off of open list - it has lowest estimated total path cost - parentCell = m_openList; - m_openList = parentCell->removeFromOpenList(m_openList); + parentCell = m_openList.getHead(); + parentCell->removeFromOpenList(m_openList); Coord3D cellCenter; adjustCoordToCell(parentCell->getXIndex(), parentCell->getYIndex(), centerInCell, cellCenter, parentCell->getLayer()); @@ -10189,7 +10257,7 @@ Path *Pathfinder::patchPath( const Object *obj, const LocomotorSet& locomotorSet return path; } // put parent cell onto closed list - its evaluation is finished - m_closedList = parentCell->putOnClosedList( m_closedList ); + parentCell->putOnClosedList( m_closedList ); if (cellCount < CELL_LIMIT) { // Check to see if we can change layers in this cell. @@ -10300,7 +10368,7 @@ Path *Pathfinder::findAttackPath( const Object *obj, const LocomotorSet& locomot Int cellCount = 0; - DEBUG_ASSERTCRASH(m_openList== nullptr && m_closedList == nullptr, ("Dangling lists.")); + DEBUG_ASSERTCRASH(m_openList.empty() && m_closedList.empty(), ("Dangling lists.")); Int attackDistance = weapon->getAttackDistance(obj, victim, victimPos); attackDistance += 3*PATHFIND_CELL_SIZE; @@ -10342,10 +10410,19 @@ Path *Pathfinder::findAttackPath( const Object *obj, const LocomotorSet& locomot } // initialize "open" list to contain start cell - m_openList = parentCell; +#if RETAIL_COMPATIBLE_PATHFINDING + if (!s_useFixedPathfinding) { + m_openList.reset(parentCell); + } + else +#endif + { + m_openList.reset(); + parentCell->putOnSortedOpenList(m_openList); + } // "closed" list is initially empty - m_closedList = nullptr; + m_closedList.reset(); // // Continue search until "open" list is empty, or @@ -10362,11 +10439,11 @@ Path *Pathfinder::findAttackPath( const Object *obj, const LocomotorSet& locomot checkLOS = true; } - while( m_openList != nullptr ) + while( !m_openList.empty() ) { // take head cell off of open list - it has lowest estimated total path cost - parentCell = m_openList; - m_openList = parentCell->removeFromOpenList(m_openList); + parentCell = m_openList.getHead(); + parentCell->removeFromOpenList(m_openList); Coord3D cellCenter; adjustCoordToCell(parentCell->getXIndex(), parentCell->getYIndex(), centerInCell, cellCenter, parentCell->getLayer()); @@ -10406,7 +10483,7 @@ Path *Pathfinder::findAttackPath( const Object *obj, const LocomotorSet& locomot #ifdef INTENSE_DEBUG Int count = 0; PathfindCell *cur; - for (cur = m_closedList; cur; cur=cur->getNextOpen()) { + for (cur = m_closedList.getHead(); cur; cur=cur->getNextOpen()) { count++; } if (count>1000) { @@ -10458,7 +10535,7 @@ Path *Pathfinder::findAttackPath( const Object *obj, const LocomotorSet& locomot } // put parent cell onto closed list - its evaluation is finished - m_closedList = parentCell->putOnClosedList( m_closedList ); + parentCell->putOnClosedList( m_closedList ); if (cellCount < ATTACK_CELL_LIMIT) { // Check to see if we can change layers in this cell. @@ -10535,7 +10612,7 @@ Path *Pathfinder::findSafePath( const Object *obj, const LocomotorSet& locomotor isHuman = false; // computer gets to cheat. } - DEBUG_ASSERTCRASH(m_openList== nullptr && m_closedList == nullptr, ("Dangling lists.")); + DEBUG_ASSERTCRASH(m_openList.empty() && m_closedList.empty(), ("Dangling lists.")); // create unique "mark" values for open and closed cells for this pathfind invocation m_zoneManager.setAllPassable(); @@ -10554,10 +10631,19 @@ Path *Pathfinder::findSafePath( const Object *obj, const LocomotorSet& locomotor parentCell->startPathfind( nullptr); // initialize "open" list to contain start cell - m_openList = parentCell; +#if RETAIL_COMPATIBLE_PATHFINDING + if (!s_useFixedPathfinding) { + m_openList.reset(parentCell); + } + else +#endif + { + m_openList.reset(); + parentCell->putOnSortedOpenList(m_openList); + } // "closed" list is initially empty - m_closedList = nullptr; + m_closedList.reset(); // // Continue search until "open" list is empty, or @@ -10566,11 +10652,11 @@ Path *Pathfinder::findSafePath( const Object *obj, const LocomotorSet& locomotor Real farthestDistanceSqr = 0; - while( m_openList != nullptr ) + while( !m_openList.empty() ) { // take head cell off of open list - it has lowest estimated total path cost - parentCell = m_openList; - m_openList = parentCell->removeFromOpenList(m_openList); + parentCell = m_openList.getHead(); + parentCell->removeFromOpenList(m_openList); Coord3D cellCenter; adjustCoordToCell(parentCell->getXIndex(), parentCell->getYIndex(), centerInCell, cellCenter, parentCell->getLayer()); @@ -10589,7 +10675,7 @@ Path *Pathfinder::findSafePath( const Object *obj, const LocomotorSet& locomotor if (distSqr>repulsorDistSqr) { ok = true; } - if (m_openList == nullptr && cellCount>0) { + if (m_openList.empty() && cellCount>0) { ok = true; // exhausted the search space, just take the last cell. } if (distSqr > farthestDistanceSqr) { @@ -10609,7 +10695,7 @@ Path *Pathfinder::findSafePath( const Object *obj, const LocomotorSet& locomotor #ifdef INTENSE_DEBUG Int count = 0; PathfindCell *cur; - for (cur = m_closedList; cur; cur=cur->getNextOpen()) { + for (cur = m_closedList.getHead(); cur; cur=cur->getNextOpen()) { count++; } if (count>2000) { @@ -10646,7 +10732,7 @@ Path *Pathfinder::findSafePath( const Object *obj, const LocomotorSet& locomotor } // put parent cell onto closed list - its evaluation is finished - m_closedList = parentCell->putOnClosedList( m_closedList ); + parentCell->putOnClosedList( m_closedList ); // Check to see if we can change layers in this cell. checkChangeLayers(parentCell); diff --git a/GeneralsMD/Code/GameEngine/Include/GameLogic/AIPathfind.h b/GeneralsMD/Code/GameEngine/Include/GameLogic/AIPathfind.h index a7ab136c909..1491f751927 100644 --- a/GeneralsMD/Code/GameEngine/Include/GameLogic/AIPathfind.h +++ b/GeneralsMD/Code/GameEngine/Include/GameLogic/AIPathfind.h @@ -248,6 +248,24 @@ class PathfindCellInfo UnsignedInt m_closed:1; ///< place for marking this cell as on the closed list }; +// TheSuperHackers @info The PathfindCellList class acts as a new management class for the pathfindcell open and closed lists +class PathfindCellList +{ + friend class PathfindCell; + +public: + PathfindCellList() : m_head(nullptr) {} + + void reset(PathfindCell* newHead = nullptr) { m_head = newHead; } + + PathfindCell* getHead() const { return m_head; } + + Bool empty() const { return m_head == nullptr; } + +private: + PathfindCell* m_head; +}; + /** * This represents one cell in the pathfinding grid. * These cells categorize the world into idealized cellular states, @@ -308,23 +326,23 @@ class PathfindCell UnsignedInt costSoFar( PathfindCell *parent ); - /// put self on "open" list in ascending cost order, return new list - PathfindCell *putOnSortedOpenList( PathfindCell *list ); + /// put self on "open" list in ascending cost order + void putOnSortedOpenList( PathfindCellList &list ); /// remove self from "open" list - PathfindCell *removeFromOpenList( PathfindCell *list ); + void removeFromOpenList( PathfindCellList &list ); /// put self on "closed" list, return new list - PathfindCell *putOnClosedList( PathfindCell *list ); + void putOnClosedList( PathfindCellList &list ); /// remove self from "closed" list - PathfindCell *removeFromClosedList( PathfindCell *list ); + void removeFromClosedList( PathfindCellList &list ); /// remove all cells from closed list. - static Int releaseClosedList( PathfindCell *list ); + static Int releaseClosedList( PathfindCellList &list ); /// remove all cells from closed list. - static Int releaseOpenList( PathfindCell *list ); + static Int releaseOpenList( PathfindCellList &list ); inline PathfindCell *getNextOpen(void) {return m_info->m_nextOpen?m_info->m_nextOpen->m_cell: nullptr;} @@ -856,8 +874,8 @@ class Pathfinder : PathfindServicesInterface, public Snapshot IRegion2D m_extent; ///< Grid extent limits IRegion2D m_logicalExtent; ///< Logical grid extent limits - PathfindCell *m_openList; ///< Cells ready to be explored - PathfindCell *m_closedList; ///< Cells already explored + PathfindCellList m_openList; ///< Cells ready to be explored + PathfindCellList m_closedList; ///< Cells already explored Bool m_isMapReady; ///< True if all cells of map have been classified Bool m_isTunneling; ///< True if path started in an obstacle diff --git a/GeneralsMD/Code/GameEngine/Source/GameLogic/AI/AIPathfind.cpp b/GeneralsMD/Code/GameEngine/Source/GameLogic/AI/AIPathfind.cpp index f6f4c98fc5d..564cff7d769 100644 --- a/GeneralsMD/Code/GameEngine/Source/GameLogic/AI/AIPathfind.cpp +++ b/GeneralsMD/Code/GameEngine/Source/GameLogic/AI/AIPathfind.cpp @@ -1132,8 +1132,8 @@ void Pathfinder::forceCleanCells() TheAudio->addAudioEvent(&TheAudio->getMiscAudio()->m_allCheerSound); PathfindCellInfo::forceCleanPathFindCellInfos(); - m_openList = nullptr; - m_closedList = nullptr; + m_openList.reset(); + m_closedList.reset(); for (int j = 0; j <= m_extent.hi.y; ++j) { for (int i = 0; i <= m_extent.hi.x; ++i) { @@ -1682,13 +1682,13 @@ Bool PathfindCell::removeObstacle( Object *obstacle ) } /// put self on "open" list in ascending cost order, return new list -PathfindCell *PathfindCell::putOnSortedOpenList( PathfindCell *list ) +void PathfindCell::putOnSortedOpenList( PathfindCellList &list ) { DEBUG_ASSERTCRASH(m_info, ("Has to have info.")); DEBUG_ASSERTCRASH(m_info->m_closed==FALSE && m_info->m_open==FALSE, ("Serious error - Invalid flags. jba")); - if (list == nullptr) + if (list.m_head == nullptr) { - list = this; + list.m_head = this; m_info->m_prevOpen = nullptr; m_info->m_nextOpen = nullptr; } @@ -1701,11 +1701,11 @@ PathfindCell *PathfindCell::putOnSortedOpenList( PathfindCell *list ) // External code should pickup on the bad behaviour and cleanup properly, but we need to explicitly break out here // The fixed pathfinding does not have this issue due to the proper cleanup of pathfindCells and their pathfindCellInfos UnsignedInt cellCount = 0; - for (c = list; c && cellCount < PATHFIND_CELLS_PER_FRAME; c = c->getNextOpen()) + for (c = list.m_head; c && cellCount < PATHFIND_CELLS_PER_FRAME; c = c->getNextOpen()) { cellCount++; #else - for (c = list; c; c = c->getNextOpen()) + for (c = list.m_head; c; c = c->getNextOpen()) { #endif if (c->m_info->m_totalCost > m_info->m_totalCost) @@ -1720,7 +1720,7 @@ PathfindCell *PathfindCell::putOnSortedOpenList( PathfindCell *list ) if (c->m_info->m_prevOpen) c->m_info->m_prevOpen->m_nextOpen = this->m_info; else - list = this; + list.m_head = this; m_info->m_prevOpen = c->m_info->m_prevOpen; c->m_info->m_prevOpen = this->m_info; @@ -1741,11 +1741,10 @@ PathfindCell *PathfindCell::putOnSortedOpenList( PathfindCell *list ) m_info->m_open = true; m_info->m_closed = false; - return list; } /// remove self from "open" list -PathfindCell *PathfindCell::removeFromOpenList( PathfindCell *list ) +void PathfindCell::removeFromOpenList( PathfindCellList &list ) { DEBUG_ASSERTCRASH(m_info, ("Has to have info.")); DEBUG_ASSERTCRASH(m_info->m_closed==FALSE && m_info->m_open==TRUE, ("Serious error - Invalid flags. jba")); @@ -1755,25 +1754,24 @@ PathfindCell *PathfindCell::removeFromOpenList( PathfindCell *list ) if (m_info->m_prevOpen) m_info->m_prevOpen->m_nextOpen = m_info->m_nextOpen; else - list = getNextOpen(); + list.m_head = getNextOpen(); m_info->m_open = false; m_info->m_nextOpen = nullptr; m_info->m_prevOpen = nullptr; - return list; } /// remove all cells from "open" list -Int PathfindCell::releaseOpenList( PathfindCell *list ) +Int PathfindCell::releaseOpenList( PathfindCellList &list ) { Int count = 0; - while (list) { + while (list.m_head) { count++; - DEBUG_ASSERTCRASH(list->m_info, ("Has to have info.")); - DEBUG_ASSERTCRASH(list->m_info->m_closed==FALSE && list->m_info->m_open==TRUE, ("Serious error - Invalid flags. jba")); - PathfindCell *cur = list; - PathfindCellInfo *curInfo = list->m_info; + DEBUG_ASSERTCRASH(list.m_head->m_info, ("Has to have info.")); + DEBUG_ASSERTCRASH(list.m_head->m_info->m_closed==FALSE && list.m_head->m_info->m_open==TRUE, ("Serious error - Invalid flags. jba")); + PathfindCell *cur = list.m_head; + PathfindCellInfo *curInfo = list.m_head->m_info; #if RETAIL_COMPATIBLE_PATHFINDING // TheSuperHackers @info This is only here to catch a crash point in the retail compatible pathfinding @@ -1787,9 +1785,9 @@ Int PathfindCell::releaseOpenList( PathfindCell *list ) #endif if (curInfo->m_nextOpen) { - list = curInfo->m_nextOpen->m_cell; + list.m_head = curInfo->m_nextOpen->m_cell; } else { - list = nullptr; + list.m_head = nullptr; } DEBUG_ASSERTCRASH(cur == curInfo->m_cell, ("Bad backpointer in PathfindCellInfo")); curInfo->m_nextOpen = nullptr; @@ -1801,15 +1799,15 @@ Int PathfindCell::releaseOpenList( PathfindCell *list ) } /// remove all cells from "closed" list -Int PathfindCell::releaseClosedList( PathfindCell *list ) +Int PathfindCell::releaseClosedList( PathfindCellList &list ) { Int count = 0; - while (list) { + while (list.m_head) { count++; - DEBUG_ASSERTCRASH(list->m_info, ("Has to have info.")); - DEBUG_ASSERTCRASH(list->m_info->m_closed==TRUE && list->m_info->m_open==FALSE, ("Serious error - Invalid flags. jba")); - PathfindCell *cur = list; - PathfindCellInfo *curInfo = list->m_info; + DEBUG_ASSERTCRASH(list.m_head->m_info, ("Has to have info.")); + DEBUG_ASSERTCRASH(list.m_head->m_info->m_closed==TRUE && list.m_head->m_info->m_open==FALSE, ("Serious error - Invalid flags. jba")); + PathfindCell *cur = list.m_head; + PathfindCellInfo *curInfo = list.m_head->m_info; #if RETAIL_COMPATIBLE_PATHFINDING // TheSuperHackers @info This is only here to catch a crash point in the retail compatible pathfinding // One crash mode is where a cell has no PathfindCellInfo, resulting in a nullptr access and a crash. @@ -1822,9 +1820,9 @@ Int PathfindCell::releaseClosedList( PathfindCell *list ) #endif if (curInfo->m_nextOpen) { - list = curInfo->m_nextOpen->m_cell; + list.m_head = curInfo->m_nextOpen->m_cell; } else { - list = nullptr; + list.m_head = nullptr; } DEBUG_ASSERTCRASH(cur == curInfo->m_cell, ("Bad backpointer in PathfindCellInfo")); curInfo->m_nextOpen = nullptr; @@ -1836,7 +1834,7 @@ Int PathfindCell::releaseClosedList( PathfindCell *list ) } /// put self on "closed" list, return new list -PathfindCell *PathfindCell::putOnClosedList( PathfindCell *list ) +void PathfindCell::putOnClosedList( PathfindCellList &list ) { DEBUG_ASSERTCRASH(m_info, ("Has to have info.")); DEBUG_ASSERTCRASH(m_info->m_closed==FALSE && m_info->m_open==FALSE, ("Serious error - Invalid flags. jba")); @@ -1847,18 +1845,17 @@ PathfindCell *PathfindCell::putOnClosedList( PathfindCell *list ) m_info->m_closed = TRUE; m_info->m_prevOpen = nullptr; - m_info->m_nextOpen = list?list->m_info:nullptr; - if (list) - list->m_info->m_prevOpen = this->m_info; + m_info->m_nextOpen = list.m_head ? list.m_head->m_info : nullptr; + if (list.m_head) + list.m_head->m_info->m_prevOpen = this->m_info; - list = this; + list.m_head = this; } - return list; } /// remove self from "closed" list -PathfindCell *PathfindCell::removeFromClosedList( PathfindCell *list ) +void PathfindCell::removeFromClosedList( PathfindCellList &list ) { DEBUG_ASSERTCRASH(m_info, ("Has to have info.")); DEBUG_ASSERTCRASH(m_info->m_closed==TRUE && m_info->m_open==FALSE, ("Serious error - Invalid flags. jba")); @@ -1868,13 +1865,12 @@ PathfindCell *PathfindCell::removeFromClosedList( PathfindCell *list ) if (m_info->m_prevOpen) m_info->m_prevOpen->m_nextOpen = m_info->m_nextOpen; else - list = getNextOpen(); + list.m_head = getNextOpen(); m_info->m_closed = false; m_info->m_nextOpen = nullptr; m_info->m_prevOpen = nullptr; - return list; } /** @@ -3882,8 +3878,8 @@ void Pathfinder::reset( void ) // reset the pathfind grid m_extent.lo.x=m_extent.lo.y=m_extent.hi.x=m_extent.hi.y=0; m_logicalExtent.lo.x=m_logicalExtent.lo.y=m_logicalExtent.hi.x=m_logicalExtent.hi.y=0; - m_openList = nullptr; - m_closedList = nullptr; + m_openList.reset(); + m_closedList.reset(); m_ignoreObstacleID = INVALID_ID; m_isTunneling = false; @@ -4637,7 +4633,7 @@ void Pathfinder::debugShowSearch( Bool pathFound ) addIcon(nullptr, 0, 0, color); // erase. } - for( s = m_openList; s; s=s->getNextOpen() ) + for( s = m_openList.getHead(); s; s=s->getNextOpen() ) { // create objects to show path - they decay RGBColor color; @@ -4651,7 +4647,7 @@ void Pathfinder::debugShowSearch( Bool pathFound ) addIcon(&pos, PATHFIND_CELL_SIZE_F*.6f, 200, color); } - for( s = m_closedList; s; s=s->getNextOpen() ) + for( s = m_closedList.getHead(); s; s=s->getNextOpen() ) { // create objects to show path - they decay RGBColor color; @@ -4741,9 +4737,9 @@ Bool Pathfinder::validMovementTerrain( PathfindLayerEnum layer, const Locomotor* // void Pathfinder::cleanOpenAndClosedLists(void) { Int count = 0; - if (m_openList) { + if (!m_openList.empty()) { count += PathfindCell::releaseOpenList(m_openList); - m_openList = nullptr; + m_openList.reset(); } #if RETAIL_COMPATIBLE_PATHFINDING @@ -4756,9 +4752,9 @@ void Pathfinder::cleanOpenAndClosedLists(void) { } #endif - if (m_closedList) { + if (!m_closedList.empty()) { count += PathfindCell::releaseClosedList(m_closedList); - m_closedList = nullptr; + m_closedList.reset(); } #if RETAIL_COMPATIBLE_PATHFINDING @@ -5881,7 +5877,7 @@ void Pathfinder::checkChangeLayers(PathfindCell *parentCell) newCell->setCostSoFar(parentCell->getCostSoFar()); // same as parent cost newCell->setTotalCost(parentCell->getTotalCost()); // insert newCell in open list such that open list is sorted, smallest total path cost first - m_openList = newCell->putOnSortedOpenList( m_openList ); + newCell->putOnSortedOpenList( m_openList ); } bool Pathfinder::checkCellOutsideExtents(ICoord2D& cell) { @@ -5980,14 +5976,14 @@ struct ExamineCellsStruct // if to was on closed list, remove it from the list if (to->getClosed()) - d->thePathfinder->m_closedList = to->removeFromClosedList( d->thePathfinder->m_closedList ); + to->removeFromClosedList( d->thePathfinder->m_closedList ); // if the to was already on the open list, remove it so it can be re-inserted in order if (to->getOpen()) - d->thePathfinder->m_openList = to->removeFromOpenList( d->thePathfinder->m_openList ); + to->removeFromOpenList( d->thePathfinder->m_openList ); // insert to in open list such that open list is sorted, smallest total path cost first - d->thePathfinder->m_openList = to->putOnSortedOpenList( d->thePathfinder->m_openList ); + to->putOnSortedOpenList( d->thePathfinder->m_openList ); } return 0; // keep going @@ -6214,14 +6210,14 @@ Int Pathfinder::examineNeighboringCells(PathfindCell *parentCell, PathfindCell * // if newCell was on closed list, remove it from the list if (newCell->getClosed()) - m_closedList = newCell->removeFromClosedList( m_closedList ); + newCell->removeFromClosedList( m_closedList ); // if the newCell was already on the open list, remove it so it can be re-inserted in order if (newCell->getOpen()) - m_openList = newCell->removeFromOpenList( m_openList ); + newCell->removeFromOpenList( m_openList ); // insert newCell in open list such that open list is sorted, smallest total path cost first - m_openList = newCell->putOnSortedOpenList( m_openList ); + newCell->putOnSortedOpenList( m_openList ); } return cellCount; } @@ -6287,7 +6283,7 @@ Path *Pathfinder::internalFindPath( Object *obj, const LocomotorSet& locomotorSe DEBUG_LOG(("Attempting pathfind to 0,0, generally a bug.")); return nullptr; } - DEBUG_ASSERTCRASH(m_openList== nullptr && m_closedList == nullptr, ("Dangling lists.")); + DEBUG_ASSERTCRASH(m_openList.empty() && m_closedList.empty(), ("Dangling lists.")); if (m_isMapReady == false) { return nullptr; } @@ -6399,10 +6395,19 @@ Path *Pathfinder::internalFindPath( Object *obj, const LocomotorSet& locomotorSe parentCell->startPathfind(goalCell); // initialize "open" list to contain start cell - m_openList = parentCell; +#if RETAIL_COMPATIBLE_PATHFINDING + if (!s_useFixedPathfinding) { + m_openList.reset(parentCell); + } + else +#endif + { + m_openList.reset(); + parentCell->putOnSortedOpenList(m_openList); + } // "closed" list is initially empty - m_closedList = nullptr; + m_closedList.reset(); Int cellCount = 0; @@ -6410,11 +6415,11 @@ Path *Pathfinder::internalFindPath( Object *obj, const LocomotorSet& locomotorSe // Continue search until "open" list is empty, or // until goal is found. // - while( m_openList != nullptr ) + while( !m_openList.empty() ) { // take head cell off of open list - it has lowest estimated total path cost - parentCell = m_openList; - m_openList = parentCell->removeFromOpenList(m_openList); + parentCell = m_openList.getHead(); + parentCell->removeFromOpenList(m_openList); if (parentCell == goalCell) { @@ -6457,7 +6462,7 @@ Path *Pathfinder::internalFindPath( Object *obj, const LocomotorSet& locomotorSe } // put parent cell onto closed list - its evaluation is finished - m_closedList = parentCell->putOnClosedList( m_closedList ); + parentCell->putOnClosedList( m_closedList ); // Check to see if we can change layers in this cell. checkChangeLayers(parentCell); @@ -6819,7 +6824,7 @@ struct GroundCellsStruct to->setTotalCost(to->getCostSoFar() + costRemaining) ; // insert to in open list such that open list is sorted, smallest total path cost first - d->thePathfinder->m_openList = to->putOnSortedOpenList( d->thePathfinder->m_openList ); + to->putOnSortedOpenList( d->thePathfinder->m_openList ); } return 0; // keep going @@ -6855,7 +6860,7 @@ Path *Pathfinder::findGroundPath( const Coord3D *from, DEBUG_LOG(("Attempting pathfind to 0,0, generally a bug.")); return nullptr; } - DEBUG_ASSERTCRASH(m_openList== nullptr && m_closedList == nullptr, ("Dangling lists.")); + DEBUG_ASSERTCRASH(m_openList.empty() && m_closedList.empty(), ("Dangling lists.")); if (m_isMapReady == false) { return nullptr; } @@ -6948,10 +6953,19 @@ Path *Pathfinder::findGroundPath( const Coord3D *from, parentCell->startPathfind(goalCell); // initialize "open" list to contain start cell - m_openList = parentCell; +#if RETAIL_COMPATIBLE_PATHFINDING + if (!s_useFixedPathfinding) { + m_openList.reset(parentCell); + } + else +#endif + { + m_openList.reset(); + parentCell->putOnSortedOpenList(m_openList); + } // "closed" list is initially empty - m_closedList = nullptr; + m_closedList.reset(); // TheSuperHackers @fix helmutbuhler This was originally uninitialized and in the loop below. #if RETAIL_COMPATIBLE_CRC @@ -6963,11 +6977,11 @@ Path *Pathfinder::findGroundPath( const Coord3D *from, // until goal is found. // Int cellCount = 0; - while( m_openList != nullptr ) + while( !m_openList.empty() ) { // take head cell off of open list - it has lowest estimated total path cost - parentCell = m_openList; - m_openList = parentCell->removeFromOpenList(m_openList); + parentCell = m_openList.getHead(); + parentCell->removeFromOpenList(m_openList); if (parentCell == goalCell) { @@ -7000,7 +7014,7 @@ Path *Pathfinder::findGroundPath( const Coord3D *from, } // put parent cell onto closed list - its evaluation is finished - m_closedList = parentCell->putOnClosedList( m_closedList ); + parentCell->putOnClosedList( m_closedList ); // Check to see if we can change layers in this cell. checkChangeLayers(parentCell); @@ -7135,14 +7149,14 @@ Path *Pathfinder::findGroundPath( const Coord3D *from, // if newCell was on closed list, remove it from the list if (newCell->getClosed()) - m_closedList = newCell->removeFromClosedList( m_closedList ); + newCell->removeFromClosedList( m_closedList ); // if the newCell was already on the open list, remove it so it can be re-inserted in order if (newCell->getOpen()) - m_openList = newCell->removeFromOpenList( m_openList ); + newCell->removeFromOpenList( m_openList ); // insert newCell in open list such that open list is sorted, smallest total path cost first - m_openList = newCell->putOnSortedOpenList( m_openList ); + newCell->putOnSortedOpenList( m_openList ); } } // failure - goal cannot be reached @@ -7270,14 +7284,14 @@ void Pathfinder::processHierarchicalCell( const ICoord2D &scanCell, const ICoord if (!s_useFixedPathfinding) { if (!newCell->getClosed() && !newCell->getOpen()) { - m_closedList = newCell->putOnClosedList(m_closedList); + newCell->putOnClosedList(m_closedList); } } else #endif { if (newCell->hasInfo() && !newCell->getClosed() && !newCell->getOpen()) { - m_closedList = newCell->putOnClosedList(m_closedList); + newCell->putOnClosedList(m_closedList); } } @@ -7299,7 +7313,7 @@ void Pathfinder::processHierarchicalCell( const ICoord2D &scanCell, const ICoord adjNewCell->setTotalCost(adjNewCell->getCostSoFar()+remCost); adjNewCell->setParentCellHierarchical(parentCell); // insert newCell in open list such that open list is sorted, smallest total path cost first - m_openList = adjNewCell->putOnSortedOpenList( m_openList ); + adjNewCell->putOnSortedOpenList( m_openList ); } } @@ -7345,7 +7359,7 @@ Path *Pathfinder::internal_findHierarchicalPath( Bool isHuman, const LocomotorSu DEBUG_LOG(("Attempting pathfind to 0,0, generally a bug.")); return nullptr; } - DEBUG_ASSERTCRASH(m_openList== nullptr && m_closedList == nullptr, ("Dangling lists.")); + DEBUG_ASSERTCRASH(m_openList.empty() && m_closedList.empty(), ("Dangling lists.")); if (m_isMapReady == false) { return nullptr; } @@ -7402,7 +7416,7 @@ Path *Pathfinder::internal_findHierarchicalPath( Bool isHuman, const LocomotorSu parentCell->startPathfind(goalCell); // "closed" list is initially empty - m_closedList = nullptr; + m_closedList.reset(); Int cellCount = 0; @@ -7421,7 +7435,16 @@ Path *Pathfinder::internal_findHierarchicalPath( Bool isHuman, const LocomotorSu } // initialize "open" list to contain start cell - m_openList = parentCell; +#if RETAIL_COMPATIBLE_PATHFINDING + if (!s_useFixedPathfinding) { + m_openList.reset(parentCell); + } + else +#endif + { + m_openList.reset(); + parentCell->putOnSortedOpenList(m_openList); + } if (parentCell->getLayer()!=LAYER_GROUND) { PathfindLayerEnum layer = parentCell->getLayer(); @@ -7434,8 +7457,8 @@ Path *Pathfinder::internal_findHierarchicalPath( Bool isHuman, const LocomotorSu PathfindCell *startCell = getCell(LAYER_GROUND, ndx.x, ndx.y); if (cell && startCell) { // Close parent cell; - m_openList = parentCell->removeFromOpenList(m_openList); - m_closedList = parentCell->putOnClosedList(m_closedList); + parentCell->removeFromOpenList(m_openList); + parentCell->putOnClosedList(m_closedList); if (!startCell->allocateInfo(ndx)) { // TheSuperHackers @info We need to forcefully cleanup dangling pathfinding cells if this failure condition is hit in retail // Retail clients will crash beyond this point, but we attempt to recover by performing a full cleanup then enabling the fixed pathfinding codepath @@ -7460,7 +7483,7 @@ Path *Pathfinder::internal_findHierarchicalPath( Bool isHuman, const LocomotorSu startCell->setTotalCost(remCost); startCell->setParentCellHierarchical(parentCell); // insert newCell in open list such that open list is sorted, smallest total path cost first - m_openList = startCell->putOnSortedOpenList( m_openList ); + startCell->putOnSortedOpenList( m_openList ); cellCount++; if(!cell->allocateInfo(toNdx)) { @@ -7485,7 +7508,7 @@ Path *Pathfinder::internal_findHierarchicalPath( Bool isHuman, const LocomotorSu cell->setTotalCost(remCost); cell->setParentCellHierarchical(parentCell); // insert newCell in open list such that open list is sorted, smallest total path cost first - m_openList = cell->putOnSortedOpenList( m_openList ); + cell->putOnSortedOpenList( m_openList ); } } @@ -7496,11 +7519,11 @@ Path *Pathfinder::internal_findHierarchicalPath( Bool isHuman, const LocomotorSu // Continue search until "open" list is empty, or // until goal is found. // - while( m_openList != nullptr ) + while( !m_openList.empty() ) { // take head cell off of open list - it has lowest estimated total path cost - parentCell = m_openList; - m_openList = parentCell->removeFromOpenList(m_openList); + parentCell = m_openList.getHead(); + parentCell->removeFromOpenList(m_openList); zoneStorageType parentZone; if (parentCell->getLayer()==LAYER_GROUND) { @@ -7584,7 +7607,7 @@ Path *Pathfinder::internal_findHierarchicalPath( Bool isHuman, const LocomotorSu } startCell->setParentCellHierarchical(parentCell); if (!startCell->getClosed() && !startCell->getOpen()) { - m_closedList = startCell->putOnClosedList(m_closedList); + startCell->putOnClosedList(m_closedList); } } if(!cell->allocateInfo(toNdx)) { @@ -7613,7 +7636,7 @@ Path *Pathfinder::internal_findHierarchicalPath( Bool isHuman, const LocomotorSu cell->setTotalCost(cell->getCostSoFar()+remCost); cell->setParentCellHierarchical(startCell); // insert newCell in open list such that open list is sorted, smallest total path cost first - m_openList = cell->putOnSortedOpenList( m_openList ); + cell->putOnSortedOpenList( m_openList ); } } @@ -7682,7 +7705,7 @@ Path *Pathfinder::internal_findHierarchicalPath( Bool isHuman, const LocomotorSu } // put parent cell onto closed list - its evaluation is finished - m_closedList = parentCell->putOnClosedList( m_closedList ); + parentCell->putOnClosedList( m_closedList ); Int i; zoneStorageType examinedZones[PathfindZoneManager::ZONE_BLOCK_SIZE]; @@ -8115,7 +8138,7 @@ Bool Pathfinder::pathDestination( Object *obj, const LocomotorSet& locomotorSet Coord3D adjustTo = *groupDest; Coord3D *to = &adjustTo; - DEBUG_ASSERTCRASH(m_openList== nullptr && m_closedList == nullptr, ("Dangling lists.")); + DEBUG_ASSERTCRASH(m_openList.empty() && m_closedList.empty(), ("Dangling lists.")); // create unique "mark" values for open and closed cells for this pathfind invocation Bool isCrusher = obj ? obj->getCrusherLevel() > 0 : false; @@ -8178,24 +8201,33 @@ Bool Pathfinder::pathDestination( Object *obj, const LocomotorSet& locomotorSet parentCell->startPathfind(goalCell); // initialize "open" list to contain start cell - m_openList = parentCell; +#if RETAIL_COMPATIBLE_PATHFINDING + if (!s_useFixedPathfinding) { + m_openList.reset(parentCell); + } + else +#endif + { + m_openList.reset(); + parentCell->putOnSortedOpenList(m_openList); + } // "closed" list is initially empty - m_closedList = nullptr; + m_closedList.reset(); // // Continue search until "open" list is empty, or // until goal is found. // - while( m_openList != nullptr ) + while( !m_openList.empty() ) { // take head cell off of open list - it has lowest estimated total path cost - parentCell = m_openList; - m_openList = parentCell->removeFromOpenList(m_openList); + parentCell = m_openList.getHead(); + parentCell->removeFromOpenList(m_openList); Coord3D pos; // put parent cell onto closed list - its evaluation is finished - m_closedList = parentCell->putOnClosedList( m_closedList ); + parentCell->putOnClosedList( m_closedList ); if (checkForAdjust(obj, locomotorSet, isHuman, parentCell->getXIndex(), parentCell->getYIndex(), parentCell->getLayer(), radius, center, &pos, groupDest)) { Int dx = IABS(goalCell->getXIndex()-parentCell->getXIndex()); @@ -8312,14 +8344,14 @@ Bool Pathfinder::pathDestination( Object *obj, const LocomotorSet& locomotorSet // if newCell was on closed list, remove it from the list if (newCell->getClosed()) - m_closedList = newCell->removeFromClosedList( m_closedList ); + newCell->removeFromClosedList( m_closedList ); // if the newCell was already on the open list, remove it so it can be re-inserted in order if (newCell->getOpen()) - m_openList = newCell->removeFromOpenList( m_openList ); + newCell->removeFromOpenList( m_openList ); // insert newCell in open list such that open list is sorted, smallest total path cost first - m_openList = newCell->putOnSortedOpenList( m_openList ); + newCell->putOnSortedOpenList( m_openList ); } } @@ -8409,7 +8441,7 @@ Int Pathfinder::checkPathCost(Object *obj, const LocomotorSet& locomotorSet, con Coord3D adjustTo = *rawTo; Coord3D *to = &adjustTo; - DEBUG_ASSERTCRASH(m_openList== nullptr && m_closedList == nullptr, ("Dangling lists.")); + DEBUG_ASSERTCRASH(m_openList.empty() && m_closedList.empty(), ("Dangling lists.")); // create unique "mark" values for open and closed cells for this pathfind invocation Bool isCrusher = obj ? obj->getCrusherLevel() > 0 : false; @@ -8454,25 +8486,34 @@ Int Pathfinder::checkPathCost(Object *obj, const LocomotorSet& locomotorSet, con parentCell->startPathfind(goalCell); // initialize "open" list to contain start cell - m_openList = parentCell; +#if RETAIL_COMPATIBLE_PATHFINDING + if (!s_useFixedPathfinding) { + m_openList.reset(parentCell); + } + else +#endif + { + m_openList.reset(); + parentCell->putOnSortedOpenList(m_openList); + } // "closed" list is initially empty - m_closedList = nullptr; + m_closedList.reset(); // // Continue search until "open" list is empty, or // until goal is found. // - while( m_openList != nullptr ) + while( !m_openList.empty() ) { // take head cell off of open list - it has lowest estimated total path cost - parentCell = m_openList; - m_openList = parentCell->removeFromOpenList(m_openList); + parentCell = m_openList.getHead(); + parentCell->removeFromOpenList(m_openList); // put parent cell onto closed list - its evaluation is finished - Retail compatible behaviour #if RETAIL_COMPATIBLE_PATHFINDING if (!s_useFixedPathfinding) { - m_closedList = parentCell->putOnClosedList( m_closedList ); + parentCell->putOnClosedList( m_closedList ); } #endif @@ -8494,7 +8535,7 @@ Int Pathfinder::checkPathCost(Object *obj, const LocomotorSet& locomotorSet, con if (s_useFixedPathfinding) #endif { - m_closedList = parentCell->putOnClosedList( m_closedList ); + parentCell->putOnClosedList( m_closedList ); } if (cellCount > MAX_CELL_COUNT) { @@ -8597,16 +8638,16 @@ Int Pathfinder::checkPathCost(Object *obj, const LocomotorSet& locomotorSet, con // if newCell was on closed list, remove it from the list if (newCell->getClosed()) - m_closedList = newCell->removeFromClosedList( m_closedList ); + newCell->removeFromClosedList( m_closedList ); // if the newCell was already on the open list, remove it so it can be re-inserted in order if (newCell->getOpen()) - m_openList = newCell->removeFromOpenList( m_openList ); + newCell->removeFromOpenList( m_openList ); #if RETAIL_COMPATIBLE_PATHFINDING // TheSuperHacker @info This is here to catch a retail pathfinding crash point and to recover from it // A cell has gotten onto the open list without pathfinding info due to a danling m_open pointer on the previous listed cell so we need to force a cleanup - if (!s_useFixedPathfinding && m_openList && !m_openList->hasInfo()) { + if (!s_useFixedPathfinding && m_openList.getHead() && !m_openList.getHead()->hasInfo()) { s_useFixedPathfinding = true; forceCleanCells(); return MAX_COST; @@ -8614,7 +8655,7 @@ Int Pathfinder::checkPathCost(Object *obj, const LocomotorSet& locomotorSet, con #endif // insert newCell in open list such that open list is sorted, smallest total path cost first - m_openList = newCell->putOnSortedOpenList( m_openList ); + newCell->putOnSortedOpenList( m_openList ); } } @@ -8678,7 +8719,7 @@ Path *Pathfinder::findClosestPath( Object *obj, const LocomotorSet& locomotorSet adjustTo.x += PATHFIND_CELL_SIZE_F/2; adjustTo.y += PATHFIND_CELL_SIZE_F/2; } - DEBUG_ASSERTCRASH(m_openList== nullptr && m_closedList == nullptr, ("Dangling lists.")); + DEBUG_ASSERTCRASH(m_openList.empty() && m_closedList.empty(), ("Dangling lists.")); // create unique "mark" values for open and closed cells for this pathfind invocation Bool isCrusher = obj ? obj->getCrusherLevel() > 0 : false; @@ -8783,24 +8824,33 @@ Path *Pathfinder::findClosestPath( Object *obj, const LocomotorSet& locomotorSet Real closestDistScreenSqr = FLT_MAX; // initialize "open" list to contain start cell - m_openList = parentCell; +#if RETAIL_COMPATIBLE_PATHFINDING + if (!s_useFixedPathfinding) { + m_openList.reset(parentCell); + } + else +#endif + { + m_openList.reset(); + parentCell->putOnSortedOpenList(m_openList); + } // "closed" list is initially empty - m_closedList = nullptr; + m_closedList.reset(); Int count = 0; // // Continue search until "open" list is empty, or // until goal is found. // Bool foundGoal = false; - while( m_openList != nullptr ) + while( !m_openList.empty() ) { Real dx; Real dy; Real distSqr; // take head cell off of open list - it has lowest estimated total path cost - parentCell = m_openList; - m_openList = parentCell->removeFromOpenList(m_openList); + parentCell = m_openList.getHead(); + parentCell->removeFromOpenList(m_openList); if (parentCell == goalCell) { @@ -8818,7 +8868,7 @@ Path *Pathfinder::findClosestPath( Object *obj, const LocomotorSet& locomotorSet #ifdef INTENSE_DEBUG Int count = 0; PathfindCell *cur; - for (cur = m_closedList; cur; cur=cur->getNextOpen()) { + for (cur = m_closedList.getHead(); cur; cur=cur->getNextOpen()) { count++; } if (count>1000) { @@ -8855,7 +8905,7 @@ Path *Pathfinder::findClosestPath( Object *obj, const LocomotorSet& locomotorSet return path; } // put parent cell onto closed list - its evaluation is finished - m_closedList = parentCell->putOnClosedList( m_closedList ); + parentCell->putOnClosedList( m_closedList ); if (!m_isTunneling && checkDestination(obj, parentCell->getXIndex(), parentCell->getYIndex(), parentCell->getLayer(), radius, centerInCell)) { if (!startedStuck || validMovementPosition( isCrusher, locomotorSet.getValidSurfaces(), parentCell )) { dx = IABS(goalCell->getXIndex()-parentCell->getXIndex()); @@ -10274,7 +10324,7 @@ Path *Pathfinder::getMoveAwayFromPath(Object* obj, Object *otherObj, Int radius; getRadiusAndCenter(obj, radius, centerInCell); - DEBUG_ASSERTCRASH(m_openList== nullptr && m_closedList == nullptr, ("Dangling lists.")); + DEBUG_ASSERTCRASH(m_openList.empty() && m_closedList.empty(), ("Dangling lists.")); // determine start cell ICoord2D startCellNdx; @@ -10315,10 +10365,19 @@ Path *Pathfinder::getMoveAwayFromPath(Object* obj, Object *otherObj, parentCell->startPathfind(nullptr); // initialize "open" list to contain start cell - m_openList = parentCell; +#if RETAIL_COMPATIBLE_PATHFINDING + if (!s_useFixedPathfinding) { + m_openList.reset(parentCell); + } + else +#endif + { + m_openList.reset(); + parentCell->putOnSortedOpenList(m_openList); + } // "closed" list is initially empty - m_closedList = nullptr; + m_closedList.reset(); // // Continue search until "open" list is empty, or @@ -10330,11 +10389,11 @@ Path *Pathfinder::getMoveAwayFromPath(Object* obj, Object *otherObj, boxHalfWidth += otherRadius*PATHFIND_CELL_SIZE_F; if (otherCenter) boxHalfWidth+=PATHFIND_CELL_SIZE_F/2; - while( m_openList != nullptr ) + while( !m_openList.empty() ) { // take head cell off of open list - it has lowest estimated total path cost - parentCell = m_openList; - m_openList = parentCell->removeFromOpenList(m_openList); + parentCell = m_openList.getHead(); + parentCell->removeFromOpenList(m_openList); Region2D bounds; Coord3D cellCenter; @@ -10400,7 +10459,7 @@ Path *Pathfinder::getMoveAwayFromPath(Object* obj, Object *otherObj, return newPath; } // put parent cell onto closed list - its evaluation is finished - m_closedList = parentCell->putOnClosedList( m_closedList ); + parentCell->putOnClosedList( m_closedList ); // Check to see if we can change layers in this cell. checkChangeLayers(parentCell); @@ -10451,7 +10510,7 @@ Path *Pathfinder::patchPath( const Object *obj, const LocomotorSet& locomotorSet m_zoneManager.setAllPassable(); - DEBUG_ASSERTCRASH(m_openList== nullptr && m_closedList == nullptr, ("Dangling lists.")); + DEBUG_ASSERTCRASH(m_openList.empty() && m_closedList.empty(), ("Dangling lists.")); enum {CELL_LIMIT = 2000}; // max cells to examine. Int cellCount = 0; @@ -10482,10 +10541,19 @@ Path *Pathfinder::patchPath( const Object *obj, const LocomotorSet& locomotorSet parentCell->startPathfind( nullptr); // initialize "open" list to contain start cell - m_openList = parentCell; +#if RETAIL_COMPATIBLE_PATHFINDING + if (!s_useFixedPathfinding) { + m_openList.reset(parentCell); + } + else +#endif + { + m_openList.reset(); + parentCell->putOnSortedOpenList(m_openList); + } // "closed" list is initially empty - m_closedList = nullptr; + m_closedList.reset(); // // Continue search until "open" list is empty, or @@ -10566,11 +10634,11 @@ Path *Pathfinder::patchPath( const Object *obj, const LocomotorSet& locomotorSet return nullptr; } - while( m_openList != nullptr ) + while( !m_openList.empty() ) { // take head cell off of open list - it has lowest estimated total path cost - parentCell = m_openList; - m_openList = parentCell->removeFromOpenList(m_openList); + parentCell = m_openList.getHead(); + parentCell->removeFromOpenList(m_openList); Coord3D cellCenter; adjustCoordToCell(parentCell->getXIndex(), parentCell->getYIndex(), centerInCell, cellCenter, parentCell->getLayer()); @@ -10614,7 +10682,7 @@ Path *Pathfinder::patchPath( const Object *obj, const LocomotorSet& locomotorSet return path; } // put parent cell onto closed list - its evaluation is finished - m_closedList = parentCell->putOnClosedList( m_closedList ); + parentCell->putOnClosedList( m_closedList ); if (cellCount < CELL_LIMIT) { // Check to see if we can change layers in this cell. @@ -10725,7 +10793,7 @@ Path *Pathfinder::findAttackPath( const Object *obj, const LocomotorSet& locomot Int cellCount = 0; - DEBUG_ASSERTCRASH(m_openList== nullptr && m_closedList == nullptr, ("Dangling lists.")); + DEBUG_ASSERTCRASH(m_openList.empty() && m_closedList.empty(), ("Dangling lists.")); Int attackDistance = weapon->getAttackDistance(obj, victim, victimPos); attackDistance += 3*PATHFIND_CELL_SIZE; @@ -10767,10 +10835,19 @@ Path *Pathfinder::findAttackPath( const Object *obj, const LocomotorSet& locomot } // initialize "open" list to contain start cell - m_openList = parentCell; +#if RETAIL_COMPATIBLE_PATHFINDING + if (!s_useFixedPathfinding) { + m_openList.reset(parentCell); + } + else +#endif + { + m_openList.reset(); + parentCell->putOnSortedOpenList(m_openList); + } // "closed" list is initially empty - m_closedList = nullptr; + m_closedList.reset(); // // Continue search until "open" list is empty, or @@ -10787,11 +10864,11 @@ Path *Pathfinder::findAttackPath( const Object *obj, const LocomotorSet& locomot checkLOS = true; } - while( m_openList != nullptr ) + while( !m_openList.empty() ) { // take head cell off of open list - it has lowest estimated total path cost - parentCell = m_openList; - m_openList = parentCell->removeFromOpenList(m_openList); + parentCell = m_openList.getHead(); + parentCell->removeFromOpenList(m_openList); Coord3D cellCenter; adjustCoordToCell(parentCell->getXIndex(), parentCell->getYIndex(), centerInCell, cellCenter, parentCell->getLayer()); @@ -10831,7 +10908,7 @@ Path *Pathfinder::findAttackPath( const Object *obj, const LocomotorSet& locomot #ifdef INTENSE_DEBUG Int count = 0; PathfindCell *cur; - for (cur = m_closedList; cur; cur=cur->getNextOpen()) { + for (cur = m_closedList.getHead(); cur; cur=cur->getNextOpen()) { count++; } if (count>1000) { @@ -10850,7 +10927,7 @@ Path *Pathfinder::findAttackPath( const Object *obj, const LocomotorSet& locomot debugShowSearch(true); // put parent cell onto closed list - its evaluation is finished - m_closedList = parentCell->putOnClosedList( m_closedList ); + parentCell->putOnClosedList( m_closedList ); // construct and return path if (obj->isKindOf(KINDOF_VEHICLE)) { // Strip backwards. @@ -10940,7 +11017,7 @@ Path *Pathfinder::findAttackPath( const Object *obj, const LocomotorSet& locomot } // put parent cell onto closed list - its evaluation is finished - m_closedList = parentCell->putOnClosedList( m_closedList ); + parentCell->putOnClosedList( m_closedList ); if (cellCount < ATTACK_CELL_LIMIT) { // Check to see if we can change layers in this cell. @@ -11017,7 +11094,7 @@ Path *Pathfinder::findSafePath( const Object *obj, const LocomotorSet& locomotor isHuman = false; // computer gets to cheat. } - DEBUG_ASSERTCRASH(m_openList== nullptr && m_closedList == nullptr, ("Dangling lists.")); + DEBUG_ASSERTCRASH(m_openList.empty() && m_closedList.empty(), ("Dangling lists.")); // create unique "mark" values for open and closed cells for this pathfind invocation m_zoneManager.setAllPassable(); @@ -11036,10 +11113,19 @@ Path *Pathfinder::findSafePath( const Object *obj, const LocomotorSet& locomotor parentCell->startPathfind( nullptr); // initialize "open" list to contain start cell - m_openList = parentCell; +#if RETAIL_COMPATIBLE_PATHFINDING + if (!s_useFixedPathfinding) { + m_openList.reset(parentCell); + } + else +#endif + { + m_openList.reset(); + parentCell->putOnSortedOpenList(m_openList); + } // "closed" list is initially empty - m_closedList = nullptr; + m_closedList.reset(); // // Continue search until "open" list is empty, or @@ -11048,11 +11134,11 @@ Path *Pathfinder::findSafePath( const Object *obj, const LocomotorSet& locomotor Real farthestDistanceSqr = 0; - while( m_openList != nullptr ) + while( !m_openList.empty() ) { // take head cell off of open list - it has lowest estimated total path cost - parentCell = m_openList; - m_openList = parentCell->removeFromOpenList(m_openList); + parentCell = m_openList.getHead(); + parentCell->removeFromOpenList(m_openList); Coord3D cellCenter; adjustCoordToCell(parentCell->getXIndex(), parentCell->getYIndex(), centerInCell, cellCenter, parentCell->getLayer()); @@ -11071,7 +11157,7 @@ Path *Pathfinder::findSafePath( const Object *obj, const LocomotorSet& locomotor if (distSqr>repulsorDistSqr) { ok = true; } - if (m_openList == nullptr && cellCount>0) { + if (m_openList.empty() && cellCount>0) { ok = true; // exhausted the search space, just take the last cell. } if (distSqr > farthestDistanceSqr) { @@ -11091,7 +11177,7 @@ Path *Pathfinder::findSafePath( const Object *obj, const LocomotorSet& locomotor #ifdef INTENSE_DEBUG Int count = 0; PathfindCell *cur; - for (cur = m_closedList; cur; cur=cur->getNextOpen()) { + for (cur = m_closedList.getHead(); cur; cur=cur->getNextOpen()) { count++; } if (count>2000) { @@ -11128,7 +11214,7 @@ Path *Pathfinder::findSafePath( const Object *obj, const LocomotorSet& locomotor } // put parent cell onto closed list - its evaluation is finished - m_closedList = parentCell->putOnClosedList( m_closedList ); + parentCell->putOnClosedList( m_closedList ); // Check to see if we can change layers in this cell. checkChangeLayers(parentCell);