Skip to content

feature(headless): Add ViewDummy for headless mode#2246

Open
bobtista wants to merge 5 commits intoTheSuperHackers:mainfrom
bobtista:bobtista/view-dummy
Open

feature(headless): Add ViewDummy for headless mode#2246
bobtista wants to merge 5 commits intoTheSuperHackers:mainfrom
bobtista:bobtista/view-dummy

Conversation

@bobtista
Copy link

@bobtista bobtista commented Feb 2, 2026

Summary

  • Adds ViewDummy class in Core/GameEngine/Include/GameClient/View.h with no-op implementations for headless mode
  • Factory in W3DInGameUI returns dummy when m_headless is true
  • Refactors InGameUI::init() to always create TheTacticalView, but only init/attach to display when TheDisplay exists
  • Empty xfer() to skip view block in saves

Related

Split from #2139 per @xezon's suggestion to review each dummy class separately.

@greptile-apps
Copy link

greptile-apps bot commented Feb 2, 2026

Greptile Summary

Adds ViewDummy class to support headless mode by providing no-op implementations of view interface methods. The factory method in W3DInGameUI returns the dummy when headless flag is set, and InGameUI::init() has been refactored to create the view unconditionally but only initialize/attach when display exists.

  • Correctly avoids overriding View::xfer() to preserve save file compatibility
  • Properly expands inline function bodies to multi-line format for breakpoint placement
  • Uses appropriate 2026 dates in comments
  • One potential null dereference of TheGlobalData needs addressing

Confidence Score: 4/5

  • Safe to merge with one minor fix for null pointer safety
  • The implementation is well-structured and addresses previous review feedback properly. The ViewDummy class correctly avoids overriding xfer() for save compatibility, and the refactored initialization logic cleanly separates view creation from display attachment. The only issue is the unconditional dereference of TheGlobalData in two files, which could cause a crash if the initialization order is unexpected. This is a defensive fix that should be applied before merging.
  • Pay attention to W3DInGameUI.h files (both Generals and GeneralsMD) for the null pointer check

Important Files Changed

Filename Overview
Core/GameEngine/Include/GameClient/View.h Added ViewDummy class with no-op implementations for headless mode; properly avoids overriding xfer() to maintain save compatibility
Generals/Code/GameEngineDevice/Include/W3DDevice/GameClient/W3DInGameUI.h Modified createView() to return ViewDummy when headless, dereferences TheGlobalData without null check
GeneralsMD/Code/GameEngineDevice/Include/W3DDevice/GameClient/W3DInGameUI.h Modified createView() to return ViewDummy when headless, dereferences TheGlobalData without null check

Class Diagram

%%{init: {'theme': 'neutral'}}%%
classDiagram
    class View {
        <<abstract>>
        +xfer(Xfer* xfer)
        +init()
        +drawView()
        +updateView()
        +stepView()
    }
    
    class ViewDummy {
        +pickDrawable() nullptr
        +iterateDrawablesInRegion() 0
        +forceRedraw() no-op
        +get3DCameraPosition() zero
        +worldToScreenTriReturn() WTS_INVALID
        +screenToWorld() no-op
        +drawView() no-op
        +updateView() no-op
        +stepView() no-op
        Note: Does NOT override xfer()
    }
    
    class W3DView {
        +init()
        +drawView()
        +updateView()
    }
    
    class W3DInGameUI {
        -m_headless: bool
        +createView() View*
    }
    
    View <|-- ViewDummy : inherits
    View <|-- W3DView : inherits
    W3DInGameUI --> View : creates
    W3DInGameUI ..> ViewDummy : when headless
    W3DInGameUI ..> W3DView : when graphical
Loading

Last reviewed commit: e439eee

Copy link

@greptile-apps greptile-apps bot left a comment

Choose a reason for hiding this comment

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

5 files reviewed, 5 comments

Edit Code Review Agent Settings | Greptile

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

Comment on lines 334 to 354
// 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 ) {}
};
Copy link

Choose a reason for hiding this comment

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

ViewDummy::xfer() is overridden to a no-op, which will prevent the base View snapshot data from being serialized/deserialized. This can corrupt saves/replays if a headless-generated save is later loaded in a non-headless context, or if any code expects View::xfer() to run to keep snapshot CRC/state consistent.

If the goal is to skip only view blocks during save, it may be safer to keep calling View::xfer(xfer) (or gate the no-op on xfer->getXferMode() / a headless flag) rather than fully disabling serialization for this type.

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

Comment:
`ViewDummy::xfer()` is overridden to a no-op, which will prevent the base `View` snapshot data from being serialized/deserialized. This can corrupt saves/replays if a headless-generated save is later loaded in a non-headless context, or if any code expects `View::xfer()` to run to keep snapshot CRC/state consistent.

If the goal is to skip only view *blocks* during save, it may be safer to keep calling `View::xfer(xfer)` (or gate the no-op on `xfer->getXferMode()` / a headless flag) rather than fully disabling serialization for this type.

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.

Do we ever plan on generating saves in headless mode, then loading them in full graphics mode? If yes, this is worth addressing

Copy link

Choose a reason for hiding this comment

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

Based on the context from PR #2139, I can see that the goal is to support saving games in headless mode and loading them later. The testing checklist even includes "Load the headless-created save in normal mode and verify it works" which directly answers your question.

Yes, you do plan to generate saves in headless mode and load them in full graphics mode. This is evident from:

  1. PR bugfix(savegame): Fix crashes when saving a game in headless mode #2139's testing requirements: The checklist specifically includes loading headless-created saves in normal mode
  2. The broader headless context: This appears to be for running dedicated servers or automated simulations that need to save state and potentially transfer it to clients

Given this, the empty ViewDummy::xfer() implementation is problematic because:

  • When a headless save is loaded in graphics mode, the View snapshot data will be missing/corrupted
  • The CRC mismatch could cause save validation failures
  • Any code expecting View state to be preserved across save/load cycles will break

Recommendation: Call View::xfer(xfer) to preserve the base snapshot data, then conditionally skip only the graphics-specific blocks if needed. This ensures save compatibility while still avoiding unnecessary visual data serialization.

Choose a reason for hiding this comment

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

Do we ever plan on generating saves in headless mode, then loading them in full graphics mode? If yes, this is worth addressing

Maybe not at the moment, perhaps useful in the future though for troubleshooting or generating specific scenarios programmatically or something like that?

Comment on lines +334 to +336
// TheSuperHackers @feature bobtista 31/01/2026
// View that does nothing. Used for Headless Mode.
class ViewDummy : public View
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 73 to 74
// TheSuperHackers @fix bobtista 31/01/2026 Return dummy in headless mode
virtual View *createView( void ) { return TheGlobalData->m_headless ? NEW ViewDummy : NEW W3DView; }
Copy link

Choose a reason for hiding this comment

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

createView() dereferences TheGlobalData unconditionally (TheGlobalData->m_headless). If this factory can run before global data initialization, this will crash in headless startup paths. If TheGlobalData is guaranteed non-null here, it may be worth asserting; otherwise guard with a null check (defaulting to W3DView or ViewDummy depending on intended behavior).

Also appears in GeneralsMD/Code/GameEngineDevice/Include/W3DDevice/GameClient/W3DInGameUI.h:73-74.

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

Comment:
`createView()` dereferences `TheGlobalData` unconditionally (`TheGlobalData->m_headless`). If this factory can run before global data initialization, this will crash in headless startup paths. If `TheGlobalData` is guaranteed non-null here, it may be worth asserting; otherwise guard with a null check (defaulting to `W3DView` or `ViewDummy` depending on intended behavior).

Also appears in `GeneralsMD/Code/GameEngineDevice/Include/W3DDevice/GameClient/W3DInGameUI.h:73-74`.

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

Copy link

@greptile-apps greptile-apps bot left a comment

Choose a reason for hiding this comment

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

5 files reviewed, 5 comments

Edit Code Review Agent Settings | Greptile

Comment on lines 1240 to +1243
been moved to where all the other translators are attached in game client */

// create the tactical view
if (TheDisplay)
TheTacticalView = createView();
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.

Comment on lines +334 to +336
// TheSuperHackers @feature bobtista 31/01/2026
// View that does nothing. Used for Headless Mode.
class ViewDummy : public View
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 70 to 72
protected:

/// factory for views
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.

Comment on lines +334 to +336
// TheSuperHackers @feature bobtista 31/01/2026
// View that does nothing. Used for Headless Mode.
class ViewDummy : public View
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.

Comment on lines 337 to 339
{
public:
virtual Drawable *pickDrawable( const ICoord2D *screen, Bool forceAttack, PickType pickType ) { return nullptr; }
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.

@bobtista bobtista force-pushed the bobtista/view-dummy branch from e30fa7a to e241df5 Compare February 24, 2026 14:57
Copy link

@greptile-apps greptile-apps bot left a comment

Choose a reason for hiding this comment

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

5 files reviewed, 1 comment

Edit Code Review Agent Settings | Greptile

Comment on lines +339 to +379
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 )
{
}
Copy link

Choose a reason for hiding this comment

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

Several method bodies are on the same line as their signatures, which prevents placing breakpoints on the function body separately from the declaration. Per project conventions, expand these to multi-line format:

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

Context Used: Rule from dashboard - Always place if/else/for/while statement bodies on separate lines from the condition to allow precis... (source)

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

Comment:
Several method bodies are on the same line as their signatures, which prevents placing breakpoints on the function body separately from the declaration. Per project conventions, expand these to multi-line format:

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

**Context Used:** Rule from `dashboard` - Always place if/else/for/while statement bodies on separate lines from the condition to allow precis... ([source](https://app.greptile.com/review/custom-context?memory=16b9b669-b823-49be-ba5b-2bd30ff3ba6d))

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

@bobtista bobtista force-pushed the bobtista/view-dummy branch from e241df5 to e439eee Compare February 24, 2026 23:52
Copy link

@greptile-apps greptile-apps bot left a comment

Choose a reason for hiding this comment

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

5 files reviewed, 2 comments

Edit Code Review Agent Settings | Greptile

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

Choose a reason for hiding this comment

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

Dereferences TheGlobalData without null check; if createView() is called before global data initialization, this will crash

Suggested change
return TheGlobalData->m_headless ? static_cast<View*>(NEW ViewDummy) : NEW W3DView;
return (TheGlobalData && TheGlobalData->m_headless) ? static_cast<View*>(NEW ViewDummy) : NEW W3DView;
Prompt To Fix With AI
This is a comment left during a code review.
Path: Generals/Code/GameEngineDevice/Include/W3DDevice/GameClient/W3DInGameUI.h
Line: 76

Comment:
Dereferences `TheGlobalData` without null check; if `createView()` is called before global data initialization, this will crash

```suggestion
		return (TheGlobalData && TheGlobalData->m_headless) ? static_cast<View*>(NEW ViewDummy) : NEW W3DView;
```

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

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

Choose a reason for hiding this comment

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

Dereferences TheGlobalData without null check; if createView() is called before global data initialization, this will crash

Suggested change
return TheGlobalData->m_headless ? static_cast<View*>(NEW ViewDummy) : NEW W3DView;
return (TheGlobalData && TheGlobalData->m_headless) ? static_cast<View*>(NEW ViewDummy) : NEW W3DView;
Prompt To Fix With AI
This is a comment left during a code review.
Path: GeneralsMD/Code/GameEngineDevice/Include/W3DDevice/GameClient/W3DInGameUI.h
Line: 76

Comment:
Dereferences `TheGlobalData` without null check; if `createView()` is called before global data initialization, this will crash

```suggestion
		return (TheGlobalData && TheGlobalData->m_headless) ? static_cast<View*>(NEW ViewDummy) : NEW W3DView;
```

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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants