From 136ebf4d57a12c75392890096efe81951b70b769 Mon Sep 17 00:00:00 2001 From: chsami <23292806+chsami@users.noreply.github.com> Date: Fri, 16 Oct 2026 17:55:59 +0200 Subject: [PATCH 1/3] fix(PVirewatchKiller): skip script loop until fight area is set (1.0.5) The script loop starts with no initial delay and dereferenced plugin.fightArea before the first GameTick assigned it, and again after the plugin stop hook cleared it. Read the player location once with a null guard, snapshot fightArea and startingLocation, and return early while any of them is missing. Compare WorldPoints with equals instead of identity so the return-to-start branch is no longer always taken. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01LjtEMzQHGuq4M1Mpqk9pPV --- .../virewatch/PVirewatchKillerPlugin.java | 2 +- .../microbot/virewatch/PVirewatchScript.java | 27 +++++++++++-- .../virewatch/PVirewatchScriptTest.java | 40 +++++++++++++++++++ 3 files changed, 64 insertions(+), 5 deletions(-) create mode 100644 src/test/java/net/runelite/client/plugins/microbot/virewatch/PVirewatchScriptTest.java diff --git a/src/main/java/net/runelite/client/plugins/microbot/virewatch/PVirewatchKillerPlugin.java b/src/main/java/net/runelite/client/plugins/microbot/virewatch/PVirewatchKillerPlugin.java index d50994b3e3..b0d71abbee 100644 --- a/src/main/java/net/runelite/client/plugins/microbot/virewatch/PVirewatchKillerPlugin.java +++ b/src/main/java/net/runelite/client/plugins/microbot/virewatch/PVirewatchKillerPlugin.java @@ -47,7 +47,7 @@ ) public class PVirewatchKillerPlugin extends Plugin { - public final static String version = "1.0.4"; + public final static String version = "1.0.5"; private PLooter looterScript = new PLooter(); private PAlcher alchScript = new PAlcher(); diff --git a/src/main/java/net/runelite/client/plugins/microbot/virewatch/PVirewatchScript.java b/src/main/java/net/runelite/client/plugins/microbot/virewatch/PVirewatchScript.java index 403ae30d68..6862254bf3 100644 --- a/src/main/java/net/runelite/client/plugins/microbot/virewatch/PVirewatchScript.java +++ b/src/main/java/net/runelite/client/plugins/microbot/virewatch/PVirewatchScript.java @@ -1,6 +1,9 @@ package net.runelite.client.plugins.microbot.virewatch; +import net.runelite.api.Player; import net.runelite.api.Skill; +import net.runelite.api.coords.WorldArea; +import net.runelite.api.coords.WorldPoint; import net.runelite.client.plugins.microbot.Microbot; import net.runelite.client.plugins.microbot.Script; import net.runelite.client.plugins.microbot.util.combat.Rs2Combat; @@ -19,13 +22,21 @@ public boolean run(PVirewatchKillerConfig config, PVirewatchKillerPlugin plugin) if (!super.run()) return; Rs2Combat.enableAutoRetialiate(); - if(plugin.fightArea.contains(Microbot.getClientThread().invoke(() -> Microbot.getClient().getLocalPlayer().getWorldLocation()))) { + WorldPoint playerLocation = Microbot.getClientThread().invoke(() -> { + Player localPlayer = Microbot.getClient().getLocalPlayer(); + return localPlayer == null ? null : localPlayer.getWorldLocation(); + }); + WorldArea fightArea = plugin.fightArea; + WorldPoint startingLocation = plugin.startingLocation; + if (!hasFightState(playerLocation, fightArea, startingLocation)) return; + + if(fightArea.contains(playerLocation)) { Microbot.status = "Figthing"; } - if(Microbot.getClientThread().invoke(() -> Microbot.getClient().getLocalPlayer().getWorldLocation()) != plugin.startingLocation) { + if(isAwayFromStart(playerLocation, startingLocation)) { if(plugin.ticksOutOfArea > config.tickToReturn() || plugin.countedTicks > config.tickToReturnCombat()) { - Rs2Walker.walkTo(plugin.startingLocation, 0); + Rs2Walker.walkTo(startingLocation, 0); } } @@ -45,7 +56,7 @@ public boolean run(PVirewatchKillerConfig config, PVirewatchKillerPlugin plugin) if(Rs2Player.isInteracting()) { sleepUntil(() -> Microbot.getClient().getBoostedSkillLevel(Skill.PRAYER) > config.prayAt()); Microbot.status = "WALKING TO STARTING POINT"; - Rs2Walker.walkTo(plugin.startingLocation, 0); + Rs2Walker.walkTo(startingLocation, 0); } } @@ -60,6 +71,14 @@ public boolean run(PVirewatchKillerConfig config, PVirewatchKillerPlugin plugin) return true; } + static boolean hasFightState(WorldPoint playerLocation, WorldArea fightArea, WorldPoint startingLocation) { + return playerLocation != null && fightArea != null && startingLocation != null; + } + + static boolean isAwayFromStart(WorldPoint playerLocation, WorldPoint startingLocation) { + return !playerLocation.equals(startingLocation); + } + @Override public void shutdown() { super.shutdown(); diff --git a/src/test/java/net/runelite/client/plugins/microbot/virewatch/PVirewatchScriptTest.java b/src/test/java/net/runelite/client/plugins/microbot/virewatch/PVirewatchScriptTest.java new file mode 100644 index 0000000000..a6357795a9 --- /dev/null +++ b/src/test/java/net/runelite/client/plugins/microbot/virewatch/PVirewatchScriptTest.java @@ -0,0 +1,40 @@ +package net.runelite.client.plugins.microbot.virewatch; + +import net.runelite.api.coords.WorldArea; +import net.runelite.api.coords.WorldPoint; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; + +class PVirewatchScriptTest { + + private final WorldPoint start = new WorldPoint(3600, 3360, 0); + private final WorldArea fightArea = new WorldArea(3598, 3358, 5, 5, 0); + + @Test + void fightAreaNotYetSetByFirstGameTickSkipsTheLoop() { + assertFalse(PVirewatchScript.hasFightState(start, null, null)); + assertFalse(PVirewatchScript.hasFightState(start, null, start)); + } + + @Test + void missingLocalPlayerSkipsTheLoop() { + assertFalse(PVirewatchScript.hasFightState(null, fightArea, start)); + } + + @Test + void fightStateIsReadyOncePlayerAreaAndStartAreSet() { + assertTrue(PVirewatchScript.hasFightState(start, fightArea, start)); + } + + @Test + void standingOnAnEqualStartTileIsNotAwayFromStart() { + assertFalse(PVirewatchScript.isAwayFromStart(new WorldPoint(3600, 3360, 0), start)); + } + + @Test + void anotherTileIsAwayFromStart() { + assertTrue(PVirewatchScript.isAwayFromStart(new WorldPoint(3601, 3360, 0), start)); + } +} From a44e95f1926eba1e4e9d8d199f65d67a206ff2b5 Mon Sep 17 00:00:00 2001 From: chsami <23292806+chsami@users.noreply.github.com> Date: Fri, 16 Oct 2026 17:58:17 +0200 Subject: [PATCH 2/3] fix(PVirewatchKiller): skip NPC outline in overlay until fight area is set Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01LjtEMzQHGuq4M1Mpqk9pPV --- .../plugins/microbot/virewatch/PVirewatchKillerOverlay.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/main/java/net/runelite/client/plugins/microbot/virewatch/PVirewatchKillerOverlay.java b/src/main/java/net/runelite/client/plugins/microbot/virewatch/PVirewatchKillerOverlay.java index 8e58ec4794..5161861ccf 100644 --- a/src/main/java/net/runelite/client/plugins/microbot/virewatch/PVirewatchKillerOverlay.java +++ b/src/main/java/net/runelite/client/plugins/microbot/virewatch/PVirewatchKillerOverlay.java @@ -5,6 +5,7 @@ import net.runelite.api.Perspective; import net.runelite.api.TileObject; import net.runelite.api.coords.LocalPoint; +import net.runelite.api.coords.WorldArea; import net.runelite.api.coords.WorldPoint; import net.runelite.client.plugins.microbot.Microbot; import net.runelite.client.plugins.microbot.util.gameobject.Rs2GameObject; @@ -75,11 +76,12 @@ public Dimension render(Graphics2D graphics) { } } - if (!config.disableNPCOutline()) { + WorldArea fightArea = plugin.fightArea; + if (!config.disableNPCOutline() && fightArea != null) { for (var npcModel : Microbot.getRs2NpcCache().query().withName("Vyrewatch Sentinel").where(n -> !n.isDead()).toList()) { NPC npc = npcModel.getNpc(); if (npc != null && npc.getCanvasTilePoly() != null) { - if (!plugin.fightArea.contains(npc.getWorldLocation())) continue; + if (!fightArea.contains(npc.getWorldLocation())) continue; try { modelOutlineRenderer.drawOutline(npc, 2, Color.ORANGE, 4); From 961895c19167c6d1f7af430ca420827b89766b7a Mon Sep 17 00:00:00 2001 From: chsami <23292806+chsami@users.noreply.github.com> Date: Fri, 16 Oct 2026 18:00:27 +0200 Subject: [PATCH 3/3] fix(PVirewatchKiller): read fight area once per frame for the tile loop Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01LjtEMzQHGuq4M1Mpqk9pPV --- .../microbot/virewatch/PVirewatchKillerOverlay.java | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/main/java/net/runelite/client/plugins/microbot/virewatch/PVirewatchKillerOverlay.java b/src/main/java/net/runelite/client/plugins/microbot/virewatch/PVirewatchKillerOverlay.java index 5161861ccf..a00a297c40 100644 --- a/src/main/java/net/runelite/client/plugins/microbot/virewatch/PVirewatchKillerOverlay.java +++ b/src/main/java/net/runelite/client/plugins/microbot/virewatch/PVirewatchKillerOverlay.java @@ -56,10 +56,11 @@ public Dimension render(Graphics2D graphics) { renderOutline(graphics, alterStatue); } - if (plugin.fightArea != null && !config.disableFightArea()) { - for (int x = plugin.fightArea.getX(); x < plugin.fightArea.getX() + plugin.fightArea.getWidth(); x++) { - for (int y = plugin.fightArea.getY(); y < plugin.fightArea.getY() + plugin.fightArea.getHeight(); y++) { - WorldPoint worldPoint = new WorldPoint(x, y, plugin.fightArea.getPlane()); + WorldArea fightArea = plugin.fightArea; + if (fightArea != null && !config.disableFightArea()) { + for (int x = fightArea.getX(); x < fightArea.getX() + fightArea.getWidth(); x++) { + for (int y = fightArea.getY(); y < fightArea.getY() + fightArea.getHeight(); y++) { + WorldPoint worldPoint = new WorldPoint(x, y, fightArea.getPlane()); drawTile(graphics, worldPoint, Color.YELLOW); } } @@ -76,7 +77,6 @@ public Dimension render(Graphics2D graphics) { } } - WorldArea fightArea = plugin.fightArea; if (!config.disableNPCOutline() && fightArea != null) { for (var npcModel : Microbot.getRs2NpcCache().query().withName("Vyrewatch Sentinel").where(n -> !n.isDead()).toList()) { NPC npc = npcModel.getNpc();