Summary
In Rs2Walker.handleTransports(...), the inner for (int i = indexOfStartPoint; i < path.size(); i++) loop has break statements after every transport-type handler except SHIP, NPC, and BOAT. As a result, when a candidate SHIP/NPC/BOAT transport is processed (or simply considered) the loop continues iterating the entire remaining path, doing per-iteration work and emitting per-iteration log.debug lines.
Where
runelite-client/src/main/java/net/runelite/client/plugins/microbot/util/walker/Rs2Walker.java, around lines 1937–1972 on development:
if (path.get(i).equals(origin)) {
if (transport.getType() == TransportType.SHIP || transport.getType() == TransportType.NPC || transport.getType() == TransportType.BOAT) {
Rs2NpcModel npc = Rs2Npc.getNpc(transport.getName());
if (Rs2Npc.canWalkTo(npc, 20) && Rs2Npc.interact(npc, transport.getAction())) {
Rs2Player.waitForWalking();
// ... dialogue / animation / distance waits ...
sleepTickJitter(6);
} else {
Rs2Walker.walkFastCanvas(path.get(i));
sleep(1200, 1600);
}
// <-- no break here, success or failure
}
if (transport.getType() == TransportType.CHARTER_SHIP) {
if (handleCharterShip(transport)) {
// ...
break; // <-- CHARTER_SHIP breaks
}
}
}
log.debug("[Walker] Handling {} transport: {} (i={}, path[i]={}, origin={})", ...);
if (transport.getType() == TransportType.POH) { ... break; }
if (transport.getType() == TransportType.CANOE) { ... break; }
if (transport.getType() == TransportType.SPIRIT_TREE) { ... break; }
if (transport.getType() == TransportType.QUETZAL) { ... break; }
if (transport.getType() == TransportType.MAGIC_CARPET) { ... break; }
if (transport.getType() == TransportType.WILDERNESS_OBELISK) { ... break; }
if (transport.getType() == TransportType.GNOME_GLIDER) { ... break; }
if (transport.getType() == TransportType.FAIRY_RING) { ... break; }
if (transport.getType() == TransportType.TELEPORTATION_MINIGAME) { ... break; }
if (transport.getType() == TransportType.TELEPORTATION_ITEM) { ... break; }
if (transport.getType() == TransportType.TELEPORTATION_SPELL) { ... break; }
if (transport.getType() == TransportType.SEASONAL_TRANSPORT) { ... break; }
if (transport.getObjectId() <= 0) break;
// fallthrough: scene-object scan via Rs2GameObject.getAll(predicate, transport.getOrigin(), 10)
SHIP, NPC, BOAT are the only types whose handler is intended to be terminal but does not break. Once path.get(i).equals(origin) matches and the NPC/ship is interacted with, control falls through and i keeps advancing.
For NPC transports whose objectId > 0, the if (transport.getObjectId() <= 0) break; guard at ~line 2079 does not fire either, so each subsequent iteration also runs the Rs2GameObject.getAll(predicate, transport.getOrigin(), 10) scene scan that follows.
Symptom — log evidence
While running through the Auburn Valley NPC transport, handleTransports produces ~99 consecutive Handling NPC transport lines for a single transport candidate, all sharing the same origin, while i walks from indexOfStartPoint to path.size()-1:
[Walker] Handling NPC transport: Auburn Valley (i=388, path[i]=WorldPoint(x=1364, y=3287, plane=0), origin=WorldPoint(x=1487, y=3232, plane=0))
[Walker] Handling NPC transport: Auburn Valley (i=389, path[i]=WorldPoint(x=1364, y=3286, plane=0), origin=WorldPoint(x=1487, y=3232, plane=0))
...
[Walker] Handling NPC transport: Auburn Valley (i=486, path[i]=WorldPoint(x=1274, y=3168, plane=0), origin=WorldPoint(x=1487, y=3232, plane=0))
origin=(1487, 3232) is well behind the player's current position in the path, so path.get(i).equals(origin) is never true in this run — the loop is purely overhead. With debug logging on, this runs on the script thread and visibly delays the walker between game ticks; with debug logging off, the per-iteration Rs2GameObject.getAll(...) scan still runs.
Expected behavior
The SHIP/NPC/BOAT branch should break after a successful interaction (mirroring CHARTER_SHIP directly below it and every other terminal handler in the same loop). Additionally, the bare Rs2Npc.interact(...) failure path (else { walkFastCanvas; sleep; }) probably should also break rather than falling through into the fallback scene-object scan, since it is unrelated to the NPC interaction.
Suggested fix
Add explicit breaks to the SHIP/NPC/BOAT block, e.g.:
if (transport.getType() == TransportType.SHIP || transport.getType() == TransportType.NPC || transport.getType() == TransportType.BOAT) {
Rs2NpcModel npc = Rs2Npc.getNpc(transport.getName());
if (Rs2Npc.canWalkTo(npc, 20) && Rs2Npc.interact(npc, transport.getAction())) {
// ... existing handling ...
sleepTickJitter(6);
break;
} else {
Rs2Walker.walkFastCanvas(path.get(i));
sleep(1200, 1600);
break;
}
}
Reproduction
- Have the script walk a long route that crosses an NPC transport (e.g. the Quetzal NPCs in Varlamore: Auburn Valley, Quetzacalli Gorge).
- Enable DEBUG for
net.runelite.client.plugins.microbot.util.walker.Rs2Walker.
- Observe
[Walker] Handling NPC transport: <name> repeating ~path.size() - indexOfStartPoint times for a single transport on a single handleTransports invocation.
Versions
- Repo:
chsami/Microbot
- Branch:
development
- File:
runelite-client/src/main/java/net/runelite/client/plugins/microbot/util/walker/Rs2Walker.java
- Lines: 1925–2160 (
handleTransports inner loop)
Summary
In
Rs2Walker.handleTransports(...), the innerfor (int i = indexOfStartPoint; i < path.size(); i++)loop hasbreakstatements after every transport-type handler exceptSHIP,NPC, andBOAT. As a result, when a candidateSHIP/NPC/BOATtransport is processed (or simply considered) the loop continues iterating the entire remaining path, doing per-iteration work and emitting per-iterationlog.debuglines.Where
runelite-client/src/main/java/net/runelite/client/plugins/microbot/util/walker/Rs2Walker.java, around lines 1937–1972 ondevelopment:SHIP,NPC,BOATare the only types whose handler is intended to be terminal but does notbreak. Oncepath.get(i).equals(origin)matches and the NPC/ship is interacted with, control falls through andikeeps advancing.For
NPCtransports whoseobjectId > 0, theif (transport.getObjectId() <= 0) break;guard at ~line 2079 does not fire either, so each subsequent iteration also runs theRs2GameObject.getAll(predicate, transport.getOrigin(), 10)scene scan that follows.Symptom — log evidence
While running through the Auburn Valley NPC transport,
handleTransportsproduces ~99 consecutiveHandling NPC transportlines for a single transport candidate, all sharing the sameorigin, whileiwalks fromindexOfStartPointtopath.size()-1:origin=(1487, 3232)is well behind the player's current position in the path, sopath.get(i).equals(origin)is never true in this run — the loop is purely overhead. With debug logging on, this runs on the script thread and visibly delays the walker between game ticks; with debug logging off, the per-iterationRs2GameObject.getAll(...)scan still runs.Expected behavior
The
SHIP/NPC/BOATbranch shouldbreakafter a successful interaction (mirroringCHARTER_SHIPdirectly below it and every other terminal handler in the same loop). Additionally, the bareRs2Npc.interact(...)failure path (else { walkFastCanvas; sleep; }) probably should alsobreakrather than falling through into the fallback scene-object scan, since it is unrelated to the NPC interaction.Suggested fix
Add explicit
breaks to theSHIP/NPC/BOATblock, e.g.:Reproduction
net.runelite.client.plugins.microbot.util.walker.Rs2Walker.[Walker] Handling NPC transport: <name>repeating ~path.size() - indexOfStartPointtimes for a single transport on a singlehandleTransportsinvocation.Versions
chsami/Microbotdevelopmentrunelite-client/src/main/java/net/runelite/client/plugins/microbot/util/walker/Rs2Walker.javahandleTransportsinner loop)