Skip to content

Commit 743f11d

Browse files
committed
bugfix(ghostobject): Properly refresh real and ghost objects when changing the local player in the Ghost Object Manager (#1569)
1 parent 98f6cd1 commit 743f11d

File tree

12 files changed

+158
-63
lines changed

12 files changed

+158
-63
lines changed

Core/Libraries/Source/WWVegas/WW3D2/rendobj.cpp

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -807,24 +807,27 @@ void RenderObjClass::Add(SceneClass * scene)
807807
* 11/04/1997 GH : Created. *
808808
* 2/25/99 GTH : moved to the base RenderObjClass *
809809
*=============================================================================================*/
810-
void RenderObjClass::Remove(void)
810+
bool RenderObjClass::Remove(void)
811811
{
812812
// All render objects have their scene pointers set. To check if this is a "top level"
813813
// object, (i.e. directly in the scene) you see if its Container pointer is NULL.
814814
#if 1
815815
if (Container == NULL) {
816816
if (Scene != NULL) {
817817
Scene->Remove_Render_Object(this);
818-
return;
818+
return true;
819819
}
820+
return false;
820821
} else {
821822
Container->Remove_Sub_Object(this);
822-
return;
823+
return true;
823824
}
824825
#else
825-
if (!Scene) return;
826+
if (!Scene)
827+
return false;
826828
Scene->Remove_Render_Object(this);
827829
Scene = NULL;
830+
return true;
828831
#endif
829832
}
830833

Core/Libraries/Source/WWVegas/WW3D2/rendobj.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -265,7 +265,7 @@ class RenderObjClass : public RefCountClass , public PersistClass, public MultiL
265265
// as small as possible
266266
///////////////////////////////////////////////////////////////////////////////////////////////////////////////
267267
virtual void Add(SceneClass * scene);
268-
virtual void Remove(void);
268+
virtual bool Remove(void);
269269
virtual SceneClass * Get_Scene(void);
270270
virtual SceneClass * Peek_Scene(void) { return Scene; }
271271
virtual void Set_Container(RenderObjClass * con);

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -391,6 +391,7 @@ class Object : public Thing, public Snapshot
391391
void friend_setPartitionData(PartitionData *pd) { m_partitionData = pd; }
392392
PartitionData *friend_getPartitionData() const { return m_partitionData; }
393393
const PartitionData *friend_getConstPartitionData() const { return m_partitionData; }
394+
Bool hasGhostObject() const; ///< This object has a ghost object. This does not imply that a ghost snapshot is taken or active.
394395

395396
void onPartitionCellChange();///< We have moved a 'significant' amount, so do maintenence that can be considered 'cell-based'
396397
void handlePartitionCellMaintenance(); ///< Undo and redo all shroud actions. Call when something has changed, like position or ownership or Death

Generals/Code/GameEngine/Source/GameClient/GameClient.cpp

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -655,11 +655,16 @@ void GameClient::update( void )
655655
{
656656
if (TheGhostObjectManager->trackAllPlayers())
657657
{
658-
Int *playerIndex = nonLocalPlayerIndices;
659-
Int *const playerIndexEnd = nonLocalPlayerIndices + numNonLocalPlayers;
660-
for (; playerIndex < playerIndexEnd; ++playerIndex)
658+
// TheSuperHackers @info Update the shrouded status for all objects
659+
// that own a ghost object for all non local players. This is costly.
660+
if (object->hasGhostObject())
661661
{
662-
object->getShroudedStatus(*playerIndex);
662+
Int *playerIndex = nonLocalPlayerIndices;
663+
Int *const playerIndexEnd = nonLocalPlayerIndices + numNonLocalPlayers;
664+
for (; playerIndex < playerIndexEnd; ++playerIndex)
665+
{
666+
object->getShroudedStatus(*playerIndex);
667+
}
663668
}
664669
}
665670

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

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4198,6 +4198,15 @@ void Object::adjustModelConditionForWeaponStatus()
41984198
}
41994199
}
42004200

4201+
//-------------------------------------------------------------------------------------------------
4202+
Bool Object::hasGhostObject() const
4203+
{
4204+
if (m_partitionData == NULL)
4205+
return false;
4206+
4207+
return m_partitionData->getGhostObject() != NULL;
4208+
}
4209+
42014210
//-------------------------------------------------------------------------------------------------
42024211
/// We have moved a 'significant' amount, so do maintenence that can be considered 'cell-based'
42034212
void Object::onPartitionCellChange()

Generals/Code/GameEngineDevice/Include/W3DDevice/GameLogic/W3DGhostObject.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -59,8 +59,8 @@ class W3DGhostObject: public GhostObject
5959
virtual void loadPostProcess( void );
6060
void removeParentObject(void);
6161
void restoreParentObject(void); ///< restore the original non-ghosted object to scene.
62-
void addToScene(int playerIndex);
63-
void removeFromScene(int playerIndex);
62+
Bool addToScene(int playerIndex);
63+
Bool removeFromScene(int playerIndex);
6464
ObjectShroudStatus getShroudStatus(int playerIndex); ///< used to get the partition manager to update ghost objects without parent objects.
6565
void freeAllSnapShots(void); ///< used to free all snapshots from all players.
6666

Generals/Code/GameEngineDevice/Source/W3DDevice/GameLogic/W3DGhostObject.cpp

Lines changed: 54 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -63,8 +63,8 @@ class W3DRenderObjectSnapshot : public Snapshot
6363
~W3DRenderObjectSnapshot() {REF_PTR_RELEASE(m_robj);}
6464

6565
inline void update(RenderObjClass *robj, DrawableInfo *drawInfo, Bool cloneParentRobj = TRUE); ///<refresh the current snapshot with latest state
66-
inline void addToScene(void); ///< add this fogged render object to the scene.
67-
inline void removeFromScene(); ///< remove this fogged render object from the scene.
66+
inline Bool addToScene(void); ///< add this fogged render object to the scene.
67+
inline Bool removeFromScene(); ///< remove this fogged render object from the scene.
6868

6969
protected:
7070

