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
22 changes: 22 additions & 0 deletions Core/GameEngine/Include/GameClient/View.h
Original file line number Diff line number Diff line change
Expand Up @@ -331,5 +331,27 @@ class ViewLocation
}
};

// TheSuperHackers @feature bobtista 31/01/2026
// View that does nothing. Used for Headless Mode.
class ViewDummy : public View
Comment on lines +334 to +336
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The new ViewDummy block adds // TheSuperHackers @feature bobtista ... comments. If this repository is enforcing the standardized prologue/no-author-comments rule, these author-tag comments may violate that convention even though they aren't in the file prologue. Consider removing the author attribution and keeping only the functional description (e.g. “Dummy view used for headless mode”).

Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

Prompt To Fix With AI
This is a comment left during a code review.
Path: Core/GameEngine/Include/GameClient/View.h
Line: 334:336

Comment:
The new `ViewDummy` block adds `// TheSuperHackers @feature bobtista ...` comments. If this repository is enforcing the standardized prologue/no-author-comments rule, these author-tag comments may violate that convention even though they aren't in the file prologue. Consider removing the author attribution and keeping only the functional description (e.g. “Dummy view used for headless mode”).

<sub>Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!</sub>

How can I resolve this? If you propose a fix, please make it concise.

Comment on lines +334 to +336
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[P0] ViewDummy no longer overrides xfer(), but it also doesn’t provide any serialization behavior of its own. If headless mode saves are expected to be loadable in non-headless mode, the view block still needs to be written/read in a compatible way (either by calling View::xfer(xfer) or by writing a compatible stub block). Otherwise, headless-created saves may be missing view data or desync snapshot CRC/state.

If the intent is “dummy view but still serialize base view state”, explicitly add virtual void xfer(Xfer* xfer) override { View::xfer(xfer); }.

Prompt To Fix With AI
This is a comment left during a code review.
Path: Core/GameEngine/Include/GameClient/View.h
Line: 334:336

Comment:
[P0] `ViewDummy` no longer overrides `xfer()`, but it also doesn’t provide any serialization behavior of its own. If headless mode saves are expected to be loadable in non-headless mode, the view block still needs to be written/read in a compatible way (either by calling `View::xfer(xfer)` or by writing a compatible stub block). Otherwise, headless-created saves may be missing view data or desync snapshot CRC/state.

If the intent is “dummy view but still serialize base view state”, explicitly add `virtual void xfer(Xfer* xfer) override { View::xfer(xfer); }`.

How can I resolve this? If you propose a fix, please make it concise.

Comment on lines +334 to +336
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[P2] The new ViewDummy includes author-tag comments (// TheSuperHackers @feature bobtista ...). If this repo is trying to keep attribution out of code comments (and especially out of headers), consider replacing these with a short functional comment (e.g., // Dummy view used in headless mode). This keeps the header consistent with the rest of the codebase’s style conventions.

Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

Prompt To Fix With AI
This is a comment left during a code review.
Path: Core/GameEngine/Include/GameClient/View.h
Line: 334:336

Comment:
[P2] The new `ViewDummy` includes author-tag comments (`// TheSuperHackers @feature bobtista ...`). If this repo is trying to keep attribution out of code comments (and especially out of headers), consider replacing these with a short functional comment (e.g., `// Dummy view used in headless mode`). This keeps the header consistent with the rest of the codebase’s style conventions.

<sub>Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!</sub>

How can I resolve this? If you propose a fix, please make it concise.

{
public:
virtual Drawable *pickDrawable( const ICoord2D *screen, Bool forceAttack, PickType pickType ) { return nullptr; }
Comment on lines +337 to +339
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[P3] Several ViewDummy overrides put the body on the same line as the signature (e.g., forceRedraw() {}). If you’re following the project’s breakpoint-friendly formatting rule, expand these to put the body on its own line.

Also appears in Generals*/.../W3DInGameUI.h for createView().

Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

Prompt To Fix With AI
This is a comment left during a code review.
Path: Core/GameEngine/Include/GameClient/View.h
Line: 337:339

Comment:
[P3] Several `ViewDummy` overrides put the body on the same line as the signature (e.g., `forceRedraw() {}`). If you’re following the project’s breakpoint-friendly formatting rule, expand these to put the body on its own line.

Also appears in `Generals*/.../W3DInGameUI.h` for `createView()`.

<sub>Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!</sub>

How can I resolve this? If you propose a fix, please make it concise.

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 ) {}

Comment on lines +339 to +351
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ViewDummy overrides many methods with one-liners on the same line as the signature (e.g. virtual void forceRedraw() {}). If the project rule is to keep bodies on separate lines for breakpoint placement, these should be expanded.

This pattern also appears in Generals*/Code/GameEngineDevice/Include/W3DDevice/GameClient/W3DInGameUI.h for createView().

Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

Prompt To Fix With AI
This is a comment left during a code review.
Path: Core/GameEngine/Include/GameClient/View.h
Line: 339:351

Comment:
`ViewDummy` overrides many methods with one-liners on the same line as the signature (e.g. `virtual void forceRedraw() {}`). If the project rule is to keep bodies on separate lines for breakpoint placement, these should be expanded.

This pattern also appears in `Generals*/Code/GameEngineDevice/Include/W3DDevice/GameClient/W3DInGameUI.h` for `createView()`.

<sub>Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!</sub>

How can I resolve this? If you propose a fix, please make it concise.

// 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 //////////////////////////////////////////////////////////////////////////////////////
extern View *TheTacticalView; ///< the main tactical interface to the game world
6 changes: 3 additions & 3 deletions Generals/Code/GameEngine/Source/GameClient/InGameUI.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1240,17 +1240,17 @@ void InGameUI::init( void )
been moved to where all the other translators are attached in game client */

// create the tactical view
if (TheDisplay)
TheTacticalView = createView();
Comment on lines 1240 to +1243
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[P0] TheTacticalView is now always created, but setDefaultView() is only called when TheDisplay exists. Even if View::setDefaultView() is currently a no-op, derived view implementations (e.g., W3DView) may rely on it to initialize camera defaults; in headless mode this can leave view state uninitialized while still being used by non-display code paths.

Consider calling TheTacticalView->setDefaultView(0.0f, 0.0f, 1.0f); unconditionally after createView() (guarded only by TheTacticalView), and keep only init/attach/size under the display check.

Prompt To Fix With AI
This is a comment left during a code review.
Path: Generals/Code/GameEngine/Source/GameClient/InGameUI.cpp
Line: 1240:1243

Comment:
[P0] `TheTacticalView` is now always created, but `setDefaultView()` is only called when `TheDisplay` exists. Even if `View::setDefaultView()` is currently a no-op, derived view implementations (e.g., `W3DView`) may rely on it to initialize camera defaults; in headless mode this can leave view state uninitialized while still being used by non-display code paths.

Consider calling `TheTacticalView->setDefaultView(0.0f, 0.0f, 1.0f);` unconditionally after `createView()` (guarded only by `TheTacticalView`), and keep only `init/attach/size` under the display check.

How can I resolve this? If you propose a fix, please make it concise.

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);
}
Comment on lines 1242 to 1253
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

TheTacticalView->setDefaultView(...) is now only called inside the if (TheTacticalView && TheDisplay) block. In headless mode (or any scenario where TheDisplay == nullptr), this skips setting the view's default parameters, which can leave downstream code reading uninitialized/incorrect view defaults.

If the intent is “always create the view, always set its default parameters, but only init/attach/size when a display exists”, consider moving setDefaultView(0.0f, 0.0f, 1.0f) back outside the display check (guarded only by TheTacticalView).

Prompt To Fix With AI
This is a comment left during a code review.
Path: Generals/Code/GameEngine/Source/GameClient/InGameUI.cpp
Line: 1242:1253

Comment:
`TheTacticalView->setDefaultView(...)` is now only called inside the `if (TheTacticalView && TheDisplay)` block. In headless mode (or any scenario where `TheDisplay == nullptr`), this skips setting the view's default parameters, which can leave downstream code reading uninitialized/incorrect view defaults.

If the intent is “always create the view, always set its default parameters, but only init/attach/size when a display exists”, consider moving `setDefaultView(0.0f, 0.0f, 1.0f)` back outside the display check (guarded only by `TheTacticalView`).

How can I resolve this? If you propose a fix, please make it concise.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is an empty no-op function in the base class, so calling or not calling it makes no difference. In headless mode, a ViewDummy is used which doesn't need camera defaults since there's no camera.

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 */
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -69,7 +70,8 @@ class W3DInGameUI : public InGameUI
protected:

/// factory for views
Comment on lines 70 to 72
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[P0] createView() dereferences TheGlobalData unconditionally (TheGlobalData->m_headless). If W3DInGameUI::init() (or any caller of createView()) can run before TheGlobalData is initialized, this will crash on startup.

Either guard (if (TheGlobalData && TheGlobalData->m_headless) ...) or add an assertion documenting the initialization order guarantee.

Prompt To Fix With AI
This is a comment left during a code review.
Path: Generals/Code/GameEngineDevice/Include/W3DDevice/GameClient/W3DInGameUI.h
Line: 70:72

Comment:
[P0] `createView()` dereferences `TheGlobalData` unconditionally (`TheGlobalData->m_headless`). If `W3DInGameUI::init()` (or any caller of `createView()`) can run before `TheGlobalData` is initialized, this will crash on startup.

Either guard (`if (TheGlobalData && TheGlobalData->m_headless) ...`) or add an assertion documenting the initialization order guarantee.

How can I resolve this? If you propose a fix, please make it concise.

virtual View *createView( void ) { return NEW W3DView; }
// TheSuperHackers @fix bobtista 31/01/2026 Return dummy in headless mode
virtual View *createView( void ) { return TheGlobalData->m_headless ? static_cast<View*>(NEW ViewDummy) : NEW W3DView; }

virtual void drawSelectionRegion( void ); ///< draw the selection region on screen
virtual void drawMoveHints( View *view ); ///< draw move hint visual feedback
Expand Down
6 changes: 3 additions & 3 deletions GeneralsMD/Code/GameEngine/Source/GameClient/InGameUI.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1270,17 +1270,17 @@ void InGameUI::init( void )
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 */
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -69,7 +70,8 @@ class W3DInGameUI : public InGameUI
protected:

/// factory for views
virtual View *createView( void ) { return NEW W3DView; }
// TheSuperHackers @fix bobtista 31/01/2026 Return dummy in headless mode
virtual View *createView( void ) { return TheGlobalData->m_headless ? static_cast<View*>(NEW ViewDummy) : NEW W3DView; }

virtual void drawSelectionRegion( void ); ///< draw the selection region on screen
virtual void drawMoveHints( View *view ); ///< draw move hint visual feedback
Expand Down
Loading