Skip to main content

Break Handler

Verification boundary

This page documents the committed source. Treat revision-sensitive RuneLite UI, packet, or in-game outcomes as pending live-client verification unless the page records direct evidence.

Packet Utils owns the Break Handler runtime and its tab in the shared n3 sidebar. The repository retains the existing n3breakhandler configuration group. Break handling remains disabled by default and stays neutral until the user selects Enable Break Handler in Packet Utils. Active automation remains visible, so enabling it mid-run begins break scheduling without restarting the automation. The runtime ports PiggyPlugins' ChinBreakHandler onto the n3 surfaces.

Architecture

  • PacketUtilsPlugin - lifecycle, shared navigation, and the enable gate for Break Handler.
  • BreakHandlerPlugin - Packet Utils-owned login-screen/logout state machine and auto bank pin runtime.
  • BreakHandler - @Singleton RxJava3 service bus; registry of consumer plugins, planned/active breaks, and break statistics. The shared coordination point other plugins inject.
  • State - state-machine enum (NULL, LOGIN_SCREEN, INVENTORY, RESUME, LOGOUT*).
  • OptionsConfig / NullConfig - RuneLite config interfaces for the Options tab.
  • ui/ - BreakHandlerPanel (tabbed: Plugins / Accounts / Options), BreakHandlerPluginPanel (per-plugin spinners + AFK/Logout), BreakHandlerStatusPanel (live countdown), BreakHandlerAccountPanel (login source), LoginMode.
  • util/ - ConfigPanel (generic RuneLite config renderer), spinners/formatters, OnOffToggleButton, IntRandomNumberGenerator, SwingUtilExtended.syncExec.

Reactive bus

BreakHandler exposes RxJava3 Observables (PublishSubject.hide()) for plugin registration, active plugins, planned breaks, active breaks, the current break, extra data, and login/logout actions. Panels and the plugin subscribe to drive their UI and the state machine. currentActiveBreaksSubject carries a Map.Entry<Plugin, Instant> (AbstractMap.SimpleImmutableEntry) - the n3 port's replacement for org.apache.commons.lang3.tuple.Pair.

Consumer API

Another plugin injects BreakHandler and calls:

  • registerPlugin(plugin) / unregisterPlugin(plugin) - appear in the panel.
  • startPlugin(plugin) / stopPlugin(plugin) - begin/stop tracking runtime + breaks.
  • isBreakActive(plugin) / shouldBreak(plugin) - gate work loops.
  • setExtraData(plugin, key, value) - surface live status in the panel.

The plugin schedules breaks itself from the per-plugin threshold spinners. A consumer only needs to register, start, and pause its work while a break remains active.

Full automation plugins must integrate with BreakHandler as an active-only runtime requirement:

  • Register with registerPlugin(this) on plugin startup and unregisterPlugin(this) on shutdown.
  • Call startPlugin(this) only while automation runs actively, and stopPlugin(this) when the plugin sits idle, disables, completes, halts, or shuts down.
  • Before issuing gameplay actions, check shouldBreak(this) and isBreakActive(this). When a planned break triggers, call startBreak(this), release any input lock, and skip the action tick.

The required full automation plugins include Market Alcher, Power Skiller, GE Buyer, GE Flipper, AIO Fighter, Auto Looter, Tutorial Island, Guardians of the Rift, Mule Orchestrator, and Bank Stander. Dialogue Helper, Walk Assistant, Questing Assistant, Combat Awareness, and Inventory Setups act as QoL/helper plugins and hold intentional exemptions from this requirement. Registered suite/support plugins such as Packet Utils, Profiles, Code Console, Break Handler, and Agent Server hold separate classification because they omit full automation loops.

State machine

onGameTick drives logout (ESC → logout tab → logout button via MousePackets/WidgetPackets) and login-screen re-entry through BlockingEventActions.continueWelcomeScreen(). This resolves visible legacy or Jagex welcome-screen click targets without hard-coded child IDs in Break Handler. seconds() (1 Hz RxJava interval) performs re-login only when all active breaks elapse and the client rests on the login screen. Reconnect attempts require a five-second initial idle and then use jittered bounded backoff based on 15-second, 60-second, and five-minute stages. Backoff resets only after establishing a stable logged-in state with the welcome screen closed. Auto bank pin types the PIN one digit per tick against widget (213, 0) and blocks key presses via VarClientInt.BLOCK_KEYPRESS.

Break anti-idle mouse events select a center-biased point within the current live canvas. They are suppressed when the canvas has no usable area and never use the historical 0,0 coordinate.

Login sources (Accounts tab)

LoginModeRe-login behavior
MANUALUsername/password/bank-pin entered directly in the tab (n3breakhandler config).
PROFILESReads the n3 Profiles typed ProfileStore (see below). Enabled only when the user configures an n3 Profiles unlock password.
LAUNCHERJagex Launcher session already present; sets GameState.LOGGING_IN directly.

Profiles integration (Part C)

When the user selects LoginMode.PROFILES, the break handler reads the unified com.n3plugins.n3Profiles.ProfileStore (decrypted with the configured n3 Profiles unlock password), rather than a local credential cache:

  • The Accounts dropdown lists StoredProfile.getLabel() for every stored profile.
  • seconds() re-login looks up the selected label:
    • LEGACYProfileLoginService.applyLegacyProfile(login, password, false) then GameState.LOGGING_IN.
    • JAGEXProfileLoginService.applyJagexProfile(sessionId, characterId, displayName) then GameState.LOGGING_IN.
  • BreakHandler.getBankPin(ConfigManager) returns the selected LEGACY profile's 4-digit pin. It falls back to the manual bank-pin config when the profile lacks a usable pin or the store remains unavailable.

The system injects ProfileStore (constructible from ConfigManager alone), so the break handler reads the same encrypted blob without cross-plugin singleton sharing.

Configuration (Options tab)

stopAfterBreaks, autoBankPin, autoLoginOnDisconnect, avoidWorldsPlayerCount, avoidWorldsNumbers, and the Hopping section (hop-after-break, american, united-kingdom, german, australian). Per-plugin: <plugin>-thresholdfrom/to, <plugin>-breakfrom/to, <plugin>-enabled, <plugin>-logout.

Testing

.\gradlew.bat test --tests com.n3plugins.breakhandler.* --console plain
  • LoginModeTest - parse (case-insensitive, null, unknown).
  • IntRandomNumberGeneratorTest - inclusive range, singleton range.
  • BreakHandlerTest - getBankPin (manual, PROFILES fallback, null guards), getOrDefaultFrom/To, plugin registry, shouldBreak, startBreak counting.
  • AutomationBreakHandlerRegistrationTest - source-level guardrail for required full automation plugin registration, active lifecycle calls, break gating, helper-plugin exemptions, and registered support-plugin classification.

Client-dependent paths (state machine, packet sends, world hopping) lack unit tests - N3Client evaluates as null in the test JVM. See profiles.md for the surviving Packet Utils Profiles tab and store.

Live validation (pending)

Logout/login state machine on rev240, auto bank pin entry, world hopping filters, LoginMode.PROFILES re-login through the surviving n3 Profiles store for both LEGACY and JAGEX profiles end-to-end.

Break Handler Integration Flow

The Break Handler manages breaks using an RxJava3 event bus. Active full automation plugins monitor this status to pause execution, and the Break Handler executes logouts/logins.


State Machine & Re-Login Backoff Flow