Skip to content

[GEN][ZH] Fix ThingTemplate override copy to prevent mismatch with mod map and quickstart #1194

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

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions Generals/Code/GameEngine/Include/Common/ThingTemplate.h
Original file line number Diff line number Diff line change
Expand Up @@ -369,6 +369,9 @@ class ThingTemplate : public Overridable
// copy the guts of that into this, but preserve this' name, id, and list-links.
void copyFrom(const ThingTemplate* that);

// clear data that's only valid for the 'parent' template but not the override.
void clearOnNewOverride();

/// called by ThingFactory after all templates have been loaded.
void resolveNames();

Expand Down
3 changes: 3 additions & 0 deletions Generals/Code/GameEngine/Source/Common/Thing/ThingFactory.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -194,6 +194,9 @@ ThingTemplate* ThingFactory::newOverride( ThingTemplate *thingTemplate )
newTemplate->markAsOverride();
child->setNextOverride(newTemplate);

// TheSuperHackers @bugfix Caball009 25/06/2025 Clear data that was valid for the 'parent' template but not for the override.
newTemplate->clearOnNewOverride();
Copy link

Choose a reason for hiding this comment

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

So what happens here is that the 2 SparseMatchFinder instances are copied first with *newTemplate = *child, and then they are cleared here to purge the pointers to the unrelated vector of the other ThingTemplate.

There are 2 Problems:

Problem 1

It does not cover all copies automatically. There are 3 places that copy:

  1. In ThingFactory::newTemplate
  2. In ThingFactory::newOverride (this is covered by this change)
  3. In ThingTemplate::copyFrom

Problem 2

The 2 SparseMatchFinder instances are allocated and copied before they are cleared. Their allocated memory is probably kept on clear too. This is unnecessary work and can be avoided.

We do not want to implement ThingTemplate::operator= by hand, because there are 80 or so class members. But there is something else we can do: #1234

Copy link
Author

Choose a reason for hiding this comment

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

Fair enough.


// return the newly created override for us to set values with etc
return newTemplate;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1093,6 +1093,14 @@ void ThingTemplate::copyFrom(const ThingTemplate* that)
this->m_nameString = name;
}

//-------------------------------------------------------------------------------------------------
void ThingTemplate::clearOnNewOverride()
{
// TheSuperHackers @info Clear containers that may contain pointers to data in the 'parent' template for memoization purposes.
Copy link

Choose a reason for hiding this comment

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

Superfluous comment, because that is already explained with comments at the function declaration and the caller.

m_weaponTemplateSetFinder.clear();
m_armorTemplateSetFinder.clear();
}

//-------------------------------------------------------------------------------------------------
void ThingTemplate::setCopiedFromDefault()
{
Expand Down
3 changes: 3 additions & 0 deletions GeneralsMD/Code/GameEngine/Include/Common/ThingTemplate.h
Original file line number Diff line number Diff line change
Expand Up @@ -369,6 +369,9 @@ class ThingTemplate : public Overridable
// copy the guts of that into this, but preserve this' name, id, and list-links.
void copyFrom(const ThingTemplate* that);

// clear data that's only valid for the 'parent' template but not the override.
void clearOnNewOverride();

/// called by ThingFactory after all templates have been loaded.
void resolveNames();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -194,6 +194,9 @@ ThingTemplate* ThingFactory::newOverride( ThingTemplate *thingTemplate )
newTemplate->markAsOverride();
child->setNextOverride(newTemplate);

// TheSuperHackers @bugfix Caball009 25/06/2025 Clear data that was valid for the 'parent' template but not for the override.
newTemplate->clearOnNewOverride();

// return the newly created override for us to set values with etc
return newTemplate;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1232,6 +1232,14 @@ void ThingTemplate::copyFrom(const ThingTemplate* that)
this->m_nameString = name;
}

//-------------------------------------------------------------------------------------------------
void ThingTemplate::clearOnNewOverride()
{
// TheSuperHackers @info Clear containers that may contain pointers to data in the 'parent' template for memoization purposes.
m_weaponTemplateSetFinder.clear();
m_armorTemplateSetFinder.clear();
}

//-------------------------------------------------------------------------------------------------
void ThingTemplate::setCopiedFromDefault()
{
Expand Down
Loading