From a20674ee54b57aea482cd1c49cbc9f24286d6dd0 Mon Sep 17 00:00:00 2001 From: Mauller <26652186+Mauller@users.noreply.github.com> Date: Mon, 3 Aug 2026 21:33:04 +0100 Subject: [PATCH 1/2] bugfix(pathfinder): Prevent a retail crash where the head of the closed list has no associated m_info (#3113) --- Core/GameEngine/Source/GameLogic/AI/AIPathfind.cpp | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/Core/GameEngine/Source/GameLogic/AI/AIPathfind.cpp b/Core/GameEngine/Source/GameLogic/AI/AIPathfind.cpp index 0614563bd43..f80d3376d44 100644 --- a/Core/GameEngine/Source/GameLogic/AI/AIPathfind.cpp +++ b/Core/GameEngine/Source/GameLogic/AI/AIPathfind.cpp @@ -1976,7 +1976,19 @@ void PathfindCell::putOnClosedList( PathfindCellList &list ) m_info->m_prevOpen = nullptr; m_info->m_nextOpen = list.m_head ? list.m_head->m_info : nullptr; if (list.m_head) +#if RETAIL_COMPATIBLE_PATHFINDING + // TheSuperHackers @info This is only here to catch a crash point in the retail compatible pathfinding + // This crash mode occurs due to the closed list head not having an m_info associated with it + // A node cannot be put onto the closed list without an m_info under normal conditions + { + if (list.m_head->m_info) + { + list.m_head->m_info->m_prevOpen = this->m_info; + } + } +#else list.m_head->m_info->m_prevOpen = this->m_info; +#endif list.m_head = this; } From c0fc2b640897b44ae4bd79c74dfdf926b22c9cdc Mon Sep 17 00:00:00 2001 From: Mauller <26652186+Mauller@users.noreply.github.com> Date: Mon, 3 Aug 2026 21:34:55 +0100 Subject: [PATCH 2/2] bugfix(pathfinder): Prevent a retail crash where a pathfindCell has a dangling linked list pointer (#3113) --- Core/GameEngine/Source/GameLogic/AI/AIPathfind.cpp | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/Core/GameEngine/Source/GameLogic/AI/AIPathfind.cpp b/Core/GameEngine/Source/GameLogic/AI/AIPathfind.cpp index f80d3376d44..4377e6d2105 100644 --- a/Core/GameEngine/Source/GameLogic/AI/AIPathfind.cpp +++ b/Core/GameEngine/Source/GameLogic/AI/AIPathfind.cpp @@ -1125,9 +1125,11 @@ void PathfindCellInfo::forceCleanPathFindCellInfos() void Pathfinder::forceCleanCells() { - UnicodeString pathfinderFailoverMessage = TheGameText->FETCH_OR_SUBSTITUTE("GUI:PathfindingCrashPrevented", L"A pathfinding crash was prevented, now switching to the crash fixed pathfinding."); + UnicodeString pathfinderFailoverMessage = TheGameText->FETCH_OR_SUBSTITUTE_FORMAT("GUI:PathfindingCrashPrevented", L"A pathfinding crash was prevented at frame %u, now switching to the crash fixed pathfinding.", TheGameLogic->getFrame()); TheInGameUI->message(pathfinderFailoverMessage); + printf("%ls\n", pathfinderFailoverMessage.str()); + TheAudio->addAudioEvent(&TheAudio->getMiscAudio()->m_allCheerSound); PathfindCellInfo::forceCleanPathFindCellInfos(); @@ -1727,6 +1729,13 @@ void PathfindCell::forwardInsertionSortRetailCompatible(PathfindCellList& list) UnsignedInt cellCount = 0; while (currentCell && cellCount < PATHFIND_CELLS_PER_FRAME && currentCell->m_info->m_totalCost <= m_info->m_totalCost) { + // Prevent a retail crash where a pathfindCell has an m_info with a dangling nextOpen pointer + if (currentCell->m_info->m_nextOpen && !currentCell->m_info->m_nextOpen->m_cell->m_info) + { + currentCell->m_info->m_nextOpen->m_cell = nullptr; + currentCell->m_info->m_nextOpen = nullptr; + } + cellCount++; previousCell = currentCell; currentCell = currentCell->getNextOpen();