Skip to content

Conversation

@Mauller
Copy link

@Mauller Mauller commented Jan 18, 2026

Merge by rebase

Closes: #1984

This PR come in two parts, a retail compatible version, with a failover when the pathfinding crashes, and a non retail compatible path.

The new define RETAIL_COMPATIBLE_PATHFINDING_ALLOCATION was added and will be used for further pathfinding changes that are not retail compatible that will be upcoming. These changes alter data handling within the pathfinding.

The main issue resolved is when units stop moving late game and where parts of the map become impassable.
The reason units stop moving is that objects / buildings placed on the map use up PathfindCellInfo resources which are in a limited pool and are used during the A* Pathfinding.

In this PR we first refactor the obstacle handling functions within PathfindCell from the header and into the cpp, this was required to allow the retail compatible changes to make use of the static variable that signals the pathfinding failover within the cpp file.

In the second commit, the objectID, object blocked by ally, object is transparent and object is fence variables were added to the PathfindCell from the PathfindCellInfo. These variables are then used explicitly in the non retail codepath, in the retail mode they are used in parallel before failover to help identify invalid impassable terrain, then used in a dedicated way in the fixed pathfinding pathway.

Might need better names on the commits but can discuss it bellow


  • Replicate in generals

@Mauller Mauller self-assigned this Jan 18, 2026
@Mauller Mauller added Bug Something is not working right, typically is user facing Major Severity: Minor < Major < Critical < Blocker Gen Relates to Generals ZH Relates to Zero Hour Fix Is fixing something, but is not user facing labels Jan 18, 2026
@greptile-apps
Copy link

greptile-apps bot commented Jan 18, 2026

Greptile Summary

This PR fixes a critical late-game bug where units stop moving and terrain becomes impassable due to PathfindCellInfo resource exhaustion. The solution moves obstacle tracking data (m_obstacleID, m_blockedByAlly, m_obstacleIsFence, m_obstacleIsTransparent) from the dynamically-allocated PathfindCellInfo structure into the statically-allocated PathfindCell structure.

The implementation provides two modes controlled by RETAIL_COMPATIBLE_PATHFINDING_ALLOCATION:

  • Retail-compatible mode: Uses the original allocation scheme but with a failover mechanism that switches to fixed pathfinding when resources are exhausted, maintaining CRC compatibility until failover occurs
  • Non-retail mode: Always uses the static obstacle data in PathfindCell, eliminating the resource exhaustion issue entirely

Key changes:

  • Added RETAIL_COMPATIBLE_PATHFINDING_ALLOCATION define to control allocation strategy
  • Moved obstacle data fields from PathfindCellInfo to PathfindCell for persistent tracking
  • Implemented conditional logic throughout pathfinding code to support both modes
  • Added cleanup logic in forceCleanCells() to identify and clear orphaned cells (obstacles with no m_info) during failover
  • Modified accessor functions (getObstacleID, isBlockedByAlly, isObstacleTransparent, isObstacleFence) to check s_useFixedPathfinding flag and use appropriate data source

Confidence Score: 4/5

  • This PR is relatively safe to merge with moderate risk
  • The fix addresses a critical late-game bug with a well-designed failover mechanism. The dual-mode approach maintains retail compatibility while providing a permanent fix. However, the complexity of conditionally checking s_useFixedPathfinding throughout the codebase introduces subtle state management that could have edge cases. The score is 4 rather than 5 due to the pervasive nature of the changes and the complexity of the failover logic.
  • Pay close attention to GeneralsMD/Code/GameEngine/Source/GameLogic/AI/AIPathfind.cpp - the failover logic and dual-mode accessor functions are complex and critical to correctness

Important Files Changed