@@ -151,17 +151,21 @@ void W3DRenderObjectSnapshot::update(RenderObjClass *robj, DrawableInfo *drawInf
151151

152152
// ------------------------------------------------------------------------------------------------
153153
// ------------------------------------------------------------------------------------------------
154-
void W3DRenderObjectSnapshot::addToScene(void)
154+
Bool W3DRenderObjectSnapshot::addToScene(void)
155155
{
156156
if (!m_robj->Is_In_Scene())
157+
{
157158
W3DDisplay::m_3DScene->Add_Render_Object(m_robj);
159+
return true;
160+
}
161+
return false;
158162
}
159163

160164
// ------------------------------------------------------------------------------------------------
161165
// ------------------------------------------------------------------------------------------------
162-
void W3DRenderObjectSnapshot::removeFromScene()
166+
Bool W3DRenderObjectSnapshot::removeFromScene()
163167
{
164-
m_robj->Remove();
168+
return m_robj->Remove();
165169
}
166170

167171
// ------------------------------------------------------------------------------------------------
@@ -531,29 +535,37 @@ void W3DGhostObject::updateParentObject(Object *object, PartitionData *mod)
531535
// ------------------------------------------------------------------------------------------------
532536
/**Remove the dummy render objects from scene that belong to given player*/
533537
// ------------------------------------------------------------------------------------------------
534-
void W3DGhostObject::removeFromScene(int playerIndex)
538+
Bool W3DGhostObject::removeFromScene(int playerIndex)
535539
{
536540
W3DRenderObjectSnapshot *snap = m_parentSnapshots[playerIndex];
537541

542+
Bool removed = false;
543+
538544
while (snap)
539545
{
540-
snap->removeFromScene();
546+
removed |= snap->removeFromScene();
541547
snap = snap->m_next;
542548
}
549+
550+
return removed;
543551
}
544552

545553
// ------------------------------------------------------------------------------------------------
546554
/**Add the dummy render objects to scene so player sees the correct version within the fog*/
547555
// ------------------------------------------------------------------------------------------------
548-
void W3DGhostObject::addToScene(int playerIndex)
556+
Bool W3DGhostObject::addToScene(int playerIndex)
549557
{
550558
W3DRenderObjectSnapshot *snap = m_parentSnapshots[playerIndex];
551559

560+
Bool added = false;
561+
552562
while (snap)
553563
{
554-
snap->addToScene();
564+
added |= snap->addToScene();
555565
snap = snap->m_next;
556566
}
567+
568+
return added;
557569
}
558570

559571
// ------------------------------------------------------------------------------------------------
@@ -923,38 +935,57 @@ GhostObject *W3DGhostObjectManager::addGhostObject(Object *object, PartitionData
923935
// ------------------------------------------------------------------------------------------------
924936
void W3DGhostObjectManager::setLocalPlayerIndex(int playerIndex)
925937
{
938+
const int oldPlayerIndex = getLocalPlayerIndex();
939+
940+
if (playerIndex == oldPlayerIndex)
941+
return;
942+
943+
GhostObjectManager::setLocalPlayerIndex(playerIndex);
944+
926945
//Whenever we switch local players, we need to remove all ghost objects belonging
927946
//to another player from the map. We then insert the current local player's
928947
//ghost objects into the map.
948+
// TheSuperHackers @bugfix xezon 06/09/2025 This function now properly
949+
// updates ghost objects and real objects when changing players.
929950

930951
W3DGhostObject *mod = m_usedModules;
931952

932953
while (mod)
933954
{
934-
mod->removeFromScene(m_localPlayer);
955+
const Bool oldGhostRemoved = mod->removeFromScene(oldPlayerIndex);
956+
const ObjectShroudStatus newShroudStatus = mod->getShroudStatus(playerIndex);
957+
Bool newGhostAdded = false;
935958

936-
if (mod->m_parentSnapshots[playerIndex])
959+
if (newShroudStatus >= OBJECTSHROUD_FOGGED)
937960
{
938-
//new player has his own snapshot
939-
if (!mod->m_parentSnapshots[m_localPlayer])
940-
{
941-
//previous player didn't have a snapshot so real object must
942-
//have been in the scene. Replace it with our snapshot.
943-
mod->removeParentObject();
944-
}
945-
mod->addToScene(playerIndex);
961+
newGhostAdded = mod->addToScene(playerIndex);
946962
}
947-
else if (mod->m_parentSnapshots[m_localPlayer])
963+
964+
if (oldGhostRemoved && !newGhostAdded)
948965
{
949-
//new player doesn't have a snapshot which means restore original object
950-
//if it was replaced by a snapshot by the previous player.
951966
mod->restoreParentObject();
952967
}
968+
else if (!oldGhostRemoved && newGhostAdded)
969+
{
970+
mod->removeParentObject();
971+
}
953972

954973
mod = mod->m_nextSystem;
955974
}
956975

957-
GhostObjectManager::setLocalPlayerIndex(playerIndex);
976+
// TheSuperHackers @bugfix xezon 06/09/2025 This function now properly updates
977+
// all real objects when changing players without waiting for another logic step.
978+
// This is particularly noticeable when changing the player while the game is paused.
979+
for (Drawable* draw = TheGameClient->firstDrawable(); draw != NULL; draw = draw->getNextDrawable())
980+
{
981+
Object* obj = draw->getObject();
982+
if (obj == NULL)
983+
continue;
984+
985+
const ObjectShroudStatus shroudStatus = obj->getShroudedStatus(playerIndex);
986+
const Bool shrouded = shroudStatus >= OBJECTSHROUD_FOGGED;
987+
draw->setFullyObscuredByShroud(shrouded);
988+
}
958989
}
959990

960991
// ------------------------------------------------------------------------------------------------

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -416,6 +416,7 @@ class Object : public Thing, public Snapshot
416416
void friend_setPartitionData(PartitionData *pd) { m_partitionData = pd; }
417417
PartitionData *friend_getPartitionData() const { return m_partitionData; }
418418
const PartitionData *friend_getConstPartitionData() const { return m_partitionData; }
419+
Bool hasGhostObject() const; ///< This object has a ghost object. This does not imply that a ghost snapshot is taken or active.
419420

420421
void onPartitionCellChange();///< We have moved a 'significant' amount, so do maintenence that can be considered 'cell-based'
421422
void handlePartitionCellMaintenance(); ///< Undo and redo all shroud actions. Call when something has changed, like position or ownership or Death

GeneralsMD/Code/GameEngine/Source/GameClient/GameClient.cpp

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -693,11 +693,16 @@ void GameClient::update( void )
693693
{
694694
if (TheGhostObjectManager->trackAllPlayers())
695695
{
696-
Int *playerIndex = nonLocalPlayerIndices;
697-
Int *const playerIndexEnd = nonLocalPlayerIndices + numNonLocalPlayers;
698-
for (; playerIndex < playerIndexEnd; ++playerIndex)
696+
// TheSuperHackers @info Update the shrouded status for all objects
697+
// that own a ghost object for all non local players. This is costly.
698+
if (object->hasGhostObject())
699699
{
700-
object->getShroudedStatus(*playerIndex);
700+
Int *playerIndex = nonLocalPlayerIndices;
701+
Int *const playerIndexEnd = nonLocalPlayerIndices + numNonLocalPlayers;
702+
for (; playerIndex < playerIndexEnd; ++playerIndex)
703+
{
704+
object->getShroudedStatus(*playerIndex);
705+
}
701706
}
702707
}
703708

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

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4763,6 +4763,15 @@ void Object::adjustModelConditionForWeaponStatus()
47634763
}
47644764
}
47654765

4766+
//-------------------------------------------------------------------------------------------------
4767+
Bool Object::hasGhostObject() const
4768+
{
4769+
if (m_partitionData == NULL)
4770+
return false;
4771+
4772+
return m_partitionData->getGhostObject() != NULL;
4773+
}
4774+
47664775
//-------------------------------------------------------------------------------------------------
47674776
/// We have moved a 'significant' amount, so do maintenence that can be considered 'cell-based'
47684777
void Object::onPartitionCellChange()

0 commit comments

Comments
 (0)