From 7db34100e16219e505188ddef8e600da7945420a Mon Sep 17 00:00:00 2001 From: Bobby Battista Date: Mon, 2 Feb 2026 16:41:52 -0600 Subject: [PATCH 01/10] feature(headless): Add ViewDummy for headless mode --- Core/GameEngine/Include/GameClient/View.h | 22 +++++++++++++++++++ .../GameEngine/Source/GameClient/InGameUI.cpp | 6 ++--- .../W3DDevice/GameClient/W3DInGameUI.h | 4 +++- 3 files changed, 28 insertions(+), 4 deletions(-) diff --git a/Core/GameEngine/Include/GameClient/View.h b/Core/GameEngine/Include/GameClient/View.h index 16d7171755b..cacbed83d4b 100644 --- a/Core/GameEngine/Include/GameClient/View.h +++ b/Core/GameEngine/Include/GameClient/View.h @@ -331,5 +331,27 @@ class ViewLocation } }; +// TheSuperHackers @feature bobtista 31/01/2026 +// View that does nothing. Used for Headless Mode. +class ViewDummy : public View +{ +public: + virtual Drawable *pickDrawable( const ICoord2D *screen, Bool forceAttack, PickType pickType ) { return nullptr; } + virtual Int iterateDrawablesInRegion( IRegion2D *screenRegion, Bool (*callback)( Drawable *draw, void *userData ), void *userData ) { return 0; } + virtual void forceRedraw() {} + virtual const Coord3D& get3DCameraPosition() const { static Coord3D zero = {0,0,0}; return zero; } + virtual WorldToScreenReturn worldToScreenTriReturn(const Coord3D *w, ICoord2D *s ) { return WTS_INVALID; } + virtual void screenToWorld( const ICoord2D *s, Coord3D *w ) {} + virtual void screenToTerrain( const ICoord2D *screen, Coord3D *world ) {} + virtual void screenToWorldAtZ( const ICoord2D *s, Coord3D *w, Real z ) {} + virtual void drawView( void ) {} + virtual void updateView(void) {} + virtual void stepView() {} + virtual void setGuardBandBias( const Coord2D *gb ) {} + +protected: + virtual void xfer( Xfer *xfer ) {} +}; + // EXTERNALS ////////////////////////////////////////////////////////////////////////////////////// extern View *TheTacticalView; ///< the main tactical interface to the game world diff --git a/GeneralsMD/Code/GameEngine/Source/GameClient/InGameUI.cpp b/GeneralsMD/Code/GameEngine/Source/GameClient/InGameUI.cpp index 3b852e3f676..d031448ba3f 100644 --- a/GeneralsMD/Code/GameEngine/Source/GameClient/InGameUI.cpp +++ b/GeneralsMD/Code/GameEngine/Source/GameClient/InGameUI.cpp @@ -1367,17 +1367,17 @@ void InGameUI::init() been moved to where all the other translators are attached in game client */ // create the tactical view - if (TheDisplay) + TheTacticalView = createView(); + if (TheTacticalView && TheDisplay) { - TheTacticalView = createView(); TheTacticalView->init(); TheDisplay->attachView( TheTacticalView ); // make the tactical display the full screen width and height TheTacticalView->setWidth( TheDisplay->getWidth() ); TheTacticalView->setHeight( TheDisplay->getHeight() ); + TheTacticalView->setDefaultView(0.0f, 0.0f, 1.0f); } - TheTacticalView->setDefaultView(0.0f, 0.0f, 1.0f); /** @todo this may be the wrong place to create the sidebar, but for now this is where it lives */ diff --git a/GeneralsMD/Code/GameEngineDevice/Include/W3DDevice/GameClient/W3DInGameUI.h b/GeneralsMD/Code/GameEngineDevice/Include/W3DDevice/GameClient/W3DInGameUI.h index f239e05e1f9..e69b349975a 100644 --- a/GeneralsMD/Code/GameEngineDevice/Include/W3DDevice/GameClient/W3DInGameUI.h +++ b/GeneralsMD/Code/GameEngineDevice/Include/W3DDevice/GameClient/W3DInGameUI.h @@ -36,6 +36,7 @@ // SYSTEM INCLUDES //////////////////////////////////////////////////////////// // USER INCLUDES ////////////////////////////////////////////////////////////// +#include "Common/GlobalData.h" #include "GameClient/InGameUI.h" #include "GameClient/View.h" #include "W3DDevice/GameClient/W3DView.h" @@ -69,7 +70,8 @@ class W3DInGameUI : public InGameUI protected: /// factory for views - virtual View *createView() { return NEW W3DView; } + // TheSuperHackers @fix bobtista 31/01/2026 Return dummy in headless mode + virtual View *createView() { return TheGlobalData->m_headless ? NEW ViewDummy : NEW W3DView; } virtual void drawSelectionRegion(); ///< draw the selection region on screen virtual void drawMoveHints( View *view ); ///< draw move hint visual feedback From 8509cf8e9b5c86ba1e149d6a4bac94fdab5fe1e0 Mon Sep 17 00:00:00 2001 From: Bobby Battista Date: Mon, 2 Feb 2026 16:42:31 -0600 Subject: [PATCH 02/10] feature(headless): Replicate ViewDummy to Generals --- Generals/Code/GameEngine/Source/GameClient/InGameUI.cpp | 6 +++--- .../Include/W3DDevice/GameClient/W3DInGameUI.h | 4 +++- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/Generals/Code/GameEngine/Source/GameClient/InGameUI.cpp b/Generals/Code/GameEngine/Source/GameClient/InGameUI.cpp index a7c70a70f7b..87e66bad696 100644 --- a/Generals/Code/GameEngine/Source/GameClient/InGameUI.cpp +++ b/Generals/Code/GameEngine/Source/GameClient/InGameUI.cpp @@ -1337,17 +1337,17 @@ void InGameUI::init() been moved to where all the other translators are attached in game client */ // create the tactical view - if (TheDisplay) + TheTacticalView = createView(); + if (TheTacticalView && TheDisplay) { - TheTacticalView = createView(); TheTacticalView->init(); TheDisplay->attachView( TheTacticalView ); // make the tactical display the full screen width and height TheTacticalView->setWidth( TheDisplay->getWidth() ); TheTacticalView->setHeight( TheDisplay->getHeight() ); + TheTacticalView->setDefaultView(0.0f, 0.0f, 1.0f); } - TheTacticalView->setDefaultView(0.0f, 0.0f, 1.0f); /** @todo this may be the wrong place to create the sidebar, but for now this is where it lives */ diff --git a/Generals/Code/GameEngineDevice/Include/W3DDevice/GameClient/W3DInGameUI.h b/Generals/Code/GameEngineDevice/Include/W3DDevice/GameClient/W3DInGameUI.h index 02109bc27cd..f2e54e3b231 100644 --- a/Generals/Code/GameEngineDevice/Include/W3DDevice/GameClient/W3DInGameUI.h +++ b/Generals/Code/GameEngineDevice/Include/W3DDevice/GameClient/W3DInGameUI.h @@ -36,6 +36,7 @@ // SYSTEM INCLUDES //////////////////////////////////////////////////////////// // USER INCLUDES ////////////////////////////////////////////////////////////// +#include "Common/GlobalData.h" #include "GameClient/InGameUI.h" #include "GameClient/View.h" #include "W3DDevice/GameClient/W3DView.h" @@ -69,7 +70,8 @@ class W3DInGameUI : public InGameUI protected: /// factory for views - virtual View *createView() { return NEW W3DView; } + // TheSuperHackers @fix bobtista 31/01/2026 Return dummy in headless mode + virtual View *createView() { return TheGlobalData->m_headless ? NEW ViewDummy : NEW W3DView; } virtual void drawSelectionRegion(); ///< draw the selection region on screen virtual void drawMoveHints( View *view ); ///< draw move hint visual feedback From ed1c2fb6ae33eb3566b02d40302c20a41eef8710 Mon Sep 17 00:00:00 2001 From: Bobby Battista Date: Tue, 3 Feb 2026 13:06:12 -0600 Subject: [PATCH 03/10] bugfix(headless): Fix ViewDummy xfer save corruption and VC6 ternary build error --- Core/GameEngine/Include/GameClient/View.h | 4 ++-- .../Include/W3DDevice/GameClient/W3DInGameUI.h | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Core/GameEngine/Include/GameClient/View.h b/Core/GameEngine/Include/GameClient/View.h index cacbed83d4b..3a5daed192f 100644 --- a/Core/GameEngine/Include/GameClient/View.h +++ b/Core/GameEngine/Include/GameClient/View.h @@ -349,8 +349,8 @@ class ViewDummy : public View virtual void stepView() {} virtual void setGuardBandBias( const Coord2D *gb ) {} -protected: - virtual void xfer( Xfer *xfer ) {} + // TheSuperHackers @bugfix bobtista 03/02/2026 Do not override View::xfer(). The base + // implementation must run to serialize valid view state for save file compatibility. }; // EXTERNALS ////////////////////////////////////////////////////////////////////////////////////// diff --git a/GeneralsMD/Code/GameEngineDevice/Include/W3DDevice/GameClient/W3DInGameUI.h b/GeneralsMD/Code/GameEngineDevice/Include/W3DDevice/GameClient/W3DInGameUI.h index e69b349975a..7998c19319a 100644 --- a/GeneralsMD/Code/GameEngineDevice/Include/W3DDevice/GameClient/W3DInGameUI.h +++ b/GeneralsMD/Code/GameEngineDevice/Include/W3DDevice/GameClient/W3DInGameUI.h @@ -71,7 +71,7 @@ class W3DInGameUI : public InGameUI /// factory for views // TheSuperHackers @fix bobtista 31/01/2026 Return dummy in headless mode - virtual View *createView() { return TheGlobalData->m_headless ? NEW ViewDummy : NEW W3DView; } + virtual View *createView() { return TheGlobalData->m_headless ? static_cast(NEW ViewDummy) : NEW W3DView; } virtual void drawSelectionRegion(); ///< draw the selection region on screen virtual void drawMoveHints( View *view ); ///< draw move hint visual feedback From a9f47a3db98734fd06b5320d3652bd84a3f2ab76 Mon Sep 17 00:00:00 2001 From: Bobby Battista Date: Tue, 3 Feb 2026 13:06:16 -0600 Subject: [PATCH 04/10] bugfix(headless): Replicate VC6 ternary build fix to Generals --- .../GameEngineDevice/Include/W3DDevice/GameClient/W3DInGameUI.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Generals/Code/GameEngineDevice/Include/W3DDevice/GameClient/W3DInGameUI.h b/Generals/Code/GameEngineDevice/Include/W3DDevice/GameClient/W3DInGameUI.h index f2e54e3b231..5ee0562d738 100644 --- a/Generals/Code/GameEngineDevice/Include/W3DDevice/GameClient/W3DInGameUI.h +++ b/Generals/Code/GameEngineDevice/Include/W3DDevice/GameClient/W3DInGameUI.h @@ -71,7 +71,7 @@ class W3DInGameUI : public InGameUI /// factory for views // TheSuperHackers @fix bobtista 31/01/2026 Return dummy in headless mode - virtual View *createView() { return TheGlobalData->m_headless ? NEW ViewDummy : NEW W3DView; } + virtual View *createView() { return TheGlobalData->m_headless ? static_cast(NEW ViewDummy) : NEW W3DView; } virtual void drawSelectionRegion(); ///< draw the selection region on screen virtual void drawMoveHints( View *view ); ///< draw move hint visual feedback From e439eee5c8a282472cbd3c8d82994025d491227d Mon Sep 17 00:00:00 2001 From: Bobby Battista Date: Tue, 24 Feb 2026 09:56:25 -0500 Subject: [PATCH 05/10] style: Expand inline function bodies to multi-line for breakpoint-friendly formatting --- Core/GameEngine/Include/GameClient/View.h | 53 ++++++++++++++----- .../W3DDevice/GameClient/W3DInGameUI.h | 5 +- .../W3DDevice/GameClient/W3DInGameUI.h | 5 +- 3 files changed, 49 insertions(+), 14 deletions(-) diff --git a/Core/GameEngine/Include/GameClient/View.h b/Core/GameEngine/Include/GameClient/View.h index 3a5daed192f..8d1e9ebac55 100644 --- a/Core/GameEngine/Include/GameClient/View.h +++ b/Core/GameEngine/Include/GameClient/View.h @@ -336,18 +336,47 @@ class ViewLocation class ViewDummy : public View { public: - virtual Drawable *pickDrawable( const ICoord2D *screen, Bool forceAttack, PickType pickType ) { return nullptr; } - virtual Int iterateDrawablesInRegion( IRegion2D *screenRegion, Bool (*callback)( Drawable *draw, void *userData ), void *userData ) { return 0; } - virtual void forceRedraw() {} - virtual const Coord3D& get3DCameraPosition() const { static Coord3D zero = {0,0,0}; return zero; } - virtual WorldToScreenReturn worldToScreenTriReturn(const Coord3D *w, ICoord2D *s ) { return WTS_INVALID; } - virtual void screenToWorld( const ICoord2D *s, Coord3D *w ) {} - virtual void screenToTerrain( const ICoord2D *screen, Coord3D *world ) {} - virtual void screenToWorldAtZ( const ICoord2D *s, Coord3D *w, Real z ) {} - virtual void drawView( void ) {} - virtual void updateView(void) {} - virtual void stepView() {} - virtual void setGuardBandBias( const Coord2D *gb ) {} + virtual Drawable *pickDrawable( const ICoord2D *screen, Bool forceAttack, PickType pickType ) + { + return nullptr; + } + virtual Int iterateDrawablesInRegion( IRegion2D *screenRegion, Bool (*callback)( Drawable *draw, void *userData ), void *userData ) + { + return 0; + } + virtual void forceRedraw() + { + } + virtual const Coord3D& get3DCameraPosition() const + { + static Coord3D zero = {0,0,0}; + return zero; + } + virtual WorldToScreenReturn worldToScreenTriReturn(const Coord3D *w, ICoord2D *s ) + { + return WTS_INVALID; + } + virtual void screenToWorld( const ICoord2D *s, Coord3D *w ) + { + } + virtual void screenToTerrain( const ICoord2D *screen, Coord3D *world ) + { + } + virtual void screenToWorldAtZ( const ICoord2D *s, Coord3D *w, Real z ) + { + } + virtual void drawView( void ) + { + } + virtual void updateView(void) + { + } + virtual void stepView() + { + } + virtual void setGuardBandBias( const Coord2D *gb ) + { + } // TheSuperHackers @bugfix bobtista 03/02/2026 Do not override View::xfer(). The base // implementation must run to serialize valid view state for save file compatibility. diff --git a/Generals/Code/GameEngineDevice/Include/W3DDevice/GameClient/W3DInGameUI.h b/Generals/Code/GameEngineDevice/Include/W3DDevice/GameClient/W3DInGameUI.h index 5ee0562d738..e60bdb5dc06 100644 --- a/Generals/Code/GameEngineDevice/Include/W3DDevice/GameClient/W3DInGameUI.h +++ b/Generals/Code/GameEngineDevice/Include/W3DDevice/GameClient/W3DInGameUI.h @@ -71,7 +71,10 @@ class W3DInGameUI : public InGameUI /// factory for views // TheSuperHackers @fix bobtista 31/01/2026 Return dummy in headless mode - virtual View *createView() { return TheGlobalData->m_headless ? static_cast(NEW ViewDummy) : NEW W3DView; } + virtual View *createView() + { + return TheGlobalData->m_headless ? static_cast(NEW ViewDummy) : NEW W3DView; + } virtual void drawSelectionRegion(); ///< draw the selection region on screen virtual void drawMoveHints( View *view ); ///< draw move hint visual feedback diff --git a/GeneralsMD/Code/GameEngineDevice/Include/W3DDevice/GameClient/W3DInGameUI.h b/GeneralsMD/Code/GameEngineDevice/Include/W3DDevice/GameClient/W3DInGameUI.h index 7998c19319a..03886aa6e9f 100644 --- a/GeneralsMD/Code/GameEngineDevice/Include/W3DDevice/GameClient/W3DInGameUI.h +++ b/GeneralsMD/Code/GameEngineDevice/Include/W3DDevice/GameClient/W3DInGameUI.h @@ -71,7 +71,10 @@ class W3DInGameUI : public InGameUI /// factory for views // TheSuperHackers @fix bobtista 31/01/2026 Return dummy in headless mode - virtual View *createView() { return TheGlobalData->m_headless ? static_cast(NEW ViewDummy) : NEW W3DView; } + virtual View *createView() + { + return TheGlobalData->m_headless ? static_cast(NEW ViewDummy) : NEW W3DView; + } virtual void drawSelectionRegion(); ///< draw the selection region on screen virtual void drawMoveHints( View *view ); ///< draw move hint visual feedback From dc7c2fa82b9e2577f251c73ff8696135988a1b0d Mon Sep 17 00:00:00 2001 From: Bobby Battista Date: Wed, 18 Mar 2026 17:14:43 -0400 Subject: [PATCH 06/10] refactor(headless): Add override, shorten empty bodies, pass dummy bool arg in GeneralsMD ViewDummy --- Core/GameEngine/Include/GameClient/View.h | 40 ++++++------------- .../GameEngine/Include/GameClient/InGameUI.h | 2 +- .../GameEngine/Source/GameClient/InGameUI.cpp | 2 +- .../W3DDevice/GameClient/W3DInGameUI.h | 8 ++-- 4 files changed, 18 insertions(+), 34 deletions(-) diff --git a/Core/GameEngine/Include/GameClient/View.h b/Core/GameEngine/Include/GameClient/View.h index 8d1e9ebac55..42b54137f99 100644 --- a/Core/GameEngine/Include/GameClient/View.h +++ b/Core/GameEngine/Include/GameClient/View.h @@ -336,47 +336,31 @@ class ViewLocation class ViewDummy : public View { public: - virtual Drawable *pickDrawable( const ICoord2D *screen, Bool forceAttack, PickType pickType ) + virtual Drawable *pickDrawable( const ICoord2D *screen, Bool forceAttack, PickType pickType ) override { return nullptr; } - virtual Int iterateDrawablesInRegion( IRegion2D *screenRegion, Bool (*callback)( Drawable *draw, void *userData ), void *userData ) + virtual Int iterateDrawablesInRegion( IRegion2D *screenRegion, Bool (*callback)( Drawable *draw, void *userData ), void *userData ) override { return 0; } - virtual void forceRedraw() - { - } - virtual const Coord3D& get3DCameraPosition() const + virtual void forceRedraw() override {} + virtual const Coord3D& get3DCameraPosition() const override { static Coord3D zero = {0,0,0}; return zero; } - virtual WorldToScreenReturn worldToScreenTriReturn(const Coord3D *w, ICoord2D *s ) + virtual WorldToScreenReturn worldToScreenTriReturn(const Coord3D *w, ICoord2D *s ) override { return WTS_INVALID; } - virtual void screenToWorld( const ICoord2D *s, Coord3D *w ) - { - } - virtual void screenToTerrain( const ICoord2D *screen, Coord3D *world ) - { - } - virtual void screenToWorldAtZ( const ICoord2D *s, Coord3D *w, Real z ) - { - } - virtual void drawView( void ) - { - } - virtual void updateView(void) - { - } - virtual void stepView() - { - } - virtual void setGuardBandBias( const Coord2D *gb ) - { - } + virtual void screenToWorld( const ICoord2D *s, Coord3D *w ) override {} + virtual void screenToTerrain( const ICoord2D *screen, Coord3D *world ) override {} + virtual void screenToWorldAtZ( const ICoord2D *s, Coord3D *w, Real z ) override {} + virtual void drawView( void ) override {} + virtual void updateView(void) override {} + virtual void stepView() override {} + virtual void setGuardBandBias( const Coord2D *gb ) override {} // TheSuperHackers @bugfix bobtista 03/02/2026 Do not override View::xfer(). The base // implementation must run to serialize valid view state for save file compatibility. diff --git a/GeneralsMD/Code/GameEngine/Include/GameClient/InGameUI.h b/GeneralsMD/Code/GameEngine/Include/GameClient/InGameUI.h index 2ed0c91abfd..a7f1d05866e 100644 --- a/GeneralsMD/Code/GameEngine/Include/GameClient/InGameUI.h +++ b/GeneralsMD/Code/GameEngine/Include/GameClient/InGameUI.h @@ -689,7 +689,7 @@ friend class Drawable; // for selection/deselection transactions void incrementSelectCount() { ++m_selectCount; } ///< Increase by one the running total of "selected" drawables void decrementSelectCount() { --m_selectCount; } ///< Decrease by one the running total of "selected" drawables - virtual View *createView() = 0; ///< Factory for Views + virtual View *createView(bool dummy = false) = 0; ///< Factory for Views void evaluateSoloNexus( Drawable *newlyAddedDrawable = nullptr ); /// expire a hint from of the specified type at the hint index diff --git a/GeneralsMD/Code/GameEngine/Source/GameClient/InGameUI.cpp b/GeneralsMD/Code/GameEngine/Source/GameClient/InGameUI.cpp index d031448ba3f..f43748cba86 100644 --- a/GeneralsMD/Code/GameEngine/Source/GameClient/InGameUI.cpp +++ b/GeneralsMD/Code/GameEngine/Source/GameClient/InGameUI.cpp @@ -1367,7 +1367,7 @@ void InGameUI::init() been moved to where all the other translators are attached in game client */ // create the tactical view - TheTacticalView = createView(); + TheTacticalView = createView(TheGlobalData->m_headless); if (TheTacticalView && TheDisplay) { TheTacticalView->init(); diff --git a/GeneralsMD/Code/GameEngineDevice/Include/W3DDevice/GameClient/W3DInGameUI.h b/GeneralsMD/Code/GameEngineDevice/Include/W3DDevice/GameClient/W3DInGameUI.h index 03886aa6e9f..9b7c49dfc4c 100644 --- a/GeneralsMD/Code/GameEngineDevice/Include/W3DDevice/GameClient/W3DInGameUI.h +++ b/GeneralsMD/Code/GameEngineDevice/Include/W3DDevice/GameClient/W3DInGameUI.h @@ -36,7 +36,6 @@ // SYSTEM INCLUDES //////////////////////////////////////////////////////////// // USER INCLUDES ////////////////////////////////////////////////////////////// -#include "Common/GlobalData.h" #include "GameClient/InGameUI.h" #include "GameClient/View.h" #include "W3DDevice/GameClient/W3DView.h" @@ -70,10 +69,11 @@ class W3DInGameUI : public InGameUI protected: /// factory for views - // TheSuperHackers @fix bobtista 31/01/2026 Return dummy in headless mode - virtual View *createView() + virtual View *createView(bool dummy) { - return TheGlobalData->m_headless ? static_cast(NEW ViewDummy) : NEW W3DView; + if (dummy) + return NEW ViewDummy; + return NEW W3DView; } virtual void drawSelectionRegion(); ///< draw the selection region on screen From 9a38f16175716d4e3f0f4ac58050146b6cdee630 Mon Sep 17 00:00:00 2001 From: Bobby Battista Date: Wed, 18 Mar 2026 17:17:30 -0400 Subject: [PATCH 07/10] refactor(headless): Pass dummy bool arg in Generals ViewDummy, remove GlobalData include --- Generals/Code/GameEngine/Include/GameClient/InGameUI.h | 2 +- Generals/Code/GameEngine/Source/GameClient/InGameUI.cpp | 2 +- .../Include/W3DDevice/GameClient/W3DInGameUI.h | 8 ++++---- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/Generals/Code/GameEngine/Include/GameClient/InGameUI.h b/Generals/Code/GameEngine/Include/GameClient/InGameUI.h index a64ba0c95e9..54487f2f419 100644 --- a/Generals/Code/GameEngine/Include/GameClient/InGameUI.h +++ b/Generals/Code/GameEngine/Include/GameClient/InGameUI.h @@ -669,7 +669,7 @@ friend class Drawable; // for selection/deselection transactions void incrementSelectCount() { ++m_selectCount; } ///< Increase by one the running total of "selected" drawables void decrementSelectCount() { --m_selectCount; } ///< Decrease by one the running total of "selected" drawables - virtual View *createView() = 0; ///< Factory for Views + virtual View *createView(bool dummy = false) = 0; ///< Factory for Views void evaluateSoloNexus( Drawable *newlyAddedDrawable = nullptr ); /// expire a hint from of the specified type at the hint index diff --git a/Generals/Code/GameEngine/Source/GameClient/InGameUI.cpp b/Generals/Code/GameEngine/Source/GameClient/InGameUI.cpp index 87e66bad696..2b4498bcec4 100644 --- a/Generals/Code/GameEngine/Source/GameClient/InGameUI.cpp +++ b/Generals/Code/GameEngine/Source/GameClient/InGameUI.cpp @@ -1337,7 +1337,7 @@ void InGameUI::init() been moved to where all the other translators are attached in game client */ // create the tactical view - TheTacticalView = createView(); + TheTacticalView = createView(TheGlobalData->m_headless); if (TheTacticalView && TheDisplay) { TheTacticalView->init(); diff --git a/Generals/Code/GameEngineDevice/Include/W3DDevice/GameClient/W3DInGameUI.h b/Generals/Code/GameEngineDevice/Include/W3DDevice/GameClient/W3DInGameUI.h index e60bdb5dc06..cc84fe56c17 100644 --- a/Generals/Code/GameEngineDevice/Include/W3DDevice/GameClient/W3DInGameUI.h +++ b/Generals/Code/GameEngineDevice/Include/W3DDevice/GameClient/W3DInGameUI.h @@ -36,7 +36,6 @@ // SYSTEM INCLUDES //////////////////////////////////////////////////////////// // USER INCLUDES ////////////////////////////////////////////////////////////// -#include "Common/GlobalData.h" #include "GameClient/InGameUI.h" #include "GameClient/View.h" #include "W3DDevice/GameClient/W3DView.h" @@ -70,10 +69,11 @@ class W3DInGameUI : public InGameUI protected: /// factory for views - // TheSuperHackers @fix bobtista 31/01/2026 Return dummy in headless mode - virtual View *createView() + virtual View *createView(bool dummy) { - return TheGlobalData->m_headless ? static_cast(NEW ViewDummy) : NEW W3DView; + if (dummy) + return NEW ViewDummy; + return NEW W3DView; } virtual void drawSelectionRegion(); ///< draw the selection region on screen From 9d7a2f669b70a507089a4a8649ffcdf0dacd0144 Mon Sep 17 00:00:00 2001 From: Bobby Battista Date: Wed, 18 Mar 2026 17:40:56 -0400 Subject: [PATCH 08/10] bugfix(headless): Remove spurious screenToWorld override from ViewDummy --- Core/GameEngine/Include/GameClient/View.h | 1 - 1 file changed, 1 deletion(-) diff --git a/Core/GameEngine/Include/GameClient/View.h b/Core/GameEngine/Include/GameClient/View.h index 42b54137f99..8b8d448e115 100644 --- a/Core/GameEngine/Include/GameClient/View.h +++ b/Core/GameEngine/Include/GameClient/View.h @@ -354,7 +354,6 @@ class ViewDummy : public View { return WTS_INVALID; } - virtual void screenToWorld( const ICoord2D *s, Coord3D *w ) override {} virtual void screenToTerrain( const ICoord2D *screen, Coord3D *world ) override {} virtual void screenToWorldAtZ( const ICoord2D *s, Coord3D *w, Real z ) override {} virtual void drawView( void ) override {} From 374af7da906678845be2829265f15759b0927225 Mon Sep 17 00:00:00 2001 From: Bobby Battista Date: Wed, 18 Mar 2026 17:46:07 -0400 Subject: [PATCH 09/10] bugfix(headless): Add missing pure virtual overrides to ViewDummy --- Core/GameEngine/Include/GameClient/View.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Core/GameEngine/Include/GameClient/View.h b/Core/GameEngine/Include/GameClient/View.h index 8b8d448e115..a465d495f78 100644 --- a/Core/GameEngine/Include/GameClient/View.h +++ b/Core/GameEngine/Include/GameClient/View.h @@ -360,6 +360,8 @@ class ViewDummy : public View virtual void updateView(void) override {} virtual void stepView() override {} virtual void setGuardBandBias( const Coord2D *gb ) override {} + virtual Bool isDoingScriptedCamera() override { return false; } + virtual void stopDoingScriptedCamera() override {} // TheSuperHackers @bugfix bobtista 03/02/2026 Do not override View::xfer(). The base // implementation must run to serialize valid view state for save file compatibility. From ab5f7a5afec123bf5a533a06299b409177ed502e Mon Sep 17 00:00:00 2001 From: Bobby Battista Date: Thu, 19 Mar 2026 16:30:01 -0400 Subject: [PATCH 10/10] refactor(headless): Remove TheSuperHackers tag from ViewDummy xfer comment in View.h --- Core/GameEngine/Include/GameClient/View.h | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Core/GameEngine/Include/GameClient/View.h b/Core/GameEngine/Include/GameClient/View.h index a465d495f78..683fb39294c 100644 --- a/Core/GameEngine/Include/GameClient/View.h +++ b/Core/GameEngine/Include/GameClient/View.h @@ -363,8 +363,7 @@ class ViewDummy : public View virtual Bool isDoingScriptedCamera() override { return false; } virtual void stopDoingScriptedCamera() override {} - // TheSuperHackers @bugfix bobtista 03/02/2026 Do not override View::xfer(). The base - // implementation must run to serialize valid view state for save file compatibility. + // Do not override View::xfer(). The base implementation must run to serialize valid view state for save file compatibility. }; // EXTERNALS //////////////////////////////////////////////////////////////////////////////////////