tweak(gamemessage): Reduce number of MSG_DESTROY_SELECTED_GROUP messages#2668
tweak(gamemessage): Reduce number of MSG_DESTROY_SELECTED_GROUP messages#2668Caball009 wants to merge 6 commits intoTheSuperHackers:mainfrom
Conversation
|
| Filename | Overview |
|---|---|
| GeneralsMD/Code/GameEngine/Source/GameClient/InGameUI.cpp | Core optimization: deselectAllDrawables now captures selected->empty() before clearing, renames parameter to updateGameLogic, and guards MSG_DESTROY_SELECTED_GROUP behind both the new name and the non-empty check. One idle-worker call site updated to FALSE. |
| GeneralsMD/Code/GameEngine/Source/GameClient/MessageStream/SelectionXlat.cpp | Removes thin deselectAll() wrapper, introduces m_pendingDeselection to defer deselect in alternate-mouse mode from RAW_MOUSE_LEFT_BUTTON_UP to MSG_MOUSE_LEFT_CLICK, preventing double destroy-group messages when clicking a new unit while one is already selected. |
| GeneralsMD/Code/GameEngine/Source/GameClient/MessageStream/CommandXlat.cpp | Five call sites updated to deselectAllDrawables(FALSE) — each is immediately followed by MSG_CREATE_SELECTED_GROUP, so skipping the destroy message is safe. |
| GeneralsMD/Code/GameEngine/Source/GameClient/GUI/ControlBar/ControlBarCommandProcessing.cpp | Single call site updated to deselectAllDrawables(FALSE) before a MSG_CREATE_SELECTED_GROUP; change is consistent with the pattern across the PR. |
| GeneralsMD/Code/GameEngine/Include/GameClient/SelectionXlat.h | Adds Bool m_pendingDeselection private member to SelectionTranslator, correctly initialised in the constructor. |
| GeneralsMD/Code/GameEngine/Include/GameClient/InGameUI.h | Parameter rename postMsg → updateGameLogic in the virtual declaration; no interface change. |
Sequence Diagram
sequenceDiagram
participant Mouse
participant SelectionXlat
participant InGameUI
participant MsgStream as MessageStream
Note over Mouse,MsgStream: Alternate mouse mode — click on new unit while one is selected (NEW behaviour)
Mouse->>SelectionXlat: MSG_RAW_MOUSE_LEFT_BUTTON_UP
SelectionXlat->>SelectionXlat: m_pendingDeselection = TRUE
Mouse->>SelectionXlat: MSG_MOUSE_LEFT_CLICK (drawable found)
SelectionXlat->>SelectionXlat: m_pendingDeselection = FALSE
SelectionXlat->>InGameUI: deselectAllDrawables(FALSE)
Note right of InGameUI: No MSG_DESTROY_SELECTED_GROUP
SelectionXlat->>MsgStream: MSG_CREATE_SELECTED_GROUP
Note over Mouse,MsgStream: Click on empty space (nothing selected) — optimisation
Mouse->>SelectionXlat: MSG_RAW_MOUSE_LEFT_BUTTON_UP
SelectionXlat->>SelectionXlat: m_pendingDeselection = TRUE
Mouse->>SelectionXlat: MSG_MOUSE_LEFT_CLICK (no drawables)
Note right of SelectionXlat: break early
SelectionXlat->>InGameUI: deselectAllDrawables() post-switch
Note right of InGameUI: selected list empty → MSG_DESTROY_SELECTED_GROUP skipped
Reviews (4): Last reviewed commit: "Added logic to avoid double deselection ..." | Re-trigger Greptile
| // TheSuperHackers @tweak Originally this message had one boolean argument, but it wasn't used for anything. | ||
| TheMessageStream->appendMessage( GameMessage::MSG_DESTROY_SELECTED_GROUP ); | ||
| // TheSuperHackers @tweak Avoid sending this message when no objects are currently selected. | ||
| if (!ThePlayerList->getLocalPlayer()->isCurrentlySelectedGroupEmpty()) |
There was a problem hiding this comment.
Looks suspicious. Let's say we select the drawable and then deselect it real fast before the AIGroup is created in the logic (network delay). Wouldn't that then mean the deselect is missed entirely in the logic, while it is deselected in client?
Maybe empty list test needs to come with above drawable list instead?
There was a problem hiding this comment.
Wouldn't that then mean the deselect is missed entirely in the logic, while it is deselected in client?
Yes, that's right, good find. I had overlooked that. I think it won't cause a mismatch because it's purely a client issue, but it needs changing.
Maybe empty list test needs to come with above drawable list instead?
As an early return if current selection is empty?
EDIT1: That needs some tweaking, otherwise you may not be able to deselect units while the game is paused.
EDIT2: Perhaps this is even less desirable. If the logic is slow to update, client deselection attempts may fail because the logic group selection is still empty, making it harder to deselect objects.
Let's say we select the drawable and then deselect it real fast before the AIGroup is created in the logic (network delay).
EDIT3: The reproduction is slightly more complex than described and not likely to happen imo:
- no selection
- select unit(s)
- deselect unit(s)
- hold SHIFT and select other unit(s)
- issue order
- if done fast enough, depending on the current runahead, the units selected with (2) and (4) will carry out the order
There was a problem hiding this comment.
Yes so if there is an issue, even if difficult to reproduce for a human, we cannot do this.
There was a problem hiding this comment.
That's fair. What about this instead? It has a check for client and logic:
const DrawableList *selected = getAllSelectedDrawables();
const Bool emptyDrawableSelection = selected->empty();
...
if (updateGameLogic)
{
if (!emptyDrawableSelection || !ThePlayerList->getLocalPlayer()->isCurrentlySelectedGroupEmpty())
{
TheMessageStream->appendMessage(GameMessage::MSG_DESTROY_SELECTED_GROUP);
}
}… before new group creation.
To avoid issues with fast deselection when the game's paused, or when the runahead is significant in multiplayer.
| // TheSuperHackers @tweak Originally this message had one boolean argument, but it wasn't used for anything. | ||
| TheMessageStream->appendMessage( GameMessage::MSG_DESTROY_SELECTED_GROUP ); | ||
| // TheSuperHackers @tweak Avoid sending this message when no objects are currently selected. | ||
| if (!emptyDrawableSelection || !ThePlayerList->getLocalPlayer()->isCurrentlySelectedGroupEmpty()) |
There was a problem hiding this comment.
!ThePlayerList->getLocalPlayer()->isCurrentlySelectedGroupEmpty()
With the addition of the tweak to avoid double deselection on MSG_RAW_MOUSE_LEFT_BUTTON_UP and MSG_MOUSE_LEFT_CLICK, I don't think the logic selection check is even still necessary.
2a1e6c7 to
fcb6ef1
Compare
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_GROUPmessages are sent frequently, even if no objects are currently selected. There's actually an old EA comment on this issue. This PR changes that by checking first if the local player has objects selected, which reduces the number of messages.I've tested with two local clients in multiplayer (VS22 debug builds); one had this feature and one didn't, and everything worked fine.
TODO: