Skip to content

Commit 9e9ecdc

Browse files
committed
perf(fps): optimize Object::isHero with cached hero counter
1 parent 35b3f01 commit 9e9ecdc

File tree

9 files changed

+37
-27
lines changed

9 files changed

+37
-27
lines changed

Generals/Code/GameEngine/Include/GameLogic/Module/ContainModule.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -155,6 +155,7 @@ class ContainModuleInterface
155155
virtual const Object *friend_getRider() const = 0; ///< Damn. The draw order dependency bug for riders means that our draw module needs to cheat to get around it.
156156
virtual Real getContainedItemsMass() const = 0;
157157
virtual UnsignedInt getStealthUnitsContained() const = 0;
158+
virtual UnsignedInt getHeroUnitsContained() const = 0;
158159

159160
virtual Bool calcBestGarrisonPosition( Coord3D *sourcePos, const Coord3D *targetPos ) = 0;
160161
virtual Bool attemptBestFirePointPosition( Object *source, Weapon *weapon, Object *victim ) = 0;

Generals/Code/GameEngine/Include/GameLogic/Module/OpenContain.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -164,6 +164,7 @@ class OpenContain : public UpdateModule,
164164
virtual const Object *friend_getRider() const{return NULL;} ///< Damn. The draw order dependency bug for riders means that our draw module needs to cheat to get around it.
165165
virtual Real getContainedItemsMass() const;
166166
virtual UnsignedInt getStealthUnitsContained() const { return m_stealthUnitsContained; }
167+
virtual UnsignedInt getHeroUnitsContained() const { return m_heroUnitsContained; }
167168

168169
virtual PlayerMaskType getPlayerWhoEntered(void) const { return m_playerEnteredMask; }
169170

@@ -238,6 +239,7 @@ class OpenContain : public UpdateModule,
238239

239240
ObjectEnterExitMap m_objectEnterExitInfo;
240241
UnsignedInt m_stealthUnitsContained; ///< number of stealth units that can't be seen by enemy players.
242+
UnsignedInt m_heroUnitsContained; ///< cached hero count
241243
Int m_whichExitPath; ///< Cycles from 1 to n and is used only in modules whose data has numberOfExitPaths > 1.
242244
UnsignedInt m_doorCloseCountdown; ///< When should I shut my door.
243245

Generals/Code/GameEngine/Source/GameLogic/Object/Contain/OpenContain.cpp

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,7 @@ OpenContain::OpenContain( Thing *thing, const ModuleData* moduleData ) : UpdateM
125125
m_lastLoadSoundFrame = 0;
126126
m_containListSize = 0;
127127
m_stealthUnitsContained = 0;
128+
m_heroUnitsContained = 0;
128129
m_doorCloseCountdown = 0;
129130

130131
//Added By Sadullah Nader
@@ -623,7 +624,7 @@ void OpenContain::scatterToNearbyPosition(Object* rider)
623624
}
624625

625626
//-------------------------------------------------------------------------------------------------
626-
void OpenContain::onContaining( Object * /*rider*/ )
627+
void OpenContain::onContaining( Object *rider )
627628
{
628629
// Play audio
629630
if( m_loadSoundsEnabled )
@@ -632,6 +633,12 @@ void OpenContain::onContaining( Object * /*rider*/ )
632633
enterSound.setObjectID(getObject()->getID());
633634
TheAudio->addAudioEvent(&enterSound);
634635
}
636+
637+
// TheSuperHackers @performance bobtista 13/11/2025 Cache hero count to avoid O(n) iteration in Object::isHero().
638+
if( rider && rider->isKindOf( KINDOF_HERO ) )
639+
{
640+
m_heroUnitsContained++;
641+
}
635642
}
636643

637644
//-------------------------------------------------------------------------------------------------
@@ -647,6 +654,11 @@ void OpenContain::onRemoving( Object *rider)
647654
AudioEventRTS fallingSound = *rider->getTemplate()->getSoundFalling();
648655
fallingSound.setObjectID(rider->getID());
649656
TheAudio->addAudioEvent(&fallingSound);
657+
658+
if( rider->isKindOf( KINDOF_HERO ) && m_heroUnitsContained > 0 )
659+
{
660+
m_heroUnitsContained--;
661+
}
650662
}
651663
}
652664

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

Lines changed: 2 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -595,25 +595,14 @@ Object::~Object()
595595
}
596596

597597
//-------------------------------------------------------------------------------------------------
598-
void localIsHero( Object *obj, void* userData )
599-
{
600-
Bool *hero = (Bool*)userData;
601-
602-
if( obj && obj->isKindOf( KINDOF_HERO ) )
603-
{
604-
*hero = TRUE;
605-
}
606-
}
607-
608598
//-------------------------------------------------------------------------------------------------
599+
// TheSuperHackers @performance bobtista 13/11/2025 Use cached hero count for O(1) lookup instead of O(n) iteration.
609600
Bool Object::isHero() const
610601
{
611602
ContainModuleInterface *contain = getContain();
612603
if( contain )
613604
{
614-
Bool heroInside = FALSE;
615-
contain->iterateContained( localIsHero, (void*)(&heroInside), FALSE );
616-
if( heroInside )
605+
if( contain->getHeroUnitsContained() > 0 )
617606
{
618607
return TRUE;
619608
}

GeneralsMD/Code/GameEngine/Include/GameLogic/Module/ContainModule.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -175,6 +175,7 @@ class ContainModuleInterface
175175
virtual const Object *friend_getRider() const = 0; ///< Damn. The draw order dependency bug for riders means that our draw module needs to cheat to get around it.
176176
virtual Real getContainedItemsMass() const = 0;
177177
virtual UnsignedInt getStealthUnitsContained() const = 0;
178+
virtual UnsignedInt getHeroUnitsContained() const = 0;
178179

179180
virtual Bool calcBestGarrisonPosition( Coord3D *sourcePos, const Coord3D *targetPos ) = 0;
180181
virtual Bool attemptBestFirePointPosition( Object *source, Weapon *weapon, Object *victim ) = 0;

GeneralsMD/Code/GameEngine/Include/GameLogic/Module/OpenContain.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -174,6 +174,7 @@ class OpenContain : public UpdateModule,
174174
virtual const Object *friend_getRider() const{return NULL;} ///< Damn. The draw order dependency bug for riders means that our draw module needs to cheat to get around it.
175175
virtual Real getContainedItemsMass() const;
176176
virtual UnsignedInt getStealthUnitsContained() const { return m_stealthUnitsContained; }
177+
virtual UnsignedInt getHeroUnitsContained() const { return m_heroUnitsContained; }
177178

178179
virtual PlayerMaskType getPlayerWhoEntered(void) const { return m_playerEnteredMask; }
179180

@@ -259,6 +260,7 @@ class OpenContain : public UpdateModule,
259260

260261
ObjectEnterExitMap m_objectEnterExitInfo;
261262
UnsignedInt m_stealthUnitsContained; ///< number of stealth units that can't be seen by enemy players.
263+
UnsignedInt m_heroUnitsContained; ///< cached hero count
262264
Int m_whichExitPath; ///< Cycles from 1 to n and is used only in modules whose data has numberOfExitPaths > 1.
263265
UnsignedInt m_doorCloseCountdown; ///< When should I shut my door.
264266

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

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,7 @@ OpenContain::OpenContain( Thing *thing, const ModuleData* moduleData ) : UpdateM
129129
m_lastLoadSoundFrame = 0;
130130
m_containListSize = 0;
131131
m_stealthUnitsContained = 0;
132+
m_heroUnitsContained = 0;
132133
m_doorCloseCountdown = 0;
133134

134135
//Added By Sadullah Nader
@@ -752,6 +753,12 @@ void OpenContain::onContaining( Object *rider, Bool wasSelected )
752753
enterSound.setObjectID(getObject()->getID());
753754
TheAudio->addAudioEvent(&enterSound);
754755
}
756+
757+
// TheSuperHackers @performance bobtista 13/11/2025 Cache hero count to avoid O(n) iteration in Object::isHero().
758+
if( rider && rider->isKindOf( KINDOF_HERO ) )
759+
{
760+
m_heroUnitsContained++;
761+
}
755762
}
756763

757764
//-------------------------------------------------------------------------------------------------
@@ -767,6 +774,11 @@ void OpenContain::onRemoving( Object *rider)
767774
AudioEventRTS fallingSound = *rider->getTemplate()->getSoundFalling();
768775
fallingSound.setObjectID(rider->getID());
769776
TheAudio->addAudioEvent(&fallingSound);
777+
778+
if( rider->isKindOf( KINDOF_HERO ) && m_heroUnitsContained > 0 )
779+
{
780+
m_heroUnitsContained--;
781+
}
770782
}
771783
}
772784

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -184,6 +184,8 @@ Bool RiderChangeContain::isValidContainerFor(const Object* rider, Bool checkCapa
184184
//-------------------------------------------------------------------------------------------------
185185
void RiderChangeContain::onContaining( Object *rider, Bool wasSelected )
186186
{
187+
TransportContain::onContaining( rider, wasSelected );
188+
187189
Object *obj = getObject();
188190
m_containing = TRUE;
189191
//Remove our existing rider

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

Lines changed: 2 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -2028,25 +2028,14 @@ Bool Object::isNonFactionStructure(void) const
20282028
return isStructure() && !isFactionStructure();
20292029
}
20302030

2031-
void localIsHero( Object *obj, void* userData )
2032-
{
2033-
Bool *hero = (Bool*)userData;
2034-
2035-
if( obj && obj->isKindOf( KINDOF_HERO ) )
2036-
{
2037-
*hero = TRUE;
2038-
}
2039-
}
2040-
20412031
//-------------------------------------------------------------------------------------------------
2032+
// TheSuperHackers @performance bobtista 13/11/2025 Use cached hero count for O(1) lookup instead of O(n) iteration.
20422033
Bool Object::isHero(void) const
20432034
{
20442035
ContainModuleInterface *contain = getContain();
20452036
if( contain )
20462037
{
2047-
Bool heroInside = FALSE;
2048-
contain->iterateContained( localIsHero, (void*)(&heroInside), FALSE );
2049-
if( heroInside )
2038+
if( contain->getHeroUnitsContained() > 0 )
20502039
{
20512040
return TRUE;
20522041
}

0 commit comments

Comments
 (0)