Skip to content

Comments

2.0.16#1544

Merged
chsami merged 42 commits intomainfrom
development
Oct 1, 2025
Merged

2.0.16#1544
chsami merged 42 commits intomainfrom
development

Conversation

@chsami
Copy link
Owner

@chsami chsami commented Oct 1, 2025

No description provided.

Nightfirecat and others added 30 commits September 24, 2025 11:17
This commit reworks the report button date option to change the widget
text rather than drawing an overlay, which ensures the text is still
drawn correctly even if the chatbox is moved. As a bonus, because it is
not drawn as an overlay, the overlay class (and all related
dependencies) can be removed.
The number of puzzle box moves can now be configured between four and eight when displaying the solution as dots. Leaving it at four there is no risk of overlapping moves while increasing the number of moves allows for faster puzzle solving.

Dots now interpolate between two colors instead of being a single yellow color. While the further away dots become smaller they now also gradually become a different color, providing another visual queue.

Puzzle box steps now default to being displayed as dots due to the arrows being confusing to many users.
The Lunar Isle multi combat areas changed recently, meaning this step is
no longer in a multi combat zone.
This step was unobtainable. It was confused with the CoordinateClue "Arceuus essence mine (CIS)".
- Implement quest helper navigation button in the toolbar
- Add icons for quest helper on and off states
- Update configuration handling for quest helper toggle
- use InterfaceID instead of InventoryID on InventorySetupsPluginPanel.java
This doesn't actually save, and the script callback isn't setup for
filtering it either.
RuneLite Cache-Code Autoupdater and others added 10 commits September 30, 2025 12:44
# Conflicts:
#	cache/pom.xml
#	pom.xml
#	runelite-api/pom.xml
#	runelite-client/pom.xml
#	runelite-client/src/main/java/net/runelite/client/plugins/screenshot/ScreenshotPlugin.java
#	runelite-jshell/pom.xml
#	runelite-maven-plugin/pom.xml
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Oct 1, 2025

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.

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

Walkthrough

This PR updates parent POM versions across modules and introduces extensive game-value constant changes (InterfaceID, VarbitID, VarPlayerID, NpcID/ObjectID, interfaces.toml). It removes deprecated APIs (ClientThread.runOnClientThread, Random class, multiple Rs2Equipment helpers) and refactors several plugins: FairyRing enum rename with a new event-driven plugin and RS2ASM scripts; Screenshot overlay removal with a new timestamp workflow in ScreenshotPlugin; Microbot refactors to int-based container IDs and equipment checks. UI adds a Quest Helper toggle button/icons. Additional updates include clue data tweaks, PuzzleSolver config/overlay enhancements, item_variations.json edits, and script/hash updates.

Possibly related PRs

  • Add quest helper navigation button #1543 — Also adds QUEST_ICON_ON/OFF to Icon and a Quest Helper navigation button in ClientUI, directly overlapping UI/icon changes.
  • 2.0.7 #1526 — Touches runelite-client pom and refactors microbot-related classes/plugins, overlapping with Microbot API and behavior changes here.
  • 1.9.9.1 #1435 — Performs parent POM bumps and modifies game-value constants, aligning with this PR’s widespread constants and version updates.

Pre-merge checks and finishing touches

❌ Failed checks (2 warnings, 1 inconclusive)
Check name Status Explanation Resolution
Description Check ⚠️ Warning The pull request description is empty and provides no details about the objectives or changes contained in this PR, leaving reviewers without context. Please add a concise description summarizing the goals and major modifications of this pull request, such as the rationale for version bumps and any important API or behavioral updates.
Docstring Coverage ⚠️ Warning Docstring coverage is 40.96% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
Title Check ❓ Inconclusive The title “2.0.16” is a version number that offers no insight into the substantive changes included in this pull request, making it too vague for reviewers to understand the main update at a glance. Consider renaming the title to summarize the primary updates, for example “Bump Microbot to v2.0.16 and update POM dependencies,” or highlight a key functional change if the version bump is not the core focus.

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
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: 10

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (9)
runelite-client/pom.xml (1)

468-473: Remove the stray character in the shade filter.

The literal §y embedded after <exclude>META-INF/*.DSA</exclude> makes the POM invalid XML, so Maven will fail to parse this module until it is removed.

-                                        <exclude>META-INF/*.DSA</exclude>§y
+                                        <exclude>META-INF/*.DSA</exclude>
docs/development.md (1)

138-165: Random usage no longer matches the imported class The snippet now imports Rs2Random, but the code below still calls Random.random(...). That import/call pair can’t both be correct—either revert the import or update the calls to Rs2Random.random(...) so the example compiles and reflects the intended API.

runelite-client/src/main/java/net/runelite/client/plugins/microbot/util/player/Rs2Player.java (1)

1243-1247: Correct the anti-poison guard logic.

Line 1243 returns early when anti-poison is inactive, so we never actually drink the potion. The guard should only bypass when anti-poison or anti-venom is already active.

Apply this diff to restore the expected behaviour:

-        if (!hasAntiPoisonActive() || hasAntiVenomActive()) {
+        if (hasAntiPoisonActive() || hasAntiVenomActive()) {
             return true;
         }
         return usePotion(Rs2Potion.getAntiPoisonVariants().toArray(new String[0]));
runelite-client/src/main/java/net/runelite/client/plugins/microbot/configs/SpecialAttackConfigs.java (1)

96-97: Potential NPE: missing null check for currently equipped weapon.

Line 97 assumes Rs2Equipment.get(EquipmentInventorySlot.WEAPON) is non-null, but if no weapon is currently equipped, calling .getId() will throw a NullPointerException.

Apply this diff to add a null-safe check:

 Rs2ItemModel rs2Item = currentEquipment.stream().filter(x -> x.getSlot() == EquipmentInventorySlot.WEAPON.getSlotIdx()).findFirst().orElse(null);
-if (rs2Item != null && rs2Item.getId() != Rs2Equipment.get(EquipmentInventorySlot.WEAPON).getId()) {
+Rs2ItemModel currentWeapon = Rs2Equipment.get(EquipmentInventorySlot.WEAPON);
+if (rs2Item != null && currentWeapon != null && rs2Item.getId() != currentWeapon.getId()) {
     Rs2ItemModel weapon = currentEquipment
runelite-client/src/main/java/net/runelite/client/plugins/microbot/VoxPlugins/schedulable/example/SchedulableExamplePrePostScheduleRequirements.java (4)

79-99: Conflicting mandatory spellbook requirements (unsatisfiable when pre-schedule ≠ MODERN).

If config selects a non‑MODERN pre‑schedule spellbook, the alch block still registers a mandatory MODERN spellbook at PRE_SCHEDULE, creating an impossible combo. Guard the MODERN requirement to avoid conflict.

Apply:

-            SpellbookRequirement normalSpellbookRequirement = new SpellbookRequirement(
-                Rs2Spellbook.MODERN,
-                TaskContext.PRE_SCHEDULE,
-                RequirementPriority.MANDATORY,
-                10,
-                "Normal spellbook required for High Alchemy"
-            );
-            this.register(normalSpellbookRequirement);
+            if (config.preScheduleSpellbook().isNone()
+                || config.preScheduleSpellbook().getSpellbook() == Rs2Spellbook.MODERN) {
+                SpellbookRequirement normalSpellbookRequirement = new SpellbookRequirement(
+                    Rs2Spellbook.MODERN,
+                    TaskContext.PRE_SCHEDULE,
+                    RequirementPriority.MANDATORY,
+                    10,
+                    "Normal spellbook required for High Alchemy"
+                );
+                this.register(normalSpellbookRequirement);
+            }

Based on learnings.

Also applies to: 565-571


573-581: Nature rune marked as “equip-only” via inventorySlot = -2.

Runes aren’t equipable; -2 is used elsewhere to signal “must be equipped”. Use -1 (any inventory slot).

-            ItemRequirement natureRuneRequirement = new ItemRequirement(
-                ItemID.NATURERUNE,
-                1,
-                -2,
+            ItemRequirement natureRuneRequirement = new ItemRequirement(
+                ItemID.NATURERUNE,
+                1,
+                -1,
                 RequirementPriority.MANDATORY,
                 10,
                 "Nature rune for alching",
                 TaskContext.PRE_SCHEDULE
             );

633-634: Display labels misrepresent what’s enabled.

enableShopRequirement controls maple bows (GE/Brian), while hammer/bucket is gated by externalRequirements. Fix the labels.

-            sb.append("  - Shop Requirement: ").append(config.enableShopRequirement() ? "ENABLED (Hammer & Bucket from nearest general store)" : "DISABLED").append("\n");
+            sb.append("  - Shop Requirement: ").append(config.enableShopRequirement() ? "ENABLED (Maple bows via GE/Brian)" : "DISABLED").append("\n");
+            sb.append("  - External Requirements: ").append(config.externalRequirements() ? "ENABLED (Hammer & Bucket from nearest general store)" : "DISABLED").append("\n");

377-389: Fix GE buy requirement description or quantities to match.

The description says “longbow x20, shortbow x20” but the ShopItemRequirement is instantiated with 2 of each. Either update the string to x2 or increase the desired quantities to 20. For example:

-             "Buy maple bows (longbow x20, shortbow x20) from Grand Exchange (pre-schedule)",
+             "Buy maple bows (longbow x2, shortbow x2) from Grand Exchange (pre-schedule)",

Also adjust the same in the corresponding post-schedule block at lines 404–406.

runelite-client/src/main/java/net/runelite/client/plugins/fairyring/FairyRing.java (1)

37-96: Sync FairyRing enum with DBTableID codes
The enum is missing valid codes present in DBTableID (AIP, BIR, BJQ, CJP, CJQ, CJS, CLQ, DJQ, DJS, DKQ, DLP), causing getFairyRingDestination(...).valueOf(...) to fail for those rings. Add the missing entries or derive destinations dynamically to avoid drift.

🧹 Nitpick comments (3)
runelite-client/src/main/java/net/runelite/client/plugins/cluescrolls/clues/SkillChallengeClue.java (2)

258-258: Label could be more descriptive.

Same as line 220, the label "Soul Rune x2" doesn't mention the Astral Rune alternative. Consider "Soul or Astral Rune x2" for consistency and clarity.


295-295: Label could be more descriptive.

Same pattern as lines 220 and 258: "Soul Rune x4" doesn't indicate the Astral Rune alternative is available.

runelite-client/src/main/java/net/runelite/client/plugins/puzzlesolver/PuzzleSolverOverlay.java (1)

221-224: Make gradient/size span the actual number of dots drawn so the last dot reaches the end color/size.

Using movesToShow as the interpolation domain means when stepsLeft < movesToShow the last drawn dot isn’t the end color and isn’t the largest size. Interpolate over dotsToShow = min(movesToShow, stepsLeft) and handle the single-dot case.

- int movesToShow = config.movesToShow();
- // Display the next movesToShow steps
- for (int i = 1; i <= movesToShow; i++)
+ int dotsToShow = Math.min(config.movesToShow(), stepsLeft);
+ // Display the next dotsToShow steps
+ for (int i = 1; i <= dotsToShow; i++)
   {
     int j = solver.getPosition() + i;
     if (j >= solver.getStepCount())
     {
       break;
     }
@@
- int numerator = (i - 1) * (DOT_MARKER_MAX_SIZE - DOT_MARKER_MIN_SIZE);
- double denominator = movesToShow - 1;
- int markerSize = (int) Math.round(DOT_MARKER_MAX_SIZE - numerator / denominator);
+ // denom spans the actually drawn dots
+ int denomInt = dotsToShow - 1;
+ double denom = denomInt <= 0 ? 0.0 : denomInt;
+ double t = denom == 0.0 ? 1.0 : (double) (i - 1) / denom;
+ int markerSize = (int) Math.round(
+   DOT_MARKER_MIN_SIZE + t * (DOT_MARKER_MAX_SIZE - DOT_MARKER_MIN_SIZE)
+ );
@@
- Color color = ColorUtil.colorLerp(config.dotColor(), config.dotEndColor(),
-   (double) (i - 1) / (movesToShow - 1));
+ Color color = ColorUtil.colorLerp(
+   config.dotColor(), config.dotEndColor(), t
+ );

Also applies to: 242-245, 252-255

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between e55a4e3 and eb19886.

⛔ Files ignored due to path filters (2)
  • runelite-client/src/main/resources/net/runelite/client/plugins/microbot/questhelper/quest_icon_off.png is excluded by !**/*.png
  • runelite-client/src/main/resources/net/runelite/client/plugins/microbot/questhelper/quest_icon_on.png is excluded by !**/*.png
📒 Files selected for processing (59)
  • cache/pom.xml (1 hunks)
  • docs/development.md (1 hunks)
  • pom.xml (1 hunks)
  • runelite-api/pom.xml (1 hunks)
  • runelite-api/src/main/interfaces/interfaces.toml (2 hunks)
  • runelite-api/src/main/java/net/runelite/api/NpcID.java (2 hunks)
  • runelite-api/src/main/java/net/runelite/api/NullNpcID.java (3 hunks)
  • runelite-api/src/main/java/net/runelite/api/NullObjectID.java (1 hunks)
  • runelite-api/src/main/java/net/runelite/api/ObjectID.java (1 hunks)
  • runelite-api/src/main/java/net/runelite/api/gameval/InterfaceID.java (42 hunks)
  • runelite-api/src/main/java/net/runelite/api/gameval/NpcID.java (1 hunks)
  • runelite-api/src/main/java/net/runelite/api/gameval/ObjectID1.java (1 hunks)
  • runelite-api/src/main/java/net/runelite/api/gameval/VarPlayerID.java (1 hunks)
  • runelite-api/src/main/java/net/runelite/api/gameval/VarbitID.java (1 hunks)
  • runelite-client/pom.xml (2 hunks)
  • runelite-client/src/main/java/net/runelite/client/callback/ClientThread.java (0 hunks)
  • runelite-client/src/main/java/net/runelite/client/plugins/banktags/BankTagsPlugin.java (0 hunks)
  • runelite-client/src/main/java/net/runelite/client/plugins/cannon/CannonPlugin.java (0 hunks)
  • runelite-client/src/main/java/net/runelite/client/plugins/cluescrolls/clues/CoordinateClue.java (1 hunks)
  • runelite-client/src/main/java/net/runelite/client/plugins/cluescrolls/clues/SkillChallengeClue.java (3 hunks)
  • runelite-client/src/main/java/net/runelite/client/plugins/cluescrolls/clues/hotcold/HotColdLocation.java (0 hunks)
  • runelite-client/src/main/java/net/runelite/client/plugins/devtools/VarInspector.java (0 hunks)
  • runelite-client/src/main/java/net/runelite/client/plugins/fairyring/FairyRing.java (2 hunks)
  • runelite-client/src/main/java/net/runelite/client/plugins/fairyring/FairyRingPlugin.java (4 hunks)
  • runelite-client/src/main/java/net/runelite/client/plugins/microbot/Microbot.java (0 hunks)
  • runelite-client/src/main/java/net/runelite/client/plugins/microbot/VoxPlugins/schedulable/example/SchedulableExamplePrePostScheduleRequirements.java (1 hunks)
  • runelite-client/src/main/java/net/runelite/client/plugins/microbot/configs/SpecialAttackConfigs.java (1 hunks)
  • runelite-client/src/main/java/net/runelite/client/plugins/microbot/inventorysetups/InventorySetupsSlotID.java (2 hunks)
  • runelite-client/src/main/java/net/runelite/client/plugins/microbot/inventorysetups/MInventorySetupsPlugin.java (11 hunks)
  • runelite-client/src/main/java/net/runelite/client/plugins/microbot/inventorysetups/ui/InventorySetupsPluginPanel.java (3 hunks)
  • runelite-client/src/main/java/net/runelite/client/plugins/microbot/pluginscheduler/tasks/examples/ExamplePrePostScheduleTasks.java (2 hunks)
  • runelite-client/src/main/java/net/runelite/client/plugins/microbot/pluginscheduler/tasks/requirements/PrePostScheduleRequirements.java (1 hunks)
  • runelite-client/src/main/java/net/runelite/client/plugins/microbot/pluginscheduler/tasks/requirements/requirement/SpellbookRequirement.java (2 hunks)
  • runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/tools/Icon.java (1 hunks)
  • runelite-client/src/main/java/net/runelite/client/plugins/microbot/util/bank/Rs2Bank.java (3 hunks)
  • runelite-client/src/main/java/net/runelite/client/plugins/microbot/util/depositbox/DepositBoxLocation.java (1 hunks)
  • runelite-client/src/main/java/net/runelite/client/plugins/microbot/util/equipment/Rs2Equipment.java (0 hunks)
  • runelite-client/src/main/java/net/runelite/client/plugins/microbot/util/item/Rs2ExplorersRing.java (2 hunks)
  • runelite-client/src/main/java/net/runelite/client/plugins/microbot/util/math/Random.java (0 hunks)
  • runelite-client/src/main/java/net/runelite/client/plugins/microbot/util/npc/Rs2NpcModel.java (2 hunks)
  • runelite-client/src/main/java/net/runelite/client/plugins/microbot/util/player/Rs2Player.java (3 hunks)
  • runelite-client/src/main/java/net/runelite/client/plugins/microbot/util/reflection/Rs2Reflection.java (1 hunks)
  • runelite-client/src/main/java/net/runelite/client/plugins/microbot/util/tabs/Rs2Tab.java (1 hunks)
  • runelite-client/src/main/java/net/runelite/client/plugins/microbot/util/world/Rs2WorldUtil.java (0 hunks)
  • runelite-client/src/main/java/net/runelite/client/plugins/puzzlesolver/PuzzleSolverConfig.java (3 hunks)
  • runelite-client/src/main/java/net/runelite/client/plugins/puzzlesolver/PuzzleSolverOverlay.java (4 hunks)
  • runelite-client/src/main/java/net/runelite/client/plugins/screenshot/ScreenshotOverlay.java (0 hunks)
  • runelite-client/src/main/java/net/runelite/client/plugins/screenshot/ScreenshotPlugin.java (6 hunks)
  • runelite-client/src/main/java/net/runelite/client/ui/ClientUI.java (3 hunks)
  • runelite-client/src/main/resources/item_variations.json (1 hunks)
  • runelite-client/src/main/scripts/LayoutResizableStones.hash (1 hunks)
  • runelite-client/src/main/scripts/LayoutResizableStones.rs2asm (3 hunks)
  • runelite-client/src/main/scripts/fairyrings_sort_update.hash (1 hunks)
  • runelite-client/src/main/scripts/fairyrings_sort_update.rs2asm (1 hunks)
  • runelite-client/src/test/java/net/runelite/client/plugins/fairyring/FairyRingTest.java (1 hunks)
  • runelite-client/src/test/java/net/runelite/client/plugins/screenshot/ScreenshotPluginTest.java (0 hunks)
  • runelite-client/src/test/java/net/runelite/client/plugins/worldmap/FairyRingLocationTest.java (2 hunks)
  • runelite-jshell/pom.xml (1 hunks)
  • runelite-maven-plugin/pom.xml (1 hunks)
💤 Files with no reviewable changes (11)
  • runelite-client/src/main/java/net/runelite/client/callback/ClientThread.java
  • runelite-client/src/main/java/net/runelite/client/plugins/microbot/Microbot.java
  • runelite-client/src/main/java/net/runelite/client/plugins/microbot/util/math/Random.java
  • runelite-client/src/main/java/net/runelite/client/plugins/devtools/VarInspector.java
  • runelite-client/src/main/java/net/runelite/client/plugins/screenshot/ScreenshotOverlay.java
  • runelite-client/src/test/java/net/runelite/client/plugins/screenshot/ScreenshotPluginTest.java
  • runelite-client/src/main/java/net/runelite/client/plugins/banktags/BankTagsPlugin.java
  • runelite-client/src/main/java/net/runelite/client/plugins/cluescrolls/clues/hotcold/HotColdLocation.java
  • runelite-client/src/main/java/net/runelite/client/plugins/cannon/CannonPlugin.java
  • runelite-client/src/main/java/net/runelite/client/plugins/microbot/util/world/Rs2WorldUtil.java
  • runelite-client/src/main/java/net/runelite/client/plugins/microbot/util/equipment/Rs2Equipment.java
🧰 Additional context used
🧠 Learnings (2)
📚 Learning: 2025-08-26T14:40:59.477Z
Learnt from: Voxsylvae
PR: chsami/Microbot#1415
File: runelite-client/src/main/java/net/runelite/client/plugins/microbot/pluginscheduler/tasks/requirements/requirement/SpellbookRequirement.java:306-348
Timestamp: 2025-08-26T14:40:59.477Z
Learning: In SpellbookRequirement, the design intent is to always fulfill the spellbook requirement regardless of TaskContext (PRE_SCHEDULE/POST_SCHEDULE), as spellbooks are fundamental game configuration that should be set up whenever needed. Cancellation handling would require implementing a movement watchdog similar to LocationRequirement, which adds complexity that's not warranted for this use case.

Applied to files:

  • runelite-client/src/main/java/net/runelite/client/plugins/microbot/VoxPlugins/schedulable/example/SchedulableExamplePrePostScheduleRequirements.java
  • runelite-client/src/main/java/net/runelite/client/plugins/microbot/pluginscheduler/tasks/requirements/requirement/SpellbookRequirement.java
📚 Learning: 2025-08-25T06:45:09.673Z
Learnt from: Voxsylvae
PR: chsami/Microbot#1415
File: runelite-client/src/main/java/net/runelite/client/plugins/microbot/agility/MicroAgilityPrePostScheduleRequirements.java:7-7
Timestamp: 2025-08-25T06:45:09.673Z
Learning: Always use game ID classes from net.runelite.api.gameval package (like ItemID, ObjectID, NpcID) instead of the deprecated classes in net.runelite.api package. The gameval package contains the new, preferred classes while the old ones in the direct api package are deprecated.

Applied to files:

  • runelite-client/src/main/java/net/runelite/client/plugins/microbot/inventorysetups/MInventorySetupsPlugin.java
🧬 Code graph analysis (11)
runelite-client/src/main/java/net/runelite/client/plugins/microbot/pluginscheduler/tasks/examples/ExamplePrePostScheduleTasks.java (1)
runelite-client/src/main/java/net/runelite/client/plugins/microbot/util/equipment/Rs2Equipment.java (1)
  • Rs2Equipment (27-361)
runelite-client/src/main/java/net/runelite/client/plugins/microbot/util/tabs/Rs2Tab.java (1)
runelite-client/src/main/java/net/runelite/client/plugins/microbot/util/keyboard/Rs2Keyboard.java (1)
  • Rs2Keyboard (15-174)
runelite-client/src/main/java/net/runelite/client/plugins/microbot/VoxPlugins/schedulable/example/SchedulableExamplePrePostScheduleRequirements.java (2)
runelite-client/src/main/java/net/runelite/client/plugins/microbot/pluginscheduler/tasks/requirements/data/ItemRequirementCollection.java (1)
  • ItemRequirementCollection (32-1444)
runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/requirements/item/ItemRequirement.java (1)
  • ItemRequirement (63-1099)
runelite-client/src/main/java/net/runelite/client/plugins/microbot/pluginscheduler/tasks/requirements/PrePostScheduleRequirements.java (1)
runelite-client/src/main/java/net/runelite/client/plugins/microbot/util/equipment/Rs2Equipment.java (1)
  • Rs2Equipment (27-361)
runelite-client/src/main/java/net/runelite/client/plugins/microbot/pluginscheduler/tasks/requirements/requirement/SpellbookRequirement.java (1)
runelite-client/src/main/java/net/runelite/client/plugins/microbot/util/equipment/Rs2Equipment.java (1)
  • Rs2Equipment (27-361)
runelite-client/src/main/java/net/runelite/client/plugins/screenshot/ScreenshotPlugin.java (1)
runelite-api/src/main/java/net/runelite/api/gameval/InterfaceID.java (1)
  • Chatbox (6682-7251)
runelite-client/src/main/java/net/runelite/client/plugins/microbot/util/depositbox/DepositBoxLocation.java (1)
runelite-client/src/main/java/net/runelite/client/plugins/microbot/util/equipment/Rs2Equipment.java (1)
  • Rs2Equipment (27-361)
runelite-client/src/main/java/net/runelite/client/plugins/microbot/configs/SpecialAttackConfigs.java (2)
runelite-client/src/main/java/net/runelite/client/plugins/microbot/util/equipment/Rs2Equipment.java (1)
  • Rs2Equipment (27-361)
runelite-client/src/main/java/net/runelite/client/plugins/microbot/util/inventory/Rs2Inventory.java (1)
  • Rs2Inventory (46-2324)
runelite-client/src/main/java/net/runelite/client/plugins/microbot/util/item/Rs2ExplorersRing.java (1)
runelite-client/src/main/java/net/runelite/client/plugins/microbot/util/equipment/Rs2Equipment.java (1)
  • Rs2Equipment (27-361)
runelite-client/src/main/java/net/runelite/client/plugins/fairyring/FairyRingPlugin.java (2)
runelite-api/src/main/java/net/runelite/api/gameval/InterfaceID.java (2)
  • FairyringsLog (14574-14748)
  • Fairyrings (15243-15273)
runelite-api/src/main/java/net/runelite/api/gameval/DBTableID.java (1)
  • Fairyring (7657-7788)
runelite-client/src/main/java/net/runelite/client/plugins/microbot/inventorysetups/MInventorySetupsPlugin.java (1)
runelite-api/src/main/java/net/runelite/api/gameval/InterfaceID.java (1)
  • Bankmain (1188-1332)
⏰ 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
🔇 Additional comments (21)
runelite-client/src/main/java/net/runelite/client/plugins/microbot/util/item/Rs2ExplorersRing.java (1)

112-115: LGTM! API refactor is consistent.

The replacement of hasEquipped with isWearing maintains the same logic and is consistent with the broader refactor pattern across the codebase. Both methods check inventory first, then equipment, which is correct.

Also applies to: 150-153

runelite-client/src/main/java/net/runelite/client/plugins/microbot/pluginscheduler/tasks/requirements/requirement/SpellbookRequirement.java (1)

349-349: LGTM! Consistent API refactor.

The change from hasEquipped to isWearing maintains the same equipment validation logic while aligning with the broader API cleanup in this PR. Both occurrences correctly verify that the seal was equipped after interaction.

Also applies to: 410-410

runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/tools/Icon.java (1)

49-50: LGTM!

The new icon constants follow the established enum pattern and integrate cleanly with the existing icon loading mechanism.

runelite-client/src/main/java/net/runelite/client/ui/ClientUI.java (1)

58-59: LGTM!

The quest helper toggle implementation is internally consistent. The button correctly reads and updates the configuration state, updates its own icon and tooltip to reflect the new state after toggling, and clears the walker target when disabling the feature. The logic correctly uses !isEnabled in the toggle handler to represent the new state after inversion.

Also applies to: 129-131, 568-583

runelite-api/src/main/java/net/runelite/api/ObjectID.java (1)

27866-27866: Inconsistent naming for object ID 57723 across ID classes

Object ID 57723 appears as ENERGY_BARRIER_57723 in runelite-api/src/main/java/net/runelite/api/ObjectID.java but is also defined as AHOY_TOWN_BARRIER_POST_QUEST (with an “Energy Barrier” comment) in runelite-api/src/main/java/net/runelite/api/gameval/ObjectID1.java. Confirm whether these refer to the same in-game object and, if so, align their constant names or documentation to avoid ambiguity.

runelite-api/src/main/java/net/runelite/api/NullNpcID.java (1)

116-116: Straightforward constant additions.

The three new NPC ID constants follow the established pattern and are consistent with the auto-generated nature of this deprecated file.

Also applies to: 922-922, 1756-1756

runelite-client/src/main/java/net/runelite/client/plugins/cluescrolls/clues/SkillChallengeClue.java (1)

220-220: No label change needed

Rune requirement labels follow the established pattern of naming only the primary rune (e.g., “Cosmic Rune x1” or “Soul Rune x2”) even when alternatives like Astral Runes are included; updating the label would break consistency.

Likely an incorrect or invalid review comment.

runelite-client/src/main/java/net/runelite/client/plugins/microbot/inventorysetups/MInventorySetupsPlugin.java (8)

868-868: Correct usage of BANKMAIN constant. The group ID InterfaceID.BANKMAIN is defined in net.runelite.api.gameval.InterfaceID (value 12) and is referenced correctly; no changes needed.


36-36: LGTM: Import updated to gameval package.

The import change to net.runelite.api.gameval.InterfaceID aligns with the migration to the new game value constants package.

Based on learnings.


429-429: LGTM: Bank container check uses correct constant.

The bank container check correctly uses net.runelite.api.gameval.InventoryID.BANK from the new gameval package.


549-569: LGTM: Interface widget checks use gameval constants.

The widget checks for bank title (line 549) and bank universe (line 564) correctly use the fully-qualified net.runelite.api.gameval.InterfaceID constants.


965-965: LGTM: Inventory container calls use correct gameval constants.

The calls to getNormalizedContainer correctly use the fully-qualified net.runelite.api.gameval.InventoryID.INV and WORN constants, consistent with the refactored method signature.

Also applies to: 1017-1018, 1421-1422


2056-2067: LGTM: Slot ID mapping uses correct constants.

The getNormalizedContainer(InventorySetupsSlotID) overload correctly maps to the int-based method using net.runelite.api.gameval.InventoryID.INV and WORN.


2069-2111: LGTM: Container retrieval logic updated correctly.

The refactored getNormalizedContainer(int) method:

  1. Correctly accepts an int parameter instead of InventoryID enum
  2. Uses proper assertions with net.runelite.api.gameval.InventoryID.INV and WORN constants
  3. Maintains the same container size logic
  4. Properly calls InventorySetupsSlotID.fromInventoryID(id) which now expects an int

The logic is consistent and correct.


868-868: Remove this warning: both InterfaceID.BANKMAIN references resolve to net.runelite.api.gameval.InterfaceID via the import at line 36.

Likely an incorrect or invalid review comment.

runelite-client/src/main/java/net/runelite/client/plugins/microbot/VoxPlugins/schedulable/example/SchedulableExamplePrePostScheduleRequirements.java (1)

515-524: Condition checks bank presence but equip step may not.

hasFireStaffAvailable returns true if staff is only in bank, steering flow to the “equip staff” step. The ItemRequirement(s) used in fireStaffOrRequirement don’t appear to be bank‑aware by default.

Please confirm that these ItemRequirement instances check bank/withdraw automatically. If not, either:

  • enable bank checking on them (e.g., alsoCheckBank(...)), or
  • change the condition to require inventory/equipped presence only.

Also applies to: 541-563

runelite-client/src/main/java/net/runelite/client/plugins/microbot/inventorysetups/ui/InventorySetupsPluginPanel.java (3)

30-31: LGTM: Import refactoring is clean.

The consolidation to wildcard imports and addition of static imports for INV, WORN, and plugin constants improves readability without changing behavior.

Also applies to: 39-53


784-785: LGTM: Container ID usage updated correctly.

The doHighlighting method now uses the int-based INV and WORN constants consistently with the refactored getNormalizedContainer signature.


810-817: LGTM: Highlighting methods use correct constants.

Both highlightInventory and highlightEquipment correctly use the new int-based constants (INV and WORN) matching the updated plugin API.

runelite-client/src/main/java/net/runelite/client/plugins/microbot/inventorysetups/InventorySetupsSlotID.java (2)

29-31: LGTM: Static imports align with refactor.

The addition of static imports for INV and WORN from net.runelite.api.gameval.InventoryID aligns with the broader migration to int-based IDs.


61-77: Verify sentinel mapping in fromInventoryID
Ensure inventoryId == 0 is the correct “no inventory” sentinel and that callers now pass 0 instead of null. Double-check that InventoryID.INV and InventoryID.WORN map to the intended integer values in net.runelite.api.gameval.InventoryID.

Comment on lines +69357 to +69362
public static final int AHOY_TOWN_BARRIER_MULTI = 57722;

/**
* Energy Barrier
*/
public static final int AHOY_TOWN_BARRIER_POST_QUEST = 57723;
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Inconsistent documentation between related constants.

AHOY_TOWN_BARRIER_POST_QUEST includes a Javadoc comment clarifying it's an "Energy Barrier", but the preceding AHOY_TOWN_BARRIER_MULTI at ID 57722 has no comment explaining what type of barrier it represents. If both represent the same logical entity in different states, they should have consistent documentation.

Since this file is auto-generated (line 69363), the source data or generation script should be updated to ensure related constants have consistent documentation.

🤖 Prompt for AI Agents
In runelite-api/src/main/java/net/runelite/api/gameval/ObjectID1.java around
lines 69357 to 69362, the constant AHOY_TOWN_BARRIER_MULTI (ID 57722) lacks
documentation while the related AHOY_TOWN_BARRIER_POST_QUEST includes a Javadoc
saying "Energy Barrier"; update the auto-generation source or generation script
so that related constants receive consistent Javadoc (e.g., copy or derive the
same "Energy Barrier" comment for AHOY_TOWN_BARRIER_MULTI) and regenerate the
file so both constants have matching documentation.

Comment on lines +29 to 33
import java.util.Arrays;
import java.util.Map;
import java.util.stream.Collectors;
import javax.annotation.Nullable;
import lombok.Getter;
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Case-sensitivity mismatch in forCode; normalize input.

forCode keys are upper-case enum names, but callers don’t guarantee case. Normalize to upper-case to prevent silent misses.

 import java.util.Arrays;
 import java.util.Map;
 import java.util.stream.Collectors;
+import java.util.Locale;
 import javax.annotation.Nullable;
@@
 @Nullable
 public static FairyRing forCode(String code)
 {
-    return BY_CODE.get(code);
+    if (code == null) {
+        return null;
+    }
+    return BY_CODE.get(code.toUpperCase(Locale.ROOT));
 }

Also applies to: 118-122

Comment on lines +196 to +201
var filter = client.getVarcStrValue(VarClientID.MESLAYERINPUT);

// if we have both favorites and standard items in the search results, show the separator
if (hasFavorites && hasNormal)
{
separator.setHidden(false);
}
}
else if (c.getFavorite() != null && c.getFavorite().getSpriteId() == SpriteID.FavouriteIcons.REMOVE)
if (code.toLowerCase().contains(filter)
|| tags != null && tags.contains(filter)
|| getConfigTags(code).stream().anyMatch(s -> s.contains(filter))
)
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Filter comparison is inconsistently case-insensitive; also risk of NPE.

code.toLowerCase()/tags (lower-cased) are compared to a raw filter; if filter is mixed-case or null, matches fail or NPE occurs. Normalize filter and null-guard.

-            var filter = client.getVarcStrValue(VarClientID.MESLAYERINPUT);
-
-            if (code.toLowerCase().contains(filter)
-                || tags != null && tags.contains(filter)
-                || getConfigTags(code).stream().anyMatch(s -> s.contains(filter))
+            var filter = client.getVarcStrValue(VarClientID.MESLAYERINPUT);
+            var filterNorm = (filter == null ? "" : filter).toLowerCase(java.util.Locale.ROOT);
+
+            if (code.toLowerCase(java.util.Locale.ROOT).contains(filterNorm)
+                || (tags != null && tags.contains(filterNorm))
+                || getConfigTags(code).stream().anyMatch(s -> s.contains(filterNorm))
             )
📝 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.

Suggested change
var filter = client.getVarcStrValue(VarClientID.MESLAYERINPUT);
// if we have both favorites and standard items in the search results, show the separator
if (hasFavorites && hasNormal)
{
separator.setHidden(false);
}
}
else if (c.getFavorite() != null && c.getFavorite().getSpriteId() == SpriteID.FavouriteIcons.REMOVE)
if (code.toLowerCase().contains(filter)
|| tags != null && tags.contains(filter)
|| getConfigTags(code).stream().anyMatch(s -> s.contains(filter))
)
var filter = client.getVarcStrValue(VarClientID.MESLAYERINPUT);
var filterNorm = (filter == null ? "" : filter).toLowerCase(java.util.Locale.ROOT);
if (code.toLowerCase(java.util.Locale.ROOT).contains(filterNorm)
|| (tags != null && tags.contains(filterNorm))
|| getConfigTags(code).stream().anyMatch(s -> s.contains(filterNorm))
)
🤖 Prompt for AI Agents
In
runelite-client/src/main/java/net/runelite/client/plugins/fairyring/FairyRingPlugin.java
around lines 196-201, the filter comparison mixes case-normalized values and raw
filter and also risks NPE if filter or tags is null; fix by null-guarding and
normalizing filter once (e.g., if filter is null or empty skip matching or set
filter = filter.toLowerCase(Locale.ROOT)), then compare against lower-cased
code, lower-cased tags (check tags != null before calling contains) and
lower-cased config tags in the stream (s ->
s.toLowerCase(Locale.ROOT).contains(filter)) so all comparisons are consistently
case-insensitive and safe from NPEs.

Comment on lines +222 to 225
private FairyRing getFairyRingDestination(int varbitValueDialLeft, int varbitValueDialMiddle, int varbitValueDialRight)
{
return FairyRing.valueOf(leftDial[varbitValueDialLeft] + middleDial[varbitValueDialMiddle] + rightDial[varbitValueDialRight]);
}
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Exception type mismatch: possible AIOOBE from dial arrays; caller catches only IllegalArgumentException.

Indexing leftDial[middle/right] can throw ArrayIndexOutOfBoundsException. Validate ranges and throw IllegalArgumentException; also prefer FairyRing.forCode to avoid valueOf surprises.

-    private FairyRing getFairyRingDestination(int varbitValueDialLeft, int varbitValueDialMiddle, int varbitValueDialRight)
-    {
-        return FairyRing.valueOf(leftDial[varbitValueDialLeft] + middleDial[varbitValueDialMiddle] + rightDial[varbitValueDialRight]);
-    }
+    private FairyRing getFairyRingDestination(int left, int mid, int right)
+    {
+        if (left < 0 || left > 3 || mid < 0 || mid > 3 || right < 0 || right > 3)
+        {
+            throw new IllegalArgumentException("Invalid dial value(s): " + left + "," + mid + "," + right);
+        }
+        final String code = leftDial[left] + middleDial[mid] + rightDial[right];
+        final FairyRing ring = FairyRing.forCode(code);
+        if (ring == null)
+        {
+            throw new IllegalArgumentException("Unknown fairy ring code: " + code);
+        }
+        return ring;
+    }
📝 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.

Suggested change
private FairyRing getFairyRingDestination(int varbitValueDialLeft, int varbitValueDialMiddle, int varbitValueDialRight)
{
return FairyRing.valueOf(leftDial[varbitValueDialLeft] + middleDial[varbitValueDialMiddle] + rightDial[varbitValueDialRight]);
}
private FairyRing getFairyRingDestination(int left, int mid, int right)
{
if (left < 0 || left > 3 || mid < 0 || mid > 3 || right < 0 || right > 3)
{
throw new IllegalArgumentException("Invalid dial value(s): " + left + "," + mid + "," + right);
}
final String code = leftDial[left] + middleDial[mid] + rightDial[right];
final FairyRing ring = FairyRing.forCode(code);
if (ring == null)
{
throw new IllegalArgumentException("Unknown fairy ring code: " + code);
}
return ring;
}
🤖 Prompt for AI Agents
In
runelite-client/src/main/java/net/runelite/client/plugins/fairyring/FairyRingPlugin.java
around lines 222 to 225, the method indexes leftDial/middleDial/rightDial with
unvalidated ints which can throw ArrayIndexOutOfBoundsException (but callers
only catch IllegalArgumentException); validate that varbitValueDialLeft,
varbitValueDialMiddle, and varbitValueDialRight are within the respective array
lengths before indexing, build the ring code from those validated entries, call
FairyRing.forCode(code) (or equivalent null-returning lookup) instead of
Enum.valueOf, and if validation fails or forCode returns null throw a clear
IllegalArgumentException with context so callers will receive the expected
exception type.

Comment on lines +61 to 66
public static InventorySetupsSlotID fromInventoryID(final int inventoryId)
{
if (inventoryId == null)
if (inventoryId == 0)
{
return null;
}
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

Verify that 0 is a safe sentinel value for "no inventory".

The change from inventoryId == null to inventoryId == 0 assumes that 0 is never a valid inventory ID. Confirm that no actual game inventory uses ID 0, as this could cause incorrect null returns if 0 is valid.


🏁 Script executed:

#!/bin/bash
# Search for InventoryID constant definitions to verify 0 is not used
rg -n "^\s*(public\s+)?static\s+final\s+int\s+\w+\s*=\s*0" --type java -g "**/gameval/InventoryID.java"

Length of output: 118


Disallow treating 0 as “no inventory”

0 is a valid InventoryID (TRAWLER_REWARDINV = 0), so returning null when inventoryId == 0 will break that case. Remove or adjust this sentinel check—either accept 0 as a legitimate ID or switch to a dedicated “none” constant/OptionalInt to represent a missing inventory.

🤖 Prompt for AI Agents
In
runelite-client/src/main/java/net/runelite/client/plugins/microbot/inventorysetups/InventorySetupsSlotID.java
around lines 61 to 66, the method currently treats inventoryId == 0 as a
sentinel and returns null, but 0 is a valid InventoryID (TRAWLER_REWARDINV);
remove this special-case check and treat 0 as a legitimate ID in the mapping
logic, or if the codebase expects a missing value instead, replace the null
sentinel with a clear alternative such as returning an OptionalInt or adding an
explicit NONE constant and updating callers accordingly; pick one approach and
apply it consistently (prefer accepting 0 as valid unless callers require a
missing value, in which case introduce OptionalInt/NONE and refactor callers).

clientThread.invokeLater(() ->
{
List<InventorySetupsItem> inv = getNormalizedContainer(InventoryID.INVENTORY);
List<InventorySetupsItem> inv = getNormalizedContainer(InterfaceID.INVENTORY);
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

Inconsistent inventory ID usage: InterfaceID vs InventoryID.

Line 957 calls getNormalizedContainer(InterfaceID.INVENTORY), while lines 965, 1017-1018, and 1421-1422 use gameval.InventoryID.INV or gameval.InventoryID.WORN. InterfaceID.INVENTORY appears to be the wrong constant class. This should likely be gameval.InventoryID.INV to match the other usage and the method signature change at line 2069.

Apply this diff to fix the inconsistency:

-			List<InventorySetupsItem> inv = getNormalizedContainer(InterfaceID.INVENTORY);
+			List<InventorySetupsItem> inv = getNormalizedContainer(net.runelite.api.gameval.InventoryID.INV);
📝 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.

Suggested change
List<InventorySetupsItem> inv = getNormalizedContainer(InterfaceID.INVENTORY);
@@ Lines 957
List<InventorySetupsItem> inv = getNormalizedContainer(net.runelite.api.gameval.InventoryID.INV);
🤖 Prompt for AI Agents
In
runelite-client/src/main/java/net/runelite/client/plugins/microbot/inventorysetups/MInventorySetupsPlugin.java
around line 957, the call getNormalizedContainer(InterfaceID.INVENTORY) uses the
wrong constant class; replace InterfaceID.INVENTORY with gameval.InventoryID.INV
so the call matches other uses (lines ~965, 1017-1018, 1421-1422) and the
updated method signature referenced at line 2069.

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

Verify InterfaceID.INVENTORY constant usage.

Line 957 uses InterfaceID.INVENTORY when creating a normalized container. Based on the surrounding context where other lines use net.runelite.api.gameval.InventoryID.INV, verify that:

  1. InterfaceID.INVENTORY is the correct constant (not InventoryID.INV), and
  2. This references the gameval package, not the deprecated API.

The usage seems suspicious given that lines 965, 1017-1018, and 1421-1422 all use net.runelite.api.gameval.InventoryID.INV for similar inventory container operations.


🏁 Script executed:

#!/bin/bash
# Check if InterfaceID.INVENTORY exists and is correct, or if this should be InventoryID.INV
ast-grep --pattern 'class InterfaceID {
  $$$
  public static final int INVENTORY = $_;
  $$$
}'

# Compare with InventoryID.INV
ast-grep --pattern 'class InventoryID {
  $$$
  public static final int INV = $_;
  $$$
}'

# Check all usages in the file to see the pattern
rg -nP --type=java '(InterfaceID|InventoryID)\.(INVENTORY|INV)' runelite-client/src/main/java/net/runelite/client/plugins/microbot/inventorysetups/MInventorySetupsPlugin.java

Length of output: 762


🏁 Script executed:

#!/bin/bash
rg -n "getNormalizedContainer" -C3 --type java runelite-client/src/main/java/net/runelite/client/plugins/microbot/inventorysetups/MInventorySetupsPlugin.java

Length of output: 2676


Replace InterfaceID.INVENTORY with net.runelite.api.gameval.InventoryID.INV. Line 957 currently passes the widget interface ID into getNormalizedContainer(int), which asserts the argument is InventoryID.INV or WORN. Use the container constant InventoryID.INV to match the other calls and avoid assertion failures.

🤖 Prompt for AI Agents
In
runelite-client/src/main/java/net/runelite/client/plugins/microbot/inventorysetups/MInventorySetupsPlugin.java
around line 957, the call passes InterfaceID.INVENTORY into
getNormalizedContainer(int) which asserts the parameter must be InventoryID.INV
or WORN; replace InterfaceID.INVENTORY with
net.runelite.api.gameval.InventoryID.INV (or add an import for InventoryID and
use InventoryID.INV) so the container constant is used consistently with other
calls and the assertion no longer fails.

Comment on lines +171 to +192
public HeadIcon getHeadIcon() {
if (runeliteNpc == null) {
return null;
}

if (runeliteNpc.getOverheadSpriteIds() == null) {
Microbot.log("Failed to find the correct overhead prayer.");
return null;
}

for (int i = 0; i < runeliteNpc.getOverheadSpriteIds().length; i++) {
int overheadSpriteId = runeliteNpc.getOverheadSpriteIds()[i];

if (overheadSpriteId == -1) continue;

return HeadIcon.values()[overheadSpriteId];
}

Microbot.log("Found overheadSpriteIds: " + Arrays.toString(runeliteNpc.getOverheadSpriteIds()) + " but failed to find valid overhead prayer.");

return null;
}
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Guard against array index out of bounds.

At line 186, HeadIcon.values()[overheadSpriteId] directly indexes into the enum array without validating that overheadSpriteId is within valid bounds. While the code checks for -1, it doesn't verify the upper bound, which can cause an ArrayIndexOutOfBoundsException if the game returns an unexpected sprite ID.

Apply this diff to add bounds checking:

 		for (int i = 0; i < runeliteNpc.getOverheadSpriteIds().length; i++) {
 			int overheadSpriteId = runeliteNpc.getOverheadSpriteIds()[i];
 
 			if (overheadSpriteId == -1) continue;
 
+			if (overheadSpriteId < 0 || overheadSpriteId >= HeadIcon.values().length) {
+				Microbot.log("Invalid overhead sprite ID: " + overheadSpriteId);
+				continue;
+			}
+
 			return HeadIcon.values()[overheadSpriteId];
 		}
📝 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.

Suggested change
public HeadIcon getHeadIcon() {
if (runeliteNpc == null) {
return null;
}
if (runeliteNpc.getOverheadSpriteIds() == null) {
Microbot.log("Failed to find the correct overhead prayer.");
return null;
}
for (int i = 0; i < runeliteNpc.getOverheadSpriteIds().length; i++) {
int overheadSpriteId = runeliteNpc.getOverheadSpriteIds()[i];
if (overheadSpriteId == -1) continue;
return HeadIcon.values()[overheadSpriteId];
}
Microbot.log("Found overheadSpriteIds: " + Arrays.toString(runeliteNpc.getOverheadSpriteIds()) + " but failed to find valid overhead prayer.");
return null;
}
public HeadIcon getHeadIcon() {
if (runeliteNpc == null) {
return null;
}
if (runeliteNpc.getOverheadSpriteIds() == null) {
Microbot.log("Failed to find the correct overhead prayer.");
return null;
}
for (int i = 0; i < runeliteNpc.getOverheadSpriteIds().length; i++) {
int overheadSpriteId = runeliteNpc.getOverheadSpriteIds()[i];
if (overheadSpriteId == -1) continue;
if (overheadSpriteId < 0 || overheadSpriteId >= HeadIcon.values().length) {
Microbot.log("Invalid overhead sprite ID: " + overheadSpriteId);
continue;
}
return HeadIcon.values()[overheadSpriteId];
}
Microbot.log("Found overheadSpriteIds: " + Arrays.toString(runeliteNpc.getOverheadSpriteIds())
" but failed to find valid overhead prayer.");
return null;
}
🤖 Prompt for AI Agents
In
runelite-client/src/main/java/net/runelite/client/plugins/microbot/util/npc/Rs2NpcModel.java
around lines 171-192, the code indexes HeadIcon.values()[overheadSpriteId]
without checking the upper bound which can throw ArrayIndexOutOfBoundsException;
change the loop to validate that overheadSpriteId is >= 0 and <
HeadIcon.values().length before indexing, skip or log and continue when the id
is out of range (instead of returning), and preserve the existing -1 check and
final log when no valid icon is found.

Comment on lines +73 to 75
private static final int DOT_MARKER_MAX_SIZE = 24;
private static final int DOT_MARKER_MIN_SIZE = 4;

Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Dot size decreases, but config says “increasing in size” — flip the interpolation.

Current formula shrinks from DOT_MARKER_MAX_SIZE to DOT_MARKER_MIN_SIZE as i grows, contradicting PuzzleSolverConfig.drawDots() description. Make sizes increase step-by-step to align behavior and text.

Apply:

- int numerator = (i - 1) * (DOT_MARKER_MAX_SIZE - DOT_MARKER_MIN_SIZE);
- double denominator = movesToShow - 1;
- int markerSize = (int) Math.round(DOT_MARKER_MAX_SIZE - numerator / denominator);
+ // t in [0..1]; size grows from MIN -> MAX
+ double t = denom == 0 ? 1.0 : (double) (i - 1) / denom;
+ int markerSize = (int) Math.round(
+   DOT_MARKER_MIN_SIZE + t * (DOT_MARKER_MAX_SIZE - DOT_MARKER_MIN_SIZE)
+ );

Also applies to: 242-245

🤖 Prompt for AI Agents
In
runelite-client/src/main/java/net/runelite/client/plugins/puzzlesolver/PuzzleSolverOverlay.java
around lines 73-75 and again around lines 242-245, the dot size calculation
currently interpolates from DOT_MARKER_MAX_SIZE down to DOT_MARKER_MIN_SIZE as
the index i increases, which contradicts the config text saying sizes should
increase; change the interpolation to start at DOT_MARKER_MIN_SIZE and grow
toward DOT_MARKER_MAX_SIZE as i increases (i.e., compute size =
DOT_MARKER_MIN_SIZE + ratio * (DOT_MARKER_MAX_SIZE - DOT_MARKER_MIN_SIZE) using
the same ratio and cast/rounding as before) so the sequence increases
step-by-step and update both occurrences.

Comment on lines +804 to +826
@Subscribe
private void onPostClientTick(PostClientTick e)
{
if (!consumers.isEmpty())
{
final Widget reportButtonTextWidget = client.getWidget(InterfaceID.Chatbox.REPORTABUSE_TEXT1);
if (reportButtonTextWidget != null)
{
if (reportButtonText == null)
{
reportButtonText = reportButtonTextWidget.getText();
}

reportButtonTextWidget.setText(DATE_FORMAT.format(new Date()));
}

Consumer<Image> consumer;
while ((consumer = consumers.poll()) != null)
{
drawManager.requestNextFrameListener(consumer);
}
}
}
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Always restore the report button text even if saving fails (move restore into a try/finally).

Current restore runs only after a successful save; if saveScreenshot throws or the task is rejected, the chatbox can remain stamped with the date. Capture is already complete before saving, so restoration should be unconditional.

-            executor.submit(() ->
-            {
-                saveScreenshot(fileName, subDir, img);
-
-                if (reportButtonText != null)
-                {
-                    clientThread.invokeLater(() ->
-                    {
-                        final Widget reportButtonTextWidget = client.getWidget(InterfaceID.Chatbox.REPORTABUSE_TEXT1);
-                        if (reportButtonTextWidget != null)
-                        {
-                            reportButtonTextWidget.setText(reportButtonText);
-                        }
-
-                        reportButtonText = null;
-                    });
-                }
-            });
+            final String toRestore = reportButtonText;
+            executor.submit(() -> {
+                try {
+                    saveScreenshot(fileName, subDir, img);
+                } finally {
+                    if (toRestore != null) {
+                        clientThread.invokeLater(() -> {
+                            final Widget reportButtonTextWidget = client.getWidget(InterfaceID.Chatbox.REPORTABUSE_TEXT1);
+                            if (reportButtonTextWidget != null) {
+                                reportButtonTextWidget.setText(toRestore);
+                            }
+                            // Avoid racing with a newer timestamp op
+                            if (reportButtonText == toRestore) {
+                                reportButtonText = null;
+                            }
+                        });
+                    }
+                }
+            });

Also applies to: 962-975

🤖 Prompt for AI Agents
In
runelite-client/src/main/java/net/runelite/client/plugins/screenshot/ScreenshotPlugin.java
around lines 804 to 826 (and similarly at 962-975), the code sets the report
button text to the current date but only restores the original text after a
successful save; if saveScreenshot throws or the save task is rejected the
chatbox remains stamped. Wrap the save/queue logic in a try/finally where the
original reportButtonTextWidget.setText(reportButtonText) (or equivalent
restoration) is executed in the finally block so the button text is restored
unconditionally, ensuring null-checks for the widget and preserving
reportButtonText if it was captured earlier.

@chsami chsami merged commit cb45581 into main Oct 1, 2025
3 checks passed
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.

8 participants