Skip to content

Comments

feature(gamelogic): Implement ALT + F4 and Window X button to close game#2336

Open
githubawn wants to merge 4 commits intoTheSuperHackers:mainfrom
githubawn:fix/graceful-exit-logic
Open

feature(gamelogic): Implement ALT + F4 and Window X button to close game#2336
githubawn wants to merge 4 commits intoTheSuperHackers:mainfrom
githubawn:fix/graceful-exit-logic

Conversation

@githubawn
Copy link

@githubawn githubawn commented Feb 21, 2026

Fixes #1356

Split up in 2 commits.

  1. Previously, the quit logic was duplicated and inconsistent across several places (the quit menu, the "quit to desktop" button, and the Alt+F4 handler). This commit centralizes all of that into a single GameLogic::quit(Bool toDesktop) method. It properly handles edge cases like stopping an active recording, sending a self-destruct message in multiplayer (using a new m_quitToDesktopAfterMatch flag), unpausing/unfreezing the game before exiting. All the old scattered quit code is replaced with a simple call to TheGameLogic->quit(true/false).

  2. This follow-up extends the graceful exit to two more situations where the game previously couldn't be closed cleanly:
    During the loading screen: The load progress update now checks if a quit has been requested and throws a QuitGameException, which is caught in startNewGame() to cleanly abort the loading process mid-way.
    During movies: The inline ESC-key checking that was copy-pasted in multiple video playback loops is refactored into a new GameClient::isMovieAbortRequested() method. This method now also checks for window close / Alt+F4 events (not just ESC), so closing the window during a movie no longer gets stuck. The MSG_META_DEMO_INSTANT_QUIT message is also registered as a system message so it propagates correctly even during loading.

@greptile-apps
Copy link

greptile-apps bot commented Feb 21, 2026

Greptile Summary

This PR successfully implements graceful shutdown for Alt+F4 and window close events by centralizing quit logic and extending it to handle loading screens and movie playback.

Key changes:

  • Refactored duplicated quit code into single GameLogic::quit(Bool toDesktop) method that handles recorder cleanup, multiplayer self-destruct messages, game unpausing/unfreezing, and proper shutdown sequencing
  • Added exception-based abort mechanism (QuitGameException) to cleanly exit during map loading when quit is requested
  • Created GameClient::isMovieAbortRequested() helper that consolidates ESC/Alt+F4/window-close detection for video playback, replacing duplicated keyboard polling code
  • Moved MSG_META_DEMO_INSTANT_QUIT out of debug-only section and registered it as system message to ensure proper propagation during loading
  • Properly synchronized changes across both Generals and GeneralsMD codebases

The implementation correctly handles edge cases including stopping active recordings, sending multiplayer disconnect messages, and deferring desktop quit until after match end in multiplayer games.

Confidence Score: 5/5

  • This PR is safe to merge - it's a well-executed refactoring that centralizes quit logic and extends graceful shutdown to previously problematic scenarios
  • The code demonstrates thorough handling of edge cases (multiplayer self-destruct, recording cleanup, game state management), uses clean exception handling for loading abort, eliminates code duplication, and maintains consistency across both Generals and GeneralsMD codebases. The previous null check concern was correctly dismissed as TheGameLogic is guaranteed to be initialized.
  • No files require special attention

Important Files Changed

Filename Overview
Generals/Code/GameEngine/Source/GameLogic/System/GameLogic.cpp Centralizes quit logic into GameLogic::quit() method and adds exception-based abort for loading process
Generals/Code/GameEngine/Source/GameClient/GameClient.cpp Adds isMovieAbortRequested() helper to check for ESC, Alt+F4, and window close during video playback
Generals/Code/GameEngine/Source/GameClient/MessageStream/CommandXlat.cpp Simplifies instant quit handler to use centralized quit logic and marks message as system message
Core/GameEngine/Source/GameClient/GUI/LoadScreen.cpp Refactors movie abort checks to use isMovieAbortRequested() and adds abort support during loading
Generals/Code/GameEngine/Include/GameLogic/GameLogic.h Adds public m_quitToDesktopAfterMatch flag and quit() method declaration

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A[User Action: Alt+F4 / Window X / ESC] --> B{Context?}
    B -->|In Game| C[GameLogic::quit called]
    B -->|During Movie| D[isMovieAbortRequested]
    B -->|During Loading| E[updateLoadProgress checks flags]
    
    C --> F{In Multiplayer?}
    F -->|Yes, not Skirmish| G[Send MSG_SELF_DESTRUCT]
    F -->|No| H[Skip self-destruct]
    
    G --> I{Recording?}
    H --> I
    I -->|Yes| J[Stop recording]
    I -->|No| K[Skip stop recording]
    
    J --> L[Unpause & unfreeze game]
    K --> L
    
    L --> M{toDesktop flag?}
    M -->|Yes & Multiplayer| N[Set m_quitToDesktopAfterMatch]
    M -->|Yes & Not Multiplayer| O[clearGameData]
    M -->|No| P[exitGame]
    
    N --> Q[exitGame]
    O --> R[setQuitting TRUE]
    P --> S[setClientQuiet]
    Q --> S
    R --> S
    
    D --> T{Quit flag set?}
    E --> U{Quit flag set?}
    T -->|Yes| V[Abort movie playback]
    U -->|Yes| W[Throw QuitGameException]
    
    W --> X[Caught in startNewGame]
    X --> Y[Clean abort]
    V --> Y
Loading

Last reviewed commit: 036ed84

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.

8 files reviewed, 1 comment

Edit Code Review Agent Settings | Greptile

TheGameEngine->serviceWindowsOS();
if (TheGameEngine->getQuitting())
TheMessageStream->propagateMessages();
if (TheGameEngine->getQuitting() || TheGameLogic->m_quitToDesktopAfterMatch)
Copy link

Choose a reason for hiding this comment

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

Missing null check for TheGameLogic before accessing m_quitToDesktopAfterMatch. GameClient.cpp:820 includes this check. Add the same guard here to prevent potential null pointer dereference.

Suggested change
if (TheGameEngine->getQuitting() || TheGameLogic->m_quitToDesktopAfterMatch)
if (TheGameEngine->getQuitting() || (TheGameLogic && TheGameLogic->m_quitToDesktopAfterMatch))
Prompt To Fix With AI
This is a comment left during a code review.
Path: GeneralsMD/Code/GameEngine/Source/GameClient/GUI/LoadScreen.cpp
Line: 166

Comment:
Missing null check for `TheGameLogic` before accessing `m_quitToDesktopAfterMatch`. `GameClient.cpp:820` includes this check. Add the same guard here to prevent potential null pointer dereference.

```suggestion
	if (TheGameEngine->getQuitting() || (TheGameLogic && TheGameLogic->m_quitToDesktopAfterMatch))
```

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

Copy link

@Caball009 Caball009 Feb 22, 2026

Choose a reason for hiding this comment

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

I gave this a thumbs up, but on second thought TheGameLogic is initialized as part of the game engine initialization, so it doesn't seem necessary. (3 several times in this PR)

Copy link
Author

Choose a reason for hiding this comment

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

keeping it as free insurance, no cost to having it, open to removing if there's a concrete reason

@xezon
Copy link

xezon commented Feb 21, 2026

Needs rebase.

My initial thought on this, without looking at code, is that it will make it easier for players to disconnect from a Multiplayer match - by accident or intentional - so this feature must not work during a Multiplayer Match.

@githubawn
Copy link
Author

Will rebase soon.

The multiplayer behavior was designed based on your comment from #1356 (comment).
Rather than blocking Alt+F4 entirely, it intercepts the OS close command to ensure a MSG_SELF_DESTRUCT (Surrender) message is sent over the network before the game quits, so other players aren't left hanging. Happy to adjust if your thinking has changed since then!

It also adds safe abort logic so Alt+F4 works consistently everywhere addressing helmutbuhler's #1356 (comment) concern about the button only working in some situations.

@Caball009
Copy link

Caball009 commented Feb 21, 2026

Thank you for implementing this. I did a few quick tests and the current implementation appears to work well.

@githubawn githubawn force-pushed the fix/graceful-exit-logic branch from 843b370 to 4fda496 Compare February 22, 2026 00:47
@githubawn githubawn force-pushed the fix/graceful-exit-logic branch from 2d896d5 to 036ed84 Compare February 22, 2026 23:35
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.

Implement ALT + F4 and Window X button to close game

4 participants