Skip to content

feat(headless): Implement GhostObjectManagerDummy#2244

Merged
xezon merged 10 commits intoTheSuperHackers:mainfrom
bobtista:bobtista/ghost-object-manager-dummy
Mar 19, 2026
Merged

feat(headless): Implement GhostObjectManagerDummy#2244
xezon merged 10 commits intoTheSuperHackers:mainfrom
bobtista:bobtista/ghost-object-manager-dummy

Conversation

@bobtista
Copy link

@bobtista bobtista commented Feb 2, 2026

Summary

  • Adds GhostObjectManagerDummy class that provides no-op implementations for headless mode
  • Factory in W3DGameLogic returns dummy when m_headless is true
  • Intentionally does NOT override crc/xfer/loadPostProcess to maintain save compatibility

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

This PR introduces GhostObjectManagerDummy, a no-op subclass of GhostObjectManager used in headless server mode. The factory method createGhostObjectManager is updated in both GameLogic (base) and W3DGameLogic (W3D device) to accept a bool dummy flag driven by TheGlobalData->m_headless, and all changes are applied symmetrically across both the Generals/ and GeneralsMD/ trees.

Key points:

  • GhostObjectManagerDummy stubs out all rendering-related virtual methods with no-ops and returns nullptr from addGhostObject, correctly preventing any ghost-object bookkeeping in headless mode.
  • crc/xfer/loadPostProcess are intentionally not overridden so that save-game serialisation uses the base-class path unchanged — this is well-documented in both the PR description and the in-code comment.
  • A static_cast<GhostObjectManager*> that looks redundant is a known VC6 compiler requirement (acknowledged in a prior review thread).
  • Both W3DGhostObject.cpp files also drop the W3DDisplay::m_3DScene != nullptr && guard in W3DRenderObjectSnapshot::addToScene(). Since this code is now exclusively reached in W3D (non-headless) mode — where m_3DScene should always be initialised — the change is logically safe, but it removes a defensive check that previously prevented silent failures; see the inline comment for details.

Confidence Score: 4/5

  • Safe to merge; the only notable change beyond the dummy class itself is the removal of a defensive null guard that is now logically unreachable in its original context.
  • The core GhostObjectManagerDummy implementation is clean and well-reasoned. The changes are mirrored correctly across both game trees. The single concern is the removal of W3DDisplay::m_3DScene != nullptr in addToScene() — in practice safe because that code path is only reached in W3D non-headless mode, but it eliminates a safety net that was present for a reason.
  • Generals/Code/GameEngineDevice/Source/W3DDevice/GameLogic/W3DGhostObject.cpp and its GeneralsMD counterpart — specifically the removed null guard in W3DRenderObjectSnapshot::addToScene().

Important Files Changed

Filename Overview
Generals/Code/GameEngine/Include/GameLogic/GhostObject.h Adds GhostObjectManagerDummy class with clean no-op overrides for all virtual methods; intentionally skips crc/xfer/loadPostProcess for save compatibility as documented.
Generals/Code/GameEngine/Source/GameLogic/System/GameLogic.cpp Passes TheGlobalData->m_headless to createGhostObjectManager; base factory now returns GhostObjectManagerDummy when headless. Clean and straightforward.
Generals/Code/GameEngineDevice/Include/W3DDevice/GameLogic/W3DGameLogic.h Override updated to accept bool dummy parameter; returns GhostObjectManagerDummy for headless and W3DGhostObjectManager otherwise. The static_cast is a known VC6 requirement (acknowledged in prior review).
Generals/Code/GameEngineDevice/Source/W3DDevice/GameLogic/W3DGhostObject.cpp Removes W3DDisplay::m_3DScene != nullptr && null guard from addToScene(). Safe in practice now that headless mode uses the dummy manager, but removes defensive protection for W3D edge cases.
GeneralsMD/Code/GameEngine/Include/GameLogic/GhostObject.h Identical GhostObjectManagerDummy addition as in Generals counterpart; correctly mirrors the Generals changes with proper Zero Hour copyright header.
GeneralsMD/Code/GameEngineDevice/Source/W3DDevice/GameLogic/W3DGhostObject.cpp Same null guard removal as the Generals variant — same concern applies regarding losing the defensive check for m_3DScene.
GeneralsMD/Code/GameEngine/Source/GameLogic/System/GameLogic.cpp Mirrors the Generals change; createGhostObjectManager(TheGlobalData->m_headless) correctly wires headless detection into the factory.
GeneralsMD/Code/GameEngineDevice/Include/W3DDevice/GameLogic/W3DGameLogic.h Identical to Generals counterpart; correctly overrides createGhostObjectManager(bool dummy) and dispatches to GhostObjectManagerDummy or W3DGhostObjectManager.
Generals/Code/GameEngine/Include/GameLogic/GameLogic.h Virtual createGhostObjectManager() signature updated to createGhostObjectManager(bool dummy = false) — default value preserves backward compatibility for any subclasses that don't override it.
GeneralsMD/Code/GameEngine/Include/GameLogic/GameLogic.h Mirrors Generals counterpart; createGhostObjectManager(bool dummy = false) declaration with default parameter is consistent and safe.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A["GameLogic::init()"] --> B["createGhostObjectManager(TheGlobalData->m_headless)"]
    B --> C{dummy == true?}
    C -- "headless mode" --> D["NEW GhostObjectManagerDummy\n(no-op stubs)"]
    C -- "normal mode\n(base GameLogic)" --> E["NEW GhostObjectManager"]
    C -- "normal mode\n(W3DGameLogic)" --> F["NEW W3DGhostObjectManager\n(full W3D rendering)"]
    D --> G["TheGhostObjectManager = dummy\nAll calls are no-ops"]
    E --> H["TheGhostObjectManager = base"]
    F --> I["TheGhostObjectManager = W3D\nW3DRenderObjectSnapshot::addToScene()\ncalls m_3DScene->Add_Render_Object()"]
Loading
Prompt To Fix All With AI
This is a comment left during a code review.
Path: Generals/Code/GameEngineDevice/Source/W3DDevice/GameLogic/W3DGhostObject.cpp
Line: 154-162

Comment:
**Removed null guard for `m_3DScene`**

The previous check `W3DDisplay::m_3DScene != nullptr &&` guarded against a null pointer dereference on `W3DDisplay::m_3DScene->Add_Render_Object(m_robj)`. With `GhostObjectManagerDummy` now correctly handling headless mode, this path should only be reached when `m_3DScene` is valid — but if `m_3DScene` is ever null in W3D mode (e.g., during startup or teardown edge cases), this will crash instead of failing silently.

The same change exists in `GeneralsMD/Code/GameEngineDevice/Source/W3DDevice/GameLogic/W3DGhostObject.cpp` line 160.

Consider whether the old silent-failure behaviour was masking a real bug, or whether the guard should be preserved as a `DEBUG_ASSERTCRASH` to catch regressions:</p>

```cpp
Bool W3DRenderObjectSnapshot::addToScene()
{
    DEBUG_ASSERTCRASH(W3DDisplay::m_3DScene != nullptr, ("W3DRenderObjectSnapshot::addToScene - m_3DScene is null"));
    if (!m_robj->Is_In_Scene())
    {
        W3DDisplay::m_3DScene->Add_Render_Object(m_robj);
        return true;
    }
    return false;
}
```

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

Last reviewed commit: "style(headless): Exp..."

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.

2 files reviewed, 2 comments

Edit Code Review Agent Settings | Greptile

@bobtista bobtista force-pushed the bobtista/ghost-object-manager-dummy branch from 4d12a95 to f02b950 Compare February 24, 2026 23:51
@xezon xezon added Enhancement Is new feature or request Debug Is mostly debug functionality labels Mar 10, 2026
…bool arg in GeneralsMD GhostObjectManagerDummy
…bool arg in Generals GhostObjectManagerDummy
@xezon
Copy link

xezon commented Mar 18, 2026

has left over comments

…le dummy in base class in GeneralsMD GhostObjectManagerDummy
…le dummy in base class in Generals GhostObjectManagerDummy
@xezon xezon changed the title feature(headless): Add GhostObjectManagerDummy for headless mode feat(headless): Add GhostObjectManagerDummy for headless mode Mar 19, 2026
Copy link

@xezon xezon left a comment

Choose a reason for hiding this comment

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

OK

@xezon xezon changed the title feat(headless): Add GhostObjectManagerDummy for headless mode feat(headless): Implement GhostObjectManagerDummy Mar 19, 2026
@xezon xezon merged commit dd894c2 into TheSuperHackers:main Mar 19, 2026
23 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Debug Is mostly debug functionality Enhancement Is new feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants