Skip to content

tweak(gamemessage): Reduce number of MSG_DESTROY_SELECTED_GROUP messages#2668

Open
Caball009 wants to merge 7 commits into
TheSuperHackers:mainfrom
Caball009:tweak_msg_destroy_sel_group_reduced
Open

tweak(gamemessage): Reduce number of MSG_DESTROY_SELECTED_GROUP messages#2668
Caball009 wants to merge 7 commits into
TheSuperHackers:mainfrom
Caball009:tweak_msg_destroy_sel_group_reduced

Conversation

@Caball009

@Caball009 Caball009 commented Apr 30, 2026

Copy link
Copy Markdown

The client considers primary mouse clicks in the game world as a deselection, and will also update the game logic. This means that GameMessage::MSG_DESTROY_SELECTED_GROUP messages are sent frequently, even if no objects are currently selected. There's actually an old EA comment on this issue. It's also unnecessary to send this message prior to the creation of a new group. This PR changes that by checking first if the local player has objects selected, which reduces the number of messages significantly.

I've tested with two local clients in multiplayer (VS22 debug builds); one had this feature and one didn't, and everything worked fine.

See commits for cleaner diffs.


Results for Golden Replay 1:

  • MSG_NETWORK_MESSAGES: 58770
  • MSG_LOGIC_CRC: 13386
  • MSG_DO_MOVETO: 6888
  • MSG_AREA_SELECTION_DEPRECATED: 4476
  • MSG_QUEUE_UNIT_CREATE: 2225
  • MSG_DESTROY_SELECTED_GROUP: 17366
  • MSG_CREATE_SELECTED_GROUP_NO_SOUND: 317, new group: 88
  • MSG_CREATE_SELECTED_GROUP: 8299, new group: 8114
  • MSG_DESTROY_SELECTED_GROUP before new group creation: 8901

Just avoiding the MSG_DESTROY_SELECTED_GROUP before the creation of a new group accounts for 15% of all network messages in this replay. That doesn't even take into account how many times this message was sent when no units were selected.


TODO:

  • Replicate in Generals.
  • Do more thorough testing.

@Caball009 Caball009 added Enhancement Is new feature or request Minor Severity: Minor < Major < Critical < Blocker Gen Relates to Generals ZH Relates to Zero Hour labels Apr 30, 2026
@greptile-apps

greptile-apps Bot commented Apr 30, 2026

Copy link
Copy Markdown

Greptile Summary

This PR reduces the frequency of MSG_DESTROY_SELECTED_GROUP network messages by ensuring the message is only sent when there are actually selected drawables, and by suppressing it in call-sites that immediately follow with MSG_CREATE_SELECTED_GROUP (which implicitly replaces any existing group on the logic side).

  • InGameUI::deselectAllDrawables gains an updateGameLogic parameter (renamed from postMsg) and captures hadSelectedDrawables before the deselection loop, gating MSG_DESTROY_SELECTED_GROUP on both updateGameLogic=true and the selection being non-empty.
  • SelectionXlat introduces m_pendingDeselection to defer the deselect message from RAW_MOUSE_LEFT_BUTTON_UP until after MOUSE_LEFT_CLICK has resolved, preventing a double MSG_DESTROY_SELECTED_GROUP when the user clicks a new object while another is already selected.
  • All deselectAllDrawables() call-sites that directly precede MSG_CREATE_SELECTED_GROUP are updated to pass FALSE, and a pre-existing double-deselection bug in onMetaAddTeam is fixed with a deselectedAllDrawables guard flag.

Confidence Score: 5/5

Safe to merge — the changes are logically consistent across all call-sites and the game logic correctly handles MSG_CREATE_SELECTED_GROUP as an implicit group replacement without a preceding destroy message.

The optimization is narrowly scoped: the hadSelectedDrawables snapshot is taken before the deselection loop so it is always accurate, m_pendingDeselection is properly initialized and cleared in every branch, and the FALSE-parameter updates are applied consistently across all relevant call-sites. The author validated the change in a two-client local multiplayer session. No rule violations were found and no pre-existing correctness assumptions are broken.

No files require special attention.

Important Files Changed

Filename Overview
GeneralsMD/Code/GameEngine/Source/GameClient/InGameUI.cpp Core change: deselectAllDrawables now captures whether any drawables were selected before clearing them, and only posts MSG_DESTROY_SELECTED_GROUP when updateGameLogic=true AND objects were previously selected. Logic is correct; the snapshot precedes the deselection loop.
Core/GameEngine/Source/GameClient/MessageStream/SelectionXlat.cpp Introduces m_pendingDeselection to defer the deselect message from RAW_MOUSE_LEFT_BUTTON_UP until after MOUSE_LEFT_CLICK resolves, preventing double MSG_DESTROY_SELECTED_GROUP on new-object selection. Removes the now-redundant deselectAll() static helper. Double-deselection bug in onMetaAddTeam is also fixed with a deselectedAllDrawables flag.
Core/GameEngine/Source/GameClient/MessageStream/CommandXlat.cpp All deselectAllDrawables() call-sites that immediately precede MSG_CREATE_SELECTED_GROUP are updated to pass FALSE, suppressing the redundant MSG_DESTROY_SELECTED_GROUP in those paths. One change is inside a block comment and has no runtime effect.
GeneralsMD/Code/GameEngine/Include/GameClient/InGameUI.h Parameter rename only: postMsg → updateGameLogic for better clarity. No functional change.
Core/GameEngine/Include/GameClient/SelectionXlat.h Adds the m_pendingDeselection Bool member to SelectionTranslator. Straightforward declaration change.
GeneralsMD/Code/GameEngine/Source/GameClient/GUI/ControlBar/ControlBarCommandProcessing.cpp Single call-site update: deselectAllDrawables(FALSE) before MSG_CREATE_SELECTED_GROUP, suppressing the redundant destroy message.
Core/GameEngine/Source/GameLogic/System/GameLogicDispatch.cpp Single call-site update in replay observer path: deselectAllDrawables(FALSE) before reselecting objects for the replay camera, suppressing the destroy message during replay sync.

Sequence Diagram

%%{init: {'theme': 'neutral'}}%%
sequenceDiagram
    participant Mouse
    participant SelectionXlat
    participant InGameUI
    participant MessageStream

    Note over Mouse,MessageStream: Alternate mouse mode – click on empty space (deselect)
    Mouse->>SelectionXlat: RAW_MOUSE_LEFT_BUTTON_UP
    SelectionXlat->>SelectionXlat: "m_pendingDeselection = TRUE"
    Mouse->>SelectionXlat: MOUSE_LEFT_CLICK
    SelectionXlat->>SelectionXlat: onMouseLeftClick() – no object found
    Note over SelectionXlat: m_pendingDeselection still TRUE
    SelectionXlat->>InGameUI: "deselectAllDrawables(updateGameLogic=true)"
    InGameUI-->>InGameUI: hadSelectedDrawables?
    alt had selected drawables
        InGameUI->>MessageStream: MSG_DESTROY_SELECTED_GROUP
    end

    Note over Mouse,MessageStream: Alternate mouse mode – click on new object
    Mouse->>SelectionXlat: RAW_MOUSE_LEFT_BUTTON_UP
    SelectionXlat->>SelectionXlat: "m_pendingDeselection = TRUE"
    Mouse->>SelectionXlat: MOUSE_LEFT_CLICK
    SelectionXlat->>SelectionXlat: onMouseLeftClick() – object found
    SelectionXlat->>SelectionXlat: "m_pendingDeselection = FALSE"
    SelectionXlat->>InGameUI: "deselectAllDrawables(updateGameLogic=false)"
    Note over SelectionXlat: No MSG_DESTROY_SELECTED_GROUP (skipped)
    SelectionXlat->>MessageStream: MSG_CREATE_SELECTED_GROUP
Loading
%%{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 Mouse
    participant SelectionXlat
    participant InGameUI
    participant MessageStream

    Note over Mouse,MessageStream: Alternate mouse mode – click on empty space (deselect)
    Mouse->>SelectionXlat: RAW_MOUSE_LEFT_BUTTON_UP
    SelectionXlat->>SelectionXlat: "m_pendingDeselection = TRUE"
    Mouse->>SelectionXlat: MOUSE_LEFT_CLICK
    SelectionXlat->>SelectionXlat: onMouseLeftClick() – no object found
    Note over SelectionXlat: m_pendingDeselection still TRUE
    SelectionXlat->>InGameUI: "deselectAllDrawables(updateGameLogic=true)"
    InGameUI-->>InGameUI: hadSelectedDrawables?
    alt had selected drawables
        InGameUI->>MessageStream: MSG_DESTROY_SELECTED_GROUP
    end

    Note over Mouse,MessageStream: Alternate mouse mode – click on new object
    Mouse->>SelectionXlat: RAW_MOUSE_LEFT_BUTTON_UP
    SelectionXlat->>SelectionXlat: "m_pendingDeselection = TRUE"
    Mouse->>SelectionXlat: MOUSE_LEFT_CLICK
    SelectionXlat->>SelectionXlat: onMouseLeftClick() – object found
    SelectionXlat->>SelectionXlat: "m_pendingDeselection = FALSE"
    SelectionXlat->>InGameUI: "deselectAllDrawables(updateGameLogic=false)"
    Note over SelectionXlat: No MSG_DESTROY_SELECTED_GROUP (skipped)
    SelectionXlat->>MessageStream: MSG_CREATE_SELECTED_GROUP
Loading

Reviews (6): Last reviewed commit: "Misc fixes." | Re-trigger Greptile

Comment thread GeneralsMD/Code/GameEngine/Source/GameClient/MessageStream/SelectionXlat.cpp Outdated
Comment thread GeneralsMD/Code/GameEngine/Source/GameClient/InGameUI.cpp
Comment thread GeneralsMD/Code/GameEngine/Source/GameClient/InGameUI.cpp Outdated
Comment thread GeneralsMD/Code/GameEngine/Source/GameClient/MessageStream/SelectionXlat.cpp Outdated
Comment thread GeneralsMD/Code/GameEngine/Source/GameClient/InGameUI.cpp Outdated
@Caball009 Caball009 force-pushed the tweak_msg_destroy_sel_group_reduced branch 2 times, most recently from 2a1e6c7 to fcb6ef1 Compare May 3, 2026 18:48

@xezon xezon left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

How confident are we that this will cause no gameplay issues?

Comment thread GeneralsMD/Code/GameEngine/Source/GameClient/MessageStream/SelectionXlat.cpp Outdated
Comment thread GeneralsMD/Code/GameEngine/Source/GameClient/InGameUI.cpp Outdated
Comment thread GeneralsMD/Code/GameEngine/Source/GameClient/InGameUI.cpp Outdated

// TheSuperHackers @tweak Avoid double deselection when selecting a new object with another object selected,
// originally triggered by RAW_MOUSE_LEFT_BUTTON_UP and MOUSE_LEFT_CLICK, respectively.
if (msg->getType() == GameMessage::MSG_MOUSE_LEFT_CLICK && m_pendingDeselection)

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Can this be moved into a switch case?

Comment thread GeneralsMD/Code/GameEngine/Source/GameClient/MessageStream/SelectionXlat.cpp Outdated
Comment thread GeneralsMD/Code/GameEngine/Source/GameClient/MessageStream/SelectionXlat.cpp Outdated
if( !TheInGameUI->getPreventLeftClickDeselectionInAlternateMouseModeForOneClick() )
{
deselectAll();
m_pendingDeselection = 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.

Why is this necessary? Can't we just call deselectAllDrawables here? A second call to deselectAllDrawables will not send a second message then.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

(My comment assumes alternate mouse mode is enabled).

The selection of an object generates two messages, RAW_MOUSE_LEFT_BUTTON_DOWN and MOUSE_LEFT_CLICK. Originally, both would deselect everything, even in the case of a new group creation, which doesn't require prior deselection.

Why is this necessary? Can't we just call deselectAllDrawables here? A second call to deselectAllDrawables will not send a second message then.

It would be ok to call deselectAllDrawables here, except it's extremely likely that the next message is MOUSE_LEFT_CLICK creating a new group in which case there's no Logic deselection required at all. If you can think of a cleaner way to do this, I'd like that.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

So MSG_MOUSE_LEFT_CLICK is synonymous for a single MSG_RAW_MOUSE_LEFT_BUTTON_UP.

If object deselect cannot be fully determined at RAW_MOUSE_LEFT_BUTTON_DOWN, then why not just determine it at only MSG_MOUSE_LEFT_CLICK?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Perhaps for consistency with RAW_MOUSE_RIGHT_BUTTON_DOWN, and because MSG_MOUSE_LEFT_CLICK has 7 early breaks before it gets to the code that does the group creation.

Comment thread GeneralsMD/Code/GameEngine/Source/GameClient/MessageStream/SelectionXlat.cpp Outdated
@Caball009 Caball009 force-pushed the tweak_msg_destroy_sel_group_reduced branch from 65a34a7 to 74b9ff4 Compare June 30, 2026 04:35
@Caball009 Caball009 force-pushed the tweak_msg_destroy_sel_group_reduced branch from 8baab11 to 219fa73 Compare June 30, 2026 04:39
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Enhancement Is new feature or request Gen Relates to Generals Minor Severity: Minor < Major < Critical < Blocker ZH Relates to Zero Hour

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants