Skip to main content

Walker Transport Execution

Verification boundary

This page documents source-level behavior and deterministic test coverage. It does not certify current game widgets, menu entries, transport animations, or landing coordinates. Those behaviors remain live-client verification pending until observed on the pinned RuneLite revision.

This guide covers execution of transport edges selected by the embedded Shortest Path plugin and converted into PluginRouteTransportEdge values. For route planning, ownership, resource downloads, and public navigation APIs, see walker.md.

Ownership and data flow

ShortestPathPlugin converts the selected upstream transport to a PluginRouteTransportEdge. PluginTransportActionResolver parses that edge and selects an executor. Each executor implements WalkerAction and is advanced only by WalkerPath; feature plugins must not tick transport actions or create another walker tick owner.

Game interactions remain owned by Api.actions.* through WalkerContext. A WalkerAction returns booleans to the path engine, while the context methods preserve InteractionResult acceptance and failure before those booleans are produced.


Transport Resolution & Handler Execution Logic Flow


Imported metadata contract

The upstream menuOption menuTarget targetID column is carried as PluginRouteTransportEdge.objectInfo. The resolver interprets it as:

<menu option> <menu target> <numeric NPC, object, or item id>

The resolver's supported action catalog matches menu options before it extracts the target. This supports multi-word actions such as Climb over; splitting on the first space would incorrectly turn over into part of the target name. Spell and home-spell rows do not require object metadata and resolve from displayInfo before object parsing.

displayInfo is transport-specific:

  • fairy rings use the first three characters as the destination code;
  • destination networks use the visible destination label, with a numeric prefix removed and text after a colon preferred;
  • item and spell teleports use text after a colon as a secondary destination option when present;
  • minigame teleports begin with the MinigameTeleport display name.

Malformed metadata fails closed: the resolver returns no action rather than inventing an ID, action, target, spell, or destination.

Dispatch matrix

TransportTypeExecutorEntry behaviorDestination behaviorArrival RadiusStall Multiplier
FAIRY_RINGFairyRingWalkerActionVerifies the ring code; when the Lumbridge Elite Diary is incomplete, verifies or equips a Dramen/Lunar staffAdvances the existing FairyRingActions dial state one accepted action per tick51.5
QUETZALDestinationNetworkWalkerActionOpens the row-defined landing-site NPCSelects an unambiguous dialogue or visible map destination51.5
SPIRIT_TREEDestinationNetworkWalkerActionOpens the row-defined spirit-tree objectSelects an unambiguous dialogue or visible destination widget51.5
CHARTER_SHIPDestinationNetworkWalkerActionOpens the row-defined crew NPCSelects an unambiguous dialogue or visible destination widget51.5
GNOME_GLIDERDestinationNetworkWalkerActionOpens the row-defined pilot NPCSelects an unambiguous dialogue or visible destination widget51.5
TELEPORTATION_ITEMTeleportItemWalkerActionPrefers a matching equipped item, then inventory; uses the parsed item ID/name and actionSelects a secondary dialogue option when displayInfo contains one51.2
TELEPORTATION_SPELL, TELEPORTATION_SPELL_HOMETeleportSpellWalkerActionNormalizes the display spell name against Spell using ActionResolver and calls MagicActions.castSelects a secondary dialogue option when present51.2
CANOECanoeWalkerActionObserves build and destination interfaces plus station actionsProgresses through chop, shape, float, paddle, destination selection, and wilderness confirmation from live state31.3
TELEPORTATION_MINIGAMEMinigameTeleportWalkerActionOpens the Magic entry pointChooses the resolved minigame and waits for observed arrival201.2
TOLL_GATE (e.g. Al-Kharid gate)TollGateWalkerActionInteracts with gate object (IDs 2882/2883 or Pay-fare)Handles fee payment (coins) and dialogue prompts ("Pay 10 coins", "Can I come through?") before observing gate opening11.1
BOAT, MAGIC_CARPET, SHIPNpcWalkerActionUses the row NPC ID/name and required actionAdvances allowlisted travel/payment dialogue, then completes after observed destination-plane arrival within five tiles and no destination-side vessel crossing remains51.5
TRANSPORTImportedTransportWalkerActionResolves the exact row ID/name/action against live NPCs and objects; dispatches only when exactly one target kind matchesDelegates to the NPC or object executor; both or neither matching fails closedvariesvaries
AGILITY_SHORTCUT, GRAPPLE_SHORTCUT, and remaining object-backed typesImportedObjectWalkerActionUses the row object ID/name/action; transformed closed objects may match by name/actionObserves destination arrival; vessel traversal and adjacent barriers require exact arrival, other object transports allow two tiles, and shortcuts additionally fail after a bounded wait0/21.0

The action classes are package-private implementation details. Callers use Walker, NavigationActions, route options, and route snapshots rather than constructing transport actions directly.

Destination selector state machine

DestinationNetworkWalkerAction provides the common state machine for Quetzals, spirit trees, charter ships, and gnome gliders.

StateObservationActionNext state
Awaiting entryPlayer is not already near the destinationInteract with the exact NPC/object and row actionSelector opening
Selector openingDialogue is openSelect the normalized destination textDestination selected
Selector openingNo dialogue; one matching visible widget existsDispatch Travel, Select, or ContinueDestination selected
Selector openingNo unique match existsWait without blind-clickingSelector opening
Destination selectedPlayer has not arrivedIssue no duplicate selectionDestination selected
AnyPlayer is on the destination plane within five tiles and no destination-side vessel crossing remainsReport completionComplete

Visible-widget lookup scans loaded widget roots and dispatches only when it resolves one unique match. Zero matches wait. Multiple matches fail closed for that tick. Jagex color and formatting tags are removed before destination-label normalization. This avoids substituting a guessed packed widget ID or clicking an ambiguous label.

Pre-execution Requirement Revalidation

All transport actions implement validateRequirements(WalkerContext) which is called by WalkerPath.tickActionStep() before dispatching the action. This ensures requirements are still met at execution time (not only planning time):

  • FairyRingWalkerAction: Verifies Lumbridge Elite Diary varbit or staff in equipment/inventory
  • TeleportItemWalkerAction: Checks item still exists in equipment/inventory
  • TeleportSpellWalkerAction: Validates spell is known and available
  • CanoeWalkerAction: Confirms axe in inventory/equipment and minimum Woodcutting level
  • TollGateWalkerAction: Verifies sufficient coins for toll fee
  • NpcWalkerAction: Confirms the expected NPC remains resolvable, unless destination arrival is already observed
  • ImportedObjectWalkerAction: Confirms the row-defined object/action, a name/action-matching transformed object, destination arrival, or an observed already-open adjacent Open barrier
  • ImportedTransportWalkerAction: Delegates to resolved delegate's validation
  • DestinationNetworkWalkerAction (SpiritTree, Quetzal, Charter, Glider): Returns true (validated upstream)

If validation fails, WalkerPath increments recoveryAttempts and triggers a replan with decision requirements-changed-replan:<stepName>.

Specialized behavior

Fairy rings

The handler parses a FairyRing enum code from displayInfo. If the Lumbridge Elite Diary varbit is not complete, it checks equipment first and inventory second for a Dramen or Lunar staff. An inventory staff equips, and the next tick re-observes equipment before ring interaction continues. Dial rotation and confirmation reuse FairyRingActions, which owns the dial varbits, widget constants, last-destination optimization, and per-tick pacing.

Item teleports

The item handler searches using both the imported numeric ID and target name. It prefers equipped items because worn jewellery often exposes the desired destination directly; inventory items use the imported action plus destination, Rub, and Teleport fallbacks. After one accepted dispatch, the handler does not repeat the item interaction. If a destination dialogue appears, it selects the parsed secondary option.

Route requirements remain responsible for deciding whether charges, items, and other prerequisites make an edge eligible. The execution handler does not reconstruct upstream charge tables.

Spell teleports

The handler normalizes the text before the first colon to an uppercase underscore enum name and resolves it against Spell. Unknown spells fail closed. Casting goes through MagicActions.cast, keeping active spellbook checks, widget availability, pacing, rune checks, and structured failures centralized.

Canoes

CanoeWalkerAction derives its next operation from visible interfaces and the station's current actions rather than assuming a fixed elapsed-time sequence. It validates the minimum Woodcutting level and an inventory/equipped axe before chopping, chooses the best canoe supported by the real Woodcutting level, and handles wilderness confirmation before waiting for arrival.

Generic target resolution and object fallback

TRANSPORT metadata does not identify an ID namespace. The numeric value can refer to an NPC even though the upstream field is historically named objectInfo. ImportedTransportWalkerAction therefore queries both live target kinds using the row-defined ID, name, and action before dispatch:

  • one matching NPC delegates to NpcWalkerAction;
  • one matching object delegates to ImportedObjectWalkerAction;
  • both matching, or neither matching, fails closed and lets WalkerPath recover or replan.

The Varrock-side Civitas route is the regression case:

3280 3412 0 -> 1700 3141 0
TRANSPORT
Travel Primio 12888

Primio is an NPC. The live RuneLite menu event uses NPC_FIRST_OPTION and the NPC's current scene index, while target discovery continues to use NPC ID 12888. Treating that ID as an object produces no dispatch and creates the empty-path replan loop that this resolver prevents.

ImportedObjectWalkerAction remains the executor for resolved generic objects, ordinary imported object types, and shortcuts. It first prefers the row-defined ID/name/action and may then match a transformed closed object by the same name/action without requiring the stale ID. Non-adjacent objects wait for correct-plane arrival within two tiles; they do not wait for a static ladder, portal, or lever to despawn. Vessel traversal actions require exact destination arrival. Disembark, Board, Embark, and Cross-gangplank identify vessel traversal directly; generic Cross, Walk-across, and Leave require a gangplank, mooring, or plank object name, so ordinary bridge shortcuts keep their two-tile completion radius. For an adjacent same-plane Open barrier, the live physical-door query distinguishes closed openable state from a close-only transformed open state. Once open, it queues one correlated movement request to the exact destination. The already-open bypass is not used for missing non-barrier objects.

Agility and grapple shortcuts enable the bounded-shortcut flag. If it does not observe completion after ten action ticks, the action fails and lets WalkerPath recover or replan instead of waiting indefinitely. We deliberately do not enable the bounded wait for ordinary object transports because their animation and plane-change timing can legitimately be longer.

LiveWalkerContext behavior

The live context provides the transport handlers with these guarantees:

  • inventory and equipment name patterns are case-insensitive;
  • NPC and object names are case-insensitive while actions are already matched case-insensitively;
  • object lookup accepts either the scene object's ID or the resolved ObjectComposition ID, covering transformed/multiloc objects;
  • widget destination selection must resolve one visible match;
  • client state reads marshal through ClientThreadBridge when needed;
  • all queued interactions use existing result-aware action APIs.
  • dispatched walker NPC/object actions copy through Packet Utils' disabled-by-default issued-action clipboard trace, including the NPC ID and current scene index for NPC actions.

VesselDisembarkation supplies a dedicated gangplank/mooring query rather than adding vessel verbs to the generic door policy. Barrier lookup scans the area between the source and destination, including a one-tile margin, and accepts only Disembark, Cross-gangplank, Walk-across, Cross, and Leave under the vessel-name rules above. Board and Embark are embarkation actions — they put the player onto a vessel, not off it — and are deliberately excluded from the barrier-detection filter so charter ship dock gangplanks are never treated as blocking doors during land-step traversal. Nearby recovery uses the same disembarkation set and prioritizes Disembark, Cross-gangplank, Walk-across, Cross, then Leave.

Vessel arrival and land-step recovery

NPC and destination-network transports do not report completion merely because the player enters their normal five-tile arrival radius. When a nearby vessel barrier still lies on the destination side, requiresDisembarkation(...) keeps the action active. Exact destination arrival clears the requirement.

After a transport, a land route can be empty or its movement dispatch can fail across the water gap. WalkerPath then requests one nearby disembarkation for that land step. An accepted interaction waits up to three walker ticks for a location change. Progress recalculates the remaining land path. No progress, a rejected interaction, or a second request returns to the existing exhausted-step replan path. This bound prevents a gangplank interaction from replacing a NO_ROUTE failure with an unlimited retry loop.

The default WalkerContext.queueVisibleWidgetByText implementation returns false. This preserves compatibility for deterministic fake contexts while requiring test doubles to opt into selector behavior explicitly when a test covers a destination-map transition.

Failure and retry semantics

A handler returns false when it cannot resolve or accept its required target, item, spell, or initial interaction. WalkerPath records that failure and applies its existing retry/replan policy. Once an entry or destination selection is accepted, handlers wait for observable state instead of issuing the same action every tick.

Completion relies on player position, not merely on an accepted click. For specialized handlers and NpcWalkerAction, arrival means the player is on the same plane and within five tiles of the selected edge destination. Imported object arrival uses radius zero for adjacent barriers and radius two otherwise; source-equals-destination rows still require the defined action transition. Moving away from the source does not complete an NPC or object transport. NPC dialogue progression is limited to Can I journey on this ship?, Pay-fare, Yes, and visible continue prompts, with at most one accepted dialogue action per tick. Unknown dialogue waits under the existing route-step timeout rather than selecting an arbitrary option.

Automated validation

Use the focused resolver and canoe tests first:

.\gradlew.bat test --tests com.n3plugins.sdk.walker.PluginTransportActionResolverTest --tests com.n3plugins.sdk.walker.NpcWalkerActionTest --tests com.n3plugins.sdk.walker.CanoeWalkerActionTest --console plain
./gradlew test --tests com.n3plugins.sdk.walker.PluginTransportActionResolverTest --tests com.n3plugins.sdk.walker.NpcWalkerActionTest --tests com.n3plugins.sdk.walker.CanoeWalkerActionTest --console plain

Then run the shared walker suite for changes to context, action state, or path recovery:

.\gradlew.bat test --tests com.n3plugins.sdk.walker.* --console plain
./gradlew test --tests 'com.n3plugins.sdk.walker.*' --console plain

Documentation changes require the checks in validation.md:

./gradlew auditDocs checkDocDrift --console plain
npm --prefix docs-site run build

Live-client acceptance checklist

Static tests cannot establish current UI or in-world correctness. Before marking transport execution live-verified, record evidence for:

  1. one world fairy ring that requires equipping a staff and one account with the Lumbridge Elite Diary bypass;
  2. POH and world spirit-tree entry where available;
  3. a Quetzal map destination selected through Renu;
  4. one charter-ship and one gnome-glider map destination;
  5. an equipped multi-destination teleport item and an inventory teleport item;
  6. a direct spell teleport and a spell with a secondary destination option;
  7. all canoe phases, including a wilderness confirmation route;
  8. an agility shortcut that completes and one controlled failure that reaches the bounded retry path;
  9. generic object, boat, magic-carpet, and ship regression routes;
  10. the generic Varrock-side Travel Primio 12888 route, with NPC_FIRST_OPTION, live NPC index, and arrival near (1700,3141,0) observed after rebuilding and reloading the plugin.

Record the RuneLite version, game revision, source/destination, imported metadata, execution decisions, and observed landing point for each result. For scenarios without that evidence, report:

Live client verification: pending

Recorded live evidence

DateRevisionRouteMetadataResultEvidence boundary
2026-07-29239Varrock-side (3280,3412,0) to Civitas (1700,3141,0)TRANSPORT, Travel Primio 12888Passed in game after the generic target-resolution fixUser-verified route completion; no Agent Server operation record or retained screenshot was supplied
2026-08-31240Any charter ship route (e.g. Brimhaven → Port Sarim)CHARTER_SHIP, Charter Trader Crewmember 1330VesselDisembarkation.findBetween() changed to use selectAction() only; Board/Embark no longer register as blocking barriers during land-step traversal. boardOnlyObjectIsNotABlockingDoorBarrier test added and passing.Static fix; live client verification pending

This closes live acceptance for the specific Primio regression route. It does not establish live correctness for the other transports in the checklist.