Skip to content

fix(walker): convert unbounded recursion to iterative loop#1759

Open
seppulcro wants to merge 3 commits intochsami:developmentfrom
seppulcro:fix/walker-unbounded-recursion
Open

fix(walker): convert unbounded recursion to iterative loop#1759
seppulcro wants to merge 3 commits intochsami:developmentfrom
seppulcro:fix/walker-unbounded-recursion

Conversation

@seppulcro
Copy link
Copy Markdown

Bug: Walking long paths via world map (e.g. to Lighthouse for Horror from the Deep) causes the client to freeze with cascading TimeoutExceptions when the
walker hits a stuck condition near obstacles.

Cause: processWalk() recurses at 3 call sites with no depth limit, flooding the client thread queue.

Fix: Iterative while(true) loop with MAX_RECALC_ATTEMPTS=15. Returns UNREACHABLE cleanly instead of crashing.

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 5, 2026

Important

Review skipped

Auto incremental reviews are disabled on this repository.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: b2a0ba03-e140-4c88-a59f-d4374e1d4584

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

Walkthrough

The processWalk method was refactored from recursive retry calls to an iterative loop with explicit state tracking. A MAX_RECALC_ATTEMPTS constant (15) was introduced to cap recalculation attempts; when exceeded, the walker returns WalkerState.UNREACHABLE and clears the target. Partial-path retries now increment a counter and continue the loop instead of recursing. Exception handling was simplified to directly return WalkerState.EXIT without additional logging paths.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 33.33% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately summarizes the main change: converting unbounded recursion to an iterative loop in the walker module.
Description check ✅ Passed The description clearly explains the bug, its root cause, and the implemented fix, all directly related to the changeset.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

Tip

💬 Introducing Slack Agent: The best way for teams to turn conversations into code.

Slack Agent is built on CodeRabbit's deep understanding of your code, so your team can collaborate across the entire SDLC without losing context.

  • Generate code and open pull requests
  • Plan features and break down work
  • Investigate incidents and troubleshoot customer tickets together
  • Automate recurring tasks and respond to alerts with triggers
  • Summarize progress and report instantly

Built for teams:

  • Shared memory across your entire org—no repeating context
  • Per-thread sandboxes to safely plan and execute work
  • Governance built-in—scoped access, auditability, and budget controls

One agent for your entire SDLC. Right inside Slack.

👉 Get started


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 and usage tips.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In
`@runelite-client/src/main/java/net/runelite/client/plugins/microbot/util/walker/Rs2Walker.java`:
- Around line 615-622: recalcAttempts is being incremented every loop iteration
in Rs2Walker (causing premature UNREACHABLE returns); change logic so
recalcAttempts is only incremented when you actually trigger a path
recalculation (e.g., inside the branch that calls recalculatePath() or in the
stall-detection branch), not on normal progress or "off-path-but-moving" wait
branches, and reset recalcAttempts to 0 whenever the walker makes forward
progress or a new valid path is established; keep the existing behavior that
when recalcAttempts >= MAX_RECALC_ATTEMPTS you log, setTarget(null), and return
WalkerState.UNREACHABLE.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: 9153c4b8-5e82-4efa-8e85-2ec93b5eda5b

📥 Commits

Reviewing files that changed from the base of the PR and between fe71cce and 0415515.

📒 Files selected for processing (1)
  • runelite-client/src/main/java/net/runelite/client/plugins/microbot/util/walker/Rs2Walker.java

@seppulcro seppulcro force-pushed the fix/walker-unbounded-recursion branch from 0415515 to 7e25f66 Compare May 5, 2026 11:09
processWalk() calls itself recursively at 3 sites with no depth limit.
When the walker gets stuck (e.g. near obstacles on long paths), this
floods the client thread task queue causing cascading TimeoutExceptions
that freeze the entire client.

Replace recursive processWalk() calls with a while(true) loop capped at
MAX_RECALC_ATTEMPTS=15. Returns UNREACHABLE cleanly instead of crashing.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@seppulcro seppulcro force-pushed the fix/walker-unbounded-recursion branch from 7e25f66 to 2028d84 Compare May 5, 2026 11:13
off-path-but-moving is normal forward progress and should not count
toward the MAX_RECALC_ATTEMPTS limit. This prevents premature
UNREACHABLE returns on valid long walks.

Addresses CodeRabbit review feedback.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@seppulcro
Copy link
Copy Markdown
Author

Added an additional with a couple more fixes I noticed while trying to use walker

  1. Early-arrive at unwalkable tiles

When the player is adjacent (dist ≤ 1) to a target tile that isn't walkable (e.g. NPC spawn tile, object, wall), return ARRIVED immediately instead of burning all 15 recalc attempts. This was the root cause of the Exceeded max recalc attempts spam during quest helper walks — the pathfinder finds a route but the
exact destination tile has a collision flag, so the walker keeps recalculating despite the player being as close as possible.

  1. Preserve minimap zoom on walkMiniMap()

walkMiniMap(WorldPoint) was delegating to walkMiniMap(wp, 5) which force-resets the minimap zoom to 5.0 on every single walk click. This is detectable bot behaviour — real players don't snap their zoom level 50 times a minute. The no-arg overload now reads the current minimap position directly without touching
zoom.

When the player is adjacent (dist≤1) to an unwalkable target tile
(NPC, object, wall), return ARRIVED immediately instead of burning
all 15 recalc attempts on a tile that can never be reached.

When recalc attempts are exhausted but the player is within
max(distance, 5) tiles of the target, treat as ARRIVED instead of
UNREACHABLE. The ShortestPath pathfinder only considers exact tile
matches as 'reached' — when the target tile has collision flags, the
best path ends 1 tile short. The walker should accept that as success.

Also stop resetting minimap zoom to 5 on every walkMiniMap() call —
preserve the player's current zoom level. The forced zoom reset is
detectable bot behaviour.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@seppulcro seppulcro force-pushed the fix/walker-unbounded-recursion branch from e0703b7 to 3e22ad9 Compare May 9, 2026 00:20
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant