Conversation
|
Important Review skippedAuto incremental reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the You can disable this status message by setting the WalkthroughThis pull request implements a comprehensive sailing system for the microbot plugin. The changes include updating the microbot version in the build configuration, modifying core utility classes to support client-thread execution for safer data access, integrating a new Rs2Sailing utility class with extensive boat navigation and control capabilities, introducing multiple sailing-related data classes (BoatType, Heading, PortLocation, PortPaths, etc.), creating a SailingPanel UI component for route selection and navigation, and refactoring existing utilities like Rs2GameObject and NewMenuEntry to handle world view context. Additionally, the example plugin is updated to demonstrate overlay management using the new infrastructure. Possibly related PRs
Pre-merge checks and finishing touches❌ Failed checks (1 warning, 1 inconclusive)
✅ Passed checks (1 passed)
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. Comment |
There was a problem hiding this comment.
Actionable comments posted: 3
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (2)
runelite-client/src/main/java/net/runelite/client/plugins/microbot/util/gameobject/Rs2GameObject.java (2)
1523-1607: Boat-aware scene traversal has inconsistent plane handling and ignores predicatesTwo problems in
getSceneObjects(...):
Plane/scene selection logic is self-contradictory
- In the
elsebranch you callplayer.getWorldView().getScene()even thoughworldViewis known to be null, which can NPE if that path is ever taken.int z = Rs2Sailing.isOnBoat() ? 3 : player.getWorldView().getPlane();is then used as an upper bound infor (int h = 0; h < z; h++), butzis a plane index, not a plane count. This means:
- When
plane == 0, you never iterate any tiles.- When
plane == 1, you only scantiles[0].- On boats, if the relevant tiles are not all on planes
< 3, they may be skipped.This will cause object enumeration to silently miss the actual plane in several configurations.
Boat branch of
getSceneObjects(extractor, predicate, anchorLocal, distance)ignores the predicate
- When
Rs2Sailing.isOnBoat()is true, you returngetSceneObjects(extractor).collect(...)without applyingpredicateordistance.- Callers like
getGameObject(id, ...)rely on this predicate to limit results to a specific id/name, so on a boat they may receive the first arbitrary object in the scene instead of a matching one.Consider reworking these pieces along the following lines:
- Use
worldViewconsistently with a safe fallback:WorldView worldView = player.getWorldView(); WorldView fallback = Microbot.getClient().getTopLevelWorldView(); WorldView effective = worldView != null ? worldView : fallback; Scene scene = effective.getScene(); Tile[][][] tiles = scene.getTiles(); int z = effective.getPlane(); // or a known constant if you truly need a fixed boat plane
Iterate the plane you actually want (e.g.
Tile tile = tiles[z][x][y];) or, if you intend to scan all planes, use a fixed bound (for (int h = 0; h < Constants.MAX_Z; h++)), not a single plane index.In
getSceneObjects(extractor, predicate, anchorLocal, distance), keep the boat-specific distance relaxation but still honor the predicate:if (Rs2Sailing.isOnBoat()) { return getSceneObjects(extractor) .filter(predicate) .collect(Collectors.toList()); }
1738-1741:fetchGameObjects(..., WorldPoint)incorrectly delegates tofetchTileObjectsThe overload:
private static <T extends TileObject> List<T> fetchGameObjects(Predicate<? super T> predicate, WorldPoint anchor) { return fetchTileObjects(predicate, anchor, Constants.SCENE_SIZE); }never actually fetches
GameObjects; it callsfetchTileObjects, so any use of this method will silently return tile/ground/wall objects instead of game objects.It should delegate to the
fetchGameObjects(predicate, anchor, distance)overload:private static <T extends TileObject> List<T> fetchGameObjects(Predicate<? super T> predicate, WorldPoint anchor) { - return fetchTileObjects(predicate, anchor, Constants.SCENE_SIZE); + return fetchGameObjects(predicate, anchor, Constants.SCENE_SIZE); }
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (1)
runelite-client/src/main/resources/net/runelite/client/plugins/microbot/shortestpath/sailing_icon.pngis excluded by!**/*.png
📒 Files selected for processing (20)
runelite-client/pom.xml(1 hunks)runelite-client/src/main/java/net/runelite/client/plugins/microbot/Microbot.java(2 hunks)runelite-client/src/main/java/net/runelite/client/plugins/microbot/MicrobotPlugin.java(3 hunks)runelite-client/src/main/java/net/runelite/client/plugins/microbot/example/ExamplePlugin.java(2 hunks)runelite-client/src/main/java/net/runelite/client/plugins/microbot/example/ExampleScript.java(2 hunks)runelite-client/src/main/java/net/runelite/client/plugins/microbot/example/ExampleScriptOverlay.java(1 hunks)runelite-client/src/main/java/net/runelite/client/plugins/microbot/shortestpath/SailingPanel.java(1 hunks)runelite-client/src/main/java/net/runelite/client/plugins/microbot/shortestpath/ShortestPathPlugin.java(3 hunks)runelite-client/src/main/java/net/runelite/client/plugins/microbot/util/gameobject/Rs2GameObject.java(13 hunks)runelite-client/src/main/java/net/runelite/client/plugins/microbot/util/menu/NewMenuEntry.java(4 hunks)runelite-client/src/main/java/net/runelite/client/plugins/microbot/util/player/Rs2Player.java(2 hunks)runelite-client/src/main/java/net/runelite/client/plugins/microbot/util/sailing/Rs2Sailing.java(1 hunks)runelite-client/src/main/java/net/runelite/client/plugins/microbot/util/sailing/data/BoatPathFollower.java(1 hunks)runelite-client/src/main/java/net/runelite/client/plugins/microbot/util/sailing/data/BoatType.java(1 hunks)runelite-client/src/main/java/net/runelite/client/plugins/microbot/util/sailing/data/Heading.java(1 hunks)runelite-client/src/main/java/net/runelite/client/plugins/microbot/util/sailing/data/LedgerID.java(1 hunks)runelite-client/src/main/java/net/runelite/client/plugins/microbot/util/sailing/data/PortLocation.java(1 hunks)runelite-client/src/main/java/net/runelite/client/plugins/microbot/util/sailing/data/PortPaths.java(1 hunks)runelite-client/src/main/java/net/runelite/client/plugins/microbot/util/sailing/data/PortTaskVarbits.java(1 hunks)runelite-client/src/main/java/net/runelite/client/plugins/microbot/util/sailing/data/RelativeMove.java(1 hunks)
🧰 Additional context used
📓 Path-based instructions (7)
runelite-client/src/main/java/net/runelite/client/plugins/microbot/**/*.java
📄 CodeRabbit inference engine (AGENTS.md)
runelite-client/src/main/java/net/runelite/client/plugins/microbot/**/*.java: Place all gameplay automation code under runelite-client/src/main/java/net/runelite/client/plugins/microbot
Prefix configuration interfaces with the plugin name (e.g., ExampleConfig) within microbot plugins
Files:
runelite-client/src/main/java/net/runelite/client/plugins/microbot/util/sailing/data/RelativeMove.javarunelite-client/src/main/java/net/runelite/client/plugins/microbot/util/sailing/data/BoatType.javarunelite-client/src/main/java/net/runelite/client/plugins/microbot/example/ExampleScriptOverlay.javarunelite-client/src/main/java/net/runelite/client/plugins/microbot/shortestpath/SailingPanel.javarunelite-client/src/main/java/net/runelite/client/plugins/microbot/util/player/Rs2Player.javarunelite-client/src/main/java/net/runelite/client/plugins/microbot/MicrobotPlugin.javarunelite-client/src/main/java/net/runelite/client/plugins/microbot/util/sailing/data/PortTaskVarbits.javarunelite-client/src/main/java/net/runelite/client/plugins/microbot/util/sailing/data/PortPaths.javarunelite-client/src/main/java/net/runelite/client/plugins/microbot/util/sailing/data/LedgerID.javarunelite-client/src/main/java/net/runelite/client/plugins/microbot/util/sailing/data/PortLocation.javarunelite-client/src/main/java/net/runelite/client/plugins/microbot/util/sailing/Rs2Sailing.javarunelite-client/src/main/java/net/runelite/client/plugins/microbot/util/sailing/data/BoatPathFollower.javarunelite-client/src/main/java/net/runelite/client/plugins/microbot/example/ExamplePlugin.javarunelite-client/src/main/java/net/runelite/client/plugins/microbot/example/ExampleScript.javarunelite-client/src/main/java/net/runelite/client/plugins/microbot/util/sailing/data/Heading.javarunelite-client/src/main/java/net/runelite/client/plugins/microbot/shortestpath/ShortestPathPlugin.javarunelite-client/src/main/java/net/runelite/client/plugins/microbot/Microbot.javarunelite-client/src/main/java/net/runelite/client/plugins/microbot/util/gameobject/Rs2GameObject.javarunelite-client/src/main/java/net/runelite/client/plugins/microbot/util/menu/NewMenuEntry.java
runelite-client/src/main/java/net/runelite/client/plugins/microbot/util/**/*.java
📄 CodeRabbit inference engine (AGENTS.md)
Put shared helpers under .../microbot/util
Files:
runelite-client/src/main/java/net/runelite/client/plugins/microbot/util/sailing/data/RelativeMove.javarunelite-client/src/main/java/net/runelite/client/plugins/microbot/util/sailing/data/BoatType.javarunelite-client/src/main/java/net/runelite/client/plugins/microbot/util/player/Rs2Player.javarunelite-client/src/main/java/net/runelite/client/plugins/microbot/util/sailing/data/PortTaskVarbits.javarunelite-client/src/main/java/net/runelite/client/plugins/microbot/util/sailing/data/PortPaths.javarunelite-client/src/main/java/net/runelite/client/plugins/microbot/util/sailing/data/LedgerID.javarunelite-client/src/main/java/net/runelite/client/plugins/microbot/util/sailing/data/PortLocation.javarunelite-client/src/main/java/net/runelite/client/plugins/microbot/util/sailing/Rs2Sailing.javarunelite-client/src/main/java/net/runelite/client/plugins/microbot/util/sailing/data/BoatPathFollower.javarunelite-client/src/main/java/net/runelite/client/plugins/microbot/util/sailing/data/Heading.javarunelite-client/src/main/java/net/runelite/client/plugins/microbot/util/gameobject/Rs2GameObject.javarunelite-client/src/main/java/net/runelite/client/plugins/microbot/util/menu/NewMenuEntry.java
**/*.java
📄 CodeRabbit inference engine (AGENTS.md)
**/*.java: Use tabs for indentation, follow the brace placement style exemplified in MicrobotPlugin.java, and keep lines under 120 characters
Use UpperCamelCase for types and lowerCamelCase for members
Files:
runelite-client/src/main/java/net/runelite/client/plugins/microbot/util/sailing/data/RelativeMove.javarunelite-client/src/main/java/net/runelite/client/plugins/microbot/util/sailing/data/BoatType.javarunelite-client/src/main/java/net/runelite/client/plugins/microbot/example/ExampleScriptOverlay.javarunelite-client/src/main/java/net/runelite/client/plugins/microbot/shortestpath/SailingPanel.javarunelite-client/src/main/java/net/runelite/client/plugins/microbot/util/player/Rs2Player.javarunelite-client/src/main/java/net/runelite/client/plugins/microbot/MicrobotPlugin.javarunelite-client/src/main/java/net/runelite/client/plugins/microbot/util/sailing/data/PortTaskVarbits.javarunelite-client/src/main/java/net/runelite/client/plugins/microbot/util/sailing/data/PortPaths.javarunelite-client/src/main/java/net/runelite/client/plugins/microbot/util/sailing/data/LedgerID.javarunelite-client/src/main/java/net/runelite/client/plugins/microbot/util/sailing/data/PortLocation.javarunelite-client/src/main/java/net/runelite/client/plugins/microbot/util/sailing/Rs2Sailing.javarunelite-client/src/main/java/net/runelite/client/plugins/microbot/util/sailing/data/BoatPathFollower.javarunelite-client/src/main/java/net/runelite/client/plugins/microbot/example/ExamplePlugin.javarunelite-client/src/main/java/net/runelite/client/plugins/microbot/example/ExampleScript.javarunelite-client/src/main/java/net/runelite/client/plugins/microbot/util/sailing/data/Heading.javarunelite-client/src/main/java/net/runelite/client/plugins/microbot/shortestpath/ShortestPathPlugin.javarunelite-client/src/main/java/net/runelite/client/plugins/microbot/Microbot.javarunelite-client/src/main/java/net/runelite/client/plugins/microbot/util/gameobject/Rs2GameObject.javarunelite-client/src/main/java/net/runelite/client/plugins/microbot/util/menu/NewMenuEntry.java
**/pom.xml
📄 CodeRabbit inference engine (AGENTS.md)
Target Java 11 via maven-compiler-plugin using 11 in all module POMs
Files:
runelite-client/pom.xml
runelite-client/src/main/java/net/runelite/client/plugins/microbot/example/**/*.java
📄 CodeRabbit inference engine (AGENTS.md)
Keep runnable examples under .../microbot/example
Files:
runelite-client/src/main/java/net/runelite/client/plugins/microbot/example/ExampleScriptOverlay.javarunelite-client/src/main/java/net/runelite/client/plugins/microbot/example/ExamplePlugin.javarunelite-client/src/main/java/net/runelite/client/plugins/microbot/example/ExampleScript.java
runelite-client/src/main/java/net/runelite/client/plugins/microbot/@(!(util|example))/**/*.java
📄 CodeRabbit inference engine (AGENTS.md)
For new automation scripts, reuse the scheduler pattern demonstrated in ExampleScript
Files:
runelite-client/src/main/java/net/runelite/client/plugins/microbot/shortestpath/SailingPanel.javarunelite-client/src/main/java/net/runelite/client/plugins/microbot/shortestpath/ShortestPathPlugin.java
runelite-client/src/main/java/net/runelite/client/plugins/microbot/MicrobotPlugin.java
📄 CodeRabbit inference engine (AGENTS.md)
When adding panel controls or overlays, update the Microbot navigation panel setup in MicrobotPlugin and provide default config values
Files:
runelite-client/src/main/java/net/runelite/client/plugins/microbot/MicrobotPlugin.java
🧠 Learnings (12)
📓 Common learnings
Learnt from: CR
Repo: chsami/Microbot PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-10-16T17:14:29.778Z
Learning: Applies to runelite-client/src/main/java/net/runelite/client/plugins/microbot/MicrobotPlugin.java : When adding panel controls or overlays, update the Microbot navigation panel setup in MicrobotPlugin and provide default config values
📚 Learning: 2025-10-16T17:14:29.778Z
Learnt from: CR
Repo: chsami/Microbot PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-10-16T17:14:29.778Z
Learning: Applies to runelite-client/src/main/java/net/runelite/client/plugins/microbot/util/**/*.java : Put shared helpers under .../microbot/util
Applied to files:
runelite-client/src/main/java/net/runelite/client/plugins/microbot/util/sailing/data/RelativeMove.javarunelite-client/pom.xmlrunelite-client/src/main/java/net/runelite/client/plugins/microbot/shortestpath/SailingPanel.javarunelite-client/src/main/java/net/runelite/client/plugins/microbot/util/player/Rs2Player.javarunelite-client/src/main/java/net/runelite/client/plugins/microbot/MicrobotPlugin.javarunelite-client/src/main/java/net/runelite/client/plugins/microbot/util/sailing/Rs2Sailing.javarunelite-client/src/main/java/net/runelite/client/plugins/microbot/example/ExamplePlugin.javarunelite-client/src/main/java/net/runelite/client/plugins/microbot/example/ExampleScript.javarunelite-client/src/main/java/net/runelite/client/plugins/microbot/shortestpath/ShortestPathPlugin.javarunelite-client/src/main/java/net/runelite/client/plugins/microbot/Microbot.javarunelite-client/src/main/java/net/runelite/client/plugins/microbot/util/gameobject/Rs2GameObject.java
📚 Learning: 2025-10-16T17:14:29.778Z
Learnt from: CR
Repo: chsami/Microbot PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-10-16T17:14:29.778Z
Learning: Applies to runelite-client/src/main/java/net/runelite/client/plugins/microbot/**/*.java : Place all gameplay automation code under runelite-client/src/main/java/net/runelite/client/plugins/microbot
Applied to files:
runelite-client/pom.xmlrunelite-client/src/main/java/net/runelite/client/plugins/microbot/example/ExampleScriptOverlay.javarunelite-client/src/main/java/net/runelite/client/plugins/microbot/shortestpath/SailingPanel.javarunelite-client/src/main/java/net/runelite/client/plugins/microbot/util/player/Rs2Player.javarunelite-client/src/main/java/net/runelite/client/plugins/microbot/MicrobotPlugin.javarunelite-client/src/main/java/net/runelite/client/plugins/microbot/util/sailing/Rs2Sailing.javarunelite-client/src/main/java/net/runelite/client/plugins/microbot/util/sailing/data/BoatPathFollower.javarunelite-client/src/main/java/net/runelite/client/plugins/microbot/example/ExamplePlugin.javarunelite-client/src/main/java/net/runelite/client/plugins/microbot/example/ExampleScript.javarunelite-client/src/main/java/net/runelite/client/plugins/microbot/shortestpath/ShortestPathPlugin.javarunelite-client/src/main/java/net/runelite/client/plugins/microbot/Microbot.javarunelite-client/src/main/java/net/runelite/client/plugins/microbot/util/gameobject/Rs2GameObject.java
📚 Learning: 2025-10-16T17:14:29.778Z
Learnt from: CR
Repo: chsami/Microbot PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-10-16T17:14:29.778Z
Learning: Applies to runelite-client/src/main/java/net/runelite/client/plugins/microbot/**/*.java : Prefix configuration interfaces with the plugin name (e.g., ExampleConfig) within microbot plugins
Applied to files:
runelite-client/pom.xmlrunelite-client/src/main/java/net/runelite/client/plugins/microbot/example/ExampleScriptOverlay.javarunelite-client/src/main/java/net/runelite/client/plugins/microbot/util/player/Rs2Player.javarunelite-client/src/main/java/net/runelite/client/plugins/microbot/MicrobotPlugin.javarunelite-client/src/main/java/net/runelite/client/plugins/microbot/example/ExamplePlugin.javarunelite-client/src/main/java/net/runelite/client/plugins/microbot/example/ExampleScript.javarunelite-client/src/main/java/net/runelite/client/plugins/microbot/shortestpath/ShortestPathPlugin.javarunelite-client/src/main/java/net/runelite/client/plugins/microbot/Microbot.javarunelite-client/src/main/java/net/runelite/client/plugins/microbot/util/gameobject/Rs2GameObject.java
📚 Learning: 2025-10-16T17:14:29.778Z
Learnt from: CR
Repo: chsami/Microbot PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-10-16T17:14:29.778Z
Learning: Applies to runelite-client/src/main/java/net/runelite/client/plugins/microbot/@(!(util|example))/**/*.java : For new automation scripts, reuse the scheduler pattern demonstrated in ExampleScript
Applied to files:
runelite-client/pom.xmlrunelite-client/src/main/java/net/runelite/client/plugins/microbot/example/ExampleScriptOverlay.javarunelite-client/src/main/java/net/runelite/client/plugins/microbot/shortestpath/SailingPanel.javarunelite-client/src/main/java/net/runelite/client/plugins/microbot/util/player/Rs2Player.javarunelite-client/src/main/java/net/runelite/client/plugins/microbot/MicrobotPlugin.javarunelite-client/src/main/java/net/runelite/client/plugins/microbot/example/ExamplePlugin.javarunelite-client/src/main/java/net/runelite/client/plugins/microbot/example/ExampleScript.javarunelite-client/src/main/java/net/runelite/client/plugins/microbot/shortestpath/ShortestPathPlugin.javarunelite-client/src/main/java/net/runelite/client/plugins/microbot/Microbot.javarunelite-client/src/main/java/net/runelite/client/plugins/microbot/util/gameobject/Rs2GameObject.java
📚 Learning: 2025-10-16T17:14:29.778Z
Learnt from: CR
Repo: chsami/Microbot PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-10-16T17:14:29.778Z
Learning: Applies to runelite-client/src/main/java/net/runelite/client/plugins/microbot/example/**/*.java : Keep runnable examples under .../microbot/example
Applied to files:
runelite-client/pom.xmlrunelite-client/src/main/java/net/runelite/client/plugins/microbot/example/ExampleScriptOverlay.javarunelite-client/src/main/java/net/runelite/client/plugins/microbot/util/player/Rs2Player.javarunelite-client/src/main/java/net/runelite/client/plugins/microbot/MicrobotPlugin.javarunelite-client/src/main/java/net/runelite/client/plugins/microbot/example/ExamplePlugin.javarunelite-client/src/main/java/net/runelite/client/plugins/microbot/example/ExampleScript.javarunelite-client/src/main/java/net/runelite/client/plugins/microbot/shortestpath/ShortestPathPlugin.javarunelite-client/src/main/java/net/runelite/client/plugins/microbot/Microbot.javarunelite-client/src/main/java/net/runelite/client/plugins/microbot/util/gameobject/Rs2GameObject.java
📚 Learning: 2025-10-16T17:14:29.778Z
Learnt from: CR
Repo: chsami/Microbot PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-10-16T17:14:29.778Z
Learning: Applies to runelite-client/src/main/java/net/runelite/client/plugins/microbot/MicrobotPlugin.java : When adding panel controls or overlays, update the Microbot navigation panel setup in MicrobotPlugin and provide default config values
Applied to files:
runelite-client/pom.xmlrunelite-client/src/main/java/net/runelite/client/plugins/microbot/example/ExampleScriptOverlay.javarunelite-client/src/main/java/net/runelite/client/plugins/microbot/shortestpath/SailingPanel.javarunelite-client/src/main/java/net/runelite/client/plugins/microbot/util/player/Rs2Player.javarunelite-client/src/main/java/net/runelite/client/plugins/microbot/MicrobotPlugin.javarunelite-client/src/main/java/net/runelite/client/plugins/microbot/util/sailing/Rs2Sailing.javarunelite-client/src/main/java/net/runelite/client/plugins/microbot/example/ExamplePlugin.javarunelite-client/src/main/java/net/runelite/client/plugins/microbot/example/ExampleScript.javarunelite-client/src/main/java/net/runelite/client/plugins/microbot/shortestpath/ShortestPathPlugin.javarunelite-client/src/main/java/net/runelite/client/plugins/microbot/Microbot.javarunelite-client/src/main/java/net/runelite/client/plugins/microbot/util/gameobject/Rs2GameObject.javarunelite-client/src/main/java/net/runelite/client/plugins/microbot/util/menu/NewMenuEntry.java
📚 Learning: 2025-10-16T17:14:29.778Z
Learnt from: CR
Repo: chsami/Microbot PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-10-16T17:14:29.778Z
Learning: Applies to runelite-client/target/*.jar : Distributable JARs should be produced in runelite-client/target/
Applied to files:
runelite-client/pom.xml
📚 Learning: 2025-10-16T17:14:29.778Z
Learnt from: CR
Repo: chsami/Microbot PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-10-16T17:14:29.778Z
Learning: Applies to runelite-client/src/test/java/**/*.java : Mirror production package structure for tests under runelite-client/src/test/java
Applied to files:
runelite-client/pom.xml
📚 Learning: 2025-08-31T19:19:07.691Z
Learnt from: chsami
Repo: chsami/Microbot PR: 1455
File: runelite-client/src/main/java/net/runelite/client/plugins/microbot/MicrobotVersionChecker.java:112-132
Timestamp: 2025-08-31T19:19:07.691Z
Learning: The Microbot project uses only numeric versioning (e.g., "1.2.3") without any alphanumeric suffixes like "-beta" or "-alpha", so simple integer parsing of version segments is safe.
Applied to files:
runelite-client/pom.xml
📚 Learning: 2025-08-25T15:51:39.272Z
Learnt from: runsonmypc
Repo: chsami/Microbot PR: 1417
File: runelite-client/src/main/java/net/runelite/client/plugins/microbot/agility/AgilityScript.java:13-13
Timestamp: 2025-08-25T15:51:39.272Z
Learning: Both net.runelite.api.ItemID and net.runelite.api.gameval.ItemID are valid import paths in the RuneLite codebase. The microbot plugins consistently use net.runelite.api.ItemID as their established pattern.
Applied to files:
runelite-client/src/main/java/net/runelite/client/plugins/microbot/MicrobotPlugin.javarunelite-client/src/main/java/net/runelite/client/plugins/microbot/util/sailing/data/LedgerID.javarunelite-client/src/main/java/net/runelite/client/plugins/microbot/Microbot.javarunelite-client/src/main/java/net/runelite/client/plugins/microbot/util/gameobject/Rs2GameObject.java
📚 Learning: 2025-08-23T16:17:37.615Z
Learnt from: g-mason0
Repo: chsami/Microbot PR: 1423
File: runelite-client/src/main/java/net/runelite/client/plugins/microbot/externalplugins/MicrobotPluginManager.java:366-389
Timestamp: 2025-08-23T16:17:37.615Z
Learning: The ScheduledExecutorService injected into MicrobotPluginManager (and other RuneLite classes) is configured as a single-threaded executor via Executors.newSingleThreadScheduledExecutor() at RuneLiteModule.java line 130, wrapped in ExecutorServiceExceptionLogger. This ensures all async tasks execute sequentially, preventing race conditions.
Applied to files:
runelite-client/src/main/java/net/runelite/client/plugins/microbot/example/ExampleScript.javarunelite-client/src/main/java/net/runelite/client/plugins/microbot/Microbot.java
🧬 Code graph analysis (6)
runelite-client/src/main/java/net/runelite/client/plugins/microbot/shortestpath/SailingPanel.java (1)
runelite-client/src/main/java/net/runelite/client/plugins/microbot/util/sailing/data/BoatPathFollower.java (1)
BoatPathFollower(10-72)
runelite-client/src/main/java/net/runelite/client/plugins/microbot/util/sailing/data/LedgerID.java (1)
runelite-client/src/main/java/net/runelite/client/plugins/microbot/util/gameobject/ObjectID.java (1)
ObjectID(10-33)
runelite-client/src/main/java/net/runelite/client/plugins/microbot/util/sailing/data/PortLocation.java (1)
runelite-client/src/main/java/net/runelite/client/plugins/microbot/util/gameobject/ObjectID.java (1)
ObjectID(10-33)
runelite-client/src/main/java/net/runelite/client/plugins/microbot/util/sailing/Rs2Sailing.java (3)
runelite-client/src/main/java/net/runelite/client/plugins/microbot/util/gameobject/Rs2GameObject.java (1)
Rs2GameObject(38-2064)runelite-client/src/main/java/net/runelite/client/plugins/microbot/util/menu/NewMenuEntry.java (1)
NewMenuEntry(11-330)runelite-api/src/main/java/net/runelite/api/gameval/InterfaceID.java (1)
SailingSidepanel(30596-30638)
runelite-client/src/main/java/net/runelite/client/plugins/microbot/example/ExampleScript.java (1)
runelite-client/src/main/java/net/runelite/client/plugins/microbot/util/sailing/data/BoatPathFollower.java (1)
BoatPathFollower(10-72)
runelite-client/src/main/java/net/runelite/client/plugins/microbot/shortestpath/ShortestPathPlugin.java (1)
runelite-client/src/main/java/net/runelite/client/plugins/microbot/shortestpath/PohPanel.java (1)
PohPanel(30-304)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
- GitHub Check: Build
- GitHub Check: Build
| public static WorldPoint getWorldLocation() { | ||
| if (Microbot.getClient().getTopLevelWorldView().getScene().isInstance()) { | ||
| LocalPoint l = LocalPoint.fromWorld(Microbot.getClient().getTopLevelWorldView(), Microbot.getClient().getLocalPlayer().getWorldLocation()); | ||
| return WorldPoint.fromLocalInstance(Microbot.getClient(), l); | ||
| } else { | ||
| if (Microbot.getClient().getLocalPlayer() == null) { | ||
| return null; // Handle case where local player is not available | ||
| return Microbot.getClientThread().invoke(() -> { | ||
| if (Microbot.getClient().getTopLevelWorldView().getScene().isInstance()) { | ||
| LocalPoint l = LocalPoint.fromWorld(Microbot.getClient().getTopLevelWorldView(), Microbot.getClient().getLocalPlayer().getWorldLocation()); | ||
| return WorldPoint.fromLocalInstance(Microbot.getClient(), l); | ||
| } else { | ||
| return Microbot.getClient().getLocalPlayer().getWorldLocation(); | ||
| } | ||
| return Microbot.getClient().getLocalPlayer().getWorldLocation(); | ||
| } | ||
| }); |
There was a problem hiding this comment.
getWorldLocation now assumes non-null localPlayer, breaking callers that expect null and risking NPEs
The new getWorldLocation() body dereferences Microbot.getClient().getLocalPlayer() without a null check and always returns a value from invoke. Several callers in this class explicitly handle a null world location (e.g., isInArea, isPlayerAreaIntersecting), but with this change they will instead hit a NullPointerException during logout / world-hop / load screens rather than getting null. That’s inconsistent with how the method is used elsewhere.
Consider guarding for a missing local player and aligning with the runOnClientThreadOptional pattern already used in this class:
- public static WorldPoint getWorldLocation() {
- return Microbot.getClientThread().invoke(() -> {
- if (Microbot.getClient().getTopLevelWorldView().getScene().isInstance()) {
- LocalPoint l = LocalPoint.fromWorld(Microbot.getClient().getTopLevelWorldView(), Microbot.getClient().getLocalPlayer().getWorldLocation());
- return WorldPoint.fromLocalInstance(Microbot.getClient(), l);
- } else {
- return Microbot.getClient().getLocalPlayer().getWorldLocation();
- }
- });
- }
+ public static WorldPoint getWorldLocation() {
+ return Microbot.getClientThread().runOnClientThreadOptional(() -> {
+ if (Microbot.getClient().getLocalPlayer() == null)
+ {
+ return null;
+ }
+
+ if (Microbot.getClient().getTopLevelWorldView().getScene().isInstance())
+ {
+ LocalPoint l = LocalPoint.fromWorld(
+ Microbot.getClient().getTopLevelWorldView(),
+ Microbot.getClient().getLocalPlayer().getWorldLocation());
+ return l != null ? WorldPoint.fromLocalInstance(Microbot.getClient(), l) : null;
+ }
+
+ return Microbot.getClient().getLocalPlayer().getWorldLocation();
+ }).orElse(null);
+ }This preserves client-thread safety, avoids NPEs when the player is unavailable, and keeps the “null when unknown” contract that the rest of the class relies on.
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| public static WorldPoint getWorldLocation() { | |
| if (Microbot.getClient().getTopLevelWorldView().getScene().isInstance()) { | |
| LocalPoint l = LocalPoint.fromWorld(Microbot.getClient().getTopLevelWorldView(), Microbot.getClient().getLocalPlayer().getWorldLocation()); | |
| return WorldPoint.fromLocalInstance(Microbot.getClient(), l); | |
| } else { | |
| if (Microbot.getClient().getLocalPlayer() == null) { | |
| return null; // Handle case where local player is not available | |
| return Microbot.getClientThread().invoke(() -> { | |
| if (Microbot.getClient().getTopLevelWorldView().getScene().isInstance()) { | |
| LocalPoint l = LocalPoint.fromWorld(Microbot.getClient().getTopLevelWorldView(), Microbot.getClient().getLocalPlayer().getWorldLocation()); | |
| return WorldPoint.fromLocalInstance(Microbot.getClient(), l); | |
| } else { | |
| return Microbot.getClient().getLocalPlayer().getWorldLocation(); | |
| } | |
| return Microbot.getClient().getLocalPlayer().getWorldLocation(); | |
| } | |
| }); | |
| public static WorldPoint getWorldLocation() { | |
| return Microbot.getClientThread().runOnClientThreadOptional(() -> { | |
| if (Microbot.getClient().getLocalPlayer() == null) | |
| { | |
| return null; | |
| } | |
| if (Microbot.getClient().getTopLevelWorldView().getScene().isInstance()) | |
| { | |
| LocalPoint l = LocalPoint.fromWorld( | |
| Microbot.getClient().getTopLevelWorldView(), | |
| Microbot.getClient().getLocalPlayer().getWorldLocation()); | |
| return l != null ? WorldPoint.fromLocalInstance(Microbot.getClient(), l) : null; | |
| } | |
| return Microbot.getClient().getLocalPlayer().getWorldLocation(); | |
| }).orElse(null); | |
| } |
🤖 Prompt for AI Agents
In
runelite-client/src/main/java/net/runelite/client/plugins/microbot/util/player/Rs2Player.java
around lines 949-957, the new getWorldLocation implementation dereferences
Microbot.getClient().getLocalPlayer() on the client thread and always returns a
value, causing NPEs when the local player is null; change it to follow the
runOnClientThreadOptional pattern: run the logic on the client thread, check if
getLocalPlayer() is null and if so return null, otherwise compute
LocalPoint.fromWorld(...) and WorldPoint.fromLocalInstance(...) and return that;
ensure the method preserves client-thread safety and the original contract of
returning null when the player/world location is unavailable.
| private static final Set<Integer> GANGPLANK_IDS; | ||
| private static final Set<Integer> NOTICEBOARD_IDS; | ||
|
|
||
|
|
||
| PortLocation(String name, Integer sailingLevelRequired, int gangplankObject, int noticeboardObject, WorldPoint navigationLocation) | ||
| { | ||
| this.name = name; | ||
| this.sailingLevelRequired = sailingLevelRequired; | ||
| this.gangplankObject = gangplankObject; | ||
| this.noticeboardObject = noticeboardObject; | ||
| this.navigationLocation = navigationLocation; | ||
| } | ||
|
|
||
| static | ||
| { | ||
| Set<Integer> gangplanks = new HashSet<>(); | ||
| Set<Integer> noticeboards = new HashSet<>(); | ||
| for (PortLocation p : values()) | ||
| { | ||
| gangplanks.add(p.gangplankObject); | ||
| if (p.noticeboardObject != -1) | ||
| { | ||
| noticeboards.add(p.noticeboardObject); | ||
| } | ||
| } | ||
| GANGPLANK_IDS = Collections.unmodifiableSet(gangplanks); | ||
| NOTICEBOARD_IDS = Collections.unmodifiableSet(noticeboards); | ||
| } |
There was a problem hiding this comment.
Sentinel gangplank id -1 is treated as a real gangplank in GANGPLANK_IDS
EMPTY is defined with gangplankObject = -1, but the static init unconditionally adds every gangplankObject to GANGPLANK_IDS. As a result, isGangplank(-1) will return true, while isNoticeboard(-1) correctly returns false because -1 is filtered out there. That’s inconsistent sentinel handling and could misclassify invalid IDs.
You can mirror the noticeboard logic for gangplanks:
- for (PortLocation p : values())
- {
- gangplanks.add(p.gangplankObject);
- if (p.noticeboardObject != -1)
- {
- noticeboards.add(p.noticeboardObject);
- }
- }
+ for (PortLocation p : values())
+ {
+ if (p.gangplankObject != -1)
+ {
+ gangplanks.add(p.gangplankObject);
+ }
+ if (p.noticeboardObject != -1)
+ {
+ noticeboards.add(p.noticeboardObject);
+ }
+ }This keeps both helpers aligned and avoids ever treating the EMPTY sentinel as a real in-game object.
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| private static final Set<Integer> GANGPLANK_IDS; | |
| private static final Set<Integer> NOTICEBOARD_IDS; | |
| PortLocation(String name, Integer sailingLevelRequired, int gangplankObject, int noticeboardObject, WorldPoint navigationLocation) | |
| { | |
| this.name = name; | |
| this.sailingLevelRequired = sailingLevelRequired; | |
| this.gangplankObject = gangplankObject; | |
| this.noticeboardObject = noticeboardObject; | |
| this.navigationLocation = navigationLocation; | |
| } | |
| static | |
| { | |
| Set<Integer> gangplanks = new HashSet<>(); | |
| Set<Integer> noticeboards = new HashSet<>(); | |
| for (PortLocation p : values()) | |
| { | |
| gangplanks.add(p.gangplankObject); | |
| if (p.noticeboardObject != -1) | |
| { | |
| noticeboards.add(p.noticeboardObject); | |
| } | |
| } | |
| GANGPLANK_IDS = Collections.unmodifiableSet(gangplanks); | |
| NOTICEBOARD_IDS = Collections.unmodifiableSet(noticeboards); | |
| } | |
| private static final Set<Integer> GANGPLANK_IDS; | |
| private static final Set<Integer> NOTICEBOARD_IDS; | |
| PortLocation(String name, Integer sailingLevelRequired, int gangplankObject, int noticeboardObject, WorldPoint navigationLocation) | |
| { | |
| this.name = name; | |
| this.sailingLevelRequired = sailingLevelRequired; | |
| this.gangplankObject = gangplankObject; | |
| this.noticeboardObject = noticeboardObject; | |
| this.navigationLocation = navigationLocation; | |
| } | |
| static | |
| { | |
| Set<Integer> gangplanks = new HashSet<>(); | |
| Set<Integer> noticeboards = new HashSet<>(); | |
| for (PortLocation p : values()) | |
| { | |
| if (p.gangplankObject != -1) | |
| { | |
| gangplanks.add(p.gangplankObject); | |
| } | |
| if (p.noticeboardObject != -1) | |
| { | |
| noticeboards.add(p.noticeboardObject); | |
| } | |
| } | |
| GANGPLANK_IDS = Collections.unmodifiableSet(gangplanks); | |
| NOTICEBOARD_IDS = Collections.unmodifiableSet(noticeboards); | |
| } |
🤖 Prompt for AI Agents
In
runelite-client/src/main/java/net/runelite/client/plugins/microbot/util/sailing/data/PortLocation.java
around lines 52 to 79, the static initializer unconditionally adds every
gangplankObject (including the sentinel -1 for EMPTY) to GANGPLANK_IDS which
misclassifies the sentinel as a real object; change the initializer to only add
gangplankObject values when they are not -1 (mirror the existing noticeboard
filtering) so GANGPLANK_IDS never contains the sentinel value.
| VOID_KNIGHTS_OUTPOST_PORT_TYRAS( | ||
| PortLocation.VOID_KNIGHTS_OUTPOST, | ||
| PortLocation.PORT_KHAZARD, | ||
| new RelativeMove(-309, 0), | ||
| new RelativeMove(-12, 12), | ||
| new RelativeMove(-114, 0), | ||
| new RelativeMove(-151, 151), | ||
| new RelativeMove(0, 134), | ||
| new RelativeMove(63, 63), | ||
| new RelativeMove(0, 49), | ||
| new RelativeMove(13, 13) |
There was a problem hiding this comment.
Enum VOID_KNIGHTS_OUTPOST_PORT_TYRAS ends at the wrong port
VOID_KNIGHTS_OUTPOST_PORT_TYRAS is declared with PortLocation.PORT_KHAZARD as its end, even though:
- Its name says
...PORT_TYRAS. - There is already a
VOID_KNIGHTS_OUTPOST_PORT_KHAZARDroute.
This duplicates the VOID→PORT_KHAZARD path and leaves no VOID→PORT_TYRAS path for lookups based on start/end. Suggested fix:
- VOID_KNIGHTS_OUTPOST_PORT_TYRAS(
- PortLocation.VOID_KNIGHTS_OUTPOST,
- PortLocation.PORT_KHAZARD,
+ VOID_KNIGHTS_OUTPOST_PORT_TYRAS(
+ PortLocation.VOID_KNIGHTS_OUTPOST,
+ PortLocation.PORT_TYRAS,📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| VOID_KNIGHTS_OUTPOST_PORT_TYRAS( | |
| PortLocation.VOID_KNIGHTS_OUTPOST, | |
| PortLocation.PORT_KHAZARD, | |
| new RelativeMove(-309, 0), | |
| new RelativeMove(-12, 12), | |
| new RelativeMove(-114, 0), | |
| new RelativeMove(-151, 151), | |
| new RelativeMove(0, 134), | |
| new RelativeMove(63, 63), | |
| new RelativeMove(0, 49), | |
| new RelativeMove(13, 13) | |
| VOID_KNIGHTS_OUTPOST_PORT_TYRAS( | |
| PortLocation.VOID_KNIGHTS_OUTPOST, | |
| PortLocation.PORT_TYRAS, | |
| new RelativeMove(-309, 0), | |
| new RelativeMove(-12, 12), | |
| new RelativeMove(-114, 0), | |
| new RelativeMove(-151, 151), | |
| new RelativeMove(0, 134), | |
| new RelativeMove(63, 63), | |
| new RelativeMove(0, 49), | |
| new RelativeMove(13, 13) |
🤖 Prompt for AI Agents
In
runelite-client/src/main/java/net/runelite/client/plugins/microbot/util/sailing/data/PortPaths.java
around lines 2113 to 2123, the enum entry VOID_KNIGHTS_OUTPOST_PORT_TYRAS
incorrectly uses PortLocation.PORT_KHAZARD as its end which duplicates the
existing VOID_KNIGHTS_OUTPOST_PORT_KHAZARD route; change the second constructor
argument to PortLocation.PORT_TYRAS so the enum reflects VOID → PORT_TYRAS, and
verify there are no other duplicate entries or mismatched start/end pairs for
this route.
Microbot – Sailing utilities are live (API preview)
Sailing support in Microbot just got a serious upgrade. We now have a dedicated
Rs2Sailingutility that centralises most low-level sailing actions, so scripts can focus on logic instead of boilerplate.What’s included
isOnBoat()– Detects if the player is currently on a player boat.isNavigating()– Checks if the player is at the helm.boardBoat()– Uses gangplanks/moorings to board any nearby sailing vessel.disembarkBoat()– Temporary but robust disembark logic that scans tiles for valid gangplanks/moorings and clicks “Disembark”.navigate()– Moves the player to the steering wheel/helm and enters navigation mode.Movement state helpers:
isMovingForward()isMovingBackward()isStandingStill()Sail control:
setSails()– Sets sails to move forward (via the Sailing sidepanel controls).unsetSails()– Brings the boat to a stop.clickSailButton()– Low-level helper to press the set-sail button in the sidepanel.getPlayerBoatLocation()– Resolves the player’s world position relative to the boat, handling instances vs main world projection.getDirection(WorldPoint target)– Computes the 16-direction index towards a target world point.setHeading(Heading heading)– Issues aSet-Headingmenu action with the correct world view ID.sailTo(WorldPoint target)– High-level helper that:handleChatMessage(ChatMessage event)– Listens to game messages.trimSails()on a separate client thread.trimSails()– Searches for all known sail object IDs (various sizes/woods + colossal sails) and interacts with “Trim”, waiting for XP gain as confirmation.This gives scripts:
openCargo()– Supports all raft/2x5/large cargo hold variants (all wood types and open/closed IDs) and opens the cargo hold if you are on a boat.getBoatType()– Resolves the boat type based onVarPlayerID.SAILING_SIDEPANEL_BOAT_TYPE.getSteeringForBoatType()– Returns the correct steering object ID per boat type.getPortTasksVarbits()– Returns all active port task varbits as aMap<PortTaskVarbits, Integer>(only those with value > 0 and typeID).getPortTaskData(int varbitValue)– Maps a varbit value toPortTaskDataso scripts can reason about which tasks are active.How to use this in scripts
Examples of what you can do with this API right now:
Rs2Sailing.sailTo(targetWorldPoint).handleChatMessagein your plugin.getPortTasksVarbits()andgetPortTaskData(...).Notes / caveats
ignoreBoatWorldViewand more advanced world-view logic are available for future expansions and edge cases.If you are writing sailing-related scripts, you should stop reinventing the wheel and rely on
Rs2Sailingfor:Feedback and edge cases (especially odd ports, instances, or disembark failures) are welcome so we can harden this API.