Skip to content

perf: Remove allocation overhead when retrieving labels for Waypoints() and PolygonTriggers()#2761

Open
Mauller wants to merge 1 commit into
TheSuperHackers:mainfrom
Mauller:fix-waypoint+trigger-label-overhead
Open

perf: Remove allocation overhead when retrieving labels for Waypoints() and PolygonTriggers()#2761
Mauller wants to merge 1 commit into
TheSuperHackers:mainfrom
Mauller:fix-waypoint+trigger-label-overhead

Conversation

@Mauller
Copy link
Copy Markdown

@Mauller Mauller commented May 31, 2026

This PR reduces the allocation overhead seen when waypoint path labels and polygontrigger names are retrieved.

In mod maps with a lot of path scripted ai, such as Cobal Rush, waypoint labels are retrieved and compared every frame.
This will occur for every AI unit that is pathing along the waypoint. Polygon triggers also have a similar issue where they can be repeatedly compared every frame per scripted unit.

The following shows the side effects of this change for waypoint path labels.

Before:
image

After:
image

In game the most significant observation was that the first wave in Cobalt Rush went from stuttering to smooth.
The average FPS also significantly increased when observing the first wave and the camera also stopped stuttering.

The above flame graphs were captured in a debug build, but the stuttering still occurs in a release build and is alleviated with the same fix.

@Mauller Mauller self-assigned this May 31, 2026
@Mauller Mauller added Performance Is a performance concern Fix Is fixing something, but is not user facing Gen Relates to Generals ZH Relates to Zero Hour labels May 31, 2026
@greptile-apps
Copy link
Copy Markdown

greptile-apps Bot commented May 31, 2026

Greptile Summary

This PR changes four getter methods across both the Generals and GeneralsMD codebases to return const AsciiString& instead of AsciiString by value, eliminating per-call heap allocations on hot paths that are exercised every frame for each AI unit following scripted waypoint paths or entering polygon trigger areas.

  • Waypoint::getPathLabel1/2/3 (TerrainLogic.h, both trees): these are called repeatedly in isPurposeOfPath and ScriptConditions comparison loops that run per-unit per-frame in maps with heavy AI scripting.
  • PolygonTrigger::getTriggerName (PolygonTrigger.h, both trees): called each frame in AI guard/patrol states for each unit guarding a trigger area.
  • All existing call sites either immediately compare or .str() the result, or copy it into a local AsciiString by value — no dangling-reference risk is introduced.

Confidence Score: 5/5

Safe to merge — the change is a narrow, well-understood API signature tightening with no behavioral impact.

All four changed getters return a reference to a long-lived member field, and every existing call site either immediately uses the result in a comparison or copies it into a local AsciiString by value. No call site stores the reference beyond the expression where it is used, so no dangling-reference scenario exists in the current codebase. The Generals and GeneralsMD trees are updated symmetrically.

No files require special attention. All four header changes are consistent and low-risk.

Important Files Changed

Filename Overview
Generals/Code/GameEngine/Include/GameLogic/TerrainLogic.h Changes getPathLabel1/2/3 return type from AsciiString (by value) to const AsciiString& to eliminate per-call heap allocations; all call sites safely copy or compare the result without storing the reference.
Generals/Code/GameEngine/Include/GameLogic/PolygonTrigger.h Changes getTriggerName return type from AsciiString (by value) to const AsciiString& to eliminate per-call heap allocation; existing callers all assign to AsciiString by value or consume the result inline.
GeneralsMD/Code/GameEngine/Include/GameLogic/TerrainLogic.h Zero Hour mirror of the Generals TerrainLogic.h change; identical update to getPathLabel1/2/3 return types. Same safety assessment applies.
GeneralsMD/Code/GameEngine/Include/GameLogic/PolygonTrigger.h Zero Hour mirror of the Generals PolygonTrigger.h change; identical update to getTriggerName return type. Same safety assessment applies.

Sequence Diagram

sequenceDiagram
    participant AI as AI Unit (per frame)
    participant SC as ScriptConditions / isPurposeOfPath
    participant WP as Waypoint
    participant PT as PolygonTrigger

    AI->>SC: check waypoint path label
    SC->>WP: getPathLabel1() [before: AsciiString copy]
    WP-->>SC: "const AsciiString& (no alloc)"
    SC->>WP: getPathLabel2()
    WP-->>SC: "const AsciiString& (no alloc)"
    SC->>WP: getPathLabel3()
    WP-->>SC: "const AsciiString& (no alloc)"

    AI->>SC: check polygon trigger area
    SC->>PT: getTriggerName() [before: AsciiString copy]
    PT-->>SC: "const AsciiString& (no alloc)"
Loading

Reviews (1): Last reviewed commit: "perf: Remove allocation overhead when re..." | Re-trigger Greptile

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

Labels

Fix Is fixing something, but is not user facing Gen Relates to Generals Performance Is a performance concern ZH Relates to Zero Hour

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant