Skip to content

refactor(gamelogic): Break switch cases of GameLogic::logicMessageDispatcher into separate functions#2702

Open
xezon wants to merge 7 commits into
TheSuperHackers:mainfrom
xezon:xezon/refactor-gamelogicdispatch
Open

refactor(gamelogic): Break switch cases of GameLogic::logicMessageDispatcher into separate functions#2702
xezon wants to merge 7 commits into
TheSuperHackers:mainfrom
xezon:xezon/refactor-gamelogicdispatch

Conversation

@xezon
Copy link
Copy Markdown

@xezon xezon commented May 12, 2026

This change breaks all switch cases of GameLogic::logicMessageDispatcher into separate functions for ease of readability and maintainability.

The logic is unchanged.

TODO

  • Replicate in Generals

@xezon xezon added Minor Severity: Minor < Major < Critical < Blocker Gen Relates to Generals ZH Relates to Zero Hour Refactor Edits the code with insignificant behavior changes, is never user facing labels May 12, 2026
@greptile-apps
Copy link
Copy Markdown

greptile-apps Bot commented May 12, 2026

Greptile Summary

This PR refactors GameLogic::logicMessageDispatcher by extracting each switch case into a dedicated bool-returning member function (e.g., onNewGame, onSetRallyPoint, onDoSpecialPower, …). A shared getMessagePlayer static helper is also extracted. Both Generals/ and GeneralsMD/ headers receive the new method declarations and gain an #include "GameLogic/AI.h" (moved from the .cpp) to satisfy the AIGroupPtr & parameter type.

  • All 50+ cases are delegated to dedicated on* methods; post-switch cleanup in the dispatcher runs correctly in all cases because each call site still executes a break after the function returns.
  • onClearGameData correctly receives and nulls currentlySelectedGroup through a reference, preserving the original semantics for the post-switch group-cleanup code.
  • Functions that need msgPlayer only inside a preprocessor-guarded block (e.g., onSetRallyPoint, onDoSpecialPower*) declare it locally within that block, avoiding an unnecessary call to getMessagePlayer in other build configurations.

Confidence Score: 5/5

Safe to merge — the refactoring is a pure mechanical extraction with no behavioral changes identified.

Every extracted handler is a faithful translation of its original switch case. Post-switch cleanup in the dispatcher runs correctly for all handlers because each call site still reaches its break. The onClearGameData reference-parameter pattern correctly propagates the nullptr assignment back to the dispatcher. All preprocessor-guarded msgPlayer uses are declared within their respective #if blocks. Both header files have matching, correct signatures.

No files require special attention.

Important Files Changed

Filename Overview
Core/GameEngine/Source/GameLogic/System/GameLogicDispatch.cpp All switch cases extracted into dedicated on* member functions; logic preserved; getMessagePlayer helper introduced; include AI.h correctly removed (moved to headers). No behavioral differences found.
Generals/Code/GameEngine/Include/GameLogic/GameLogic.h New on* method declarations added with correct signatures; include AI.h added for AIGroupPtr; ALLOW_SURRENDER overloads include the AIGroupPtr currentlySelectedGroup parameter, matching the implementation.
GeneralsMD/Code/GameEngine/Include/GameLogic/GameLogic.h Identical set of on* declarations as the Generals header; signatures match the implementation including ALLOW_SURRENDER overloads.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A[logicMessageDispatcher] --> B{switch msgType}
    B -->|MSG_NEW_GAME| C[onNewGame]
    B -->|MSG_CLEAR_GAME_DATA| D[onClearGameData]
    B -->|MSG_SET_RALLY_POINT| E[onSetRallyPoint]
    B -->|MSG_DO_SPECIAL_POWER| F[onDoSpecialPower variants]
    B -->|MSG_LOGIC_CRC| H[onLogicCrc]
    B -->|MSG_EXIT| I[onExit]
    B -->|other cases| J[on* handlers]
    C --> K[break to post-switch cleanup]
    D --> K
    E --> K
    F --> K
    H --> K
    I --> K
    J --> K
    K --> L[AIGroup cleanup and Replay camera sync]
Loading

Reviews (5): Last reviewed commit: "Fix compile error" | Re-trigger Greptile

@xezon
Copy link
Copy Markdown
Author

xezon commented May 12, 2026

Generals fails to compile until replicated.

Comment thread Core/GameEngine/Source/GameLogic/System/GameLogicDispatch.cpp
Comment thread Core/GameEngine/Source/GameLogic/System/GameLogicDispatch.cpp
Comment thread Core/GameEngine/Source/GameLogic/System/GameLogicDispatch.cpp
Comment thread Generals/Code/GameEngine/Include/GameLogic/GameLogic.h
@Caball009
Copy link
Copy Markdown

Do we need the braces per case? It makes the function a lot longer.

@xezon
Copy link
Copy Markdown
Author

xezon commented May 13, 2026

Do we need the braces per case? It makes the function a lot longer.

Is not strictly necessary. Braces are only needed if a variable needs declaration in the top switch case scope. Do you want it removed?

@xezon xezon force-pushed the xezon/refactor-gamelogicdispatch branch from 91c7c5d to 5d14b30 Compare May 13, 2026 19:41
@Caball009
Copy link
Copy Markdown

I don't have a strong opinion on it either way, but I lean toward removing them to make the function shorter.

@xezon
Copy link
Copy Markdown
Author

xezon commented May 22, 2026

Needs rebase.

@xezon xezon force-pushed the xezon/refactor-gamelogicdispatch branch from 5d14b30 to 883093b Compare May 22, 2026 19:19
@xezon
Copy link
Copy Markdown
Author

xezon commented May 22, 2026

Rebased without conflicts.

return true;
}

bool GameLogic::onDoWeapon(GameMessage *msg, AIGroupPtr &currentlySelectedGroup)
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Why is currentlySelectedGroup passed as AIGroup*& everywhere?

Player *msgPlayer = getMessagePlayer(msg);

#if RETAIL_COMPATIBLE_CRC
(void)msgPlayer;
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

FWIW we do have MAYBE_UNUSED now.

{
Object* obj = findObjectByID( msg->getArgument( 0 )->objectID );
if (!obj)
return false;
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Indentation; 2 times in this function.

return true;
}

bool GameLogic::onEnableRetaliationMode(GameMessage *msg, AIGroupPtr &currentlySelectedGroup)
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

currentlySelectedGroup is unused.

return true;
}

bool GameLogic::onInternetHack(GameMessage *msg, AIGroupPtr &currentlySelectedGroup)
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

GameMessage *msg is unused.

return true;
}

bool GameLogic::onDoCheer(GameMessage *msg, AIGroupPtr &currentlySelectedGroup)
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

GameMessage *msg is unused.

return true;
}

bool GameLogic::onEvacuate(GameMessage *msg, AIGroupPtr &currentlySelectedGroup)
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

GameMessage *msg is unused.

return true;
}

bool GameLogic::onExecuteRailedTransport(GameMessage *msg, AIGroupPtr &currentlySelectedGroup)
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

GameMessage *msg is unused.

return true;
}

bool GameLogic::onToggleOvercharge(GameMessage *msg, AIGroupPtr &currentlySelectedGroup)
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

GameMessage *msg is unused.

return true;
}

bool GameLogic::onReturnToPrison(GameMessage *msg, AIGroupPtr &currentlySelectedGroup)
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

GameMessage *msg is unused.

Copy link
Copy Markdown

@Caball009 Caball009 left a comment

Choose a reason for hiding this comment

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

Incomplete review.

  1. There's a bunch of unused function parameters. Could remove or mark with MAYBE_UNUSED.
  2. Player *msgPlayer = getMessagePlayer(msg) can be made const in some functions.
  3. currentlySelectedGroup can be passed by pointer instead of pointer ref, I think.

Comment on lines 735 to 738
case GameMessage::MSG_SELECTED_GROUP_COMMAND:
{

break;

}
Copy link
Copy Markdown

@Caball009 Caball009 May 24, 2026

Choose a reason for hiding this comment

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

This case could be removed technically.


TheRecorder->handleCRCMessage(newCRC, msgPlayer->getPlayerIndex(), (msg->getArgument(1)->boolean));
}
return true;
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Empty line before return like all other functions.

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

Labels

Gen Relates to Generals Minor Severity: Minor < Major < Critical < Blocker Refactor Edits the code with insignificant behavior changes, is never user facing ZH Relates to Zero Hour

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants