From 581e1c4a22e04e88d9c77bde6493c4192eb9fa9c Mon Sep 17 00:00:00 2001 From: vi3tcn <60859658+vi3tcn@users.noreply.github.com> Date: Sun, 10 Aug 2025 18:37:53 +0100 Subject: [PATCH 1/3] Add files via upload --- .../accountselector/AutoLoginConfig.java | 133 ++++++++++++------ .../accountselector/AutoLoginPlugin.java | 94 ++++++------- .../accountselector/AutoLoginScript.java | 104 +++++++++----- 3 files changed, 207 insertions(+), 124 deletions(-) diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/accountselector/AutoLoginConfig.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/accountselector/AutoLoginConfig.java index 39be1fa0b63..5927f8e2ec6 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/accountselector/AutoLoginConfig.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/accountselector/AutoLoginConfig.java @@ -1,44 +1,89 @@ -package net.runelite.client.plugins.microbot.accountselector; - -import net.runelite.client.config.Config; -import net.runelite.client.config.ConfigGroup; -import net.runelite.client.config.ConfigItem; -import net.runelite.client.config.ConfigSection; - -@ConfigGroup("AutoLoginConfig") -public interface AutoLoginConfig extends Config { - @ConfigSection( - name = "General", - description = "General", - position = 0, - closedByDefault = false - ) - String generalSection = "general"; - - @ConfigItem( - keyName = "World", - name = "World", - description = "World", - position = 0, - section = generalSection - ) - default int world() { return 360; } - - @ConfigItem( - keyName = "Is Member", - name = "Is Member", - description = "use Member worlds", - position = 0, - section = generalSection - ) - default boolean isMember() { return false; } - - @ConfigItem( - keyName = "RandomWorld", - name = "RandomWorld", - description = "use random worlds", - position = 0, - section = generalSection - ) - default boolean useRandomWorld() { return true; } -} +package net.runelite.client.plugins.microbot.accountselector; + +import net.runelite.client.config.Config; +import net.runelite.client.config.ConfigGroup; +import net.runelite.client.config.ConfigItem; +import net.runelite.client.config.ConfigSection; + +@ConfigGroup("AutoLoginConfig") +public interface AutoLoginConfig extends Config { + @ConfigSection( + name = "General", + description = "General", + position = 0, + closedByDefault = false + ) + String generalSection = "general"; + + @ConfigItem( + keyName = "World", + name = "World", + description = "World", + position = 0, + section = generalSection + ) + default int world() { return 360; } + + @ConfigItem( + keyName = "Is Member", + name = "Is Member", + description = "Use member worlds", + position = 1, + section = generalSection + ) + default boolean isMember() { return false; } + + @ConfigItem( + keyName = "RandomWorld", + name = "Use Random World", + description = "Use random worlds", + position = 2, + section = generalSection + ) + default boolean useRandomWorld() { return true; } + + @ConfigSection( + name = "Region Filter", + description = "Filter random world selection by region", + position = 10, + closedByDefault = false + ) + String regionSection = "region"; + + + @ConfigItem( + keyName = "AllowUK", + name = "UK", + description = "Allow UK worlds", + position = 1, + section = regionSection + ) + default boolean allowUK() { return true; } + + @ConfigItem( + keyName = "AllowUS", + name = "US", + description = "Allow US worlds", + position = 2, + section = regionSection + ) + default boolean allowUS() { return true; } + + @ConfigItem( + keyName = "AllowGermany", + name = "Germany", + description = "Allow German worlds", + position = 3, + section = regionSection + ) + default boolean allowGermany() { return true; } + + @ConfigItem( + keyName = "AllowAustralia", + name = "Australia", + description = "Allow Australian worlds", + position = 4, + section = regionSection + ) + default boolean allowAustralia() { return true; } +} \ No newline at end of file diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/accountselector/AutoLoginPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/accountselector/AutoLoginPlugin.java index 29d713196e9..ecd8e5e69ea 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/accountselector/AutoLoginPlugin.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/accountselector/AutoLoginPlugin.java @@ -1,47 +1,47 @@ -package net.runelite.client.plugins.microbot.accountselector; - -import com.google.inject.Provides; -import lombok.extern.slf4j.Slf4j; -import net.runelite.api.Client; -import net.runelite.client.Notifier; -import net.runelite.client.callback.ClientThread; -import net.runelite.client.config.ConfigManager; -import net.runelite.client.config.ProfileManager; -import net.runelite.client.game.WorldService; -import net.runelite.client.plugins.Plugin; -import net.runelite.client.plugins.PluginDescriptor; -import net.runelite.client.plugins.microbot.Microbot; -import net.runelite.client.plugins.microbot.util.mouse.VirtualMouse; - -import javax.inject.Inject; -import java.awt.*; - -@PluginDescriptor( - name = PluginDescriptor.Mocrosoft + "AutoLogin", - description = "Microbot autologin plugin", - tags = {"account", "microbot", "login"}, - enabledByDefault = false -) -@Slf4j -public class AutoLoginPlugin extends Plugin { - @Inject - AutoLoginScript accountSelectorScript; - - @Inject - AutoLoginConfig autoLoginConfig; - @Provides - AutoLoginConfig provideConfig(ConfigManager configManager) { - return configManager.getConfig(AutoLoginConfig.class); - } - - @Override - protected void startUp() throws AWTException { - Microbot.pauseAllScripts.compareAndSet(true, false); - accountSelectorScript.run(autoLoginConfig); - } - - protected void shutDown() { - accountSelectorScript.shutdown(); - } - -} +package net.runelite.client.plugins.microbot.accountselector; + +import com.google.inject.Provides; +import lombok.extern.slf4j.Slf4j; +import net.runelite.api.Client; +import net.runelite.client.Notifier; +import net.runelite.client.callback.ClientThread; +import net.runelite.client.config.ConfigManager; +import net.runelite.client.config.ProfileManager; +import net.runelite.client.game.WorldService; +import net.runelite.client.plugins.Plugin; +import net.runelite.client.plugins.PluginDescriptor; +import net.runelite.client.plugins.microbot.Microbot; +import net.runelite.client.plugins.microbot.util.mouse.VirtualMouse; + +import javax.inject.Inject; +import java.awt.*; + +@PluginDescriptor( + name = PluginDescriptor.Mocrosoft + "AutoLogin", + description = "Microbot autologin plugin", + tags = {"account", "microbot", "login"}, + enabledByDefault = false +) +@Slf4j +public class AutoLoginPlugin extends Plugin { + @Inject + AutoLoginScript accountSelectorScript; + + @Inject + AutoLoginConfig autoLoginConfig; + @Provides + AutoLoginConfig provideConfig(ConfigManager configManager) { + return configManager.getConfig(AutoLoginConfig.class); + } + + @Override + protected void startUp() throws AWTException { + Microbot.pauseAllScripts.compareAndSet(true, false); + accountSelectorScript.run(autoLoginConfig); + } + + protected void shutDown() { + accountSelectorScript.shutdown(); + } + +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/accountselector/AutoLoginScript.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/accountselector/AutoLoginScript.java index f9bf10613db..aa21b24bb6e 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/accountselector/AutoLoginScript.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/accountselector/AutoLoginScript.java @@ -1,33 +1,71 @@ -package net.runelite.client.plugins.microbot.accountselector; - -import net.runelite.api.GameState; -import net.runelite.client.plugins.microbot.Microbot; -import net.runelite.client.plugins.microbot.Script; -import net.runelite.client.plugins.microbot.util.security.Login; - -import java.util.concurrent.TimeUnit; - -public class AutoLoginScript extends Script { - - public boolean run(AutoLoginConfig autoLoginConfig) { - mainScheduledFuture = scheduledExecutorService.scheduleWithFixedDelay(() -> { - try { - if (!super.run()) return; - - if (Microbot.getClient().getGameState() == GameState.LOGIN_SCREEN) { - if (autoLoginConfig.useRandomWorld()) { - new Login(Login.getRandomWorld(autoLoginConfig.isMember())); - } else { - new Login(autoLoginConfig.world()); - } - sleep(5000); - } - - - } catch (Exception ex) { - Microbot.logStackTrace(this.getClass().getSimpleName(), ex); - } - }, 0, 1000, TimeUnit.MILLISECONDS); - return true; - } -} +package net.runelite.client.plugins.microbot.accountselector; + +import net.runelite.api.GameState; +import net.runelite.client.plugins.microbot.Microbot; +import net.runelite.client.plugins.microbot.Script; +import net.runelite.client.plugins.microbot.util.security.Login; +import net.runelite.http.api.worlds.WorldRegion; + +import java.util.ArrayList; +import java.util.List; +import java.util.Random; +import java.util.concurrent.TimeUnit; + +public class AutoLoginScript extends Script { + + private List getAllowedRegions(AutoLoginConfig config) { + List allowedRegions = new ArrayList<>(); + + if (config.allowUK()) { + allowedRegions.add(WorldRegion.UNITED_KINGDOM); + } + if (config.allowUS()) { + allowedRegions.add(WorldRegion.UNITED_STATES_OF_AMERICA); + } + if (config.allowGermany()) { + allowedRegions.add(WorldRegion.GERMANY); + } + if (config.allowAustralia()) { + allowedRegions.add(WorldRegion.AUSTRALIA); + } + + return allowedRegions; + } + + private int getRandomWorldWithRegionFilter(AutoLoginConfig config) { + List allowedRegions = getAllowedRegions(config); + + if (allowedRegions.isEmpty()) { + // If no regions allowed, use default method + return Login.getRandomWorld(config.isMember()); + } + + // Pick a random region from allowed regions + Random random = new Random(); + WorldRegion selectedRegion = allowedRegions.get(random.nextInt(allowedRegions.size())); + + return Login.getRandomWorld(config.isMember(), selectedRegion); + } + + public boolean run(AutoLoginConfig autoLoginConfig) { + mainScheduledFuture = scheduledExecutorService.scheduleWithFixedDelay(() -> { + try { + if (!super.run()) return; + + if (Microbot.getClient().getGameState() == GameState.LOGIN_SCREEN) { + if (autoLoginConfig.useRandomWorld()) { + new Login(getRandomWorldWithRegionFilter(autoLoginConfig)); + } else { + new Login(autoLoginConfig.world()); + } + sleep(5000); + } + + + } catch (Exception ex) { + Microbot.logStackTrace(this.getClass().getSimpleName(), ex); + } + }, 0, 1000, TimeUnit.MILLISECONDS); + return true; + } +} From 21431c062ad31a4db38e1245343a550d5e07643c Mon Sep 17 00:00:00 2001 From: vi3tcn <60859658+vi3tcn@users.noreply.github.com> Date: Sun, 10 Aug 2025 18:42:50 +0100 Subject: [PATCH 2/3] Add files via upload --- .../breakhandler/BreakHandlerConfig.java | 495 ++++--- .../breakhandler/BreakHandlerOverlay.java | 204 +-- .../breakhandler/BreakHandlerPlugin.java | 218 +-- .../breakhandler/BreakHandlerScript.java | 1225 +++++++++++------ .../breakhandler/BreakHandlerState.java | 62 + 5 files changed, 1404 insertions(+), 800 deletions(-) create mode 100644 runelite-client/src/main/java/net/runelite/client/plugins/microbot/breakhandler/BreakHandlerState.java diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/breakhandler/BreakHandlerConfig.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/breakhandler/BreakHandlerConfig.java index 5abad73e51f..eecdc09c7ff 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/breakhandler/BreakHandlerConfig.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/breakhandler/BreakHandlerConfig.java @@ -1,178 +1,319 @@ -package net.runelite.client.plugins.microbot.breakhandler; - -import net.runelite.client.config.Config; -import net.runelite.client.config.ConfigGroup; -import net.runelite.client.config.ConfigItem; -import net.runelite.client.config.ConfigSection; -import net.runelite.client.plugins.microbot.util.antiban.enums.PlaySchedule; - -@ConfigGroup(BreakHandlerConfig.configGroup) -public interface BreakHandlerConfig extends Config { - // Group name constant for configuration grouping. - String configGroup = "break-handler"; - String hideOverlay = "hideOverlay"; - - // ============================================================ - // Break Timing Settings - // ============================================================ - @ConfigSection( - name = "Break Timing", - description = "Configure when and how long breaks occur", - position = 0 - ) - String breakTimingSettings = "breakTimingSettings"; - - @ConfigItem( - keyName = "Min Playtime", - name = "Min Playtime", - description = "Time until break start in minutes", - position = 0, - section = breakTimingSettings - ) - default int timeUntilBreakStart() { - return 60; - } - - @ConfigItem( - keyName = "Max Playtime", - name = "Max Playtime", - description = "Time until break ends in minutes", - position = 1, - section = breakTimingSettings - ) - default int timeUntilBreakEnd() { - return 120; - } - - @ConfigItem( - keyName = "Min BreakTime", - name = "Min BreakTime", - description = "Break duration start in minutes", - position = 2, - section = breakTimingSettings - ) - default int breakDurationStart() { - return 10; - } - - @ConfigItem( - keyName = "Max BreakTime", - name = "Max BreakTime", - description = "Break duration end in minutes", - position = 3, - section = breakTimingSettings - ) - default int breakDurationEnd() { - return 15; - } - - @ConfigItem( - keyName = "breakNow", - name = "Break Now", - description = "Toggle this to start a break immediately", - position = 4, - section = breakTimingSettings - ) - default boolean breakNow() { - return false; - } - - @ConfigItem( - keyName = "breakEndNow", - name = "End Break Now", - description = "Toggle this to stop the current break immediately", - position = 5, - section = breakTimingSettings - ) - default boolean breakEndNow() { - return false; - } - - // ============================================================ - // Break Behavior Options - // ============================================================ - @ConfigSection( - name = "Break Behavior", - description = "Configure what happens during breaks", - position = 1 - ) - String breakBehaviorOptions = "breakBehaviorOptions"; - - @ConfigItem( - keyName = "OnlyMicroBreaks", - name = "Micro Breaks Only", - description = "Only use micro breaks if enabled", - position = 0, - section = breakBehaviorOptions - ) - default boolean onlyMicroBreaks() { - return false; - } - - @ConfigItem( - keyName = "Logout", - name = "Logout", - description = "Logout when taking a break", - position = 1, - section = breakBehaviorOptions - ) - default boolean logoutAfterBreak() { - return true; - } - - @ConfigItem( - keyName = "useRandomWorld", - name = "Use RandomWorld", - description = "Change to a random world once break is finished", - position = 2, - section = breakBehaviorOptions - ) - default boolean useRandomWorld() { - return false; - } - - // ============================================================ - // Play Schedule Configuration Section - // ============================================================ - @ConfigSection( - name = "Play Schedule", - description = "Options related to using a play schedule", - position = 2 - ) - String usePlaySchedule = "usePlaySchedule"; - - @ConfigItem( - keyName = "UsePlaySchedule", - name = "Use Play Schedule", - description = "Enable or disable the use of a play schedule", - position = 0, - section = usePlaySchedule - ) - default boolean usePlaySchedule() { - return false; - } - - @ConfigItem( - keyName = "PlaySchedule", - name = "Play Schedule", - description = "Select the play schedule", - position = 1, - section = usePlaySchedule - ) - default PlaySchedule playSchedule() { - return PlaySchedule.MEDIUM_DAY; - } - - // ============================================================ - // Overlay Settings - // ============================================================ - @ConfigItem( - keyName = "hideOverlay", - name = "Hide Overlay", - description = "Select this if you want to hide overlay", - position = 0 - ) - default boolean isHideOverlay() { - return false; - } +package net.runelite.client.plugins.microbot.breakhandler; + +import net.runelite.client.config.Config; +import net.runelite.client.config.ConfigGroup; +import net.runelite.client.config.ConfigItem; +import net.runelite.client.config.ConfigSection; +import net.runelite.client.config.Range; +import net.runelite.client.plugins.microbot.util.antiban.enums.PlaySchedule; + +@ConfigGroup(BreakHandlerConfig.configGroup) +public interface BreakHandlerConfig extends Config { + // Group name constant for configuration grouping. + String configGroup = "break-handler"; + String hideOverlay = "hideOverlay"; + + // ============================================================ + // Break Timing Settings + // ============================================================ + @ConfigSection( + name = "Break Timing", + description = "Configure when and how long breaks occur", + position = 0 + ) + String breakTimingSettings = "breakTimingSettings"; + + @ConfigItem( + keyName = "Min Playtime", + name = "Min Playtime", + description = "Time until break start in minutes", + position = 0, + section = breakTimingSettings + ) + default int timeUntilBreakStart() { + return 60; + } + + @ConfigItem( + keyName = "Max Playtime", + name = "Max Playtime", + description = "Time until break ends in minutes", + position = 1, + section = breakTimingSettings + ) + default int timeUntilBreakEnd() { + return 120; + } + + @ConfigItem( + keyName = "Min BreakTime", + name = "Min BreakTime", + description = "Break duration start in minutes", + position = 2, + section = breakTimingSettings + ) + default int breakDurationStart() { + return 10; + } + + @ConfigItem( + keyName = "Max BreakTime", + name = "Max BreakTime", + description = "Break duration end in minutes", + position = 3, + section = breakTimingSettings + ) + default int breakDurationEnd() { + return 15; + } + + @ConfigItem( + keyName = "breakNow", + name = "Break Now", + description = "Toggle this to start a break immediately", + position = 4, + section = breakTimingSettings + ) + default boolean breakNow() { + return false; + } + + @ConfigItem( + keyName = "breakEndNow", + name = "End Break Now", + description = "Toggle this to stop the current break immediately", + position = 5, + section = breakTimingSettings + ) + default boolean breakEndNow() { + return false; + } + + // ============================================================ + // Region Filter + // ============================================================ + @ConfigSection( + name = "Region Filter", + description = "Filter world selection by region", + position = 1, + closedByDefault = false + ) + String regionSection = "region"; + + @ConfigItem( + keyName = "useRandomWorld", + name = "Use Random World", + description = "Change to a random world once break is finished", + position = 0, + section = regionSection + ) + default boolean useRandomWorld() { + return false; + } + + @ConfigItem( + keyName = "AllowUK", + name = "UK", + description = "Allow UK worlds", + position = 1, + section = regionSection + ) + default boolean allowUK() { return true; } + + @ConfigItem( + keyName = "AllowUS", + name = "US", + description = "Allow US worlds", + position = 2, + section = regionSection + ) + default boolean allowUS() { return true; } + + @ConfigItem( + keyName = "AllowGermany", + name = "Germany", + description = "Allow German worlds", + position = 3, + section = regionSection + ) + default boolean allowGermany() { return true; } + + @ConfigItem( + keyName = "AllowAustralia", + name = "Australia", + description = "Allow Australian worlds", + position = 4, + section = regionSection + ) + default boolean allowAustralia() { return true; } + + // ============================================================ + // Break Behavior Options + // ============================================================ + @ConfigSection( + name = "Break Behavior", + description = "Configure what happens during breaks", + position = 2 + ) + String breakBehaviorOptions = "breakBehaviorOptions"; + + @ConfigItem( + keyName = "OnlyMicroBreaks", + name = "Micro Breaks Only", + description = "Only use micro breaks if enabled", + position = 0, + section = breakBehaviorOptions + ) + default boolean onlyMicroBreaks() { + return false; + } + + @ConfigItem( + keyName = "Logout", + name = "Logout", + description = "Logout when taking a break", + position = 1, + section = breakBehaviorOptions + ) + default boolean logoutAfterBreak() { + return true; + } + + @ConfigItem( + keyName = "shutdownClient", + name = "Shutdown Client", + description = "WARNING: This will completely shutdown the entire RuneLite client during breaks.
Use with caution - you will need to manually restart the client after breaks.", + position = 2, + section = breakBehaviorOptions + ) + default boolean shutdownClient() { + return false; + } + + // ============================================================ + // Advanced Options Section + // ============================================================ + @ConfigSection( + name = "Advanced Options", + description = "Advanced timing and retry configuration (for experienced users)", + position = 3 + ) + String advancedOptions = "advancedOptions"; + + @ConfigItem( + keyName = "combatCheckInterval", + name = "Combat Check Interval", + description = "How often to check for safe conditions when waiting to break (in seconds)", + position = 0, + section = advancedOptions + ) + @Range(min = 1, max = 60) + default int combatCheckInterval() { + return 30; + } + + @ConfigItem( + keyName = "logoutRetryDelay", + name = "Logout Retry Delay", + description = "Delay between logout attempts (in seconds)", + position = 1, + section = advancedOptions + ) + @Range(min = 1, max = 30) + default int logoutRetryDelay() { + return 3; + } + + @ConfigItem( + keyName = "loginRetryDelay", + name = "Login Retry Delay", + description = "Delay between login attempts (in seconds)", + position = 2, + section = advancedOptions + ) + @Range(min = 1, max = 60) + default int loginRetryDelay() { + return 5; + } + + @ConfigItem( + keyName = "maxLogoutRetries", + name = "Max Logout Retries", + description = "Maximum number of logout attempts before giving up", + position = 3, + section = advancedOptions + ) + @Range(min = 1, max = 20) + default int maxLogoutRetries() { + return 5; + } + + @ConfigItem( + keyName = "maxLoginRetries", + name = "Max Login Retries", + description = "Maximum number of login attempts before giving up", + position = 4, + section = advancedOptions + ) + @Range(min = 1, max = 20) + default int maxLoginRetries() { + return 3; + } + + @ConfigItem( + keyName = "safeConditionTimeout", + name = "Safe Condition Timeout", + description = "Maximum time to wait for safe conditions before skipping break (in minutes)", + position = 5, + section = advancedOptions + ) + @Range(min = 1, max = 10) + default int safeConditionTimeout() { + return 10; + } + + // ============================================================ + // Play Schedule Configuration Section + // ============================================================ + @ConfigSection( + name = "Play Schedule", + description = "Options related to using a play schedule", + position = 3 + ) + String usePlaySchedule = "usePlaySchedule"; + + @ConfigItem( + keyName = "UsePlaySchedule", + name = "Use Play Schedule", + description = "Enable or disable the use of a play schedule", + position = 0, + section = usePlaySchedule + ) + default boolean usePlaySchedule() { + return false; + } + + @ConfigItem( + keyName = "PlaySchedule", + name = "Play Schedule", + description = "Select the play schedule", + position = 1, + section = usePlaySchedule + ) + default PlaySchedule playSchedule() { + return PlaySchedule.MEDIUM_DAY; + } + + // ============================================================ + // Overlay Settings + // ============================================================ + @ConfigItem( + keyName = "hideOverlay", + name = "Hide Overlay", + description = "Select this if you want to hide overlay", + position = 0 + ) + default boolean isHideOverlay() { + return false; + } } \ No newline at end of file diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/breakhandler/BreakHandlerOverlay.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/breakhandler/BreakHandlerOverlay.java index 2624284f6b7..f0c8cdb9083 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/breakhandler/BreakHandlerOverlay.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/breakhandler/BreakHandlerOverlay.java @@ -1,86 +1,118 @@ -package net.runelite.client.plugins.microbot.breakhandler; - -import net.runelite.client.plugins.microbot.pluginscheduler.util.SchedulerPluginUtil; -import net.runelite.client.plugins.microbot.util.antiban.Rs2AntibanSettings; -import net.runelite.client.ui.overlay.OverlayPanel; -import net.runelite.client.ui.overlay.OverlayPosition; -import net.runelite.client.ui.overlay.components.LineComponent; -import net.runelite.client.ui.overlay.components.TitleComponent; - -import javax.inject.Inject; -import java.awt.*; -import java.time.Duration; - -public class BreakHandlerOverlay extends OverlayPanel { - private final BreakHandlerConfig config; - - @Inject - BreakHandlerOverlay(BreakHandlerPlugin plugin, BreakHandlerConfig config) - { - super(plugin); - this.config = config; - setPosition(OverlayPosition.TOP_LEFT); - setNaughty(); - } - @Override - public Dimension render(Graphics2D graphics) { - try { - panelComponent.setPreferredSize(new Dimension(200, 300)); - panelComponent.getChildren().add(TitleComponent.builder() - .text("BreakHandler V" + BreakHandlerScript.version) - .color(Color.GREEN) - .build()); - - panelComponent.getChildren().add(LineComponent.builder().build()); - - panelComponent.getChildren().add(LineComponent.builder() - .left("Total breaks: " + BreakHandlerScript.totalBreaks) - .build()); - - // Display lock state information - if (BreakHandlerScript.isLockState()) { - panelComponent.getChildren().add(LineComponent.builder() - .left("Status: LOCKED") - .right("Breaks Prevented") - .leftColor(Color.RED) - .rightColor(Color.RED) - .build()); - - // Show specific lock reason if it's manual lock vs plugin lock - if (BreakHandlerScript.lockState.get() && !SchedulerPluginUtil.hasLockedSchedulablePlugins()) { - panelComponent.getChildren().add(LineComponent.builder() - .left("Reason: Manual Lock") - .leftColor(Color.ORANGE) - .build()); - } else { - panelComponent.getChildren().add(LineComponent.builder() - .left("Reason: Plugin Lock Condition Active") - .leftColor(Color.ORANGE) - .build()); - } - } else { - panelComponent.getChildren().add(LineComponent.builder() - .left("Status: UNLOCKED") - .right("Breaks Allowed") - .leftColor(Color.GREEN) - .rightColor(Color.GREEN) - .build()); - } - - if (BreakHandlerScript.breakIn > 0) { - panelComponent.getChildren().add(LineComponent.builder() - .left((Rs2AntibanSettings.takeMicroBreaks && config.onlyMicroBreaks()) ? "Only Micro Breaks" : BreakHandlerScript.formatDuration(Duration.ofSeconds(BreakHandlerScript.breakIn), "Break in:")) - .build()); - } - if (BreakHandlerScript.breakDuration > 0) { - panelComponent.getChildren().add(LineComponent.builder() - .left(BreakHandlerScript.formatDuration(Duration.ofSeconds(BreakHandlerScript.breakDuration), "Break duration:")) - .build()); - } - - } catch(Exception ex) { - System.out.println(ex.getMessage()); - } - return super.render(graphics); - } -} +package net.runelite.client.plugins.microbot.breakhandler; + +import net.runelite.client.plugins.microbot.pluginscheduler.util.SchedulerPluginUtil; +import net.runelite.client.plugins.microbot.util.antiban.Rs2AntibanSettings; +import net.runelite.client.ui.overlay.OverlayPanel; +import net.runelite.client.ui.overlay.OverlayPosition; +import net.runelite.client.ui.overlay.components.LineComponent; +import net.runelite.client.ui.overlay.components.TitleComponent; + +import javax.inject.Inject; +import java.awt.*; +import java.time.Duration; + +public class BreakHandlerOverlay extends OverlayPanel { + private final BreakHandlerConfig config; + + @Inject + BreakHandlerOverlay(BreakHandlerPlugin plugin, BreakHandlerConfig config) + { + super(plugin); + this.config = config; + setPosition(OverlayPosition.TOP_LEFT); + setNaughty(); + } + @Override + public Dimension render(Graphics2D graphics) { + try { + panelComponent.setPreferredSize(new Dimension(200, 300)); + panelComponent.getChildren().add(TitleComponent.builder() + .text("BreakHandler V" + BreakHandlerScript.version) + .color(Color.GREEN) + .build()); + + panelComponent.getChildren().add(LineComponent.builder().build()); + + panelComponent.getChildren().add(LineComponent.builder() + .left("Total breaks: " + BreakHandlerScript.totalBreaks) + .build()); + + // Display current state information + panelComponent.getChildren().add(LineComponent.builder() + .left("State: " + BreakHandlerScript.getCurrentState().toString().replace("_", " ")) + .leftColor(getStateColor(BreakHandlerScript.getCurrentState())) + .build()); + + // Display lock state information + if (BreakHandlerScript.isLockState()) { + panelComponent.getChildren().add(LineComponent.builder() + .left("Status: LOCKED") + .right("Breaks Prevented") + .leftColor(Color.RED) + .rightColor(Color.RED) + .build()); + + // Show specific lock reason if it's manual lock vs plugin lock + if (BreakHandlerScript.lockState.get() && !SchedulerPluginUtil.hasLockedSchedulablePlugins()) { + panelComponent.getChildren().add(LineComponent.builder() + .left("Reason: Manual Lock") + .leftColor(Color.ORANGE) + .build()); + } else { + panelComponent.getChildren().add(LineComponent.builder() + .left("Reason: Plugin Lock Condition Active") + .leftColor(Color.ORANGE) + .build()); + } + } else { + panelComponent.getChildren().add(LineComponent.builder() + .left("Status: UNLOCKED") + .right("Breaks Allowed") + .leftColor(Color.GREEN) + .rightColor(Color.GREEN) + .build()); + } + + if (BreakHandlerScript.breakIn > 0) { + panelComponent.getChildren().add(LineComponent.builder() + .left((Rs2AntibanSettings.takeMicroBreaks && config.onlyMicroBreaks()) ? "Only Micro Breaks" : BreakHandlerScript.formatDuration(Duration.ofSeconds(BreakHandlerScript.breakIn), "Break in:")) + .build()); + } + if (BreakHandlerScript.breakDuration > 0) { + panelComponent.getChildren().add(LineComponent.builder() + .left(BreakHandlerScript.formatDuration(Duration.ofSeconds(BreakHandlerScript.breakDuration), "Break duration:")) + .build()); + } + + } catch(Exception ex) { + System.out.println(ex.getMessage()); + } + return super.render(graphics); + } + + /** + * Returns appropriate color for the current break handler state. + */ + private Color getStateColor(BreakHandlerState state) { + switch (state) { + case WAITING_FOR_BREAK: + return Color.GREEN; + case BREAK_REQUESTED: + return Color.YELLOW; + case INITIATING_BREAK: + return Color.ORANGE; + case LOGOUT_REQUESTED: + case LOGGING_IN: + return Color.CYAN; + case LOGGED_OUT: + case MICRO_BREAK_ACTIVE: + return Color.RED; + case LOGIN_REQUESTED: + return Color.MAGENTA; + case BREAK_ENDING: + return Color.LIGHT_GRAY; + default: + return Color.WHITE; + } + } +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/breakhandler/BreakHandlerPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/breakhandler/BreakHandlerPlugin.java index 137b6c5d55a..e3545a3e5fa 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/breakhandler/BreakHandlerPlugin.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/breakhandler/BreakHandlerPlugin.java @@ -1,110 +1,110 @@ -package net.runelite.client.plugins.microbot.breakhandler; - -import com.google.inject.Provides; -import lombok.extern.slf4j.Slf4j; -import net.runelite.client.config.ConfigManager; -import net.runelite.client.eventbus.Subscribe; -import net.runelite.client.events.ConfigChanged; -import net.runelite.client.plugins.Plugin; -import net.runelite.client.plugins.PluginDescriptor; -import net.runelite.client.plugins.microbot.Microbot; -import net.runelite.client.plugins.microbot.util.events.PluginPauseEvent; -import net.runelite.client.ui.overlay.OverlayManager; - -import javax.inject.Inject; -import java.awt.*; - -@PluginDescriptor( - name = PluginDescriptor.Default + "BreakHandler", - description = "Microbot breakhandler", - tags = {"break", "microbot", "breakhandler"}, - enabledByDefault = false -) -@Slf4j -public class BreakHandlerPlugin extends Plugin { - @Inject - BreakHandlerScript breakHandlerScript; - @Inject - private BreakHandlerConfig config; - @Inject - private OverlayManager overlayManager; - @Inject - private BreakHandlerOverlay breakHandlerOverlay; - - @Provides - BreakHandlerConfig provideConfig(ConfigManager configManager) { - return configManager.getConfig(BreakHandlerConfig.class); - } - - private boolean hideOverlay; - - @Override - protected void startUp() throws AWTException { - if (overlayManager != null) { - overlayManager.add(breakHandlerOverlay); - } - hideOverlay = config.isHideOverlay(); - toggleOverlay(hideOverlay); - breakHandlerScript.run(config); - } - - private void toggleOverlay(boolean hideOverlay) { - if (overlayManager != null) { - boolean hasOverlay = overlayManager.anyMatch(ov -> ov.getName().equalsIgnoreCase(BreakHandlerOverlay.class.getSimpleName())); - - if (hideOverlay) { - if(!hasOverlay) return; - - overlayManager.remove(breakHandlerOverlay); - } else { - if (hasOverlay) return; - - overlayManager.add(breakHandlerOverlay); - } - } - } - - protected void shutDown() { - log.info("\nshutdown: "+ - "\nbreakDuration: " + BreakHandlerScript.breakDuration + - "\nbreakIn: " + BreakHandlerScript.breakIn + - "\nisLockState: " + BreakHandlerScript.isLockState() + - "\npauseAllScripts: " + Microbot.pauseAllScripts.get() + - "\nPluginPauseEvent.isPaused: " + PluginPauseEvent.isPaused()); - breakHandlerScript.shutdown(); - log.info("\nshutdown: "+ - "\nbreakDuration: " + BreakHandlerScript.breakDuration + - "\nbreakIn: " + BreakHandlerScript.breakIn + - "\nisLockState: " + BreakHandlerScript.isLockState() + - "\npauseAllScripts: " + Microbot.pauseAllScripts.get() + - "\nPluginPauseEvent.isPaused: " + PluginPauseEvent.isPaused()); - overlayManager.remove(breakHandlerOverlay); - - - } - - // on settings change - @Subscribe - public void onConfigChanged(final ConfigChanged event) { - if (event.getGroup().equals(BreakHandlerConfig.configGroup)) { - if (event.getKey().equals("UsePlaySchedule")) { - breakHandlerScript.reset(); - } - - if (event.getKey().equals("breakNow")) { - boolean breakNowValue = config.breakNow(); - log.debug("Break Now toggled: {}", breakNowValue); - } - - if (event.getKey().equals("breakEndNow")) { - boolean breakEndNowValue = config.breakEndNow(); - log.debug("Break End Now toggled: {}", breakEndNowValue); - } - - if (event.getKey().equals(BreakHandlerConfig.hideOverlay)) { - hideOverlay = config.isHideOverlay(); - toggleOverlay(hideOverlay); - } - } - } +package net.runelite.client.plugins.microbot.breakhandler; + +import com.google.inject.Provides; +import lombok.extern.slf4j.Slf4j; +import net.runelite.client.config.ConfigManager; +import net.runelite.client.eventbus.Subscribe; +import net.runelite.client.events.ConfigChanged; +import net.runelite.client.plugins.Plugin; +import net.runelite.client.plugins.PluginDescriptor; +import net.runelite.client.plugins.microbot.Microbot; +import net.runelite.client.plugins.microbot.util.events.PluginPauseEvent; +import net.runelite.client.ui.overlay.OverlayManager; + +import javax.inject.Inject; +import java.awt.*; + +@PluginDescriptor( + name = PluginDescriptor.Default + "BreakHandler", + description = "Microbot breakhandler", + tags = {"break", "microbot", "breakhandler"}, + enabledByDefault = false +) +@Slf4j +public class BreakHandlerPlugin extends Plugin { + @Inject + BreakHandlerScript breakHandlerScript; + @Inject + private BreakHandlerConfig config; + @Inject + private OverlayManager overlayManager; + @Inject + private BreakHandlerOverlay breakHandlerOverlay; + + @Provides + BreakHandlerConfig provideConfig(ConfigManager configManager) { + return configManager.getConfig(BreakHandlerConfig.class); + } + + private boolean hideOverlay; + + @Override + protected void startUp() throws AWTException { + if (overlayManager != null) { + overlayManager.add(breakHandlerOverlay); + } + hideOverlay = config.isHideOverlay(); + toggleOverlay(hideOverlay); + breakHandlerScript.run(config); + } + + private void toggleOverlay(boolean hideOverlay) { + if (overlayManager != null) { + boolean hasOverlay = overlayManager.anyMatch(ov -> ov.getName().equalsIgnoreCase(BreakHandlerOverlay.class.getSimpleName())); + + if (hideOverlay) { + if(!hasOverlay) return; + + overlayManager.remove(breakHandlerOverlay); + } else { + if (hasOverlay) return; + + overlayManager.add(breakHandlerOverlay); + } + } + } + + protected void shutDown() { + log.info("\nshutdown: "+ + "\nbreakDuration: " + BreakHandlerScript.breakDuration + + "\nbreakIn: " + BreakHandlerScript.breakIn + + "\nisLockState: " + BreakHandlerScript.isLockState() + + "\npauseAllScripts: " + Microbot.pauseAllScripts.get() + + "\nPluginPauseEvent.isPaused: " + PluginPauseEvent.isPaused()); + breakHandlerScript.shutdown(); + log.info("\nshutdown: "+ + "\nbreakDuration: " + BreakHandlerScript.breakDuration + + "\nbreakIn: " + BreakHandlerScript.breakIn + + "\nisLockState: " + BreakHandlerScript.isLockState() + + "\npauseAllScripts: " + Microbot.pauseAllScripts.get() + + "\nPluginPauseEvent.isPaused: " + PluginPauseEvent.isPaused()); + overlayManager.remove(breakHandlerOverlay); + + + } + + // on settings change + @Subscribe + public void onConfigChanged(final ConfigChanged event) { + if (event.getGroup().equals(BreakHandlerConfig.configGroup)) { + if (event.getKey().equals("UsePlaySchedule")) { + breakHandlerScript.reset(); + } + + if (event.getKey().equals("breakNow")) { + boolean breakNowValue = config.breakNow(); + log.debug("Break Now toggled: {}", breakNowValue); + } + + if (event.getKey().equals("breakEndNow")) { + boolean breakEndNowValue = config.breakEndNow(); + log.debug("Break End Now toggled: {}", breakEndNowValue); + } + + if (event.getKey().equals(BreakHandlerConfig.hideOverlay)) { + hideOverlay = config.isHideOverlay(); + toggleOverlay(hideOverlay); + } + } + } } \ No newline at end of file diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/breakhandler/BreakHandlerScript.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/breakhandler/BreakHandlerScript.java index 90df4aa59cd..a1fc03df3bc 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/breakhandler/BreakHandlerScript.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/breakhandler/BreakHandlerScript.java @@ -1,428 +1,797 @@ -package net.runelite.client.plugins.microbot.breakhandler; -import lombok.extern.slf4j.Slf4j; -import net.runelite.client.plugins.microbot.Microbot; -import net.runelite.client.plugins.microbot.Script; -import net.runelite.client.plugins.microbot.pluginscheduler.util.SchedulerPluginUtil; -import net.runelite.client.plugins.microbot.util.antiban.Rs2AntibanSettings; -import net.runelite.client.plugins.microbot.util.events.PluginPauseEvent; -import net.runelite.client.plugins.microbot.util.math.Rs2Random; -import net.runelite.client.plugins.microbot.util.player.Rs2Player; -import net.runelite.client.plugins.microbot.util.security.Login; -import net.runelite.client.ui.ClientUI; -import java.time.Duration; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.atomic.AtomicBoolean; -/** - * BreakHandlerScript manages automated break scheduling and execution for botting activities. - * This script handles timing between breaks, break duration management, play schedule enforcement, - * and integration with micro-break systems and plugin lock conditions. - * - * The script operates on a scheduled executor that runs every second to: - * - Monitor break timers and trigger breaks when appropriate - * - Handle user-initiated break toggles - * - Enforce play schedule restrictions - * - Manage break state transitions and cleanup - * - Update UI elements like window titles during breaks - * - * Key Features: - * - Configurable break intervals and durations - * - Play schedule enforcement with automatic logout - * - Integration with micro-break antiban system - * - Lock state management to prevent breaks during critical operations - * - World switching capabilities after breaks - * - Statistics tracking for break frequency - * - * @version 1.0.0 - */ - -@Slf4j -public class BreakHandlerScript extends Script { - public static String version = "1.0.0"; - - // Constants for better maintainability - private static final int SCHEDULER_INTERVAL_MS = 1000; - private static final int MINUTES_TO_SECONDS = 60; - - public static int breakIn = -1; - public static int breakDuration = -1; - public static Duration setBreakDurationTime = Duration.ZERO; - public static int totalBreaks = 0; - - - public static AtomicBoolean lockState = new AtomicBoolean(false); - public static void setLockState(boolean state) { - boolean currentState = BreakHandlerScript.lockState.get(); - if (currentState != state) { - log.info("\n\t-Setting lock state to: " + state + "\n\t-previous state: " + currentState); - BreakHandlerScript.lockState.set(state); - } - } - private String title = ""; - private BreakHandlerConfig config; - - public static boolean isBreakActive() { - return breakDuration >= 0 ; - } - public static boolean isMicroBreakActive() { - return Rs2AntibanSettings.takeMicroBreaks && Rs2AntibanSettings.microBreakActive; - } - - public static String formatDuration(Duration duration, String header) { - return String.format(header + " %s", formatDuration(duration)); - } - - /** - * Formats a duration into HH:MM:SS format - * @param duration the duration to format - * @return formatted time string - */ - public static String formatDuration(Duration duration) { - if (duration == null || duration.isNegative() || duration.isZero()) { - return "00:00:00"; - } - long hours = duration.toHours(); - long minutes = duration.toMinutes() % 60; - long seconds = duration.getSeconds() % 60; - return String.format("%02d:%02d:%02d", hours, minutes, seconds); - } - - public boolean run(BreakHandlerConfig config) { - this.config = config; - Microbot.enableAutoRunOn = false; - title = ClientUI.getFrame().getTitle(); - initializeNextBreakTimer(); - mainScheduledFuture = scheduledExecutorService.scheduleWithFixedDelay(() -> { - try { - processBreakHandlerLogic(); - } catch (Exception ex) { - Microbot.log("BreakHandler error: " + ex.getMessage()); - } - }, 0, SCHEDULER_INTERVAL_MS, TimeUnit.MILLISECONDS); - - return true; - } - - /** - * Main break handler logic - processes all break-related operations - */ - private void processBreakHandlerLogic() { - // Handle immediate user requests first - if (handleConfigToggles()) { - return; - } - - // Handle play schedule logic - if (handlePlaySchedule()) { - return; - } - - // Update timers and UI - updateBreakTimers(); - updateWindowTitle(); - - // Handle break state transitions - if (shouldEndBreak()) { - log.debug(" Break ended naturally - " + - "\nshouldStartBreak: " + shouldStartBreak() + - "\nshouldEndBreak: " + shouldEndBreak() + - "\nbreakDuration: " + breakDuration + - "\nbreakIn: " + breakIn + - "\nisLockState: " + isLockState() + - "\npauseAllScripts: " + Microbot.pauseAllScripts.get() + - "\nPluginPauseEvent.isPaused: " + PluginPauseEvent.isPaused()); - stopBreak(); - return; - } - - if (shouldStartBreak()) { - log.debug(" Break start naturally - " + - "\nshouldStartBreak: " + shouldStartBreak() + - "\nshouldEndBreak: " + shouldEndBreak() + - "\nbreakDuration: " + breakDuration + - "\nbreakIn: " + breakIn + - "\nisLockState: " + isLockState() + - "\npauseAllScripts: " + Microbot.pauseAllScripts.get() + - "\nPluginPauseEvent.isPaused: " + PluginPauseEvent.isPaused()); - startBreak(); - } - } - - /** - * Handles immediate config toggle requests (breakNow, breakEndNow) - * @return true if a toggle was processed and execution should return - */ - private boolean handleConfigToggles() { - if (config.breakNow() && !Microbot.pauseAllScripts.get() && !isLockState() && !PluginPauseEvent.isPaused()) { - Microbot.log("Break start triggered via config toggle"); - startBreak(); - return true; - } - - if (config.breakEndNow()) { - Microbot.log("Break ended triggered via config toggle"); - stopBreak(); - return true; - } - - return false; - } - - /** - * Handles play schedule logic for outside schedule hours - * @return true if schedule logic was processed and execution should return - */ - private boolean handlePlaySchedule() { - if (config.playSchedule().isOutsideSchedule() && config.usePlaySchedule() && !isLockState()) { - Duration untilNextSchedule = config.playSchedule().timeUntilNextSchedule(); - breakIn = -1; - breakDuration = (int) untilNextSchedule.toSeconds(); - setBreakDurationTime = Duration.ofSeconds(breakDuration); - return true; - } - return false; - } - - /** - * Updates break-related timers and duration calculations - */ - private void updateBreakTimers() { - // Count down to next break - if (breakIn >= 0 && breakDuration <= 0) { - if (!(Rs2AntibanSettings.takeMicroBreaks && config.onlyMicroBreaks())) { - if(Microbot.isLoggedIn()) { - breakIn--; - } - } - } - - // Count down active break - if (breakDuration >= 0) { - breakDuration--; - } - } - - /** - * Updates window title based on current break state - */ - private void updateWindowTitle() { - if (breakDuration > 0) { - String formattedTime = formatDuration(Duration.ofSeconds(breakDuration)); - - if (Rs2AntibanSettings.takeMicroBreaks && Rs2AntibanSettings.microBreakActive) { - ClientUI.getFrame().setTitle("Micro break duration: " + formattedTime); - } else if (config.playSchedule().isOutsideSchedule() && config.usePlaySchedule()) { - ClientUI.getFrame().setTitle("Next schedule in: " + formattedTime); - } else { - ClientUI.getFrame().setTitle("Break duration: " + formattedTime); - } - } - } - - /** - * Determines if a break should naturally end - */ - private boolean shouldEndBreak() { - return ((breakDuration <= 0 && Microbot.pauseAllScripts.get() && PluginPauseEvent.isPaused()) ); - //!(Rs2AntibanSettings.universalAntiban && Rs2AntibanSettings.actionCooldownActive); - } - - /** - * Determines if a break should start - */ - private boolean shouldStartBreak() { - boolean normalBreakTime = breakIn <= 0 && !Microbot.pauseAllScripts.get() && !isLockState() && !PluginPauseEvent.isPaused(); - boolean microBreakTime = Rs2AntibanSettings.microBreakActive && !Microbot.pauseAllScripts.get() && !isLockState(); - - return normalBreakTime || microBreakTime; - } - - /** - * Initializes the timer for the next break - */ - private void initializeNextBreakTimer() { - breakIn = Rs2Random.between( - config.timeUntilBreakStart() * MINUTES_TO_SECONDS, - config.timeUntilBreakEnd() * MINUTES_TO_SECONDS - ); - resetConfigToggles(); - } - - /** - * Starts a break with appropriate duration and logout handling - */ - private void startBreak() { - Microbot.log("Starting break - breakNow: " + config.breakNow() + - ", microBreak: " + Rs2AntibanSettings.microBreakActive+", playSchedule: " + config.usePlaySchedule() ); - - // Pause all scripts - Microbot.pauseAllScripts.compareAndSet(false, true); - PluginPauseEvent.setPaused(true); - // Handle micro break case - if (Rs2AntibanSettings.microBreakActive) { - return; - } - - // Handle play schedule logout - if (isOutsidePlaySchedule()) { - Rs2Player.logout(); - return; - } - - // Set break duration and handle logout - setBreakDuration(); - if (config.logoutAfterBreak()) { - Rs2Player.logout(); - } - } - - /** - * Stops the current break and resumes normal operation - */ - private void stopBreak() { - - Microbot.log("Stopping break - duration: " + breakDuration + - ", microBreak: " + Rs2AntibanSettings.microBreakActive); - - // Resume scripts and reset state - resumeFromBreak(); - - // Handle world switching - handleWorldSwitching(); - - // Update statistics and UI - updateBreakStatistics(); - resetWindowTitle(); - - // Clean up break state - cleanupBreakState(); - - // Reset config toggles - resetConfigToggles(); - } - - /** - * Checks if currently outside play schedule hours - */ - private boolean isOutsidePlaySchedule() { - return config.playSchedule().isOutsideSchedule() && config.usePlaySchedule(); - } - - /** - * Sets the break duration based on configuration - */ - private void setBreakDuration() { - breakDuration = Rs2Random.between( - config.breakDurationStart() * MINUTES_TO_SECONDS, - config.breakDurationEnd() * MINUTES_TO_SECONDS - ); - setBreakDurationTime = Duration.ofSeconds(breakDuration); - } - - /** - * Resumes scripts and resets break timing - */ - private void resumeFromBreak() { - Microbot.pauseAllScripts.compareAndSet(true, false); - PluginPauseEvent.setPaused(false); - breakDuration = -1; - setBreakDurationTime = Duration.ZERO; - if (breakIn <= 0) { - initializeNextBreakTimer(); - } - log.info("\n\tResuming scripts after break. \n\t\tcurrent duration: " + breakDuration+ "\n\t\tnext break in: " + breakIn); - } - - /** - * Handles world switching based on configuration - */ - private void handleWorldSwitching() { - if(!Microbot.isLoggedIn()){ - if (config.useRandomWorld()) { - new Login(Login.getRandomWorld(Login.activeProfile.isMember())); - } else { - new Login(); - } - } - } - - /** - * Updates break statistics - */ - private void updateBreakStatistics() { - totalBreaks++; - } - - /** - * Resets window title to original - */ - private void resetWindowTitle() { - ClientUI.getFrame().setTitle(title); - } - - /** - * Cleans up break-related state variables - */ - private void cleanupBreakState() { - if (Rs2AntibanSettings.takeMicroBreaks) { - Rs2AntibanSettings.microBreakActive = false; - } - } - - /** - * Resets config toggles to false after processing - */ - private void resetConfigToggles() { - if (config.breakNow()) { - Microbot.getConfigManager().setConfiguration( - BreakHandlerConfig.configGroup, "breakNow", false - ); - } - if (config.breakEndNow()) { - Microbot.getConfigManager().setConfiguration( - BreakHandlerConfig.configGroup, "breakEndNow", false - ); - } - } - - @Override - public void shutdown() { - resetBreakState(); - super.shutdown(); - } - - /** - * Resets the break handler state - */ - public void reset() { - resetBreakState(); - } - - /** - * Centralized method to reset all break-related state - */ - private void resetBreakState() { - if(isBreakActive()){ - PluginPauseEvent.setPaused(false); - Microbot.pauseAllScripts.compareAndSet(true, false); - } - BreakHandlerScript.breakIn = -1; - BreakHandlerScript.breakDuration = -1; - BreakHandlerScript.setBreakDurationTime = Duration.ZERO; - BreakHandlerScript.totalBreaks = 0; - BreakHandlerScript.lockState.set(false); - - resetWindowTitle(); - } - - /** - * Checks if the break handler is currently in a locked state. - * This includes both the manual lock state and any locked conditions from schedulable plugins. - * - * @return true if locked, false otherwise - */ - public static boolean isLockState() { - boolean hasLockedSchedulablePlugins = SchedulerPluginUtil.hasLockedSchedulablePlugins(); - return lockState.get(); - } - -} +package net.runelite.client.plugins.microbot.breakhandler; +import lombok.extern.slf4j.Slf4j; +import net.runelite.api.Constants; +import net.runelite.client.plugins.microbot.Microbot; +import net.runelite.client.plugins.microbot.Script; +import net.runelite.client.plugins.microbot.pluginscheduler.util.SchedulerPluginUtil; +import net.runelite.client.plugins.microbot.util.antiban.Rs2AntibanSettings; +import net.runelite.client.plugins.microbot.util.events.PluginPauseEvent; +import net.runelite.client.plugins.microbot.util.math.Rs2Random; +import net.runelite.client.plugins.microbot.util.player.Rs2Player; +import net.runelite.client.plugins.microbot.util.security.Login; +import net.runelite.client.plugins.microbot.util.walker.Rs2Walker; +import net.runelite.client.ui.ClientUI; +import net.runelite.http.api.worlds.WorldRegion; +import java.time.Duration; +import java.time.Instant; +import java.util.ArrayList; +import java.util.List; +import java.util.Random; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.concurrent.atomic.AtomicReference; +/** + * Enhanced BreakHandlerScript with state-based break management for reliable automation. + * + * This script provides comprehensive break handling with proper state transitions, combat/interaction + * monitoring, and reliable login/logout sequences. It prevents interruption of critical activities + * and ensures safe break execution. + * + * Key Features: + * - State-based break management with proper transitions + * - Combat and interaction detection before pausing scripts + * - Reliable logout/login sequences with retry mechanisms + * - Integration with micro-break antiban system + * - Lock state management for preventing breaks during critical operations + * - Play schedule enforcement with automatic logout + * - Configurable retry delays and timeouts + * + * State Flow: + * WAITING_FOR_BREAK -> BREAK_REQUESTED -> INITIATING_BREAK -> LOGOUT_REQUESTED -> + * LOGGED_OUT -> LOGIN_REQUESTED -> LOGGING_IN -> BREAK_ENDING -> WAITING_FOR_BREAK + * + * Micro breaks follow: WAITING_FOR_BREAK -> BREAK_REQUESTED -> MICRO_BREAK_ACTIVE -> BREAK_ENDING + * + * @version 2.0.0 + */ +@Slf4j +public class BreakHandlerScript extends Script { + public static String version = "2.0.0"; + + // Constants for configuration and timing + private static final int SCHEDULER_INTERVAL_MS = Constants.GAME_TICK_LENGTH; + private static final int MINUTES_TO_SECONDS = 60; + + // Configuration-dependent timing values (accessed through helper methods) + private int getCombatCheckIntervalMs() { + return config.combatCheckInterval() * 1000; + } + + private int getLogoutRetryDelayMs() { + return config.logoutRetryDelay() * 1000; + } + + private int getLoginRetryDelayMs() { + return config.loginRetryDelay() * 1000; + } + + private int getMaxLogoutRetries() { + return config.maxLogoutRetries(); + } + + private int getMaxLoginRetries() { + return config.maxLoginRetries(); + } + + private int getSafeConditionTimeoutMs() { + return config.safeConditionTimeout() * 60 * 1000; // Convert minutes to milliseconds + } + + // Core break timing variables + public static int breakIn = -1; + public static int breakDuration = -1; + public static Duration setBreakDurationTime = Duration.ZERO; + public static int totalBreaks = 0; + + // State management - Thread-safe using atomic references + private static final AtomicReference currentState = new AtomicReference<>(BreakHandlerState.WAITING_FOR_BREAK); + private static final AtomicReference stateChangeTime = new AtomicReference<>(Instant.now()); + private static final AtomicInteger retryCount = new AtomicInteger(0); + private static Instant lastCombatCheckTime = Instant.now(); + private static Instant safeConditionWaitStartTime = null; + + // Lock state management + public static AtomicBoolean lockState = new AtomicBoolean(false); + + /** + * Sets the manual lock state and logs the change. + * When locked, breaks are prevented from starting. + */ + public static void setLockState(boolean state) { + boolean currentState = BreakHandlerScript.lockState.get(); + if (currentState != state) { + BreakHandlerScript.lockState.set(state); + log.info("Break handler lock state changed: {} -> {}", currentState, state); + } + } + + // UI and configuration + private String originalWindowTitle = ""; + private BreakHandlerConfig config; + + /** + * Checks if a break is currently active (any break state except waiting). + */ + public static boolean isBreakActive() { + return currentState.get() != BreakHandlerState.WAITING_FOR_BREAK; + } + + /** + * Checks if a micro break is currently active. + */ + public static boolean isMicroBreakActive() { + BreakHandlerState state = currentState.get(); + return state == BreakHandlerState.MICRO_BREAK_ACTIVE || + (Rs2AntibanSettings.takeMicroBreaks && Rs2AntibanSettings.microBreakActive); + } + + /** + * Gets the current break handler state. + */ + public static BreakHandlerState getCurrentState() { + return currentState.get(); + } + + /** + * Formats a duration with header text. + */ + public static String formatDuration(Duration duration, String header) { + return String.format(header + " %s", formatDuration(duration)); + } + + /** + * Formats a duration into HH:MM:SS format. + */ + public static String formatDuration(Duration duration) { + if (duration == null || duration.isNegative() || duration.isZero()) { + return "00:00:00"; + } + long hours = duration.toHours(); + long minutes = duration.toMinutes() % 60; + long seconds = duration.getSeconds() % 60; + return String.format("%02d:%02d:%02d", hours, minutes, seconds); + } + + /** + * Main entry point for the break handler script. + */ + public boolean run(BreakHandlerConfig config) { + this.config = config; + originalWindowTitle = ClientUI.getFrame().getTitle(); + // Initialize state and timing + currentState.set(BreakHandlerState.WAITING_FOR_BREAK); + stateChangeTime.set(Instant.now()); + retryCount.set(0); + initializeNextBreakTimer(); + mainScheduledFuture = scheduledExecutorService.scheduleWithFixedDelay(() -> { + try { + super.run(); + processBreakHandlerStateMachine(); + } catch (Exception ex) { + log.error("Error in break handler main loop", ex); + } + }, 0, SCHEDULER_INTERVAL_MS, TimeUnit.MILLISECONDS); + + return true; + } + + /** + * Main state machine processor - handles all break-related state transitions. + */ + private void processBreakHandlerStateMachine() { + // Handle immediate user config toggles first + if (handleConfigToggles()) { + return; + } + // Process current state + BreakHandlerState state = currentState.get(); + switch (state) { + case WAITING_FOR_BREAK: + handleWaitingForBreakState(); + break; + case BREAK_REQUESTED: + handleBreakRequestedState(); + break; + case INITIATING_BREAK: + handleInitiatingBreakState(); + break; + case LOGOUT_REQUESTED: + handleLogoutRequestedState(); + break; + case LOGGED_OUT: + handleLoggedOutState(); + break; + case MICRO_BREAK_ACTIVE: + handleMicroBreakActiveState(); + break; + case LOGIN_REQUESTED: + handleLoginRequestedState(); + break; + case LOGGING_IN: + handleLoggingInState(); + break; + case BREAK_ENDING: + handleBreakEndingState(); + break; + } + + // Update UI regardless of state + updateBreakTimers(); + updateWindowTitle(); + } + + /** + * Handles immediate config toggle requests (breakNow, breakEndNow). + */ + private boolean handleConfigToggles() { + BreakHandlerState state = currentState.get(); + + if (config.breakNow() && state == BreakHandlerState.WAITING_FOR_BREAK && !isLockState()) { + log.info("Manual break requested"); + transitionToState(BreakHandlerState.BREAK_REQUESTED); + resetConfigToggles(); + return true; + } + + if (config.breakEndNow() && isBreakActive() && state != BreakHandlerState.BREAK_ENDING && state != BreakHandlerState.LOGGING_IN) { + log.info("Manual break end requested"); + if (state == BreakHandlerState.LOGGED_OUT || state == BreakHandlerState.MICRO_BREAK_ACTIVE) { + if (state == BreakHandlerState.LOGGED_OUT){ + transitionToState(BreakHandlerState.LOGGING_IN); + }else if (state == BreakHandlerState.MICRO_BREAK_ACTIVE) { + transitionToState(BreakHandlerState.BREAK_ENDING); + } + resetConfigToggles(); + return true; + } + } + + return false; + } + + /** + * State: WAITING_FOR_BREAK + * Normal operation - counting down to next break and checking for break conditions. + */ + private void handleWaitingForBreakState() { + // Handle play schedule logic + if (config.playSchedule().isOutsideSchedule() && config.usePlaySchedule() && !isLockState()) { + log.info("Outside play schedule, requesting break"); + transitionToState(BreakHandlerState.BREAK_REQUESTED); + return; + } + + // Check for normal break conditions + boolean normalBreakTime = breakIn <= 0 && !isLockState(); + boolean microBreakTime = Rs2AntibanSettings.microBreakActive && !isLockState(); + + if (normalBreakTime || microBreakTime) { + log.info("Break time reached - Normal: {}, Micro: {}", normalBreakTime, microBreakTime); + transitionToState(BreakHandlerState.BREAK_REQUESTED); + } + } + + /** + * State: BREAK_REQUESTED + * Break should start but waiting for safe conditions (not in combat/interacting). + */ + private void handleBreakRequestedState() { + // Check for timeout on waiting for safe conditions + if (safeConditionWaitStartTime != null) { + long waitTime = Duration.between(safeConditionWaitStartTime, Instant.now()).toMillis(); + if (waitTime > getSafeConditionTimeoutMs()) { + // Check if client shutdown is configured for timeout scenarios + if (config.shutdownClient()) { + log.warn("Timeout waiting for safe conditions with client shutdown enabled - shutting down RuneLite client"); + // Pause all scripts before shutdown + Microbot.pauseAllScripts.compareAndSet(false, true); + PluginPauseEvent.setPaused(true); + handleClientShutdown(); + return; + } else { + log.warn("Timeout waiting for safe conditions, skipping this break and waiting for next one"); + // Skip this break and wait for the next one + initializeNextBreakTimer(); + transitionToState(BreakHandlerState.WAITING_FOR_BREAK); + return; + } + } + } else { + safeConditionWaitStartTime = Instant.now(); + } + + // Check for safe conditions periodically + Instant now = Instant.now(); + if (Duration.between(lastCombatCheckTime, now).toMillis() >= getCombatCheckIntervalMs()) { + lastCombatCheckTime = now; + + if (isSafeToBreak()) { + log.info("Safe conditions met, initiating break"); + transitionToState(BreakHandlerState.INITIATING_BREAK); + } else { + log.debug("Waiting for safe conditions - Combat: {}, Interacting: {}", + Rs2Player.isInCombat(), Rs2Player.isInteracting()); + } + } + } + + /** + * State: INITIATING_BREAK + * Safe to pause scripts, starting break process. + */ + private void handleInitiatingBreakState() { + log.info("Initiating break - pausing all scripts"); + + // Pause all scripts + Microbot.pauseAllScripts.compareAndSet(false, true); + PluginPauseEvent.setPaused(true); + Rs2Walker.setTarget(null); + // Determine next state based on break type + if (Rs2AntibanSettings.microBreakActive && (config.onlyMicroBreaks() || !shouldLogout())) { + setBreakDuration(); + transitionToState(BreakHandlerState.MICRO_BREAK_ACTIVE); + } else { + transitionToState(BreakHandlerState.LOGOUT_REQUESTED); + } + } + + /** + * Handles client shutdown when configured to shutdown the entire client during breaks. + * This will completely close the RuneLite client. + */ + private void handleClientShutdown() { + try { + log.info("Shutting down RuneLite client due to break handler configuration"); + + // Update break statistics before shutdown + updateBreakStatistics(); + + // Clean shutdown of the client + ClientUI.getFrame().setTitle(originalWindowTitle + " - Shutting Down"); + if (scheduledFuture != null && !scheduledFuture.isDone()) { + scheduledFuture.cancel(true); + } + // Schedule shutdown to allow logging to complete + scheduledFuture = scheduledExecutorService.schedule(() -> { + System.exit(0); + }, 1000, TimeUnit.MILLISECONDS); + + } catch (Exception ex) { + log.error("Error during client shutdown", ex); + // Force shutdown if graceful shutdown fails + System.exit(1); + } + } + + /** + * State: LOGOUT_REQUESTED + * Attempting to logout, with retry logic. + */ + private void handleLogoutRequestedState() { + int currentRetryCount = retryCount.get(); + Instant currentStateChangeTime = stateChangeTime.get(); + + if (currentRetryCount >= getMaxLogoutRetries()) { + log.warn("Max logout retries reached, continuing with logged-in break"); + setBreakDuration(); + transitionToState(BreakHandlerState.MICRO_BREAK_ACTIVE); + return; + } + + // Check if enough time has passed for retry + if (currentRetryCount > 0 && Duration.between(currentStateChangeTime, Instant.now()).toMillis() < getLogoutRetryDelayMs()) { + long remainingTime = getLogoutRetryDelayMs() - Duration.between(currentStateChangeTime, Instant.now()).toMillis(); + log.debug("Waiting for next logout retry ({} ms remaining)", remainingTime); + return; + } + + log.info("Attempting logout (attempt {}/{})", currentRetryCount + 1, getMaxLogoutRetries()); + + try { + Rs2Player.logout(); + // Don't immediately transition - wait for next cycle to check if logout was successful + retryCount.incrementAndGet(); + stateChangeTime.set(Instant.now()); + if (scheduledFuture != null && !scheduledFuture.isDone()) { + scheduledFuture.cancel(true); + } + // Check on next cycle if we successfully logged out + scheduledFuture = scheduledExecutorService.schedule(() -> { + if (!Microbot.isLoggedIn()) { + log.info("Logout successful"); + setBreakDuration(); + transitionToState(BreakHandlerState.LOGGED_OUT); + } + }, 2000, TimeUnit.MILLISECONDS); + + } catch (Exception ex) { + log.error("Error during logout attempt", ex); + retryCount.incrementAndGet(); + stateChangeTime.set(Instant.now()); + } + } + + /** + * State: LOGGED_OUT + * Successfully logged out, waiting for break duration to complete. + */ + private void handleLoggedOutState() { + // Check if break should end + if (breakDuration <= 0 || config.breakEndNow()) { + log.info("Break duration completed, requesting login"); + transitionToState(BreakHandlerState.LOGIN_REQUESTED); + } + } + + /** + * State: MICRO_BREAK_ACTIVE + * In micro break state (no logout), waiting for duration to complete. + */ + private void handleMicroBreakActiveState() { + // Check if micro break should end + if ((breakDuration <= 0 && !Rs2AntibanSettings.microBreakActive) || config.breakEndNow()) { + log.info("Micro break completed"); + transitionToState(BreakHandlerState.BREAK_ENDING); + } + } + + /** + * State: LOGIN_REQUESTED + * Break ended, attempting to login. + */ + private void handleLoginRequestedState() { + if (Microbot.isLoggedIn()) { + log.info("Already logged in, proceeding to break ending"); + transitionToState(BreakHandlerState.BREAK_ENDING); + return; + } + + log.info("Attempting login"); + try { + // Use the Login utility class to handle login + if (Login.activeProfile != null) { + if (config.useRandomWorld()) { + // Get random world with region filter for break handler + int randomWorld = getRandomWorldWithRegionFilter(config); + new Login(randomWorld); + } else { + new Login(); + } + } else { + // If no active profile, use default login + if (config.useRandomWorld()) { + // Get random world with region filter for break handler + int randomWorld = getRandomWorldWithRegionFilter(config); + new Login(randomWorld); + } else { + new Login(); + } + } + transitionToState(BreakHandlerState.LOGGING_IN); + } catch (Exception ex) { + log.error("Error initiating login", ex); + // Retry login request after delay + scheduledFuture = scheduledExecutorService.schedule(() -> { + if (currentState.get() == BreakHandlerState.LOGIN_REQUESTED) { + retryCount.incrementAndGet(); + } + }, getLoginRetryDelayMs(), TimeUnit.MILLISECONDS); + } + } + + /** + * State: LOGGING_IN + * Currently attempting to log in, with retry logic. + */ + private void handleLoggingInState() { + if (Microbot.isLoggedIn()) { + log.info("Login successful"); + transitionToState(BreakHandlerState.BREAK_ENDING); + return; + } + + // Get current values atomically + int currentRetryCount = retryCount.get(); + Instant currentStateChangeTime = stateChangeTime.get(); + + // Check for timeout or max retries + long loginTime = Duration.between(currentStateChangeTime, Instant.now()).toMillis(); + if (loginTime > (getLoginRetryDelayMs() * (currentRetryCount + 1)) && currentRetryCount < getMaxLoginRetries()) { + log.info("Login retry {} of {}", currentRetryCount + 1, getMaxLoginRetries()); + retryCount.incrementAndGet(); + transitionToState(BreakHandlerState.LOGIN_REQUESTED); + } else if (currentRetryCount >= getMaxLoginRetries()) { + log.warn("Max login retries reached, staying logged out"); + // Stay in logged out state and wait for manual intervention or next attempt + setBreakDuration(); // Reset break duration to prevent immediate retry + transitionToState(BreakHandlerState.LOGGED_OUT); + } + } + + /** + * State: BREAK_ENDING + * Break ended successfully, cleaning up and resuming normal operation. + */ + private void handleBreakEndingState() { + log.info("Break ending, resuming normal operation"); + + // Resume scripts and reset state + resumeFromBreak(); + + // Handle world switching if configured + handleWorldSwitching(); + + // Update statistics and UI + updateBreakStatistics(); + resetWindowTitle(); + + // Clean up break state + cleanupBreakState(); + + // Reset config toggles + resetConfigToggles(); + + // Return to waiting state + initializeNextBreakTimer(); + transitionToState(BreakHandlerState.WAITING_FOR_BREAK); + } + + /** + * Transitions to a new state and resets relevant counters. + * This method is thread-safe and can be called from any thread. + */ + private static void transitionToState(BreakHandlerState newState) { + BreakHandlerState oldState = currentState.get(); + if (oldState != newState) { + log.debug("State transition: {} -> {}", oldState, newState); + currentState.set(newState); + stateChangeTime.set(Instant.now()); + retryCount.set(0); + + // Reset safe condition wait time when leaving BREAK_REQUESTED + if (newState != BreakHandlerState.BREAK_REQUESTED) { + safeConditionWaitStartTime = null; + } + } + } + + /** + * Checks if it's safe to break (not in combat, not interacting). + */ + private boolean isSafeToBreak() { + return !Rs2Player.isInCombat() && !Rs2Player.isInteracting(); + } + + /** + * Determines if logout should occur based on configuration and conditions. + */ + private boolean shouldLogout() { + return isOutsidePlaySchedule() || config.logoutAfterBreak(); + } + + /** + * Initializes the timer for the next break. + */ + private void initializeNextBreakTimer() { + breakIn = Rs2Random.between( + config.timeUntilBreakStart() * MINUTES_TO_SECONDS, + config.timeUntilBreakEnd() * MINUTES_TO_SECONDS + ); + log.debug("Next break in {} seconds", breakIn); + } + + /** + * Sets the break duration based on configuration and break type. + */ + private void setBreakDuration() { + if (Rs2AntibanSettings.microBreakActive) { + // Micro break duration - use proper range and convert minutes to seconds + breakDuration = Rs2Random.between( + Rs2AntibanSettings.microBreakDurationLow * MINUTES_TO_SECONDS, + Rs2AntibanSettings.microBreakDurationHigh * MINUTES_TO_SECONDS + ); + setBreakDurationTime = Duration.ofSeconds(breakDuration); + log.debug("Micro break duration set to {} seconds ({} minutes)", + breakDuration, breakDuration / MINUTES_TO_SECONDS); + } else if (isOutsidePlaySchedule()) { + // For play schedule, break until next play time + Duration timeUntilPlaySchedule = config.playSchedule().timeUntilNextSchedule(); + breakDuration = (int) timeUntilPlaySchedule.toSeconds(); + setBreakDurationTime = Duration.ofSeconds(breakDuration); + log.info("Play schedule break duration set to {} seconds", breakDuration); + } else { + // Normal break duration + breakDuration = Rs2Random.between( + config.breakDurationStart() * MINUTES_TO_SECONDS, + config.breakDurationEnd() * MINUTES_TO_SECONDS + ); + setBreakDurationTime = Duration.ofSeconds(breakDuration); + log.debug("Normal break duration set to {} seconds", breakDuration); + } + } + + /** + * Resumes scripts and resets break timing. + */ + private void resumeFromBreak() { + Microbot.pauseAllScripts.compareAndSet(true, false); + PluginPauseEvent.setPaused(false); + Rs2AntibanSettings.microBreakActive = false; + } + + private List getAllowedRegions(BreakHandlerConfig config) { + List allowedRegions = new ArrayList<>(); + + if (config.allowUK()) { + allowedRegions.add(WorldRegion.UNITED_KINGDOM); + } + if (config.allowUS()) { + allowedRegions.add(WorldRegion.UNITED_STATES_OF_AMERICA); + } + if (config.allowGermany()) { + allowedRegions.add(WorldRegion.GERMANY); + } + if (config.allowAustralia()) { + allowedRegions.add(WorldRegion.AUSTRALIA); + } + + return allowedRegions; + } + + private int getRandomWorldWithRegionFilter(BreakHandlerConfig config) { + List allowedRegions = getAllowedRegions(config); + + // Use automatic member detection from profiles + boolean isMember = Rs2Player.isMember(); + + if (allowedRegions.isEmpty()) { + // If no regions allowed, use default method + return Login.getRandomWorld(isMember); + } + + // Pick a random region from allowed regions + Random random = new Random(); + WorldRegion selectedRegion = allowedRegions.get(random.nextInt(allowedRegions.size())); + + return Login.getRandomWorld(isMember, selectedRegion); + } + + /** + * Handles world switching based on configuration. + */ + private void handleWorldSwitching() { + if (config.useRandomWorld()) { + try { + int randomWorld = getRandomWorldWithRegionFilter(config); + Microbot.hopToWorld(randomWorld); + } catch (Exception ex) { + // Silent error handling + } + } + } + + /** + * Updates break statistics. + */ + private void updateBreakStatistics() { + totalBreaks++; + log.info("Break completed. Total breaks: {}", totalBreaks); + } + + /** + * Resets window title to original. + */ + private void resetWindowTitle() { + ClientUI.getFrame().setTitle(originalWindowTitle); + } + + /** + * Cleans up break-related state variables. + */ + private void cleanupBreakState() { + breakDuration = -1; + setBreakDurationTime = Duration.ZERO; + } + + /** + * Resets config toggles to false after processing. + */ + private void resetConfigToggles() { + // Note: These will reset automatically due to the config system + // This method exists for potential future toggle handling + if (Microbot.getConfigManager() == null) { + return; + } + Microbot.getConfigManager().setConfiguration(BreakHandlerConfig.configGroup, "breakNow", false); + Microbot.getConfigManager().setConfiguration(BreakHandlerConfig.configGroup, "breakEndNow", false); + } + + /** + * Updates break-related timers and duration calculations. + */ + private void updateBreakTimers() { + BreakHandlerState state = currentState.get(); + + // Count down to next break (only in waiting state and when logged in) + if (state == BreakHandlerState.WAITING_FOR_BREAK && breakIn >= 0 && Microbot.isLoggedIn()) { + breakIn--; + } + + // Count down active break duration + if ((state == BreakHandlerState.LOGGED_OUT || state == BreakHandlerState.MICRO_BREAK_ACTIVE) + && breakDuration >= 0) { + breakDuration--; + } + } + + /** + * Updates window title based on current state and break information. + */ + private void updateWindowTitle() { + BreakHandlerState state = currentState.get(); + + if (state == BreakHandlerState.LOGGED_OUT || state == BreakHandlerState.MICRO_BREAK_ACTIVE) { + String breakType = state == BreakHandlerState.MICRO_BREAK_ACTIVE ? "Micro Break" : "Break"; + ClientUI.getFrame().setTitle(originalWindowTitle + " - " + breakType + ": " + + formatDuration(Duration.ofSeconds(Math.max(0, breakDuration)))); + } else if (isBreakActive()) { + ClientUI.getFrame().setTitle(originalWindowTitle + " - " + state.toString().replace("_", " ")); + } + } + + /** + * Checks if currently outside play schedule hours. + */ + private boolean isOutsidePlaySchedule() { + return config.playSchedule().isOutsideSchedule() && config.usePlaySchedule(); + } + + @Override + public void shutdown() { + BreakHandlerState state = currentState.get(); + log.info("Break handler shutting down. Current state: {}", state); + + // If we're in a break state, try to clean up gracefully + if (state == BreakHandlerState.LOGGED_OUT) { + log.info("Attempting to resume from logged out state"); + transitionToState(BreakHandlerState.LOGIN_REQUESTED); + } else if (isBreakActive()) { + log.info("Attempting to end break gracefully"); + transitionToState(BreakHandlerState.BREAK_ENDING); + } + + resetWindowTitle(); + super.shutdown(); + } + + /** + * Resets the break handler to initial state. + */ + public void reset() { + log.info("Resetting break handler"); + resetBreakState(); + transitionToState(BreakHandlerState.WAITING_FOR_BREAK); + initializeNextBreakTimer(); + } + + /** + * Centralized method to reset all break-related state. + */ + private void resetBreakState() { + breakIn = -1; + breakDuration = -1; + setBreakDurationTime = Duration.ZERO; + retryCount.set(0); + safeConditionWaitStartTime = null; + lastCombatCheckTime = Instant.now(); + } + + /** + * Checks if the break handler is currently in a locked state. + * This includes both the manual lock state and any locked conditions from schedulable plugins. + */ + public static boolean isLockState() { + return lockState.get() || SchedulerPluginUtil.hasLockedSchedulablePlugins(); + } +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/breakhandler/BreakHandlerState.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/breakhandler/BreakHandlerState.java new file mode 100644 index 00000000000..d9386b494bf --- /dev/null +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/breakhandler/BreakHandlerState.java @@ -0,0 +1,62 @@ +package net.runelite.client.plugins.microbot.breakhandler; + +/** + * Enumeration representing the various states of the BreakHandler system. + * This state machine ensures reliable break transitions and prevents interruption + * of critical game activities. + */ +public enum BreakHandlerState { + /** + * Normal operation state - counting down to the next break. + * Scripts are running normally. + */ + WAITING_FOR_BREAK, + + /** + * Break has been requested but waiting for safe conditions. + * Monitoring for combat/interaction to end before pausing scripts. + */ + BREAK_REQUESTED, + + /** + * Safe conditions met, initiating break by pausing scripts. + * Brief transition state. + */ + INITIATING_BREAK, + + /** + * Logout has been requested and is being attempted. + * May retry logout if unsuccessful. + */ + LOGOUT_REQUESTED, + + /** + * Successfully logged out and in break state. + * Waiting for break duration to complete. + */ + LOGGED_OUT, + + /** + * Micro break is active - scripts paused but no logout. + * Used for short antiban breaks. + */ + MICRO_BREAK_ACTIVE, + + /** + * Break duration completed, requesting login. + * Attempting to log back in. + */ + LOGIN_REQUESTED, + + /** + * Currently attempting to log in. + * May retry if unsuccessful. + */ + LOGGING_IN, + + /** + * Break ended successfully, resuming normal operation. + * Brief transition state before returning to WAITING_FOR_BREAK. + */ + BREAK_ENDING +} From a1c20a64c387543491b1f8d3627d8806f079a22b Mon Sep 17 00:00:00 2001 From: vi3tcn <60859658+vi3tcn@users.noreply.github.com> Date: Mon, 11 Aug 2025 21:55:08 +0100 Subject: [PATCH 3/3] Delete runelite-client/src/main/java/net/runelite/client/plugins/microbot/breakhandler directory --- .../breakhandler/BreakHandlerConfig.java | 319 ------- .../breakhandler/BreakHandlerOverlay.java | 118 --- .../breakhandler/BreakHandlerPlugin.java | 110 --- .../breakhandler/BreakHandlerScript.java | 797 ------------------ .../breakhandler/BreakHandlerState.java | 62 -- 5 files changed, 1406 deletions(-) delete mode 100644 runelite-client/src/main/java/net/runelite/client/plugins/microbot/breakhandler/BreakHandlerConfig.java delete mode 100644 runelite-client/src/main/java/net/runelite/client/plugins/microbot/breakhandler/BreakHandlerOverlay.java delete mode 100644 runelite-client/src/main/java/net/runelite/client/plugins/microbot/breakhandler/BreakHandlerPlugin.java delete mode 100644 runelite-client/src/main/java/net/runelite/client/plugins/microbot/breakhandler/BreakHandlerScript.java delete mode 100644 runelite-client/src/main/java/net/runelite/client/plugins/microbot/breakhandler/BreakHandlerState.java diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/breakhandler/BreakHandlerConfig.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/breakhandler/BreakHandlerConfig.java deleted file mode 100644 index eecdc09c7ff..00000000000 --- a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/breakhandler/BreakHandlerConfig.java +++ /dev/null @@ -1,319 +0,0 @@ -package net.runelite.client.plugins.microbot.breakhandler; - -import net.runelite.client.config.Config; -import net.runelite.client.config.ConfigGroup; -import net.runelite.client.config.ConfigItem; -import net.runelite.client.config.ConfigSection; -import net.runelite.client.config.Range; -import net.runelite.client.plugins.microbot.util.antiban.enums.PlaySchedule; - -@ConfigGroup(BreakHandlerConfig.configGroup) -public interface BreakHandlerConfig extends Config { - // Group name constant for configuration grouping. - String configGroup = "break-handler"; - String hideOverlay = "hideOverlay"; - - // ============================================================ - // Break Timing Settings - // ============================================================ - @ConfigSection( - name = "Break Timing", - description = "Configure when and how long breaks occur", - position = 0 - ) - String breakTimingSettings = "breakTimingSettings"; - - @ConfigItem( - keyName = "Min Playtime", - name = "Min Playtime", - description = "Time until break start in minutes", - position = 0, - section = breakTimingSettings - ) - default int timeUntilBreakStart() { - return 60; - } - - @ConfigItem( - keyName = "Max Playtime", - name = "Max Playtime", - description = "Time until break ends in minutes", - position = 1, - section = breakTimingSettings - ) - default int timeUntilBreakEnd() { - return 120; - } - - @ConfigItem( - keyName = "Min BreakTime", - name = "Min BreakTime", - description = "Break duration start in minutes", - position = 2, - section = breakTimingSettings - ) - default int breakDurationStart() { - return 10; - } - - @ConfigItem( - keyName = "Max BreakTime", - name = "Max BreakTime", - description = "Break duration end in minutes", - position = 3, - section = breakTimingSettings - ) - default int breakDurationEnd() { - return 15; - } - - @ConfigItem( - keyName = "breakNow", - name = "Break Now", - description = "Toggle this to start a break immediately", - position = 4, - section = breakTimingSettings - ) - default boolean breakNow() { - return false; - } - - @ConfigItem( - keyName = "breakEndNow", - name = "End Break Now", - description = "Toggle this to stop the current break immediately", - position = 5, - section = breakTimingSettings - ) - default boolean breakEndNow() { - return false; - } - - // ============================================================ - // Region Filter - // ============================================================ - @ConfigSection( - name = "Region Filter", - description = "Filter world selection by region", - position = 1, - closedByDefault = false - ) - String regionSection = "region"; - - @ConfigItem( - keyName = "useRandomWorld", - name = "Use Random World", - description = "Change to a random world once break is finished", - position = 0, - section = regionSection - ) - default boolean useRandomWorld() { - return false; - } - - @ConfigItem( - keyName = "AllowUK", - name = "UK", - description = "Allow UK worlds", - position = 1, - section = regionSection - ) - default boolean allowUK() { return true; } - - @ConfigItem( - keyName = "AllowUS", - name = "US", - description = "Allow US worlds", - position = 2, - section = regionSection - ) - default boolean allowUS() { return true; } - - @ConfigItem( - keyName = "AllowGermany", - name = "Germany", - description = "Allow German worlds", - position = 3, - section = regionSection - ) - default boolean allowGermany() { return true; } - - @ConfigItem( - keyName = "AllowAustralia", - name = "Australia", - description = "Allow Australian worlds", - position = 4, - section = regionSection - ) - default boolean allowAustralia() { return true; } - - // ============================================================ - // Break Behavior Options - // ============================================================ - @ConfigSection( - name = "Break Behavior", - description = "Configure what happens during breaks", - position = 2 - ) - String breakBehaviorOptions = "breakBehaviorOptions"; - - @ConfigItem( - keyName = "OnlyMicroBreaks", - name = "Micro Breaks Only", - description = "Only use micro breaks if enabled", - position = 0, - section = breakBehaviorOptions - ) - default boolean onlyMicroBreaks() { - return false; - } - - @ConfigItem( - keyName = "Logout", - name = "Logout", - description = "Logout when taking a break", - position = 1, - section = breakBehaviorOptions - ) - default boolean logoutAfterBreak() { - return true; - } - - @ConfigItem( - keyName = "shutdownClient", - name = "Shutdown Client", - description = "WARNING: This will completely shutdown the entire RuneLite client during breaks.
Use with caution - you will need to manually restart the client after breaks.", - position = 2, - section = breakBehaviorOptions - ) - default boolean shutdownClient() { - return false; - } - - // ============================================================ - // Advanced Options Section - // ============================================================ - @ConfigSection( - name = "Advanced Options", - description = "Advanced timing and retry configuration (for experienced users)", - position = 3 - ) - String advancedOptions = "advancedOptions"; - - @ConfigItem( - keyName = "combatCheckInterval", - name = "Combat Check Interval", - description = "How often to check for safe conditions when waiting to break (in seconds)", - position = 0, - section = advancedOptions - ) - @Range(min = 1, max = 60) - default int combatCheckInterval() { - return 30; - } - - @ConfigItem( - keyName = "logoutRetryDelay", - name = "Logout Retry Delay", - description = "Delay between logout attempts (in seconds)", - position = 1, - section = advancedOptions - ) - @Range(min = 1, max = 30) - default int logoutRetryDelay() { - return 3; - } - - @ConfigItem( - keyName = "loginRetryDelay", - name = "Login Retry Delay", - description = "Delay between login attempts (in seconds)", - position = 2, - section = advancedOptions - ) - @Range(min = 1, max = 60) - default int loginRetryDelay() { - return 5; - } - - @ConfigItem( - keyName = "maxLogoutRetries", - name = "Max Logout Retries", - description = "Maximum number of logout attempts before giving up", - position = 3, - section = advancedOptions - ) - @Range(min = 1, max = 20) - default int maxLogoutRetries() { - return 5; - } - - @ConfigItem( - keyName = "maxLoginRetries", - name = "Max Login Retries", - description = "Maximum number of login attempts before giving up", - position = 4, - section = advancedOptions - ) - @Range(min = 1, max = 20) - default int maxLoginRetries() { - return 3; - } - - @ConfigItem( - keyName = "safeConditionTimeout", - name = "Safe Condition Timeout", - description = "Maximum time to wait for safe conditions before skipping break (in minutes)", - position = 5, - section = advancedOptions - ) - @Range(min = 1, max = 10) - default int safeConditionTimeout() { - return 10; - } - - // ============================================================ - // Play Schedule Configuration Section - // ============================================================ - @ConfigSection( - name = "Play Schedule", - description = "Options related to using a play schedule", - position = 3 - ) - String usePlaySchedule = "usePlaySchedule"; - - @ConfigItem( - keyName = "UsePlaySchedule", - name = "Use Play Schedule", - description = "Enable or disable the use of a play schedule", - position = 0, - section = usePlaySchedule - ) - default boolean usePlaySchedule() { - return false; - } - - @ConfigItem( - keyName = "PlaySchedule", - name = "Play Schedule", - description = "Select the play schedule", - position = 1, - section = usePlaySchedule - ) - default PlaySchedule playSchedule() { - return PlaySchedule.MEDIUM_DAY; - } - - // ============================================================ - // Overlay Settings - // ============================================================ - @ConfigItem( - keyName = "hideOverlay", - name = "Hide Overlay", - description = "Select this if you want to hide overlay", - position = 0 - ) - default boolean isHideOverlay() { - return false; - } -} \ No newline at end of file diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/breakhandler/BreakHandlerOverlay.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/breakhandler/BreakHandlerOverlay.java deleted file mode 100644 index f0c8cdb9083..00000000000 --- a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/breakhandler/BreakHandlerOverlay.java +++ /dev/null @@ -1,118 +0,0 @@ -package net.runelite.client.plugins.microbot.breakhandler; - -import net.runelite.client.plugins.microbot.pluginscheduler.util.SchedulerPluginUtil; -import net.runelite.client.plugins.microbot.util.antiban.Rs2AntibanSettings; -import net.runelite.client.ui.overlay.OverlayPanel; -import net.runelite.client.ui.overlay.OverlayPosition; -import net.runelite.client.ui.overlay.components.LineComponent; -import net.runelite.client.ui.overlay.components.TitleComponent; - -import javax.inject.Inject; -import java.awt.*; -import java.time.Duration; - -public class BreakHandlerOverlay extends OverlayPanel { - private final BreakHandlerConfig config; - - @Inject - BreakHandlerOverlay(BreakHandlerPlugin plugin, BreakHandlerConfig config) - { - super(plugin); - this.config = config; - setPosition(OverlayPosition.TOP_LEFT); - setNaughty(); - } - @Override - public Dimension render(Graphics2D graphics) { - try { - panelComponent.setPreferredSize(new Dimension(200, 300)); - panelComponent.getChildren().add(TitleComponent.builder() - .text("BreakHandler V" + BreakHandlerScript.version) - .color(Color.GREEN) - .build()); - - panelComponent.getChildren().add(LineComponent.builder().build()); - - panelComponent.getChildren().add(LineComponent.builder() - .left("Total breaks: " + BreakHandlerScript.totalBreaks) - .build()); - - // Display current state information - panelComponent.getChildren().add(LineComponent.builder() - .left("State: " + BreakHandlerScript.getCurrentState().toString().replace("_", " ")) - .leftColor(getStateColor(BreakHandlerScript.getCurrentState())) - .build()); - - // Display lock state information - if (BreakHandlerScript.isLockState()) { - panelComponent.getChildren().add(LineComponent.builder() - .left("Status: LOCKED") - .right("Breaks Prevented") - .leftColor(Color.RED) - .rightColor(Color.RED) - .build()); - - // Show specific lock reason if it's manual lock vs plugin lock - if (BreakHandlerScript.lockState.get() && !SchedulerPluginUtil.hasLockedSchedulablePlugins()) { - panelComponent.getChildren().add(LineComponent.builder() - .left("Reason: Manual Lock") - .leftColor(Color.ORANGE) - .build()); - } else { - panelComponent.getChildren().add(LineComponent.builder() - .left("Reason: Plugin Lock Condition Active") - .leftColor(Color.ORANGE) - .build()); - } - } else { - panelComponent.getChildren().add(LineComponent.builder() - .left("Status: UNLOCKED") - .right("Breaks Allowed") - .leftColor(Color.GREEN) - .rightColor(Color.GREEN) - .build()); - } - - if (BreakHandlerScript.breakIn > 0) { - panelComponent.getChildren().add(LineComponent.builder() - .left((Rs2AntibanSettings.takeMicroBreaks && config.onlyMicroBreaks()) ? "Only Micro Breaks" : BreakHandlerScript.formatDuration(Duration.ofSeconds(BreakHandlerScript.breakIn), "Break in:")) - .build()); - } - if (BreakHandlerScript.breakDuration > 0) { - panelComponent.getChildren().add(LineComponent.builder() - .left(BreakHandlerScript.formatDuration(Duration.ofSeconds(BreakHandlerScript.breakDuration), "Break duration:")) - .build()); - } - - } catch(Exception ex) { - System.out.println(ex.getMessage()); - } - return super.render(graphics); - } - - /** - * Returns appropriate color for the current break handler state. - */ - private Color getStateColor(BreakHandlerState state) { - switch (state) { - case WAITING_FOR_BREAK: - return Color.GREEN; - case BREAK_REQUESTED: - return Color.YELLOW; - case INITIATING_BREAK: - return Color.ORANGE; - case LOGOUT_REQUESTED: - case LOGGING_IN: - return Color.CYAN; - case LOGGED_OUT: - case MICRO_BREAK_ACTIVE: - return Color.RED; - case LOGIN_REQUESTED: - return Color.MAGENTA; - case BREAK_ENDING: - return Color.LIGHT_GRAY; - default: - return Color.WHITE; - } - } -} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/breakhandler/BreakHandlerPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/breakhandler/BreakHandlerPlugin.java deleted file mode 100644 index e3545a3e5fa..00000000000 --- a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/breakhandler/BreakHandlerPlugin.java +++ /dev/null @@ -1,110 +0,0 @@ -package net.runelite.client.plugins.microbot.breakhandler; - -import com.google.inject.Provides; -import lombok.extern.slf4j.Slf4j; -import net.runelite.client.config.ConfigManager; -import net.runelite.client.eventbus.Subscribe; -import net.runelite.client.events.ConfigChanged; -import net.runelite.client.plugins.Plugin; -import net.runelite.client.plugins.PluginDescriptor; -import net.runelite.client.plugins.microbot.Microbot; -import net.runelite.client.plugins.microbot.util.events.PluginPauseEvent; -import net.runelite.client.ui.overlay.OverlayManager; - -import javax.inject.Inject; -import java.awt.*; - -@PluginDescriptor( - name = PluginDescriptor.Default + "BreakHandler", - description = "Microbot breakhandler", - tags = {"break", "microbot", "breakhandler"}, - enabledByDefault = false -) -@Slf4j -public class BreakHandlerPlugin extends Plugin { - @Inject - BreakHandlerScript breakHandlerScript; - @Inject - private BreakHandlerConfig config; - @Inject - private OverlayManager overlayManager; - @Inject - private BreakHandlerOverlay breakHandlerOverlay; - - @Provides - BreakHandlerConfig provideConfig(ConfigManager configManager) { - return configManager.getConfig(BreakHandlerConfig.class); - } - - private boolean hideOverlay; - - @Override - protected void startUp() throws AWTException { - if (overlayManager != null) { - overlayManager.add(breakHandlerOverlay); - } - hideOverlay = config.isHideOverlay(); - toggleOverlay(hideOverlay); - breakHandlerScript.run(config); - } - - private void toggleOverlay(boolean hideOverlay) { - if (overlayManager != null) { - boolean hasOverlay = overlayManager.anyMatch(ov -> ov.getName().equalsIgnoreCase(BreakHandlerOverlay.class.getSimpleName())); - - if (hideOverlay) { - if(!hasOverlay) return; - - overlayManager.remove(breakHandlerOverlay); - } else { - if (hasOverlay) return; - - overlayManager.add(breakHandlerOverlay); - } - } - } - - protected void shutDown() { - log.info("\nshutdown: "+ - "\nbreakDuration: " + BreakHandlerScript.breakDuration + - "\nbreakIn: " + BreakHandlerScript.breakIn + - "\nisLockState: " + BreakHandlerScript.isLockState() + - "\npauseAllScripts: " + Microbot.pauseAllScripts.get() + - "\nPluginPauseEvent.isPaused: " + PluginPauseEvent.isPaused()); - breakHandlerScript.shutdown(); - log.info("\nshutdown: "+ - "\nbreakDuration: " + BreakHandlerScript.breakDuration + - "\nbreakIn: " + BreakHandlerScript.breakIn + - "\nisLockState: " + BreakHandlerScript.isLockState() + - "\npauseAllScripts: " + Microbot.pauseAllScripts.get() + - "\nPluginPauseEvent.isPaused: " + PluginPauseEvent.isPaused()); - overlayManager.remove(breakHandlerOverlay); - - - } - - // on settings change - @Subscribe - public void onConfigChanged(final ConfigChanged event) { - if (event.getGroup().equals(BreakHandlerConfig.configGroup)) { - if (event.getKey().equals("UsePlaySchedule")) { - breakHandlerScript.reset(); - } - - if (event.getKey().equals("breakNow")) { - boolean breakNowValue = config.breakNow(); - log.debug("Break Now toggled: {}", breakNowValue); - } - - if (event.getKey().equals("breakEndNow")) { - boolean breakEndNowValue = config.breakEndNow(); - log.debug("Break End Now toggled: {}", breakEndNowValue); - } - - if (event.getKey().equals(BreakHandlerConfig.hideOverlay)) { - hideOverlay = config.isHideOverlay(); - toggleOverlay(hideOverlay); - } - } - } -} \ No newline at end of file diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/breakhandler/BreakHandlerScript.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/breakhandler/BreakHandlerScript.java deleted file mode 100644 index a1fc03df3bc..00000000000 --- a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/breakhandler/BreakHandlerScript.java +++ /dev/null @@ -1,797 +0,0 @@ -package net.runelite.client.plugins.microbot.breakhandler; -import lombok.extern.slf4j.Slf4j; -import net.runelite.api.Constants; -import net.runelite.client.plugins.microbot.Microbot; -import net.runelite.client.plugins.microbot.Script; -import net.runelite.client.plugins.microbot.pluginscheduler.util.SchedulerPluginUtil; -import net.runelite.client.plugins.microbot.util.antiban.Rs2AntibanSettings; -import net.runelite.client.plugins.microbot.util.events.PluginPauseEvent; -import net.runelite.client.plugins.microbot.util.math.Rs2Random; -import net.runelite.client.plugins.microbot.util.player.Rs2Player; -import net.runelite.client.plugins.microbot.util.security.Login; -import net.runelite.client.plugins.microbot.util.walker.Rs2Walker; -import net.runelite.client.ui.ClientUI; -import net.runelite.http.api.worlds.WorldRegion; -import java.time.Duration; -import java.time.Instant; -import java.util.ArrayList; -import java.util.List; -import java.util.Random; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.atomic.AtomicBoolean; -import java.util.concurrent.atomic.AtomicInteger; -import java.util.concurrent.atomic.AtomicReference; -/** - * Enhanced BreakHandlerScript with state-based break management for reliable automation. - * - * This script provides comprehensive break handling with proper state transitions, combat/interaction - * monitoring, and reliable login/logout sequences. It prevents interruption of critical activities - * and ensures safe break execution. - * - * Key Features: - * - State-based break management with proper transitions - * - Combat and interaction detection before pausing scripts - * - Reliable logout/login sequences with retry mechanisms - * - Integration with micro-break antiban system - * - Lock state management for preventing breaks during critical operations - * - Play schedule enforcement with automatic logout - * - Configurable retry delays and timeouts - * - * State Flow: - * WAITING_FOR_BREAK -> BREAK_REQUESTED -> INITIATING_BREAK -> LOGOUT_REQUESTED -> - * LOGGED_OUT -> LOGIN_REQUESTED -> LOGGING_IN -> BREAK_ENDING -> WAITING_FOR_BREAK - * - * Micro breaks follow: WAITING_FOR_BREAK -> BREAK_REQUESTED -> MICRO_BREAK_ACTIVE -> BREAK_ENDING - * - * @version 2.0.0 - */ -@Slf4j -public class BreakHandlerScript extends Script { - public static String version = "2.0.0"; - - // Constants for configuration and timing - private static final int SCHEDULER_INTERVAL_MS = Constants.GAME_TICK_LENGTH; - private static final int MINUTES_TO_SECONDS = 60; - - // Configuration-dependent timing values (accessed through helper methods) - private int getCombatCheckIntervalMs() { - return config.combatCheckInterval() * 1000; - } - - private int getLogoutRetryDelayMs() { - return config.logoutRetryDelay() * 1000; - } - - private int getLoginRetryDelayMs() { - return config.loginRetryDelay() * 1000; - } - - private int getMaxLogoutRetries() { - return config.maxLogoutRetries(); - } - - private int getMaxLoginRetries() { - return config.maxLoginRetries(); - } - - private int getSafeConditionTimeoutMs() { - return config.safeConditionTimeout() * 60 * 1000; // Convert minutes to milliseconds - } - - // Core break timing variables - public static int breakIn = -1; - public static int breakDuration = -1; - public static Duration setBreakDurationTime = Duration.ZERO; - public static int totalBreaks = 0; - - // State management - Thread-safe using atomic references - private static final AtomicReference currentState = new AtomicReference<>(BreakHandlerState.WAITING_FOR_BREAK); - private static final AtomicReference stateChangeTime = new AtomicReference<>(Instant.now()); - private static final AtomicInteger retryCount = new AtomicInteger(0); - private static Instant lastCombatCheckTime = Instant.now(); - private static Instant safeConditionWaitStartTime = null; - - // Lock state management - public static AtomicBoolean lockState = new AtomicBoolean(false); - - /** - * Sets the manual lock state and logs the change. - * When locked, breaks are prevented from starting. - */ - public static void setLockState(boolean state) { - boolean currentState = BreakHandlerScript.lockState.get(); - if (currentState != state) { - BreakHandlerScript.lockState.set(state); - log.info("Break handler lock state changed: {} -> {}", currentState, state); - } - } - - // UI and configuration - private String originalWindowTitle = ""; - private BreakHandlerConfig config; - - /** - * Checks if a break is currently active (any break state except waiting). - */ - public static boolean isBreakActive() { - return currentState.get() != BreakHandlerState.WAITING_FOR_BREAK; - } - - /** - * Checks if a micro break is currently active. - */ - public static boolean isMicroBreakActive() { - BreakHandlerState state = currentState.get(); - return state == BreakHandlerState.MICRO_BREAK_ACTIVE || - (Rs2AntibanSettings.takeMicroBreaks && Rs2AntibanSettings.microBreakActive); - } - - /** - * Gets the current break handler state. - */ - public static BreakHandlerState getCurrentState() { - return currentState.get(); - } - - /** - * Formats a duration with header text. - */ - public static String formatDuration(Duration duration, String header) { - return String.format(header + " %s", formatDuration(duration)); - } - - /** - * Formats a duration into HH:MM:SS format. - */ - public static String formatDuration(Duration duration) { - if (duration == null || duration.isNegative() || duration.isZero()) { - return "00:00:00"; - } - long hours = duration.toHours(); - long minutes = duration.toMinutes() % 60; - long seconds = duration.getSeconds() % 60; - return String.format("%02d:%02d:%02d", hours, minutes, seconds); - } - - /** - * Main entry point for the break handler script. - */ - public boolean run(BreakHandlerConfig config) { - this.config = config; - originalWindowTitle = ClientUI.getFrame().getTitle(); - // Initialize state and timing - currentState.set(BreakHandlerState.WAITING_FOR_BREAK); - stateChangeTime.set(Instant.now()); - retryCount.set(0); - initializeNextBreakTimer(); - mainScheduledFuture = scheduledExecutorService.scheduleWithFixedDelay(() -> { - try { - super.run(); - processBreakHandlerStateMachine(); - } catch (Exception ex) { - log.error("Error in break handler main loop", ex); - } - }, 0, SCHEDULER_INTERVAL_MS, TimeUnit.MILLISECONDS); - - return true; - } - - /** - * Main state machine processor - handles all break-related state transitions. - */ - private void processBreakHandlerStateMachine() { - // Handle immediate user config toggles first - if (handleConfigToggles()) { - return; - } - // Process current state - BreakHandlerState state = currentState.get(); - switch (state) { - case WAITING_FOR_BREAK: - handleWaitingForBreakState(); - break; - case BREAK_REQUESTED: - handleBreakRequestedState(); - break; - case INITIATING_BREAK: - handleInitiatingBreakState(); - break; - case LOGOUT_REQUESTED: - handleLogoutRequestedState(); - break; - case LOGGED_OUT: - handleLoggedOutState(); - break; - case MICRO_BREAK_ACTIVE: - handleMicroBreakActiveState(); - break; - case LOGIN_REQUESTED: - handleLoginRequestedState(); - break; - case LOGGING_IN: - handleLoggingInState(); - break; - case BREAK_ENDING: - handleBreakEndingState(); - break; - } - - // Update UI regardless of state - updateBreakTimers(); - updateWindowTitle(); - } - - /** - * Handles immediate config toggle requests (breakNow, breakEndNow). - */ - private boolean handleConfigToggles() { - BreakHandlerState state = currentState.get(); - - if (config.breakNow() && state == BreakHandlerState.WAITING_FOR_BREAK && !isLockState()) { - log.info("Manual break requested"); - transitionToState(BreakHandlerState.BREAK_REQUESTED); - resetConfigToggles(); - return true; - } - - if (config.breakEndNow() && isBreakActive() && state != BreakHandlerState.BREAK_ENDING && state != BreakHandlerState.LOGGING_IN) { - log.info("Manual break end requested"); - if (state == BreakHandlerState.LOGGED_OUT || state == BreakHandlerState.MICRO_BREAK_ACTIVE) { - if (state == BreakHandlerState.LOGGED_OUT){ - transitionToState(BreakHandlerState.LOGGING_IN); - }else if (state == BreakHandlerState.MICRO_BREAK_ACTIVE) { - transitionToState(BreakHandlerState.BREAK_ENDING); - } - resetConfigToggles(); - return true; - } - } - - return false; - } - - /** - * State: WAITING_FOR_BREAK - * Normal operation - counting down to next break and checking for break conditions. - */ - private void handleWaitingForBreakState() { - // Handle play schedule logic - if (config.playSchedule().isOutsideSchedule() && config.usePlaySchedule() && !isLockState()) { - log.info("Outside play schedule, requesting break"); - transitionToState(BreakHandlerState.BREAK_REQUESTED); - return; - } - - // Check for normal break conditions - boolean normalBreakTime = breakIn <= 0 && !isLockState(); - boolean microBreakTime = Rs2AntibanSettings.microBreakActive && !isLockState(); - - if (normalBreakTime || microBreakTime) { - log.info("Break time reached - Normal: {}, Micro: {}", normalBreakTime, microBreakTime); - transitionToState(BreakHandlerState.BREAK_REQUESTED); - } - } - - /** - * State: BREAK_REQUESTED - * Break should start but waiting for safe conditions (not in combat/interacting). - */ - private void handleBreakRequestedState() { - // Check for timeout on waiting for safe conditions - if (safeConditionWaitStartTime != null) { - long waitTime = Duration.between(safeConditionWaitStartTime, Instant.now()).toMillis(); - if (waitTime > getSafeConditionTimeoutMs()) { - // Check if client shutdown is configured for timeout scenarios - if (config.shutdownClient()) { - log.warn("Timeout waiting for safe conditions with client shutdown enabled - shutting down RuneLite client"); - // Pause all scripts before shutdown - Microbot.pauseAllScripts.compareAndSet(false, true); - PluginPauseEvent.setPaused(true); - handleClientShutdown(); - return; - } else { - log.warn("Timeout waiting for safe conditions, skipping this break and waiting for next one"); - // Skip this break and wait for the next one - initializeNextBreakTimer(); - transitionToState(BreakHandlerState.WAITING_FOR_BREAK); - return; - } - } - } else { - safeConditionWaitStartTime = Instant.now(); - } - - // Check for safe conditions periodically - Instant now = Instant.now(); - if (Duration.between(lastCombatCheckTime, now).toMillis() >= getCombatCheckIntervalMs()) { - lastCombatCheckTime = now; - - if (isSafeToBreak()) { - log.info("Safe conditions met, initiating break"); - transitionToState(BreakHandlerState.INITIATING_BREAK); - } else { - log.debug("Waiting for safe conditions - Combat: {}, Interacting: {}", - Rs2Player.isInCombat(), Rs2Player.isInteracting()); - } - } - } - - /** - * State: INITIATING_BREAK - * Safe to pause scripts, starting break process. - */ - private void handleInitiatingBreakState() { - log.info("Initiating break - pausing all scripts"); - - // Pause all scripts - Microbot.pauseAllScripts.compareAndSet(false, true); - PluginPauseEvent.setPaused(true); - Rs2Walker.setTarget(null); - // Determine next state based on break type - if (Rs2AntibanSettings.microBreakActive && (config.onlyMicroBreaks() || !shouldLogout())) { - setBreakDuration(); - transitionToState(BreakHandlerState.MICRO_BREAK_ACTIVE); - } else { - transitionToState(BreakHandlerState.LOGOUT_REQUESTED); - } - } - - /** - * Handles client shutdown when configured to shutdown the entire client during breaks. - * This will completely close the RuneLite client. - */ - private void handleClientShutdown() { - try { - log.info("Shutting down RuneLite client due to break handler configuration"); - - // Update break statistics before shutdown - updateBreakStatistics(); - - // Clean shutdown of the client - ClientUI.getFrame().setTitle(originalWindowTitle + " - Shutting Down"); - if (scheduledFuture != null && !scheduledFuture.isDone()) { - scheduledFuture.cancel(true); - } - // Schedule shutdown to allow logging to complete - scheduledFuture = scheduledExecutorService.schedule(() -> { - System.exit(0); - }, 1000, TimeUnit.MILLISECONDS); - - } catch (Exception ex) { - log.error("Error during client shutdown", ex); - // Force shutdown if graceful shutdown fails - System.exit(1); - } - } - - /** - * State: LOGOUT_REQUESTED - * Attempting to logout, with retry logic. - */ - private void handleLogoutRequestedState() { - int currentRetryCount = retryCount.get(); - Instant currentStateChangeTime = stateChangeTime.get(); - - if (currentRetryCount >= getMaxLogoutRetries()) { - log.warn("Max logout retries reached, continuing with logged-in break"); - setBreakDuration(); - transitionToState(BreakHandlerState.MICRO_BREAK_ACTIVE); - return; - } - - // Check if enough time has passed for retry - if (currentRetryCount > 0 && Duration.between(currentStateChangeTime, Instant.now()).toMillis() < getLogoutRetryDelayMs()) { - long remainingTime = getLogoutRetryDelayMs() - Duration.between(currentStateChangeTime, Instant.now()).toMillis(); - log.debug("Waiting for next logout retry ({} ms remaining)", remainingTime); - return; - } - - log.info("Attempting logout (attempt {}/{})", currentRetryCount + 1, getMaxLogoutRetries()); - - try { - Rs2Player.logout(); - // Don't immediately transition - wait for next cycle to check if logout was successful - retryCount.incrementAndGet(); - stateChangeTime.set(Instant.now()); - if (scheduledFuture != null && !scheduledFuture.isDone()) { - scheduledFuture.cancel(true); - } - // Check on next cycle if we successfully logged out - scheduledFuture = scheduledExecutorService.schedule(() -> { - if (!Microbot.isLoggedIn()) { - log.info("Logout successful"); - setBreakDuration(); - transitionToState(BreakHandlerState.LOGGED_OUT); - } - }, 2000, TimeUnit.MILLISECONDS); - - } catch (Exception ex) { - log.error("Error during logout attempt", ex); - retryCount.incrementAndGet(); - stateChangeTime.set(Instant.now()); - } - } - - /** - * State: LOGGED_OUT - * Successfully logged out, waiting for break duration to complete. - */ - private void handleLoggedOutState() { - // Check if break should end - if (breakDuration <= 0 || config.breakEndNow()) { - log.info("Break duration completed, requesting login"); - transitionToState(BreakHandlerState.LOGIN_REQUESTED); - } - } - - /** - * State: MICRO_BREAK_ACTIVE - * In micro break state (no logout), waiting for duration to complete. - */ - private void handleMicroBreakActiveState() { - // Check if micro break should end - if ((breakDuration <= 0 && !Rs2AntibanSettings.microBreakActive) || config.breakEndNow()) { - log.info("Micro break completed"); - transitionToState(BreakHandlerState.BREAK_ENDING); - } - } - - /** - * State: LOGIN_REQUESTED - * Break ended, attempting to login. - */ - private void handleLoginRequestedState() { - if (Microbot.isLoggedIn()) { - log.info("Already logged in, proceeding to break ending"); - transitionToState(BreakHandlerState.BREAK_ENDING); - return; - } - - log.info("Attempting login"); - try { - // Use the Login utility class to handle login - if (Login.activeProfile != null) { - if (config.useRandomWorld()) { - // Get random world with region filter for break handler - int randomWorld = getRandomWorldWithRegionFilter(config); - new Login(randomWorld); - } else { - new Login(); - } - } else { - // If no active profile, use default login - if (config.useRandomWorld()) { - // Get random world with region filter for break handler - int randomWorld = getRandomWorldWithRegionFilter(config); - new Login(randomWorld); - } else { - new Login(); - } - } - transitionToState(BreakHandlerState.LOGGING_IN); - } catch (Exception ex) { - log.error("Error initiating login", ex); - // Retry login request after delay - scheduledFuture = scheduledExecutorService.schedule(() -> { - if (currentState.get() == BreakHandlerState.LOGIN_REQUESTED) { - retryCount.incrementAndGet(); - } - }, getLoginRetryDelayMs(), TimeUnit.MILLISECONDS); - } - } - - /** - * State: LOGGING_IN - * Currently attempting to log in, with retry logic. - */ - private void handleLoggingInState() { - if (Microbot.isLoggedIn()) { - log.info("Login successful"); - transitionToState(BreakHandlerState.BREAK_ENDING); - return; - } - - // Get current values atomically - int currentRetryCount = retryCount.get(); - Instant currentStateChangeTime = stateChangeTime.get(); - - // Check for timeout or max retries - long loginTime = Duration.between(currentStateChangeTime, Instant.now()).toMillis(); - if (loginTime > (getLoginRetryDelayMs() * (currentRetryCount + 1)) && currentRetryCount < getMaxLoginRetries()) { - log.info("Login retry {} of {}", currentRetryCount + 1, getMaxLoginRetries()); - retryCount.incrementAndGet(); - transitionToState(BreakHandlerState.LOGIN_REQUESTED); - } else if (currentRetryCount >= getMaxLoginRetries()) { - log.warn("Max login retries reached, staying logged out"); - // Stay in logged out state and wait for manual intervention or next attempt - setBreakDuration(); // Reset break duration to prevent immediate retry - transitionToState(BreakHandlerState.LOGGED_OUT); - } - } - - /** - * State: BREAK_ENDING - * Break ended successfully, cleaning up and resuming normal operation. - */ - private void handleBreakEndingState() { - log.info("Break ending, resuming normal operation"); - - // Resume scripts and reset state - resumeFromBreak(); - - // Handle world switching if configured - handleWorldSwitching(); - - // Update statistics and UI - updateBreakStatistics(); - resetWindowTitle(); - - // Clean up break state - cleanupBreakState(); - - // Reset config toggles - resetConfigToggles(); - - // Return to waiting state - initializeNextBreakTimer(); - transitionToState(BreakHandlerState.WAITING_FOR_BREAK); - } - - /** - * Transitions to a new state and resets relevant counters. - * This method is thread-safe and can be called from any thread. - */ - private static void transitionToState(BreakHandlerState newState) { - BreakHandlerState oldState = currentState.get(); - if (oldState != newState) { - log.debug("State transition: {} -> {}", oldState, newState); - currentState.set(newState); - stateChangeTime.set(Instant.now()); - retryCount.set(0); - - // Reset safe condition wait time when leaving BREAK_REQUESTED - if (newState != BreakHandlerState.BREAK_REQUESTED) { - safeConditionWaitStartTime = null; - } - } - } - - /** - * Checks if it's safe to break (not in combat, not interacting). - */ - private boolean isSafeToBreak() { - return !Rs2Player.isInCombat() && !Rs2Player.isInteracting(); - } - - /** - * Determines if logout should occur based on configuration and conditions. - */ - private boolean shouldLogout() { - return isOutsidePlaySchedule() || config.logoutAfterBreak(); - } - - /** - * Initializes the timer for the next break. - */ - private void initializeNextBreakTimer() { - breakIn = Rs2Random.between( - config.timeUntilBreakStart() * MINUTES_TO_SECONDS, - config.timeUntilBreakEnd() * MINUTES_TO_SECONDS - ); - log.debug("Next break in {} seconds", breakIn); - } - - /** - * Sets the break duration based on configuration and break type. - */ - private void setBreakDuration() { - if (Rs2AntibanSettings.microBreakActive) { - // Micro break duration - use proper range and convert minutes to seconds - breakDuration = Rs2Random.between( - Rs2AntibanSettings.microBreakDurationLow * MINUTES_TO_SECONDS, - Rs2AntibanSettings.microBreakDurationHigh * MINUTES_TO_SECONDS - ); - setBreakDurationTime = Duration.ofSeconds(breakDuration); - log.debug("Micro break duration set to {} seconds ({} minutes)", - breakDuration, breakDuration / MINUTES_TO_SECONDS); - } else if (isOutsidePlaySchedule()) { - // For play schedule, break until next play time - Duration timeUntilPlaySchedule = config.playSchedule().timeUntilNextSchedule(); - breakDuration = (int) timeUntilPlaySchedule.toSeconds(); - setBreakDurationTime = Duration.ofSeconds(breakDuration); - log.info("Play schedule break duration set to {} seconds", breakDuration); - } else { - // Normal break duration - breakDuration = Rs2Random.between( - config.breakDurationStart() * MINUTES_TO_SECONDS, - config.breakDurationEnd() * MINUTES_TO_SECONDS - ); - setBreakDurationTime = Duration.ofSeconds(breakDuration); - log.debug("Normal break duration set to {} seconds", breakDuration); - } - } - - /** - * Resumes scripts and resets break timing. - */ - private void resumeFromBreak() { - Microbot.pauseAllScripts.compareAndSet(true, false); - PluginPauseEvent.setPaused(false); - Rs2AntibanSettings.microBreakActive = false; - } - - private List getAllowedRegions(BreakHandlerConfig config) { - List allowedRegions = new ArrayList<>(); - - if (config.allowUK()) { - allowedRegions.add(WorldRegion.UNITED_KINGDOM); - } - if (config.allowUS()) { - allowedRegions.add(WorldRegion.UNITED_STATES_OF_AMERICA); - } - if (config.allowGermany()) { - allowedRegions.add(WorldRegion.GERMANY); - } - if (config.allowAustralia()) { - allowedRegions.add(WorldRegion.AUSTRALIA); - } - - return allowedRegions; - } - - private int getRandomWorldWithRegionFilter(BreakHandlerConfig config) { - List allowedRegions = getAllowedRegions(config); - - // Use automatic member detection from profiles - boolean isMember = Rs2Player.isMember(); - - if (allowedRegions.isEmpty()) { - // If no regions allowed, use default method - return Login.getRandomWorld(isMember); - } - - // Pick a random region from allowed regions - Random random = new Random(); - WorldRegion selectedRegion = allowedRegions.get(random.nextInt(allowedRegions.size())); - - return Login.getRandomWorld(isMember, selectedRegion); - } - - /** - * Handles world switching based on configuration. - */ - private void handleWorldSwitching() { - if (config.useRandomWorld()) { - try { - int randomWorld = getRandomWorldWithRegionFilter(config); - Microbot.hopToWorld(randomWorld); - } catch (Exception ex) { - // Silent error handling - } - } - } - - /** - * Updates break statistics. - */ - private void updateBreakStatistics() { - totalBreaks++; - log.info("Break completed. Total breaks: {}", totalBreaks); - } - - /** - * Resets window title to original. - */ - private void resetWindowTitle() { - ClientUI.getFrame().setTitle(originalWindowTitle); - } - - /** - * Cleans up break-related state variables. - */ - private void cleanupBreakState() { - breakDuration = -1; - setBreakDurationTime = Duration.ZERO; - } - - /** - * Resets config toggles to false after processing. - */ - private void resetConfigToggles() { - // Note: These will reset automatically due to the config system - // This method exists for potential future toggle handling - if (Microbot.getConfigManager() == null) { - return; - } - Microbot.getConfigManager().setConfiguration(BreakHandlerConfig.configGroup, "breakNow", false); - Microbot.getConfigManager().setConfiguration(BreakHandlerConfig.configGroup, "breakEndNow", false); - } - - /** - * Updates break-related timers and duration calculations. - */ - private void updateBreakTimers() { - BreakHandlerState state = currentState.get(); - - // Count down to next break (only in waiting state and when logged in) - if (state == BreakHandlerState.WAITING_FOR_BREAK && breakIn >= 0 && Microbot.isLoggedIn()) { - breakIn--; - } - - // Count down active break duration - if ((state == BreakHandlerState.LOGGED_OUT || state == BreakHandlerState.MICRO_BREAK_ACTIVE) - && breakDuration >= 0) { - breakDuration--; - } - } - - /** - * Updates window title based on current state and break information. - */ - private void updateWindowTitle() { - BreakHandlerState state = currentState.get(); - - if (state == BreakHandlerState.LOGGED_OUT || state == BreakHandlerState.MICRO_BREAK_ACTIVE) { - String breakType = state == BreakHandlerState.MICRO_BREAK_ACTIVE ? "Micro Break" : "Break"; - ClientUI.getFrame().setTitle(originalWindowTitle + " - " + breakType + ": " + - formatDuration(Duration.ofSeconds(Math.max(0, breakDuration)))); - } else if (isBreakActive()) { - ClientUI.getFrame().setTitle(originalWindowTitle + " - " + state.toString().replace("_", " ")); - } - } - - /** - * Checks if currently outside play schedule hours. - */ - private boolean isOutsidePlaySchedule() { - return config.playSchedule().isOutsideSchedule() && config.usePlaySchedule(); - } - - @Override - public void shutdown() { - BreakHandlerState state = currentState.get(); - log.info("Break handler shutting down. Current state: {}", state); - - // If we're in a break state, try to clean up gracefully - if (state == BreakHandlerState.LOGGED_OUT) { - log.info("Attempting to resume from logged out state"); - transitionToState(BreakHandlerState.LOGIN_REQUESTED); - } else if (isBreakActive()) { - log.info("Attempting to end break gracefully"); - transitionToState(BreakHandlerState.BREAK_ENDING); - } - - resetWindowTitle(); - super.shutdown(); - } - - /** - * Resets the break handler to initial state. - */ - public void reset() { - log.info("Resetting break handler"); - resetBreakState(); - transitionToState(BreakHandlerState.WAITING_FOR_BREAK); - initializeNextBreakTimer(); - } - - /** - * Centralized method to reset all break-related state. - */ - private void resetBreakState() { - breakIn = -1; - breakDuration = -1; - setBreakDurationTime = Duration.ZERO; - retryCount.set(0); - safeConditionWaitStartTime = null; - lastCombatCheckTime = Instant.now(); - } - - /** - * Checks if the break handler is currently in a locked state. - * This includes both the manual lock state and any locked conditions from schedulable plugins. - */ - public static boolean isLockState() { - return lockState.get() || SchedulerPluginUtil.hasLockedSchedulablePlugins(); - } -} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/breakhandler/BreakHandlerState.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/breakhandler/BreakHandlerState.java deleted file mode 100644 index d9386b494bf..00000000000 --- a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/breakhandler/BreakHandlerState.java +++ /dev/null @@ -1,62 +0,0 @@ -package net.runelite.client.plugins.microbot.breakhandler; - -/** - * Enumeration representing the various states of the BreakHandler system. - * This state machine ensures reliable break transitions and prevents interruption - * of critical game activities. - */ -public enum BreakHandlerState { - /** - * Normal operation state - counting down to the next break. - * Scripts are running normally. - */ - WAITING_FOR_BREAK, - - /** - * Break has been requested but waiting for safe conditions. - * Monitoring for combat/interaction to end before pausing scripts. - */ - BREAK_REQUESTED, - - /** - * Safe conditions met, initiating break by pausing scripts. - * Brief transition state. - */ - INITIATING_BREAK, - - /** - * Logout has been requested and is being attempted. - * May retry logout if unsuccessful. - */ - LOGOUT_REQUESTED, - - /** - * Successfully logged out and in break state. - * Waiting for break duration to complete. - */ - LOGGED_OUT, - - /** - * Micro break is active - scripts paused but no logout. - * Used for short antiban breaks. - */ - MICRO_BREAK_ACTIVE, - - /** - * Break duration completed, requesting login. - * Attempting to log back in. - */ - LOGIN_REQUESTED, - - /** - * Currently attempting to log in. - * May retry if unsuccessful. - */ - LOGGING_IN, - - /** - * Break ended successfully, resuming normal operation. - * Brief transition state before returning to WAITING_FOR_BREAK. - */ - BREAK_ENDING -}