From 4e7ca7abdcc643d281760f7423b838cd1b9b423c Mon Sep 17 00:00:00 2001 From: chsami <23292806+chsami@users.noreply.github.com> Date: Sat, 17 Oct 2026 15:45:21 +0200 Subject: [PATCH] fix(MahoganyHomes): guard null home and player location in walkToHome and bank (0.0.15) walkToHome and bank null-checked a local copy of the current home but then re-read plugin.getCurrentHome() through isMissingItems, planksNeeded and steelBarsNeeded and for the walk target, so a contract cleared on the client thread mid-loop threw an NPE. Rs2Player.getWorldLocation() was also passed to distanceBetween unchecked. Snapshot both once, guard them in isAwayFromHome, and pass the Home through to the material helpers. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01LjtEMzQHGuq4M1Mpqk9pPV --- .../mahoganyhomez/MahoganyHomesPlugin.java | 2 +- .../mahoganyhomez/MahoganyHomesScript.java | 41 +++++++++++-------- .../MahoganyHomesScriptTest.java | 23 +++++++++++ 3 files changed, 47 insertions(+), 19 deletions(-) diff --git a/src/main/java/net/runelite/client/plugins/microbot/mahoganyhomez/MahoganyHomesPlugin.java b/src/main/java/net/runelite/client/plugins/microbot/mahoganyhomez/MahoganyHomesPlugin.java index 5b2326c9ba..9ad95f8239 100644 --- a/src/main/java/net/runelite/client/plugins/microbot/mahoganyhomez/MahoganyHomesPlugin.java +++ b/src/main/java/net/runelite/client/plugins/microbot/mahoganyhomez/MahoganyHomesPlugin.java @@ -55,7 +55,7 @@ isExternal = PluginConstants.IS_EXTERNAL ) public class MahoganyHomesPlugin extends Plugin { - public static final String version = "0.0.14"; + public static final String version = "0.0.15"; private static final List PLANKS = Arrays.asList(ItemID.PLANK, ItemID.OAK_PLANK, ItemID.TEAK_PLANK, ItemID.MAHOGANY_PLANK); private static final List PLANK_NAMES = Arrays.asList("Plank", "Oak plank", "Teak plank", "Mahogany plank"); private static final Map MAHOGANY_HOMES_REPAIRS = new HashMap<>(); diff --git a/src/main/java/net/runelite/client/plugins/microbot/mahoganyhomez/MahoganyHomesScript.java b/src/main/java/net/runelite/client/plugins/microbot/mahoganyhomez/MahoganyHomesScript.java index 7fa515249e..d6c4bc6fa6 100644 --- a/src/main/java/net/runelite/client/plugins/microbot/mahoganyhomez/MahoganyHomesScript.java +++ b/src/main/java/net/runelite/client/plugins/microbot/mahoganyhomez/MahoganyHomesScript.java @@ -541,9 +541,8 @@ public void handleContractDialogue() { // Bank if we need to private void bank() { Home currentHome = plugin.getCurrentHome(); - if (currentHome != null - && plugin.distanceBetween(currentHome.getArea(), Rs2Player.getWorldLocation()) > 0 - && isMissingItems()) { + if (isAwayFromHome(currentHome, Rs2Player.getWorldLocation()) + && isMissingItems(currentHome)) { ShortestPathPlugin.getPathfinderConfig().setIgnoreTeleportAndItems(true); BankLocation bankLocation = Rs2Bank.getNearestBank(currentHome.getLocation()); ShortestPathPlugin.getPathfinderConfig().setIgnoreTeleportAndItems(false); @@ -582,19 +581,19 @@ && isMissingItems()) { } } else { // Withdraw steel bars first if needed - if (steelBarsNeeded() > steelBarsInInventory()) { - Rs2Bank.withdrawX(ItemID.STEEL_BAR, steelBarsNeeded() - steelBarsInInventory()); + if (steelBarsNeeded(currentHome) > steelBarsInInventory()) { + Rs2Bank.withdrawX(ItemID.STEEL_BAR, steelBarsNeeded(currentHome) - steelBarsInInventory()); Rs2Inventory.waitForInventoryChanges(5000); } // Calculate if we'll have enough space for planks after steel bars int freeSlots = Rs2Inventory.emptySlotCount(); int currentPlanks = planksInInventory() + planksInPlankSack(); - int additionalPlanksNeeded = planksNeeded() - currentPlanks; + int additionalPlanksNeeded = planksNeeded(currentHome) - currentPlanks; if (additionalPlanksNeeded <= 0) { // We already have enough planks - log("Already have sufficient planks: %d/%d", currentPlanks, planksNeeded()); + log("Already have sufficient planks: %d/%d", currentPlanks, planksNeeded(currentHome)); } else if (freeSlots >= additionalPlanksNeeded) { // Withdraw all planks to fill inventory Rs2Bank.withdrawAll(plugin.getConfig().currentTier().getPlankSelection().getPlankId()); @@ -617,25 +616,31 @@ && isMissingItems()) { // Walk to current home private void walkToHome() { Home currentHome = plugin.getCurrentHome(); - if (currentHome != null - && plugin.distanceBetween(currentHome.getArea(), Rs2Player.getWorldLocation()) > 0 - && !isMissingItems()) { - Rs2Walker.walkWithStateUntil(plugin.getCurrentHome().getLocation(), 3, + if (isAwayFromHome(currentHome, Rs2Player.getWorldLocation()) + && !isMissingItems(currentHome)) { + Rs2Walker.walkWithStateUntil(currentHome.getLocation(), 3, () -> readyFurniture() != null); if (readyFurniture() != null) fix(); } } - private boolean isMissingItems() { - return (planksInInventory() + planksInPlankSack()) < planksNeeded() - || steelBarsInInventory() < steelBarsNeeded(); + + boolean isAwayFromHome(Home home, WorldPoint playerLocation) { + return home != null + && playerLocation != null + && plugin.distanceBetween(home.getArea(), playerLocation) > 0; + } + + private boolean isMissingItems(Home home) { + return (planksInInventory() + planksInPlankSack()) < planksNeeded(home) + || steelBarsInInventory() < steelBarsNeeded(home); } - private int planksNeeded() { - return plugin.getCurrentHome().getRequiredPlanks(plugin.getContractTier()); + private int planksNeeded(Home home) { + return home.getRequiredPlanks(plugin.getContractTier()); } - private int steelBarsNeeded() { - return plugin.getCurrentHome().getRequiredSteelBars(plugin.getContractTier()); + private int steelBarsNeeded(Home home) { + return home.getRequiredSteelBars(plugin.getContractTier()); } private int planksInInventory() { diff --git a/src/test/java/net/runelite/client/plugins/microbot/mahoganyhomez/MahoganyHomesScriptTest.java b/src/test/java/net/runelite/client/plugins/microbot/mahoganyhomez/MahoganyHomesScriptTest.java index fa6272ff6c..3544b0d6ba 100644 --- a/src/test/java/net/runelite/client/plugins/microbot/mahoganyhomez/MahoganyHomesScriptTest.java +++ b/src/test/java/net/runelite/client/plugins/microbot/mahoganyhomez/MahoganyHomesScriptTest.java @@ -4,7 +4,9 @@ import org.junit.jupiter.api.Test; import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertTrue; class MahoganyHomesScriptTest { @@ -24,4 +26,25 @@ void closestContractLocationPicksNearestOffice() { assertEquals(ContractLocation.MAHOGANY_HOMES_HOSIDIUS.getLocation(), MahoganyHomesScript.getClosestContractLocation(new WorldPoint(1760, 3600, 0))); } + + @Test + void isAwayFromHomeIsFalseWithoutHomeOrPlayerLocation() { + MahoganyHomesScript script = scriptWithPlugin(); + assertFalse(script.isAwayFromHome(null, new WorldPoint(3213, 3424, 0))); + assertFalse(script.isAwayFromHome(Home.JESS, null)); + assertFalse(script.isAwayFromHome(null, null)); + } + + @Test + void isAwayFromHomeComparesPlayerLocationToHomeArea() { + MahoganyHomesScript script = scriptWithPlugin(); + assertTrue(script.isAwayFromHome(Home.JESS, new WorldPoint(3213, 3424, 0))); + assertFalse(script.isAwayFromHome(Home.JESS, new WorldPoint(2615, 3293, 1))); + } + + private static MahoganyHomesScript scriptWithPlugin() { + MahoganyHomesScript script = new MahoganyHomesScript(); + script.plugin = new MahoganyHomesPlugin(); + return script; + } }