feat(headless): stub gogoMessageBox in GameWindowManagerDummy#2894
feat(headless): stub gogoMessageBox in GameWindowManagerDummy#2894bobtista wants to merge 2 commits into
Conversation
|
| Filename | Overview |
|---|---|
| Generals/Code/GameEngine/Include/GameClient/GameWindowManager.h | Adds two gogoMessageBox no-op overrides to GameWindowManagerDummy returning nullptr, preventing headless-mode crashes when the base class tries to build a window layout without a display. |
| GeneralsMD/Code/GameEngine/Include/GameClient/GameWindowManager.h | Identical change to the Zero Hour counterpart — mirrors the same two gogoMessageBox stubs in the Zero Hour GameWindowManagerDummy, keeping the two builds in sync. |
Sequence Diagram
%%{init: {'theme': 'neutral'}}%%
sequenceDiagram
participant GS as GameState::saveGame
participant WM as TheWindowManager
participant B as GameWindowManager (base)
participant D as GameWindowManagerDummy
Note over WM: Headless mode uses Dummy
GS->>WM: gogoMessageBox(...)
alt Before this PR (base class)
WM->>B: gogoMessageBox(...)
B-->>B: Build window layout (no display!)
B--xGS: crash / undefined behavior
end
alt After this PR (dummy override)
WM->>D: gogoMessageBox(...)
D-->>GS: return nullptr
GS->>GS: ignore nullptr (no-op)
end
%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%%
sequenceDiagram
participant GS as GameState::saveGame
participant WM as TheWindowManager
participant B as GameWindowManager (base)
participant D as GameWindowManagerDummy
Note over WM: Headless mode uses Dummy
GS->>WM: gogoMessageBox(...)
alt Before this PR (base class)
WM->>B: gogoMessageBox(...)
B-->>B: Build window layout (no display!)
B--xGS: crash / undefined behavior
end
alt After this PR (dummy override)
WM->>D: gogoMessageBox(...)
D-->>GS: return nullptr
GS->>GS: ignore nullptr (no-op)
end
Reviews (1): Last reviewed commit: "feat(headless): replicate gogoMessageBox..." | Re-trigger Greptile
|
I'm not a fan of this implementation. The use of a dummy class in production is a code smell imho. This reads like a hack rather than a proper solution. It looks like there is an issue with separation of concerns here. A save call should not be invoking any UI elements. I think the proper solution would be a refactor that ensures proper SoC. |
I'm with you that a better fix is decoupling save from UI. That might take a few more PRs and more time though. As for the dummy class, it's how we've been doing it. Headless mode in this codebase is built on Dummy device classes eg GameWindowManagerDummy. I'm also with you that there should be clear issues and these PRs should address them. edit: I'll work on the better solution and will close these PRs |
GameWindowManagerDummy inherits the base gogoMessageBox implementations, so paths that raise a message box in headless mode, eg GameState::saveGame reporting a save error via MessageBoxOk still try to build a message box layout without a display.
Fix:
GameWindowManagerDummy returns no window for both gogoMessageBox overloads, consistent with its other no-op window functions. The message box call sites reachable in headless mode ignore the returned window - the callers that keep the pointer are all interactive menu code.
Todo: