Repository navigation
bugfix(CacheButtonImage):Allow player to edit images with map/solo.ini #3446
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -430,6 +430,12 @@ AsciiString TheThingTemplateBeingParsedName; | |
|
|
||
| thingTemplate->validate(); | ||
|
|
||
| // TheSuperHackers @bugfix DrGoldFish 14/10/2026 Resolves references in map object overrides. | ||
| if( ini->getLoadType() == INI_LOAD_CREATE_OVERRIDES ) | ||
| { | ||
| thingTemplate->resolveNames(); | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
In Generals, this new Add the empty-name guard already used in Zero Hour before calling this method again.
Comment on lines
+434
to
+436
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. In Generals, this call resolves each object before later definitions in Resolve object images after both files load, or keep failed names and retry them then. Knowledge Base Used: RTS engine core |
||
| } | ||
|
|
||
|
Comment on lines
+433
to
+438
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win 🔎 Supported by static analysis🏁 Script executed: rg -n "ThingTemplate::resolveNames|resolveNames\\(|postProcessLoad|addTemplate|add.*Template|m_thingTemplate" Generals/Code/GameEngine/Source/Common Generals/Code/GameEngine/Include/Common
sed -n '400,455p' Generals/Code/GameEngine/Source/Common/Thing/ThingFactory.cpp
sed -n '500,550p' Generals/Code/GameEngine/Source/Common/Thing/ThingFactory.cppRepository: TheSuperHackers/GeneralsGameCode Length of output: 5326 🏁 Script executed: set -o pipefail
printf '%s\n' '--- ThingFactory registration and override creation ---'
sed -n '1,220p' Generals/Code/GameEngine/Source/Common/Thing/ThingFactory.cpp
printf '%s\n' '--- ThingFactory load/post-process block ---'
sed -n '300,555p' Generals/Code/GameEngine/Source/Common/Thing/ThingFactory.cpp
printf '%s\n' '--- ThingTemplate declarations and resolveNames references ---'
rg -n -F -- 'resolveNames' Generals/Code/GameEngine/Source/Common/Thing Generals/Code/GameEngine/Include/Common/Thing
rg -n -F -- 'class ThingTemplate' Generals/Code/GameEngine/Include/Common
printf '%s\n' '--- resolveNames definition context ---'
rg -n -F -- 'void ThingTemplate::resolveNames' Generals/Code/GameEngine
printf '%s\n' '--- template list and override-related declarations ---'
rg -n -F -e 'friend_getNextTemplate' -e 'newOverride' -e 'addTemplate' -e 'm_firstTemplate' Generals/Code/GameEngine/Include/Common Generals/Code/GameEngine/Source/Common/ThingRepository: TheSuperHackers/GeneralsGameCode Length of output: 20626 🏁 Script executed: set -o pipefail
printf '%s\n' '--- locate ThingTemplate source/header ---'
rg --files Generals/Code/GameEngine | rg '(^|/)(ThingTemplate|ThingFactory)\.(h|cpp)$'
printf '%s\n' '--- locate definitions and declarations ---'
rg -n -F --glob '*.{h,cpp}' -e 'ThingTemplate::resolveNames' -e 'resolveNames()' -e 'friend_getFinalOverride' -e 'setNextOverride' -e 'getFinalOverride' Generals/Code/GameEngine || test "$?" -eq 1
printf '%s\n' '--- inspect candidate ThingTemplate files ---'
for f in $(rg --files Generals/Code/GameEngine | rg '(^|/)(ThingTemplate)\.(h|cpp)$'); do
echo "### $f"
rg -n -F -e 'resolveNames' -e 'm_override' -e 'm_nextOverride' -e 'friend_getFinalOverride' -e 'setNextOverride' "$f" || true
done
printf '%s\n' '--- inspect all matching resolveNames definitions with context ---'
while IFS=: read -r f n rest; do
[ -n "$f" ] || continue
start=$((n-35)); [ "$start" -lt 1 ] && start=1
end=$((n+90))
sed -n "${start},${end}p" "$f"
done < <(rg -n -F --glob '*.cpp' -- 'ThingTemplate::resolveNames' Generals/Code/GameEngine || true)Repository: TheSuperHackers/GeneralsGameCode Length of output: 4397 🏁 Script executed: set -o pipefail
printf '%s\n' '--- full repository ThingTemplate search ---'
rg -n -F --hidden --glob '!/.git/**' -e 'class ThingTemplate' -e 'ThingTemplate::' -e 'resolveNames' . || test "$?" -eq 1
printf '%s\n' '--- files containing ThingTemplate-like declarations ---'
rg -l --hidden --glob '!/.git/**' 'ThingTemplate' . | sed -n '1,160p'
printf '%s\n' '--- build/include references to ThingTemplate headers ---'
rg -n --hidden --glob '!/.git/**' -e 'ThingTemplate.h' -e 'ThingTemplate.hpp' -e 'ThingTemplate' Generals/Code | sed -n '1,220p'
printf '%s\n' '--- repository layout around Common headers and source ---'
find Generals/Code -maxdepth 5 -type f | rg '/(Thing|Template|Object|Overridable)' | sed -n '1,220p'Repository: TheSuperHackers/GeneralsGameCode Length of output: 41701 🏁 Script executed: set -o pipefail
printf '%s\n' '--- ThingTemplate declaration and reference fields ---'
sed -n '320,470p' Core/GameEngine/Include/Common/ThingTemplate.h
printf '%s\n' '--- ThingTemplate resolveNames implementation ---'
sed -n '1235,1335p' Core/GameEngine/Source/Common/Thing/ThingTemplate.cpp
printf '%s\n' '--- related prerequisite resolution implementation ---'
sed -n '1,125p' Generals/Code/GameEngine/Source/Common/RTS/ProductionPrerequisite.cpp
printf '%s\n' '--- override traversal semantics ---'
sed -n '1,125p' Generals/Code/GameEngine/Include/Common/Overridable.h
printf '%s\n' '--- all postProcessLoad and load-type callers in relevant trees ---'
rg -n -F --glob '*.cpp' -e 'postProcessLoad()' -e 'INI_LOAD_CREATE_OVERRIDES' -e 'parseObjectDefinition' Core/GameEngine Generals/Code/GameEngine | sed -n '1,260p'Repository: TheSuperHackers/GeneralsGameCode Length of output: 23979 🏁 Script executed: set -o pipefail
printf '%s\n' '--- ThingFactory lookup and reset semantics ---'
sed -n '200,310p' Generals/Code/GameEngine/Source/Common/Thing/ThingFactory.cpp
printf '%s\n' '--- complete resolveNames remainder ---'
sed -n '1280,1350p' Core/GameEngine/Source/Common/Thing/Thing/ThingTemplate.cpp 2>/dev/null || sed -n '1280,1350p' Core/GameEngine/Source/Common/Thing/ThingTemplate.cpp
printf '%s\n' '--- map override load entrypoints ---'
sed -n '2140,2230p' Generals/Code/GameEngine/Source/GameLogic/System/GameLogic.cpp
printf '%s\n' '--- subsystem post-process ordering ---'
sed -n '130,190p' Core/GameEngine/Source/Common/System/SubsystemInterface.cpp
printf '%s\n' '--- ThingFactory registration declaration and lookup declaration ---'
sed -n '45,135p' Generals/Code/GameEngine/Include/Common/ThingFactory.hRepository: TheSuperHackers/GeneralsGameCode Length of output: 16043 🏁 Script executed: set -o pipefail
printf '%s\n' '--- prerequisite parsing and override behavior ---'
sed -n '650,725p' Core/GameEngine/Source/Common/Thing/ThingTemplate.cpp
sed -n '130,180p' Core/GameEngine/Source/Common/Thing/ThingTemplate.cpp
printf '%s\n' '--- loadMapINI callers and nearby lifecycle ---'
rg -n -F --glob '*.cpp' -e 'loadMapINI(' -e 'postProcessLoadAll(' Generals/Code/GameEngine Core/GameEngine | sed -n '1,160p'
printf '%s\n' '--- prerequisite consumption ---'
rg -n -F --glob '*.cpp' -e 'm_prereqUnits' -e 'calcNumPrereqUnitsOwned' -e 'getAllPossibleBuildFacilityTemplates' Generals/Code/GameEngine Core/GameEngine | sed -n '1,220p'Repository: TheSuperHackers/GeneralsGameCode Length of output: 11559 🏁 Script executed: set -o pipefail
printf '%s\n' '--- initial post-process and map-load ordering ---'
sed -n '480,525p' Generals/Code/GameEngine/Source/Common/GameEngine.cpp
sed -n '1145,1200p' Generals/Code/GameEngine/Source/GameLogic/System/GameLogic.cpp
printf '%s\n' '--- prerequisite consumer block ---'
sed -n '120,180p' Generals/Code/GameEngine/Source/Common/RTS/ProductionPrerequisite.cpp
printf '%s\n' '--- exact map load function with line numbers ---'
nl -ba Generals/Code/GameEngine/Source/GameLogic/System/GameLogic.cpp | sed -n '2150,2220p'Repository: TheSuperHackers/GeneralsGameCode Length of output: 8925 Defer When an existing object override contains a prerequisite for a new object declared later in Suggested fix- // TheSuperHackers @bugfix DrGoldFish 14/10/2026 Resolves references in map object overrides.
- if( ini->getLoadType() == INI_LOAD_CREATE_OVERRIDES )
- {
- thingTemplate->resolveNames();
- }
- // go through all thing templates
for( ThingTemplate *thingTemplate = m_firstTemplate;
thingTemplate;
thingTemplate = thingTemplate->friend_getNextTemplate() )
{
// resolve the prerequisite names
- thingTemplate->resolveNames();
+ static_cast<ThingTemplate*>(thingTemplate->friend_getFinalOverride())->resolveNames(); if (TheFileSystem->doesFileExist(fullFledgeFilename)) {
DEBUG_LOG(("Loading solo.ini"));
INI ini;
ini.load( AsciiString(fullFledgeFilename), INI_LOAD_CREATE_OVERRIDES, nullptr );
}
+ TheThingFactory->postProcessLoad();
+
if (TheControlBar)
TheControlBar->postProcessCommands(); |
||
| #if defined(RTS_DEBUG) || defined(DEBUG_CRASHING) | ||
| TheThingTemplateBeingParsedName.clear(); | ||
| #endif | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win
🔎 Supported by static analysis
🏁 Script executed:
rg -n -C 5 'copyImagesFrom\(|getButtonImage\(|getFinalOverride\(' Core/GameEngine/Source/GameClient/GUI/ControlBar Core/GameEngine/Include/GameClient/ControlBar.hRepository: TheSuperHackers/GeneralsGameCode
Length of output: 25663
🏁 Script executed:
Repository: TheSuperHackers/GeneralsGameCode
Length of output: 23377
🏁 Script executed:
Repository: TheSuperHackers/GeneralsGameCode
Length of output: 44644
🏁 Script executed:
Repository: TheSuperHackers/GeneralsGameCode
Length of output: 41651
🏁 Script executed:
Repository: TheSuperHackers/GeneralsGameCode
Length of output: 36858
🏁 Script executed:
Repository: TheSuperHackers/GeneralsGameCode
Length of output: 41501
🏁 Script executed:
Repository: TheSuperHackers/GeneralsGameCode
Length of output: 41713
🏁 Script executed:
Repository: TheSuperHackers/GeneralsGameCode
Length of output: 41664
🏁 Script executed:
Repository: TheSuperHackers/GeneralsGameCode
Length of output: 1791
Write copied images to the final command-button override.
When a command-set slot still points to the base button and a later map/solo override exists, the special-power shortcut updates the base image with
copyImagesFrom().getButtonImage()then reads the final override image. The shortcut can display the old override image instead of the science-selected image.Resolve the receiver to its final override inside
copyImagesFrom()and preserve the existing dirty-state behavior.Suggested fix
void CommandButton::copyImagesFrom( const CommandButton *button, Bool markUIDirtyIfChanged ) const { - if( m_buttonImage != button->getButtonImage() ) + CommandButton* finalOverride = (CommandButton*)getFinalOverride(); + if( finalOverride->m_buttonImage != button->getButtonImage() ) { - m_buttonImage = button->getButtonImage(); + finalOverride->m_buttonImage = button->getButtonImage(); //Code renderer handles these states now.