Filename Overview
Core/GameEngine/Include/Common/GameDefines.h Added new RETAIL_COMPATIBLE_PATHFINDING_ALLOCATION define to control pathfinding memory allocation mode
GeneralsMD/Code/GameEngine/Include/GameLogic/AIPathfind.h Moved obstacle data from PathfindCellInfo to PathfindCell, changed inline functions to declarations for retail failover support
GeneralsMD/Code/GameEngine/Source/GameLogic/AI/AIPathfind.cpp Implemented dual-mode pathfinding with failover: tracks obstacles in PathfindCell to survive resource exhaustion, cleans up orphaned cells during failover

Sequence Diagram

sequenceDiagram
    participant Game
    participant Pathfinder
    participant PathfindCell
    participant PathfindCellInfo
    
    Note over Game,PathfindCellInfo: Normal Operation (Retail Mode)
    Game->>Pathfinder: Place building on map
    Pathfinder->>PathfindCell: setTypeAsObstacle(obstacle)
    PathfindCell->>PathfindCell: Set m_obstacleID, m_obstacleIsFence, etc
    PathfindCell->>PathfindCellInfo: getACellInfo()
    alt Resources Available
        PathfindCellInfo-->>PathfindCell: Return info
        PathfindCell->>PathfindCellInfo: Store obstacle data in m_info
    else Resources Exhausted
        PathfindCellInfo-->>PathfindCell: Return nullptr
        Note over PathfindCell: Cell becomes orphaned<br/>(has m_obstacleID but no m_info)
    end
    
    Note over Game,PathfindCellInfo: Failover Trigger
    Game->>Pathfinder: Request pathfind
    Pathfinder->>PathfindCell: Process cells
    PathfindCell->>PathfindCell: Detect nullptr m_info
    PathfindCell->>Pathfinder: Set s_useFixedPathfinding = true
    Pathfinder->>Pathfinder: forceCleanCells()
    Pathfinder->>PathfindCell: isObstructionInvalid()
    alt Orphaned Cell Found
        PathfindCell-->>Pathfinder: true (has m_obstacleID, no m_info)
        Pathfinder->>PathfindCell: clearObstruction()
        PathfindCell->>PathfindCell: Clear m_type, m_obstacleID
    end
    
    Note over Game,PathfindCellInfo: Fixed Pathfinding Mode
    Game->>Pathfinder: Place/remove building
    Pathfinder->>PathfindCell: setTypeAsObstacle() / removeObstacle()
    PathfindCell->>PathfindCell: Use static m_obstacleID fields only
    Note over PathfindCellInfo: PathfindCellInfo bypassed<br/>No resource exhaustion possible
Loading

@greptile-apps
Copy link

greptile-apps bot commented Jan 18, 2026

Greptile's behavior is changing!

From now on, if a review finishes with no comments, we will not post an additional "statistics" comment to confirm that our review found nothing to comment on. However, you can confirm that we reviewed your changes in the status check section.

This feature can be toggled off in your Code Review Settings by deselecting "Create a status check for each PR".

@Mauller
Copy link
Author

Mauller commented Jan 18, 2026

Fish tested the failover mechanism, when the game is running before failover you can make areas of the map impassable, after the failover those areas were properly cleared and passable again.

The game also allowed units to properly move again. compared to before the fail over, more buildings could be placed without causing unit lockups.

@Caball009
Copy link

Does not fix #424, with RETAIL_COMPATIBLE_PATHFINDING_ALLOCATION set to 0 and 1.

@xezon xezon added Stability Concerns stability of the runtime and removed Fix Is fixing something, but is not user facing labels Jan 18, 2026
@Mauller
Copy link
Author

Mauller commented Jan 19, 2026

Does not fix #424, with RETAIL_COMPATIBLE_PATHFINDING_ALLOCATION set to 0 and 1.

Okay there must be something else happening there, could be due to AI State handling instead of pathfinding.
With the rate at which the units are being created, the dozers are likely being told to, move out of the way, which interrupts the state of moving to the waypoint.

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

Labels

Bug Something is not working right, typically is user facing Gen Relates to Generals Major Severity: Minor < Major < Critical < Blocker Stability Concerns stability of the runtime ZH Relates to Zero Hour

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Ground units freezes instantly after reaching max amount of PathFindCells

3 participants