Skip to content

unify(controlbar): Merge and move ControlBar and related code to core#2675

Open
DevGeniusCode wants to merge 2 commits intoTheSuperHackers:mainfrom
DevGeniusCode:unify/merge-move-controlbar
Open

unify(controlbar): Merge and move ControlBar and related code to core#2675
DevGeniusCode wants to merge 2 commits intoTheSuperHackers:mainfrom
DevGeniusCode:unify/merge-move-controlbar

Conversation

@DevGeniusCode
Copy link
Copy Markdown

@DevGeniusCode DevGeniusCode commented May 2, 2026

This PR unifies the core ControlBar GUI system, standardizing the GameEngine logic and W3D rendering device files against the Zero Hour (GeneralsMD) baseline. 18 files.

The merged is by ControlBar.h that we defined the command:

GUI_COMMAND_SPECIAL_POWER_FROM_SHORTCUT,
#if RTS_GENERALS
GUI_COMMAND_SPECIAL_POWER_FROM_COMMAND_CENTER = GUI_COMMAND_SPECIAL_POWER_FROM_SHORTCUT, ///< Legacy name
#endif

Fixes & Regressions

ControlBar/UI Features (Zero Hour Port):

  • Added m_powerPurchaseImage to ControlBarScheme to support dynamic General's Power purchase icons.
  • Updated ControlBarScheme::repositionControlBar to automatically resize the GeneralsExpPoints.wnd:GenExpParent window using getImageWidth() and getImageHeight() from the scheme.
  • Unified Special Power shortcut logic under GUI_COMMAND_SPECIAL_POWER_FROM_SHORTCUT (aliased to GUI_COMMAND_SPECIAL_POWER_FROM_COMMAND_CENTER for Generals), utilizing findNaturalCommandCenter() for legacy behavior and hasAnyShortcutSelection() / hasAnyShortcutSpecialPower() for Zero Hour behavior.
  • Enhanced ControlBarOCLTimer to detect KINDOF_TECH_BUILDING and KINDOF_AUTO_RALLYPOINT, enabling ExitInterface::getRallyPoint and showRallyPoint() functionality on objects that previously only supported a hardcoded "Sell" button.
  • Improved ControlBarPopupDescription tooltip logic to dynamically call winHide(TRUE) on the StaticTextCost window if calcCostToBuild() or getSciencePurchaseCost() returns 0.
  • Added a KINDOF_STRUCTURE check during CANMAKE_MAXED_OUT_FOR_PLAYER validation to display the TOOLTIP:TooltipCannotBuildBuildingBecauseMaximumNumber string instead of the generic unit error.
  • Tooltips now detect missingScience for GUI_COMMAND_PLAYER_UPGRADE and GUI_COMMAND_OBJECT_UPGRADE types to explicitly list required General's Promotions in the description.
  • Bug Fixes:
    • Fixed UI artifacts in ControlBarStructureInventory by implementing a winHide(TRUE) loop across m_commandWindows for all MAX_COMMANDS_PER_SET slots before rebuilding the inventory.
--- MERGE FIRST ---
GameEngine/Include/GameClient/ControlBarScheme.h
GameEngine/Source/GameClient/GUI/ControlBar/ControlBar.cpp // Fix Generals Powers side menu (Shortcut Bar)
GameEngine/Source/GameClient/GUI/ControlBar/ControlBarOCLTimer.cpp
GameEngine/Source/GameClient/GUI/ControlBar/ControlBarScheme.cpp
GameEngine/Source/GameClient/GUI/ControlBar/ControlBarStructureInventory.cpp
GameEngine/Source/GameClient/GUI/GUICallbacks/ControlBarCallback.cpp
GameEngine/Source/GameClient/GUI/GUICallbacks/ControlBarPopupDescription.cpp

--- MOVE ONLY ---
GameEngine/Include/GameClient/ControlBar.h
GameEngine/Include/GameClient/ControlBarResizer.h
GameEngine/Source/GameClient/GUI/ControlBar/ControlBarBeacon.cpp
GameEngine/Source/GameClient/GUI/ControlBar/ControlBarCommand.cpp
GameEngine/Source/GameClient/GUI/ControlBar/ControlBarCommandProcessing.cpp
GameEngine/Source/GameClient/GUI/ControlBar/ControlBarMultiSelect.cpp
GameEngine/Source/GameClient/GUI/ControlBar/ControlBarObserver.cpp
GameEngine/Source/GameClient/GUI/ControlBar/ControlBarPrintPositions.cpp
GameEngine/Source/GameClient/GUI/ControlBar/ControlBarResizer.cpp
GameEngine/Source/GameClient/GUI/ControlBar/ControlBarUnderConstruction.cpp
GameEngineDevice/Source/W3DDevice/GameClient/GUI/GUICallbacks/W3DControlBar.cpp

@DevGeniusCode DevGeniusCode added this to the Code foundation build up milestone May 2, 2026
@DevGeniusCode DevGeniusCode added Gen Relates to Generals ZH Relates to Zero Hour Unify Unifies code between Generals and Zero Hour labels May 2, 2026
@greptile-apps
Copy link
Copy Markdown

greptile-apps Bot commented May 2, 2026

Greptile Summary

This PR consolidates the ControlBar GUI subsystem into Core by deleting the Generals-specific source files and updating CMakeLists across all three targets (Core, Generals, GeneralsMD), using the Zero Hour build as the canonical baseline. The substantive code change fixes a UI regression from PR #2655 where the Generals Powers shortcut bar disappeared in Base Generals: updateSpecialPowerShortcut and showSpecialPowerShortcut now gate on #if RTS_GENERALS to restore the original command-center presence check, while Zero Hour continues to use the hasAnyShortcutSpecialPower / hasAnyShortcutSelection path.

Confidence Score: 4/5

Safe to merge; only P2 findings in the developer utility script, all runtime C++ logic is sound.

All findings are P2 (style/best-practice) in the non-compiled Python utility script. The C++ regression fix is logically correct, uses nullptr consistently, follows #pragma once conventions, and the #if RTS_GENERALS gating matches the established codebase pattern.

scripts/cpp/unify_move_files.py — minor non-idempotent ADD_COMMENT logic and built-in name shadowing.

Important Files Changed

Filename Overview
Core/GameEngine/Source/GameClient/GUI/ControlBar/ControlBar.cpp New Core file (Zero Hour baseline + regression fix): adds hasAnyShortcutSelection() and #if RTS_GENERALS conditional blocks to restore original Generals shortcut-bar visibility logic (command-center check) separate from the Zero Hour path (shortcut power/selection check).
scripts/cpp/unify_move_files.py Newly added developer utility script for moving/unifying files between Generals, GeneralsMD and Core; main() is fully commented-out and serves as documentation. Minor issues: type parameter shadowing built-in and non-idempotent ADD_COMMENT path.
Core/GameEngine/Source/GameClient/GUI/ControlBar/ControlBarStructureInventory.cpp Zero Hour baseline introduced into Core; key fix hides all m_commandWindows slots before rebuilding the structure inventory, eliminating stale-button UI artifacts.
Core/GameEngine/CMakeLists.txt Uncomments all ControlBar headers and source files so they participate in the Core build; mirrors the corresponding removals in Generals and GeneralsMD CMakeLists.
GeneralsMD/Code/GameEngine/CMakeLists.txt Comments out all ControlBar source and header entries now provided by Core; no source files deleted from GeneralsMD (they were already moved in a prior step).
Generals/Code/GameEngine/CMakeLists.txt Comments out ControlBar entries as the source files are deleted from Generals/ in this PR.
Core/GameEngine/Include/GameClient/ControlBarScheme.h Zero Hour baseline moved to Core; adds m_powerPurchaseImage member for dynamic General's Power purchase icons. Uses #pragma once correctly.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A[updateSpecialPowerShortcut] --> B{RTS_GENERALS?}
    B -- Yes --> C[findNaturalCommandCenter != nullptr]
    B -- No --> D[hasAnyShortcutSpecialPower OR hasAnyShortcutSelection]
    C --> E{hasValidShortcutButton}
    D --> E
    E -- true AND bar hidden --> F[showSpecialPowerShortcut\nanimateSpecialPowerShortcut TRUE]
    E -- false AND bar visible --> G[hideSpecialPowerShortcut\nanimateSpecialPowerShortcut FALSE]

    F --> H[showSpecialPowerShortcut]
    H --> I{dontAnimate?}
    I -- Yes --> J[return early]
    I -- No --> K{RTS_GENERALS?}
    K -- Yes --> L{findNaturalCommandCenter?}
    L -- No --> J
    L -- Yes --> M[winHide FALSE\npopulateSpecialPowerShortcut]
    K -- No --> N{hasShortcutPower OR\nhasShortcutSelection?}
    N -- No --> J
    N -- Yes --> M
Loading

Comments Outside Diff (1)

  1. scripts/cpp/unify_move_files.py, line 65-68 (link)

    P2 Double-comment risk in ADD_COMMENT path

    if searchString in line matches regardless of whether the line is already commented out. If modify_cmakelists is called twice with ADD_COMMENT on the same file/search string (e.g. if the script is re-run), the entry becomes ## Source/... which CMake will not recognise as a commented line that can be cleanly un-commented. Adding an early-continue guard like if line.lstrip().startswith('#'): continue before the modification would make the function idempotent.

    Prompt To Fix With AI
    This is a comment left during a code review.
    Path: scripts/cpp/unify_move_files.py
    Line: 65-68
    
    Comment:
    **Double-comment risk in `ADD_COMMENT` path**
    
    `if searchString in line` matches regardless of whether the line is already commented out. If `modify_cmakelists` is called twice with `ADD_COMMENT` on the same file/search string (e.g. if the script is re-run), the entry becomes `##    Source/...` which CMake will not recognise as a commented line that can be cleanly un-commented. Adding an early-continue guard like `if line.lstrip().startswith('#'): continue` before the modification would make the function idempotent.
    
    How can I resolve this? If you propose a fix, please make it concise.
Prompt To Fix All With AI
Fix the following 2 code review issues. Work through them one at a time, proposing concise fixes.

---

### Issue 1 of 2
scripts/cpp/unify_move_files.py:58
**`type` parameter shadows Python built-in**

The parameter name `type` in `modify_cmakelists` shadows Python's built-in `type()`. While this doesn't cause a runtime bug here, it is a well-known Python anti-pattern that can cause confusing behavior if `type()` is later needed inside the function. Consider renaming to `modify_type` or `operation`.

### Issue 2 of 2
scripts/cpp/unify_move_files.py:65-68
**Double-comment risk in `ADD_COMMENT` path**

`if searchString in line` matches regardless of whether the line is already commented out. If `modify_cmakelists` is called twice with `ADD_COMMENT` on the same file/search string (e.g. if the script is re-run), the entry becomes `##    Source/...` which CMake will not recognise as a commented line that can be cleanly un-commented. Adding an early-continue guard like `if line.lstrip().startswith('#'): continue` before the modification would make the function idempotent.

Reviews (1): Last reviewed commit: "unify(controlbar): Move ControlBar files..." | Re-trigger Greptile

|| !ThePlayerList || !ThePlayerList->getLocalPlayer())
return;

#if RTS_GENERALS
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

This looks incorrect.
The original code in generals is the same as in Zero Hour, so I don't understand the #if statement

Copy link
Copy Markdown
Author

@DevGeniusCode DevGeniusCode May 3, 2026

Choose a reason for hiding this comment

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

This is not the original code, it was changed to be like this after PR #2655

break;
}
}
#if RTS_GENERALS
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Again, looks incorrect.


#if RTS_GENERALS
// Base Generals just needs a Command Center to show the shortcut bar
Bool hasValidShortcutButton = (ThePlayerList->getLocalPlayer()->findNaturalCommandCenter() != nullptr);
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

I missed this. I have prepared a fix with #2680

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Needs rebase

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

Labels

Gen Relates to Generals Unify Unifies code between Generals and Zero Hour ZH Relates to Zero Hour

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants