Skip to content

fix(headless): Skip early load abort in headless replay simulations#2730

Closed
githubawn wants to merge 1 commit into
TheSuperHackers:mainfrom
githubawn:fix/ci
Closed

fix(headless): Skip early load abort in headless replay simulations#2730
githubawn wants to merge 1 commit into
TheSuperHackers:mainfrom
githubawn:fix/ci

Conversation

@githubawn
Copy link
Copy Markdown

@githubawn githubawn commented May 18, 2026

Fixes the CI replay checker instantly completing introduced by #2336.

Prevents transitioning the engine to a quitting state globally and ignores quit events in GameLogic when running in headless mode. This eliminates the need for bypass hacks in GameLogic::updateLoadProgress() and ensures that early initialization triggers or replay quit events do not prematurely abort consecutive replay simulations.

Claude helped. Worked locally.

@greptile-apps
Copy link
Copy Markdown

greptile-apps Bot commented May 18, 2026

Greptile Summary

This PR fixes the CI replay checker prematurely completing (introduced in #2336) by preventing headless-mode quit signals from aborting consecutive replay simulations. The fix moves setQuitting from an inline header definition to a .cpp implementation with a headless guard, and adds an early return to GameLogic::quit() in headless mode — both changes are mirrored symmetrically across Generals and GeneralsMD.

  • GameEngine::setQuitting is no longer inline; when called with true in headless mode it becomes a no-op, leaving m_quitting false so the engine loop continues across replays.
  • GameLogic::quit now returns immediately in headless mode, preventing any replay-end quit event from tearing down the game state between consecutive replays.
  • Both guards null-check TheGlobalData before dereferencing, and the changes are correctly applied to both the base game and the Zero Hour expansion trees.

Confidence Score: 5/5

Safe to merge — the change is narrowly scoped to headless mode and does not affect normal game or quit behaviour.

Both guards are conditional on TheGlobalData->m_headless, so normal (non-headless) quit paths are completely unchanged. The setQuitting(false) path still works in headless mode (the guard only fires for true), so any code that resets the quit flag is unaffected. The fix is mirrored exactly between Generals and GeneralsMD, null-guards are in place, and no existing callers of setQuitting are broken by the move from inline to out-of-line.

No files require special attention.

Important Files Changed

Filename Overview
Generals/Code/GameEngine/Include/Common/GameEngine.h Removes the inline setQuitting definition so the implementation can live in the .cpp with the headless guard.
Generals/Code/GameEngine/Source/Common/GameEngine.cpp Adds non-inline setQuitting that no-ops when quitting=true in headless mode; null-guards TheGlobalData correctly.
Generals/Code/GameEngine/Source/GameLogic/System/GameLogic.cpp Early-returns from GameLogic::quit() in headless mode to prevent replay simulations from aborting prematurely.
GeneralsMD/Code/GameEngine/Include/Common/GameEngine.h Mirror of the Generals header change — removes inline setQuitting.
GeneralsMD/Code/GameEngine/Source/Common/GameEngine.cpp Mirror of Generals GameEngine.cpp change — identical headless guard in setQuitting.
GeneralsMD/Code/GameEngine/Source/GameLogic/System/GameLogic.cpp Mirror of Generals GameLogic.cpp change — identical early-return guard in GameLogic::quit().

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A[Replay simulation ends] --> B{GameLogic::quit called}
    B --> C{Headless mode?}
    C -- Yes --> D[Early return — no-op]
    C -- No --> E[Normal quit flow]
    E --> F[setQuitting called]
    F --> G{quitting=true && headless?}
    G -- Yes --> H[Early return — m_quitting stays false]
    G -- No --> I[m_quitting = quitting]
    D --> J[Engine loop continues]
    H --> J
    I --> K{m_quitting true?}
    K -- Yes --> L[Engine exits]
    K -- No --> J
    J --> M[Next replay starts]
Loading

Reviews (7): Last reviewed commit: "fix(headless): Prevent setting quit stat..." | Re-trigger Greptile

Comment thread Core/GameEngine/Source/Common/ReplaySimulation.cpp Outdated
@githubawn
Copy link
Copy Markdown
Author

did some triaging and it happens much earlier than found, run 5930 instead of 7153 https://github.com/TheSuperHackers/GeneralsGameCode/actions/runs/22267506812/job/64416452283 basically either the first or second commit of the PR

@xezon
Copy link
Copy Markdown

xezon commented May 19, 2026

As long as the test passes green, it is not working correctly.

@xezon xezon added Blocker Severity: Minor < Major < Critical < Blocker Debug Is mostly debug functionality Bug Something is not working right, typically is user facing labels May 19, 2026
@stephanmeesters
Copy link
Copy Markdown

stephanmeesters commented May 19, 2026

Suggest to first revert #2336 entirely, observe tests (of GitHub CI), then divide and conquer

@githubawn githubawn changed the title fix(replay): Prevent quit menu from blocking headless replay simulation fix(headless): Skip early load abort in headless replay simulations May 19, 2026
Copy link
Copy Markdown

@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.

This fix looks confusing.

Comment thread GeneralsMD/Code/Main/WinMain.cpp Outdated
Comment thread Generals/Code/Main/WinMain.cpp Outdated
Comment thread GeneralsMD/Code/GameEngine/Source/GameLogic/System/GameLogic.cpp Outdated
@xezon
Copy link
Copy Markdown

xezon commented May 19, 2026

Needs Rebase too

Avoid setting the quit or quitting state in the engine or logic while running in headless mode. This ensures that OS messages (like WM_CLOSE) or game replay quit events do not stick and prematurely abort subsequent replay simulations in the process queue.

Also removes the redundant load progress bypass hack in updateLoadProgress.
@githubawn
Copy link
Copy Markdown
Author

Rebased

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

Labels

Blocker Severity: Minor < Major < Critical < Blocker Bug Something is not working right, typically is user facing Debug Is mostly debug functionality

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants