+ * This class extends the {@code Overlay} class from RuneLite's API and leverages {@code ProgressPieComponent} + * to render a circular timer. The timer visually decreases over time, providing an indication of when the + * next action will be performed. It is designed to be unobtrusive and provides important feedback for + * antiban behaviors. + *
+ * + *+ * The {@code AntibanOverlay} class does not need to be explicitly initialized or called. + * It is automatically integrated into the overlay system and activated when the anti-ban action cooldown + * is active, as determined by the {@code Rs2AntibanSettings}. + *
+ * + *+ * This class works in conjunction with {@code Rs2Antiban} to monitor the player's activity and to display the + * appropriate overlay based on the current status of the anti-ban system. It draws a circular timer around the + * player character, providing a visual cue for the current cooldown. + *
+ * + *+ * // This class is automatically invoked by the overlay system when the action cooldown is active. + * // The following example describes its integration in the larger system: + * + * // 1. The anti-ban system detects an action cooldown. + * Rs2Antiban.actionCooldown(); + * + * // 2. If the cooldown is active, the overlay renders the progress pie around the player. + * AntibanOverlay.render(graphics); + *+ * + *
getCanvasTextLocation(Graphics2D graphics, Actor actor)
: Calculates the screen location of the player,
+ * used for positioning the overlay relative to the player's character.drawTimerPieOverlay(Graphics2D graphics)
: Renders the progress pie overlay, representing the remaining
+ * cooldown time as a gradually decreasing pie chart.render(Graphics2D graphics)
: The main render loop that checks if an action cooldown is active and draws
+ * the overlay if necessary.+ * The rendering process begins with checking if the anti-ban cooldown is active. If active, the overlay retrieves + * the player's screen location and calculates the remaining cooldown time. The progress pie is then drawn at the + * calculated location, visually indicating the time left until the next action. + *
+ * + *+ * The color of the overlay and the size of the timer can be customized by adjusting the constants + * {@code PUBLIC_TIMER_COLOR}, and {@code TIMER_OVERLAY_DIAMETER}. + *
+ * + *+ * This plugin ensures that the bot behaves in a more human-like manner to avoid detection by using various + * anti-ban strategies. These strategies include simulating breaks, adjusting activity levels, and mimicking + * attention span variations. The plugin tracks user activity and game state to dynamically adjust bot behavior. + *
+ * + *
+ * The AntibanPlugin
works silently in the background to adjust the bot's behavior during runtime.
+ * Users do not need to manually interact with this plugin, as it is automatically integrated into the bot framework.
+ *
+ * The plugin monitors in-game actions, such as cooking, mining, and skill changes, to adjust its anti-ban strategy + * accordingly. It also manages the simulation of breaks, cooldowns, and play style variations to mimic human behavior + * and avoid detection. + *
+ * + *+ * Each method in this class corresponds to a specific activity (e.g., combat, runecrafting, construction) and + * adjusts various settings to create a more realistic and undetectable experience for the bot. + * These setups adjust mouse movement patterns, simulate breaks, introduce variability, and more. + *
+ * + *+ * These methods are intended to be called before executing specific game activities to ensure that the antiban measures + * are properly configured for the task. The configurations can be adjusted to suit different activities or playstyles + * by enabling or disabling certain features like profile switching or dynamic intensity. + *
+ * + *Inside your plugin script class, execute the initialization outside the main loop.
+ *+ * private void initialize() { + * Rs2Antiban.antibanSetupTemplates.applyMiningSetup(); + * } + *+ * + *
applyCombatSetup()
: Configures antiban settings for combat activities.applyRunecraftingSetup()
: Configures antiban settings for runecrafting activities.applyConstructionSetup()
: Configures antiban settings for construction activities.applyAgilitySetup()
: Configures antiban settings for agility tasks.applyHerbloreSetup()
: Configures antiban settings for herblore tasks.applyThievingSetup()
: Configures antiban settings for thieving tasks.applyCraftingSetup()
: Configures antiban settings for crafting tasks.applyFletchingSetup()
: Configures antiban settings for fletching tasks.applyHunterSetup()
: Configures antiban settings for hunter tasks.applyMiningSetup()
: Configures antiban settings for mining tasks.applySmithingSetup()
: Configures antiban settings for smithing tasks.applyFishingSetup()
: Configures antiban settings for fishing tasks.applyCookingSetup()
: Configures antiban settings for cooking tasks.applyFiremakingSetup()
: Configures antiban settings for firemaking tasks.applyWoodcuttingSetup()
: Configures antiban settings for woodcutting tasks.applyFarmingSetup()
: Configures antiban settings for farming tasks.applyGeneralBasicSetup()
: Applies a basic antiban configuration without advanced features.+ * The class uses configurations set in {@code Rs2AntibanSettings} to determine the behavior of the bot + * during activities like woodcutting, mining, cooking, and more. It leverages various methods to simulate + * natural player behaviors, such as random mouse movements and taking breaks. It also integrates with + * specific activity configurations like play style, activity intensity, and categories, which are adjusted + * based on the activity being performed. + *
+ * + *+ * The methods provided in this class are designed to be called during in-game activities to ensure the antiban + * system is engaged and functioning according to the activity being performed. The configurations can be customized + * through {@code Rs2AntibanSettings} to adjust behaviors such as action cooldowns, break chances, and mouse movements. + *
+ * + *+ * // Setting the antiban activity to woodcutting + * Rs2Antiban.setActivity(Activity.GENERAL_WOODCUTTING); + * + * // Triggering an action cooldown based on current settings + * Rs2Antiban.actionCooldown(); + * + * // Rendering the antiban overlay in a panel + * Rs2Antiban.renderAntibanOverlayComponents(panelComponent); + *+ * + *
setActivity(Activity activity)
: Sets the current activity and adjusts antiban settings based on the activity type.setActivityIntensity(ActivityIntensity intensity)
: Sets the intensity level of the current activity.actionCooldown()
: Triggers an action cooldown, potentially adjusting play style and performing random mouse movements.takeMicroBreakByChance()
: Attempts to trigger a micro-break based on a random chance.isWoodcutting()
: Checks if the player is currently performing a woodcutting animation.isMining()
: Checks if the player is currently performing a mining animation.isIdle()
: Checks if the player is currently idle (not performing any animation).renderAntibanOverlayComponents(PanelComponent panelComponent)
: Renders an overlay showing the current antiban status and action cooldown progress.moveMouseOffScreen()
: Moves the mouse off-screen to simulate taking a break.moveMouseRandomly()
: Moves the mouse randomly to simulate natural behavior during gameplay.activateAntiban()
: Activates the antiban system.deactivateAntiban()
: Deactivates the antiban system.resetAntibanSettings()
: Resets all antiban settings to their default values.+ * This method controls the flow for activating the cooldown either with certainty or based on a chance. + * It includes logic to adjust behaviors such as non-linear intervals, behavioral variability, and random mouse movements + * to simulate more human-like actions. + *
+ *+ * Execute this method at any point in your script where you want to trigger an action cooldown. + *
+ *
+ * The cooldown can be triggered directly if actionCooldownChance
is 1.00 (100%),
+ * or by chance if actionCooldownChance
is less than 1.00 (100%). Several features like universal antiban,
+ * non-linear intervals, and play style evolution are configurable through Rs2AntibanSettings
.
+ *
Rs2AntibanSettings.usePlayStyle
is disabled, the cooldown will not be performed.actionCooldownChance
< 1.00 (100%), the cooldown is triggered based on the result of a random dice roll.actionCooldownChance
is 1.00 (100%) or greater, the cooldown is triggered unconditionally.
+ * performActionCooldown()
encapsulates the shared logic for performing the cooldown,
+ * adjusting the play style, and invoking other anti-ban actions like moving the mouse randomly or off-screen.
+ *
+ * This method simulates human-like pauses in the bot's behavior by invoking a micro-break if a randomly generated
+ * value is less than the configured microBreakChance
. When triggered, the break duration is determined
+ * randomly within a specified range and the mouse may be optionally moved off-screen.
+ *
Rs2AntibanSettings.microBreakChance
, the micro-break is activated.Rs2AntibanSettings.microBreakDurationLow
and
+ * Rs2AntibanSettings.microBreakDurationHigh
, in seconds.Rs2AntibanSettings.moveMouseOffScreen
is enabled, the mouse is moved off-screen during the break.Rs2AntibanSettings
must define valid break chance and duration values.Rs2AntibanSettings.microBreakActive
is set to true
if the break is triggered.BreakHandlerScript.breakDuration
is set to a randomly determined value in seconds.
+ * This method populates a PanelComponent
with details regarding the current anti-ban system's state,
+ * activity levels, play styles, and other related information. It is intended for use in providing a visual representation
+ * of the anti-ban system's status during runtime, with debug information shown when enabled.
+ *
Rs2AntibanSettings.devDebug
is enabled, several debug lines will show key anti-ban settings,
+ * such as action cooldown, random intervals, and behavioral variability.Rs2AntibanSettings
+ * and playStyle
.playStyle
and Rs2AntibanSettings
must be properly initialized.panelComponent
must be passed as a valid and non-null component to receive overlay data.
+ * This method should be used within overlay rendering methods, typically in custom overlay classes that extend
+ * OverlayPanel
. For example, in the MotherloadMineOverlay
class, this method is used to
+ * display anti-ban information in the mining overlay. It is invoked within the render(Graphics2D graphics)
+ * method to ensure that the anti-ban status is updated every time the overlay is drawn.
+ *
+ * To integrate this method into a custom overlay: + *
+ *OverlayPanel
or a similar class that supports adding components.Rs2Antiban.renderAntibanOverlayComponents(panelComponent);
within the overlay's
+ * render
method, before or after other components are added, depending on the desired layout.Rs2AntibanSettings
are configured before invoking the method.+ * {@code + * @Override + * public Dimension render(Graphics2D graphics) { + * try { + * panelComponent.setPreferredSize(new Dimension(275, 900)); + * panelComponent.getChildren().add(TitleComponent.builder() + * .text("\uD83E\uDD86 Motherlode Mine \uD83E\uDD86") + * .color(Color.ORANGE) + * .build()); + * + * Rs2Antiban.renderAntibanOverlayComponents(panelComponent); + * addEmptyLine(); + * + * panelComponent.getChildren().add(LineComponent.builder() + * .left("Mining Location: " + MotherloadMineScript.miningSpot.name()) + * .build()); + * + * addEmptyLine(); + * + * panelComponent.getChildren().add(LineComponent.builder() + * .left(status.toString()) + * .right("Version: " + MotherloadMineScript.version) + * .build()); + * } catch (Exception ex) { + * System.out.println(ex.getMessage()); + * } + * return super.render(graphics); + * } + * } + *+ */ + + public static void renderAntibanOverlayComponents(PanelComponent panelComponent) { + final ProgressBarComponent progressBarComponent = new ProgressBarComponent(); + progressBarComponent.setBackgroundColor(Color.DARK_GRAY); + progressBarComponent.setForegroundColor(ColorUtil.fromHex("#cc8400")); + progressBarComponent.setMaximum(0); + progressBarComponent.setMaximum(playStyle.getSecondaryTickInterval()); + progressBarComponent.setValue(TIMEOUT); + progressBarComponent.setLabelDisplayMode(ProgressBarComponent.LabelDisplayMode.TEXT_ONLY); + progressBarComponent.setLeftLabel("0"); + progressBarComponent.setRightLabel(String.valueOf(playStyle.getSecondaryTickInterval())); + progressBarComponent.setCenterLabel(String.valueOf(TIMEOUT)); + + panelComponent.getChildren().add(TitleComponent.builder().text("\uD83E\uDD86 Humanizer \uD83E\uDD86") + .color(Color.ORANGE).build()); + panelComponent.getChildren().add(LineComponent.builder().build()); + panelComponent.getChildren().add(SplitComponent.builder() + .first(LineComponent.builder().left("Activity: " + activity.getMethod()).right(Rs2AntibanSettings.devDebug ? "Dynamic: " + (Rs2AntibanSettings.dynamicActivity ? "✔" : "❌") : "").build()) + .second(LineComponent.builder().left("Category: " + category.getName()).build()).build()); + panelComponent.getChildren().add(LineComponent.builder().build()); + panelComponent.getChildren().add(LineComponent.builder().left("Activity Intensity: " + activityIntensity.getName()).right(Rs2AntibanSettings.devDebug ? "Dynamic: " + (Rs2AntibanSettings.dynamicIntensity ? "✔" : "❌") : "").build()); + if (Rs2AntibanSettings.devDebug) { + panelComponent.getChildren().add(LineComponent.builder().left("isActionCooldownActive: " + (Rs2AntibanSettings.actionCooldownActive ? "✔" : "❌")).build()); + panelComponent.getChildren().add(LineComponent.builder().left("isEnabled: " + (Rs2AntibanSettings.antibanEnabled ? "✔" : "❌")).build()); + panelComponent.getChildren().add(LineComponent.builder().left("useRandomIntervals: " + (Rs2AntibanSettings.randomIntervals ? "✔" : "❌")).build()); + panelComponent.getChildren().add(LineComponent.builder().left("simulateFatigue: " + (Rs2AntibanSettings.simulateFatigue ? "✔" : "❌")).build()); + panelComponent.getChildren().add(LineComponent.builder().left("simulateAttentionSpan: " + (Rs2AntibanSettings.simulateAttentionSpan ? "✔" : "❌")).build()); + panelComponent.getChildren().add(LineComponent.builder().left("useBehavioralVariability: " + (Rs2AntibanSettings.behavioralVariability ? "✔" : "❌")).build()); + panelComponent.getChildren().add(LineComponent.builder().left("useNonLinearIntervals: " + (Rs2AntibanSettings.nonLinearIntervals ? "✔" : "❌")).build()); + panelComponent.getChildren().add(LineComponent.builder().left("enableProfileSwitching: " + (Rs2AntibanSettings.profileSwitching ? "✔" : "❌")).build()); + panelComponent.getChildren().add(LineComponent.builder().left("adjustForTimeOfDay: " + (Rs2AntibanSettings.timeOfDayAdjust ? "✔" : "❌")).build()); + panelComponent.getChildren().add(LineComponent.builder().left("simulateMistakes: " + (Rs2AntibanSettings.simulateMistakes ? "✔" : "❌")).build()); + panelComponent.getChildren().add(LineComponent.builder().left("useNaturalMouse: " + (Rs2AntibanSettings.naturalMouse ? "✔" : "❌")).build()); + panelComponent.getChildren().add(LineComponent.builder().left("useContextualVariability: " + (Rs2AntibanSettings.contextualVariability ? "✔" : "❌")).build()); + } + if (playStyle != null) { + panelComponent.getChildren().add(LineComponent.builder().left("Play Style: " + playStyle.getName()).build()); + if (Rs2AntibanSettings.simulateAttentionSpan) { + panelComponent.getChildren().add(LineComponent.builder().left("Play style change in: " + playStyle.getTimeLeftUntilNextSwitch()).build()); + } + panelComponent.getChildren().add(LineComponent.builder().build()); + if (Rs2Antiban.getCategory().isBusy()) { + panelComponent.getChildren().add(LineComponent.builder().left("We are busy").build()); + } else { + panelComponent.getChildren().add(LineComponent.builder().left("Not busy anymore, breaking").build()); + } + panelComponent.getChildren().add(LineComponent.builder().build()); + panelComponent.getChildren().add(TitleComponent.builder().text("Action cooldown(Tick)").color(Color.WHITE).build()); + panelComponent.getChildren().add(progressBarComponent); + } + + } + + /** + *
+ * The Rs2AntibanSettings
class contains a collection of static fields that define behaviors
+ * and settings related to anti-ban mechanisms. These settings control how the bot simulates human-like
+ * behavior to avoid detection during automated tasks. Each setting adjusts a specific aspect of the
+ * anti-ban system, including break patterns, mouse movements, play style variability, and other behaviors
+ * designed to mimic natural human interaction with the game.
+ *
actionCooldownActive
: Tracks whether action cooldowns are currently active.microBreakActive
: Indicates if a micro break is currently active.antibanEnabled
: Globally enables or disables the anti-ban system.usePlayStyle
: Determines whether play style simulation is active.randomIntervals
: Enables random intervals between actions to avoid detection.simulateFatigue
: Simulates user fatigue by introducing delays or slower actions.simulateAttentionSpan
: Simulates varying levels of user attention over time.behavioralVariability
: Adds variability to actions to simulate a human's inconsistency.nonLinearIntervals
: Activates non-linear time intervals between actions.profileSwitching
: Simulates user behavior switching profiles at intervals.timeOfDayAdjust
: (TODO) Adjusts behaviors based on the time of day.simulateMistakes
: Simulates user mistakes, often controlled by natural mouse movements.naturalMouse
: Enables natural-looking mouse movements.moveMouseOffScreen
: Moves the mouse off-screen during breaks to simulate user behavior.moveMouseRandomly
: Moves the mouse randomly to simulate human inconsistency.contextualVariability
: Adjusts behaviors based on the context of the user's actions.dynamicIntensity
: Dynamically adjusts the intensity of user actions based on context.dynamicActivity
: Adjusts activities dynamically based on the user's behavior profile.devDebug
: Enables debug mode for developers to inspect the anti-ban system's state.takeMicroBreaks
: Controls whether the bot takes micro breaks at random intervals.playSchedule
: (TODO) Allows scheduling of playtime based on specific conditions.universalAntiban
: Applies the same anti-ban settings across all plugins.microBreakDurationLow
: Minimum duration for micro breaks, in minutes.microBreakDurationHigh
: Maximum duration for micro breaks, in minutes.actionCooldownChance
: Probability of triggering an action cooldown.microBreakChance
: Probability of taking a micro break.moveMouseRandomlyChance
: Probability of moving the mouse randomly.+ * These settings are typically used by anti-ban mechanisms within various plugins to adjust their behavior + * dynamically based on the user's preferences or to simulate human-like play styles. Developers can adjust + * these fields based on the needs of their specific automation scripts. + *
+ * + *+ * // Enable fatigue simulation and random intervals + * Rs2AntibanSettings.simulateFatigue = true; + * Rs2AntibanSettings.randomIntervals = true; + * + * // Set the micro break chance to 20% + * Rs2AntibanSettings.microBreakChance = 0.2; + *+ */ + +public class Rs2AntibanSettings { + public static boolean actionCooldownActive = false; + public static boolean microBreakActive = false; + public static boolean antibanEnabled = true; + public static boolean usePlayStyle = false; + public static boolean randomIntervals = false; + public static boolean simulateFatigue = false; + public static boolean simulateAttentionSpan = false; + public static boolean behavioralVariability = false; + public static boolean nonLinearIntervals = false; + public static boolean profileSwitching = false; + public static boolean timeOfDayAdjust = false; //TODO: Implement this + public static boolean simulateMistakes = false; //Handled by the natural mouse + public static boolean naturalMouse = false; + public static boolean moveMouseOffScreen = false; + public static boolean moveMouseRandomly = false; + public static boolean contextualVariability = false; + public static boolean dynamicIntensity = false; + public static boolean dynamicActivity = false; + public static boolean devDebug = false; + public static boolean takeMicroBreaks = false; // will take micro breaks lasting 3-15 minutes at random intervals by default. + public static boolean playSchedule = false; //TODO: Implement this + public static boolean universalAntiban = false; // Will attempt to use the same antiban settings for all plugins that has not yet implemented their own antiban settings. + public static int microBreakDurationLow = 3; // 3 minutes + public static int microBreakDurationHigh = 15; // 15 minutes + public static double actionCooldownChance = 0.1; // 10% chance of activating the action cooldown by default + public static double microBreakChance = 0.1; // 10% chance of taking a micro break by default + public static double moveMouseRandomlyChance = 0.1; // 10% chance of moving the mouse randomly by default + + // reset method to reset all settings to default values + public static void reset() { + actionCooldownActive = false; + microBreakActive = false; + antibanEnabled = true; + usePlayStyle = false; + randomIntervals = false; + simulateFatigue = false; + simulateAttentionSpan = false; + behavioralVariability = false; + nonLinearIntervals = false; + profileSwitching = false; + timeOfDayAdjust = false; + simulateMistakes = false; + naturalMouse = false; + moveMouseOffScreen = false; + moveMouseRandomly = false; + contextualVariability = false; + dynamicIntensity = false; + dynamicActivity = false; + devDebug = false; + takeMicroBreaks = false; + playSchedule = false; + universalAntiban = false; + microBreakDurationLow = 3; + microBreakDurationHigh = 15; + actionCooldownChance = 0.1; + microBreakChance = 0.1; + moveMouseRandomlyChance = 0.1; + } +} \ No newline at end of file diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/util/antiban/enums/Activity.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/util/antiban/enums/Activity.java new file mode 100644 index 0000000000..688390f28f --- /dev/null +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/util/antiban/enums/Activity.java @@ -0,0 +1,530 @@ +package net.runelite.client.plugins.microbot.util.antiban.enums; + +import lombok.Getter; +import net.runelite.api.Skill; + +/** + * The Activity enum represents various activities that the player can perform in the game, each associated with a specific + * category and intensity level. + * + *
+ * Activities range from general skilling and combat tasks to specific high-intensity boss fights or complex tasks. Each activity
+ * is linked to a Category
that defines the type of activity (e.g., skilling, combat), and an ActivityIntensity
+ * that controls how aggressive or passive the bot's behavior should be during that activity.
+ *
Category
that helps the bot identify the
+ * type of activity and how to handle it.ActivityIntensity
. For example, combat activities tend to have higher intensity, while
+ * skilling tasks may be more moderate or low intensity.
+ * The Activity
enum is used to control bot behavior based on the type of activity the player is performing.
+ * Each activity informs the bot of the type of task being executed, its intensity, and the corresponding category to ensure
+ * appropriate behavior, such as taking breaks or adjusting actions dynamically.
+ *
+ * Rs2Antiban.setActivity(Activity activity); + * Rs2Antiban.getCategory(); + * Rs2Antiban.setActivityIntensity(ActivityIntensity activityIntensity); + *+ * + *
+ * The fromSkill(Skill skill)
method maps in-game skills (e.g., Mining, Fishing, Combat) to general activities,
+ * allowing the bot to adjust its behavior based on the skill currently being trained. This ensures that the bot
+ * behaves consistently for all general activities related to a specific skill.
+ *
+ * Each activity belongs to a Category
that defines the overall type of the activity (e.g., skilling, combat,
+ * collecting), and each is assigned an ActivityIntensity
level, which determines the speed and aggression of
+ * the bot's actions during that activity.
+ *
+ * Activity intensities are used to simulate varying levels of focus and action frequency during bot operation. + * Each intensity level controls the frequency and amplitude of actions, which corresponds to how aggressive or passive + * the bot's behavior is during different tasks. The intensity also determines the corresponding play style, which + * adjusts the bot's overall behavior to better mimic human variability. + *
+ * + *PlayStyle
, which defines the overall behavior
+ * of the bot during specific activities.
+ * The ActivityIntensity
enum is used to dynamically adjust the bot's behavior based on the intensity of the
+ * player's activity. Higher intensity levels correspond to more aggressive actions, while lower intensity levels simulate
+ * slower, more deliberate behavior. This allows the bot to adapt to different types of activities, from combat to skilling.
+ *
+ * ActivityIntensity currentIntensity = ActivityIntensity.HIGH; + * PlayStyle associatedStyle = currentIntensity.getPlayStyle(); + * double actionFrequency = currentIntensity.getFrequency(); + *+ * + *
+ * The fromSkill(Skill skill)
method maps in-game skills to specific activity intensity levels. For example,
+ * combat-related skills such as Attack, Defence, and Ranged are mapped to higher intensities, while skills like Cooking,
+ * Fishing, and Crafting are mapped to lower intensities. This allows the bot to adjust its behavior based on the current
+ * skill being trained.
+ *
+ * The random()
method provides a way to select a random activity intensity, introducing unpredictability
+ * and making the bot's actions appear more human-like by varying the intensity over time.
+ *
+ * Each category is associated with a specific type of activity and contains logic to determine whether the player is "busy" + * based on the current game state. This is used to control bot behavior and ensure it adapts to the player's activity, + * pausing or adjusting actions when the player is engaged in a task. + *
+ * + *isBusy()
method, providing custom logic
+ * for determining if the player is engaged in the respective activity.
+ * The Category
enum is used within the bot's logic to monitor the player's activities and determine
+ * if the bot should continue executing actions or wait for the player to finish their current task. Each category
+ * provides specific logic to handle different types of activities such as combat, skilling, and crafting.
+ * This class is used by the anti-ban system to make sure the action cooldown is not counting down while the player is busy.
+ *
+ * Category currentCategory = Category.SKILLING_COOKING; + * if (currentCategory.isBusy()) { + * // The player is busy cooking, so the bot may pause actions. + * } else { + * // The player is idle, and the bot can continue with the next task. + * } + *+ * + *
+ * Each category overrides the isBusy()
method to implement custom logic for checking if the player is engaged
+ * in a specific task. For example, the COMBAT_MID
category checks if the player is in combat, while the
+ * SKILLING_COOKING
category checks if the player is currently cooking. Some categories are not fully implemented
+ * and include TODO notes for further customization based on game-specific conditions.
+ *
+ * Several categories contain TODO notes indicating that additional logic may be required to accurately determine if the player is busy. + * These categories currently rely on simple checks, such as whether the player is animating or if the inventory is full, + * but may need further refinement based on specific interactions or game mechanics. + *
+ */ + +public enum Category { + COMBAT_MID("Combat/Mid") { + @Override + public boolean isBusy() { + return Rs2Combat.inCombat(); + } + }, + SKILLING_AGILITY("Skilling/Agility") { + @Override + public boolean isBusy() { + return Rs2Player.isMoving(); + } + }, + PROCESSING("Processing") { + @Override + public boolean isBusy() { + return Rs2Player.isAnimating() || Microbot.isGainingExp; + } + }, + COLLECTING("Collecting") { + @Override + public boolean isBusy() { + return Rs2Player.isMoving() || Rs2Player.isInteracting(); + } + }, + SKILLING_CRAFTING("Skilling/Crafting") { + @Override + public boolean isBusy() { + return !Rs2Antiban.isIdle(); + } + }, + SKILLING_MAGIC("Skilling/Magic") { + @Override + public boolean isBusy() { + return Rs2Player.isAnimating() || Microbot.isGainingExp; + } + }, + COMBAT_LOW("Combat/Low") { + @Override + public boolean isBusy() { + return Rs2Combat.inCombat(); + } + }, + SKILLING_HERBLORE("Skilling/Herblore") { + @Override + public boolean isBusy() { + return !Rs2Antiban.isIdle() || Microbot.isGainingExp; + } + }, + SKILLING_FLETCHING("Skilling/Fletching") { + @Override + public boolean isBusy() { + return !Rs2Antiban.isIdle(); + } + }, + SKILLING_FISHING("Skilling/Fishing") { + @Override + public boolean isBusy() { + return Rs2Player.isInteracting(); + } + }, + PROCESSING_MAGIC("Processing/Magic") { + @Override + public boolean isBusy() { + return Rs2Player.isAnimating() && Microbot.isGainingExp; + } + }, + SKILLING_COOKING("Skilling/Cooking") { + @Override + public boolean isBusy() { + return AntibanPlugin.isCooking(); + } + }, + SKILLING_FIREMAKING("Skilling/Firemaking") { + @Override + public boolean isBusy() { + return Rs2Player.getPoseAnimation() == AnimationID.FIREMAKING; + } + }, + SKILLING_THIEVING("Skilling/Thieving") { + @Override + public boolean isBusy() { + return !Rs2Player.isAnimating(); + } + }, + SKILLING("Skilling") { + @Override + public boolean isBusy() { + return !Rs2Player.isAnimating() || !Rs2Inventory.isFull(); + } + }, + COLLECTING_NONE("Collecting/None") { + @Override + public boolean isBusy() { + return Rs2Player.isMoving(); + } + }, + COMBAT_HIGH("Combat/High") { + @Override + public boolean isBusy() { + return Rs2Combat.inCombat(); + } + }, + SKILLING_WOODCUTTING("Skilling/Woodcutting") { + @Override + public boolean isBusy() { + return Rs2Antiban.isWoodcutting(); + } + }, + SKILLING_MINING("Skilling/Mining") { + @Override + public boolean isBusy() { + return AntibanPlugin.isMining(); + } + }, + SKILLING_RUNECRAFT("Skilling/Runecraft") { + @Override + public boolean isBusy() { + return Rs2Inventory.contains("pure essence", "rune essence", "Daeyalt essence", "Dark essence fragment", "blood essence"); + } + }, + SKILLING_SMITHING("Skilling/Smithing") { + /** + * Checks if the player is busy. + *+ * TODO: This method has not been implemented correctly yet. + * It currently only checks if the player is animating or if the inventory is full. + * Additional conditions may need to be added to accurately determine if the player is busy. + * Consider adding checks for: + *
+ * TODO: This method has not been implemented correctly yet. + * It currently only checks if the player is animating or if the inventory is full. + * Additional conditions may need to be added to accurately determine if the player is busy. + * Consider adding checks for: + *
+ * TODO: This method has not been implemented correctly yet. + * It currently only checks if the player is animating or if the inventory is full. + * Additional conditions may need to be added to accurately determine if the player is busy. + * Consider adding checks for: + *
+ * TODO: This method has not been implemented correctly yet. + * It currently only checks if the player is animating or if the inventory is full. + * Additional conditions may need to be added to accurately determine if the player is busy. + * Consider adding checks for: + *
+ * TODO: This method has not been implemented correctly yet. + * It currently only checks if the player is animating or if the inventory is full. + * Additional conditions may need to be added to accurately determine if the player is busy. + * Consider adding checks for: + *
+ * Each schedule defines a specific time range during which the bot is active, allowing for more human-like + * behavior by simulating different play habits throughout the day. These schedules are managed and enforced + * by the Break Handler plugin, which controls when the bot should be active or inactive based on the selected schedule. + *
+ * + *
+ * The PlaySchedule
enum is used to control when the bot is active during specific periods of the day.
+ * By adhering to these schedules, the bot avoids continuous operation and mimics a more realistic user behavior.
+ * The Break Handler plugin ensures that the bot respects the defined schedules and manages any necessary pauses.
+ *
+ * The isOutsideSchedule()
method determines whether the current time is outside of the defined play schedule.
+ * This is useful for ensuring that the bot only runs during the specified time periods, as controlled by the Break Handler plugin.
+ * The timeUntilNextSchedule()
method calculates how long the bot must wait until the next play period starts,
+ * helping to schedule breaks and restarts efficiently.
+ *
+ * Each play style has its own characteristics, such as how aggressive or passive the bot's actions are, + * the length of breaks between actions, and the overall attention span. The enum offers profiles ranging + * from highly aggressive behavior with minimal breaks to passive styles with long pauses between actions. + * It is used to simulate different user behavior patterns and make the bot's actions less predictable. + *
+ * + *
+ * The PlayStyle
enum is primarily used to control how the bot behaves in different situations,
+ * allowing it to alternate between aggressive, moderate, or cautious behaviors dynamically. This helps the bot
+ * to avoid detection by simulating varied human actions over time.
+ *
+ * PlayStyle currentStyle = PlayStyle.AGGRESSIVE; + * Rs2Antiban.playStyle = currentStyle; // Set the current play style + * Rs2Antiban.playStyle.evolvePlayStyle(); // Dynamically evolve the play style (evolve is called each time Rs2Antiban.actionCooldown() is triggered) + *+ * + *
+ * Each play style tracks an attention span, representing the time the bot will continue with the current profile + * before switching to a new one. This ensures that the bot does not remain in a single behavior pattern for too long, + * helping it to mimic real human behavior. + *
+ */ + +@Slf4j +public enum PlayStyle { + EXTREME_AGGRESSIVE("Extreme Aggressive", 1, 3, 2, 0.00), // Almost no break between inputs + AGGRESSIVE("Aggressive", 2, 5, 5, 0.01), // Very short breaks + MODERATE("Moderate", 3, 9, 10, 0.08), // Short breaks + BALANCED("Balanced", 7, 15, 14, 0.12), // Moderate breaks + CAREFUL("Careful", 12, 21, 14, 0.17), // Longer breaks + CAUTIOUS("Cautious", 17, 30, 14, 0.23), // Very long breaks + PASSIVE("Passive", 20, 35, 14, 0.4), // Minimal actions + RANDOM("Random", 1, 35, 25, 0.00); // Random actions + + + @Getter + private final String name; + private final int originalPrimaryTickInterval; + private final int originalSecondaryTickInterval; + private final int baseDuration; // Base duration for the attention span + private final double refocusProbability; // Probability of refocusing + @Getter + @Setter + public double frequency; + @Getter + @Setter + public double amplitude; + @Setter + public Instant startTime; // Start time for the current playstyle + @Getter + private int primaryTickInterval; + @Getter + private int secondaryTickInterval; + private double phase; // Phase angle for the sine function + private int attentionSpan; // Attention span for the current playstyle + + PlayStyle(String name, int primaryTickInterval, int secondaryTickInterval, int baseDuration, double refocusProbability) { + this.name = name; + this.originalPrimaryTickInterval = primaryTickInterval; + this.originalSecondaryTickInterval = secondaryTickInterval; + this.primaryTickInterval = primaryTickInterval; + this.secondaryTickInterval = secondaryTickInterval; + this.refocusProbability = refocusProbability; + this.phase = 0.0; + this.frequency = 0.2; + this.amplitude = 2.0; + this.startTime = Instant.now(); + this.baseDuration = baseDuration; + this.attentionSpan = generateAttentionSpan(baseDuration); + } + + // Return a random PlayStyle + public static PlayStyle random() { + return values()[(int) (Math.random() * values().length)]; + } + + public int getRandomTickInterval() { + return ThreadLocalRandom.current().nextInt(primaryTickInterval, secondaryTickInterval + 1); + } + + // Method to evolve the play style over time using a sine function + public void evolvePlayStyle() { + phase += frequency; + primaryTickInterval = adjustInterval(primaryTickInterval, amplitude); + log.info("Primary tick interval: {}", primaryTickInterval); + secondaryTickInterval = adjustInterval(secondaryTickInterval, amplitude); + log.info("Secondary tick interval: {}", secondaryTickInterval); + Microbot.log("Slightly adjusting playStyle intervals."); + } + + // Helper method to adjust intervals using the sine of the phase + private int adjustInterval(int interval, double amplitude) { + int change = (int) (amplitude * Math.sin(phase)); + interval += change; + // Ensure intervals remain within logical boundaries + return Math.max(1, interval); + } + + // Method to reset the intervals to their original values + public void resetPlayStyle() { + this.primaryTickInterval = originalPrimaryTickInterval; + this.secondaryTickInterval = originalSecondaryTickInterval; + this.phase = 0.0; // Reset the phase as well + this.startTime = Instant.now(); // Reset start time + this.attentionSpan = generateAttentionSpan(this.baseDuration); // Generate new attention span + } + + // Switch profile to a new play style either one step up or down + public PlayStyle switchProfile() { + boolean up = Math.random() < 0.5; + boolean refocus = Math.random() < refocusProbability; + if (refocus) { + PlayStyle newProfile = values()[0]; + Microbot.log("Refocusing, switching to: " + newProfile.getName()); + return newProfile; + } + int index = this.ordinal(); + if (up) { + index++; + } else { + index--; + } + + // Check if index is out of bounds and invert the direction if necessary + if (index < 0 || index >= values().length - 1) { + // Invert the direction + up = !up; + // Reset index to the current ordinal value + index = this.ordinal(); + // Update the index again with the inverted direction + if (up) { + index = Math.min(values().length - 1, index + 1); + } else { + index = Math.max(0, index - 1); + } + } + + PlayStyle newProfile = values()[index]; + Microbot.log("Switched profile to: " + newProfile.getName()); + return newProfile; + } + + // Switch profile based on simulated attention span + public boolean shouldSwitchProfileBasedOnAttention() { + Instant currentTime = Instant.now(); + long elapsedTime = java.time.Duration.between(this.startTime, currentTime).getSeconds(); // elapsed time in seconds + + return elapsedTime >= this.attentionSpan; + } + + // Time left in the current play style + public String getTimeLeftUntilNextSwitch() { + Instant currentTime = Instant.now(); + long elapsedTime = Duration.between(this.startTime, currentTime).getSeconds(); // elapsed time in seconds + long timeLeft = (this.attentionSpan) - elapsedTime; + + if (timeLeft <= 0) { + return "00:00"; // switch should occur immediately + } + + long minutes = timeLeft / 60; + long seconds = timeLeft % 60; + + return String.format("%02d:%02d", minutes, seconds); + } + + // Generate attention span using normal and Poisson distributions + private int generateAttentionSpan(int baseDuration) { + // Define parameters for normal and Poisson distributions + double normalMean = baseDuration * 60; // mean of the normal distribution + double normalStdDev = normalMean * 0.2; // standard deviation of the normal distribution (20% of mean) + double poissonLambda = normalMean * 0.1; // lambda parameter for the Poisson distribution (10% of mean) + + // Generate random values from normal and Poisson distributions + Random random = new Random(); + double normalSample = random.nextGaussian() * normalStdDev + normalMean; + double poissonSample = nextPoisson(poissonLambda); + + // Combine the values to get the attention span + return (int) Math.max(1, normalSample + poissonSample); + } + + // Helper method to generate a Poisson-distributed random value + private int nextPoisson(double lambda) { + Random random = new Random(); + double l = Math.exp(-lambda); + int k = 0; + double p = 1.0; + do { + k++; + p *= random.nextDouble(); + } while (p > l); + return k - 1; + } +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/util/antiban/ui/ActivityPanel.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/util/antiban/ui/ActivityPanel.java new file mode 100644 index 0000000000..d319b29052 --- /dev/null +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/util/antiban/ui/ActivityPanel.java @@ -0,0 +1,64 @@ +package net.runelite.client.plugins.microbot.util.antiban.ui; + +import net.runelite.client.plugins.microbot.util.antiban.Rs2AntibanSettings; +import net.runelite.client.ui.ColorScheme; + +import javax.swing.*; +import java.awt.*; + +public class ActivityPanel extends JPanel { + private final JCheckBox usePlayStyle = new JCheckBox("Use Play Style"); + private final JCheckBox useRandomIntervals = new JCheckBox("Use Random Intervals"); + private final JCheckBox simulateFatigue = new JCheckBox("Simulate Fatigue"); + private final JCheckBox simulateAttentionSpan = new JCheckBox("Simulate Attention Span"); + private final JCheckBox useBehavioralVariability = new JCheckBox("Use Behavioral Variability"); + private final JCheckBox useNonLinearIntervals = new JCheckBox("Use Non-Linear Intervals"); + private final JCheckBox dynamicActivityIntensity = new JCheckBox("Dynamic Activity Intensity"); + private final JCheckBox dynamicActivity = new JCheckBox("Dynamic Activity"); + + public ActivityPanel() { + setLayout(new GridBagLayout()); + setBackground(ColorScheme.DARK_GRAY_HOVER_COLOR); + GridBagConstraints gbc = new GridBagConstraints(); + gbc.gridx = 0; + gbc.gridy = GridBagConstraints.RELATIVE; + gbc.anchor = GridBagConstraints.WEST; + gbc.insets = new Insets(5, 5, 5, 5); + + add(usePlayStyle, gbc); + add(useRandomIntervals, gbc); + add(simulateFatigue, gbc); + add(simulateAttentionSpan, gbc); + add(useBehavioralVariability, gbc); + add(useNonLinearIntervals, gbc); + add(dynamicActivityIntensity, gbc); + add(dynamicActivity, gbc); + + setupActionListeners(); + + } + + private void setupActionListeners() { + usePlayStyle.addActionListener(e -> Rs2AntibanSettings.usePlayStyle = usePlayStyle.isSelected()); + useRandomIntervals.addActionListener(e -> Rs2AntibanSettings.randomIntervals = useRandomIntervals.isSelected()); + simulateFatigue.addActionListener(e -> Rs2AntibanSettings.simulateFatigue = simulateFatigue.isSelected()); + simulateAttentionSpan.addActionListener(e -> Rs2AntibanSettings.simulateAttentionSpan = simulateAttentionSpan.isSelected()); + useBehavioralVariability.addActionListener(e -> Rs2AntibanSettings.behavioralVariability = useBehavioralVariability.isSelected()); + useNonLinearIntervals.addActionListener(e -> Rs2AntibanSettings.nonLinearIntervals = useNonLinearIntervals.isSelected()); + dynamicActivityIntensity.addActionListener(e -> Rs2AntibanSettings.dynamicIntensity = dynamicActivityIntensity.isSelected()); + dynamicActivity.addActionListener(e -> Rs2AntibanSettings.dynamicActivity = dynamicActivity.isSelected()); + + } + + public void updateValues() { + usePlayStyle.setSelected(Rs2AntibanSettings.usePlayStyle); + useRandomIntervals.setSelected(Rs2AntibanSettings.randomIntervals); + simulateFatigue.setSelected(Rs2AntibanSettings.simulateFatigue); + simulateAttentionSpan.setSelected(Rs2AntibanSettings.simulateAttentionSpan); + useBehavioralVariability.setSelected(Rs2AntibanSettings.behavioralVariability); + useNonLinearIntervals.setSelected(Rs2AntibanSettings.nonLinearIntervals); + dynamicActivityIntensity.setSelected(Rs2AntibanSettings.dynamicIntensity); + dynamicActivity.setSelected(Rs2AntibanSettings.dynamicActivity); + } + +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/util/antiban/ui/CardPanel.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/util/antiban/ui/CardPanel.java new file mode 100644 index 0000000000..5f2fc90ab5 --- /dev/null +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/util/antiban/ui/CardPanel.java @@ -0,0 +1,25 @@ +package net.runelite.client.plugins.microbot.util.antiban.ui; + +import net.runelite.client.ui.ColorScheme; + +import javax.swing.*; +import java.awt.*; + +public class CardPanel extends JPanel { + public CardPanel() { + setLayout(new CardLayout()); + setBorder(BorderFactory.createCompoundBorder( + BorderFactory.createMatteBorder(2, 2, 2, 2, ColorScheme.DARKER_GRAY_COLOR.darker()), + BorderFactory.createEmptyBorder(0, 0, 5, 0))); + setBackground(ColorScheme.DARK_GRAY_HOVER_COLOR); + } + + public void addPanel(JPanel panel, String name) { + add(panel, name); + } + + public void showPanel(String name) { + CardLayout cardLayout = (CardLayout) getLayout(); + cardLayout.show(this, name); + } +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/util/antiban/ui/CooldownPanel.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/util/antiban/ui/CooldownPanel.java new file mode 100644 index 0000000000..155fdb1bba --- /dev/null +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/util/antiban/ui/CooldownPanel.java @@ -0,0 +1,73 @@ +package net.runelite.client.plugins.microbot.util.antiban.ui; + +import net.runelite.client.plugins.microbot.util.antiban.Rs2Antiban; +import net.runelite.client.plugins.microbot.util.antiban.Rs2AntibanSettings; +import net.runelite.client.ui.ColorScheme; + +import javax.swing.*; +import java.awt.*; + +import static net.runelite.client.plugins.microbot.util.antiban.ui.UiHelper.setupSlider; + +public class CooldownPanel extends JPanel { + private final JCheckBox isActionCooldownActive = new JCheckBox("Action Cooldown Active"); + private final JSlider actionCooldownChance = new JSlider(0, 100, (int) (Rs2AntibanSettings.actionCooldownChance * 100)); + private final JSlider timeout = new JSlider(0, 60, Rs2Antiban.getTIMEOUT()); + private final JLabel actionCooldownChanceLabel = new JLabel("Action Cooldown Chance (%): " + (int) (Rs2AntibanSettings.actionCooldownChance * 100)); + private final JLabel timeoutLabel = new JLabel("Timeout (min): " + Rs2Antiban.getTIMEOUT()); + + public CooldownPanel() { + // Set the layout manager for the panel to GridBagLayout + setLayout(new GridBagLayout()); + setBackground(ColorScheme.DARK_GRAY_HOVER_COLOR); + setupSlider(actionCooldownChance, 20, 100, 10); + setupSlider(timeout, 10, 60, 5); + + // Create a GridBagConstraints object to define the layout settings for each component + GridBagConstraints gbc = new GridBagConstraints(); + gbc.insets = new Insets(5, 5, 5, 5); // Padding around components + gbc.anchor = GridBagConstraints.WEST; // Align components to the left + gbc.gridx = 0; // All components will be in column 0 + gbc.gridy = GridBagConstraints.RELATIVE; // Components will be placed in consecutive rows + + // Add the "Action Cooldown Active" checkbox + add(isActionCooldownActive, gbc); + + // Add the "Action Cooldown Chance" label + add(actionCooldownChanceLabel, gbc); + + gbc.fill = GridBagConstraints.HORIZONTAL; + // Add the "Action Cooldown Chance" slider + add(actionCooldownChance, gbc); + + gbc.fill = GridBagConstraints.NONE; + // Add the "Timeout" label + add(timeoutLabel, gbc); + + gbc.fill = GridBagConstraints.HORIZONTAL; + // Add the "Timeout" slider + add(timeout, gbc); + + setupActionListeners(); + } + + private void setupActionListeners() { + isActionCooldownActive.addActionListener(e -> Rs2AntibanSettings.actionCooldownActive = isActionCooldownActive.isSelected()); + actionCooldownChance.addChangeListener(e -> { + Rs2AntibanSettings.actionCooldownChance = actionCooldownChance.getValue() / 100.0; + actionCooldownChanceLabel.setText("Action Cooldown Chance (%): " + actionCooldownChance.getValue()); + }); + timeout.addChangeListener(e -> { + Rs2Antiban.setTIMEOUT(timeout.getValue()); + timeoutLabel.setText("Timeout (min): " + timeout.getValue()); + }); + } + + public void updateValues() { + actionCooldownChance.setValue((int) (Rs2AntibanSettings.actionCooldownChance * 100)); + actionCooldownChanceLabel.setText("Action Cooldown Chance (%): " + actionCooldownChance.getValue()); + timeout.setValue(Rs2Antiban.getTIMEOUT()); + timeoutLabel.setText("Timeout (min): " + timeout.getValue()); + + } +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/util/antiban/ui/GeneralPanel.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/util/antiban/ui/GeneralPanel.java new file mode 100644 index 0000000000..be20a36d60 --- /dev/null +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/util/antiban/ui/GeneralPanel.java @@ -0,0 +1,57 @@ +package net.runelite.client.plugins.microbot.util.antiban.ui; + +import net.runelite.client.plugins.microbot.util.antiban.Rs2AntibanSettings; +import net.runelite.client.ui.ColorScheme; + +import javax.swing.*; +import java.awt.*; + +public class GeneralPanel extends JPanel { + + private final JCheckBox isEnabled = new JCheckBox("Enabled"); + private final JCheckBox universalAntiban = new JCheckBox("Universal Antiban"); + private final JCheckBox useContextualVariability = new JCheckBox("Use Contextual Variability"); + private final JCheckBox devDebug = new JCheckBox("Dev Debug"); + + public GeneralPanel() { + // Set the layout manager for the panel to GridBagLayout + setLayout(new GridBagLayout()); + setBackground(ColorScheme.DARK_GRAY_HOVER_COLOR); + // Create a GridBagConstraints object to define the layout settings for each component + GridBagConstraints gbc = new GridBagConstraints(); + gbc.insets = new Insets(5, 5, 5, 5); // Padding around components + gbc.anchor = GridBagConstraints.WEST; // Align components to the left + gbc.gridx = 0; // All components will be in column 0 + gbc.gridy = GridBagConstraints.RELATIVE; // Components will be placed in consecutive rows + + // Add the "Enabled" checkbox + add(isEnabled, gbc); + + // Add the "Universal Antiban" checkbox + add(universalAntiban, gbc); + + // Add the "Use Contextual Variability" checkbox + add(useContextualVariability, gbc); + + // Add the "Dev Debug" checkbox + add(devDebug, gbc); + + setupActionListeners(); + } + + private void setupActionListeners() { + isEnabled.addActionListener(e -> Rs2AntibanSettings.antibanEnabled = isEnabled.isSelected()); + universalAntiban.addActionListener(e -> Rs2AntibanSettings.universalAntiban = universalAntiban.isSelected()); + useContextualVariability.addActionListener(e -> Rs2AntibanSettings.contextualVariability = useContextualVariability.isSelected()); + devDebug.addActionListener(e -> Rs2AntibanSettings.devDebug = devDebug.isSelected()); + + } + + public void updateValues() { + isEnabled.setSelected(Rs2AntibanSettings.antibanEnabled); + universalAntiban.setSelected(Rs2AntibanSettings.universalAntiban); + useContextualVariability.setSelected(Rs2AntibanSettings.contextualVariability); + devDebug.setSelected(Rs2AntibanSettings.devDebug); + } + +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/util/antiban/ui/MasterPanel.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/util/antiban/ui/MasterPanel.java new file mode 100644 index 0000000000..3ca94d9b2d --- /dev/null +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/util/antiban/ui/MasterPanel.java @@ -0,0 +1,228 @@ +package net.runelite.client.plugins.microbot.util.antiban.ui; + +import net.runelite.client.plugins.microbot.Microbot; +import net.runelite.client.plugins.microbot.util.antiban.Rs2Antiban; +import net.runelite.client.plugins.microbot.util.antiban.Rs2AntibanSettings; +import net.runelite.client.ui.FontManager; +import net.runelite.client.ui.PluginPanel; + +import javax.swing.*; +import java.awt.*; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.geom.AffineTransform; + +/** + * The MasterPanel is a user interface panel for configuring anti-ban settings. + * + *+ * This panel allows users to adjust settings related to the anti-ban system, such as enabling micro-breaks, + * adjusting action cooldown probabilities, and configuring behavioral simulations like fatigue or attention span. + * The panel is divided into different categories, each focusing on specific aspects of anti-ban behavior, + * including activity settings, mouse behavior, and cooldown management. + *
+ * + *+ * Users can interact with various checkboxes and sliders to tailor the bot's anti-ban features to their preferences, + * making it behave more like a human player during automated tasks. + *
+ * + *+ * This panel is automatically integrated into the bot's user interface and does not require manual initialization by the user. + *
+ */ +public class MasterPanel extends PluginPanel { + private static final int BOUNDARY_RIGHT = 150; // Adjust for how far you want the GIF to move + private static final int BOUNDARY_LEFT = 0; + // Additional Info Panel + private final JLabel playStyleLabel = new JLabel("Play Style: " + (Rs2Antiban.getPlayStyle() != null ? Rs2Antiban.getPlayStyle().getName() : "null")); + private final JLabel playStyleChangeLabel = new JLabel("Play Style Change: " + (Rs2Antiban.getPlayStyle() != null ? Rs2Antiban.getPlayStyle().getTimeLeftUntilNextSwitch() : "null")); + private final JLabel profileLabel = new JLabel("Category: " + (Rs2Antiban.getCategory() != null ? Rs2Antiban.getCategory().getName() : "null")); + private final JLabel activityLabel = new JLabel("Activity: " + (Rs2Antiban.getActivity() != null ? Rs2Antiban.getActivity().getMethod() : "null")); + private final JLabel activityIntensityLabel = new JLabel("Activity Intensity: " + (Rs2Antiban.getActivityIntensity() != null ? Rs2Antiban.getActivityIntensity().getName() : "null")); + private final JLabel busyLabel = new JLabel("Busy: " + (Rs2Antiban.getCategory() != null ? Rs2Antiban.getCategory().isBusy() : "null")); + private final boolean isFlipped = false; // Track if the image is flipped + private final FlippableLabel label; + private final JLayeredPane layeredPane; // Use a layered pane for positioning the GIF + GeneralPanel generalPanel = new GeneralPanel(); + ActivityPanel activityPanel = new ActivityPanel(); + ProfilePanel profilePanel = new ProfilePanel(); + MousePanel mousePanel = new MousePanel(); + MicroBreakPanel microBreakPanel = new MicroBreakPanel(); + CooldownPanel cooldownPanel = new CooldownPanel(); + JButton resetButton = new JButton("Reset"); + private int xPosition = 0; + private int xVelocity = 1; // Change this value to control the speed of movement + + public MasterPanel() { + setLayout(new BorderLayout()); + + // Create the CardPanel (which contains the CardLayout) + CardPanel cardPanel = new CardPanel(); + + // Add panels to the CardPanel with unique names + cardPanel.addPanel(generalPanel, "General"); + cardPanel.addPanel(activityPanel, "Activity"); + cardPanel.addPanel(profilePanel, "Profile"); + cardPanel.addPanel(mousePanel, "Mouse"); + cardPanel.addPanel(microBreakPanel, "MicroBreak"); + cardPanel.addPanel(cooldownPanel, "Cooldown"); + + // Create the NavigationPanel and pass the CardPanel to it + NavigationPanel navigationPanel = new NavigationPanel(cardPanel); + + JPanel headerPanel = createHeaderPanel(navigationPanel); + JPanel mainDisplayPanel = new JPanel(); + + mainDisplayPanel.add(cardPanel); + mainDisplayPanel.setLayout(new BoxLayout(mainDisplayPanel, BoxLayout.Y_AXIS)); + mainDisplayPanel.add(createInfoPanel()); + mainDisplayPanel.add(Box.createVerticalStrut(100)); + mainDisplayPanel.add(new Box(BoxLayout.Y_AXIS)); + layeredPane = new JLayeredPane(); + layeredPane.setPreferredSize(new Dimension(250, 32)); + + // Create and position the GIF JLabel + ImageIcon icon = new ImageIcon(Rs2Antiban.class.getResource("walkingduckdark.gif")); + label = new FlippableLabel(icon); + label.setBounds(xPosition, 0, icon.getIconWidth(), icon.getIconHeight()); // Initial position + layeredPane.add(label, JLayeredPane.DEFAULT_LAYER); // Add label to the default layer + mainDisplayPanel.add(layeredPane); + + // Timer to move the GIF back and forth + Timer timer = new Timer(80, new ActionListener() { // Update every 20ms (50fps) + @Override + public void actionPerformed(ActionEvent e) { + // Update the position + xPosition += xVelocity; + + // Check boundaries and reverse direction if needed + if (xPosition >= 250 || xPosition <= BOUNDARY_LEFT) { + xVelocity = -xVelocity; // Reverse direction + label.flip(); // Flip the image when direction changes + } + + // Update the label's position + label.updatePosition(xPosition); + } + }); + timer.start(); // Start the movement timer + + add(headerPanel, BorderLayout.NORTH); + add(mainDisplayPanel, BorderLayout.CENTER); + add(resetButton, BorderLayout.SOUTH); + + cardPanel.showPanel("General"); + setupResetButton(); + + } + + private JPanel createHeaderPanel(NavigationPanel navigationPanel) { + JPanel headerPanel = new JPanel(); + headerPanel.setLayout(new BorderLayout()); + headerPanel.setBackground(new Color(27, 27, 27)); + +// JLabel headerLabel = new JLabel("\uD83E\uDD86 ANTIBAN \uD83E\uDD86"); + JLabel headerLabel = new JLabel("ANTIBAN"); + headerLabel.setFont(FontManager.getRunescapeBoldFont().deriveFont(24.0F)); + headerLabel.setBorder(BorderFactory.createEmptyBorder(10, 0, 10, 0)); + headerLabel.setHorizontalAlignment(SwingConstants.CENTER); + + headerPanel.add(headerLabel, BorderLayout.NORTH); + headerPanel.add(navigationPanel, BorderLayout.CENTER); + + return headerPanel; + } + + //set up the reset button to reset all settings + public void setupResetButton() { + resetButton.addActionListener(e -> { + Rs2AntibanSettings.reset(); + loadSettings(); + }); + } + + public void loadSettings() { + // Load settings from the settings object and set the checkboxes accordingly + generalPanel.updateValues(); + activityPanel.updateValues(); + profilePanel.updateValues(); + mousePanel.updateValues(); + microBreakPanel.updateValues(); + cooldownPanel.updateValues(); + + if (!Microbot.isLoggedIn()) + return; + + playStyleLabel.setText("Play Style: " + (Rs2Antiban.getPlayStyle() != null ? Rs2Antiban.getPlayStyle().getName() : "null")); + playStyleChangeLabel.setText("Play Style Change: " + (Rs2Antiban.getPlayStyle() != null ? Rs2Antiban.getPlayStyle().getTimeLeftUntilNextSwitch() : "null")); + profileLabel.setText("Category: " + (Rs2Antiban.getCategory() != null ? Rs2Antiban.getCategory().getName() : "null")); + activityLabel.setText("Activity: " + (Rs2Antiban.getActivity() != null ? Rs2Antiban.getActivity().getMethod() : "null")); + activityIntensityLabel.setText("Activity Intensity: " + (Rs2Antiban.getActivityIntensity() != null ? Rs2Antiban.getActivityIntensity().getName() : "null")); + busyLabel.setText("Busy: " + (Rs2Antiban.getCategory() != null ? Rs2Antiban.getCategory().isBusy() : "null")); + } + + private JPanel createInfoPanel() { + JPanel panel = new JPanel(new GridBagLayout()); + panel.setBorder(BorderFactory.createTitledBorder("Additional Info")); + + GridBagConstraints gbc = new GridBagConstraints(); + gbc.gridx = 0; + gbc.gridy = GridBagConstraints.RELATIVE; + gbc.anchor = GridBagConstraints.WEST; + gbc.insets = new Insets(5, 5, 5, 5); + + panel.add(playStyleLabel, gbc); + panel.add(playStyleChangeLabel, gbc); + panel.add(profileLabel, gbc); + panel.add(activityLabel, gbc); + panel.add(activityIntensityLabel, gbc); + panel.add(busyLabel, gbc); + + return panel; + } + + // Custom JLabel class that supports flipping the image + private class FlippableLabel extends JLabel { + private boolean isFlipped = false; + + public FlippableLabel(ImageIcon icon) { + super(icon); + setDoubleBuffered(true); // Enable double buffering to prevent flickering + } + + public void flip() { + isFlipped = !isFlipped; + repaint(); // Request a repaint to apply the flip + } + + public void updatePosition(int x) { + // Safely update the label position without interfering with other UI events + SwingUtilities.invokeLater(() -> setBounds(x, getY(), getWidth(), getHeight())); + } + + @Override + protected void paintComponent(Graphics g) { + Graphics2D g2d = (Graphics2D) g.create(); // Create a copy of Graphics2D to avoid modifying the original + + if (isFlipped) { + // Apply horizontal flip by flipping the x-axis + AffineTransform transform = AffineTransform.getScaleInstance(-1, 1); + transform.translate(-getWidth(), 0); + g2d.setTransform(transform); + } + + super.paintComponent(g2d); // Let JLabel handle the image rendering + g2d.dispose(); // Dispose of the copy to release resources + } + } +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/util/antiban/ui/MicroBreakPanel.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/util/antiban/ui/MicroBreakPanel.java new file mode 100644 index 0000000000..408aa32aa4 --- /dev/null +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/util/antiban/ui/MicroBreakPanel.java @@ -0,0 +1,95 @@ +package net.runelite.client.plugins.microbot.util.antiban.ui; + +import net.runelite.client.plugins.microbot.util.antiban.Rs2AntibanSettings; +import net.runelite.client.ui.ColorScheme; + +import javax.swing.*; +import java.awt.*; + +import static net.runelite.client.plugins.microbot.util.antiban.ui.UiHelper.setupSlider; + +public class MicroBreakPanel extends JPanel { + private final JCheckBox isMicroBreakActive = new JCheckBox("Micro Break Active"); + private final JCheckBox takeMicroBreaks = new JCheckBox("Take Micro Breaks"); + private final JSlider microBreakDurationLow = new JSlider(1, 10, Rs2AntibanSettings.microBreakDurationLow); + private final JSlider microBreakDurationHigh = new JSlider(1, 30, Rs2AntibanSettings.microBreakDurationHigh); + private final JSlider microBreakChance = new JSlider(0, 100, (int) (Rs2AntibanSettings.microBreakChance * 100)); + private final JLabel microBreakDurationLowLabel = new JLabel("Micro Break Duration Low (min): " + Rs2AntibanSettings.microBreakDurationLow); + private final JLabel microBreakDurationHighLabel = new JLabel("Micro Break Duration High (min): " + Rs2AntibanSettings.microBreakDurationHigh); + private final JLabel microBreakChanceLabel = new JLabel("Micro Break Chance (%): " + (int) (Rs2AntibanSettings.microBreakChance * 100)); + + public MicroBreakPanel() { + // Set the layout manager for the panel to GridBagLayout + setLayout(new GridBagLayout()); + setBackground(ColorScheme.DARK_GRAY_HOVER_COLOR); + setupSlider(microBreakDurationLow, 1, 5, 1); + setupSlider(microBreakDurationHigh, 5, 15, 1); + setupSlider(microBreakChance, 20, 100, 10); + + // Create a GridBagConstraints object to define the layout settings for each component + GridBagConstraints gbc = new GridBagConstraints(); + gbc.insets = new Insets(5, 5, 5, 5); // Padding around components + gbc.anchor = GridBagConstraints.WEST; // Align components to the left + gbc.gridx = 0; // All components will be in column 0 + gbc.gridy = GridBagConstraints.RELATIVE; // Components will be placed in consecutive rows + + // Add the "Micro Break Active" checkbox + add(isMicroBreakActive, gbc); + + // Add the "Take Micro Breaks" checkbox + add(takeMicroBreaks, gbc); + + // Add the "Micro Break Duration Low" label + add(microBreakDurationLowLabel, gbc); + + gbc.fill = GridBagConstraints.HORIZONTAL; + // Add the "Micro Break Duration Low" slider + add(microBreakDurationLow, gbc); + + gbc.fill = GridBagConstraints.NONE; + // Add the "Micro Break Duration High" label + add(microBreakDurationHighLabel, gbc); + + gbc.fill = GridBagConstraints.HORIZONTAL; + // Add the "Micro Break Duration High" slider + add(microBreakDurationHigh, gbc); + + gbc.fill = GridBagConstraints.NONE; + // Add the "Micro Break Chance" label + add(microBreakChanceLabel, gbc); + + gbc.fill = GridBagConstraints.HORIZONTAL; + // Add the "Micro Break Chance" slider + add(microBreakChance, gbc); + + setupActionListeners(); + } + + private void setupActionListeners() { + isMicroBreakActive.addActionListener(e -> Rs2AntibanSettings.microBreakActive = isMicroBreakActive.isSelected()); + takeMicroBreaks.addActionListener(e -> Rs2AntibanSettings.takeMicroBreaks = takeMicroBreaks.isSelected()); + microBreakDurationLow.addChangeListener(e -> { + Rs2AntibanSettings.microBreakDurationLow = microBreakDurationLow.getValue(); + microBreakDurationLowLabel.setText("Micro Break Duration Low (min): " + microBreakDurationLow.getValue()); + }); + microBreakDurationHigh.addChangeListener(e -> { + Rs2AntibanSettings.microBreakDurationHigh = microBreakDurationHigh.getValue(); + microBreakDurationHighLabel.setText("Micro Break Duration High (min): " + microBreakDurationHigh.getValue()); + }); + microBreakChance.addChangeListener(e -> { + Rs2AntibanSettings.microBreakChance = microBreakChance.getValue() / 100.0; + microBreakChanceLabel.setText("Micro Break Chance (%): " + microBreakChance.getValue()); + }); + } + + public void updateValues() { + isMicroBreakActive.setSelected(Rs2AntibanSettings.microBreakActive); + takeMicroBreaks.setSelected(Rs2AntibanSettings.takeMicroBreaks); + microBreakDurationLow.setValue(Rs2AntibanSettings.microBreakDurationLow); + microBreakDurationLowLabel.setText("Micro Break Duration Low (min): " + microBreakDurationLow.getValue()); + microBreakDurationHigh.setValue(Rs2AntibanSettings.microBreakDurationHigh); + microBreakDurationHighLabel.setText("Micro Break Duration High (min): " + microBreakDurationHigh.getValue()); + microBreakChance.setValue((int) (Rs2AntibanSettings.microBreakChance * 100)); + microBreakChanceLabel.setText("Micro Break Chance (%): " + microBreakChance.getValue()); + } +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/util/antiban/ui/MousePanel.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/util/antiban/ui/MousePanel.java new file mode 100644 index 0000000000..dfb8c1c56f --- /dev/null +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/util/antiban/ui/MousePanel.java @@ -0,0 +1,79 @@ +package net.runelite.client.plugins.microbot.util.antiban.ui; + +import net.runelite.client.plugins.microbot.util.antiban.Rs2AntibanSettings; +import net.runelite.client.ui.ColorScheme; + +import javax.swing.*; +import java.awt.*; + +import static net.runelite.client.plugins.microbot.util.antiban.ui.UiHelper.setupSlider; + +public class MousePanel extends JPanel { + private final JCheckBox useNaturalMouse = new JCheckBox("Use Natural Mouse"); + private final JCheckBox simulateMistakes = new JCheckBox("Simulate Mistakes"); + private final JCheckBox moveMouseOffScreen = new JCheckBox("Move Mouse Off Screen"); + private final JCheckBox moveMouseRandomly = new JCheckBox("Move Mouse Randomly"); + private final JSlider moveMouseRandomlyChance = new JSlider(0, 100, (int) (Rs2AntibanSettings.moveMouseRandomlyChance * 100)); + private final JLabel moveMouseRandomlyChanceLabel = new JLabel("Random Mouse Movement (%): " + (int) (Rs2AntibanSettings.moveMouseRandomlyChance * 100)); + + public MousePanel() { + // Set the layout manager for the panel to GridBagLayout + setLayout(new GridBagLayout()); + setBackground(ColorScheme.DARK_GRAY_HOVER_COLOR); + setupSlider(moveMouseRandomlyChance, 20, 100, 10); + + // Create a GridBagConstraints object to define the layout settings for each component + GridBagConstraints gbc = new GridBagConstraints(); + gbc.insets = new Insets(5, 5, 5, 5); // Padding around components + gbc.anchor = GridBagConstraints.WEST; // Align components to the left + gbc.gridx = 0; // All components will be in column 0 + gbc.gridy = GridBagConstraints.RELATIVE; // Components will be placed in consecutive rows + + // Add the "Use Natural Mouse" checkbox + add(useNaturalMouse, gbc); + + // Add a gap between "Use Natural Mouse" and the rest of the settings + gbc.insets = new Insets(20, 5, 5, 5); // Increase the top padding to create a larger gap + add(Box.createVerticalStrut(15), gbc); // Add a vertical gap of 15 pixels + + // Add the "Simulate Mistakes" checkbox + gbc.insets = new Insets(5, 5, 5, 5); // Reset padding for normal spacing + add(simulateMistakes, gbc); + + // Add the "Move Mouse Off Screen" checkbox + add(moveMouseOffScreen, gbc); + + // Add the "Move Mouse Randomly" checkbox + add(moveMouseRandomly, gbc); + + // Add the "Random Mouse Movement" label + add(moveMouseRandomlyChanceLabel, gbc); + + gbc.fill = GridBagConstraints.HORIZONTAL; + // Add the "Random Mouse Movement" slider + add(moveMouseRandomlyChance, gbc); + + setupActionListeners(); + } + + private void setupActionListeners() { + useNaturalMouse.addActionListener(e -> Rs2AntibanSettings.naturalMouse = useNaturalMouse.isSelected()); + simulateMistakes.addActionListener(e -> Rs2AntibanSettings.simulateMistakes = simulateMistakes.isSelected()); + moveMouseOffScreen.addActionListener(e -> Rs2AntibanSettings.moveMouseOffScreen = moveMouseOffScreen.isSelected()); + moveMouseRandomly.addActionListener(e -> Rs2AntibanSettings.moveMouseRandomly = moveMouseRandomly.isSelected()); + moveMouseRandomlyChance.addChangeListener(e -> { + Rs2AntibanSettings.moveMouseRandomlyChance = moveMouseRandomlyChance.getValue() / 100.0; + moveMouseRandomlyChanceLabel.setText("Random Mouse Movement (%): " + moveMouseRandomlyChance.getValue()); + }); + } + + public void updateValues() { + + useNaturalMouse.setSelected(Rs2AntibanSettings.naturalMouse); + simulateMistakes.setSelected(Rs2AntibanSettings.simulateMistakes); + moveMouseOffScreen.setSelected(Rs2AntibanSettings.moveMouseOffScreen); + moveMouseRandomly.setSelected(Rs2AntibanSettings.moveMouseRandomly); + moveMouseRandomlyChance.setValue((int) (Rs2AntibanSettings.moveMouseRandomlyChance * 100)); + moveMouseRandomlyChanceLabel.setText("Random Mouse Movement (%): " + moveMouseRandomlyChance.getValue()); + } +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/util/antiban/ui/NavigationPanel.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/util/antiban/ui/NavigationPanel.java new file mode 100644 index 0000000000..e95e4c7536 --- /dev/null +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/util/antiban/ui/NavigationPanel.java @@ -0,0 +1,52 @@ +package net.runelite.client.plugins.microbot.util.antiban.ui; + +import net.runelite.client.plugins.microbot.util.antiban.Rs2Antiban; + +import javax.swing.*; +import java.awt.*; +import java.util.Objects; + +public class NavigationPanel extends JPanel { + + public NavigationPanel(CardPanel cardPanel) { + setLayout(new BorderLayout()); + + // Create a navigation panel for the buttons + JPanel navPanel = new JPanel(); + navPanel.setLayout(new GridLayout(1, 6)); // 1 rows, 6 column + + // Create buttons with icons + JButton generalButton = createIconButton("general.png", "General"); + JButton activityButton = createIconButton("activity.png", "Activity"); + JButton profileButton = createIconButton("profile.png", "Profile"); + JButton mouseButton = createIconButton("mouse.png", "Mouse"); + JButton microBreakButton = createIconButton("microbreak.png", "MicroBreak"); + JButton cooldownButton = createIconButton("cooldown.png", "Cooldown"); + + // Add buttons to the navigation panel + navPanel.add(generalButton); + navPanel.add(activityButton); + navPanel.add(profileButton); + navPanel.add(mouseButton); + navPanel.add(microBreakButton); + navPanel.add(cooldownButton); + + // Add navigation panel to the NavigationPanel + add(navPanel, BorderLayout.CENTER); + + // Add action listeners to switch panels on button click + generalButton.addActionListener(e -> cardPanel.showPanel("General")); + activityButton.addActionListener(e -> cardPanel.showPanel("Activity")); + profileButton.addActionListener(e -> cardPanel.showPanel("Profile")); + mouseButton.addActionListener(e -> cardPanel.showPanel("Mouse")); + microBreakButton.addActionListener(e -> cardPanel.showPanel("MicroBreak")); + cooldownButton.addActionListener(e -> cardPanel.showPanel("Cooldown")); + } + + private JButton createIconButton(String iconPath, String altText) { + ImageIcon icon = new ImageIcon(Objects.requireNonNull(Rs2Antiban.class.getResource(iconPath))); + JButton button = new JButton(icon); + button.setToolTipText(altText); // Set alt text for accessibility + return button; + } +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/util/antiban/ui/ProfilePanel.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/util/antiban/ui/ProfilePanel.java new file mode 100644 index 0000000000..734cf815a7 --- /dev/null +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/util/antiban/ui/ProfilePanel.java @@ -0,0 +1,50 @@ +package net.runelite.client.plugins.microbot.util.antiban.ui; + +import net.runelite.client.plugins.microbot.util.antiban.Rs2AntibanSettings; +import net.runelite.client.ui.ColorScheme; + +import javax.swing.*; +import java.awt.*; + +public class ProfilePanel extends JPanel { + + private final JCheckBox enableProfileSwitching = new JCheckBox("Enable Profile Switching"); + private final JCheckBox adjustForTimeOfDay = new JCheckBox("Adjust For Time Of Day"); + private final JCheckBox simulatePlaySchedule = new JCheckBox("Simulate Play Schedule"); + + public ProfilePanel() { + // Set the layout manager for the panel to GridBagLayout + setLayout(new GridBagLayout()); + setBackground(ColorScheme.DARK_GRAY_HOVER_COLOR); + // Create a GridBagConstraints object to define the layout settings for each component + GridBagConstraints gbc = new GridBagConstraints(); + gbc.insets = new Insets(5, 5, 5, 5); // Padding around components + gbc.anchor = GridBagConstraints.WEST; // Align components to the left + gbc.gridx = 0; // All components will be in column 0 + gbc.gridy = GridBagConstraints.RELATIVE; // Components will be placed in consecutive rows + + // Add the "Enable Profile Switching" checkbox + add(enableProfileSwitching, gbc); + + // Add the "Adjust For Time Of Day" checkbox + add(adjustForTimeOfDay, gbc); + + // Add the "Simulate Play Schedule" checkbox + add(simulatePlaySchedule, gbc); + + setupActionListeners(); + } + + private void setupActionListeners() { + enableProfileSwitching.addActionListener(e -> Rs2AntibanSettings.profileSwitching = enableProfileSwitching.isSelected()); + adjustForTimeOfDay.addActionListener(e -> Rs2AntibanSettings.timeOfDayAdjust = adjustForTimeOfDay.isSelected()); + simulatePlaySchedule.addActionListener(e -> Rs2AntibanSettings.playSchedule = simulatePlaySchedule.isSelected()); + + } + + public void updateValues() { + enableProfileSwitching.setSelected(Rs2AntibanSettings.profileSwitching); + adjustForTimeOfDay.setSelected(Rs2AntibanSettings.timeOfDayAdjust); + simulatePlaySchedule.setSelected(Rs2AntibanSettings.playSchedule); + } +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/util/antiban/ui/UiHelper.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/util/antiban/ui/UiHelper.java new file mode 100644 index 0000000000..bf897c7e7e --- /dev/null +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/util/antiban/ui/UiHelper.java @@ -0,0 +1,14 @@ +package net.runelite.client.plugins.microbot.util.antiban.ui; + +import javax.swing.*; + +public class UiHelper { + public static void setupSlider(JSlider slider, int majorTickSpacing, int max, int minorTickSpacing) { + slider.setMajorTickSpacing(majorTickSpacing); + slider.setMinorTickSpacing(minorTickSpacing); + slider.setPaintTicks(true); + slider.setPaintLabels(true); + slider.setMinimum(0); + slider.setMaximum(max); + } +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/util/bank/Rs2Bank.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/util/bank/Rs2Bank.java index 8d015f1fc7..4ce8162fe2 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/util/bank/Rs2Bank.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/util/bank/Rs2Bank.java @@ -37,6 +37,7 @@ import static net.runelite.api.widgets.ComponentID.BANK_ITEM_CONTAINER; import static net.runelite.client.plugins.microbot.Microbot.updateItemContainer; import static net.runelite.client.plugins.microbot.util.Global.*; +import static net.runelite.client.plugins.microbot.util.inventory.Rs2Inventory.itemBounds; @SuppressWarnings("unused") @Slf4j @@ -68,7 +69,7 @@ public static void invokeMenu(int entryIndex, Rs2Item rs2Item) { if (container == ComponentID.BANK_INVENTORY_ITEM_CONTAINER) { identifier = identifier + 1; } - Microbot.doInvoke(new NewMenuEntry(rs2Item.slot, container, MenuAction.CC_OP.getId(), identifier, rs2Item.id, rs2Item.name), new Rectangle(1, 1, Microbot.getClient().getCanvasWidth(), Microbot.getClient().getCanvasHeight())); + Microbot.doInvoke(new NewMenuEntry(rs2Item.slot, container, MenuAction.CC_OP.getId(), identifier, rs2Item.id, rs2Item.name), (itemBounds(rs2Item) == null) ? new Rectangle(1, 1) : itemBounds(rs2Item)); // MenuEntryImpl(getOption=Wear, getTarget=+ * The randomness generated by this class is intended to mimic the variability in human + * actions, reducing the predictability of the bot's behavior and avoiding detection + * by anti-cheat systems. + *
+ * + *+ * // Example: Generate a random point on the screen within a rectangle, biased towards the center + * Point randomPoint = Rs2Random.randomPoint(new Rectangle(100, 100, 300, 300), 2.0); + * + * // Example: Simulate a wait with random duration biased towards the middle of the range + * Rs2Random.wait(1000, 2000, Rs2Random.EWaitDir.wdMean); + *+ * + *
+ * DeviationProvider implementation should be immutable. + */ +public interface DeviationProvider { + + /** + * Gets the deviation for current trajectory. Deviation is an offset from the original straight trajectory. + *
+ * Deviation is different from the Noise because it works like a mathematical function, the resulting + * Point is added to single trajectory point and it will not have any effect in the next + * mouse movement step, making it easy to implement this as a formula based on the input parameters. + * e.g the something like 'deviation = totalDistanceInPixels / completionFraction', resulting in smooth movement. + * (Don't actually use this formula), 'Noise' is generating an offset from the original trajectory and is accumulating. + *
+ * As deviation should be deterministic and return same result for same parameters, it should not include Random + * behaviour, thus Random is not included as a parameter. + *
+ * It is recommended that deviation is decreasing when completionFraction nears 1, but MouseMotion itself
+ * also makes sure that the effect of deviation is reduced when the mouse is nearing its destination.
+ *
+ * @param totalDistanceInPixels the total pixels between target and mouse initial position
+ * @param completionFraction the completed fraction of mouse movement total distance, value from 0...1 (0;1]
+ * @return a point which describes how much the mouse is going to deviate from the straight trajectory between
+ * target and initial position. This is not the final deviation of the mouse as MouseMotion will randomly decide
+ * to either amplify or decrease it over the whole mouse movement, making the resulting arc stand out more or less,
+ * or is flipped negatively.
+ * @see NoiseProvider
+ */
+ DoublePoint getDeviation(double totalDistanceInPixels, double completionFraction);
+}
diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/util/mouse/naturalmouse/api/MouseInfoAccessor.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/util/mouse/naturalmouse/api/MouseInfoAccessor.java
new file mode 100644
index 0000000000..cde30447ca
--- /dev/null
+++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/util/mouse/naturalmouse/api/MouseInfoAccessor.java
@@ -0,0 +1,18 @@
+package net.runelite.client.plugins.microbot.util.mouse.naturalmouse.api;
+
+import java.awt.*;
+
+/**
+ * Abstraction for getting mouse position.
+ */
+public interface MouseInfoAccessor {
+ /**
+ * Get the current mouse position.
+ * NB, for optimization reasons this method might return the same Point instance, but is not quaranteed to.
+ * It is recommended not to save this Point anywhere as it may or may not change its coordinates.
+ *
+ * @return the current mouse position
+ */
+
+ Point getMousePosition();
+}
diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/util/mouse/naturalmouse/api/MouseMotion.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/util/mouse/naturalmouse/api/MouseMotion.java
new file mode 100644
index 0000000000..d8f7abab8b
--- /dev/null
+++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/util/mouse/naturalmouse/api/MouseMotion.java
@@ -0,0 +1,203 @@
+package net.runelite.client.plugins.microbot.util.mouse.naturalmouse.api;
+
+import net.runelite.client.plugins.microbot.util.mouse.naturalmouse.support.DoublePoint;
+import net.runelite.client.plugins.microbot.util.mouse.naturalmouse.support.Flow;
+import net.runelite.client.plugins.microbot.util.mouse.naturalmouse.support.MouseMotionNature;
+import net.runelite.client.plugins.microbot.util.mouse.naturalmouse.support.mousemotion.MouseMovement;
+import net.runelite.client.plugins.microbot.util.mouse.naturalmouse.support.mousemotion.MovementFactory;
+import net.runelite.client.plugins.microbot.util.mouse.naturalmouse.util.MathUtil;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.awt.*;
+import java.util.ArrayDeque;
+import java.util.Random;
+
+/**
+ * Contains instructions to move cursor smoothly to the destination coordinates from where ever the cursor
+ * currently is. The class is reusable, meaning user can keep calling it and the cursor returns in a random,
+ * but reliable way, described in this class, to the destination.
+ */
+public class MouseMotion {
+ private static final Logger log = LoggerFactory.getLogger(MouseMotion.class);
+ private static final int SLEEP_AFTER_ADJUSTMENT_MS = 2;
+ private final int minSteps;
+ private final int effectFadeSteps;
+ private final int reactionTimeBaseMs;
+ private final int reactionTimeVariationMs;
+ private final double timeToStepsDivider;
+ private final Dimension screenSize;
+ private final SystemCalls systemCalls;
+ private final DeviationProvider deviationProvider;
+ private final NoiseProvider noiseProvider;
+ private final SpeedManager speedManager;
+ private final OvershootManager overshootManager;
+ private final int xDest;
+ private final int yDest;
+ private final Random random;
+ private final MouseInfoAccessor mouseInfo;
+ private Point mousePosition;
+
+ /**
+ * @param nature the nature that defines how mouse is moved
+ * @param xDest the x-coordinate of destination
+ * @param yDest the y-coordinate of destination
+ * @param random the random used for unpredictability
+ */
+ public MouseMotion(MouseMotionNature nature, Random random, int xDest, int yDest) {
+ this.deviationProvider = nature.getDeviationProvider();
+ this.noiseProvider = nature.getNoiseProvider();
+ this.systemCalls = nature.getSystemCalls();
+ this.screenSize = systemCalls.getScreenSize();
+ this.xDest = limitByScreenWidth(xDest);
+ this.yDest = limitByScreenHeight(yDest);
+ this.random = random;
+ this.mouseInfo = nature.getMouseInfo();
+ this.speedManager = nature.getSpeedManager();
+ this.timeToStepsDivider = nature.getTimeToStepsDivider();
+ this.minSteps = nature.getMinSteps();
+ this.effectFadeSteps = nature.getEffectFadeSteps();
+ this.reactionTimeBaseMs = nature.getReactionTimeBaseMs();
+ this.reactionTimeVariationMs = nature.getReactionTimeVariationMs();
+ this.overshootManager = nature.getOvershootManager();
+ }
+
+ /**
+ * Blocking call, starts to move the cursor to the specified location from where it currently is.
+ *
+ * @throws InterruptedException when interrupted
+ */
+ public void move() throws InterruptedException {
+ move((x, y) ->
+ {
+ });
+ }
+
+ /**
+ * Blocking call, starts to move the cursor to the specified location from where it currently is.
+ *
+ * @param observer Provide observer if you are interested receiving the location of mouse on every step
+ * @throws InterruptedException when interrupted
+ */
+ public void move(MouseMotionObserver observer) throws InterruptedException {
+ updateMouseInfo();
+
+ MovementFactory movementFactory = new MovementFactory(xDest, yDest, speedManager, overshootManager, screenSize);
+ ArrayDeque
+ * NoiseProvider implementation should be immutable.
+ */
+public interface NoiseProvider {
+ /**
+ * Noise is offset from the original trajectory, simulating user and physical errors on mouse movement.
+ *
+ * Noise is accumulating, so on average it should create an equal chance of either positive or negative movement
+ * on each axis, otherwise the mouse movement will always be slightly offset to single direction.
+ *
+ * Deviation from DeviationProvider is different from the Noise
+ * because it works like a mathematical function and is not accumulating.
+ *
+ * Not every step needs to add noise, use randomness to only add noise sometimes, otherwise return Point(0, 0).
+ *
+ * During the final steps of mouse movement, the effect of noise is gradually reduced, so the mouse
+ * would finish on the intended pixel smoothly, thus the implementation of this class can safely ignore
+ * and not know the beginning and end of the movement.
+ *
+ * @param random use this to generate randomness in the offset
+ * @param xStepSize the step size that is taken horizontally
+ * @param yStepSize the step size that is taken vertically
+ * @return a point which describes how much the mouse offset is increased or decreased this step.
+ * This value must not include the parameters xStepSize and yStepSize. For no change in noise just return (0,0).
+ * @see DeviationProvider
+ */
+ DoublePoint getNoise(Random random, double xStepSize, double yStepSize);
+}
diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/util/mouse/naturalmouse/api/OvershootManager.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/util/mouse/naturalmouse/api/OvershootManager.java
new file mode 100644
index 0000000000..119d615884
--- /dev/null
+++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/util/mouse/naturalmouse/api/OvershootManager.java
@@ -0,0 +1,49 @@
+package net.runelite.client.plugins.microbot.util.mouse.naturalmouse.api;
+
+import net.runelite.client.plugins.microbot.util.mouse.naturalmouse.support.Flow;
+
+import java.awt.*;
+
+/**
+ * Overshoots provide a realistic way to simulate user trying to reach the destination with mouse, but miss.
+ * Points around the destination are produced which will be hit before the mouse hits the real destination.
+ * If overshoot happens to match the target, then overshooting is cancelled and real destination will be reached.
+ */
+public interface OvershootManager {
+ /**
+ * Get the maximum amount of overshoots the cursor does before reaching its final destination.
+ *
+ * @param flow the flow which is planned to be used to reach the target.
+ * (If returned overshoots > 0, then a new flow will be calculated for each overshoot.).
+ * This flow could be analyzed if overshooting is suitable. It is not available
+ * as a parameter in overshootAmount calculation, because flow itself is calculated
+ * from the movement distance, which is dependent on the overshoot amount.
+ * @param mouseMovementMs the planned time for reaching the real target
+ * @param distance the distance between mouse position and real target
+ * @return the number of maximum overshoots used or 0 if no overshoots
+ */
+ int getOvershoots(Flow flow, long mouseMovementMs, double distance);
+
+ /**
+ * Returns the overshoot amount which will be added to real target, thus getting the overshoot target.
+ *
+ * @param distanceToRealTargetX distance to real target X-coordinate
+ * @param distanceToRealTargetY distance to real target Y-coordinate
+ * @param mouseMovementMs the time planned for reaching the real target
+ * @param overshootsRemaining the amount of overshoots remaining, current included.
+ * Values from (n to 1), where n >= 1
+ * @return the amount which will be added to real target, thus getting the overshoot target.
+ */
+ Point getOvershootAmount(double distanceToRealTargetX, double distanceToRealTargetY, long mouseMovementMs, int overshootsRemaining);
+
+ /**
+ * Once the mouse reaches the overshoot target, new trajectory with new speed is calculated for next target
+ * (can be real or overshoot target, if the next target is real target, the overshootsRemaining value is 0)
+ *
+ * @param mouseMovementMs the last mouse movement in ms
+ * @param overshootsRemaining the amount of overshoots remaining, including this.
+ * Values from (n to 0), where n >= 0
+ * @return the next mouse movement time in ms
+ */
+ long deriveNextMouseMovementTimeMs(long mouseMovementMs, int overshootsRemaining);
+}
diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/util/mouse/naturalmouse/api/SpeedManager.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/util/mouse/naturalmouse/api/SpeedManager.java
new file mode 100644
index 0000000000..a3833f2132
--- /dev/null
+++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/util/mouse/naturalmouse/api/SpeedManager.java
@@ -0,0 +1,20 @@
+package net.runelite.client.plugins.microbot.util.mouse.naturalmouse.api;
+
+import net.runelite.client.plugins.microbot.util.mouse.naturalmouse.support.Flow;
+import net.runelite.client.plugins.microbot.util.mouse.naturalmouse.util.Pair;
+
+/**
+ * SpeedManager controls how long does it take to complete a mouse movement and within that
+ * time how slow or fast the cursor is moving at a particular moment, the flow.
+ * Flow controls how jagged or smooth, accelerating or decelerating, the movement is.
+ */
+public interface SpeedManager {
+
+ /**
+ * Get the SpeedFlow object, which contains Flow and planned time for mouse movement in ms.
+ *
+ * @param distance the distance from where the cursor is now to the destination point *
+ * @return the SpeedFlow object, which details are a SpeedManager implementation decision.
+ */
+ Pair Moves the mouse to specified pixel using the provided Robot. It seems there is a certain delay, measurable in less than milliseconds,
+ * before the mouse actually ends up on the requested pixel when using a Robot class.
+ * this usually isn't a problem, but when we ask the mouse position right after this call,
+ * there's extremely low but real chance we get wrong information back. I didn't add sleep
+ * here as it would cause overhead to sleep always, even when we don't instantly use
+ * the mouse position, but just acknowledged the issue with this warning.
+ * (Use fast unrestricted loop of Robot movement and checking the position after every move to invoke the issue.)
+ * This is an unintuitive method, because it turns out that, for example, array size of 3
+ * scales better to array size of 5 than it does to array size of 6. [1, 2, 3] can be
+ * easily scaled to [1, 1.5, 2, 2.5, 3], but it's not possible without recalculating middle number (2)
+ * with array size of 6, simplistic solutions quickly would run to trouble like this [1, 1.5, 2, 2.5, 3, (3)? ]
+ * or maybe: [1, 1.5, 2, 2.5, ..., 3 ]. The correct solution would correctly scale the middle numbers
+ *
+ * @param flow the original flow
+ * @param targetLength the resulting flow length
+ * @return the resulting flow
+ */
+ public static double[] stretchFlow(double[] flow, int targetLength) {
+ return stretchFlow(flow, targetLength, a -> a);
+ }
+
+ /**
+ * Stretch flow to longer length. Tries to fill the caps with averages.
+ *
+ * This is an unintuitive method, because it turns out that, for example, array size of 3
+ * scales better to array size of 5 than it does to array size of 6. [1, 2, 3] can be
+ * easily scaled to [1, 1.5, 2, 2.5, 3], but it's not possible without recalculating middle number (2)
+ * with array size of 6, simplistic solutions quickly would run to trouble like this [1, 1.5, 2, 2.5, 3, (3)? ]
+ * or maybe: [1, 1.5, 2, 2.5, ..., 3 ]. The correct solution would correctly scale the middle numbers
+ * over several indexes.
+ *
+ * @param flow the original flow
+ * @param targetLength the resulting flow length
+ * @param modifier modifies the resulting values, you can use this to provide noise or amplify
+ * the flow characteristics.
+ * @return the resulting flow
+ */
+ public static double[] stretchFlow(double[] flow, int targetLength, FunctionStereotypical granny using a computer with non-optical mouse from the 90s.
+ * Low speed, variating flow, lots of noise in movement.
+ *
+ * @return the factory
+ */
+ public static MouseMotionFactory createGrannyMotionFactory() {
+ return createGrannyMotionFactory(new DefaultMouseMotionNature());
+ }
+
+ /**
+ * Stereotypical granny using a computer with non-optical mouse from the 90s.
+ * Low speed, variating flow, lots of noise in movement.
+ *
+ * @param nature the nature for the template to be configured on
+ * @return the factory
+ */
+ public static MouseMotionFactory createGrannyMotionFactory(MouseMotionNature nature) {
+ MouseMotionFactory factory = new MouseMotionFactory(nature);
+ ListRobotic fluent movement.
+ * Custom speed, constant movement, no mistakes, no overshoots.
+ *
+ * @param motionTimeMsPer100Pixels approximate time a movement takes per 100 pixels of travelling
+ * @return the factory
+ */
+ public static MouseMotionFactory createDemoRobotMotionFactory(long motionTimeMsPer100Pixels) {
+ return createDemoRobotMotionFactory(new DefaultMouseMotionNature(), motionTimeMsPer100Pixels);
+ }
+
+ /**
+ * Robotic fluent movement.
+ * Custom speed, constant movement, no mistakes, no overshoots.
+ *
+ * @param nature the nature for the template to be configured on
+ * @param motionTimeMsPer100Pixels approximate time a movement takes per 100 pixels of travelling
+ * @return the factory
+ */
+ public static MouseMotionFactory createDemoRobotMotionFactory(
+ MouseMotionNature nature, long motionTimeMsPer100Pixels
+ ) {
+ MouseMotionFactory factory = new MouseMotionFactory(nature);
+ final Flow flow = new Flow(FlowTemplates.constantSpeed());
+ double timePerPixel = motionTimeMsPer100Pixels / 100d;
+ SpeedManager manager = distance -> new Pair<>(flow, (long) (timePerPixel * distance));
+ factory.setDeviationProvider((totalDistanceInPixels, completionFraction) -> DoublePoint.ZERO);
+ factory.setNoiseProvider(((random, xStepSize, yStepSize) -> DoublePoint.ZERO));
+
+ DefaultOvershootManager overshootManager = (DefaultOvershootManager) factory.getOvershootManager();
+ overshootManager.setOvershoots(0);
+
+ factory.setSpeedManager(manager);
+ return factory;
+ }
+
+ /**
+ * Gamer with fast reflexes and quick mouse movements.
+ * Quick movement, low noise, some deviation, lots of overshoots.
+ *
+ * @return the factory
+ */
+ public static MouseMotionFactory createNormalGamerMotionFactory() {
+ return createNormalGamerMotionFactory(new DefaultMouseMotionNature());
+ }
+
+ /**
+ * Gamer with fast reflexes and quick mouse movements.
+ * Quick movement, low noise, some deviation, lots of overshoots.
+ *
+ * @param nature the nature for the template to be configured on
+ * @return the factory
+ */
+ public static MouseMotionFactory createNormalGamerMotionFactory(MouseMotionNature nature) {
+ int initialBaseTime = 150;
+ int maxBaseTime = 200;
+ int currentBaseTime = initialBaseTime;
+ if (Rs2AntibanSettings.simulateFatigue)
+ currentBaseTime = (Rs2Antiban.mouseFatigue.calculateBaseTimeWithNoise(currentBaseTime, maxBaseTime));
+ MouseMotionFactory factory = new MouseMotionFactory(nature);
+ ListGamer with fast reflexes and quick mouse movements.
+ * Quick movement, low noise, some deviation, lots of overshoots.
+ *
+ * @return the factory
+ */
+ public static MouseMotionFactory createFastGamerMotionFactory() {
+ return createFastGamerMotionFactory(new DefaultMouseMotionNature());
+ }
+
+ /**
+ * Gamer with fast reflexes and quick mouse movements.
+ * Quick movement, low noise, some deviation, lots of overshoots.
+ *
+ * @param nature the nature for the template to be configured on
+ * @return the factory
+ */
+ public static MouseMotionFactory createFastGamerMotionFactory(MouseMotionNature nature) {
+ int initialBaseTime = 120;
+ int maxBaseTime = 170;
+ int currentBaseTime = initialBaseTime;
+ if (Rs2AntibanSettings.simulateFatigue)
+ currentBaseTime = (Rs2Antiban.mouseFatigue.calculateBaseTimeWithNoise(currentBaseTime, maxBaseTime));
+ MouseMotionFactory factory = new MouseMotionFactory(nature);
+ ListStandard computer user with average speed and movement mistakes
+ * medium noise, medium speed, medium noise and deviation.
+ *
+ * @return the factory
+ */
+ public static MouseMotionFactory createAverageComputerUserMotionFactory() {
+ return createAverageComputerUserMotionFactory(new DefaultMouseMotionNature());
+ }
+
+ /**
+ * Standard computer user with average speed and movement mistakes
+ * medium noise, medium speed, medium noise and deviation.
+ *
+ * @param nature the nature for the template to be configured on
+ * @return the factory
+ */
+ public static MouseMotionFactory createAverageComputerUserMotionFactory(MouseMotionNature nature) {
+ MouseMotionFactory factory = new MouseMotionFactory(nature);
+ List