Skip to content

Conversation

@Flamefire
Copy link
Member

When the defender kills the current attacker (at the flag) FindAttackerNearBuilding is used to get the next one for the defender to fight. This takes the closest attacker that is ready, i.e. waiting around the flag and calls AttackDefenderAtFlag which usually causes the attacker to start walking to the flag. However if there is no path to the flag (anymore, e.g. after destroying a road) the attacker won't do anything and the function returns false.

As this isn't checked the defender will keep waiting for it.

This can lead to use-after-free if the attacker is destroyed (defeated in free fight, went back home, ...) as the defender will then have a dangling pointer to it.

Fixes #1863

…able.

When the defender kills the current attacker (at the flag)
`FindAttackerNearBuilding` is used to get the next one for the defender
to fight. This takes the closest attacker that is ready, i.e. waiting
around the flag and calls `AttackDefenderAtFlag` which usually causes
the attacker to start walking to the flag. However if there is no path
to the flag (anymore, e.g. after destroying a road) the attacker won't
do anything and the function returns `false`.

As this isn't checked the defender will keep waiting for it.

This can lead to use-after-free if the attacker is destroyed (defeated
in free fight, went back home, ...) as the defender will then have a
dangling pointer to it.

Fixes Return-To-The-Roots#1863
The point can be considered invalid if it is too far and the attacker
would abort on the next event handling.
Defenders with now missing attackers will still come out of the
building and go right back in which looks weird.
@Flamefire Flamefire marked this pull request as ready for review January 19, 2026 11:45
@Flamefire Flamefire requested a review from Flow86 January 19, 2026 11:45
// Check all points around the flag and take shortest
unsigned min_length = std::numeric_limits<unsigned>::max();
MapPoint minPt = MapPoint::Invalid();
ret_radius = 100;
Copy link
Member

Choose a reason for hiding this comment

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

should this then start at MAX_ATTACKING_RUN_DISTANCE too?

Copy link
Member Author

Choose a reason for hiding this comment

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

Actually this assignment could be removed. It is never used because the value will be overwritten when minPt gets set and if it isn't then ret_radius has no meaning

Copy link
Member

Choose a reason for hiding this comment

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

can we explicitly make it std::optional then? maybe its even eases up the do-while?

Copy link
Member Author

@Flamefire Flamefire Jan 19, 2026

Choose a reason for hiding this comment

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

Wait, this is used as the max value in the loop.
So it corresponds to GetPointsInRadius.

Added a constant to clarify

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Crash on save on Windows after long playtime, pure virtual method called

2 participants