From 180d1f745502ba82c8ac4bdb695bc138d94f480c Mon Sep 17 00:00:00 2001 From: Bobby Battista Date: Mon, 2 Feb 2026 13:36:15 -0600 Subject: [PATCH 1/4] feature(headless): Add GhostObjectManagerDummy for headless mode --- .../GameEngine/Include/GameLogic/GhostObject.h | 14 ++++++++++++++ .../Include/W3DDevice/GameLogic/W3DGameLogic.h | 4 +++- 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/GeneralsMD/Code/GameEngine/Include/GameLogic/GhostObject.h b/GeneralsMD/Code/GameEngine/Include/GameLogic/GhostObject.h index 7f2dbf14365..4307f3b0162 100644 --- a/GeneralsMD/Code/GameEngine/Include/GameLogic/GhostObject.h +++ b/GeneralsMD/Code/GameEngine/Include/GameLogic/GhostObject.h @@ -108,5 +108,19 @@ inline Bool GhostObjectManager::trackAllPlayers() const #endif } +// TheSuperHackers @feature bobtista 19/01/2026 +// GhostObjectManager that does nothing for headless mode. +// Note: Does NOT override crc/xfer/loadPostProcess to maintain save compatibility. +class GhostObjectManagerDummy : public GhostObjectManager +{ +public: + virtual void reset(void) {} + virtual GhostObject *addGhostObject(Object *object, PartitionData *pd) { return nullptr; } + virtual void removeGhostObject(GhostObject *mod) {} + virtual void updateOrphanedObjects(int *playerIndexList, int playerIndexCount) {} + virtual void releasePartitionData(void) {} + virtual void restorePartitionData(void) {} +}; + // the singleton extern GhostObjectManager *TheGhostObjectManager; diff --git a/GeneralsMD/Code/GameEngineDevice/Include/W3DDevice/GameLogic/W3DGameLogic.h b/GeneralsMD/Code/GameEngineDevice/Include/W3DDevice/GameLogic/W3DGameLogic.h index c6bb4f4c7f8..521d3bdb30b 100644 --- a/GeneralsMD/Code/GameEngineDevice/Include/W3DDevice/GameLogic/W3DGameLogic.h +++ b/GeneralsMD/Code/GameEngineDevice/Include/W3DDevice/GameLogic/W3DGameLogic.h @@ -36,6 +36,7 @@ // SYSTEM INCLUDES //////////////////////////////////////////////////////////// // USER INCLUDES ////////////////////////////////////////////////////////////// +#include "Common/GlobalData.h" #include "GameLogic/GameLogic.h" #include "W3DDevice/GameLogic/W3DTerrainLogic.h" #include "W3DDevice/GameLogic/W3DGhostObject.h" @@ -59,6 +60,7 @@ class W3DGameLogic : public GameLogic /// factory for TheTerrainLogic, called from init() virtual TerrainLogic *createTerrainLogic( void ) { return NEW W3DTerrainLogic; }; - virtual GhostObjectManager *createGhostObjectManager(void) { return NEW W3DGhostObjectManager; } + // TheSuperHackers @feature bobtista 19/01/2026 Use dummy for headless mode + virtual GhostObjectManager *createGhostObjectManager(void) { return TheGlobalData->m_headless ? static_cast(NEW GhostObjectManagerDummy) : NEW W3DGhostObjectManager; } }; From 949e4c9298f926f4ddc83af220d424175b8a39ce Mon Sep 17 00:00:00 2001 From: Bobby Battista Date: Mon, 2 Feb 2026 13:37:04 -0600 Subject: [PATCH 2/4] feature(headless): Replicate GhostObjectManagerDummy to Generals --- .../GameEngine/Include/GameLogic/GhostObject.h | 14 ++++++++++++++ .../Include/W3DDevice/GameLogic/W3DGameLogic.h | 4 +++- 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/Generals/Code/GameEngine/Include/GameLogic/GhostObject.h b/Generals/Code/GameEngine/Include/GameLogic/GhostObject.h index 17ea737e919..f8e96e37b03 100644 --- a/Generals/Code/GameEngine/Include/GameLogic/GhostObject.h +++ b/Generals/Code/GameEngine/Include/GameLogic/GhostObject.h @@ -108,5 +108,19 @@ inline Bool GhostObjectManager::trackAllPlayers() const #endif } +// TheSuperHackers @feature bobtista 19/01/2026 +// GhostObjectManager that does nothing for headless mode. +// Note: Does NOT override crc/xfer/loadPostProcess to maintain save compatibility. +class GhostObjectManagerDummy : public GhostObjectManager +{ +public: + virtual void reset(void) {} + virtual GhostObject *addGhostObject(Object *object, PartitionData *pd) { return nullptr; } + virtual void removeGhostObject(GhostObject *mod) {} + virtual void updateOrphanedObjects(int *playerIndexList, int playerIndexCount) {} + virtual void releasePartitionData(void) {} + virtual void restorePartitionData(void) {} +}; + // the singleton extern GhostObjectManager *TheGhostObjectManager; diff --git a/Generals/Code/GameEngineDevice/Include/W3DDevice/GameLogic/W3DGameLogic.h b/Generals/Code/GameEngineDevice/Include/W3DDevice/GameLogic/W3DGameLogic.h index 24c774d8e76..2a92a46d637 100644 --- a/Generals/Code/GameEngineDevice/Include/W3DDevice/GameLogic/W3DGameLogic.h +++ b/Generals/Code/GameEngineDevice/Include/W3DDevice/GameLogic/W3DGameLogic.h @@ -36,6 +36,7 @@ // SYSTEM INCLUDES //////////////////////////////////////////////////////////// // USER INCLUDES ////////////////////////////////////////////////////////////// +#include "Common/GlobalData.h" #include "GameLogic/GameLogic.h" #include "W3DDevice/GameLogic/W3DTerrainLogic.h" #include "W3DDevice/GameLogic/W3DGhostObject.h" @@ -59,6 +60,7 @@ class W3DGameLogic : public GameLogic /// factory for TheTerrainLogic, called from init() virtual TerrainLogic *createTerrainLogic( void ) { return NEW W3DTerrainLogic; }; - virtual GhostObjectManager *createGhostObjectManager(void) { return NEW W3DGhostObjectManager; } + // TheSuperHackers @feature bobtista 19/01/2026 Use dummy for headless mode + virtual GhostObjectManager *createGhostObjectManager(void) { return TheGlobalData->m_headless ? static_cast(NEW GhostObjectManagerDummy) : NEW W3DGhostObjectManager; } }; From f8639cd87b50985bc86c33d7785c062bdf6eeed3 Mon Sep 17 00:00:00 2001 From: Bobby Battista Date: Mon, 2 Feb 2026 17:04:37 -0600 Subject: [PATCH 3/4] refactor(headless): Remove redundant 3DScene null check now handled by dummy --- .../Source/W3DDevice/GameLogic/W3DGhostObject.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/GeneralsMD/Code/GameEngineDevice/Source/W3DDevice/GameLogic/W3DGhostObject.cpp b/GeneralsMD/Code/GameEngineDevice/Source/W3DDevice/GameLogic/W3DGhostObject.cpp index 4e8a78c5498..25bec35c9a9 100644 --- a/GeneralsMD/Code/GameEngineDevice/Source/W3DDevice/GameLogic/W3DGhostObject.cpp +++ b/GeneralsMD/Code/GameEngineDevice/Source/W3DDevice/GameLogic/W3DGhostObject.cpp @@ -157,7 +157,7 @@ void W3DRenderObjectSnapshot::update(RenderObjClass *robj, DrawableInfo *drawInf // ------------------------------------------------------------------------------------------------ Bool W3DRenderObjectSnapshot::addToScene(void) { - if (W3DDisplay::m_3DScene != nullptr && !m_robj->Is_In_Scene()) + if (!m_robj->Is_In_Scene()) { W3DDisplay::m_3DScene->Add_Render_Object(m_robj); return true; From 4d12a95be780a234356b5f4a4b00d210801a6c33 Mon Sep 17 00:00:00 2001 From: Bobby Battista Date: Mon, 2 Feb 2026 17:04:44 -0600 Subject: [PATCH 4/4] refactor(headless): Replicate 3DScene null check removal to Generals --- .../Source/W3DDevice/GameLogic/W3DGhostObject.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Generals/Code/GameEngineDevice/Source/W3DDevice/GameLogic/W3DGhostObject.cpp b/Generals/Code/GameEngineDevice/Source/W3DDevice/GameLogic/W3DGhostObject.cpp index fa46b30411f..e284cbbd59c 100644 --- a/Generals/Code/GameEngineDevice/Source/W3DDevice/GameLogic/W3DGhostObject.cpp +++ b/Generals/Code/GameEngineDevice/Source/W3DDevice/GameLogic/W3DGhostObject.cpp @@ -153,7 +153,7 @@ void W3DRenderObjectSnapshot::update(RenderObjClass *robj, DrawableInfo *drawInf // ------------------------------------------------------------------------------------------------ Bool W3DRenderObjectSnapshot::addToScene(void) { - if (W3DDisplay::m_3DScene != nullptr && !m_robj->Is_In_Scene()) + if (!m_robj->Is_In_Scene()) { W3DDisplay::m_3DScene->Add_Render_Object(m_robj); return true;