diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/Microbot.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/Microbot.java index 4404f8a677..1270bfa3c3 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/Microbot.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/Microbot.java @@ -36,7 +36,11 @@ import net.runelite.client.plugins.loottracker.LootTrackerRecord; import net.runelite.client.plugins.microbot.configs.SpecialAttackConfigs; import net.runelite.client.plugins.microbot.pouch.PouchScript; +import net.runelite.client.plugins.microbot.util.bank.Rs2Bank; +import net.runelite.client.plugins.microbot.util.combat.Rs2Combat; +import net.runelite.client.plugins.microbot.util.dialogues.Rs2Dialogue; import net.runelite.client.plugins.microbot.util.inventory.Rs2ItemModel; +import net.runelite.client.plugins.microbot.util.shop.Rs2Shop; import net.runelite.client.plugins.microbot.util.item.Rs2ItemManager; import net.runelite.client.plugins.microbot.util.math.Rs2Random; import net.runelite.client.plugins.microbot.util.menu.NewMenuEntry; @@ -362,9 +366,13 @@ public static boolean hopToWorld(int worldNumber) { log.error("Can't hop world, already trying to hop"); return false; } - boolean isHopping = Microbot.getClientThread().runOnClientThreadOptional(() -> { - if (Microbot.getClient().getLocalPlayer() != null && Microbot.getClient().getLocalPlayer().isInteracting()) { - log.error("Local player is interacting, cannot hop worlds"); + boolean hopIssued = Microbot.getClientThread().runOnClientThreadOptional(() -> { + if (Rs2Combat.inCombat()) { + log.error("Player is in combat, cannot hop worlds"); + return false; + } + if (Rs2Bank.isOpen() || Rs2Shop.isOpen() || Rs2Dialogue.isInDialogue()) { + log.error("Blocking widget open (bank/shop/dialogue), cannot hop worlds"); return false; } if (quickHopTargetWorld != null || Microbot.getClient().getGameState() != GameState.LOGGED_IN) { @@ -372,7 +380,7 @@ public static boolean hopToWorld(int worldNumber) { return false; } if (Microbot.getClient().getWorld() == worldNumber) { - return false; + return true; } World newWorld = Microbot.getWorldService().getWorlds().findWorld(worldNumber); if (newWorld == null) { @@ -394,29 +402,46 @@ public static boolean hopToWorld(int worldNumber) { Microbot.getClient().openWorldHopper(); Microbot.getClient().hopToWorld(rsWorld); quickHopTargetWorld = null; - sleep(600); - sleepUntil(() -> Microbot.isHopping() || Rs2Widget.getWidget(193, 0) != null, 2000); - return Microbot.isHopping(); + return true; }).orElse(false); - if (!isHopping) { + if (!hopIssued) { + log.error("Failed to hop to world {}", worldNumber); + return false; + } + // Wait off the client thread so sleeps actually block. The lambda above runs on + // the client thread, where Global.sleep / sleepUntil early-return — so any post-hop + // wait inside it is a no-op and the success check fires before the server has + // even processed the request. That's the source of "Failed to hop" spam. + if (Microbot.getClient().getWorld() != worldNumber) { + sleep(600); + sleepUntil(() -> Microbot.isHopping() + || Microbot.getClient().getWorld() == worldNumber + || Rs2Widget.getWidget(193, 0) != null, 5000); + } + boolean hopping = Microbot.isHopping() || Microbot.getClient().getWorld() == worldNumber; + if (!hopping) { Widget confirmRoot = Rs2Widget.getWidget(193, 0); if (confirmRoot != null) { List children = Arrays.stream(confirmRoot.getDynamicChildren()).collect(Collectors.toList()); Widget switchWorldWidget = sleepUntilNotNull(() -> Rs2Widget.findWidget("Switch world", children, true), 2000); - if (switchWorldWidget != null) { - boolean clicked = Rs2Widget.clickWidget(switchWorldWidget); - if (clicked) { - sleepUntil(Microbot::isHopping, 4000); - return Microbot.isHopping(); - } + if (switchWorldWidget != null && Rs2Widget.clickWidget(switchWorldWidget)) { + sleepUntil(() -> Microbot.isHopping() + || Microbot.getClient().getWorld() == worldNumber, 4000); + hopping = Microbot.isHopping() || Microbot.getClient().getWorld() == worldNumber; } } } - if (!isHopping) { + if (hopping) { + // Block until the hop fully lands so callers don't race against HOPPING/LOGIN_SCREEN. + sleepUntil(() -> Microbot.getClient().getWorld() == worldNumber + && Microbot.getClient().getGameState() == GameState.LOGGED_IN, 15000); + } + boolean success = Microbot.getClient().getWorld() == worldNumber; + if (!success) { log.error("Failed to hop to world {}", worldNumber); } - return false; + return success; } public static void showMessage(String message) {