[GameServer][Bug] Hierarchical A* never worked: region identity collapsed to (0,0,0) via a placeholder IntToRegion — long-range pathfinding fell back to straight lines through obstacles #646

Closed
opened 2026-07-17 07:21:03 +00:00 by spikerj · 1 comment
Owner

Found via SonarQube S1172 triage (2026-07-17) — the rule flagged IntToRegion's unused 'hash' parameter; reading it revealed the function is a placeholder that ALWAYS returns (0,0,0) ('This is a hack... Placeholder'), and it sits in the middle of the abstract A* loop: every dequeued region 'was' the origin, so the search could never advance. AdaptivePathfinder selects HierarchicalAStar for exactly the hard cases (30+ obstacles, long paths, :204), so long-range pathfinding around dense obstacle fields effectively produced degenerate results since the class was written.

Fix (PR incoming): the hash round-trip is unnecessary — the region tuple is now the priority-queue element directly (also eliminating the HashCode.Combine collision risk the 'proper bidirectional map' TODO would have carried). RegionToInt/IntToRegion deleted.

Regression guard: new HierarchicalAStarTests — a wall with a side gap forces the abstract search to actually traverse regions; verified FAILING on the pre-fix code (falls back to a 2-waypoint straight line through the wall) and passing after. Full GameServer suite (915) passes; slnf clean.

**Found via SonarQube S1172 triage (2026-07-17)** — the rule flagged IntToRegion's unused 'hash' parameter; reading it revealed the function is a placeholder that ALWAYS returns (0,0,0) ('This is a hack... Placeholder'), and it sits in the middle of the abstract A* loop: every dequeued region 'was' the origin, so the search could never advance. AdaptivePathfinder selects HierarchicalAStar for exactly the hard cases (30+ obstacles, long paths, :204), so long-range pathfinding around dense obstacle fields effectively produced degenerate results since the class was written. **Fix (PR incoming):** the hash round-trip is unnecessary — the region tuple is now the priority-queue element directly (also eliminating the HashCode.Combine collision risk the 'proper bidirectional map' TODO would have carried). RegionToInt/IntToRegion deleted. **Regression guard:** new HierarchicalAStarTests — a wall with a side gap forces the abstract search to actually traverse regions; verified FAILING on the pre-fix code (falls back to a 2-waypoint straight line through the wall) and passing after. Full GameServer suite (915) passes; slnf clean.
Author
Owner

Resolved in spikersoft-backend PR #351 (merged, 7/7 checks green). Region tuples are now the abstract-search queue element directly — the placeholder IntToRegion that collapsed every dequeued region to (0,0,0) is deleted along with the hash round-trip and its HashCode.Combine collision risk. The new HierarchicalAStarTests wall-with-side-gap guard is proven non-vacuous: it fails on the pre-fix code (2-waypoint straight line through the wall) and passes after. Long-range pathfinding through dense obstacle fields does real hierarchical search for the first time. Closing.

Resolved in spikersoft-backend PR #351 (merged, 7/7 checks green). Region tuples are now the abstract-search queue element directly — the placeholder IntToRegion that collapsed every dequeued region to (0,0,0) is deleted along with the hash round-trip and its HashCode.Combine collision risk. The new HierarchicalAStarTests wall-with-side-gap guard is proven non-vacuous: it fails on the pre-fix code (2-waypoint straight line through the wall) and passes after. Long-range pathfinding through dense obstacle fields does real hierarchical search for the first time. Closing.
Sign in to join this conversation.