Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 0 additions & 7 deletions Core/GameEngine/Include/Common/Radar.h
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,6 @@ class RadarObject : public MemoryPoolObject,
const RadarObject *friend_getNext( void ) const { return m_next; }

Bool isTemporarilyHidden() const;
static Bool isTemporarilyHidden(const Object* obj);

protected:

Expand Down Expand Up @@ -258,12 +257,6 @@ class Radar : public Snapshot,
* in exactly the same priority as the regular
* object list for all other objects */

// TheSuperHackers @bugfix xezon 22/11/2025 Now stores local heroes in a separate list,
// because they are treated with special icons but should otherwise work like all other
// radar objects. In retail version, the cached hero object data was able to dangle
// for a few frames and cause undefined behavior.
RadarObject *m_localHeroObjectList; ///< list of hero objects for the local player

Real m_terrainAverageZ; ///< average Z for terrain samples
Real m_waterAverageZ; ///< average Z for water samples

Expand Down
84 changes: 6 additions & 78 deletions Core/GameEngine/Source/Common/System/Radar.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,6 @@ void Radar::deleteListResources( void )
{
deleteList(&m_objectList);
deleteList(&m_localObjectList);
deleteList(&m_localHeroObjectList);

#ifdef DEBUG_CRASHING
for( Object *obj = TheGameLogic->getFirstObject(); obj; obj = obj->getNextObject() )
Expand Down Expand Up @@ -115,14 +114,8 @@ RadarObject::~RadarObject( void )
//-------------------------------------------------------------------------------------------------
Bool RadarObject::isTemporarilyHidden() const
{
return isTemporarilyHidden(m_object);
}
Drawable* draw = m_object->getDrawable();

//-------------------------------------------------------------------------------------------------
//-------------------------------------------------------------------------------------------------
Bool RadarObject::isTemporarilyHidden(const Object* obj)
{
Drawable* draw = obj->getDrawable();
if (draw == nullptr || draw->getStealthLook() == STEALTHLOOK_INVISIBLE || draw->isDrawableEffectivelyHidden())
return true;

Expand Down Expand Up @@ -192,7 +185,6 @@ Radar::Radar( void )
m_radarWindow = nullptr;
m_objectList = nullptr;
m_localObjectList = nullptr;
m_localHeroObjectList = nullptr;
std::fill(m_radarHidden, m_radarHidden + ARRAY_SIZE(m_radarHidden), false);
std::fill(m_radarForceOn, m_radarForceOn + ARRAY_SIZE(m_radarForceOn), false);
m_terrainAverageZ = 0.0f;
Expand Down Expand Up @@ -416,10 +408,7 @@ Bool Radar::addObject( Object *obj )
//
if( obj->isLocallyControlled() )
{
if ( obj->isHero() )
list = &m_localHeroObjectList;
else
list = &m_localObjectList;
list = &m_localObjectList;
}
else
{
Expand Down Expand Up @@ -483,8 +472,6 @@ Bool Radar::removeObject( Object *obj )
if( obj->friend_getRadarData() == nullptr )
return FALSE;

if( deleteFromList( obj, &m_localHeroObjectList ) == TRUE )
return TRUE;
if( deleteFromList( obj, &m_localObjectList ) == TRUE )
return TRUE;
else if( deleteFromList( obj, &m_objectList ) == TRUE )
Expand Down Expand Up @@ -718,14 +705,10 @@ Object *Radar::objectUnderRadarPixel( const ICoord2D *pixel )
// to the radar location
//

// search the local hero object list
obj = searchListForRadarLocationMatch( m_localHeroObjectList, &radar );

// search the local object list if not found
if( obj == nullptr )
obj = searchListForRadarLocationMatch( m_localObjectList, &radar );
// search the local object list
obj = searchListForRadarLocationMatch( m_localObjectList, &radar );

// search all other objects if still not found
// search all other objects if not found
if( obj == nullptr )
obj = searchListForRadarLocationMatch( m_objectList, &radar );

Expand Down Expand Up @@ -1365,7 +1348,6 @@ static void xferRadarObjectList( Xfer *xfer, RadarObject **head )
* Version Info:
* 1: Initial version
* 2: TheSuperHackers @tweak Serialize m_radarHidden, m_radarForceOn for each player
* 3: TheSuperHackers @tweak Serialize m_localHeroObjectList
*/
// ------------------------------------------------------------------------------------------------
void Radar::xfer( Xfer *xfer )
Expand All @@ -1375,7 +1357,7 @@ void Radar::xfer( Xfer *xfer )
#if RETAIL_COMPATIBLE_XFER_SAVE
XferVersion currentVersion = 1;
#else
XferVersion currentVersion = 3;
XferVersion currentVersion = 2;
#endif
XferVersion version = currentVersion;
xfer->xferVersion( &version, currentVersion );
Expand Down Expand Up @@ -1405,66 +1387,12 @@ void Radar::xfer( Xfer *xfer )
xfer->xferUser(&m_radarForceOn, sizeof(m_radarForceOn));
}

if (version <= 2)
{
if (xfer->getXferMode() == XFER_SAVE)
{
// TheSuperHackers @info For legacy xfer compatibility.
// Transfer all local hero objects to local object list.
RadarObject **fromList = &m_localHeroObjectList;
RadarObject **toList = &m_localObjectList;
while (*fromList != nullptr)
{
RadarObject* nextObject = (*fromList)->friend_getNext();
(*fromList)->friend_setNext(nullptr);
linkRadarObject(*fromList, toList);
*fromList = nextObject;
}
}
}
else
{
xferRadarObjectList( xfer, &m_localHeroObjectList );
}

// save our local object list
xferRadarObjectList( xfer, &m_localObjectList );

// save the regular object list
xferRadarObjectList( xfer, &m_objectList );

if (version <= 2)
{
// TheSuperHackers @info For legacy xfer compatibility.
// Transfer hero local object(s) back to local hero object list.
// This needs to be done on both load and save.
RadarObject **fromList = &m_localObjectList;
RadarObject **toList = &m_localHeroObjectList;
RadarObject *currObject;
RadarObject *prevObject;
RadarObject *nextObject;
prevObject = nullptr;
for (currObject = *fromList; currObject != nullptr; currObject = nextObject)
{
nextObject = currObject->friend_getNext();
if (currObject->friend_getObject()->isHero())
{
if (prevObject != nullptr)
{
prevObject->friend_setNext(nextObject);
}
else
{
*fromList = nextObject;
}
currObject->friend_setNext(nullptr);
linkRadarObject(currObject, toList);
continue;
}
prevObject = currObject;
}
}

// save the radar event count and data
UnsignedShort eventCountVerify = MAX_RADAR_EVENTS;
UnsignedShort eventCount = eventCountVerify;
Expand Down
16 changes: 10 additions & 6 deletions Core/GameEngineDevice/Source/W3DDevice/Common/System/W3DRadar.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -607,12 +607,17 @@ void W3DRadar::drawEvents( Int pixelX, Int pixelY, Int width, Int height )
void W3DRadar::drawIcons( Int pixelX, Int pixelY, Int width, Int height )
{
Player *player = rts::getObservedOrLocalPlayer();
for (RadarObject *heroObj = m_localHeroObjectList; heroObj; heroObj = heroObj->friend_getNext())
for (RadarObject *heroObj = m_localObjectList; heroObj; heroObj = heroObj->friend_getNext())
{
if (canRenderObject(heroObj, player))
{
drawHeroIcon(pixelX, pixelY, width, height, heroObj->friend_getObject()->getPosition());
}
const Object *obj = heroObj->friend_getObject();

if (!obj->isHero())
continue;

if (!canRenderObject(heroObj, player))
continue;

drawHeroIcon(pixelX, pixelY, width, height, obj->getPosition());
}
}

Expand All @@ -628,7 +633,6 @@ void W3DRadar::updateObjectTexture(TextureClass *texture)
// rebuild the object overlay
renderObjectList( m_objectList, texture );
renderObjectList( m_localObjectList, texture );
renderObjectList( m_localHeroObjectList, texture );
}

//-------------------------------------------------------------------------------------------------
Expand Down
2 changes: 2 additions & 0 deletions GeneralsMD/Code/GameEngine/Include/Common/TunnelTracker.h
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ class TunnelTracker : public MemoryPoolObject,
// contain list access
void iterateContained( ContainIterateFunc func, void *userData, Bool reverse );
UnsignedInt getContainCount() const { return m_containListSize; }
UnsignedInt getHeroUnitsContained() const { return m_heroUnitsContained; }
Int getContainMax() const;
const ContainedItemsList* getContainedItemsList() const { return &m_containList; }
void swapContainedItemsList(ContainedItemsList& newList);
Expand Down Expand Up @@ -85,6 +86,7 @@ class TunnelTracker : public MemoryPoolObject,
ContainedItemsList m_containList; ///< the contained object pointers list
std::list< ObjectID > m_xferContainList;///< for loading of m_containList during post processing
Int m_containListSize; ///< size of the contain list
UnsignedInt m_heroUnitsContained; ///< cached hero count
UnsignedInt m_tunnelCount; ///< How many tunnels have registered so we know when we should kill our contain list
UnsignedInt m_framesForFullHeal; ///< How many frames it takes to fully heal a unit
Bool m_needsFullHealTimeUpdate; ///< Set to true when needing to recalc full heal time to batch the operation
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -261,7 +261,6 @@ class OpenContain : public UpdateModule,
ObjectEnterExitMap m_objectEnterExitInfo;
UnsignedInt m_stealthUnitsContained; ///< number of stealth units that can't be seen by enemy players.
UnsignedInt m_heroUnitsContained; ///< cached hero count
XferVersion m_xferVersion; ///< version of loaded save file for loadPostProcess
Int m_whichExitPath; ///< Cycles from 1 to n and is used only in modules whose data has numberOfExitPaths > 1.
UnsignedInt m_doorCloseCountdown; ///< When should I shut my door.

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,7 @@ class TunnelContain : public OpenContain, public CreateModuleInterface
// contain list access
virtual void iterateContained( ContainIterateFunc func, void *userData, Bool reverse );
virtual UnsignedInt getContainCount() const;
virtual UnsignedInt getHeroUnitsContained() const;
virtual Int getContainMax( void ) const;
virtual const ContainedItemsList* getContainedItemsList() const;
virtual UnsignedInt getFullTimeForHeal(void) const; ///< Returns the time in frames until a contained object becomes fully healed
Expand Down
16 changes: 15 additions & 1 deletion GeneralsMD/Code/GameEngine/Source/Common/RTS/TunnelTracker.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ TunnelTracker::TunnelTracker()
{
m_tunnelCount = 0;
m_containListSize = 0;
m_heroUnitsContained = 0;
m_curNemesisID = INVALID_ID;
m_nemesisTimestamp = 0;
m_framesForFullHeal = 0;
Expand Down Expand Up @@ -187,6 +188,11 @@ void TunnelTracker::addToContainList( Object *obj )
{
m_containList.push_back(obj);
++m_containListSize;

if (obj->isKindOf(KINDOF_HERO))
{
++m_heroUnitsContained;
}
}

// ------------------------------------------------------------------------
Expand All @@ -199,6 +205,12 @@ void TunnelTracker::removeFromContain( Object *obj, Bool exposeStealthUnits )
// note that this invalidates the iterator!
m_containList.erase(it);
--m_containListSize;

if (obj->isKindOf(KINDOF_HERO))
{
DEBUG_ASSERTCRASH(m_heroUnitsContained > 0, ("TunnelTracker::removeFromContain - Removing hero but hero count is %d", m_heroUnitsContained));
--m_heroUnitsContained;
}
}

}
Expand Down Expand Up @@ -433,6 +445,8 @@ void TunnelTracker::loadPostProcess( void )
}

// translate each object ids on the xferContainList into real object pointers in the contain list
m_containListSize = 0;
m_heroUnitsContained = 0;
Object *obj;
std::list< ObjectID >::const_iterator it;
for( it = m_xferContainList.begin(); it != m_xferContainList.end(); ++it )
Expand All @@ -448,7 +462,7 @@ void TunnelTracker::loadPostProcess( void )
}

// push on the back of the contain list
m_containList.push_back( obj );
addToContainList( obj );

// Crap. This is in OpenContain as a fix, but not here.
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,6 @@ OpenContain::OpenContain( Thing *thing, const ModuleData* moduleData ) : UpdateM
m_containListSize = 0;
m_stealthUnitsContained = 0;
m_heroUnitsContained = 0;
m_xferVersion = 1;
m_doorCloseCountdown = 0;

m_rallyPoint.zero();
Expand Down Expand Up @@ -1681,21 +1680,15 @@ void OpenContain::crc( Xfer *xfer )
* Version Info:
* 1: Initial version
* 2: Added m_passengerAllowedToFire
* 3: TheSuperHackers @tweak Serialize hero units contained count
*/
// ------------------------------------------------------------------------------------------------
void OpenContain::xfer( Xfer *xfer )
{

// version
#if RETAIL_COMPATIBLE_XFER_SAVE
XferVersion currentVersion = 2;
#else
XferVersion currentVersion = 3;
#endif
XferVersion version = currentVersion;
xfer->xferVersion( &version, currentVersion );
m_xferVersion = version;

// extend base class
UpdateModule::xfer( xfer );
Expand All @@ -1720,7 +1713,7 @@ void OpenContain::xfer( Xfer *xfer )
else
{

// the containment list should be emtpy at this time
// the containment list should be empty at this time
if( m_containList.empty() == FALSE )
{
#if 1
Expand Down Expand Up @@ -1769,18 +1762,12 @@ void OpenContain::xfer( Xfer *xfer )
xfer->xferUnsignedInt( &m_lastLoadSoundFrame );

// stealth units contained
xfer->xferUnsignedInt( &m_stealthUnitsContained );

// hero units contained
if (version >= 3)
{
xfer->xferUnsignedInt( &m_heroUnitsContained );
}
xfer->xferUnsignedInt( &m_stealthUnitsContained ); // TheSuperHackers @todo This is redundant information in xfer. Remove it.

// door close countdown
xfer->xferUnsignedInt( &m_doorCloseCountdown );

// conditionstate
// condition state
m_conditionState.xfer( xfer );

// fire points
Expand Down Expand Up @@ -1829,7 +1816,7 @@ void OpenContain::xfer( Xfer *xfer )
else
{

// the map should be emtpy now
// the map should be empty now
if( m_objectEnterExitInfo.empty() == FALSE )
{

Expand Down Expand Up @@ -1887,6 +1874,9 @@ void OpenContain::loadPostProcess( void )
}

// turn the contained id list into actual object pointers in the contain list
m_containListSize = 0;
m_stealthUnitsContained = 0;
m_heroUnitsContained = 0;
Object *obj;
std::list<ObjectID>::const_iterator idIt;
for( idIt = m_xferContainIDList.begin(); idIt != m_xferContainIDList.end(); ++idIt )
Expand All @@ -1905,7 +1895,7 @@ void OpenContain::loadPostProcess( void )
}

// put object on list
m_containList.push_back( obj );
addToContainList( obj );

// remove this object from the world if we need to
if( isEnclosingContainerFor( obj ) )
Expand All @@ -1916,19 +1906,6 @@ void OpenContain::loadPostProcess( void )

}

if (m_xferVersion < 3)
{
// Restore hero count by iterating hero objects for old save versions
m_heroUnitsContained = 0;
for( ContainedItemsList::const_iterator it = m_containList.begin(); it != m_containList.end(); ++it )
{
if( (*it)->isKindOf( KINDOF_HERO ) )
{
m_heroUnitsContained++;
}
}
}

// sanity
DEBUG_ASSERTCRASH( m_containListSize == m_containList.size(),
("OpenContain::loadPostProcess - contain list count mismatch") );
Expand Down
Loading
Loading