Skip to content

bugfix: Fix delays when requesting paths too quickly#2455

Open
Stubbjax wants to merge 1 commit intoTheSuperHackers:mainfrom
Stubbjax:fix-delayed-paths
Open

bugfix: Fix delays when requesting paths too quickly#2455
Stubbjax wants to merge 1 commit intoTheSuperHackers:mainfrom
Stubbjax:fix-delayed-paths

Conversation

@Stubbjax
Copy link

This change fixes an issue where a path request that is issued within 3 frames of the previous one is delayed by up to 2 seconds. This issue is most notable and impactful when rapidly commanding Terrorists, which conspicuously moonwalk when this occurs, though the issue is apparent with all units. I imagine most players have probably experienced this behaviour at some point but do not consciously recall it.

The code comments left by the original developers indicate that the logic to delay rapidly requested paths is intentional, however the resulting unresponsiveness appears as a bug to players.

It is not yet clear what issues rapid path requests may cause, or whether it was just a precaution or a lazy performance optimisation. I've played several skirmish matches with many units and have not encountered any regressions or performance issues. Ideally any performance issues are addressed at a higher level rather than via an ungraceful workaround placed directly within the path request logic.

Demonstrations of the issue

A rapid succession of force-fire commands leave these units temporarily catatonic

DELAY_2.mp4

The classic two-second terrorist moonwalk

DELAY_1.mp4

Easily reproduced by stepping frames

DELAY_3.mp4

It's particularly bad when it comes to jets

DELAY_4.mp4

@Stubbjax Stubbjax self-assigned this Mar 14, 2026
@Stubbjax Stubbjax added Bug Something is not working right, typically is user facing Major Severity: Minor < Major < Critical < Blocker Performance Is a performance concern Unit AI Is related to unit behavior Gen Relates to Generals ZH Relates to Zero Hour NoRetail This fix or change is not applicable with Retail game compatibility labels Mar 14, 2026
@greptile-apps
Copy link

greptile-apps bot commented Mar 14, 2026

Greptile Summary

Disables the original EA path request rate-limiting logic by wrapping it behind #if RETAIL_COMPATIBLE_CRC guards. The original code imposed a 1-2 second delay when a unit requested a new path within 3 frames of its previous request, causing visible unresponsiveness (moonwalking terrorists, catatonic units, delayed jets). The fix applies symmetrically across 4 path request functions (requestPath, requestAttackPath, requestApproachPath, requestSafePath) in both Generals and Zero Hour codebases.

  • The macro choice (RETAIL_COMPATIBLE_CRC) is appropriate since path request timing directly affects game state determinism and multiplayer CRC synchronization
  • Similar timestamp checks in computeAttackPath (which only triggers for stuck/blocked units) remain active and unguarded, preserving that safety net
  • The requestPath function's m_isBlockedAndStuck collision-ignore logic is also disabled, but equivalent logic exists in computeAttackPath as a fallback
  • No regressions to custom rules (file headers, copyright, NULL/nullptr, formatting all pass)

Confidence Score: 4/5

  • This PR is safe to merge — it cleanly disables a known-problematic delay mechanism behind a well-established compatibility guard.
  • Score of 4 reflects: clean, symmetric changes using the correct guard macro; no new code introduced; original delay logic preserved behind the compatibility flag; similar timestamp safety checks in computeAttackPath remain active. Minor risk that removing the rate-limiter could increase pathfinding load under extreme conditions, but the PR author has tested with many units without regressions.
  • No files require special attention. Both files have identical logical changes (Generals and Zero Hour mirrors).

Important Files Changed

Filename Overview
Generals/Code/GameEngine/Source/GameLogic/Object/Update/AIUpdate.cpp Wraps 4 path request delay blocks with #if RETAIL_COMPATIBLE_CRC guards to disable the 1-2 second delay imposed when paths are requested within 3 frames of the previous request. Clean, symmetric changes across requestPath, requestAttackPath, requestApproachPath, and requestSafePath.
GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Update/AIUpdate.cpp Mirror of the Generals changes for Zero Hour. Same 4 functions guarded. Note: requestAttackPath in GeneralsMD additionally had a setLocomotorGoalNone() call inside the delay block (not present in Generals), which is also disabled by this change.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A[Unit requests path] --> B{RETAIL_COMPATIBLE_CRC?}
    B -->|Yes - Retail mode| C{Path requested within 3 frames?}
    C -->|Yes| D[Delay 1-2 seconds via setQueueForPathTime]
    D --> E[Return without queuing path]
    C -->|No| F[Queue path immediately]
    B -->|No - Fixed mode| F
    F --> G[pathfinder->queueForPath]
Loading

Last reviewed commit: a0d8a4b

tintinhamans
tintinhamans previously approved these changes Mar 14, 2026
@xezon
Copy link

xezon commented Mar 14, 2026

I suggest test this in Network matches too. Perhaps it has relevance when issuing many paths requests in the network.

Copy link

@Skyaero42 Skyaero42 left a comment

Choose a reason for hiding this comment

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

Based on the comment Requesting path very quickly. Can cause a spin. it looks like this code was used to prevent a potential bug.

Additionally, it looks like, it is also an identifier for a unit that is stuck - for which it temporarily disables collision detection.

The pathfinding code is very complex and extremely fragile. Imho, this needs significantly more testing as well as obtaining an understanding why this code is here.

@xezon
Copy link

xezon commented Mar 14, 2026

I agree that this code looks very deliberate with the comments and placement at multiple locations. Maybe there is a specific reason for it. I suggest give it to Goldfish too for testing.

@Mauller
Copy link

Mauller commented Mar 14, 2026

The pathfinder only has a limited queue size and if multiple units get repeated calls to repath then the list will quickly fill with multiple redundant path requests for the same unit.

At the moment there is no mechanism to cancel a pathing request if it is still queued and has not been fulfilled yet.
This will likely be a better mechanism if units track that they are waiting on a pathing request.

Edit - just looked and the pathfind queue code will search the list to see if the unit has already queued a request and will ignore subsequent checks, but it has to possibly search the entire list to check.

@tintinhamans tintinhamans self-requested a review March 14, 2026 21:49
@tintinhamans tintinhamans dismissed their stale review March 14, 2026 21:49

Further testing needed

@Skyaero42
Copy link

@DrGoldFish1 Could you do some testing on this?

@DrGoldFish1
Copy link

@Skyaero42 i can try and test it out tomorrow. Will be a bit busy today.
What will i need to test exactly. I have some ideas but not entirely sure just yet.

@xezon
Copy link

xezon commented Mar 17, 2026

I think you need a slowed game and very fast unit pathing and then see if anything goes wrong when commanding units. Test in Network match.

To simulate slow game, you can perhaps change the Network logic tick from 30 to 10 or so.

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 NoRetail This fix or change is not applicable with Retail game compatibility Performance Is a performance concern Unit AI Is related to unit behavior ZH Relates to Zero Hour

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants