Skip to content

Commit 7cb5a62

Browse files
authored
bugfix(pathfinder): Fix uninitialized variable in Pathfinder::tightenPathCallback to prevent mismatches (TheSuperHackers#2309)
1 parent 7a9254d commit 7cb5a62

2 files changed

Lines changed: 52 additions & 24 deletions

File tree

Generals/Code/GameEngine/Source/GameLogic/AI/AIPathfind.cpp

Lines changed: 26 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -7732,27 +7732,37 @@ struct TightenPathStruct
77327732
PathfindLayerEnum layer;
77337733
Int radius;
77347734
Bool center;
7735-
Bool foundDest;
7736-
Coord3D destPos;
7735+
Bool foundNewDest;
7736+
Coord3D orgDestPos;
7737+
Coord3D newDestPos;
77377738
};
77387739

77397740

77407741
/*static*/ Int Pathfinder::tightenPathCallback(Pathfinder* pathfinder, PathfindCell* from, PathfindCell* to, Int to_x, Int to_y, void* userData)
77417742
{
77427743
TightenPathStruct* d = (TightenPathStruct*)userData;
7743-
if (from == nullptr || to==nullptr) return 0;
7744+
if (from == nullptr || to==nullptr) return 0; // failure
77447745
if (d->layer != to->getLayer()) {
7745-
return 0; // abort.
7746+
return 0; // failure
77467747
}
7747-
Coord3D pos;
7748+
7749+
#if RETAIL_COMPATIBLE_CRC
7750+
// TheSuperHackers @bugfix Caball009 27/02/2026 This was originally uninitialized.
7751+
// The uninitialized values that retail uses here are usually close to zero as long as foundNewDest == false, otherwise it uses the new values of newDestPos.
7752+
// newDestPos is zero initialized by the caller, so there is no need to check foundNewDest here.
7753+
Coord3D pos = d->newDestPos;
7754+
#else
7755+
Coord3D pos = d->orgDestPos;
7756+
#endif
7757+
77487758
if (!TheAI->pathfinder()->checkForAdjust(d->obj, *d->locomotorSet, true, to_x, to_y, to->getLayer(), d->radius, d->center, &pos, nullptr))
77497759
{
7750-
return 0; // bail early
7760+
return 0; // failure
77517761
}
7752-
d->foundDest = true;
7753-
d->destPos = pos;
7762+
d->foundNewDest = true;
7763+
d->newDestPos = pos;
77547764

7755-
return 0; // keep going
7765+
return 0; // success but continue
77567766
}
77577767

77587768
/* Returns the cost, which is in the same units as coord3d distance. */
@@ -7765,10 +7775,14 @@ void Pathfinder::tightenPath(Object *obj, const LocomotorSet& locomotorSet, Coor
77657775
info.layer = TheTerrainLogic->getLayerForDestination(from);
77667776
info.obj = obj;
77677777
info.locomotorSet = &locomotorSet;
7768-
info.foundDest = false;
7778+
info.foundNewDest = false;
7779+
info.orgDestPos = *to;
7780+
#if RETAIL_COMPATIBLE_CRC
7781+
info.newDestPos.zero();
7782+
#endif
77697783
iterateCellsAlongLine(*from, *to, info.layer, tightenPathCallback, &info);
7770-
if (info.foundDest) {
7771-
*from = info.destPos;
7784+
if (info.foundNewDest) {
7785+
*from = info.newDestPos;
77727786
}
77737787
}
77747788

GeneralsMD/Code/GameEngine/Source/GameLogic/AI/AIPathfind.cpp

Lines changed: 26 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -8091,27 +8091,37 @@ struct TightenPathStruct
80918091
PathfindLayerEnum layer;
80928092
Int radius;
80938093
Bool center;
8094-
Bool foundDest;
8095-
Coord3D destPos;
8094+
Bool foundNewDest;
8095+
Coord3D orgDestPos;
8096+
Coord3D newDestPos;
80968097
};
80978098

80988099

80998100
/*static*/ Int Pathfinder::tightenPathCallback(Pathfinder* pathfinder, PathfindCell* from, PathfindCell* to, Int to_x, Int to_y, void* userData)
81008101
{
81018102
TightenPathStruct* d = (TightenPathStruct*)userData;
8102-
if (from == nullptr || to==nullptr) return 0;
8103+
if (from == nullptr || to==nullptr) return 0; // failure
81038104
if (d->layer != to->getLayer()) {
8104-
return 0; // abort.
8105+
return 0; // failure
81058106
}
8106-
Coord3D pos;
8107+
8108+
#if RETAIL_COMPATIBLE_CRC
8109+
// TheSuperHackers @bugfix Caball009 27/02/2026 This was originally uninitialized.
8110+
// The uninitialized values that retail uses here are usually close to zero as long as foundNewDest == false, otherwise it uses the new values of newDestPos.
8111+
// newDestPos is zero initialized by the caller, so there is no need to check foundNewDest here.
8112+
Coord3D pos = d->newDestPos;
8113+
#else
8114+
Coord3D pos = d->orgDestPos;
8115+
#endif
8116+
81078117
if (!TheAI->pathfinder()->checkForAdjust(d->obj, *d->locomotorSet, true, to_x, to_y, to->getLayer(), d->radius, d->center, &pos, nullptr))
81088118
{
8109-
return 0; // bail early
8119+
return 0; // failure
81108120
}
8111-
d->foundDest = true;
8112-
d->destPos = pos;
8121+
d->foundNewDest = true;
8122+
d->newDestPos = pos;
81138123

8114-
return 0; // keep going
8124+
return 0; // success but continue
81158125
}
81168126

81178127
/* Returns the cost, which is in the same units as coord3d distance. */
@@ -8124,10 +8134,14 @@ void Pathfinder::tightenPath(Object *obj, const LocomotorSet& locomotorSet, Coor
81248134
info.layer = TheTerrainLogic->getLayerForDestination(from);
81258135
info.obj = obj;
81268136
info.locomotorSet = &locomotorSet;
8127-
info.foundDest = false;
8137+
info.foundNewDest = false;
8138+
info.orgDestPos = *to;
8139+
#if RETAIL_COMPATIBLE_CRC
8140+
info.newDestPos.zero();
8141+
#endif
81288142
iterateCellsAlongLine(*from, *to, info.layer, tightenPathCallback, &info);
8129-
if (info.foundDest) {
8130-
*from = info.destPos;
8143+
if (info.foundNewDest) {
8144+
*from = info.newDestPos;
81318145
}
81328146
}
81338147

0 commit comments

Comments
 (0)