Skip to content

Commit 80daa92

Browse files
committed
[ZH] Improve AIGroup memory management and fix game crash when a player is selected in Replay playback
1 parent 3010aa7 commit 80daa92

File tree

12 files changed

+180
-189
lines changed

12 files changed

+180
-189
lines changed

GeneralsMD/Code/GameEngine/Include/Common/Player.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -634,7 +634,7 @@ class Player : public Snapshot
634634
// add to the player's current selection this hotkey team.
635635
void processAddTeamGameMessage(Int hotkeyNum, GameMessage *msg);
636636

637-
// returns an AIGroup object that is the currently selected group.
637+
// fills an AIGroup object that is the currently selected group.
638638
void getCurrentSelectionAsAIGroup(AIGroup *group);
639639

640640
// sets the currently selected group to be the given AIGroup

GeneralsMD/Code/GameEngine/Include/GameLogic/AI.h

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,8 @@
3737
#include "Common/GameType.h"
3838
#include "GameLogic/Damage.h"
3939
#include "Common/STLTypedefs.h"
40+
#include "refcount.h"
41+
#include "ref_ptr.h"
4042

4143
class AIGroup;
4244
class AttackPriorityInfo;
@@ -272,7 +274,7 @@ class AI : public SubsystemInterface, public Snapshot
272274
void loadPostProcess( void );
273275

274276
// AI Groups -----------------------------------------------------------------------------------------------
275-
AIGroup *createGroup( void ); ///< instantiate a new AI Group
277+
RefCountPtr<AIGroup> createGroup( void ); ///< instantiate a new AI Group
276278
void destroyGroup( AIGroup *group ); ///< destroy the given AI Group
277279
AIGroup *findGroup( UnsignedInt id ); ///< return the AI Group with the given ID
278280

@@ -880,7 +882,7 @@ class AICommandInterface
880882
* An "AIGroup" is a simple collection of AI objects, used by the AI
881883
* for such things as Group Pathfinding.
882884
*/
883-
class AIGroup : public MemoryPoolObject, public Snapshot
885+
class AIGroup : public MemoryPoolObject, public Snapshot, public RefCountClass
884886
{
885887
private:
886888
void groupAttackObjectPrivate( Bool forced, Object *victim, Int maxShotsToFire, CommandSourceType cmdSource ); ///< attack given object
@@ -980,13 +982,15 @@ class AIGroup : public MemoryPoolObject, public Snapshot
980982

981983
void add( Object *obj ); ///< add object to group
982984

983-
// returns true if remove destroyed the group for us.
985+
// Returns true if the group was emptied.
984986
Bool remove( Object *obj);
987+
988+
void removeAll( void );
985989

986990
// If the group contains any objects not owned by ownerPlayer, return TRUE.
987991
Bool containsAnyObjectsNotOwnedByPlayer( const Player *ownerPlayer );
988992

989-
// Remove any objects that aren't owned by the player, and return true if the group was destroyed due to emptiness
993+
// Removes any objects that aren't owned by the player, and returns true if the group was emptied.
990994
Bool removeAnyObjectsNotOwnedByPlayer( const Player *ownerPlayer );
991995

992996
UnsignedInt getID( void );
@@ -1001,6 +1005,11 @@ class AIGroup : public MemoryPoolObject, public Snapshot
10011005
void releaseWeaponLockForGroup(WeaponLockType lockType);///< Clear each guys weapon choice
10021006
void setWeaponSetFlag( WeaponSetType wst );
10031007

1008+
virtual void Delete_This(void)
1009+
{
1010+
TheAI->destroyGroup(this);
1011+
}
1012+
10041013
protected:
10051014
MEMORY_POOL_GLUE_WITH_USERLOOKUP_CREATE( AIGroup, "AIGroupPool" ); ///< @todo Set real numbers for mem alloc
10061015

GeneralsMD/Code/GameEngine/Include/GameLogic/Object.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
#define _OBJECT_H_
3232

3333
#include "Lib/BaseType.h"
34+
#include "ref_ptr.h"
3435

3536
#include "Common/Geometry.h"
3637
#include "Common/Snapshot.h"
@@ -702,7 +703,7 @@ class Object : public Thing, public Snapshot
702703

703704
GeometryInfo m_geometryInfo;
704705

705-
AIGroup* m_group; ///< if non-NULL, we are part of this group of agents
706+
RefCountPtr<AIGroup> m_group; ///< if non-NULL, we are part of this group of agents
706707

707708
// These will last for my lifetime. I will reuse them and reset them. The truly dynamic ones are in PartitionManager
708709
SightingInfo *m_partitionLastLook; ///< Where and for whom I last looked, so I can undo its effects when I stop

GeneralsMD/Code/GameEngine/Source/GameLogic/AI/AI.cpp

Lines changed: 8 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -333,18 +333,11 @@ void AI::reset( void )
333333
m_aiData = m_aiData->m_next;
334334
delete cur;
335335
}
336-
while (m_groupList.size())
337-
{
338-
AIGroup *groupToRemove = m_groupList.front();
339-
if (groupToRemove)
340-
{
341-
destroyGroup(groupToRemove);
342-
}
343-
else
344-
{
345-
m_groupList.pop_front(); // NULL group, just kill from list. Shouldn't really happen, but just in case.
346-
}
347-
}
336+
337+
DEBUG_ASSERTCRASH(m_groupList.empty(), ("AI::m_groupList is expected empty already\n"));
338+
339+
m_groupList.clear(); // Clear just in case...
340+
348341
m_nextGroupID = 0;
349342
m_nextFormationID = NO_FORMATION_ID;
350343
getNextFormationID(); // increment once past NO_FORMATION_ID. jba.
@@ -444,14 +437,14 @@ void AI::parseAiDataDefinition( INI* ini )
444437
/**
445438
* Create a new AI Group
446439
*/
447-
AIGroup *AI::createGroup( void )
440+
RefCountPtr<AIGroup> AI::createGroup( void )
448441
{
449442
// create a new instance
450-
AIGroup *group = newInstance(AIGroup);
443+
RefCountPtr<AIGroup> group = RefCountPtr<AIGroup>::Create_NoAddRef(newInstance(AIGroup));
451444

452445
// add it to the list
453446
// DEBUG_LOG(("***AIGROUP %x is being added to m_groupList.\n", group ));
454-
m_groupList.push_back( group );
447+
m_groupList.push_back( group.Peek() );
455448

456449
return group;
457450
}

GeneralsMD/Code/GameEngine/Source/GameLogic/AI/AIGroup.cpp

Lines changed: 22 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -92,20 +92,8 @@ AIGroup::~AIGroup()
9292
{
9393
// DEBUG_LOG(("***AIGROUP %x is being destructed.\n", this));
9494
// disassociate each member from the group
95-
std::list<Object *>::iterator i;
96-
for( i = m_memberList.begin(); i != m_memberList.end(); /* empty */ )
97-
{
98-
Object *member = *i;
99-
if (member)
100-
{
101-
member->leaveGroup();
102-
i = m_memberList.begin(); // jump back to the beginning, cause ai->leaveGroup will remove this element.
103-
}
104-
else
105-
{
106-
i = m_memberList.erase(i);
107-
}
108-
}
95+
removeAll();
96+
10997
if (m_groundPath) {
11098
deleteInstance(m_groundPath);
11199
m_groundPath = NULL;
@@ -223,15 +211,33 @@ Bool AIGroup::remove( Object *obj )
223211
// list has changed, properties need recomputation
224212
m_dirty = true;
225213

226-
// if the group is empty, no-one is using it any longer, so destroy it
227214
if (isEmpty()) {
228-
TheAI->destroyGroup( this );
229215
return TRUE;
230216
}
231217

232218
return FALSE;
233219
}
234220

221+
/**
222+
* Remove all objects from group
223+
*/
224+
void AIGroup::removeAll( void )
225+
{
226+
std::list<Object *> memberList;
227+
memberList.swap(m_memberList);
228+
m_memberListSize = 0;
229+
230+
std::list<Object *>::iterator i = memberList.begin();
231+
for ( ; i != memberList.end(); ++i)
232+
{
233+
Object *member = *i;
234+
if (member)
235+
member->leaveGroup();
236+
}
237+
238+
m_dirty = true;
239+
}
240+
235241
/**
236242
* If the group contains any objects not owned by ownerPlayer, return TRUE.
237243
*/

GeneralsMD/Code/GameEngine/Source/GameLogic/AI/AIPlayer.cpp

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -900,11 +900,11 @@ void AIPlayer::guardSupplyCenter( Team *team, Int minSupplies )
900900
}
901901
if (warehouse) {
902902

903-
AIGroup* theGroup = TheAI->createGroup();
903+
RefCountPtr<AIGroup> theGroup = TheAI->createGroup();
904904
if (!theGroup) {
905905
return;
906906
}
907-
team->getTeamAsAIGroup(theGroup);
907+
team->getTeamAsAIGroup(theGroup.Peek());
908908
Coord3D location = *warehouse->getPosition();
909909
// It's probably a defensive move - position towards the enemy.
910910
Region2D bounds;
@@ -2796,9 +2796,9 @@ void AIPlayer::checkReadyTeams( void )
27962796
/*
27972797
if (team->m_team->getPrototype()->getTemplateInfo()->m_hasHomeLocation &&
27982798
!team->m_reinforcement) {
2799-
AIGroup* theGroup = TheAI->createGroup();
2799+
RefCountPtr<AIGroup> theGroup = TheAI->createGroup();
28002800
if (theGroup) {
2801-
team->m_team->getTeamAsAIGroup(theGroup);
2801+
team->m_team->getTeamAsAIGroup(theGroup.Peek());
28022802
Coord3D destination = team->m_team->getPrototype()->getTemplateInfo()->m_homeLocation;
28032803
theGroup->groupTightenToPosition( &destination, false, CMD_FROM_AI );
28042804
team->m_frameStarted = TheGameLogic->getFrame();

GeneralsMD/Code/GameEngine/Source/GameLogic/AI/AIStates.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4171,8 +4171,8 @@ StateReturnType AIFollowWaypointPathState::update()
41714171
if (m_moveAsGroup) {
41724172
if (obj->getControllingPlayer()->isSkirmishAIPlayer()) {
41734173
Team *team = obj->getTeam();
4174-
AIGroup *group = TheAI->createGroup();
4175-
team->getTeamAsAIGroup(group);
4174+
RefCountPtr<AIGroup> group = TheAI->createGroup();
4175+
team->getTeamAsAIGroup(group.Peek());
41764176

41774177
Coord3D pos;
41784178
group->getCenter(&pos);

GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Object.cpp

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -645,9 +645,8 @@ Object::~Object()
645645
ThePartitionManager->unRegisterObject( this );
646646

647647
// if we are in a group, remove us
648-
if (m_group)
649-
m_group->remove( this );
650-
648+
leaveGroup();
649+
651650
// note, do NOT free these, there are just a shadow copy!
652651
m_ai = NULL;
653652
m_physics = NULL;
@@ -4371,7 +4370,7 @@ void Object::xfer( Xfer *xfer )
43714370
}
43724371

43734372
// Doesn't need to be saved. These are created as needed. jba.
4374-
//AIGroup* m_group; ///< if non-NULL, we are part of this group of agents
4373+
//m_group;
43754374

43764375
// don't need to save m_partitionData.
43774376
DEBUG_ASSERTCRASH(!(xfer->getXferMode() == XFER_LOAD && m_partitionData == NULL), ("should not be in partitionmgr yet"));
@@ -6284,7 +6283,7 @@ RadarPriorityType Object::getRadarPriority( void ) const
62846283
// ------------------------------------------------------------------------------------------------
62856284
AIGroup *Object::getGroup(void)
62866285
{
6287-
return m_group;
6286+
return m_group.Peek();
62886287
}
62896288

62906289
//-------------------------------------------------------------------------------------------------
@@ -6294,7 +6293,7 @@ void Object::enterGroup( AIGroup *group )
62946293
// if we are in another group, remove ourselves from it first
62956294
leaveGroup();
62966295

6297-
m_group = group;
6296+
m_group = RefCountPtr<AIGroup>::Create_AddRef(group);
62986297
}
62996298

63006299
//-------------------------------------------------------------------------------------------------
@@ -6305,7 +6304,7 @@ void Object::leaveGroup( void )
63056304
if (m_group)
63066305
{
63076306
// to avoid recursion, set m_group to NULL before removing
6308-
AIGroup *group = m_group;
6307+
RefCountPtr<AIGroup> group = m_group;
63096308
m_group = NULL;
63106309
group->remove( this );
63116310
}

0 commit comments

Comments
 (0)