> ## Documentation Index
> Fetch the complete documentation index at: https://runelite.zip/llms.txt
> Use this file to discover all available pages before exploring further.

# Navigation and the walker

> The walker engine, route options, transport execution, reachability checks, and NavigationActions.

The suite shares one walker: `com.n3plugins.sdk.walker` plans and runs paths for every plugin, and `PacketUtilsPlugin` is the only component that ticks it. Feature plugins should call the result-aware `NavigationActions` facade rather than the walker directly, unless they need manual path control like Walk Assistant.

## How a route runs

```mermaid theme={null}
flowchart TD
    A["Walker.walkTo / walkNear"] --> B["Create WalkerPath (PLANNING)"]
    B --> C["Route request to the Shortest Path planner"]
    C --> D["Pathfinder runs over collision and transport data"]
    D --> E["WalkerPath PLANNED / RUNNING"]
    E --> F["PacketUtilsPlugin.onGameTick calls Walker.tick"]
    F --> G{Step type}
    G -->|Land| H["Door? queue open/close. Otherwise click a waypoint 10-35 tiles ahead"]
    G -->|Transport or teleport| I["Run the scripted transport action, observe the transition"]
    H --> J{Progress stalled?}
    I --> J
    J -->|Yes| K["Replan (async)"]
    J -->|No| L["Continue"]
```

## The walker facade

```java theme={null}
WalkerPath path = Walker.walkTo(new WorldPoint(3164, 3486, 0));
if (Walker.isWalking()) {
    // the player is moving along the path
}
Walker.stop(); // cancel the active path
```

| Method                                       | Description                                                        |
| -------------------------------------------- | ------------------------------------------------------------------ |
| `planTo(target)` / `planTo(target, options)` | Builds a `WalkerPath` without starting movement                    |
| `walkTo(target)` / `walkTo(target, options)` | Builds and starts a path                                           |
| `walkPath(List<WorldPoint>)`                 | Executes a specific pre-defined path                               |
| `tick()`                                     | Advances the active path. Called by Packet Utils, never by plugins |
| `stop()`                                     | Cancels the active path                                            |
| `getActivePath()` / `isWalking()`            | Current handle and state                                           |

Concurrency is serialized with a reentrant lock, so `walkTo` and `walkPath` calls from multiple script threads cannot corrupt the active path, and `stop()` is safe from any thread.

### Deterministic land steps

Land movement uses a deterministic lookahead (no random tile selection): the base lookahead is half the remaining distance clamped to a 5-25 tile window before door clipping. Accepted movements are tracked as queued commands, so an in-flight hop is not re-dispatched, and landing beyond the queued hop resynchronizes from the observed player position instead of walking back to a stale tile.

Path recalculation is a last resort: a stalled movement is retried only after the bounded stall window, and a second stalled window cancels the movement and requests a fresh route. Transport-type stall thresholds adapt through multipliers (land 1.0, toll gates 1.1, teleports 1.2, canoes 1.3, transports 1.5).

## Route options

`WalkerRouteOptions` controls what the planner may use:

* `smartDefaults()` enables walking, teleports, transports, and wilderness avoidance.
* `walkingOnly()` disables every teleport and transport category.
* `useTeleports` and `useTransports` disable broad route families before specific types are considered.
* `avoidWilderness` skips wilderness routes unless the destination is inside it.
* `withBankedRoutePlanning(true)` asks the planner to select a complete bank-aware route: the walker walks only the prefix to that bank, waits for fresh bank-container evidence, revalidates the item manifest, withdraws through `BankActions`, and requests a fresh route. Bank contents are unknown until a container event arrives after login; known-empty and unknown are distinct states.
* Transport costs adjust edge weights per category before planning:

```java theme={null}
WalkerRouteOptions options = WalkerRouteOptions.builder()
    .withTransportCost(WalkerRouteCategory.FAIRY_RING, 50)
    .withTransportCost(WalkerRouteCategory.SPIRIT_TREE, 20)
    .build();
```

Raising a category's cost makes the planner prefer alternatives; a fairy-ring cost increase pushes routes toward walking. Catalog rows are classified by source: agility and grapple shortcuts, boats, canoes, charter ships, ships, fairy rings, gnome gliders, hot air balloons, magic carpets, magic mushtrees, minecarts, quetzals, spirit trees, teleport items, levers, portals, POH, spells, minigame teleports, wilderness obelisks, and generic transports.

## NavigationActions

`NavigationActions` is the result-aware facade for plugins:

```java theme={null}
WorldPoint altar = new WorldPoint(3052, 3484, 0);
InteractionResult result = NavigationActions.walkNear(altar, 2);
if (result.failed()) {
    log.debug("Navigation failed: {}", result.getMessage());
}
```

* `walkTo(goal)` plans globally to the tile; `walkNear(goal, distance)` completes within the accepted Chebyshev radius on the target plane.
* `cancelWalk()` stops the shared walker and resets navigation state.
* It tracks the exact `WalkerPath` handle it started. If the shared path belongs to another caller or has terminated, stale goal state clears before reporting an active-walk block.
* `walkTo` and `walkNear` never gate global planning on the local collision preview, so doors, stairs, cross-plane routes, and transports still plan.

## Transport execution

When the planner selects a transport edge, the edge is converted to a typed route step and resolved to an executor:

```mermaid theme={null}
flowchart LR
    A["Transport catalog row"] --> B["PluginRouteTransportEdge"]
    B --> C["PluginTransportActionResolver"]
    C --> D{Transport type}
    D -->|Fairy ring| E["FairyRingWalkerAction"]
    D -->|Spirit tree, quetzal, charter, glider| F["DestinationNetworkWalkerAction"]
    D -->|Teleport item| G["TeleportItemWalkerAction"]
    D -->|Teleport spell| H["TeleportSpellWalkerAction"]
    D -->|Canoe| I["CanoeWalkerAction"]
    D -->|Toll gate| J["TollGateWalkerAction"]
    D -->|Generic transport| K["Resolve one exact NPC or object"]
    D -->|Shortcut or object| L["ImportedObjectWalkerAction"]
```

Key behaviors:

* **Game interactions stay in `Api.actions`.** Executors return boolean progress to the path engine; the walker context preserves `InteractionResult` acceptance before that.
* **Requirements revalidate at execution time**, not just planning time: fairy rings verify the staff, teleport items verify the item still exists, spells verify availability, canoes verify the axe and level, toll gates verify coins. A failed validation triggers a `requirements-changed-replan`.
* **Completion relies on observed position**, not on an accepted click: arrival means the player is on the destination plane within the edge's radius (five tiles for most transports, three for canoes, up to twenty for minigame teleports, zero or two for objects).
* **Generic transports resolve exactly one target.** A row ID that matches one NPC delegates to the NPC executor; one object delegates to the object executor; both or neither fails closed and replans. This prevents ID-namespace mistakes from producing empty dispatch loops.
* **Vessel boundaries are explicit.** `Board` and `Embark` never count as blocking doors during land traversal, disembarkation recovery is bounded to one nearby attempt, and destination-side gangplank crossings keep transport actions active until exact arrival.
* **Destination selectors never blind-click.** Dialogue and widget selectors dispatch only on one unambiguous match; zero matches wait and multiple matches fail closed for that tick.
* **Agility and grapple shortcuts** fail after ten action ticks without completion so the path can recover, while ordinary object transports wait longer because their animations legitimately vary.

## Walk Assistant

`WalkAssistantPlugin` is a quality-of-life plugin (`n3walkassistant` config group) that walks to destinations on demand:

* Hotkeys for quest or clue destinations, the nearest bank, and cancellation.
* A destination panel with curated banks and cities plus metadata-driven farming, hunter, slayer, minigame, and guild catalogs.
* POH resolution from the configured house-portal varbit, failing closed on unknown values.
* An ETA and status panel while it owns a non-terminal path.

The embedded Shortest Path UI owns world-map target selection. **Set Target** selects the route, starts the shared walker when no other non-terminal path is active, and closes the world map after the walk is accepted. Manual world-map walking works without Walk Assistant enabled. Clearing the path from the world map (the Clear Path entry or the CTRL+X hotkey by default) calls `Walker.stop()` first, so the active path ends cleanly.

## Telemetry

`WalkerTelemetry` keeps a thread-safe ring buffer (capacity 256) of recent decision events plus suite counters (`recoveryCount`, `stallRecalcCount`, `unreachableCount`). Each `WalkerPath` emits one terminal event (`target-reached`, `accepted-distance-reached`, `walker-cancelled`, or a failure with its diagnostic) before the walker clears or replaces the handle, so the last outcome stays readable after `getActivePath()` returns null:

```java theme={null}
List<WalkerTelemetry.TelemetryEvent> events = Walker.getTelemetryEvents(50);
```

The Agent Server exposes the same bounded history (at most 20 events) in its navigation state.

## Reachability checks

`ReachabilityActions` reads the global collision map for local spatial reasoning. It never replaces the walker:

| Method                                                            | Behavior                                                   |
| ----------------------------------------------------------------- | ---------------------------------------------------------- |
| `isWalkable(WorldPoint)`                                          | At least one traversable cardinal edge exists for the tile |
| `isObstacle(WorldPoint)`                                          | Non-null point that is not walkable                        |
| `isInteractable(point or object)`                                 | Conservative walkability check for a target tile           |
| `isWalled(source, destination)` / `isDoored(source, destination)` | Adjacent tiles lack a traversable edge                     |
| `hasDoor(source, Direction)`                                      | Directional edge-block check                               |
| `getCollisionFlag(WorldPoint)`                                    | Bitmask: north=1, east=2, south=4, west=8                  |
| `canWalkBetween(source, destination)`                             | One-tile cardinal movement check                           |
| `getVisitedTiles(start[, maxTiles])`                              | Flood-fill of reachable tiles                              |

Door detection is collision-based and conservative. Live object-aware door interaction belongs to the walker context, not to these checks.

## Resource cache

The walker's bulk data (collision maps, destinations, transports) is not packaged in the jar. On startup the resource downloader fetches the pinned, SHA-checked archive into `.runelite/n3Plugins/shortestpath/`, stages it, validates it, and installs it. A complete installer-prepared cache means no runtime download. Feature plugins must not download, embed, or independently tick this data.
