Skip to content

fix(aiplayer): Initialize uninitialized variables in Generals AIPlayer::getPlayerStructureBounds - #3426

Draft
Caball009 wants to merge 3 commits into
TheSuperHackers:mainfrom
Caball009:Caball009/fix_uninit_var_getPlayerStructureBounds
Draft

Caball009 wants to merge 3 commits into
TheSuperHackers:mainfrom
Caball009:Caball009/fix_uninit_var_getPlayerStructureBounds

Conversation

@Caball009

@Caball009 Caball009 commented Oct 4, 2026 •

Copy link
Copy Markdown

Variables bounds->lo.y and objBounds.lo.y in function AIPlayer::getPlayerStructureBounds are not initialized due to a typo. This only affects the Generals version. This PR fixes that, refactors some of the surrounding code and replicates the changes to Zero Hour. The code changes should not affect the game logic.

See commits for clean diffs.


I checked when the variables would be left uninitialized and in my testing I encountered only one scenario with the following callstack:

AIPlayer::getPlayerStructureBounds
AIPlayer::findSupplyCenter
AIPlayer::isSupplySourceSafe
Player::isSupplySourceSafe
ScriptConditions::evaluateSkirmishSupplySourceSafe
ScriptConditions::evaluateCondition
ScriptEngine::evaluateCondition
ScriptEngine::evaluateConditions
ScriptEngine::executeScript
ScriptEngine::executeScripts
ScriptEngine::update
...

This happens in matches with one or more ai players and this code gets executed just at the 'wrong' time where a player has already died (no structures or units), but they're still considered the 'current' enemy to an ai player (this gets updated every N frames).

The uninitialized values that I observed with the Steam binary were always very close to 0. I also checked ~2000 gentool replays with one or more ai players and didn't see a mismatch because of this change.

@Caball009 Caball009 added Minor Severity: Minor < Major < Critical < Blocker Gen Relates to Generals Fix Is fixing something, but is not user facing labels Oct 4, 2026
@coderabbitai

coderabbitai Bot commented Oct 4, 2026 •

Copy link
Copy Markdown

Review in Change Stack →

Navigate logical layers of code changes, visualize relationships, and explore their blast radius.

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration
  • Configuration used: Organization UI
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: 7db6c217-4473-4b3b-9750-5e6c5e55c5ac
📥 Commits

Reviewing files that changed from the base of the PR and between fec4990 and fac88a1.

📒 Files selected for processing (2)
  • Generals/Code/GameEngine/Source/GameLogic/AI/AIPlayer.cpp
  • GeneralsMD/Code/GameEngine/Source/GameLogic/AI/AIPlayer.cpp
🚧 Files skipped from review as they are similar to previous changes (1)
  • GeneralsMD/Code/GameEngine/Source/GameLogic/AI/AIPlayer.cpp

Included review availability: This review used your included allowance. Your plan provides up to 4 included reviews per hour; 2 remain after this review.


Walkthrough

getPlayerStructureBounds now zeroes the output and temporary bounds in Generals and GeneralsMD. If the player is absent, the function returns with the output bounds initialized.

Changes

Structure Bounds Initialization

Layer / File(s) Summary
Initialize structure bounds
Generals/Code/GameEngine/Source/GameLogic/AI/AIPlayer.cpp, GeneralsMD/Code/GameEngine/Source/GameLogic/AI/AIPlayer.cpp
Both variants use Region2D::zero() for the output and temporary bounds before player lookup. If the player is absent, the function returns with initialized output bounds. GeneralsMD iterates through a const reference to the player’s team list. Generals adds a guarded comment about the prior initialization issue.

Priority: ⬇️ Low

Estimated code review effort: 2 (Simple) | ~10 minutes

Change: Bug fix · Severity of issue fixed: Low

Suggested reviewers: mirelle7

Merge Risk: ⚪ Minimal · up to fac88

Both variants now return initialized bounds when a player is missing, while preserving valid-player bounds calculations; no actionable merge risk remains.

Architecture Summary

Architecture risk: 🔵 Low · up to fac88

The change affects 2 systems.

Changed systems: Generals, GeneralsMD

Architecture concerns
No architecture-level concerns identified.

Review details

Systems and components

  • observed — Generals (service) was modified; 1 changed file maps to changed impact.
  • observed — GeneralsMD (service) was modified; 1 changed file maps to changed impact.

Before / after behavior

  • observed — Modified behavior in Generals/Code/GameEngine/Source/GameLogic/AI/AIPlayer.cpp: getPlayerStructureBounds now accepts the same arguments with unchanged behavior for valid players, but zeroes the output bounds and temporary object bounds before player lookup; if the player is missing, it returns with initialized output bounds. This replaces chained assignments that left each region’s lo.y uninitialized. The Generals retail CRC build also gains a comment documenting that prior state.
  • observed — Modified behavior in GeneralsMD/Code/GameEngine/Source/GameLogic/AI/AIPlayer.cpp: getPlayerStructureBounds now takes Region2D* without the prior spacing, zeroes both bounds objects via zero() instead of assigning each coordinate, moves the player lookup before iteration setup, and iterates through a const reference to the player’s team list. A Generals retail-CRC-guarded comment documents the historical lo.y initialization issue; the function signature and bounds logic are otherwise unchanged.
🚥 Pre-merge checks | ✅ 4
✅ Passed checks (4 passed)
Check name Status Explanation
Linked Issues check ✅ Passed Issue #557 requires fixing the Generals AIPlayer::getPlayerStructureBounds initialization bug. The PR zero-initializes bounds and objBounds, replacing the faulty assignments that left lo.y uni…
Out of Scope Changes check ✅ Passed The changes are limited to AIPlayer::getPlayerStructureBounds in Generals and Zero Hour. The bounds initialization, early-return handling, and related comment support the issue fix. No unrelated cha…
Title check ✅ Passed The title clearly identifies the initialization fix and the affected function. It is specific, though longer than necessary.
Description check ✅ Passed The description explains the uninitialized bounds, the fix, and the scenario where the issue occurs.
  • Autopilot · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 1


ℹ️ Review info
⚙️ Run configuration
  • Configuration used: Organization UI
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: f4d98897-eaff-4b15-9678-83eb8e49724f
📥 Commits

Reviewing files that changed from the base of the PR and between f8ba7eb and fec4990.

📒 Files selected for processing (2)
  • Generals/Code/GameEngine/Source/GameLogic/AI/AIPlayer.cpp
  • GeneralsMD/Code/GameEngine/Source/GameLogic/AI/AIPlayer.cpp

Included review availability: This review used your included allowance. Your plan provides up to 4 included reviews per hour; 3 remain after this review.

Comment thread Generals/Code/GameEngine/Source/GameLogic/AI/AIPlayer.cpp
@Caball009
Caball009 force-pushed the Caball009/fix_uninit_var_getPlayerStructureBounds branch from fec4990 to fac88a1 Compare October 4, 2026 21:28
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 Minor Severity: Minor < Major < Critical < Blocker

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[GEN] AIPlayer::getPlayerStructureBounds doesn't null lo.y

1 participant