Skip to content

Conversation

@helmutbuhler
Copy link

Follow-up for #632

Some variables in AIPathfind are kept uninitialized to retain compatibility. But they also might be a source of mismatches. This PR sets them to a value found empirically that keeps compatibility with a lot of replays.

Still, a few replays still mismatch with the current value. I'll try to investigate more. Ideally we reverse-engineer the original binary and find out the source of the values that occupy the stack.

@helmutbuhler helmutbuhler added Investigate Stability Concerns stability of the runtime labels Oct 26, 2025
@helmutbuhler
Copy link
Author

So, I did some more investigation, but it doesn't look good.
The uninitialized stack variables are in Pathfinder::classifyFence. That function is only called by Pathfinder::classifyObjectFootprint. That in turn is called by:

  • Pathfinder::newMap
  • Pathfinder::addObjectToPathfindMap
  • Pathfinder::removeObjectFromPathfindMap

Because the variables in question are so high up in the stack, none of these callers set that stackregion to a defined value. That's only done by callers of addObjectToPathfindMap and removeObjectFromPathfindMap, and that's a lot, around 30. So in order to set these variables to a defined value that remains compatible, we'd have to analyze all those callsites to find out how that stackregion is set in practice. That's too much work for me.
As an alternative, I also tried to set the variables to specific constant values depending on the callsite, but that also didn't work. I did find some values though that work in most replays, but not all. This PR changes the initialization to those values.

If we merge this PR, the mismatches due to these uninitialized variables will completely stop for SH players. But some replays won't play back correctly anymore. I tested on 1800 replays, and 6 will mismatch with this merged. Assuming those replays are representative, this would then possibly increase the mismatch likelihood in games with both retail and SH players by 0.3%.

If we don't merge this, replay playback will remain compatible, but the underlying issue will still result in mismatches in live games. It's hard to say for how many mismatches this issue is responsible, but I suspect that it's responsible for most of them. In all other cases where we fixed uninitialized variables, it was pretty well defined what value got used in the retail version. Here it's all over the place.

If someone is interested, I can provide the replays that mismatch with this PR and I can also provide the code to debug this issue and the code to set the variables depending on the callsite (it's a bit tricky because the tiniest changes trigger incompatiblities due to different stacklayout and different float-calculations)

If noone is interested in further improving the heuristics, I'd be in favor of merging this. For the reasons mentioned above, and also to easily rule this issue out when a mismatch happens in the future.

@helmutbuhler helmutbuhler marked this pull request as ready for review November 3, 2025 20:20
@helmutbuhler helmutbuhler requested a review from Mauller November 3, 2025 20:20
@xezon
Copy link

xezon commented Nov 3, 2025

Is there a way to estimate how many mismatches these uninitialized variable would cause originally?

@helmutbuhler
Copy link
Author

I cannot think of any way.

@xezon
Copy link

xezon commented Nov 3, 2025

If we have a way to detect all our clients in a Network match, then we could conditionally opt-in the fix on runtime. Same with the Pathfinder fixes.

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

Labels

Investigate Stability Concerns stability of the runtime

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants