diff --git a/Core/GameEngine/Source/GameLogic/System/GameLogicDispatch.cpp b/Core/GameEngine/Source/GameLogic/System/GameLogicDispatch.cpp index c002ff8f239..fa9d2292f7e 100644 --- a/Core/GameEngine/Source/GameLogic/System/GameLogicDispatch.cpp +++ b/Core/GameEngine/Source/GameLogic/System/GameLogicDispatch.cpp @@ -2120,10 +2120,9 @@ void GameLogic::logicMessageDispatcher( GameMessage *msg, void *userData ) } #if RETAIL_COMPATIBLE_AIGROUP - // TheSuperHackers @bugfix xezon 28/06/2025 This hack avoids crashing when players are selected during Replay playback. - // It can read data from an already deleted AIGroup and return this function when its member size is 0, signifying that - // it is indeed deleted. - if (currentlySelectedGroup && currentlySelectedGroup->getCount() == 0) + // TheSuperHackers @bugfix xezon/Caball009 14/05/2026 This fix avoids crashing when players are selected during Replay playback. + // The current AI group may have been destroyed, and its memory deallocated, in which case it shouldn't be used. + if (currentlySelectedGroup && !TheAI->doesGroupExist(currentlySelectedGroup)) return; #endif diff --git a/Generals/Code/GameEngine/Include/GameLogic/AI.h b/Generals/Code/GameEngine/Include/GameLogic/AI.h index ff4dc881042..ec72bc9f6d4 100644 --- a/Generals/Code/GameEngine/Include/GameLogic/AI.h +++ b/Generals/Code/GameEngine/Include/GameLogic/AI.h @@ -273,6 +273,7 @@ class AI : public SubsystemInterface, public Snapshot AIGroupPtr createGroup(); ///< instantiate a new AI Group void destroyGroup( AIGroup *group ); ///< destroy the given AI Group AIGroup *findGroup( UnsignedInt id ); ///< return the AI Group with the given ID + Bool doesGroupExist(AIGroup* group) const; ///< return whether the given AI Group exists, i.e. is part of the group list // Formation info enum FormationID getNextFormationID(); diff --git a/Generals/Code/GameEngine/Source/GameLogic/AI/AI.cpp b/Generals/Code/GameEngine/Source/GameLogic/AI/AI.cpp index fb576b640fd..f3b2f362db5 100644 --- a/Generals/Code/GameEngine/Source/GameLogic/AI/AI.cpp +++ b/Generals/Code/GameEngine/Source/GameLogic/AI/AI.cpp @@ -494,6 +494,11 @@ AIGroup *AI::findGroup( UnsignedInt id ) return nullptr; } +Bool AI::doesGroupExist(AIGroup* group) const +{ + return std::find(m_groupList.begin(), m_groupList.end(), group) != m_groupList.end(); +} + //-------------------------------------------------------------------------------------------------------- /** * Get the next formation id. diff --git a/GeneralsMD/Code/GameEngine/Include/GameLogic/AI.h b/GeneralsMD/Code/GameEngine/Include/GameLogic/AI.h index 90c3dd32785..3b46117adee 100644 --- a/GeneralsMD/Code/GameEngine/Include/GameLogic/AI.h +++ b/GeneralsMD/Code/GameEngine/Include/GameLogic/AI.h @@ -279,6 +279,7 @@ class AI : public SubsystemInterface, public Snapshot AIGroupPtr createGroup(); ///< instantiate a new AI Group void destroyGroup( AIGroup *group ); ///< destroy the given AI Group AIGroup *findGroup( UnsignedInt id ); ///< return the AI Group with the given ID + Bool doesGroupExist(AIGroup* group) const; ///< return whether the given AI Group exists, i.e. is part of the group list // Formation info enum FormationID getNextFormationID(); diff --git a/GeneralsMD/Code/GameEngine/Source/GameLogic/AI/AI.cpp b/GeneralsMD/Code/GameEngine/Source/GameLogic/AI/AI.cpp index 9959cb42546..ff0d155d9f2 100644 --- a/GeneralsMD/Code/GameEngine/Source/GameLogic/AI/AI.cpp +++ b/GeneralsMD/Code/GameEngine/Source/GameLogic/AI/AI.cpp @@ -497,6 +497,11 @@ AIGroup *AI::findGroup( UnsignedInt id ) return nullptr; } +Bool AI::doesGroupExist(AIGroup* group) const +{ + return std::find(m_groupList.begin(), m_groupList.end(), group) != m_groupList.end(); +} + //-------------------------------------------------------------------------------------------------------- /** * Get the next formation id.