diff --git a/runelite-client/pom.xml b/runelite-client/pom.xml index 88d57cccf4..8b40e4c17d 100644 --- a/runelite-client/pom.xml +++ b/runelite-client/pom.xml @@ -56,12 +56,6 @@ RoaringBitmap 0.9.44 - - - com.google.archivepatcher - archive-patch-applier - 1.0.4 - org.benf diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/camera/CameraPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/camera/CameraPlugin.java index 9689414f7f..cb4d143b24 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/camera/CameraPlugin.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/camera/CameraPlugin.java @@ -29,23 +29,8 @@ import com.google.common.annotations.VisibleForTesting; import com.google.common.primitives.Ints; import com.google.inject.Provides; -import java.awt.event.KeyEvent; -import java.awt.event.MouseEvent; -import javax.inject.Inject; -import javax.swing.SwingUtilities; -import net.runelite.api.Client; -import net.runelite.api.MenuAction; -import net.runelite.api.MenuEntry; -import net.runelite.api.ScriptID; -import net.runelite.api.SettingID; -import net.runelite.api.VarClientInt; -import net.runelite.api.VarPlayer; -import net.runelite.api.events.BeforeRender; -import net.runelite.api.events.ClientTick; -import net.runelite.api.events.FocusChanged; -import net.runelite.api.events.ScriptCallbackEvent; -import net.runelite.api.events.ScriptPreFired; -import net.runelite.api.events.WidgetLoaded; +import net.runelite.api.*; +import net.runelite.api.events.*; import net.runelite.api.widgets.ComponentID; import net.runelite.api.widgets.InterfaceID; import net.runelite.api.widgets.JavaScriptCallback; @@ -63,6 +48,11 @@ import net.runelite.client.ui.overlay.tooltip.Tooltip; import net.runelite.client.ui.overlay.tooltip.TooltipManager; +import javax.inject.Inject; +import javax.swing.*; +import java.awt.event.KeyEvent; +import java.awt.event.MouseEvent; + @PluginDescriptor( name = "Camera", description = "Expands zoom limit, provides vertical camera, and remaps mouse input keys", @@ -274,7 +264,7 @@ public void keyTyped(KeyEvent e) @Override public void keyPressed(KeyEvent e) { - if (e.getKeyCode() == KeyEvent.VK_CONTROL) + if (e.getKeyCode() == KeyEvent.VK_F1) { controlDown = true; } diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/devtools/DevToolsPanel.java b/runelite-client/src/main/java/net/runelite/client/plugins/devtools/DevToolsPanel.java index 2010ede138..2a8f00adc4 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/devtools/DevToolsPanel.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/devtools/DevToolsPanel.java @@ -125,6 +125,8 @@ private JPanel createOptionsPanel() container.add(plugin.getValidMovement()); container.add(plugin.getMovementFlags()); container.add(plugin.getInteracting()); + container.add(plugin.getMouseClick()); + container.add(plugin.getMouseMovement()); container.add(plugin.getExamine()); container.add(plugin.getDetachedCamera()); diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/devtools/DevToolsPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/devtools/DevToolsPlugin.java index ca9ad37d68..fc4161f527 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/devtools/DevToolsPlugin.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/devtools/DevToolsPlugin.java @@ -127,10 +127,50 @@ public class DevToolsPlugin extends Plugin @Inject private ChatMessageManager chatMessageManager; - @Inject private DevToolsConfig config; + private final HotkeyListener swingInspectorHotkeyListener = new HotkeyListener(() -> config.swingInspectorHotkey()) { + Object inspector; + @Override + public void hotkeyPressed() { + Window window = KeyboardFocusManager.getCurrentKeyboardFocusManager().getActiveWindow(); + try { + if (inspector == null) { + JRootPane rootPane = ((RootPaneContainer) window).getRootPane(); + FlatInspector fi = new FlatInspector(rootPane); + fi.setEnabled(true); + inspector = fi; + fi.addPropertyChangeListener(ev -> + { + if ("enabled".equals(ev.getPropertyName()) && !fi.isEnabled() && inspector == ev.getSource()) { + inspector = null; + } + }); + } else { + ((FlatInspector) inspector).setEnabled(false); + } + } catch (LinkageError | Exception e) { + log.warn("unable to open swing inspector", e); + JOptionPane.showMessageDialog(window, "The swing inspector is not available."); + } + } + }; + private final AWTEventListener swingInspectorKeyListener = rawEv -> + { + if (rawEv instanceof KeyEvent) { + KeyEvent kev = (KeyEvent) rawEv; + if (kev.getID() == KeyEvent.KEY_PRESSED) { + swingInspectorHotkeyListener.keyPressed(kev); + } else if (kev.getID() == KeyEvent.KEY_RELEASED) { + swingInspectorHotkeyListener.keyReleased(kev); + } + } + }; + @Inject + private MicrobotClickOverlay microbotClickOverlay; + @Inject + private MicrobotMouseOverlay microbotMouseOverlay; private DevToolsButton players; private DevToolsButton npcs; private DevToolsButton inventory; @@ -163,61 +203,10 @@ public class DevToolsPlugin extends Plugin private DevToolsButton shell; private DevToolsButton menus; private DevToolsButton uiDefaultsInspector; + private DevToolsButton mouseClick; + private DevToolsButton mouseMovement; private NavigationButton navButton; - private final HotkeyListener swingInspectorHotkeyListener = new HotkeyListener(() -> config.swingInspectorHotkey()) - { - Object inspector; - - @Override - public void hotkeyPressed() - { - Window window = KeyboardFocusManager.getCurrentKeyboardFocusManager().getActiveWindow(); - try - { - if (inspector == null) - { - JRootPane rootPane = ((RootPaneContainer) window).getRootPane(); - FlatInspector fi = new FlatInspector(rootPane); - fi.setEnabled(true); - inspector = fi; - fi.addPropertyChangeListener(ev -> - { - if ("enabled".equals(ev.getPropertyName()) && !fi.isEnabled() && inspector == ev.getSource()) - { - inspector = null; - } - }); - } - else - { - ((FlatInspector) inspector).setEnabled(false); - } - } - catch (LinkageError | Exception e) - { - log.warn("unable to open swing inspector", e); - JOptionPane.showMessageDialog(window, "The swing inspector is not available."); - } - } - }; - - private final AWTEventListener swingInspectorKeyListener = rawEv -> - { - if (rawEv instanceof KeyEvent) - { - KeyEvent kev = (KeyEvent) rawEv; - if (kev.getID() == KeyEvent.KEY_PRESSED) - { - swingInspectorHotkeyListener.keyPressed(kev); - } - else if (kev.getID() == KeyEvent.KEY_RELEASED) - { - swingInspectorHotkeyListener.keyReleased(kev); - } - } - }; - @Provides DevToolsConfig provideConfig(ConfigManager configManager) { @@ -267,6 +256,9 @@ protected void startUp() throws Exception uiDefaultsInspector = new DevToolsButton("Swing Defaults"); + mouseClick = new DevToolsButton("Bot Clicks"); + mouseMovement = new DevToolsButton("Bot Mouse"); + overlayManager.add(overlay); overlayManager.add(locationOverlay); overlayManager.add(sceneOverlay); @@ -274,6 +266,8 @@ protected void startUp() throws Exception overlayManager.add(worldMapLocationOverlay); overlayManager.add(mapRegionOverlay); overlayManager.add(soundEffectOverlay); + overlayManager.add(microbotClickOverlay); + overlayManager.add(microbotMouseOverlay); final DevToolsPanel panel = injector.getInstance(DevToolsPanel.class); @@ -304,6 +298,8 @@ protected void shutDown() throws Exception overlayManager.remove(worldMapLocationOverlay); overlayManager.remove(mapRegionOverlay); overlayManager.remove(soundEffectOverlay); + overlayManager.remove(microbotClickOverlay); + overlayManager.remove(microbotMouseOverlay); clientToolbar.removeNavigation(navButton); Toolkit.getDefaultToolkit().removeAWTEventListener(swingInspectorKeyListener); } diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/devtools/MicrobotClickOverlay.java b/runelite-client/src/main/java/net/runelite/client/plugins/devtools/MicrobotClickOverlay.java new file mode 100644 index 0000000000..0847b65880 --- /dev/null +++ b/runelite-client/src/main/java/net/runelite/client/plugins/devtools/MicrobotClickOverlay.java @@ -0,0 +1,56 @@ +package net.runelite.client.plugins.devtools; + +import net.runelite.api.Client; +import net.runelite.client.plugins.microbot.Microbot; +import net.runelite.client.ui.overlay.Overlay; +import net.runelite.client.ui.overlay.OverlayLayer; +import net.runelite.client.ui.overlay.OverlayPosition; +import net.runelite.client.ui.overlay.OverlayUtil; + +import javax.inject.Inject; +import java.awt.*; + +public class MicrobotClickOverlay extends Overlay { + private final Client client; + private final DevToolsPlugin plugin; + + @Inject + MicrobotClickOverlay(Client client, DevToolsPlugin plugin) { + this.client = client; + this.plugin = plugin; + setPosition(OverlayPosition.DYNAMIC); + setLayer(OverlayLayer.ABOVE_WIDGETS); + setPriority(Overlay.PRIORITY_LOW); + } + + @Override + public Dimension render(Graphics2D g) { + if (plugin.getMouseClick().isActive()) { + + g.setFont(new Font("Tahoma", Font.BOLD, 18)); + + // Get the FontMetrics for the current font + FontMetrics metrics = g.getFontMetrics(g.getFont()); + + // Get the width and height of the character + int charWidth = metrics.stringWidth("X"); + int charHeight = metrics.getAscent(); // ascent gives the height of the character above the baseline + + int x = Microbot.getMouse().getLastClick().getX() - (charWidth / 2); + int y = Microbot.getMouse().getLastClick().getY() + (charHeight / 2); + + OverlayUtil.renderTextLocation(g, new net.runelite.api.Point(x, y), "X", Color.WHITE); + + x = Microbot.getMouse().getLastClick2().getX() - (charWidth / 2); + y = Microbot.getMouse().getLastClick2().getY() + (charHeight / 2); + + OverlayUtil.renderTextLocation(g, new net.runelite.api.Point(x, y), "X", Color.GREEN); + + + + } + + return null; + } +} + diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/devtools/MicrobotMouseOverlay.java b/runelite-client/src/main/java/net/runelite/client/plugins/devtools/MicrobotMouseOverlay.java new file mode 100644 index 0000000000..119f777ebc --- /dev/null +++ b/runelite-client/src/main/java/net/runelite/client/plugins/devtools/MicrobotMouseOverlay.java @@ -0,0 +1,74 @@ +package net.runelite.client.plugins.devtools; + +import net.runelite.api.Client; +import net.runelite.client.plugins.microbot.Microbot; +import net.runelite.client.ui.overlay.Overlay; +import net.runelite.client.ui.overlay.OverlayLayer; +import net.runelite.client.ui.overlay.OverlayPosition; +import net.runelite.client.ui.overlay.OverlayUtil; + +import javax.inject.Inject; +import java.awt.*; +import java.awt.geom.Path2D; + +public class MicrobotMouseOverlay extends Overlay { + private final Client client; + private final DevToolsPlugin plugin; + + @Inject + MicrobotMouseOverlay(Client client, DevToolsPlugin plugin) { + this.client = client; + this.plugin = plugin; + setPosition(OverlayPosition.DYNAMIC); + setLayer(OverlayLayer.ABOVE_WIDGETS); + setPriority(Overlay.PRIORITY_LOW); + } + + @Override + public Dimension render(Graphics2D g) { + if (plugin.getMouseMovement().isActive()) { + if (!Microbot.getMouse().getTimer().isRunning()) { + Microbot.getMouse().getTimer().start(); + } + //g.setFont(new Font("Tahoma", Font.BOLD, 18)); + g.setFont(g.getFont().deriveFont(40.0f)); + // Get the FontMetrics for the current font + FontMetrics metrics = g.getFontMetrics(g.getFont()); + +// Get the width and height of the character + int charWidth = metrics.stringWidth("⊹"); + int charHeight = metrics.getAscent(); // ascent gives the height of the character above the baseline + +// Calculate the new position + int x = Microbot.getMouse().getLastMove().getX() - (charWidth / 2); + int y = Microbot.getMouse().getLastMove().getY() + (charHeight / 2); + + OverlayUtil.renderTextLocation(g, new net.runelite.api.Point(x, y), "⊹", Microbot.getMouse().getRainbowColor()); + + g.setStroke(new BasicStroke(3)); + g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); + var points = Microbot.getMouse().getPoints(); + if (points.size() > 1) { + Path2D path = new Path2D.Double(); + net.runelite.api.Point firstPoint = points.getFirst(); + path.moveTo(firstPoint.getX(), firstPoint.getY()); + + for (int i = 1; i < points.size(); i++) { + net.runelite.api.Point p = points.get(i); + path.lineTo(p.getX(), p.getY()); + g.setColor(Microbot.getMouse().getRainbowColor()); + } + + g.draw(path); + } + // draw trail of mouse movements + + } else { + Microbot.getMouse().getPoints().clear(); + Microbot.getMouse().getTimer().stop(); + } + + return null; + } +} + diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/construction2/Construction2Config.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/GeoffPlugins/construction2/Construction2Config.java similarity index 97% rename from runelite-client/src/main/java/net/runelite/client/plugins/microbot/construction2/Construction2Config.java rename to runelite-client/src/main/java/net/runelite/client/plugins/microbot/GeoffPlugins/construction2/Construction2Config.java index 0401fbdb4a..52696f9309 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/construction2/Construction2Config.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/GeoffPlugins/construction2/Construction2Config.java @@ -1,4 +1,4 @@ -package net.runelite.client.plugins.microbot.construction2; +package net.runelite.client.plugins.microbot.GeoffPlugins.construction2; import net.runelite.api.ItemID; import net.runelite.client.config.Config; diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/construction2/Construction2Overlay.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/GeoffPlugins/construction2/Construction2Overlay.java similarity index 90% rename from runelite-client/src/main/java/net/runelite/client/plugins/microbot/construction2/Construction2Overlay.java rename to runelite-client/src/main/java/net/runelite/client/plugins/microbot/GeoffPlugins/construction2/Construction2Overlay.java index 4f1d7dee29..821e765ae4 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/construction2/Construction2Overlay.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/GeoffPlugins/construction2/Construction2Overlay.java @@ -1,6 +1,5 @@ -package net.runelite.client.plugins.microbot.construction2; +package net.runelite.client.plugins.microbot.GeoffPlugins.construction2; -import net.runelite.client.ui.overlay.Overlay; import net.runelite.client.ui.overlay.OverlayPanel; import net.runelite.client.ui.overlay.OverlayPosition; import net.runelite.client.ui.overlay.components.LineComponent; diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/construction2/Construction2Plugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/GeoffPlugins/construction2/Construction2Plugin.java similarity index 92% rename from runelite-client/src/main/java/net/runelite/client/plugins/microbot/construction2/Construction2Plugin.java rename to runelite-client/src/main/java/net/runelite/client/plugins/microbot/GeoffPlugins/construction2/Construction2Plugin.java index 7325c546f7..b4913cb763 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/construction2/Construction2Plugin.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/GeoffPlugins/construction2/Construction2Plugin.java @@ -1,4 +1,4 @@ -package net.runelite.client.plugins.microbot.construction2; +package net.runelite.client.plugins.microbot.GeoffPlugins.construction2; import com.google.inject.Provides; import lombok.extern.slf4j.Slf4j; @@ -9,7 +9,7 @@ import net.runelite.client.plugins.Plugin; import net.runelite.client.plugins.PluginDescriptor; import net.runelite.client.plugins.microbot.Microbot; -import net.runelite.client.plugins.microbot.construction2.enums.Construction2State; +import net.runelite.client.plugins.microbot.GeoffPlugins.construction2.enums.Construction2State; import net.runelite.client.plugins.microbot.util.mouse.VirtualMouse; import net.runelite.client.ui.overlay.OverlayManager; diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/construction2/Construction2Script.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/GeoffPlugins/construction2/Construction2Script.java similarity index 98% rename from runelite-client/src/main/java/net/runelite/client/plugins/microbot/construction2/Construction2Script.java rename to runelite-client/src/main/java/net/runelite/client/plugins/microbot/GeoffPlugins/construction2/Construction2Script.java index e025a18e13..2284c0fbb2 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/construction2/Construction2Script.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/GeoffPlugins/construction2/Construction2Script.java @@ -1,10 +1,10 @@ -package net.runelite.client.plugins.microbot.construction2; +package net.runelite.client.plugins.microbot.GeoffPlugins.construction2; import net.runelite.api.*; import net.runelite.api.widgets.Widget; import net.runelite.client.plugins.microbot.Microbot; import net.runelite.client.plugins.microbot.Script; -import net.runelite.client.plugins.microbot.construction2.enums.Construction2State; +import net.runelite.client.plugins.microbot.GeoffPlugins.construction2.enums.Construction2State; import net.runelite.client.plugins.microbot.util.dialogues.Rs2Dialogue; import net.runelite.client.plugins.microbot.util.gameobject.Rs2GameObject; import net.runelite.client.plugins.microbot.util.inventory.Rs2Inventory; diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/construction2/enums/Construction2State.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/GeoffPlugins/construction2/enums/Construction2State.java similarity index 50% rename from runelite-client/src/main/java/net/runelite/client/plugins/microbot/construction2/enums/Construction2State.java rename to runelite-client/src/main/java/net/runelite/client/plugins/microbot/GeoffPlugins/construction2/enums/Construction2State.java index 593d4f94d4..f1adad9ab8 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/construction2/enums/Construction2State.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/GeoffPlugins/construction2/enums/Construction2State.java @@ -1,4 +1,4 @@ -package net.runelite.client.plugins.microbot.construction2.enums; +package net.runelite.client.plugins.microbot.GeoffPlugins.construction2.enums; public enum Construction2State { Idle, diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/plankmake/PlankMakeConfig.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/GeoffPlugins/lunarplankmake/LunarPlankMakeConfig.java similarity index 92% rename from runelite-client/src/main/java/net/runelite/client/plugins/microbot/plankmake/PlankMakeConfig.java rename to runelite-client/src/main/java/net/runelite/client/plugins/microbot/GeoffPlugins/lunarplankmake/LunarPlankMakeConfig.java index fe8e5b527a..ee74a4600f 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/plankmake/PlankMakeConfig.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/GeoffPlugins/lunarplankmake/LunarPlankMakeConfig.java @@ -1,13 +1,13 @@ -package net.runelite.client.plugins.microbot.plankmake; +package net.runelite.client.plugins.microbot.GeoffPlugins.lunarplankmake; import net.runelite.client.config.Config; import net.runelite.client.config.ConfigGroup; import net.runelite.client.config.ConfigItem; import net.runelite.client.config.ConfigSection; -import net.runelite.client.plugins.microbot.plankmake.enums.Logs; +import net.runelite.client.plugins.microbot.GeoffPlugins.lunarplankmake.enums.Logs; @ConfigGroup("plankMake") -public interface PlankMakeConfig extends Config { +public interface LunarPlankMakeConfig extends Config { String GROUP = "Plank Make"; @ConfigItem( diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/plankmake/PlankMakeOverlay.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/GeoffPlugins/lunarplankmake/LunarPlankMakeOverlay.java similarity index 74% rename from runelite-client/src/main/java/net/runelite/client/plugins/microbot/plankmake/PlankMakeOverlay.java rename to runelite-client/src/main/java/net/runelite/client/plugins/microbot/GeoffPlugins/lunarplankmake/LunarPlankMakeOverlay.java index 1a5663ba73..989476f2d5 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/plankmake/PlankMakeOverlay.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/GeoffPlugins/lunarplankmake/LunarPlankMakeOverlay.java @@ -1,4 +1,4 @@ -package net.runelite.client.plugins.microbot.plankmake; +package net.runelite.client.plugins.microbot.GeoffPlugins.lunarplankmake; import java.awt.Color; import java.awt.Dimension; @@ -11,10 +11,10 @@ import net.runelite.client.ui.overlay.components.LineComponent; import net.runelite.client.ui.overlay.components.TitleComponent; -public class PlankMakeOverlay extends OverlayPanel { +public class LunarPlankMakeOverlay extends OverlayPanel { @Inject - PlankMakeOverlay(PlankMakePlugin plugin) + LunarPlankMakeOverlay(LunarPlankMakePlugin plugin) { super(plugin); setPosition(OverlayPosition.ABOVE_CHATBOX_RIGHT); @@ -25,13 +25,13 @@ public class PlankMakeOverlay extends OverlayPanel { public Dimension render(Graphics2D graphics) { panelComponent.setPreferredSize(new Dimension(200, 300)); panelComponent.getChildren().add(TitleComponent.builder() - .text("Plank Make " + PlankMakeScript.version) + .text("Plank Make " + LunarPlankMakeScript.version) .color(Color.YELLOW) .build()); // Update to display the combined message panelComponent.getChildren().add(LineComponent.builder() - .left(PlankMakeScript.combinedMessage) + .left(LunarPlankMakeScript.combinedMessage) .build()); return super.render(graphics); diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/plankmake/PlankMakePlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/GeoffPlugins/lunarplankmake/LunarPlankMakePlugin.java similarity index 55% rename from runelite-client/src/main/java/net/runelite/client/plugins/microbot/plankmake/PlankMakePlugin.java rename to runelite-client/src/main/java/net/runelite/client/plugins/microbot/GeoffPlugins/lunarplankmake/LunarPlankMakePlugin.java index fc7ddef498..da6ebbc460 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/plankmake/PlankMakePlugin.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/GeoffPlugins/lunarplankmake/LunarPlankMakePlugin.java @@ -1,4 +1,4 @@ -package net.runelite.client.plugins.microbot.plankmake; +package net.runelite.client.plugins.microbot.GeoffPlugins.lunarplankmake; import java.awt.AWTException; @@ -15,43 +15,43 @@ import net.runelite.client.ui.overlay.OverlayManager; @PluginDescriptor( - name = PluginDescriptor.Geoff + "Plank Make", + name = PluginDescriptor.Geoff + "Lunar Plank Make", description = "Geoff's lunar plank maker", tags = {"magic", "moneymaking"}, enabledByDefault = false ) @Slf4j -public class PlankMakePlugin extends Plugin { +public class LunarPlankMakePlugin extends Plugin { @Inject - private PlankMakeConfig config; + private LunarPlankMakeConfig config; @Provides - PlankMakeConfig provideConfig(ConfigManager configManager) { - return configManager.getConfig(PlankMakeConfig.class); + LunarPlankMakeConfig provideConfig(ConfigManager configManager) { + return configManager.getConfig(LunarPlankMakeConfig.class); } @Inject private OverlayManager overlayManager; @Inject - private PlankMakeOverlay PlankMakeOverlay; + private LunarPlankMakeOverlay LunarPlankMakeOverlay; @Inject - PlankMakeScript PlankMakeScript; + LunarPlankMakeScript LunarPlankMakeScript; @Override protected void startUp() throws AWTException { Microbot.setMouse(new VirtualMouse()); - log.info("Starting up PlankMakePlugin"); + log.info("Starting up LunarPlankMakePlugin"); if (overlayManager != null) { - overlayManager.add(PlankMakeOverlay); + overlayManager.add(LunarPlankMakeOverlay); } - PlankMakeScript.run(config); + LunarPlankMakeScript.run(config); } @Override protected void shutDown() { - log.info("Shutting down PlankMakePlugin"); - PlankMakeScript.shutdown(); - overlayManager.remove(PlankMakeOverlay); + log.info("Shutting down LunarPlankMakePlugin"); + LunarPlankMakeScript.shutdown(); + overlayManager.remove(LunarPlankMakeOverlay); } } diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/plankmake/PlankMakeScript.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/GeoffPlugins/lunarplankmake/LunarPlankMakeScript.java similarity index 92% rename from runelite-client/src/main/java/net/runelite/client/plugins/microbot/plankmake/PlankMakeScript.java rename to runelite-client/src/main/java/net/runelite/client/plugins/microbot/GeoffPlugins/lunarplankmake/LunarPlankMakeScript.java index 17406e92a8..619c24a0d9 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/plankmake/PlankMakeScript.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/GeoffPlugins/lunarplankmake/LunarPlankMakeScript.java @@ -1,4 +1,4 @@ -package net.runelite.client.plugins.microbot.plankmake; +package net.runelite.client.plugins.microbot.GeoffPlugins.lunarplankmake; import java.util.concurrent.TimeUnit; import net.runelite.client.plugins.microbot.Microbot; @@ -10,7 +10,7 @@ import net.runelite.client.util.QuantityFormatter; import net.runelite.client.plugins.microbot.util.math.Random; -public class PlankMakeScript extends Script { +public class LunarPlankMakeScript extends Script { public static String version = "1.0.1"; public static String combinedMessage = ""; @@ -31,7 +31,7 @@ private enum State { private State currentState = State.PLANKING; - public boolean run(PlankMakeConfig config) { + public boolean run(LunarPlankMakeConfig config) { startTime = System.currentTimeMillis(); int unprocessedItemPrice = Microbot.getItemManager().search(config.ITEM().getName()).get(0).getPrice(); int processedItemPrice = Microbot.getItemManager().search(config.ITEM().getFinished()).get(0).getPrice(); @@ -57,13 +57,13 @@ public boolean run(PlankMakeConfig config) { break; } } catch (Exception ex) { - Microbot.log("Exception in PlankMakeScript: " + ex.getMessage()); + Microbot.log("Exception in LunarPlankMakeScript: " + ex.getMessage()); } }, 0, 50, TimeUnit.MILLISECONDS); return true; } - private void plankItems(PlankMakeConfig config) { + private void plankItems(LunarPlankMakeConfig config) { if (Rs2Inventory.hasItem(config.ITEM().getName(), true)) { int initialPlankCount = Rs2Inventory.count(config.ITEM().getFinished()); Rs2Magic.cast(MagicAction.PLANK_MAKE); @@ -95,7 +95,7 @@ private boolean waitForInventoryChange(String itemName, int initialCount) { return true; } - private void bank(PlankMakeConfig config) { + private void bank(LunarPlankMakeConfig config) { if (!Rs2Bank.openBank()) return; Rs2Bank.depositAll(config.ITEM().getFinished()); @@ -120,7 +120,7 @@ private void waitUntilReady() { currentState = State.PLANKING; } - private void calculateProfitAndDisplay(PlankMakeConfig config) { + private void calculateProfitAndDisplay(LunarPlankMakeConfig config) { double elapsedHours = (System.currentTimeMillis() - startTime) / 3600000.0; int plankPerHour = (int) (plankMade / elapsedHours); int totalProfit = profitPerPlank * (int) plankMade; diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/plankmake/enums/Logs.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/GeoffPlugins/lunarplankmake/enums/Logs.java similarity index 84% rename from runelite-client/src/main/java/net/runelite/client/plugins/microbot/plankmake/enums/Logs.java rename to runelite-client/src/main/java/net/runelite/client/plugins/microbot/GeoffPlugins/lunarplankmake/enums/Logs.java index 124aa2dd8e..285679ff3a 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/plankmake/enums/Logs.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/GeoffPlugins/lunarplankmake/enums/Logs.java @@ -1,4 +1,4 @@ -package net.runelite.client.plugins.microbot.plankmake.enums; +package net.runelite.client.plugins.microbot.GeoffPlugins.lunarplankmake.enums; import lombok.Getter; import lombok.RequiredArgsConstructor; diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/Microbot.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/Microbot.java index 01372d75a1..327b193b1f 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/Microbot.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/Microbot.java @@ -21,7 +21,10 @@ import net.runelite.client.plugins.microbot.dashboard.PluginRequestModel; import net.runelite.client.plugins.microbot.util.inventory.Rs2Item; import net.runelite.client.plugins.microbot.util.math.Random; +import net.runelite.client.plugins.microbot.util.menu.NewMenuEntry; +import net.runelite.client.plugins.microbot.util.misc.Rs2UiHelper; import net.runelite.client.plugins.microbot.util.mouse.Mouse; +import net.runelite.client.plugins.microbot.util.mouse.naturalmouse.NaturalMouse; import net.runelite.client.plugins.timers.GameTimer; import net.runelite.client.plugins.timers.TimersPlugin; import net.runelite.client.ui.overlay.infobox.InfoBox; @@ -48,7 +51,21 @@ import static net.runelite.client.plugins.microbot.util.Global.sleep; public class Microbot { + private static final ScheduledExecutorService xpSchedulor = Executors.newSingleThreadScheduledExecutor(); + @Getter + private static final SpecialAttackConfigs specialAttackConfigs = new SpecialAttackConfigs(); public static MenuEntry targetMenu; + @Inject + @Named("microbot.storage") + public static String storageUrl; + public static boolean debug = false; + public static boolean isGainingExp = false; + public static boolean pauseAllScripts = false; + public static String status = "IDLE"; + public static boolean enableAutoRunOn = true; + @Getter + @Setter + public static NaturalMouse naturalMouse; @Getter @Setter private static Mouse mouse; @@ -97,24 +114,8 @@ public class Microbot { @Getter @Setter private static ChatMessageManager chatMessageManager; - - @Inject - @Named("microbot.storage") public static String storageUrl; - - - public static boolean debug = false; - - public static boolean isGainingExp = false; - public static boolean pauseAllScripts = false; - public static String status = "IDLE"; - - public static boolean enableAutoRunOn = true; - - private static final ScheduledExecutorService xpSchedulor = Executors.newSingleThreadScheduledExecutor(); private static ScheduledFuture xpSchedulorFuture; private static net.runelite.api.World quickHopTargetWorld; - @Getter - private static final SpecialAttackConfigs specialAttackConfigs = new SpecialAttackConfigs(); @Deprecated(since = "Use isMoving", forRemoval = true) public static boolean isWalking() { @@ -239,9 +240,14 @@ public static List updateItemContainer(int id, ItemContainerChanged e) } public static void startPlugin(Plugin plugin) { + if (plugin == null) return; + Microbot.getPluginManager().setPluginEnabled(plugin, true); + Microbot.getPluginManager().startPlugins(); + } + @Deprecated(since = "1.3.8 - use Rs2UiHelper", forRemoval = true) public static Point calculateClickingPoint(Rectangle rect) { if (rect.getX() == 1 && rect.getY() == 1) return new Point(1, 1); int x = (int) (rect.getX() + (double) Random.random((int) rect.getWidth() / 6 * -1, (int) rect.getWidth() / 6) + rect.getWidth() / 2.0); @@ -249,40 +255,54 @@ public static Point calculateClickingPoint(Rectangle rect) { return new Point(x, y); } - public static void doInvoke(MenuEntry entry, Rectangle rectangle) { - targetMenu = entry; - int viewportHeight = client.getViewportHeight(); - int viewportWidth = client.getViewportWidth(); - if (!(rectangle.getX() > (double) viewportWidth) && !(rectangle.getY() > (double) viewportHeight) && !(rectangle.getX() < 0.0) && !(rectangle.getY() < 0.0)) { - click(rectangle); - } else { - click(new Rectangle(1, 1)); + public static void doInvoke(NewMenuEntry entry, Rectangle rectangle) { + + try { + if (Rs2UiHelper.isRectangleWithinViewport(rectangle)) { + click(rectangle, entry); + } else { + click(new Rectangle(1, 1), entry); + } + } catch (ArrayIndexOutOfBoundsException e) { + e.printStackTrace(); + // Handle the error as needed } } - public static void click(Rectangle rectangle) { + public static void drag(Rectangle start, Rectangle end) { + if (start == null || end == null) return; + if (!Rs2UiHelper.isRectangleWithinViewport(start) || !Rs2UiHelper.isRectangleWithinViewport(end)) return; + Point startPoint = Rs2UiHelper.getClickingPoint(start, true); + Point endPoint = Rs2UiHelper.getClickingPoint(end, true); + mouse.drag(startPoint, endPoint); + if (!Microbot.getClient().isClientThread()) { + sleep(50, 80); + } + } + + public static void click(Rectangle rectangle, NewMenuEntry entry) { + + Point point = Rs2UiHelper.getClickingPoint(rectangle, true); + mouse.click(point, entry); + - Point point = calculateClickingPoint(rectangle); - if (client.isStretchedEnabled()) { - Dimension stretched = client.getStretchedDimensions(); - Dimension real = client.getRealDimensions(); - double width = (double) stretched.width / real.getWidth(); - double height = (double) stretched.height / real.getHeight(); - point = new Point((int) ((double) point.getX() * width), (int) ((double) point.getY() * height)); + if (!Microbot.getClient().isClientThread()) { + sleep(50, 80); } + } + + public static void click(Rectangle rectangle) { + + Point point = Rs2UiHelper.getClickingPoint(rectangle, true); + mouse.click(point); - mouseEvent(504, point); - mouseEvent(505, point); - mouseEvent(503, point); - mouseEvent(501, point); - mouseEvent(502, point); - mouseEvent(500, point); if (!Microbot.getClient().isClientThread()) { - sleep(50, 100); + sleep(50, 80); } } + @Deprecated(since = "1.3.8 - use Mouse class", forRemoval = true) private static void mouseEvent(int id, Point point) { MouseEvent e = new MouseEvent(client.getCanvas(), id, System.currentTimeMillis(), 0, point.getX(), point.getY(), 1, false, 1); client.getCanvas().dispatchEvent(e); diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/MicrobotPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/MicrobotPlugin.java index 367038b573..8aa4919545 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/MicrobotPlugin.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/MicrobotPlugin.java @@ -22,6 +22,7 @@ import net.runelite.client.plugins.microbot.util.equipment.Rs2Equipment; import net.runelite.client.plugins.microbot.util.inventory.Rs2Inventory; import net.runelite.client.plugins.microbot.util.mouse.VirtualMouse; +import net.runelite.client.plugins.microbot.util.mouse.naturalmouse.NaturalMouse; import net.runelite.client.plugins.microbot.util.player.Rs2Player; import net.runelite.client.plugins.microbot.util.reflection.Rs2Reflection; import net.runelite.client.plugins.microbot.util.shop.Rs2Shop; @@ -46,12 +47,6 @@ ) @Slf4j public class MicrobotPlugin extends Plugin { - @Inject - private Client client; - @Inject - private ClientThread clientThread; - @Inject - private ClientToolbar clientToolbar; @Inject Notifier notifier; @Inject @@ -68,7 +63,12 @@ public class MicrobotPlugin extends Plugin { ChatMessageManager chatMessageManager; @Inject PluginManager pluginManager; - + @Inject + private Client client; + @Inject + private ClientThread clientThread; + @Inject + private ClientToolbar clientToolbar; @Inject private MicrobotOverlay microbotOverlay; @Inject @@ -81,6 +81,8 @@ public class MicrobotPlugin extends Plugin { private InfoBoxManager infoBoxManager; @Inject private WorldMapPointManager worldMapPointManager; + @Inject + private NaturalMouse naturalMouse; @Override protected void startUp() throws AWTException { Microbot.pauseAllScripts = false; @@ -92,6 +94,7 @@ protected void startUp() throws AWTException { Microbot.setItemManager(itemManager); Microbot.setNpcManager(npcManager); Microbot.setMouse(new VirtualMouse()); + Microbot.setNaturalMouse(naturalMouse); Microbot.setSpriteManager(spriteManager); Microbot.setPluginManager(pluginManager); Microbot.setWorldMapOverlay(worldMapOverlay); diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/breakhandler/BreakHandlerConfig.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/breakhandler/BreakHandlerConfig.java index 5d58564c7f..5a6196b508 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/breakhandler/BreakHandlerConfig.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/breakhandler/BreakHandlerConfig.java @@ -3,21 +3,33 @@ import net.runelite.client.config.Config; import net.runelite.client.config.ConfigGroup; import net.runelite.client.config.ConfigItem; +import net.runelite.client.config.ConfigSection; +import net.runelite.client.plugins.microbot.util.antiban.enums.PlaySchedule; @ConfigGroup("Breakhandler") public interface BreakHandlerConfig extends Config { + + // Play Schedule section + @ConfigSection( + name = "Play Schedule", + description = "Options related to using a play schedule", + position = 5 + ) + String usePlaySchedule = "usePlaySchedule"; + @ConfigItem( keyName = "TimeUntilBreakStart", - name = "Time break start", + name = "Time until break start", description = "Time until break start in minutes", position = 0 ) default int timeUntilBreakStart() { return 60; } + @ConfigItem( keyName = "TimeUntilBreakEnd", - name = "Time break end", + name = "Time until break end", description = "Time until break ends in minutes", position = 1 ) @@ -34,6 +46,7 @@ default int timeUntilBreakEnd() { default int breakDurationStart() { return 10; } + @ConfigItem( keyName = "BreakDurationEnd", name = "Break duration end", @@ -43,14 +56,36 @@ default int breakDurationStart() { default int breakDurationEnd() { return 15; } + @ConfigItem( keyName = "Logout", name = "Logout", - description = "logout when taking a break", + description = "Logout when taking a break", position = 4 ) default boolean logoutAfterBreak() { return true; } -} + @ConfigItem( + keyName = "UsePlaySchedule", + name = "Use Play Schedule", + description = "Enable or disable the use of a play schedule", + position = 5, + section = "UsePlaySchedule" + ) + default boolean usePlaySchedule() { + return false; + } + + @ConfigItem( + keyName = "PlaySchedule", + name = "Play Schedule", + description = "Select the play schedule", + position = 6, + section = "UsePlaySchedule" + ) + default PlaySchedule playSchedule() { + return PlaySchedule.MEDIUM_DAY; + } +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/breakhandler/BreakHandlerOverlay.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/breakhandler/BreakHandlerOverlay.java index 161d1c6a86..56198390ee 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/breakhandler/BreakHandlerOverlay.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/breakhandler/BreakHandlerOverlay.java @@ -40,12 +40,12 @@ public Dimension render(Graphics2D graphics) { if (BreakHandlerScript.breakIn > 0) { panelComponent.getChildren().add(LineComponent.builder() - .left(String.format("Break in: %02d:%02d:%02d%n", hours, minutes, seconds)) + .left(BreakHandlerScript.formatDuration(BreakHandlerScript.breakInDuration, "Break in:")) .build()); } if (BreakHandlerScript.breakDuration > 0) { panelComponent.getChildren().add(LineComponent.builder() - .left(String.format("Break duration: %02d:%02d:%02d%n", hours, minutes, seconds)) + .left(BreakHandlerScript.formatDuration(BreakHandlerScript.duration, "Break duration:")) .build()); } diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/breakhandler/BreakHandlerPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/breakhandler/BreakHandlerPlugin.java index 20b7709c04..66c5414991 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/breakhandler/BreakHandlerPlugin.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/breakhandler/BreakHandlerPlugin.java @@ -3,6 +3,8 @@ import com.google.inject.Provides; import lombok.extern.slf4j.Slf4j; import net.runelite.client.config.ConfigManager; +import net.runelite.client.eventbus.Subscribe; +import net.runelite.client.events.ConfigChanged; import net.runelite.client.plugins.Plugin; import net.runelite.client.plugins.PluginDescriptor; import net.runelite.client.ui.overlay.OverlayManager; @@ -18,21 +20,19 @@ ) @Slf4j public class BreakHandlerPlugin extends Plugin { + @Inject + BreakHandlerScript breakHandlerScript; @Inject private BreakHandlerConfig config; - @Provides - BreakHandlerConfig provideConfig(ConfigManager configManager) { - return configManager.getConfig(BreakHandlerConfig.class); - } - @Inject private OverlayManager overlayManager; @Inject private BreakHandlerOverlay breakHandlerOverlay; - @Inject - BreakHandlerScript breakHandlerScript; - + @Provides + BreakHandlerConfig provideConfig(ConfigManager configManager) { + return configManager.getConfig(BreakHandlerConfig.class); + } @Override protected void startUp() throws AWTException { @@ -46,4 +46,14 @@ protected void shutDown() { breakHandlerScript.shutdown(); overlayManager.remove(breakHandlerOverlay); } + + // on settings change + @Subscribe + public void onConfigChanged(ConfigChanged event) { + if (event.getGroup().equals("Breakhandler")) { + if (event.getKey().equals("UsePlaySchedule")) { + breakHandlerScript.reset(); + } + } + } } diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/breakhandler/BreakHandlerScript.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/breakhandler/BreakHandlerScript.java index 6a5d35193b..cea474988a 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/breakhandler/BreakHandlerScript.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/breakhandler/BreakHandlerScript.java @@ -4,6 +4,7 @@ import lombok.Setter; import net.runelite.client.plugins.microbot.Microbot; import net.runelite.client.plugins.microbot.Script; +import net.runelite.client.plugins.microbot.util.antiban.Rs2AntibanSettings; import net.runelite.client.plugins.microbot.util.math.Random; import net.runelite.client.plugins.microbot.util.player.Rs2Player; import net.runelite.client.plugins.microbot.util.security.Login; @@ -13,7 +14,6 @@ import java.time.LocalDateTime; import java.util.concurrent.TimeUnit; - public class BreakHandlerScript extends Script { public static String version = "1.0.0"; @@ -23,49 +23,90 @@ public class BreakHandlerScript extends Script { public static int totalBreaks = 0; public static Duration duration; - + public static Duration breakInDuration; @Setter @Getter public static boolean lockState = false; - private String title = ""; + + public static boolean isBreakActive() { + return breakDuration > 0; + } + + public static String formatDuration(Duration duration, String header) { + long hours = duration.toHours(); + long minutes = duration.toMinutes() % 60; + long seconds = duration.getSeconds() % 60; + return String.format(header + " %02d:%02d:%02d", hours, minutes, seconds); + } public boolean run(BreakHandlerConfig config) { + Microbot.enableAutoRunOn = false; title = ClientUI.getFrame().getTitle(); breakIn = Random.random(config.timeUntilBreakStart() * 60, config.timeUntilBreakEnd() * 60); mainScheduledFuture = scheduledExecutorService.scheduleWithFixedDelay(() -> { try { - if (breakIn > 0) { + if (config.playSchedule().isOutsideSchedule() && config.usePlaySchedule() && !isLockState()) { + Duration untilNextSchedule = config.playSchedule().timeUntilNextSchedule(); + breakIn = -1; + breakDuration = (int) untilNextSchedule.toSeconds(); + } + + if (breakIn > 0 && breakDuration <= 0) { breakIn--; - duration = Duration.between(LocalDateTime.now(),LocalDateTime.now().plusSeconds(breakIn)); + duration = Duration.between(LocalDateTime.now(), LocalDateTime.now().plusSeconds(breakIn)); + breakInDuration = duration; } + if (breakDuration > 0) { breakDuration--; - duration = Duration.between(LocalDateTime.now(),LocalDateTime.now().plusSeconds(breakDuration)); + duration = Duration.between(LocalDateTime.now(), LocalDateTime.now().plusSeconds(breakDuration)); long hours = BreakHandlerScript.duration.toHours(); long minutes = BreakHandlerScript.duration.toMinutes() % 60; long seconds = BreakHandlerScript.duration.getSeconds() % 60; - ClientUI.getFrame().setTitle(String.format("Break duration: %02d:%02d:%02d%n", hours, minutes, seconds)); + if (Rs2AntibanSettings.takeMicroBreaks && Rs2AntibanSettings.microBreakActive) { + ClientUI.getFrame().setTitle(String.format("Micro break duration: %02d:%02d:%02d", hours, minutes, seconds)); + } else if (config.playSchedule().isOutsideSchedule() && config.usePlaySchedule()) { + ClientUI.getFrame().setTitle(String.format("Next schedule in: %02d:%02d:%02d", hours, minutes, seconds)); + } else { + ClientUI.getFrame().setTitle(String.format("Break duration: %02d:%02d:%02d", hours, minutes, seconds)); + } } if (breakDuration <= 0 && Microbot.pauseAllScripts) { + if (Rs2AntibanSettings.universalAntiban && Rs2AntibanSettings.actionCooldownActive) + return; Microbot.pauseAllScripts = false; - breakIn = Random.random(config.timeUntilBreakStart() * 60, config.timeUntilBreakEnd() * 60); + if (breakIn <= 0) + breakIn = Random.random(config.timeUntilBreakStart() * 60, config.timeUntilBreakEnd() * 60); new Login(); totalBreaks++; ClientUI.getFrame().setTitle(title); + if (Rs2AntibanSettings.takeMicroBreaks) { + Rs2AntibanSettings.microBreakActive = false; + } return; } - if (breakIn <= 0 && !Microbot.pauseAllScripts && !isLockState()) { + if ((breakIn <= 0 && !Microbot.pauseAllScripts && !isLockState()) || (Rs2AntibanSettings.microBreakActive && !Microbot.pauseAllScripts && !isLockState())) { Microbot.pauseAllScripts = true; + + if (Rs2AntibanSettings.microBreakActive) + return; + if (config.playSchedule().isOutsideSchedule() && config.usePlaySchedule()) { + Rs2Player.logout(); + return; + } + + breakDuration = Random.random(config.breakDurationStart() * 60, config.breakDurationEnd() * 60); - if (config.logoutAfterBreak()) + + if (config.logoutAfterBreak()) { Rs2Player.logout(); + } } - } catch (Exception ex) { System.out.println(ex.getMessage()); } @@ -80,4 +121,10 @@ public void shutdown() { ClientUI.getFrame().setTitle(title); super.shutdown(); } + + public void reset() { + breakIn = 0; + breakDuration = 0; + ClientUI.getFrame().setTitle(title); + } } diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/fishing/barbarian/BarbarianFishingScript.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/fishing/barbarian/BarbarianFishingScript.java index e21f5c073e..e6fd125a11 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/fishing/barbarian/BarbarianFishingScript.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/fishing/barbarian/BarbarianFishingScript.java @@ -4,6 +4,8 @@ import net.runelite.client.game.FishingSpot; import net.runelite.client.plugins.microbot.Microbot; import net.runelite.client.plugins.microbot.Script; +import net.runelite.client.plugins.microbot.util.antiban.Rs2Antiban; +import net.runelite.client.plugins.microbot.util.antiban.Rs2AntibanSettings; import net.runelite.client.plugins.microbot.util.camera.Rs2Camera; import net.runelite.client.plugins.microbot.util.inventory.DropOrder; import net.runelite.client.plugins.microbot.util.inventory.Rs2Inventory; @@ -16,21 +18,21 @@ public class BarbarianFishingScript extends Script { - public static String version = "1.1.1"; + public static String version = "1.1.2"; public static int timeout = 0; private BarbarianFishingConfig config; public boolean run(BarbarianFishingConfig config) { this.config = config; - //Rs2Antiban.resetAntiban(); - //Rs2Antiban.advancedPlayStyleSetup(Activity.GENERAL_FISHING); + Rs2Antiban.resetAntibanSettings(); + Rs2Antiban.antibanSetupTemplates.applyFishingSetup(); mainScheduledFuture = scheduledExecutorService.scheduleWithFixedDelay(() -> { if (!super.run() || !Microbot.isLoggedIn() || !Rs2Inventory.hasItem("feather") || !Rs2Inventory.hasItem("rod")) { return; } - // if(Rs2Antiban.isActionCooldownActive) - // return; + if (Rs2AntibanSettings.actionCooldownActive) return; + if (Rs2Player.isInteracting()) return; @@ -77,7 +79,7 @@ private void dropInventoryItems(BarbarianFishingConfig config) { } public void shutdown() { - //Rs2Antiban.resetAntiban(); + Rs2Antiban.resetAntibanSettings(); super.shutdown(); } } \ No newline at end of file diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/fishing/eel/EelFishingConfig.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/fishing/eel/EelFishingConfig.java index c5ca436ec8..731da1094e 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/fishing/eel/EelFishingConfig.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/fishing/eel/EelFishingConfig.java @@ -27,4 +27,16 @@ public interface EelFishingConfig extends Config { default EelFishingSpot fishingSpot() { return EelFishingSpot.INFERNAL_EEL; } + + // check box if the user wants to use fast combination + @ConfigItem( + keyName = "useFastCombination", + name = "Use fast combination", + description = "Use fast combination", + position = 1, + section = generalSection + ) + default boolean useFastCombination() { + return false; + } } \ No newline at end of file diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/fishing/eel/EelFishingScript.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/fishing/eel/EelFishingScript.java index aa1aceada9..0715ad7cdc 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/fishing/eel/EelFishingScript.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/fishing/eel/EelFishingScript.java @@ -6,11 +6,13 @@ import net.runelite.client.plugins.microbot.Microbot; import net.runelite.client.plugins.microbot.Script; import net.runelite.client.plugins.microbot.fishing.eel.enums.EelFishingSpot; +import net.runelite.client.plugins.microbot.util.antiban.Rs2Antiban; +import net.runelite.client.plugins.microbot.util.antiban.Rs2AntibanSettings; +import net.runelite.client.plugins.microbot.util.antiban.enums.ActivityIntensity; import net.runelite.client.plugins.microbot.util.camera.Rs2Camera; import net.runelite.client.plugins.microbot.util.equipment.Rs2Equipment; import net.runelite.client.plugins.microbot.util.inventory.Rs2Inventory; import net.runelite.client.plugins.microbot.util.npc.Rs2Npc; -import net.runelite.client.plugins.microbot.util.player.Rs2Player; import java.util.concurrent.TimeUnit; @@ -18,7 +20,7 @@ public class EelFishingScript extends Script { - public static String version = "1.0.0"; + public static String version = "1.1.0"; private EelFishingConfig config; public static boolean hasRequiredGloves() { @@ -27,19 +29,19 @@ public static boolean hasRequiredGloves() { public boolean run(EelFishingConfig config) { this.config = config; - //Rs2Antiban.resetAntiban(); - //Rs2Antiban.advancedPlayStyleSetup(Activity.GENERAL_FISHING); + Rs2Antiban.resetAntibanSettings(); + Rs2Antiban.antibanSetupTemplates.applyFishingSetup(); mainScheduledFuture = scheduledExecutorService.scheduleWithFixedDelay(() -> { if (!super.run() || !Microbot.isLoggedIn() || !Rs2Inventory.hasItem("bait") || !Rs2Inventory.hasItem("rod")) { return; } - //if(Rs2Antiban.isActionCooldownActive) - // return; - - if (Rs2Player.isInteracting()) + if (Rs2AntibanSettings.actionCooldownActive) return; +// if (Rs2Player.isInteracting()) +// return; + if (config.fishingSpot().equals(EelFishingSpot.INFERNAL_EEL) && !hasRequiredGloves()) { Microbot.log("You need ice gloves to fish infernal eels."); return; @@ -60,7 +62,8 @@ public boolean run(EelFishingConfig config) { } if (Rs2Npc.interact(fishingspot)) { - //Rs2Antiban.actionCooldown(); + Rs2Antiban.actionCooldown(); + Rs2Antiban.takeMicroBreakByChance(); } @@ -96,19 +99,27 @@ private int[] getFishingSpotIds(EelFishingSpot spot) { private void processEels(EelFishingConfig config) { if (config.fishingSpot() == EelFishingSpot.INFERNAL_EEL) { if (Rs2Inventory.hasItem(ItemID.HAMMER)) { + if (config.useFastCombination()) { + Rs2Antiban.setActivityIntensity(ActivityIntensity.EXTREME); + while (Rs2Inventory.hasItem("Infernal eel")) { + Rs2Inventory.combineClosest("Infernal eel", "Hammer"); + } + return; + } Rs2Inventory.combineClosest("Infernal eel", "Hammer"); - sleepUntil(() -> !Rs2Inventory.hasItem("Infernal eel"), 40000); // Wait until all eels are processed + sleepUntil(() -> !Rs2Inventory.hasItem("Infernal eel"), 50000); // Wait until all eels are processed } } else if (config.fishingSpot() == EelFishingSpot.SACRED_EEL) { if (Rs2Inventory.hasItem(ItemID.KNIFE)) { Rs2Inventory.combineClosest("Sacred eel", "Knife"); - sleepUntil(() -> !Rs2Inventory.hasItem("Sacred eel"), 40000); // Wait until all eels are processed + sleepUntil(() -> !Rs2Inventory.hasItem("Sacred eel"), 50000); // Wait until all eels are processed } } + Rs2Antiban.takeMicroBreakByChance(); } public void shutdown() { - //Rs2Antiban.resetAntiban(); + Rs2Antiban.resetAntibanSettings(); super.shutdown(); } } diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/fishing/minnows/MinnowsScript.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/fishing/minnows/MinnowsScript.java index 49126bf548..5a854fe6e2 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/fishing/minnows/MinnowsScript.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/fishing/minnows/MinnowsScript.java @@ -8,6 +8,8 @@ import net.runelite.api.coords.WorldPoint; import net.runelite.client.plugins.microbot.Microbot; import net.runelite.client.plugins.microbot.Script; +import net.runelite.client.plugins.microbot.util.antiban.Rs2Antiban; +import net.runelite.client.plugins.microbot.util.antiban.Rs2AntibanSettings; import net.runelite.client.plugins.microbot.util.npc.Rs2Npc; import net.runelite.client.plugins.microbot.util.player.Rs2Player; @@ -16,7 +18,7 @@ @Slf4j public class MinnowsScript extends Script { - public static final String version = "1.0.3"; + public static final String version = "1.0.4"; public static final WorldArea MINNOWS_PLATFORM = new WorldArea(new WorldPoint(2607, 3440, 0), 2622 - 2607, 3446 - 3440); private static final int FLYING_FISH_GRAPHIC_ID = GraphicID.FLYING_FISH; @@ -28,6 +30,8 @@ public class MinnowsScript extends Script { private int timeout; public boolean run() { + Rs2Antiban.resetAntibanSettings(); + Rs2Antiban.antibanSetupTemplates.applyFishingSetup(); mainScheduledFuture = scheduledExecutorService.scheduleWithFixedDelay(() -> { try { if (!Microbot.isLoggedIn()) return; @@ -42,7 +46,7 @@ public boolean run() { Microbot.status = "MOVING"; return; } - if (Rs2Player.isInteracting()) { + if (Rs2AntibanSettings.actionCooldownActive) { if (Microbot.getClient().getLocalPlayer().getInteracting().hasSpotAnim(FLYING_FISH_GRAPHIC_ID)) { if (TARGET_SPOT_ID == FISHING_SPOT_1_ID) { TARGET_SPOT_ID = FISHING_SPOT_2_ID; @@ -52,15 +56,19 @@ public boolean run() { Microbot.status = "DODGING FLYING FISH"; fishingspot = Rs2Npc.getNpc(TARGET_SPOT_ID); Rs2Npc.interact(fishingspot, "Small Net"); + Rs2Antiban.actionCooldown(); return; } Microbot.status = "FISHING"; return; } - if (timeout != 0) return; + Microbot.status = "INTERACTING"; fishingspot = Rs2Npc.getNpc(TARGET_SPOT_ID); Rs2Npc.interact(fishingspot, "Small Net"); + Rs2Antiban.actionCooldown(); + Rs2Antiban.takeMicroBreakByChance(); + } catch (Exception ex) { System.out.println(ex.getMessage()); @@ -70,19 +78,12 @@ public boolean run() { } public void onGameTick() { - log.info("Timeout : " + timeout); - if (timeout > 0) { - timeout--; - } - if (Rs2Player.isInteracting()) { - //set timeout to random number between 3 and 4 - timeout = 3 + (int) (Math.random() * 2); - - } } @Override public void shutdown() { + + Rs2Antiban.resetAntibanSettings(); super.shutdown(); } } diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/fletching/FletchingOverlay.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/fletching/FletchingOverlay.java index e950860925..098479bed7 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/fletching/FletchingOverlay.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/fletching/FletchingOverlay.java @@ -1,6 +1,5 @@ package net.runelite.client.plugins.microbot.fletching; -import net.runelite.api.Skill; import net.runelite.client.plugins.microbot.Microbot; import net.runelite.client.ui.overlay.OverlayPanel; import net.runelite.client.ui.overlay.OverlayPosition; @@ -24,12 +23,13 @@ public Dimension render(Graphics2D graphics) { try { panelComponent.setPreferredSize(new Dimension(200, 300)); panelComponent.getChildren().add(TitleComponent.builder() - .text("Micro Fletcher V" + FletchingScript.version) + .text("Micro Fletcher") .color(Color.GREEN) .build()); panelComponent.getChildren().add(LineComponent.builder() .left(Microbot.status) + .right("Version: " + FletchingScript.version) .build()); } catch(Exception ex) { System.out.println(ex.getMessage()); diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/fletching/FletchingScript.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/fletching/FletchingScript.java index 12ff755508..9bdcb9c600 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/fletching/FletchingScript.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/fletching/FletchingScript.java @@ -9,9 +9,10 @@ import net.runelite.client.plugins.microbot.fletching.enums.FletchingItem; import net.runelite.client.plugins.microbot.fletching.enums.FletchingMaterial; import net.runelite.client.plugins.microbot.fletching.enums.FletchingMode; +import net.runelite.client.plugins.microbot.util.antiban.Rs2Antiban; +import net.runelite.client.plugins.microbot.util.antiban.Rs2AntibanSettings; import net.runelite.client.plugins.microbot.util.bank.Rs2Bank; import net.runelite.client.plugins.microbot.util.inventory.Rs2Inventory; -import net.runelite.client.plugins.microbot.util.math.Random; import net.runelite.client.plugins.microbot.util.widget.Rs2Widget; import java.util.concurrent.TimeUnit; @@ -26,7 +27,7 @@ class ProgressiveFletchingModel { public class FletchingScript extends Script { - public static double version = 1.6; + public static String version = "1.6.1"; ProgressiveFletchingModel model = new ProgressiveFletchingModel(); String primaryItemToFletch = ""; @@ -36,6 +37,8 @@ public class FletchingScript extends Script { public void run(FletchingConfig config) { fletchingMode = config.fletchingMode(); + Rs2Antiban.resetAntibanSettings(); + Rs2Antiban.antibanSetupTemplates.applyFletchingSetup(); mainScheduledFuture = scheduledExecutorService.scheduleWithFixedDelay(() -> { try { if (!Microbot.isLoggedIn()) @@ -48,8 +51,11 @@ public void run(FletchingConfig config) { if (!configChecks(config)) return; - if (config.Afk() && Random.random(1, 100) == 2) - sleep(1000, 60000); + if (Rs2AntibanSettings.actionCooldownActive) + return; + +// if (config.Afk() && Random.random(1, 100) == 2) +// sleep(1000, 60000); boolean hasRequirementsToFletch; boolean hasRequirementsToBank; @@ -148,14 +154,17 @@ private void bankItems(FletchingConfig config) { } private void fletch(FletchingConfig config) { - Rs2Inventory.combine(primaryItemToFletch, secondaryItemToFletch); + Rs2Inventory.combineClosest(primaryItemToFletch, secondaryItemToFletch); sleepUntil(() -> Rs2Widget.getWidget(17694736) != null); if (fletchingMode == FletchingMode.PROGRESSIVE) { keyPress(model.getFletchingItem().getOption(model.getFletchingMaterial(), fletchingMode)); + } else { keyPress(config.fletchingItem().getOption(config.fletchingMaterial(), fletchingMode)); } sleepUntil(() -> Rs2Widget.getWidget(17694736) == null); + Rs2Antiban.actionCooldown(); + Rs2Antiban.takeMicroBreakByChance(); if (fletchingMode == FletchingMode.PROGRESSIVE) { sleepUntil(() -> !Rs2Inventory.hasItemAmount(secondaryItemToFletch, model.getFletchingItem().getAmountRequired()) || hasLeveledUp, 60000); } else { @@ -218,6 +227,8 @@ public void calculateItemToFletch() { @Override public void shutdown() { + + Rs2Antiban.resetAntibanSettings(); super.shutdown(); } } diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/mining/AutoMiningScript.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/mining/AutoMiningScript.java index 175dde6a54..01e5ef6b0c 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/mining/AutoMiningScript.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/mining/AutoMiningScript.java @@ -4,6 +4,8 @@ import net.runelite.api.Skill; import net.runelite.client.plugins.microbot.Microbot; import net.runelite.client.plugins.microbot.Script; +import net.runelite.client.plugins.microbot.util.antiban.Rs2Antiban; +import net.runelite.client.plugins.microbot.util.antiban.Rs2AntibanSettings; import net.runelite.client.plugins.microbot.util.bank.Rs2Bank; import net.runelite.client.plugins.microbot.util.combat.Rs2Combat; import net.runelite.client.plugins.microbot.util.equipment.Rs2Equipment; @@ -23,16 +25,19 @@ enum State { public class AutoMiningScript extends Script { - public static String version = "1.4.1"; + public static String version = "1.4.2"; State state = State.MINING; public boolean run(AutoMiningConfig config) { initialPlayerLocation = null; + Rs2Antiban.resetAntibanSettings(); + Rs2Antiban.antibanSetupTemplates.applyMiningSetup(); + Rs2AntibanSettings.actionCooldownChance = 0.1; mainScheduledFuture = scheduledExecutorService.scheduleWithFixedDelay(() -> { try { if (!super.run()) return; if (!Microbot.isLoggedIn()) return; - + if (Rs2AntibanSettings.actionCooldownActive) return; if (initialPlayerLocation == null) { initialPlayerLocation = Rs2Player.getWorldLocation(); } @@ -60,6 +65,8 @@ public boolean run(AutoMiningConfig config) { if (rock != null) { if (Rs2GameObject.interact(rock)) { Rs2Player.waitForXpDrop(Skill.MINING, true); + Rs2Antiban.actionCooldown(); + Rs2Antiban.takeMicroBreakByChance(); } } break; diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/mining/amethyst/AmethystMiningConfig.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/mining/amethyst/AmethystMiningConfig.java index 4892be1649..d710c432a8 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/mining/amethyst/AmethystMiningConfig.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/mining/amethyst/AmethystMiningConfig.java @@ -3,10 +3,19 @@ import net.runelite.client.config.Config; import net.runelite.client.config.ConfigGroup; import net.runelite.client.config.ConfigItem; +import net.runelite.client.config.ConfigSection; +import net.runelite.client.plugins.microbot.mining.amethyst.enums.AmethystCraftingOption; @ConfigGroup("AmethystMining") public interface AmethystMiningConfig extends Config { + @ConfigSection( + name = "Chiseling Options", + description = "Options related to chiseling amethysts", + position = 2 + ) + String chiselingOptionsSection = "chiselingOptionsSection"; + @ConfigItem( keyName = "guide", name = "How to use", @@ -26,4 +35,26 @@ default String GUIDE() { default boolean pickAxeInInventory() { return false; } -} \ No newline at end of file + + @ConfigItem( + keyName = "chiselAmethysts", + name = "Chisel Amethysts", + description = "If enabled, the player will chisel the amethysts after mining.", + position = 0, + section = chiselingOptionsSection + ) + default boolean chiselAmethysts() { + return false; + } + + @ConfigItem( + keyName = "amethystCraftingOption", + name = "Item", + description = "Choose what to craft from amethysts.", + position = 1, + section = chiselingOptionsSection + ) + default AmethystCraftingOption amethystCraftingOption() { + return AmethystCraftingOption.BOLT_TIPS; + } +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/mining/amethyst/AmethystMiningOverlay.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/mining/amethyst/AmethystMiningOverlay.java index 2e04e86376..e57aff2c1a 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/mining/amethyst/AmethystMiningOverlay.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/mining/amethyst/AmethystMiningOverlay.java @@ -1,5 +1,6 @@ package net.runelite.client.plugins.microbot.mining.amethyst; +import net.runelite.client.plugins.microbot.util.antiban.Rs2Antiban; import net.runelite.client.ui.overlay.OverlayPanel; import net.runelite.client.ui.overlay.OverlayPosition; import net.runelite.client.ui.overlay.components.LineComponent; @@ -29,6 +30,7 @@ public Dimension render(Graphics2D graphics) { addEmptyLine(); + Rs2Antiban.renderAntibanOverlayComponents(panelComponent); addEmptyLine(); diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/mining/amethyst/AmethystMiningScript.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/mining/amethyst/AmethystMiningScript.java index 1442e80619..418ac59d13 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/mining/amethyst/AmethystMiningScript.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/mining/amethyst/AmethystMiningScript.java @@ -1,30 +1,39 @@ package net.runelite.client.plugins.microbot.mining.amethyst; +import net.runelite.api.ItemID; +import net.runelite.api.Skill; import net.runelite.api.TileObject; import net.runelite.api.WallObject; import net.runelite.api.coords.WorldPoint; +import net.runelite.api.widgets.Widget; import net.runelite.client.plugins.microbot.Microbot; import net.runelite.client.plugins.microbot.Script; +import net.runelite.client.plugins.microbot.mining.amethyst.enums.AmethystCraftingOption; import net.runelite.client.plugins.microbot.mining.amethyst.enums.MiningSpot; import net.runelite.client.plugins.microbot.mining.amethyst.enums.Status; +import net.runelite.client.plugins.microbot.util.antiban.Rs2Antiban; +import net.runelite.client.plugins.microbot.util.antiban.Rs2AntibanSettings; import net.runelite.client.plugins.microbot.util.bank.Rs2Bank; import net.runelite.client.plugins.microbot.util.bank.enums.BankLocation; import net.runelite.client.plugins.microbot.util.combat.Rs2Combat; import net.runelite.client.plugins.microbot.util.equipment.Rs2Equipment; import net.runelite.client.plugins.microbot.util.gameobject.Rs2GameObject; import net.runelite.client.plugins.microbot.util.inventory.Rs2Inventory; +import net.runelite.client.plugins.microbot.util.inventory.Rs2Item; +import net.runelite.client.plugins.microbot.util.keyboard.Rs2Keyboard; import net.runelite.client.plugins.microbot.util.player.Rs2Player; import net.runelite.client.plugins.microbot.util.walker.Rs2Walker; +import net.runelite.client.plugins.microbot.util.widget.Rs2Widget; import java.util.Comparator; import java.util.concurrent.TimeUnit; public class AmethystMiningScript extends Script { - public static String version = "1.0.0"; + public static String version = "1.1.1"; public static Status status = Status.IDLE; public static WallObject oreVein; private static AmethystMiningConfig config; - private static MiningSpot miningSpot; + private static MiningSpot miningSpot = MiningSpot.NULL; private String pickAxeInInventory = ""; public boolean run(AmethystMiningConfig config) { @@ -35,19 +44,28 @@ public boolean run(AmethystMiningConfig config) { return true; } + private boolean isClickHereToPlayButtonVisible() { + Widget clickHereToPlayButton = Rs2Widget.getWidget(24772680); + return (clickHereToPlayButton != null && !Microbot.getClientThread().runOnClientThread(clickHereToPlayButton::isHidden)); + } + private void executeTask() { - if (!super.run() || !Microbot.isLoggedIn()) { - oreVein = null; + if (!super.run() || !Microbot.isLoggedIn() || isClickHereToPlayButtonVisible()) { miningSpot = MiningSpot.NULL; + oreVein = null; return; } - + if (config.pickAxeInInventory() && pickAxeInInventory.isEmpty()) { + pickAxeInInventory = Rs2Inventory.get("pickaxe").name; + } if (pickAxeInInventory.isEmpty() && config.pickAxeInInventory()) { Microbot.showMessage("Pickaxe was not found in your inventory"); sleep(5000); return; } + if (Rs2AntibanSettings.actionCooldownActive) return; + if (Rs2Player.isAnimating() || Microbot.getClient().getLocalPlayer().isInteracting()) return; handleDragonPickaxeSpec(); @@ -62,8 +80,10 @@ private void executeTask() { case BANKING: bankItems(); break; + case CHISELING: + chiselAmethysts(); + break; } - } private void handleDragonPickaxeSpec() { @@ -73,13 +93,15 @@ private void handleDragonPickaxeSpec() { } private void handleInventory() { - if (!Rs2Inventory.isFull()) { status = Status.MINING; - } else if (Rs2Inventory.isFull()) { + } else { oreVein = null; miningSpot = MiningSpot.NULL; - status = Status.BANKING; + if (config.chiselAmethysts()) + status = Status.CHISELING; + else + status = Status.BANKING; } } @@ -95,7 +117,6 @@ private void bank() { Rs2Bank.depositAllExcept(pickAxeInInventory); sleep(100, 300); - if (config.pickAxeInInventory() && !Rs2Inventory.hasItem(pickAxeInInventory)) { Rs2Bank.withdrawOne(pickAxeInInventory); } @@ -103,13 +124,39 @@ private void bank() { } } + + private void chiselAmethysts() { + AmethystCraftingOption craftingOption = config.amethystCraftingOption(); + int requiredLevel = craftingOption.getRequiredLevel(); + Rs2Item chisel = Rs2Inventory.get("chisel"); + Rs2Inventory.moveItemToSlot(chisel, 27); + sleepUntil(() -> Rs2Inventory.slotContains(27, "chisel"), 5000); + if (Microbot.getClient().getRealSkillLevel(Skill.CRAFTING) >= requiredLevel) { + Rs2Inventory.combineClosest(ItemID.CHISEL, ItemID.AMETHYST); + sleepUntil(() -> Rs2Widget.getWidget(17694733) != null); + Rs2Keyboard.keyPress(craftingOption.getDialogOption()); + sleepUntil(() -> !Rs2Inventory.hasItem(ItemID.AMETHYST), 40000); + Rs2Antiban.takeMicroBreakByChance(); + + } else { + Microbot.showMessage("You do not have the required crafting level to make " + craftingOption.getDisplayName()); + status = Status.BANKING; + } + } + private void handleMining() { if (oreVein != null) return; if (miningSpot == MiningSpot.NULL) miningSpot = MiningSpot.getRandomMiningSpot(); - if (walkToMiningSpot()) { - mineVein(); + else { + if (walkToMiningSpot()) { + if (Rs2Player.isMoving()) return; + mineVein(); + Rs2Antiban.actionCooldown(); + Rs2Antiban.takeMicroBreakByChance(); + } } + } private boolean mineVein() { @@ -144,16 +191,17 @@ private int distanceToPlayer(WallObject wallObject) { } private void interactWithVein(WallObject vein) { - Rs2GameObject.interact(vein); - oreVein = vein; - sleepUntil(Rs2Player::isAnimating); + if (Rs2GameObject.interact(vein)) + oreVein = vein; + sleepUntil(Rs2Player::isAnimating, 10000); + if (!Rs2Player.isAnimating()) { + oreVein = null; + } } private boolean walkToMiningSpot() { WorldPoint miningWorldPoint = miningSpot.getWorldPoint(); - Rs2Walker.walkTo(miningWorldPoint); - moveToMiningSpot(); - return true; + return Rs2Walker.walkTo(miningWorldPoint, 5); } private void moveToMiningSpot() { @@ -161,12 +209,18 @@ private void moveToMiningSpot() { } private void initialize() { + Rs2Antiban.antibanSetupTemplates.applyMiningSetup(); status = Status.IDLE; miningSpot = MiningSpot.NULL; oreVein = null; - if (config.pickAxeInInventory()) { - pickAxeInInventory = Rs2Inventory.get("pickaxe").name; - } } + @Override + public void shutdown() { + Rs2Antiban.resetAntibanSettings(); + super.shutdown(); + status = Status.IDLE; + miningSpot = MiningSpot.NULL; + oreVein = null; + } } diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/mining/amethyst/enums/AmethystCraftingOption.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/mining/amethyst/enums/AmethystCraftingOption.java new file mode 100644 index 0000000000..4cd3ede525 --- /dev/null +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/mining/amethyst/enums/AmethystCraftingOption.java @@ -0,0 +1,31 @@ +package net.runelite.client.plugins.microbot.mining.amethyst.enums; + +import lombok.Getter; + +public enum AmethystCraftingOption { + BOLT_TIPS(83, "Bolt tips", '1'), + ARROW_TIPS(85, "Arrow tips", '2'), + JAVELIN_HEADS(87, "Javelin heads", '3'), + DART_TIPS(89, "Dart tips", '4'); + + @Getter + private final int requiredLevel; + @Getter + private final String displayName; + private final char dialogOption; + + AmethystCraftingOption(int requiredLevel, String displayName, char dialogOption) { + this.requiredLevel = requiredLevel; + this.displayName = displayName; + this.dialogOption = dialogOption; + } + + public char getDialogOption() { + return dialogOption; + } + + @Override + public String toString() { + return displayName + " (Level " + requiredLevel + ")"; + } +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/mining/amethyst/enums/MiningSpot.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/mining/amethyst/enums/MiningSpot.java index 42f131abcf..9f4671bc90 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/mining/amethyst/enums/MiningSpot.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/mining/amethyst/enums/MiningSpot.java @@ -14,7 +14,7 @@ public enum MiningSpot { RANDOM_POINT_3(new WorldPoint(3018, 9703, 0)), RANDOM_POINT_4(new WorldPoint(3019, 9703, 0)), RANDOM_POINT_5(new WorldPoint(3020, 9700, 0)), - NULL(new WorldPoint(0, 0, 0)); + NULL(null); private static final Random RANDOM = new Random(); private final WorldPoint worldPoint; diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/mining/amethyst/enums/Status.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/mining/amethyst/enums/Status.java index e1960d7c6e..2e25b35386 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/mining/amethyst/enums/Status.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/mining/amethyst/enums/Status.java @@ -3,5 +3,6 @@ public enum Status { IDLE, MINING, - BANKING + BANKING, + CHISELING } diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/mining/motherloadmine/MotherloadMineOverlay.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/mining/motherloadmine/MotherloadMineOverlay.java index 4dd4c142b5..094a31a6e7 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/mining/motherloadmine/MotherloadMineOverlay.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/mining/motherloadmine/MotherloadMineOverlay.java @@ -1,5 +1,6 @@ package net.runelite.client.plugins.microbot.mining.motherloadmine; +import net.runelite.client.plugins.microbot.util.antiban.Rs2Antiban; import net.runelite.client.ui.overlay.OverlayPanel; import net.runelite.client.ui.overlay.OverlayPosition; import net.runelite.client.ui.overlay.components.LineComponent; @@ -30,7 +31,7 @@ public Dimension render(Graphics2D graphics) { .build()); - //Rs2Antiban.renderAntibanOverlayComponents(panelComponent); + Rs2Antiban.renderAntibanOverlayComponents(panelComponent); addEmptyLine(); diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/mining/motherloadmine/MotherloadMineScript.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/mining/motherloadmine/MotherloadMineScript.java index 9740ad4949..573745032b 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/mining/motherloadmine/MotherloadMineScript.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/mining/motherloadmine/MotherloadMineScript.java @@ -8,6 +8,9 @@ import net.runelite.client.plugins.microbot.Script; import net.runelite.client.plugins.microbot.mining.motherloadmine.enums.MLMMiningSpot; import net.runelite.client.plugins.microbot.mining.motherloadmine.enums.MLMStatus; +import net.runelite.client.plugins.microbot.util.antiban.Rs2Antiban; +import net.runelite.client.plugins.microbot.util.antiban.Rs2AntibanSettings; +import net.runelite.client.plugins.microbot.util.antiban.enums.ActivityIntensity; import net.runelite.client.plugins.microbot.util.bank.Rs2Bank; import net.runelite.client.plugins.microbot.util.combat.Rs2Combat; import net.runelite.client.plugins.microbot.util.equipment.Rs2Equipment; @@ -24,7 +27,7 @@ @Slf4j public class MotherloadMineScript extends Script { - public static final String version = "1.5.4"; + public static final String version = "1.6.5"; private static final WorldArea UPSTAIRS = new WorldArea(new WorldPoint(3747, 5676, 0), 7, 8); private static final WorldPoint HOPPER = new WorldPoint(3748, 5674, 0); private static final int UPPER_FLOOR_HEIGHT = -490; @@ -49,9 +52,7 @@ public boolean run(MotherloadMineConfig config) { } private void initialize() { - //Rs2Antiban.isEnabled = true; - //Rs2Antiban.simulateAttentionSpan = true; - //Rs2Antiban.setActivity(Activity.MOTHERLODE_MINE); + Rs2Antiban.antibanSetupTemplates.applyMiningSetup(); miningSpot = MLMMiningSpot.IDLE; status = MLMStatus.IDLE; emptySack = false; @@ -74,7 +75,7 @@ private void executeTask() { return; } - //if(Rs2Antiban.isActionCooldownActive) return; + if (Rs2AntibanSettings.actionCooldownActive) return; if (Rs2Player.isAnimating() || Microbot.getClient().getLocalPlayer().isInteracting()) return; @@ -86,9 +87,11 @@ private void executeTask() { case IDLE: return; case MINING: + Rs2Antiban.setActivityIntensity(Rs2Antiban.getActivity().getActivityIntensity()); handleMining(); break; case EMPTY_SACK: + Rs2Antiban.setActivityIntensity(ActivityIntensity.EXTREME); emptySack(); break; case FIXING_WATERWHEEL: @@ -149,7 +152,8 @@ private void handleMining() { if (walkToMiningSpot()) { if (Rs2Player.isMoving()) return; mineVein(); - //Rs2Antiban.actionCooldown(); + Rs2Antiban.actionCooldown(); + Rs2Antiban.takeMicroBreakByChance(); } } } @@ -174,6 +178,7 @@ private void emptySack() { bank(); } emptySack = false; + Rs2Antiban.takeMicroBreakByChance(); status = MLMStatus.IDLE; } @@ -298,6 +303,7 @@ private boolean isUpperFloor() { } public void shutdown() { + Rs2Antiban.resetAntibanSettings(); oreVein = null; miningSpot = MLMMiningSpot.IDLE; Rs2Walker.setTarget(null); diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/playerassist/PlayerAssistOverlay.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/playerassist/PlayerAssistOverlay.java index d014f50b0d..31ec5aec6b 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/playerassist/PlayerAssistOverlay.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/playerassist/PlayerAssistOverlay.java @@ -6,7 +6,6 @@ import net.runelite.api.coords.LocalPoint; import net.runelite.client.plugins.microbot.Microbot; import net.runelite.client.plugins.microbot.playerassist.model.Monster; -import net.runelite.client.plugins.microbot.util.player.Rs2Player; import net.runelite.client.ui.overlay.OverlayLayer; import net.runelite.client.ui.overlay.OverlayPanel; import net.runelite.client.ui.overlay.OverlayPosition; @@ -53,9 +52,6 @@ public static void renderMinimapRect(Client client, Graphics2D graphics, Point c public Dimension render(Graphics2D graphics) { if (attackableNpcs == null) return null; - - net.runelite.api.Point loc = Perspective.localToCanvas(Microbot.getClient(), Rs2Player.getLocalLocation(), Rs2Player.getWorldLocation().getPlane(), 150); - LocalPoint lp = LocalPoint.fromWorld(Microbot.getClient(), config.centerLocation()); if (lp != null) { Polygon poly = Perspective.getCanvasTileAreaPoly(Microbot.getClient(), lp, config.attackRadius() * 2); diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/util/antiban/AntibanOverlay.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/util/antiban/AntibanOverlay.java new file mode 100644 index 0000000000..b466477e3c --- /dev/null +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/util/antiban/AntibanOverlay.java @@ -0,0 +1,149 @@ +package net.runelite.client.plugins.microbot.util.antiban; + +import net.runelite.api.Actor; +import net.runelite.api.Point; +import net.runelite.client.plugins.microbot.Microbot; +import net.runelite.client.ui.overlay.Overlay; +import net.runelite.client.ui.overlay.OverlayPosition; +import net.runelite.client.ui.overlay.components.ProgressPieComponent; + +import javax.inject.Inject; +import java.awt.*; +import java.awt.image.BufferedImage; + +/** + * The {@code AntibanOverlay} class provides a visual representation of the anti-ban system through + * an overlay component on the game screen. This overlay uses a progress pie to display the remaining + * time for the current action cooldown, simulating a human-like delay or pause in gameplay. The overlay + * dynamically follows the player's location and updates in real-time as the cooldown progresses. + * + *

+ * 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. + *

+ * + *

Features:

+ * + * + *

Usage:

+ *

+ * 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. + *

+ * + *

Example Flow:

+ *
+ * // 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);
+ * 
+ * + *

Primary Methods:

+ * + * + *

Rendering Logic:

+ *

+ * 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. + *

+ * + *

Customization:

+ *

+ * 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}. + *

+ * + *

Dependencies:

+ * + * + *

Limitations:

+ * + */ + +public class AntibanOverlay extends Overlay { + + public static Color PUBLIC_TIMER_COLOR = Color.YELLOW; + public static int TIMER_OVERLAY_DIAMETER = 20; + private final ProgressPieComponent progressPieComponent = new ProgressPieComponent(); + + @Inject + public AntibanOverlay() { + setPosition(OverlayPosition.DYNAMIC); + } + + private Point getCanvasTextLocation(Graphics2D graphics, Actor actor) { + int zOffset = Math.min(actor.getLogicalHeight(), 140); + // create blank buffered image + BufferedImage bufferedImage = new BufferedImage(TIMER_OVERLAY_DIAMETER, TIMER_OVERLAY_DIAMETER, BufferedImage.TYPE_INT_ARGB); + + return actor.getCanvasImageLocation(bufferedImage, zOffset); + } + + private void drawTimerPieOverlay(Graphics2D graphics) { + + + // Calculate the remaining time as a fraction of the total time + int totalTime = Rs2Antiban.getPlayStyle().getSecondaryTickInterval(); + + int timeLeft = Rs2Antiban.getTIMEOUT(); + float percent = (float) timeLeft / totalTime; + + // Get the player's screen location + Point playerLocation = getCanvasTextLocation(graphics, Microbot.getClient().getLocalPlayer()); + + progressPieComponent.setDiameter(TIMER_OVERLAY_DIAMETER); + // Shift over to not be on top of the text + int x = playerLocation.getX() + (TIMER_OVERLAY_DIAMETER / 2); + int y = playerLocation.getY() - (15 + (Microbot.getClient().getScale() / 30)); + progressPieComponent.setPosition(new Point(x, y)); + progressPieComponent.setFill(PUBLIC_TIMER_COLOR); + progressPieComponent.setBorderColor(PUBLIC_TIMER_COLOR); + progressPieComponent.setProgress(percent); // inverse so pie drains over time + progressPieComponent.render(graphics); + } + + @Override + public Dimension render(Graphics2D graphics) { + if (Rs2AntibanSettings.actionCooldownActive) { + drawTimerPieOverlay(graphics); + } + + + return null; + } +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/util/antiban/AntibanPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/util/antiban/AntibanPlugin.java new file mode 100644 index 0000000000..bbfd21f371 --- /dev/null +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/util/antiban/AntibanPlugin.java @@ -0,0 +1,287 @@ +package net.runelite.client.plugins.microbot.util.antiban; + +import net.runelite.api.AnimationID; +import net.runelite.api.GameState; +import net.runelite.api.Skill; +import net.runelite.api.events.ChatMessage; +import net.runelite.api.events.GameStateChanged; +import net.runelite.api.events.GameTick; +import net.runelite.api.events.StatChanged; +import net.runelite.client.eventbus.Subscribe; +import net.runelite.client.events.ProfileChanged; +import net.runelite.client.plugins.Plugin; +import net.runelite.client.plugins.PluginDescriptor; +import net.runelite.client.plugins.microbot.Microbot; +import net.runelite.client.plugins.microbot.breakhandler.BreakHandlerPlugin; +import net.runelite.client.plugins.microbot.util.antiban.enums.Activity; +import net.runelite.client.plugins.microbot.util.antiban.enums.ActivityIntensity; +import net.runelite.client.plugins.microbot.util.antiban.ui.MasterPanel; +import net.runelite.client.plugins.microbot.util.player.Rs2Player; +import net.runelite.client.ui.ClientToolbar; +import net.runelite.client.ui.NavigationButton; +import net.runelite.client.ui.overlay.OverlayManager; +import net.runelite.client.util.ImageUtil; + +import javax.inject.Inject; +import javax.swing.*; +import java.awt.*; +import java.awt.image.BufferedImage; +import java.time.Duration; +import java.time.Instant; +import java.util.EnumMap; +import java.util.Map; +import java.util.Timer; +import java.util.TimerTask; + +/** + * The AntibanPlugin is responsible for managing anti-ban behaviors during bot operation. + * + *

+ * 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. + *

+ * + *

Main Features:

+ * + * + *

Usage:

+ *

+ * 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. + *

+ * + *

Additional Details:

+ * + */ + +@PluginDescriptor( + name = PluginDescriptor.See1Duck + "Antiban", + description = "Antiban for microbot", + tags = {"main", "microbot", "antiban parent"}, + alwaysOn = true, + hidden = true +) + + +public class AntibanPlugin extends Plugin { + + private static final int COOK_TIMEOUT = 3; + private static final int MINING_TIMEOUT = 3; + private static final int IDLE_TIMEOUT = 1; + public static int ticksSinceLogin; + private static Instant lastCookingAction = Instant.MIN; + private static Instant lastMiningAction = Instant.MIN; + private static int idleTicks = 0; + private final Map skillExp = new EnumMap<>(Skill.class); + private boolean ready; + private Skill lastSkillChanged; + private NavigationButton navButton; + + @Inject + private OverlayManager overlayManager; + + @Inject + private ClientToolbar clientToolbar; + + public static boolean isCooking() { + return Rs2Player.getAnimation() == AnimationID.COOKING_FIRE + || Rs2Player.getAnimation() == AnimationID.COOKING_RANGE + || Duration.between(lastCookingAction, Instant.now()).getSeconds() < COOK_TIMEOUT; + } + + public static boolean isMining() { + return Rs2Antiban.isMining() + || Duration.between(lastMiningAction, Instant.now()).getSeconds() < MINING_TIMEOUT; + } + + public static boolean isIdle() { + return idleTicks > IDLE_TIMEOUT; + } + + private static void updateIdleTicks() { + idleTicks++; + } + + private static void updateLastCookingAction() { + lastCookingAction = Instant.now(); + } + + private static void updateLastMiningAction() { + lastMiningAction = Instant.now(); + } + + public static void performActionBreak() { + if (Rs2AntibanSettings.actionCooldownActive) { + if (Rs2Antiban.getTIMEOUT() > 0) { + if (!Rs2Antiban.getCategory().isBusy()) { + Rs2Antiban.TIMEOUT--; + } + } else { + Rs2AntibanSettings.actionCooldownActive = false; + Microbot.pauseAllScripts = false; + } + } + } + + @Override + protected void startUp() throws AWTException { + final MasterPanel panel = injector.getInstance(MasterPanel.class); + final BufferedImage icon = ImageUtil.loadImageResource(getClass(), "antiban.png"); + navButton = NavigationButton.builder() + .tooltip("Antiban") + .icon(icon) + .priority(1) + .panel(panel) + .build(); + + Timer timer = new Timer(); + timer.scheduleAtFixedRate(new TimerTask() { + @Override + public void run() { + SwingUtilities.invokeLater(panel::loadSettings); + } + }, 0, 600); + + clientToolbar.addNavigation(navButton); + overlayManager.add(new AntibanOverlay()); + } + + @Override + protected void shutDown() { + overlayManager.removeIf(overlay -> overlay instanceof AntibanOverlay); + clientToolbar.removeNavigation(navButton); + } + + @Subscribe + public void onChatMessage(ChatMessage event) { + if (Rs2Antiban.checkForCookingEvent(event)) { + updateLastCookingAction(); + } + } + + @Subscribe + public void onProfileChanged(ProfileChanged event) { + Rs2Antiban.resetAntibanSettings(); + } + + @Subscribe + public void onGameStateChanged(GameStateChanged event) { + GameState state = event.getGameState(); + + switch (state) { + case LOGGING_IN: + case HOPPING: + ready = true; + break; + case LOGGED_IN: + if (ready) { + ticksSinceLogin = 0; + ready = false; + } + break; + } + } + + @Subscribe + public void onGameTick(GameTick event) { + ticksSinceLogin++; + + if (!Rs2AntibanSettings.antibanEnabled) { + return; + } + + if (!Rs2Player.isAnimating()) { + updateIdleTicks(); + } else { + if (Rs2AntibanSettings.simulateFatigue) { + ticksSinceLogin -= idleTicks; + } + idleTicks = 0; + } + + if (Rs2AntibanSettings.takeMicroBreaks && !Microbot.isPluginEnabled(BreakHandlerPlugin.class)) { + Microbot.log("BreakHandlerPlugin is not enabled, attempting to enable it...."); + String name = BreakHandlerPlugin.class.getName(); + Plugin breakHandlerPlugin = Microbot.getPluginManager().getPlugins().stream() + .filter(x -> x.getClass().getName().equals(name)) + .findFirst() + .orElse(null); + Microbot.startPlugin(breakHandlerPlugin); + } + + if (Rs2Antiban.isMining()) { + updateLastMiningAction(); + } + + if (Rs2AntibanSettings.actionCooldownActive) { + performActionBreak(); + } + + if (Rs2AntibanSettings.simulateAttentionSpan && Rs2AntibanSettings.profileSwitching && + Rs2Antiban.getPlayStyle().shouldSwitchProfileBasedOnAttention()) { + Rs2Antiban.setPlayStyle(Rs2Antiban.getPlayStyle().switchProfile()); + Rs2Antiban.getPlayStyle().resetPlayStyle(); + } + } + + @Subscribe + public void onStatChanged(StatChanged statChanged) { + if (!Rs2AntibanSettings.antibanEnabled) { + return; + } + + final Skill skill = statChanged.getSkill(); + final int exp = statChanged.getXp(); + final Integer previous = skillExp.put(skill, exp); + + if (lastSkillChanged != null && lastSkillChanged.equals(skill)) { + if (Rs2AntibanSettings.universalAntiban && !Rs2AntibanSettings.actionCooldownActive && Rs2Antiban.getActivity() != null) { + Rs2Antiban.actionCooldown(); + } + return; + } + + lastSkillChanged = skill; + + if (previous == null || previous >= exp) { + return; + } + + updateAntibanSettings(skill); + } + + private void updateAntibanSettings(Skill skill) { + final ActivityIntensity activityIntensity = ActivityIntensity.fromSkill(skill); + final Activity activity = Activity.fromSkill(skill); + + if (activity != null && Rs2AntibanSettings.dynamicActivity) { + Rs2Antiban.setActivity(activity); + Microbot.log("Activity changed, new activity: " + activity); + if (Rs2AntibanSettings.universalAntiban) { + Rs2Antiban.actionCooldown(); + } + } + + if (activityIntensity != null && Rs2AntibanSettings.dynamicIntensity) { + Rs2Antiban.setActivityIntensity(activityIntensity); + Microbot.log("Activity changed, new activity intensity: " + activityIntensity); + } + } +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/util/antiban/AntibanSetupTemplates.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/util/antiban/AntibanSetupTemplates.java new file mode 100644 index 0000000000..c0b20adf57 --- /dev/null +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/util/antiban/AntibanSetupTemplates.java @@ -0,0 +1,600 @@ +package net.runelite.client.plugins.microbot.util.antiban; + +import net.runelite.client.plugins.microbot.util.antiban.enums.Activity; + +/** + * The {@code AntibanSetupTemplates} class provides predefined antiban setup configurations tailored to specific + * in-game activities. These configurations are designed to mimic human-like behaviors such as fatigue simulation, + * attention span, and behavioral variability, with the goal of reducing detection risks by anti-cheat systems. + * + *

+ * 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. + *

+ * + *

Main Features:

+ *
    + *
  • Activity-Specific Setups: Methods are provided to apply antiban configurations for a wide range of activities, + * including skilling, combat, and more specialized tasks like runecrafting and herblore.
  • + *
  • Human-Like Behavior Simulation: The setups simulate human-like behaviors to avoid detection, including fatigue, + * attention span, micro breaks, mouse movement patterns, and random intervals.
  • + *
  • Flexible Configurations: Each setup method customizes settings such as action cooldowns, behavioral variability, + * and micro breaks to tailor the antiban behavior to the specific activity.
  • + *
  • Basic Setup: A general setup method is included for cases where simpler antiban measures are needed without + * advanced features like attention span or micro breaks.
  • + *
+ * + *

Usage:

+ *

+ * 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. + *

+ * + *

Example:

+ *

Inside your plugin script class, execute the initialization outside the main loop.

+ *
+ * private void initialize() {
+ *         Rs2Antiban.antibanSetupTemplates.applyMiningSetup();
+ *     }
+ * 
+ * + *

Available Setup Methods:

+ *
    + *
  • 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.
  • + *
+ */ + +public class AntibanSetupTemplates { + /** + * Applies the antiban setup tailored for general combat activities. + * This setup enables various human-like behaviors such as fatigue simulation, attention span, + * and mouse movement variability to reduce detection risk. + */ + public void applyCombatSetup() { + Rs2AntibanSettings.antibanEnabled = true; + Rs2AntibanSettings.usePlayStyle = true; + Rs2AntibanSettings.randomIntervals = false; + Rs2AntibanSettings.simulateFatigue = true; + Rs2AntibanSettings.simulateAttentionSpan = true; + Rs2AntibanSettings.behavioralVariability = true; + Rs2AntibanSettings.nonLinearIntervals = true; + Rs2AntibanSettings.profileSwitching = true; + Rs2AntibanSettings.timeOfDayAdjust = false; + Rs2AntibanSettings.simulateMistakes = false; + Rs2AntibanSettings.naturalMouse = true; + Rs2AntibanSettings.contextualVariability = true; + Rs2AntibanSettings.dynamicIntensity = false; + Rs2AntibanSettings.dynamicActivity = false; + Rs2AntibanSettings.devDebug = false; + Rs2AntibanSettings.takeMicroBreaks = true; + Rs2AntibanSettings.playSchedule = true; + Rs2AntibanSettings.universalAntiban = false; + Rs2AntibanSettings.microBreakDurationLow = 3; + Rs2AntibanSettings.microBreakDurationHigh = 8; + Rs2AntibanSettings.actionCooldownChance = 1.00; + Rs2AntibanSettings.microBreakChance = 0.05; + Rs2Antiban.setActivity(Activity.GENERAL_COMBAT); + } + + /** + * Applies the antiban setup tailored for runecrafting activities. + * This setup adjusts settings to simulate human-like behaviors during runecrafting tasks. + */ + public void applyRunecraftingSetup() { + // Implementation for Runecrafting setup + Rs2AntibanSettings.antibanEnabled = true; + Rs2AntibanSettings.usePlayStyle = true; + Rs2AntibanSettings.randomIntervals = false; + Rs2AntibanSettings.simulateFatigue = true; + Rs2AntibanSettings.simulateAttentionSpan = true; + Rs2AntibanSettings.behavioralVariability = true; + Rs2AntibanSettings.nonLinearIntervals = true; + Rs2AntibanSettings.profileSwitching = true; + Rs2AntibanSettings.timeOfDayAdjust = false; + Rs2AntibanSettings.simulateMistakes = false; + Rs2AntibanSettings.naturalMouse = true; + Rs2AntibanSettings.contextualVariability = true; + Rs2AntibanSettings.dynamicIntensity = false; + Rs2AntibanSettings.dynamicActivity = false; + Rs2AntibanSettings.devDebug = false; + Rs2AntibanSettings.takeMicroBreaks = true; + Rs2AntibanSettings.playSchedule = true; + Rs2AntibanSettings.universalAntiban = false; + Rs2AntibanSettings.microBreakDurationLow = 3; + Rs2AntibanSettings.microBreakDurationHigh = 8; + Rs2AntibanSettings.actionCooldownChance = 1.00; + Rs2AntibanSettings.microBreakChance = 0.05; + Rs2Antiban.setActivity(Activity.GENERAL_RUNECRAFT); + } + + /** + * Applies the antiban setup tailored for construction activities. + * This setup focuses on mimicking human-like behaviors during construction tasks. + */ + public void applyConstructionSetup() { + // Implementation for Construction setup + Rs2AntibanSettings.antibanEnabled = true; + Rs2AntibanSettings.usePlayStyle = true; + Rs2AntibanSettings.randomIntervals = false; + Rs2AntibanSettings.simulateFatigue = true; + Rs2AntibanSettings.simulateAttentionSpan = true; + Rs2AntibanSettings.behavioralVariability = true; + Rs2AntibanSettings.nonLinearIntervals = true; + Rs2AntibanSettings.profileSwitching = true; + Rs2AntibanSettings.timeOfDayAdjust = false; + Rs2AntibanSettings.simulateMistakes = false; + Rs2AntibanSettings.naturalMouse = true; + Rs2AntibanSettings.contextualVariability = true; + Rs2AntibanSettings.dynamicIntensity = false; + Rs2AntibanSettings.dynamicActivity = false; + Rs2AntibanSettings.devDebug = false; + Rs2AntibanSettings.takeMicroBreaks = true; + Rs2AntibanSettings.playSchedule = true; + Rs2AntibanSettings.universalAntiban = false; + Rs2AntibanSettings.microBreakDurationLow = 3; + Rs2AntibanSettings.microBreakDurationHigh = 8; + Rs2AntibanSettings.actionCooldownChance = 1.00; + Rs2AntibanSettings.microBreakChance = 0.05; + Rs2Antiban.setActivity(Activity.GENERAL_CONSTRUCTION); + } + + /** + * Applies the antiban setup tailored for agility activities. + * This setup includes adjustments to simulate human-like behaviors during agility tasks. + */ + + public void applyAgilitySetup() { + // Implementation for Agility setup + Rs2AntibanSettings.antibanEnabled = true; + Rs2AntibanSettings.usePlayStyle = true; + Rs2AntibanSettings.randomIntervals = false; + Rs2AntibanSettings.simulateFatigue = true; + Rs2AntibanSettings.simulateAttentionSpan = true; + Rs2AntibanSettings.behavioralVariability = true; + Rs2AntibanSettings.nonLinearIntervals = true; + Rs2AntibanSettings.profileSwitching = true; + Rs2AntibanSettings.timeOfDayAdjust = false; + Rs2AntibanSettings.simulateMistakes = false; + Rs2AntibanSettings.naturalMouse = true; + Rs2AntibanSettings.contextualVariability = true; + Rs2AntibanSettings.dynamicIntensity = false; + Rs2AntibanSettings.dynamicActivity = false; + Rs2AntibanSettings.devDebug = false; + Rs2AntibanSettings.takeMicroBreaks = true; + Rs2AntibanSettings.playSchedule = true; + Rs2AntibanSettings.universalAntiban = false; + Rs2AntibanSettings.microBreakDurationLow = 3; + Rs2AntibanSettings.microBreakDurationHigh = 8; + Rs2AntibanSettings.actionCooldownChance = 1.00; + Rs2AntibanSettings.microBreakChance = 0.05; + Rs2Antiban.setActivity(Activity.GENERAL_AGILITY); + } + + /** + * Applies the antiban setup tailored for herblore activities. + * This setup configures settings to mimic human-like behaviors during herblore tasks. + */ + public void applyHerbloreSetup() { + // Implementation for Herblore setup + Rs2AntibanSettings.antibanEnabled = true; + Rs2AntibanSettings.usePlayStyle = true; + Rs2AntibanSettings.randomIntervals = false; + Rs2AntibanSettings.simulateFatigue = true; + Rs2AntibanSettings.simulateAttentionSpan = true; + Rs2AntibanSettings.behavioralVariability = true; + Rs2AntibanSettings.nonLinearIntervals = true; + Rs2AntibanSettings.profileSwitching = true; + Rs2AntibanSettings.timeOfDayAdjust = false; + Rs2AntibanSettings.simulateMistakes = false; + Rs2AntibanSettings.naturalMouse = true; + Rs2AntibanSettings.contextualVariability = true; + Rs2AntibanSettings.dynamicIntensity = false; + Rs2AntibanSettings.dynamicActivity = false; + Rs2AntibanSettings.devDebug = false; + Rs2AntibanSettings.takeMicroBreaks = true; + Rs2AntibanSettings.playSchedule = true; + Rs2AntibanSettings.universalAntiban = false; + Rs2AntibanSettings.microBreakDurationLow = 3; + Rs2AntibanSettings.microBreakDurationHigh = 8; + Rs2AntibanSettings.actionCooldownChance = 1.00; + Rs2AntibanSettings.microBreakChance = 0.05; + Rs2Antiban.setActivity(Activity.GENERAL_HERBLORE); + } + + /** + * Applies the antiban setup tailored for thieving activities. + * This setup simulates human-like behaviors during thieving tasks to reduce detection risk. + */ + public void applyThievingSetup() { + // Implementation for Thieving setup + Rs2AntibanSettings.antibanEnabled = true; + Rs2AntibanSettings.usePlayStyle = true; + Rs2AntibanSettings.randomIntervals = false; + Rs2AntibanSettings.simulateFatigue = true; + Rs2AntibanSettings.simulateAttentionSpan = true; + Rs2AntibanSettings.behavioralVariability = true; + Rs2AntibanSettings.nonLinearIntervals = true; + Rs2AntibanSettings.profileSwitching = true; + Rs2AntibanSettings.timeOfDayAdjust = false; + Rs2AntibanSettings.simulateMistakes = false; + Rs2AntibanSettings.naturalMouse = true; + Rs2AntibanSettings.contextualVariability = true; + Rs2AntibanSettings.dynamicIntensity = false; + Rs2AntibanSettings.dynamicActivity = false; + Rs2AntibanSettings.devDebug = false; + Rs2AntibanSettings.takeMicroBreaks = true; + Rs2AntibanSettings.playSchedule = true; + Rs2AntibanSettings.universalAntiban = false; + Rs2AntibanSettings.microBreakDurationLow = 3; + Rs2AntibanSettings.microBreakDurationHigh = 8; + Rs2AntibanSettings.actionCooldownChance = 1.00; + Rs2AntibanSettings.microBreakChance = 0.05; + Rs2Antiban.setActivity(Activity.GENERAL_THIEVING); + } + + /** + * Applies the antiban setup tailored for crafting activities. + * This setup focuses on human-like behavior simulation during crafting tasks. + */ + public void applyCraftingSetup() { + // Implementation for Crafting setup + Rs2AntibanSettings.antibanEnabled = true; + Rs2AntibanSettings.usePlayStyle = true; + Rs2AntibanSettings.randomIntervals = false; + Rs2AntibanSettings.simulateFatigue = true; + Rs2AntibanSettings.simulateAttentionSpan = true; + Rs2AntibanSettings.behavioralVariability = true; + Rs2AntibanSettings.nonLinearIntervals = true; + Rs2AntibanSettings.profileSwitching = true; + Rs2AntibanSettings.timeOfDayAdjust = false; + Rs2AntibanSettings.simulateMistakes = false; + Rs2AntibanSettings.naturalMouse = true; + Rs2AntibanSettings.contextualVariability = true; + Rs2AntibanSettings.dynamicIntensity = false; + Rs2AntibanSettings.dynamicActivity = false; + Rs2AntibanSettings.devDebug = false; + Rs2AntibanSettings.takeMicroBreaks = true; + Rs2AntibanSettings.playSchedule = true; + Rs2AntibanSettings.universalAntiban = false; + Rs2AntibanSettings.microBreakDurationLow = 3; + Rs2AntibanSettings.microBreakDurationHigh = 8; + Rs2AntibanSettings.actionCooldownChance = 1.00; + Rs2AntibanSettings.microBreakChance = 0.05; + Rs2Antiban.setActivity(Activity.GENERAL_CRAFTING); + } + + /** + * Applies the antiban setup tailored for fletching activities. + * This setup adjusts settings to mimic human behavior during fletching tasks. + */ + public void applyFletchingSetup() { + // Implementation for Fletching setup + Rs2AntibanSettings.antibanEnabled = true; + Rs2AntibanSettings.usePlayStyle = true; + Rs2AntibanSettings.randomIntervals = false; + Rs2AntibanSettings.simulateFatigue = true; + Rs2AntibanSettings.simulateAttentionSpan = true; + Rs2AntibanSettings.behavioralVariability = true; + Rs2AntibanSettings.nonLinearIntervals = true; + Rs2AntibanSettings.profileSwitching = true; + Rs2AntibanSettings.timeOfDayAdjust = false; + Rs2AntibanSettings.simulateMistakes = false; + Rs2AntibanSettings.naturalMouse = true; + Rs2AntibanSettings.contextualVariability = true; + Rs2AntibanSettings.dynamicIntensity = false; + Rs2AntibanSettings.dynamicActivity = false; + Rs2AntibanSettings.devDebug = false; + Rs2AntibanSettings.takeMicroBreaks = true; + Rs2AntibanSettings.playSchedule = true; + Rs2AntibanSettings.universalAntiban = false; + Rs2AntibanSettings.microBreakDurationLow = 3; + Rs2AntibanSettings.microBreakDurationHigh = 8; + Rs2AntibanSettings.actionCooldownChance = 1.00; + Rs2AntibanSettings.microBreakChance = 0.05; + Rs2Antiban.setActivity(Activity.GENERAL_FLETCHING); + } + + public void applySlayerSetup() { + // Implementation for Slayer setup + } + + /** + * Applies the antiban setup tailored for hunter activities. + * This setup simulates human-like behaviors during hunting tasks. + */ + public void applyHunterSetup() { + // Implementation for Hunter setup + Rs2AntibanSettings.antibanEnabled = true; + Rs2AntibanSettings.usePlayStyle = true; + Rs2AntibanSettings.randomIntervals = false; + Rs2AntibanSettings.simulateFatigue = true; + Rs2AntibanSettings.simulateAttentionSpan = true; + Rs2AntibanSettings.behavioralVariability = true; + Rs2AntibanSettings.nonLinearIntervals = true; + Rs2AntibanSettings.profileSwitching = true; + Rs2AntibanSettings.timeOfDayAdjust = false; + Rs2AntibanSettings.simulateMistakes = false; + Rs2AntibanSettings.naturalMouse = true; + Rs2AntibanSettings.contextualVariability = true; + Rs2AntibanSettings.dynamicIntensity = false; + Rs2AntibanSettings.dynamicActivity = false; + Rs2AntibanSettings.devDebug = false; + Rs2AntibanSettings.takeMicroBreaks = true; + Rs2AntibanSettings.playSchedule = true; + Rs2AntibanSettings.universalAntiban = false; + Rs2AntibanSettings.microBreakDurationLow = 3; + Rs2AntibanSettings.microBreakDurationHigh = 8; + Rs2AntibanSettings.actionCooldownChance = 1.00; + Rs2AntibanSettings.microBreakChance = 0.05; + Rs2Antiban.setActivity(Activity.GENERAL_HUNTER); + } + + /** + * Applies the antiban setup tailored for mining activities. + * This setup includes adjustments to mimic human behaviors during mining tasks. + */ + public void applyMiningSetup() { + // Implementation for Mining setup + Rs2AntibanSettings.antibanEnabled = true; + Rs2AntibanSettings.usePlayStyle = true; + Rs2AntibanSettings.randomIntervals = false; + Rs2AntibanSettings.simulateFatigue = true; + Rs2AntibanSettings.simulateAttentionSpan = true; + Rs2AntibanSettings.behavioralVariability = true; + Rs2AntibanSettings.nonLinearIntervals = true; + Rs2AntibanSettings.profileSwitching = true; + Rs2AntibanSettings.timeOfDayAdjust = false; + Rs2AntibanSettings.simulateMistakes = true; + Rs2AntibanSettings.naturalMouse = true; + Rs2AntibanSettings.contextualVariability = false; + Rs2AntibanSettings.dynamicIntensity = false; + Rs2AntibanSettings.dynamicActivity = false; + Rs2AntibanSettings.devDebug = false; + Rs2AntibanSettings.takeMicroBreaks = true; + Rs2AntibanSettings.playSchedule = true; + Rs2AntibanSettings.universalAntiban = false; + Rs2AntibanSettings.microBreakDurationLow = 1; + Rs2AntibanSettings.microBreakDurationHigh = 4; + Rs2AntibanSettings.actionCooldownChance = 1.00; + Rs2AntibanSettings.microBreakChance = 0.05; + Rs2Antiban.setActivity(Activity.GENERAL_MINING); + } + + /** + * Applies the antiban setup tailored for smithing activities. + * This setup configures settings to simulate human-like behaviors during smithing tasks. + */ + public void applySmithingSetup() { + // Implementation for Smithing setup + Rs2AntibanSettings.antibanEnabled = true; + Rs2AntibanSettings.usePlayStyle = true; + Rs2AntibanSettings.randomIntervals = false; + Rs2AntibanSettings.simulateFatigue = true; + Rs2AntibanSettings.simulateAttentionSpan = true; + Rs2AntibanSettings.behavioralVariability = true; + Rs2AntibanSettings.nonLinearIntervals = true; + Rs2AntibanSettings.profileSwitching = true; + Rs2AntibanSettings.timeOfDayAdjust = false; + Rs2AntibanSettings.simulateMistakes = false; + Rs2AntibanSettings.naturalMouse = true; + Rs2AntibanSettings.contextualVariability = true; + Rs2AntibanSettings.dynamicIntensity = false; + Rs2AntibanSettings.dynamicActivity = false; + Rs2AntibanSettings.devDebug = false; + Rs2AntibanSettings.takeMicroBreaks = true; + Rs2AntibanSettings.playSchedule = true; + Rs2AntibanSettings.universalAntiban = false; + Rs2AntibanSettings.microBreakDurationLow = 3; + Rs2AntibanSettings.microBreakDurationHigh = 8; + Rs2AntibanSettings.actionCooldownChance = 1.00; + Rs2AntibanSettings.microBreakChance = 0.05; + Rs2Antiban.setActivity(Activity.GENERAL_SMITHING); + } + + /** + * Applies the antiban setup tailored for fishing activities. + * This setup focuses on mimicking human-like behaviors during fishing tasks. + */ + public void applyFishingSetup() { + // Implementation for Fishing setup + Rs2AntibanSettings.antibanEnabled = true; + Rs2AntibanSettings.usePlayStyle = true; + Rs2AntibanSettings.randomIntervals = false; + Rs2AntibanSettings.simulateFatigue = true; + Rs2AntibanSettings.simulateAttentionSpan = true; + Rs2AntibanSettings.behavioralVariability = true; + Rs2AntibanSettings.nonLinearIntervals = true; + Rs2AntibanSettings.profileSwitching = true; + Rs2AntibanSettings.timeOfDayAdjust = false; + Rs2AntibanSettings.simulateMistakes = false; + Rs2AntibanSettings.naturalMouse = true; + Rs2AntibanSettings.contextualVariability = true; + Rs2AntibanSettings.dynamicIntensity = false; + Rs2AntibanSettings.dynamicActivity = false; + Rs2AntibanSettings.devDebug = false; + Rs2AntibanSettings.takeMicroBreaks = true; + Rs2AntibanSettings.playSchedule = true; + Rs2AntibanSettings.universalAntiban = false; + Rs2AntibanSettings.microBreakDurationLow = 3; + Rs2AntibanSettings.microBreakDurationHigh = 8; + Rs2AntibanSettings.actionCooldownChance = 1.00; + Rs2AntibanSettings.microBreakChance = 0.05; + Rs2Antiban.setActivity(Activity.GENERAL_FISHING); + } + + /** + * Applies the antiban setup tailored for cooking activities. + * This setup simulates human-like behaviors during cooking tasks to reduce detection risk. + */ + public void applyCookingSetup() { + // Implementation for Cooking setup + Rs2AntibanSettings.antibanEnabled = true; + Rs2AntibanSettings.usePlayStyle = true; + Rs2AntibanSettings.randomIntervals = false; + Rs2AntibanSettings.simulateFatigue = true; + Rs2AntibanSettings.simulateAttentionSpan = true; + Rs2AntibanSettings.behavioralVariability = true; + Rs2AntibanSettings.nonLinearIntervals = true; + Rs2AntibanSettings.profileSwitching = true; + Rs2AntibanSettings.timeOfDayAdjust = false; + Rs2AntibanSettings.simulateMistakes = false; + Rs2AntibanSettings.naturalMouse = true; + Rs2AntibanSettings.contextualVariability = true; + Rs2AntibanSettings.dynamicIntensity = false; + Rs2AntibanSettings.dynamicActivity = false; + Rs2AntibanSettings.devDebug = false; + Rs2AntibanSettings.takeMicroBreaks = true; + Rs2AntibanSettings.playSchedule = true; + Rs2AntibanSettings.universalAntiban = false; + Rs2AntibanSettings.microBreakDurationLow = 3; + Rs2AntibanSettings.microBreakDurationHigh = 8; + Rs2AntibanSettings.actionCooldownChance = 1.00; + Rs2AntibanSettings.microBreakChance = 0.05; + Rs2Antiban.setActivity(Activity.GENERAL_COOKING); + } + + /** + * Applies the antiban setup tailored for firemaking activities. + * This setup is designed to simulate human behavior during firemaking tasks. + */ + public void applyFiremakingSetup() { + // Implementation for Firemaking setup + Rs2AntibanSettings.antibanEnabled = true; + Rs2AntibanSettings.usePlayStyle = true; + Rs2AntibanSettings.randomIntervals = false; + Rs2AntibanSettings.simulateFatigue = true; + Rs2AntibanSettings.simulateAttentionSpan = true; + Rs2AntibanSettings.behavioralVariability = true; + Rs2AntibanSettings.nonLinearIntervals = true; + Rs2AntibanSettings.profileSwitching = true; + Rs2AntibanSettings.timeOfDayAdjust = false; + Rs2AntibanSettings.simulateMistakes = false; + Rs2AntibanSettings.naturalMouse = true; + Rs2AntibanSettings.contextualVariability = true; + Rs2AntibanSettings.dynamicIntensity = false; + Rs2AntibanSettings.dynamicActivity = false; + Rs2AntibanSettings.devDebug = false; + Rs2AntibanSettings.takeMicroBreaks = true; + Rs2AntibanSettings.playSchedule = true; + Rs2AntibanSettings.universalAntiban = false; + Rs2AntibanSettings.microBreakDurationLow = 3; + Rs2AntibanSettings.microBreakDurationHigh = 8; + Rs2AntibanSettings.actionCooldownChance = 1.00; + Rs2AntibanSettings.microBreakChance = 0.05; + Rs2Antiban.setActivity(Activity.GENERAL_FIREMAKING); + } + + /** + * Applies the antiban setup tailored for woodcutting activities. + * This setup mimics human-like behaviors during woodcutting tasks to reduce detection risk. + */ + public void applyWoodcuttingSetup() { + // Implementation for Woodcutting setup + Rs2AntibanSettings.antibanEnabled = true; + Rs2AntibanSettings.usePlayStyle = true; + Rs2AntibanSettings.randomIntervals = false; + Rs2AntibanSettings.simulateFatigue = true; + Rs2AntibanSettings.simulateAttentionSpan = true; + Rs2AntibanSettings.behavioralVariability = true; + Rs2AntibanSettings.nonLinearIntervals = true; + Rs2AntibanSettings.profileSwitching = true; + Rs2AntibanSettings.timeOfDayAdjust = false; + Rs2AntibanSettings.simulateMistakes = false; + Rs2AntibanSettings.naturalMouse = true; + Rs2AntibanSettings.contextualVariability = true; + Rs2AntibanSettings.dynamicIntensity = false; + Rs2AntibanSettings.dynamicActivity = false; + Rs2AntibanSettings.devDebug = false; + Rs2AntibanSettings.takeMicroBreaks = true; + Rs2AntibanSettings.playSchedule = true; + Rs2AntibanSettings.universalAntiban = false; + Rs2AntibanSettings.microBreakDurationLow = 3; + Rs2AntibanSettings.microBreakDurationHigh = 8; + Rs2AntibanSettings.actionCooldownChance = 1.00; + Rs2AntibanSettings.microBreakChance = 0.05; + Rs2Antiban.setActivity(Activity.GENERAL_WOODCUTTING); + } + + /** + * Applies the antiban setup tailored for farming activities. + * This setup configures settings to simulate human-like behaviors during farming tasks. + */ + public void applyFarmingSetup() { + // Implementation for Farming setup + Rs2AntibanSettings.antibanEnabled = true; + Rs2AntibanSettings.usePlayStyle = true; + Rs2AntibanSettings.randomIntervals = false; + Rs2AntibanSettings.simulateFatigue = true; + Rs2AntibanSettings.simulateAttentionSpan = true; + Rs2AntibanSettings.behavioralVariability = true; + Rs2AntibanSettings.nonLinearIntervals = true; + Rs2AntibanSettings.profileSwitching = true; + Rs2AntibanSettings.timeOfDayAdjust = false; + Rs2AntibanSettings.simulateMistakes = false; + Rs2AntibanSettings.naturalMouse = true; + Rs2AntibanSettings.contextualVariability = false; + Rs2AntibanSettings.dynamicIntensity = false; + Rs2AntibanSettings.dynamicActivity = false; + Rs2AntibanSettings.devDebug = false; + Rs2AntibanSettings.takeMicroBreaks = true; + Rs2AntibanSettings.playSchedule = true; + Rs2AntibanSettings.universalAntiban = false; + Rs2AntibanSettings.microBreakDurationLow = 3; + Rs2AntibanSettings.microBreakDurationHigh = 8; + Rs2AntibanSettings.actionCooldownChance = 1.00; + Rs2AntibanSettings.microBreakChance = 0.05; + Rs2Antiban.setActivity(Activity.GENERAL_FARMING); + } + + /** + * Applies the basic antiban setup. + * This setup configures settings to simulate human-like mouse movement and reduce detection risk. + * This setup does not include advanced features such as action cooldown, attention span or micro breaks. + */ + public void applyGeneralBasicSetup() { + // Implementation for General Basic setup + Rs2AntibanSettings.antibanEnabled = true; + Rs2AntibanSettings.usePlayStyle = false; + Rs2AntibanSettings.randomIntervals = false; + Rs2AntibanSettings.simulateFatigue = true; + Rs2AntibanSettings.simulateAttentionSpan = false; + Rs2AntibanSettings.behavioralVariability = false; + Rs2AntibanSettings.nonLinearIntervals = false; + Rs2AntibanSettings.profileSwitching = false; + Rs2AntibanSettings.timeOfDayAdjust = false; + Rs2AntibanSettings.simulateMistakes = true; + Rs2AntibanSettings.naturalMouse = true; + Rs2AntibanSettings.contextualVariability = false; + Rs2AntibanSettings.dynamicIntensity = false; + Rs2AntibanSettings.dynamicActivity = false; + Rs2AntibanSettings.devDebug = false; + Rs2AntibanSettings.takeMicroBreaks = false; + Rs2AntibanSettings.playSchedule = false; + Rs2AntibanSettings.universalAntiban = false; + Rs2AntibanSettings.microBreakDurationLow = 3; + Rs2AntibanSettings.microBreakDurationHigh = 8; + Rs2AntibanSettings.actionCooldownChance = 1.00; + Rs2AntibanSettings.microBreakChance = 0.05; + } + + +} + diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/util/antiban/MouseFatigue.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/util/antiban/MouseFatigue.java new file mode 100644 index 0000000000..aee1e896d0 --- /dev/null +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/util/antiban/MouseFatigue.java @@ -0,0 +1,20 @@ +package net.runelite.client.plugins.microbot.util.antiban; + +import java.util.Random; + +public class MouseFatigue { + + + private final Random random = new Random(); + public double increaseRate = 0.005; + public double noiseAmplitude = 5.0; + + // Method to calculate the base time with noise + public int calculateBaseTimeWithNoise(int initialBaseTimeMs, int maxBaseTimeMs) { + double noise = random.nextGaussian() * noiseAmplitude; + int newBaseTimeMs = (int) (initialBaseTimeMs + AntibanPlugin.ticksSinceLogin * increaseRate + noise); + return Math.min(newBaseTimeMs, maxBaseTimeMs); + } + + +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/util/antiban/Rs2Antiban.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/util/antiban/Rs2Antiban.java new file mode 100644 index 0000000000..17ac5988cf --- /dev/null +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/util/antiban/Rs2Antiban.java @@ -0,0 +1,523 @@ +package net.runelite.client.plugins.microbot.util.antiban; + +import com.google.common.collect.ImmutableSet; +import lombok.Getter; +import lombok.Setter; +import net.runelite.api.ChatMessageType; +import net.runelite.api.events.ChatMessage; +import net.runelite.client.plugins.microbot.Microbot; +import net.runelite.client.plugins.microbot.breakhandler.BreakHandlerScript; +import net.runelite.client.plugins.microbot.util.antiban.enums.Activity; +import net.runelite.client.plugins.microbot.util.antiban.enums.ActivityIntensity; +import net.runelite.client.plugins.microbot.util.antiban.enums.Category; +import net.runelite.client.plugins.microbot.util.antiban.enums.PlayStyle; +import net.runelite.client.plugins.microbot.util.math.Random; +import net.runelite.client.plugins.microbot.util.math.Rs2Random; +import net.runelite.client.plugins.microbot.util.player.Rs2Player; +import net.runelite.client.ui.overlay.components.*; +import net.runelite.client.util.ColorUtil; + +import java.awt.*; +import java.util.Set; + +import static net.runelite.api.AnimationID.*; + +/** + * The {@code Rs2Antiban} class provides a comprehensive anti-ban system that simulates human-like behavior + * during various in-game activities. This system includes features such as mouse fatigue, random intervals, + * micro-breaks, action cooldowns, and contextually aware mouse movements, all aimed at reducing the risk + * of detection by anti-cheat systems. + * + *

+ * 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. + *

+ * + *

Main Features:

+ *
    + *
  • Human-Like Behavior Simulation: Simulates actions such as moving the mouse randomly, taking micro-breaks, + * and varying the intervals between actions to mimic natural gameplay.
  • + *
  • Activity-Based Configurations: Allows setting activity-specific antiban configurations through + * the {@code setActivity()} and {@code setActivityIntensity()} methods, ensuring that the antiban + * behavior is appropriate for the current task.
  • + *
  • Mouse Fatigue Simulation: Integrates with a mouse fatigue system to simulate the effects of fatigue + * on mouse movement over time.
  • + *
  • Overlay Rendering: Provides methods to render an overlay that displays current antiban status, + * including activity, play style, and action cooldown progress.
  • + *
  • Micro-Breaks and Cooldowns: Supports taking breaks based on a random chance or specific intervals + * to simulate a player taking short pauses during gameplay.
  • + *
+ * + *

Usage:

+ *

+ * 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. + *

+ * + *

Example:

+ *
+ * // 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);
+ * 
+ * + *

Available Methods:

+ *
    + *
  • 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.
  • + *
+ */ + +@Getter +@Setter +public class Rs2Antiban { + public static final ImmutableSet MINING_ANIMATION_IDS = ImmutableSet.of( + MINING_BRONZE_PICKAXE, MINING_MOTHERLODE_BRONZE, MINING_CRASHEDSTAR_BRONZE, + MINING_IRON_PICKAXE, MINING_MOTHERLODE_IRON, MINING_CRASHEDSTAR_IRON, + MINING_STEEL_PICKAXE, MINING_MOTHERLODE_STEEL, MINING_CRASHEDSTAR_STEEL, + MINING_BLACK_PICKAXE, MINING_MOTHERLODE_BLACK, MINING_CRASHEDSTAR_BLACK, + MINING_MITHRIL_PICKAXE, MINING_MOTHERLODE_MITHRIL, MINING_CRASHEDSTAR_MITHRIL, + MINING_ADAMANT_PICKAXE, MINING_MOTHERLODE_ADAMANT, MINING_CRASHEDSTAR_ADAMANT, + MINING_RUNE_PICKAXE, MINING_MOTHERLODE_RUNE, MINING_CRASHEDSTAR_RUNE, + MINING_GILDED_PICKAXE, MINING_MOTHERLODE_GILDED, MINING_CRASHEDSTAR_GILDED, + MINING_DRAGON_PICKAXE, MINING_MOTHERLODE_DRAGON, MINING_CRASHEDSTAR_DRAGON, + MINING_DRAGON_PICKAXE_OR, MINING_MOTHERLODE_DRAGON_OR, MINING_CRASHEDSTAR_DRAGON_OR, + MINING_DRAGON_PICKAXE_OR_TRAILBLAZER, MINING_MOTHERLODE_DRAGON_OR_TRAILBLAZER, MINING_CRASHEDSTAR_DRAGON_OR_TRAILBLAZER, + MINING_DRAGON_PICKAXE_UPGRADED, MINING_MOTHERLODE_DRAGON_UPGRADED, MINING_CRASHEDSTAR_DRAGON_UPGRADED, + MINING_INFERNAL_PICKAXE, MINING_MOTHERLODE_INFERNAL, MINING_CRASHEDSTAR_INFERNAL, + MINING_3A_PICKAXE, MINING_MOTHERLODE_3A, MINING_CRASHEDSTAR_3A, + MINING_CRYSTAL_PICKAXE, MINING_MOTHERLODE_CRYSTAL, MINING_CRASHEDSTAR_CRYSTAL, + MINING_TRAILBLAZER_PICKAXE, MINING_TRAILBLAZER_PICKAXE_2, MINING_TRAILBLAZER_PICKAXE_3, MINING_MOTHERLODE_TRAILBLAZER + ); + private static final Set WOODCUTTING_ANIMS = ImmutableSet.of( + WOODCUTTING_BRONZE, WOODCUTTING_IRON, WOODCUTTING_STEEL, WOODCUTTING_BLACK, WOODCUTTING_MITHRIL, + WOODCUTTING_ADAMANT, WOODCUTTING_RUNE, WOODCUTTING_GILDED, WOODCUTTING_DRAGON, WOODCUTTING_DRAGON_OR, + WOODCUTTING_INFERNAL, WOODCUTTING_3A_AXE, WOODCUTTING_CRYSTAL, WOODCUTTING_TRAILBLAZER, + WOODCUTTING_2H_BRONZE, WOODCUTTING_2H_IRON, WOODCUTTING_2H_STEEL, WOODCUTTING_2H_BLACK, + WOODCUTTING_2H_MITHRIL, WOODCUTTING_2H_ADAMANT, WOODCUTTING_2H_RUNE, WOODCUTTING_2H_DRAGON, + WOODCUTTING_2H_CRYSTAL, WOODCUTTING_2H_CRYSTAL_INACTIVE, WOODCUTTING_2H_3A + ); + + // Mouse fatigue class + public static MouseFatigue mouseFatigue = new MouseFatigue(); + + // Antiban setup class + public static AntibanSetupTemplates antibanSetupTemplates = new AntibanSetupTemplates(); + + @Getter + @Setter + public static int TIMEOUT = 0; + @Getter + private static Activity activity; + @Getter + private static ActivityIntensity activityIntensity; + @Getter + @Setter + private static Category category; + @Getter + @Setter + private static PlayStyle playStyle; + + + public static void setActivity(Activity activity) { + Rs2Antiban.activity = activity; + Rs2Antiban.category = activity.getCategory(); + Rs2Antiban.activityIntensity = activity.getActivityIntensity(); + + if (Rs2AntibanSettings.simulateAttentionSpan) { + Rs2Antiban.playStyle = PlayStyle.EXTREME_AGGRESSIVE; + //Rs2Antiban.playStyle = activityIntensity.getPlayStyle(); + } else { + if (Rs2Antiban.playStyle == null) + Rs2Antiban.playStyle = activityIntensity.getPlayStyle(); + } + + if (Rs2AntibanSettings.randomIntervals) { + Rs2Antiban.playStyle = PlayStyle.RANDOM; + } + playStyle.frequency = activityIntensity.getFrequency(); + playStyle.amplitude = activityIntensity.getAmplitude(); + Rs2Antiban.playStyle.resetPlayStyle(); + + + } + + public static void setActivityIntensity(ActivityIntensity activityIntensity) { + Rs2AntibanSettings.dynamicIntensity = false; + Rs2Antiban.activityIntensity = activityIntensity; + } + + + public static boolean checkForCookingEvent(ChatMessage event) { + if (event.getType() != ChatMessageType.SPAM) { + return false; + } + final String message = event.getMessage(); + return message.startsWith("You successfully cook") + || message.startsWith("You successfully bake") + || message.startsWith("You successfully fry") + || message.startsWith("You manage to cook") + || message.startsWith("You roast a") + || message.startsWith("You spit-roast") + || message.startsWith("You cook") + || message.startsWith("Eventually the Jubbly") + || message.startsWith("You half-cook") + || message.startsWith("The undead meat is now cooked") + || message.startsWith("The undead chicken is now cooked") + || message.startsWith("You successfully scramble") + || message.startsWith("You dry a piece of meat") + || message.startsWith("You accidentally burn") + || message.equals("You burn the mushroom in the fire.") + || message.startsWith("Unfortunately the Jubbly") + || message.startsWith("You accidentally spoil"); + } + + /** + * Checks if the player is currently performing a woodcutting animation. + * + * @return true if the player is performing a woodcutting animation, false otherwise. + */ + public static boolean isWoodcutting() { + return WOODCUTTING_ANIMS.contains(Rs2Player.getAnimation()); + } + + /** + * Checks if the player is currently performing a mining animation. + * + * @return true if the player is performing a mining animation, false otherwise. + */ + public static boolean isMining() { + return MINING_ANIMATION_IDS.contains(Rs2Player.getAnimation()); + } + + /** + * Checks if the player is currently idle. + * + * @return true if the player is idle, false otherwise. + */ + public static boolean isIdle() { + return AntibanPlugin.isIdle(); + } + + /** + *

Handles the Execution of an Action Cooldown Based on Anti-Ban Behaviors

+ *

+ * 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. + *

+ * + *

Primary Actions Handled:

+ *
    + *
  • Pausing all scripts if the universal antiban is enabled.
  • + *
  • Evolving play style if non-linear intervals are enabled.
  • + *
  • Setting a timeout based on behavioral variability settings.
  • + *
  • Optionally moving the mouse randomly or off-screen based on respective settings.
  • + *
+ * + *

Preconditions:

+ *
    + *
  • If Rs2AntibanSettings.usePlayStyle is disabled, the cooldown will not be performed.
  • + *
+ * + *

Main Flow:

+ *
    + *
  • If actionCooldownChance < 1.00 (100%), the cooldown is triggered based on the result of a random dice roll.
  • + *
  • If actionCooldownChance is 1.00 (100%) or greater, the cooldown is triggered unconditionally.
  • + *
+ * + *

Helper Methods:

+ *

+ * 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. + *

+ */ + + public static void actionCooldown() { + if (Rs2AntibanSettings.actionCooldownChance <= 0.99) { + if (Rs2Random.dice(Rs2AntibanSettings.actionCooldownChance)) { + performActionCooldown(); + } + return; + } + + if (!Rs2AntibanSettings.usePlayStyle) { + Microbot.log("PlayStyle not enabled, cannot perform action cooldown"); + return; + } + + performActionCooldown(); + } + + private static void performActionCooldown() { + if (Rs2AntibanSettings.universalAntiban) + Microbot.pauseAllScripts = true; + + if (Rs2AntibanSettings.nonLinearIntervals) + playStyle.evolvePlayStyle(); + + if (Rs2AntibanSettings.behavioralVariability) + TIMEOUT = playStyle.getRandomTickInterval(); + else + TIMEOUT = playStyle.getPrimaryTickInterval(); + + Rs2AntibanSettings.actionCooldownActive = true; + + if (Rs2AntibanSettings.moveMouseRandomly && Rs2Random.dice(Rs2AntibanSettings.moveMouseRandomlyChance)) { + Rs2Random.wait(100, 200); + moveMouseRandomly(); + } + + if (Rs2AntibanSettings.moveMouseOffScreen) + moveMouseOffScreen(); + } + + + /** + * Attempts to trigger a micro-break based on a random chance, as configured in Rs2AntibanSettings. + * + *

+ * 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. + *

+ * + *

Behavior:

+ *
    + *
  • If a random value is less than Rs2AntibanSettings.microBreakChance, the micro-break is activated.
  • + *
  • The break duration is randomly set between Rs2AntibanSettings.microBreakDurationLow and + * Rs2AntibanSettings.microBreakDurationHigh, in seconds.
  • + *
  • If Rs2AntibanSettings.moveMouseOffScreen is enabled, the mouse is moved off-screen during the break.
  • + *
+ * + *

Preconditions:

+ *
    + *
  • The configuration in Rs2AntibanSettings must define valid break chance and duration values.
  • + *
+ * + *

Postconditions:

+ *
    + *
  • Rs2AntibanSettings.microBreakActive is set to true if the break is triggered.
  • + *
  • BreakHandlerScript.breakDuration is set to a randomly determined value in seconds.
  • + *
+ * @return true if a micro-break is triggered, false otherwise. + */ + + public static boolean takeMicroBreakByChance() { + if (Math.random() < Rs2AntibanSettings.microBreakChance) { + Rs2AntibanSettings.microBreakActive = true; + BreakHandlerScript.breakDuration = Random.random(Rs2AntibanSettings.microBreakDurationLow * 60, Rs2AntibanSettings.microBreakDurationHigh * 60); + if (Rs2AntibanSettings.moveMouseOffScreen) + moveMouseOffScreen(); + return true; + + } + return false; + } + + + /** + * Renders an overlay component that displays various anti-ban settings and information within a panel. + * + *

+ * 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. + *

+ * + *

Overlay Components:

+ *
    + *
  • A title component labeled "🦆 Humanizer 🦆" with orange coloring.
  • + *
  • Details about the current activity, including method name, category, and intensity.
  • + *
  • If Rs2AntibanSettings.devDebug is enabled, several debug lines will show key anti-ban settings, + * such as action cooldown, random intervals, and behavioral variability.
  • + *
  • If a play style is active, the panel displays the current play style name and the time remaining until the next switch + * if attention span simulation is enabled.
  • + *
  • A progress bar representing the current action cooldown based on a tick interval, providing a visual cue for + * the remaining time.
  • + *
  • Status updates on whether the bot is busy or idle, indicating potential upcoming breaks.
  • + *
+ * + *

Behavior:

+ *
    + *
  • The method dynamically updates the panel with current information based on settings in Rs2AntibanSettings + * and playStyle.
  • + *
  • If debug mode is enabled, additional lines provide detailed state information, such as whether action cooldown, + * fatigue simulation, and natural mouse movements are active.
  • + *
  • The progress bar visually indicates the current state of the action cooldown timer.
  • + *
+ * + *

Preconditions:

+ *
    + *
  • playStyle and Rs2AntibanSettings must be properly initialized.
  • + *
  • The panelComponent must be passed as a valid and non-null component to receive overlay data.
  • + *
+ * + *

Where to Use:

+ *

+ * 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: + *

+ *
    + *
  1. Ensure that your overlay class extends OverlayPanel or a similar class that supports adding components.
  2. + *
  3. Invoke Rs2Antiban.renderAntibanOverlayComponents(panelComponent); within the overlay's + * render method, before or after other components are added, depending on the desired layout.
  4. + *
  5. Ensure that the appropriate Rs2AntibanSettings are configured before invoking the method.
  6. + *
+ * + *

Example Usage:

+ *
+     * {@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); + } + + } + + /** + *

Move Mouse Off Screen

+ * This method moves the mouse off the screen with a 1/4 chance to trigger. + * This is used to simulate a user moving the mouse off the screen to take a break. + */ + public static void moveMouseOffScreen() { + Microbot.naturalMouse.moveOffScreen(); + } + + /** + *

Move Mouse Randomly

+ * This method moves the mouse randomly based on the given chance in settings. + * This is used to simulate a user moving the mouse randomly to take a break. + */ + public static void moveMouseRandomly() { + Microbot.naturalMouse.moveRandom(); + } + + public static void activateAntiban() { + Rs2AntibanSettings.antibanEnabled = true; + } + + public static void deactivateAntiban() { + Rs2AntibanSettings.antibanEnabled = false; + } + + // reset all the variables + public static void resetAntibanSettings() { + Rs2AntibanSettings.reset(); + Rs2Antiban.playStyle = null; + Rs2Antiban.activity = null; + Rs2Antiban.activityIntensity = null; + Rs2Antiban.category = null; + } + +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/util/antiban/Rs2AntibanSettings.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/util/antiban/Rs2AntibanSettings.java new file mode 100644 index 0000000000..e6009cc913 --- /dev/null +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/util/antiban/Rs2AntibanSettings.java @@ -0,0 +1,135 @@ +package net.runelite.client.plugins.microbot.util.antiban; + +/** + * Provides configuration settings for the anti-ban system used by various plugins within the bot framework. + * + *

+ * 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. + *

+ * + *

Main Features:

+ *
    + *
  • Action Cooldowns: Controls the cooldown behavior of actions, including random intervals + * and non-linear patterns.
  • + *
  • Micro Breaks: Defines settings for taking small breaks at random intervals to simulate human pauses.
  • + *
  • Play Style Simulation: Includes variables to simulate different play styles, attention span, + * and behavioral variability to create a more realistic user profile.
  • + *
  • Mouse Movements: Settings to control mouse behavior, such as moving off-screen or randomly, + * mimicking natural user actions.
  • + *
  • Dynamic Behaviors: Provides options to dynamically adjust activity intensity and behavior + * based on context and time of day.
  • + *
+ * + *

Fields:

+ *
    + *
  • 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.
  • + *
+ * + *

Usage:

+ *

+ * 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. + *

+ * + *

Example:

+ *
+ * // 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. + *

+ * + *

Main Features:

+ *
    + *
  • Wide Range of Activities: Covers general skilling activities such as mining, cooking, and woodcutting, + * as well as high-intensity tasks like boss fights and combat encounters.
  • + *
  • Category Association: Each activity is linked to a Category that helps the bot identify the + * type of activity and how to handle it.
  • + *
  • Intensity Levels: Activities have different intensity levels based on their complexity and demands, which are + * represented by ActivityIntensity. For example, combat activities tend to have higher intensity, while + * skilling tasks may be more moderate or low intensity.
  • + *
  • Skill Mapping: The enum provides a method to map game skills to the appropriate general activity, + * ensuring that the bot behaves correctly when training a particular skill.
  • + *
+ * + *

Usage:

+ *

+ * 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. + *

+ * + *

Example:

+ *
+ * Rs2Antiban.setActivity(Activity activity);
+ * Rs2Antiban.getCategory();
+ * Rs2Antiban.setActivityIntensity(ActivityIntensity activityIntensity);
+ * 
+ * + *

Skill-Based Activity Mapping:

+ *

+ * 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. + *

+ * + *

Activity Categories and Intensities:

+ *

+ * 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. + *

+ */ + +public enum Activity { + GENERAL_MINING("General Mining", Category.SKILLING_MINING, ActivityIntensity.LOW), + GENERAL_SMITHING("General Smithing", Category.SKILLING_SMITHING, ActivityIntensity.LOW), + GENERAL_FISHING("General Fishing", Category.SKILLING_FISHING, ActivityIntensity.LOW), + GENERAL_COOKING("General Cooking", Category.SKILLING_COOKING, ActivityIntensity.LOW), + GENERAL_FIREMAKING("General Firemaking", Category.SKILLING_FIREMAKING, ActivityIntensity.LOW), + GENERAL_WOODCUTTING("General Woodcutting", Category.SKILLING_WOODCUTTING, ActivityIntensity.LOW), + GENERAL_FLETCHING("General Fletching", Category.SKILLING_FLETCHING, ActivityIntensity.LOW), + GENERAL_CRAFTING("General Crafting", Category.SKILLING_CRAFTING, ActivityIntensity.LOW), + GENERAL_AGILITY("General Agility", Category.SKILLING_AGILITY, ActivityIntensity.MODERATE), + GENERAL_THIEVING("General Thieving", Category.SKILLING_THIEVING, ActivityIntensity.MODERATE), + GENERAL_SLAYER("General Slayer", Category.COMBAT_HIGH, ActivityIntensity.MODERATE), + GENERAL_RUNECRAFT("General Runecraft", Category.SKILLING_RUNECRAFT, ActivityIntensity.MODERATE), + GENERAL_HUNTER("General Hunter", Category.SKILLING_HUNTER, ActivityIntensity.MODERATE), + GENERAL_COMBAT("General Combat", Category.COMBAT_HIGH, ActivityIntensity.HIGH), + GENERAL_HERBLORE("General Herblore", Category.SKILLING_HERBLORE, ActivityIntensity.LOW), + GENERAL_FARMING("General Farming", Category.SKILLING_FARMING, ActivityIntensity.MODERATE), + GENERAL_PRAYER("General Prayer", Category.SKILLING_PRAYER, ActivityIntensity.HIGH), + GENERAL_CONSTRUCTION("General Construction", Category.SKILLING_CONSTRUCTION, ActivityIntensity.MODERATE), + COMPLETING_THE_FORTIS_COLOSSEUM_WAVE_12("Completing the Fortis Colosseum (Wave 12)", Category.COMBAT_HIGH, ActivityIntensity.HIGH), + KILLING_NEX_DUO("Killing Nex (Duo)", Category.COMBAT_HIGH, ActivityIntensity.HIGH), + TOMBS_OF_AMASCUT_SOLO_500_RAID_LEVEL("Tombs of Amascut (solo 500 raid level)", Category.COMBAT_HIGH, ActivityIntensity.HIGH), + KILLING_NEX_TEAM("Killing Nex (Team)", Category.COMBAT_HIGH, ActivityIntensity.HIGH), + THEATRE_OF_BLOOD_SCYTHE_OF_VITUR("Theatre of Blood (Scythe of vitur)", Category.COMBAT_HIGH, ActivityIntensity.HIGH), + CHAMBERS_OF_XERIC("Chambers of Xeric", Category.COMBAT_HIGH, ActivityIntensity.HIGH), + THEATRE_OF_BLOOD_ABYSSAL_TENTACLE("Theatre of Blood (Abyssal tentacle)", Category.COMBAT_HIGH, ActivityIntensity.HIGH), + KILLING_KREEARRA("Killing Kreearra", Category.COMBAT_HIGH, ActivityIntensity.HIGH), + KILLING_PHOSANIS_NIGHTMARE("Killing Phosanis Nightmare", Category.COMBAT_HIGH, ActivityIntensity.HIGH), + KILLING_VENENATIS("Killing Venenatis", Category.COMBAT_HIGH, ActivityIntensity.HIGH), + KILLING_VARDORVIS("Killing Vardorvis", Category.COMBAT_HIGH, ActivityIntensity.HIGH), + TOMBS_OF_AMASCUT_EXPERT("Tombs of Amascut (Expert)", Category.COMBAT_HIGH, ActivityIntensity.HIGH), + KILLING_COMMANDER_ZILYANA("Killing Commander Zilyana", Category.COMBAT_HIGH, ActivityIntensity.HIGH), + KILLING_SPINDEL("Killing Spindel", Category.COMBAT_HIGH, ActivityIntensity.HIGH), + KILLING_VETION("Killing Vetion", Category.COMBAT_HIGH, ActivityIntensity.HIGH), + KILLING_PHANTOM_MUSPAH_TWISTED_BOW("Killing Phantom Muspah (Twisted bow)", Category.COMBAT_HIGH, ActivityIntensity.HIGH), + KILLING_THE_ALCHEMICAL_HYDRA("Killing the Alchemical Hydra", Category.COMBAT_HIGH, ActivityIntensity.HIGH), + COMPLETING_THE_CORRUPTED_GAUNTLET("Completing The Corrupted Gauntlet", Category.COMBAT_HIGH, ActivityIntensity.HIGH), + KILLING_CERBERUS("Killing Cerberus", Category.COMBAT_HIGH, ActivityIntensity.HIGH), + KILLING_GENERAL_GRAARDOR("Killing General Graardor", Category.COMBAT_HIGH, ActivityIntensity.HIGH), + KILLING_DEMONIC_GORILLAS("Killing demonic gorillas", Category.COMBAT_HIGH, ActivityIntensity.HIGH), + KILLING_THE_WHISPERER("Killing The Whisperer", Category.COMBAT_HIGH, ActivityIntensity.HIGH), + KILLING_DUKE_SUCELLUS("Killing Duke Sucellus", Category.COMBAT_HIGH, ActivityIntensity.HIGH), + KILLING_THE_NIGHTMARE("Killing The Nightmare", Category.COMBAT_HIGH, ActivityIntensity.HIGH), + KILLING_CALVARION("Killing Calvarion", Category.COMBAT_HIGH, ActivityIntensity.HIGH), + KILLING_THE_LEVIATHAN("Killing The Leviathan", Category.COMBAT_HIGH, ActivityIntensity.HIGH), + PICKPOCKETING_VYRES("Pickpocketing vyres", Category.SKILLING_THIEVING, ActivityIntensity.HIGH), + KILLING_CALLISTO("Killing Callisto", Category.COMBAT_HIGH, ActivityIntensity.HIGH), + KILLING_REVENANTS_CRAWS_BOW("Killing revenants (Craws bow)", Category.COMBAT_MID, ActivityIntensity.HIGH), + KILLING_ARTIO("Killing Artio", Category.COMBAT_HIGH, ActivityIntensity.HIGH), + KILLING_VORKATH_DRAGON_HUNTER_LANCE("Killing Vorkath (Dragon hunter lance)", Category.COMBAT_HIGH, ActivityIntensity.HIGH), + KILLING_VORKATH_DRAGON_HUNTER_CROSSBOW("Killing Vorkath (Dragon hunter crossbow)", Category.COMBAT_HIGH, ActivityIntensity.HIGH), + KILLING_ZULRAH_MAX_EFFICIENCY("Killing Zulrah (max efficiency)", Category.COMBAT_HIGH, ActivityIntensity.HIGH), + COMPLETING_THE_FORTIS_COLOSSEUM_WAVE_1("Completing the Fortis Colosseum (Wave 1)", Category.COMBAT_HIGH, ActivityIntensity.HIGH), + WILDERNESS_AGILITY_COURSE("Wilderness Agility Course", Category.SKILLING_AGILITY, ActivityIntensity.HIGH), + KILLING_KRIL_TSUTSAROTH("Killing Kril Tsutsaroth", Category.COMBAT_HIGH, ActivityIntensity.HIGH), + KILLING_REVENANTS_MAGIC_SHORTBOW("Killing revenants (Magic shortbow)", Category.COMBAT_MID, ActivityIntensity.HIGH), + PICKPOCKETING_ELVES("Pickpocketing elves", Category.SKILLING_THIEVING, ActivityIntensity.HIGH), + KILLING_DAGANNOTH_KINGS_SOLO_TRIBRID("Killing Dagannoth Kings (Solo tribrid)", Category.COMBAT_HIGH, ActivityIntensity.MODERATE), + KILLING_THE_CORPOREAL_BEAST("Killing the Corporeal Beast", Category.COMBAT_HIGH, ActivityIntensity.HIGH), + KILLING_ZOMBIE_PIRATES("Killing zombie pirates", Category.COMBAT_LOW, ActivityIntensity.HIGH), + OPENING_ESSENCE_IMPLING_JARS("Opening essence impling jars", Category.PROCESSING, ActivityIntensity.HIGH), + CRAFTING_WRATH_RUNES("Crafting wrath runes", Category.SKILLING_RUNECRAFT, ActivityIntensity.HIGH), + KILLING_THE_GIANT_MOLE_TWISTED_BOW("Killing the Giant Mole (Twisted bow)", Category.COMBAT_MID, ActivityIntensity.LOW), + STEALING_FROM_ROGUES_CASTLE_CHESTS("Stealing from Rogues Castle chests", Category.SKILLING_THIEVING, ActivityIntensity.HIGH), + COMPLETING_THE_GAUNTLET("Completing The Gauntlet", Category.COMBAT_HIGH, ActivityIntensity.HIGH), + DELIVERING_FOOD_IN_GNOME_RESTAURANT("Delivering food in Gnome Restaurant", Category.COLLECTING, ActivityIntensity.HIGH), + OPENING_GRUBBY_CHESTS("Opening grubby chests", Category.PROCESSING, ActivityIntensity.HIGH), + MOONS_OF_PERIL("Moons of Peril", Category.COMBAT_HIGH, ActivityIntensity.HIGH), + CRAFTING_BLOOD_RUNES("Crafting blood runes", Category.SKILLING_RUNECRAFT, ActivityIntensity.HIGH), + KILLING_VORKATH_TOXIC_BLOWPIPE("Killing Vorkath (Toxic blowpipe)", Category.COMBAT_HIGH, ActivityIntensity.HIGH), + HALLOWED_SEPULCHRE("Hallowed Sepulchre", Category.SKILLING_AGILITY, ActivityIntensity.HIGH), + OPENING_SINISTER_CHESTS("Opening sinister chests", Category.PROCESSING, ActivityIntensity.HIGH), + CRAFTING_ASTRAL_RUNES("Crafting astral runes", Category.SKILLING_RUNECRAFT, ActivityIntensity.HIGH), + OPENING_ECLECTIC_IMPLING_JARS("Opening eclectic impling jars", Category.PROCESSING, ActivityIntensity.HIGH), + MAKING_TOY_CATS("Making toy cats", Category.PROCESSING, ActivityIntensity.HIGH), + CRAFTING_SUNFIRE_RUNES("Crafting sunfire runes", Category.SKILLING_RUNECRAFT, ActivityIntensity.HIGH), + SMELTING_RUNITE_BARS_AT_BLAST_FURNACE("Smelting runite bars at Blast Furnace", Category.SKILLING_SMITHING, ActivityIntensity.HIGH), + FILLING_BULLSEYE_LANTERN_EMPTY("Filling bullseye lantern (empty)", Category.PROCESSING, ActivityIntensity.MODERATE), + KILLING_THE_THERMONUCLEAR_SMOKE_DEVIL("Killing the Thermonuclear smoke devil", Category.COMBAT_HIGH, ActivityIntensity.HIGH), + BUYING_MONKEY_NUTS("Buying monkey nuts", Category.COLLECTING, ActivityIntensity.LOW), + KILLING_ZALCANO("Killing Zalcano", Category.SKILLING, ActivityIntensity.HIGH), + KILLING_RUNE_DRAGONS("Killing rune dragons", Category.COMBAT_HIGH, ActivityIntensity.MODERATE), + KILLING_LIZARDMAN_SHAMANS_CANYON("Killing Lizardman Shamans (Canyon)", Category.COMBAT_HIGH, ActivityIntensity.MODERATE), + CRAFTING_DEATH_RUNES_THROUGH_THE_ABYSS("Crafting death runes through the Abyss", Category.SKILLING_RUNECRAFT, ActivityIntensity.MODERATE), + KILLING_ZULRAH("Killing Zulrah", Category.COMBAT_HIGH, ActivityIntensity.HIGH), + CRAFTING_DOUBLE_LAW_RUNES_THROUGH_THE_ABYSS("Crafting double law runes through the Abyss", Category.SKILLING_RUNECRAFT, ActivityIntensity.MODERATE), + KILLING_LAVA_DRAGONS("Killing lava dragons", Category.COMBAT_HIGH, ActivityIntensity.MODERATE), + KILLING_DAGANNOTH_KINGS_REX_ONLY("Killing Dagannoth Kings (Rex only)", Category.COMBAT_MID, ActivityIntensity.LOW), + OPENING_CRYSTAL_CHESTS("Opening crystal chests", Category.PROCESSING, ActivityIntensity.HIGH), + MAKING_REDWOOD_PYRE_LOGS("Making redwood pyre logs", Category.PROCESSING, ActivityIntensity.MODERATE), + MAKING_SACRED_OIL("Making sacred oil", Category.SKILLING_CRAFTING, ActivityIntensity.LOW), + MAKING_DIVINE_SUPER_COMBAT_POTIONS("Making divine super combat potions", Category.SKILLING_HERBLORE, ActivityIntensity.LOW), + KILLING_THE_ABYSSAL_SIRE("Killing the Abyssal Sire", Category.COMBAT_HIGH, ActivityIntensity.HIGH), + KILLING_THE_GIANT_MOLE_DHAROKS("Killing the Giant Mole (Dharoks)", Category.COMBAT_MID, ActivityIntensity.LOW), + BUYING_KEGS_OF_BEER("Buying kegs of beer", Category.COLLECTING, ActivityIntensity.MODERATE), + MAKING_AVANTOE_POTIONS("Making avantoe potions", Category.PROCESSING, ActivityIntensity.LOW), + PICKPOCKETING_HAM_MEMBERS("Pickpocketing H.A.M. members", Category.SKILLING_THIEVING, ActivityIntensity.HIGH), + HUNTING_BLACK_CHINCHOMPAS("Hunting black chinchompas", Category.SKILLING_HUNTER, ActivityIntensity.MODERATE), + MAKING_SNAPDRAGON_POTIONS("Making snapdragon potions", Category.PROCESSING, ActivityIntensity.LOW), + CASTING_TAN_LEATHER("Casting Tan Leather", Category.SKILLING_MAGIC, ActivityIntensity.MODERATE), + KILLING_THE_GROTESQUE_GUARDIANS("Killing the Grotesque Guardians", Category.COMBAT_HIGH, ActivityIntensity.HIGH), + HUNTING_IMPLINGS("Hunting implings", Category.SKILLING_HUNTER, ActivityIntensity.HIGH), + CRAFTING_BLOOD_RUNES_THROUGH_THE_ABYSS("Crafting blood runes through the Abyss", Category.SKILLING_RUNECRAFT, ActivityIntensity.HIGH), + MAKING_MAGIC_PYRE_LOGS("Making magic pyre logs", Category.PROCESSING, ActivityIntensity.MODERATE), + KILLING_BRUTAL_BLACK_DRAGONS("Killing brutal black dragons", Category.COMBAT_HIGH, ActivityIntensity.LOW), + MAKING_RANARR_POTIONS("Making ranarr potions", Category.PROCESSING, ActivityIntensity.LOW), + KILLING_HYDRAS("Killing hydras", Category.COMBAT_HIGH, ActivityIntensity.HIGH), + ENCHANTING_DRAGONSTONE_JEWELLERY("Enchanting dragonstone jewellery", Category.SKILLING_MAGIC, ActivityIntensity.MODERATE), + MAKING_SANFEW_SERUM4("Making sanfew serum(4)", Category.SKILLING_HERBLORE, ActivityIntensity.MODERATE), + MAKING_DWARF_WEED_POTIONS("Making dwarf weed potions", Category.PROCESSING, ActivityIntensity.LOW), + SMELTING_ADAMANTITE_BARS_AT_BLAST_FURNACE("Smelting adamantite bars at Blast Furnace", Category.SKILLING_SMITHING, ActivityIntensity.HIGH), + MAKING_KWUARM_POTIONS("Making kwuarm potions", Category.PROCESSING, ActivityIntensity.LOW), + MAKING_CADANTINE_POTIONS("Making cadantine potions", Category.PROCESSING, ActivityIntensity.LOW), + KILLING_GREEN_DRAGONS_MYTHS_GUILD("Killing green dragons (Myths Guild)", Category.COMBAT_MID, ActivityIntensity.MODERATE), + MAKING_RAW_WILD_PIES("Making raw wild pies", Category.PROCESSING, ActivityIntensity.HIGH), + KILLING_VYREWATCH_SENTINELS("Killing Vyrewatch Sentinels", Category.COMBAT_HIGH, ActivityIntensity.LOW), + KILLING_THE_KRAKEN("Killing the Kraken", Category.COMBAT_HIGH, ActivityIntensity.LOW), + KILLING_FIYR_SHADES("Killing fiyr shades", Category.COMBAT_HIGH, ActivityIntensity.HIGH), + MAKING_TOADFLAX_POTIONS("Making toadflax potions", Category.PROCESSING, ActivityIntensity.LOW), + KILLING_GREEN_DRAGONS("Killing green dragons", Category.COMBAT_MID, ActivityIntensity.MODERATE), + MAKING_LANTADYME_POTIONS("Making lantadyme potions", Category.PROCESSING, ActivityIntensity.LOW), + BARROWS("Barrows", Category.COMBAT_HIGH, ActivityIntensity.HIGH), + PICKPOCKETING_MASTER_FARMERS("Pickpocketing master farmers", Category.SKILLING_THIEVING, ActivityIntensity.MODERATE), + KILLING_LIZARDMAN_SHAMANS_SETTLEMENT_OR_TEMPLE("Killing Lizardman Shamans (Settlement or Temple)", Category.COMBAT_HIGH, ActivityIntensity.MODERATE), + COLLECTING_MORT_MYRE_FUNGI("Collecting mort myre fungi", Category.COLLECTING, ActivityIntensity.LOW), + HUNTING_MOONLIGHT_ANTELOPES("Hunting moonlight antelopes", Category.SKILLING_HUNTER, ActivityIntensity.MODERATE), + COMPLETING_ELITE_CLUES_URIUM_REMAINS("Completing elite clues (urium remains)", Category.SKILLING_FIREMAKING, ActivityIntensity.HIGH), + MAKING_WEAPON_POISON_PLUS_PLUS("Making weapon poison(++)", Category.COLLECTING, ActivityIntensity.HIGH), + KILLING_MITHRIL_DRAGONS("Killing mithril dragons", Category.COMBAT_HIGH, ActivityIntensity.MODERATE), + KILLING_URIUM_SHADES("Killing urium shades", Category.COMBAT_HIGH, ActivityIntensity.MODERATE), + MAKING_GUTHIX_RESTS("Making Guthix rests", Category.PROCESSING, ActivityIntensity.HIGH), + SMELTING_STEEL_BARS_AT_BLAST_FURNACE("Smelting steel bars at Blast Furnace", Category.SKILLING_SMITHING, ActivityIntensity.HIGH), + KILLING_SKELETAL_WYVERNS("Killing skeletal wyverns", Category.COMBAT_HIGH, ActivityIntensity.LOW), + CRAFTING_DRIFT_NETS("Crafting drift nets", Category.SKILLING_CRAFTING, ActivityIntensity.MODERATE), + SMITHING_RUNE_ITEMS("Smithing rune items", Category.SKILLING_SMITHING, ActivityIntensity.LOW), + MINING_RUNITE_ORE("Mining runite ore", Category.SKILLING_MINING, ActivityIntensity.LOW), + MAKING_IRIT_POTIONS("Making irit potions", Category.PROCESSING, ActivityIntensity.LOW), + LAST_MAN_STANDING("Last Man Standing", Category.COMBAT_LOW, ActivityIntensity.HIGH), + CREATING_TELEPORT_TABLETS_AT_LECTERN_LUNAR("Creating teleport tablets at Lectern (Lunar)", Category.SKILLING_MAGIC, ActivityIntensity.LOW), + MAKING_ULTRACOMPOST("Making ultracompost", Category.PROCESSING, ActivityIntensity.LOW), + KILLING_FEVER_SPIDERS_MAXIMUM_EFFICIENCY("Killing fever spiders (maximum efficiency)", Category.COMBAT_LOW, ActivityIntensity.HIGH), + FLETCHING_MOONLIGHT_ANTLER_BOLTS("Fletching moonlight antler bolts", Category.PROCESSING, ActivityIntensity.LOW), + KILLING_DISCIPLES_OF_IBAN("Killing disciples of Iban", Category.COMBAT_LOW, ActivityIntensity.MODERATE), + KILLING_GARGOYLES("Killing gargoyles", Category.COMBAT_HIGH, ActivityIntensity.HIGH), + FLETCHING_OGRE_ARROW_SHAFTS("Fletching ogre arrow shafts", Category.PROCESSING, ActivityIntensity.LOW), + KILLING_ENTS("Killing ents", Category.COMBAT_MID, ActivityIntensity.MODERATE), + GRINDING_DESERT_GOAT_HORNS("Grinding desert goat horns", Category.PROCESSING, ActivityIntensity.MODERATE), + GRINDING_UNICORN_HORNS("Grinding unicorn horns", Category.PROCESSING, ActivityIntensity.MODERATE), + CRAFTING_DRAGONSTONE_JEWELLERY("Crafting dragonstone jewellery", Category.SKILLING_CRAFTING, ActivityIntensity.LOW), + CRAFTING_BLOOD_RUNES_AT_ARCEUUS_MAX("Crafting blood runes at Arceuus (max)", Category.SKILLING_RUNECRAFT, ActivityIntensity.LOW), + HUNTING_SUNLIGHT_ANTELOPES("Hunting sunlight antelopes", Category.SKILLING_HUNTER, ActivityIntensity.MODERATE), + PICKPOCKETING_PALADINS("Pickpocketing paladins", Category.SKILLING_THIEVING, ActivityIntensity.MODERATE), + STEALING_CAVE_GOBLIN_WIRE("Stealing cave goblin wire", Category.COLLECTING, ActivityIntensity.HIGH), + CRAFTING_COSMIC_RUNES_THROUGH_THE_ABYSS("Crafting cosmic runes through the Abyss", Category.SKILLING_RUNECRAFT, ActivityIntensity.MODERATE), + MINING_BASALT("Mining basalt", Category.SKILLING_MINING, ActivityIntensity.LOW), + TANNING_RED_DRAGONHIDE("Tanning red dragonhide", Category.PROCESSING, ActivityIntensity.LOW), + CRAFTING_BLOOD_RUNES_AT_ARCEUUS_NO_DIARY("Crafting blood runes at Arceuus (no diary)", Category.SKILLING_RUNECRAFT, ActivityIntensity.LOW), + MAKING_PINEAPPLE_PIZZAS("Making pineapple pizzas", Category.SKILLING_COOKING, ActivityIntensity.HIGH), + MAKING_HARRALANDER_POTIONS("Making harralander potions", Category.PROCESSING, ActivityIntensity.LOW), + KILLING_BLUE_DRAGONS("Killing blue dragons", Category.COMBAT_MID, ActivityIntensity.MODERATE), + MINING_GEMSTONES("Mining gemstones", Category.SKILLING_MINING, ActivityIntensity.MODERATE), + CRAFTING_OPAL_BRACELETS("Crafting opal bracelets", Category.SKILLING_CRAFTING, ActivityIntensity.LOW), + ENCHANTING_TOPAZ_JEWELLERY("Enchanting topaz jewellery", Category.SKILLING_MAGIC, ActivityIntensity.MODERATE), + KILLING_SARACHNIS("Killing Sarachnis", Category.COMBAT_MID, ActivityIntensity.MODERATE), + BUYING_BEER_TANKARDS("Buying beer tankards", Category.PROCESSING, ActivityIntensity.MODERATE), + CRAFTING_XERICIAN_ROBES("Crafting Xerician robes", Category.SKILLING_CRAFTING, ActivityIntensity.LOW), + SMELTING_MITHRIL_BARS_AT_BLAST_FURNACE("Smelting mithril bars at Blast Furnace", Category.SKILLING_SMITHING, ActivityIntensity.HIGH), + CHARGING_AND_ALCHEMISING_BRACELETS_OF_ETHEREUM("Charging and alchemising bracelets of ethereum", Category.PROCESSING, ActivityIntensity.MODERATE), + CREATING_TELEPORT_TO_HOUSE_TABLETS("Creating teleport to house tablets", Category.PROCESSING, ActivityIntensity.LOW), + CREATING_BARROWS_TELEPORT_TABLETS("Creating Barrows teleport tablets", Category.SKILLING_MAGIC, ActivityIntensity.LOW), + KILLING_THE_KALPHITE_QUEEN("Killing the Kalphite Queen", Category.COMBAT_HIGH, ActivityIntensity.HIGH), + CRAFTING_LAW_RUNES_THROUGH_THE_ABYSS("Crafting law runes through the Abyss", Category.SKILLING_RUNECRAFT, ActivityIntensity.MODERATE), + CRAFTING_COSMIC_RUNES("Crafting cosmic runes", Category.SKILLING_RUNECRAFT, ActivityIntensity.HIGH), + FILLING_BUCKETS_WITH_WATER("Filling buckets with water", Category.SKILLING_MAGIC, ActivityIntensity.MODERATE), + ENCHANTING_JADE_AMULETS("Enchanting jade amulets", Category.SKILLING_MAGIC, ActivityIntensity.MODERATE), + HUNTING_HERBIBOARS("Hunting herbiboars", Category.SKILLING_HUNTER, ActivityIntensity.LOW), + TEMPLE_TREKKING("Temple Trekking", Category.COMBAT_LOW, ActivityIntensity.LOW), + FLETCHING_RUBY_BOLTS("Fletching ruby bolts", Category.SKILLING_FLETCHING, ActivityIntensity.LOW), + PLANTING_MITHRIL_SEEDS("Planting mithril seeds", Category.COLLECTING, ActivityIntensity.LOW), + MAKING_RAW_SUMMER_PIES("Making raw summer pies", Category.PROCESSING, ActivityIntensity.MODERATE), + CRUSHING_BIRD_NESTS("Crushing bird nests", Category.PROCESSING, ActivityIntensity.MODERATE), + FLETCHING_FLIGHTED_OGRE_ARROWS("Fletching flighted ogre arrows", Category.PROCESSING, ActivityIntensity.LOW), + HIGH_ALCHING_MYSTIC_EARTH_STAVES_AT_THE_FOUNTAIN_OF_RUNE("High alching mystic earth staves at the fountain of rune", Category.SKILLING_MAGIC, ActivityIntensity.LOW), + TANNING_BLACK_DRAGONHIDE("Tanning black dragonhide", Category.PROCESSING, ActivityIntensity.LOW), + HIGH_ALCHING_MYSTIC_WATER_STAVES_AT_THE_FOUNTAIN_OF_RUNE("High alching mystic water staves at the fountain of rune", Category.SKILLING_MAGIC, ActivityIntensity.LOW), + BLAST_MINING("Blast mining", Category.SKILLING_MINING, ActivityIntensity.MODERATE), + HIGH_ALCHING_MYSTIC_AIR_STAVES_AT_THE_FOUNTAIN_OF_RUNE("High alching mystic air staves at the fountain of rune", Category.SKILLING_MAGIC, ActivityIntensity.LOW), + CRAFTING_SOUL_RUNES("Crafting soul runes", Category.SKILLING_RUNECRAFT, ActivityIntensity.HIGH), + MAKING_TARROMIN_POTIONS("Making tarromin potions", Category.PROCESSING, ActivityIntensity.LOW), + KILLING_FEVER_SPIDERS_ALCHING("Killing fever spiders (alching", Category.COMBAT_LOW, ActivityIntensity.HIGH), + MAKING_ADAMANT_BRUTAL_ARROWS("Making adamant brutal arrows", Category.PROCESSING, ActivityIntensity.LOW), + CASTING_SUPERGLASS_MAKE("Casting Superglass Make", Category.SKILLING_MAGIC, ActivityIntensity.HIGH), + KILLING_FEVER_SPIDERS_NO_CANNON("Killing fever spiders (no cannon)", Category.COMBAT_LOW, ActivityIntensity.MODERATE), + MAKING_RAW_ADMIRAL_PIES("Making raw admiral pies", Category.PROCESSING, ActivityIntensity.HIGH), + CRAFTING_TOPAZ_BRACELETS("Crafting topaz bracelets", Category.SKILLING_CRAFTING, ActivityIntensity.LOW), + MINING_RUNITE_ORE_FREE_TO_PLAY("Mining runite ore (free-to-play)", Category.SKILLING_MINING, ActivityIntensity.MODERATE), + CREATING_VARROCK_TELEPORT_TABLETS("Creating Varrock teleport tablets", Category.PROCESSING, ActivityIntensity.LOW), + CLEANING_GRIMY_TORSTOL("Cleaning grimy torstol", Category.SKILLING_HERBLORE, ActivityIntensity.HIGH), + CHARGING_AIR_ORBS("Charging air orbs", Category.SKILLING_MAGIC, ActivityIntensity.MODERATE), + KILLING_BRUTAL_RED_DRAGONS("Killing brutal red dragons", Category.COMBAT_HIGH, ActivityIntensity.HIGH), + HUNTING_CARNIVOROUS_CHINCHOMPAS("Hunting carnivorous chinchompas", Category.SKILLING_HUNTER, ActivityIntensity.MODERATE), + CRAFTING_NATURE_RUNES_THROUGH_THE_ABYSS("Crafting nature runes through the Abyss", Category.SKILLING_RUNECRAFT, ActivityIntensity.HIGH), + HIGH_ALCHING_PROFITABLE_FREE_TO_PLAY_ITEMS("High alching profitable free-to-play items", Category.SKILLING_MAGIC, ActivityIntensity.LOW), + HUMIDIFYING_CLAY("Humidifying clay", Category.SKILLING_MAGIC, ActivityIntensity.MODERATE), + SEARCHING_A_HERBLORE_CAPE("Searching a herblore cape", Category.COLLECTING, ActivityIntensity.HIGH), + KILLING_SKOGRES_AND_ZOGRES("Killing skogres and zogres", Category.COMBAT_MID, ActivityIntensity.MODERATE), + CRAFTING_BLOOD_RUNES_AT_ARCEUUS_MINIMAL_REQUIREMENTS("Crafting blood runes at Arceuus (minimal requirements)", Category.SKILLING_RUNECRAFT, ActivityIntensity.LOW), + CATCHING_DARK_CRABS("Catching dark crabs", Category.SKILLING_FISHING, ActivityIntensity.LOW), + COOKING_RAW_SUNLIGHT_ANTELOPE("Cooking raw sunlight antelope", Category.SKILLING_COOKING, ActivityIntensity.LOW), + KILLING_ICE_TROLL_RUNTS("Killing ice troll runts", Category.COMBAT_MID, ActivityIntensity.MODERATE), + SMITHING_CANNONBALLS("Smithing cannonballs", Category.SKILLING_SMITHING, ActivityIntensity.LOW), + MINING_SALTS("Mining salts", Category.SKILLING_MINING, ActivityIntensity.LOW), + CUTTING_DIAMOND_BOLT_TIPS("Cutting diamond bolt tips", Category.PROCESSING, ActivityIntensity.LOW), + MAKING_MARRENTILL_POTIONS("Making marrentill potions", Category.PROCESSING, ActivityIntensity.LOW), + HIGH_ALCHING_COMBAT_BRACELETS_AT_THE_FOUNTAIN_OF_RUNE("High alching combat bracelets at the fountain of rune", Category.SKILLING_MAGIC, ActivityIntensity.LOW), + CRAFTING_LIMESTONE_BRICKS("Crafting limestone bricks", Category.PROCESSING, ActivityIntensity.HIGH), + TANNING_BLUE_DRAGONHIDE("Tanning blue dragonhide", Category.PROCESSING, ActivityIntensity.LOW), + MAKING_MAHOGANY_PLANKS("Making mahogany planks", Category.PROCESSING, ActivityIntensity.HIGH), + CRAFTING_RUBY_BRACELETS("Crafting ruby bracelets", Category.SKILLING_CRAFTING, ActivityIntensity.LOW), + MAKING_GUAM_POTIONS("Making guam potions", Category.PROCESSING, ActivityIntensity.LOW), + CRAFTING_DIAMOND_BRACELETS("Crafting diamond bracelets", Category.SKILLING_CRAFTING, ActivityIntensity.LOW), + CLEANING_GRIMY_KWUARM("Cleaning grimy kwuarm", Category.SKILLING_HERBLORE, ActivityIntensity.HIGH), + CREATING_CAMELOT_TELEPORT_TABLETS("Creating Camelot teleport tablets", Category.PROCESSING, ActivityIntensity.LOW), + EXCHANGING_IMPLING_JARS("Exchanging impling jars", Category.PROCESSING, ActivityIntensity.MODERATE), + HIGH_ALCHING_RUNITE_LIMBS_AT_THE_FOUNTAIN_OF_RUNE("High alching runite limbs at the fountain of rune", Category.SKILLING_MAGIC, ActivityIntensity.LOW), + COLLECTING_CLIMBING_BOOTS("Collecting climbing boots", Category.COLLECTING, ActivityIntensity.HIGH), + BLESSING_UNBLESSED_SYMBOLS("Blessing unblessed symbols", Category.PROCESSING, ActivityIntensity.LOW), + CHARGING_FIRE_ORBS("Charging fire orbs", Category.SKILLING_MAGIC, ActivityIntensity.LOW), + MINING_AMETHYST("Mining amethyst", Category.SKILLING_MINING, ActivityIntensity.LOW), + MINING_IRON_ORE("Mining iron ore", Category.SKILLING_MINING, ActivityIntensity.MODERATE), + MAKING_OAK_PLANKS("Making oak planks", Category.PROCESSING, ActivityIntensity.MODERATE), + TANNING_GREEN_DRAGONHIDE("Tanning green dragonhide", Category.PROCESSING, ActivityIntensity.LOW), + MOTHERLODE_MINE("Motherlode Mine", Category.SKILLING_MINING, ActivityIntensity.LOW), + MAKING_MAHOGANY_PLANKS_AT_THE_WOODCUTTING_GUILD("Making mahogany planks at the Woodcutting Guild", Category.PROCESSING, ActivityIntensity.MODERATE), + COLLECTING_SNAPE_GRASS("Collecting snape grass", Category.COLLECTING, ActivityIntensity.LOW), + CUTTING_AMETHYST_ARROWTIPS("Cutting amethyst arrowtips", Category.PROCESSING, ActivityIntensity.LOW), + KILLING_THE_KING_BLACK_DRAGON("Killing the King Black Dragon", Category.COMBAT_HIGH, ActivityIntensity.HIGH), + RECHARGING_RINGS_OF_WEALTH("Recharging rings of wealth", Category.PROCESSING, ActivityIntensity.MODERATE), + COLLECTING_MONKS_ROBES("Collecting monks robes", Category.COLLECTING, ActivityIntensity.LOW), + LOOTING_OGRE_COFFINS("Looting ogre coffins", Category.COLLECTING, ActivityIntensity.MODERATE), + CASTING_SPIN_FLAX("Casting Spin Flax", Category.SKILLING_MAGIC, ActivityIntensity.MODERATE), + KILLING_JUBSTERS("Killing Jubsters", Category.COMBAT_LOW, ActivityIntensity.LOW), + FLETCHING_HEADLESS_ARROWS("Fletching headless arrows", Category.PROCESSING, ActivityIntensity.LOW), + CASTING_PLANK_MAKE("Casting plank make", Category.SKILLING_MAGIC, ActivityIntensity.LOW), + MAKING_DYNAMITE("Making dynamite", Category.SKILLING_MINING, ActivityIntensity.MODERATE), + CRAFTING_SAPPHIRE_BRACELETS("Crafting sapphire bracelets", Category.SKILLING_CRAFTING, ActivityIntensity.LOW), + BUYING_IRON_ORE("Buying iron ore", Category.COLLECTING, ActivityIntensity.MODERATE), + SMITHING_BRONZE_DART_TIPS("Smithing bronze dart tips", Category.SKILLING_SMITHING, ActivityIntensity.LOW), + CLEANING_GRIMY_CADANTINE("Cleaning grimy cadantine", Category.SKILLING_HERBLORE, ActivityIntensity.HIGH), + CRAFTING_JADE_BRACELETS("Crafting jade bracelets", Category.SKILLING_CRAFTING, ActivityIntensity.LOW), + DEGRIMING_GRIMY_GUAM_LEAF("Degriming grimy guam leaf", Category.SKILLING_HERBLORE, ActivityIntensity.HIGH), + CHARGING_WATER_ORBS("Charging water orbs", Category.SKILLING_MAGIC, ActivityIntensity.LOW), + CATCHING_RAW_KARAMBWAN("Catching raw karambwan", Category.SKILLING_FISHING, ActivityIntensity.LOW), + BUYING_TEAM_CAPES("Buying team capes", Category.COLLECTING, ActivityIntensity.LOW), + MAKING_DYES("Making dyes", Category.PROCESSING, ActivityIntensity.HIGH), + CHARGING_EARTH_ORBS("Charging earth orbs", Category.SKILLING_MAGIC, ActivityIntensity.MODERATE), + CRAFTING_RUBY_JEWELLERY("Crafting ruby jewellery", Category.SKILLING_CRAFTING, ActivityIntensity.LOW), + CRAFTING_CLOCKWORK_TELEPORT_METHOD("Crafting clockwork (teleport method)", Category.SKILLING_CRAFTING, ActivityIntensity.HIGH), + MAKING_PIE_SHELLS("Making pie shells", Category.PROCESSING, ActivityIntensity.LOW), + KILLING_SPIDINES("Killing spidines", Category.COMBAT_LOW, ActivityIntensity.LOW), + CATCHING_ANGLERFISH("Catching anglerfish", Category.SKILLING_FISHING, ActivityIntensity.MODERATE), + HUNTING_CHINCHOMPAS("Hunting chinchompas", Category.SKILLING_HUNTER, ActivityIntensity.MODERATE), + FLETCHING_DIAMOND_BOLTS("Fletching diamond bolts", Category.SKILLING_FLETCHING, ActivityIntensity.LOW), + CRAFTING_MUD_RUNES("Crafting mud runes", Category.SKILLING_RUNECRAFT, ActivityIntensity.MODERATE), + CRAFTING_EMERALD_BRACELETS("Crafting emerald bracelets", Category.SKILLING_CRAFTING, ActivityIntensity.LOW), + COLLECTING_STEEL_PLATEBODIES_HIGH_ALCHEMY("Collecting steel platebodies (High Alchemy)", Category.SKILLING_MAGIC, ActivityIntensity.MODERATE), + CRAFTING_DIAMOND_JEWELLERY("Crafting diamond jewellery", Category.SKILLING_CRAFTING, ActivityIntensity.LOW), + MAKING_TEAK_PLANKS("Making teak planks", Category.PROCESSING, ActivityIntensity.MODERATE), + COOKING_RAW_SHARKS("Cooking raw sharks", Category.SKILLING_COOKING, ActivityIntensity.LOW), + CUTTING_RUBY_BOLT_TIPS("Cutting ruby bolt tips", Category.PROCESSING, ActivityIntensity.LOW), + CRAFTING_RUNES_AT_OURANIA_ALTAR("Crafting runes at Ourania Altar", Category.SKILLING_RUNECRAFT, ActivityIntensity.MODERATE), + COLLECTING_BLACK_SCIMITARS_FROM_ARDOUGNE_CASTLE("Collecting black scimitars from Ardougne Castle", Category.COLLECTING, ActivityIntensity.LOW), + MAKING_UNCOOKED_BERRY_PIES("Making uncooked berry pies", Category.PROCESSING, ActivityIntensity.LOW), + PICKING_BANANAS("Picking bananas", Category.COLLECTING, ActivityIntensity.MODERATE), + ENCHANTING_DIAMOND_NECKLACES("Enchanting diamond necklaces", Category.SKILLING_MAGIC, ActivityIntensity.MODERATE), + KILLING_THE_CRAZY_ARCHAEOLOGIST("Killing the Crazy archaeologist", Category.COMBAT_HIGH, ActivityIntensity.HIGH), + KILLING_FERAL_VAMPYRES("Killing Feral Vampyres", Category.COMBAT_MID, ActivityIntensity.LOW), + COLLECTING_ANTI_DRAGON_SHIELDS_FREE_TO_PLAY("Collecting anti-dragon shields (free-to-play)", Category.COLLECTING, ActivityIntensity.MODERATE), + STRINGING_MAPLE_LONGBOWS("Stringing maple longbows", Category.SKILLING_FLETCHING, ActivityIntensity.MODERATE), + SMITHING_IRON_DART_TIPS("Smithing iron dart tips", Category.SKILLING_SMITHING, ActivityIntensity.LOW), + HIGH_ALCHING_UNFINISHED_RUNITE_CROSSBOWS_AT_THE_FOUNTAIN_OF_RUNE("High alching unfinished runite crossbows at the fountain of rune", Category.SKILLING_MAGIC, ActivityIntensity.LOW), + KILLING_RED_DRAGONS("Killing red dragons", Category.COMBAT_MID, ActivityIntensity.MODERATE), + COLLECTING_JANGERBERRIES("Collecting jangerberries", Category.COLLECTING, ActivityIntensity.LOW), + GRINDING_CHOCOLATE_BARS("Grinding chocolate bars", Category.PROCESSING, ActivityIntensity.MODERATE), + CRAFTING_EMERALD_JEWELLERY("Crafting emerald jewellery", Category.SKILLING_CRAFTING, ActivityIntensity.LOW), + MAKING_GLOVES_OF_SILENCE("Making gloves of silence", Category.PROCESSING_MAGIC, ActivityIntensity.MODERATE), + CATCHING_MINNOWS("Catching minnows", Category.SKILLING_FISHING, ActivityIntensity.MODERATE), + KILLING_BLACK_DRAGONS("Killing black dragons", Category.COMBAT_HIGH, ActivityIntensity.HIGH), + STRINGING_MAGIC_LONGBOWS("Stringing magic longbows", Category.SKILLING_FLETCHING, ActivityIntensity.MODERATE), + HIGH_ALCHING_ATLATL_DARTS_AT_THE_FOUNTAIN_OF_RUNE("High alching atlatl darts at the fountain of rune", Category.SKILLING_MAGIC, ActivityIntensity.LOW), + MAKING_UNCOOKED_APPLE_PIES("Making uncooked apple pies", Category.PROCESSING, ActivityIntensity.LOW), + KILLING_AVIANSIES("Killing aviansies", Category.COMBAT_MID, ActivityIntensity.MODERATE), + KILLING_CAVE_HORRORS("Killing cave horrors", Category.COMBAT_MID, ActivityIntensity.MODERATE), + COOKING_PLAIN_PIZZAS("Cooking plain pizzas", Category.SKILLING_COOKING, ActivityIntensity.LOW), + CLEANING_GRIMY_SNAPDRAGON("Cleaning grimy snapdragon", Category.SKILLING_HERBLORE, ActivityIntensity.HIGH), + HIGH_ALCHING_RUNE_ARROWS_AT_THE_FOUNTAIN_OF_RUNE("High alching rune arrows at the fountain of rune", Category.SKILLING_MAGIC, ActivityIntensity.LOW), + KILLING_SPIRITUAL_MAGES("Killing spiritual mages", Category.COMBAT_HIGH, ActivityIntensity.MODERATE), + CLEANING_GRIMY_TOADFLAX("Cleaning grimy toadflax", Category.SKILLING_HERBLORE, ActivityIntensity.HIGH), + COLLECTING_PLANKS("Collecting planks", Category.COLLECTING, ActivityIntensity.LOW), + COLLECTING_RED_SPIDERS_EGGS("Collecting red spiders eggs", Category.COLLECTING, ActivityIntensity.LOW), + ENCHANTING_SAPPHIRE_RINGS("Enchanting sapphire rings", Category.SKILLING_MAGIC, ActivityIntensity.MODERATE), + CATCHING_SACRED_EELS("Catching sacred eels", Category.SKILLING_FISHING, ActivityIntensity.LOW), + CLIMBING_THE_AGILITY_PYRAMID("Climbing the Agility Pyramid", Category.SKILLING_AGILITY, ActivityIntensity.HIGH), + CRAFTING_STEAM_RUNES("Crafting steam runes", Category.SKILLING_RUNECRAFT, ActivityIntensity.MODERATE), + MAKING_ANCHOVY_PIZZAS("Making anchovy pizzas", Category.SKILLING_COOKING, ActivityIntensity.MODERATE), + CRAFTING_GOLD_BRACELETS("Crafting gold bracelets", Category.SKILLING_CRAFTING, ActivityIntensity.LOW), + KILLING_BRUTAL_GREEN_DRAGONS("Killing brutal green dragons", Category.COMBAT_HIGH, ActivityIntensity.HIGH), + STRINGING_YEW_LONGBOWS("Stringing yew longbows", Category.SKILLING_FLETCHING, ActivityIntensity.MODERATE), + KILLING_BRYOPHYTA_FREE_TO_PLAY("Killing Bryophyta (free-to-play)", Category.COMBAT_MID, ActivityIntensity.MODERATE), + COLLECTING_WHITE_BERRIES("Collecting white berries", Category.COLLECTING, ActivityIntensity.LOW), + COLLECTING_ANTI_DRAGON_SHIELDS("Collecting anti-dragon shields", Category.COLLECTING, ActivityIntensity.HIGH), + CUTTING_MAHOGANY_LOGS("Cutting mahogany logs", Category.SKILLING_WOODCUTTING, ActivityIntensity.LOW), + KILLING_CHAOS_DRUIDS("Killing chaos druids", Category.COMBAT_LOW, ActivityIntensity.LOW), + COLLECTING_FISH_FOOD("Collecting fish food", Category.COLLECTING, ActivityIntensity.MODERATE), + CATCHING_INFERNAL_EELS("Catching infernal eels", Category.SKILLING_FISHING, ActivityIntensity.LOW), + MINING_VOLCANIC_ASH("Mining volcanic ash", Category.SKILLING_MINING, ActivityIntensity.LOW), + CUTTING_YEW_LOGS_FREE_TO_PLAY("Cutting yew logs (free-to-play)", Category.SKILLING_WOODCUTTING, ActivityIntensity.LOW), + FORGING_GIANT_SWORDS("Forging Giant swords", Category.SKILLING_SMITHING, ActivityIntensity.MODERATE), + COOKING_RAW_MONKFISH("Cooking raw monkfish", Category.SKILLING_COOKING, ActivityIntensity.LOW), + MINING_ADAMANTITE_ORE("Mining adamantite ore", Category.SKILLING_MINING, ActivityIntensity.LOW), + SPINNING_FLAX_TO_BOW_STRINGS("Spinning flax to bow strings", Category.PROCESSING, ActivityIntensity.LOW), + BUYING_PIES("Buying pies", Category.COLLECTING, ActivityIntensity.MODERATE), + TANNING_COWHIDE("Tanning cowhide", Category.PROCESSING, ActivityIntensity.LOW), + KILLING_BRINE_RATS("Killing brine rats", Category.COMBAT_MID, ActivityIntensity.MODERATE), + CRAFTING_SAPPHIRE_JEWELLERY("Crafting sapphire jewellery", Category.SKILLING_CRAFTING, ActivityIntensity.LOW), + COLLECTING_BRONZE_PICKAXES("Collecting bronze pickaxes", Category.COLLECTING, ActivityIntensity.HIGH), + KILLING_OGRESS_SHAMANS("Killing ogress shamans", Category.COMBAT_HIGH, ActivityIntensity.MODERATE), + SMITHING_MITHRIL_DART_TIPS("Smithing mithril dart tips", Category.SKILLING_SMITHING, ActivityIntensity.LOW), + COLLECTING_WINE_OF_ZAMORAK("Collecting wine of zamorak", Category.COLLECTING, ActivityIntensity.MODERATE), + MAKING_UNCOOKED_MEAT_PIES("Making uncooked meat pies", Category.PROCESSING, ActivityIntensity.LOW), + CLEANING_GRIMY_IRIT_LEAVES("Cleaning grimy irit leaves", Category.SKILLING_HERBLORE, ActivityIntensity.HIGH), + CLEANING_GRIMY_HARRALANDER("Cleaning grimy harralander", Category.SKILLING_HERBLORE, ActivityIntensity.HIGH), + CREATING_BONES_TO_PEACHES_TABLETS("Creating bones to peaches tablets", Category.PROCESSING, ActivityIntensity.LOW), + COLLECTING_CHAOS_RUNES("Collecting chaos runes", Category.COLLECTING, ActivityIntensity.MODERATE), + CUTTING_MAGIC_LOGS("Cutting magic logs", Category.SKILLING_WOODCUTTING, ActivityIntensity.LOW), + FILLING_WATER_CONTAINERS_HOSIDIUS_KITCHEN("Filling water containers (Hosidius kitchen)", Category.PROCESSING, ActivityIntensity.LOW), + COLLECTING_NATURE_RUNES("Collecting nature runes", Category.SKILLING_MAGIC, ActivityIntensity.MODERATE), + COLLECTING_RED_SPIDERS_EGGS_FREE_TO_PLAY("Collecting red spiders eggs (free-to-play)", Category.COLLECTING, ActivityIntensity.MODERATE), + MAKING_TUNA_POTATOES("Making tuna potatoes", Category.PROCESSING, ActivityIntensity.MODERATE), + CLEANING_GRIMY_TARROMIN("Cleaning grimy tarromin", Category.SKILLING_HERBLORE, ActivityIntensity.HIGH), + COLLECTING_TINDERBOXES("Collecting tinderboxes", Category.COLLECTING, ActivityIntensity.HIGH), + MAKING_PASTRY_DOUGH("Making pastry dough", Category.PROCESSING, ActivityIntensity.MODERATE), + MINING_ADAMANTITE_ORE_FREE_TO_PLAY("Mining adamantite ore (free-to-play)", Category.SKILLING_MINING, ActivityIntensity.LOW), + CLEANING_GRIMY_GUAM_LEAVES("Cleaning grimy guam leaves", Category.SKILLING_HERBLORE, ActivityIntensity.HIGH), + RUNNING_LAPS_OF_THE_CANIFIS_ROOFTOP_COURSE("Running laps of the Canifis rooftop course", Category.SKILLING_AGILITY, ActivityIntensity.LOW), + BAKING_POTATOES("Baking potatoes", Category.SKILLING_COOKING, ActivityIntensity.LOW), + MAKING_PIZZA_BASES("Making pizza bases", Category.PROCESSING, ActivityIntensity.HIGH), + COOKING_RAW_KARAMBWAN("Cooking raw karambwan", Category.SKILLING_COOKING, ActivityIntensity.LOW), + CREATING_ARDOUGNE_TELEPORT_TABLETS("Creating Ardougne teleport tablets", Category.PROCESSING, ActivityIntensity.LOW), + COLLECTING_COSMIC_RUNES("Collecting cosmic runes", Category.COLLECTING, ActivityIntensity.MODERATE), + BUYING_BRONZE_BARS("Buying bronze bars", Category.COLLECTING, ActivityIntensity.LOW), + FLETCHING_UNSTRUNG_MAPLE_LONGBOWS("Fletching unstrung maple longbows", Category.SKILLING_FLETCHING, ActivityIntensity.LOW), + COOKING_RAW_SWORDFISH("Cooking raw swordfish", Category.SKILLING_COOKING, ActivityIntensity.LOW), + SMELTING_RUNITE_BARS("Smelting runite bars", Category.SKILLING_SMITHING, ActivityIntensity.LOW), + COLLECTING_IRON_ORE("Collecting iron ore", Category.COLLECTING, ActivityIntensity.LOW), + CUTTING_REDWOOD_LOGS("Cutting redwood logs", Category.SKILLING_WOODCUTTING, ActivityIntensity.LOW), + COOKING_RAW_ANGLERFISH("Cooking raw anglerfish", Category.SKILLING_COOKING, ActivityIntensity.LOW), + MINING_IRON_ORE_FREE_TO_PLAY("Mining iron ore (free-to-play)", Category.SKILLING_MINING, ActivityIntensity.HIGH), + MINING_CLAY_MEMBERS("Mining clay members", Category.SKILLING_MINING, ActivityIntensity.MODERATE), + KILLING_IMPS("Killing imps", Category.COMBAT_LOW, ActivityIntensity.LOW), + COLLECTING_BIG_BONES_FROM_THE_BONE_YARD("Collecting big bones from the Bone Yard", Category.COLLECTING, ActivityIntensity.MODERATE), + KILLING_MONKEYS("Killing monkeys", Category.COMBAT_LOW, ActivityIntensity.LOW), + CATCHING_SHRIMP_AND_ANCHOVIES("Catching shrimp & anchovies", Category.SKILLING_FISHING, ActivityIntensity.LOW), + COLLECTING_ASHES("Collecting ashes", Category.COLLECTING, ActivityIntensity.LOW), + KILLING_OGRESS_WARRIORS("Killing ogress warriors", Category.COMBAT_MID, ActivityIntensity.LOW), + COLLECTING_AND_TANNING_COWHIDE("Collecting and tanning cowhide", Category.COLLECTING, ActivityIntensity.LOW), + BUYING_ALE_FROM_THE_RISING_SUN_INN("Buying ale from the Rising Sun Inn", Category.COLLECTING, ActivityIntensity.HIGH), + KILLING_HILL_GIANTS("Killing hill giants", Category.COMBAT_LOW, ActivityIntensity.MODERATE), + COLLECTING_STEEL_PLATEBODIES("Collecting steel platebodies", Category.COLLECTING, ActivityIntensity.MODERATE), + COOKING_RAW_LOBSTER("Cooking raw lobster", Category.SKILLING_COOKING, ActivityIntensity.LOW), + KILLING_COWS_AND_TANNING_COWHIDE("Killing cows and tanning cowhide", Category.COMBAT_LOW, ActivityIntensity.LOW), + BUYING_JUG_PACKS("Buying jug packs", Category.COLLECTING, ActivityIntensity.LOW), + KILLING_CHAOS_DWARVES("Killing chaos dwarves", Category.COMBAT_MID, ActivityIntensity.LOW), + FILLING_WATER_CONTAINERS("Filling water containers", Category.PROCESSING, ActivityIntensity.LOW), + COLLECTING_WINE_OF_ZAMORAK_FREE_TO_PLAY("Collecting wine of zamorak (free-to-play)", Category.COLLECTING, ActivityIntensity.LOW), + MAKING_DOUGH_AT_COOKS_GUILD("Making dough at Cooks Guild", Category.PROCESSING, ActivityIntensity.HIGH), + SMELTING_BRONZE_BARS("Smelting bronze bars", Category.SKILLING_SMITHING, ActivityIntensity.LOW), + MINING_CLAY("Mining clay", Category.SKILLING_MINING, ActivityIntensity.LOW), + CRAFTING_GOLD_JEWELLERY("Crafting gold jewellery", Category.SKILLING_CRAFTING, ActivityIntensity.LOW), + BUYING_KEBABS_IN_AL_KHARID("Buying kebabs in Al Kharid", Category.COLLECTING, ActivityIntensity.HIGH), + STEALING_WYDINS_BANANAS("Stealing Wydins bananas", Category.COLLECTING, ActivityIntensity.HIGH), + COLLECTING_GARLIC("Collecting garlic", Category.COLLECTING, ActivityIntensity.MODERATE), + COOKING_RAW_TUNA("Cooking raw tuna", Category.SKILLING_COOKING, ActivityIntensity.LOW), + COLLECTING_SPADES("Collecting spades", Category.COLLECTING, ActivityIntensity.MODERATE), + CUTTING_WILLOW_LOGS("Cutting willow logs", Category.SKILLING_WOODCUTTING, ActivityIntensity.LOW), + CUTTING_OAK_LOGS("Cutting oak logs", Category.SKILLING_WOODCUTTING, ActivityIntensity.LOW), + CATCHING_TROUT_AND_SALMON("Catching trout & salmon", Category.SKILLING_FISHING, ActivityIntensity.LOW), + KILLING_ZAMORAK_MONKS("Killing Zamorak monks", Category.COMBAT_LOW, ActivityIntensity.MODERATE), + MINING_COAL_AND_SUPERHEATING_ADAMANTITE_BARS("Mining coal and superheating Adamantite bars", Category.SKILLING_MINING, ActivityIntensity.MODERATE), + SMELTING_SILVER_BARS("Smelting silver bars", Category.SKILLING_SMITHING, ActivityIntensity.LOW), + KILLING_CHICKENS("Killing chickens", Category.COMBAT_LOW, ActivityIntensity.LOW), + SHEARING_SHEEP("Shearing sheep", Category.COLLECTING, ActivityIntensity.LOW), + PICKING_POTATOES("Picking potatoes", Category.COLLECTING, ActivityIntensity.LOW), + KILLING_HOBGOBLINS("Killing hobgoblins", Category.COMBAT_MID, ActivityIntensity.MODERATE), + MINING_GOLD_ORE_CRAFTING_GUILD("Mining gold ore (Crafting Guild)", Category.SKILLING_MINING, ActivityIntensity.LOW), + KILLING_WIZARDS("Killing wizards", Category.COMBAT_LOW, ActivityIntensity.LOW), + KILLING_BEARS("Killing bears", Category.COMBAT_MID, ActivityIntensity.MODERATE), + MINING_COAL_AND_SUPERHEATING_MITHRIL_BARS("Mining coal and superheating Mithril bars", Category.SKILLING_MINING, ActivityIntensity.MODERATE), + MINING_COAL_FREE_TO_PLAY("Mining coal (free-to-play)", Category.SKILLING_MINING, ActivityIntensity.MODERATE), + SMELTING_IRON_BARS("Smelting iron bars", Category.SKILLING_SMITHING, ActivityIntensity.LOW), + SMELTING_STEEL_BARS("Smelting steel bars", Category.SKILLING_SMITHING, ActivityIntensity.LOW), + KILLING_ANKOU_FREE_TO_PLAY("Killing Ankou (free-to-play)", Category.COMBAT_MID, ActivityIntensity.MODERATE), + BUYING_FROM_WYDINS_FOOD_STORE("Buying from Wydins Food Store", Category.COLLECTING, ActivityIntensity.HIGH), + COLLECTING_BEER_GLASSES("Collecting beer glasses", Category.COLLECTING, ActivityIntensity.LOW), + MAKING_FLOUR("Making flour", Category.PROCESSING, ActivityIntensity.LOW), + COLLECTING_AIR_TALISMANS("Collecting air talismans", Category.COLLECTING, ActivityIntensity.MODERATE), + KILLING_DARK_WIZARDS("Killing dark wizards", Category.COMBAT_LOW, ActivityIntensity.LOW), + MINING_GOLD_ORE_FREE_TO_PLAY("Mining gold ore (free-to-play)", Category.SKILLING_MINING, ActivityIntensity.LOW), + GETTING_INFINITE_MONEY("Getting infinite money", Category.COLLECTING_NONE, ActivityIntensity.HIGH); + + @Getter + private final String method; + @Getter + private final Category category; + private final ActivityIntensity intensity; + + Activity(String method, Category category, ActivityIntensity intensity) { + this.method = method; + this.category = category; + this.intensity = intensity; + } + + public static Activity fromSkill(Skill skill) { + switch (skill) { + case ATTACK: + case DEFENCE: + case STRENGTH: + case RANGED: + case MAGIC: + return GENERAL_COMBAT; + case PRAYER: + return GENERAL_PRAYER; + case CONSTRUCTION: + return GENERAL_CONSTRUCTION; + case COOKING: + return GENERAL_COOKING; + case WOODCUTTING: + return GENERAL_WOODCUTTING; + case FLETCHING: + return GENERAL_FLETCHING; + case FISHING: + return GENERAL_FISHING; + case FIREMAKING: + return GENERAL_FIREMAKING; + case CRAFTING: + return GENERAL_CRAFTING; + case SMITHING: + return GENERAL_SMITHING; + case MINING: + return GENERAL_MINING; + case HERBLORE: + return GENERAL_HERBLORE; + case AGILITY: + return GENERAL_AGILITY; + case THIEVING: + return GENERAL_THIEVING; + case SLAYER: + return GENERAL_SLAYER; + case RUNECRAFT: + return GENERAL_RUNECRAFT; + case HUNTER: + return GENERAL_HUNTER; + case FARMING: + return GENERAL_FARMING; + default: + return null; + } + } + + public ActivityIntensity getActivityIntensity() { + return intensity; + } +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/util/antiban/enums/ActivityIntensity.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/util/antiban/enums/ActivityIntensity.java new file mode 100644 index 0000000000..1edefbbd6a --- /dev/null +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/util/antiban/enums/ActivityIntensity.java @@ -0,0 +1,115 @@ +package net.runelite.client.plugins.microbot.util.antiban.enums; + +import lombok.Getter; +import net.runelite.api.Skill; + +/** + * The ActivityIntensity enum represents different levels of intensity for player activities, + * each associated with a specific play style and behavior pattern. + * + *

+ * 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. + *

+ * + *

Main Features:

+ *
    + *
  • Intensity Levels: Ranges from "Very Low" to "Extreme," with varying levels of action frequency and amplitude.
  • + *
  • Play Style Association: Each intensity is linked to a PlayStyle, which defines the overall behavior + * of the bot during specific activities.
  • + *
  • Skill Mapping: Different skills are mapped to specific intensity levels, with combat-related skills generally + * assigned higher intensities, while skilling activities are mapped to lower intensities.
  • + *
  • Randomization: Provides a method to generate a random activity intensity, adding unpredictability to bot behavior.
  • + *
+ * + *

Usage:

+ *

+ * 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. + *

+ * + *

Example:

+ *
+ * ActivityIntensity currentIntensity = ActivityIntensity.HIGH;
+ * PlayStyle associatedStyle = currentIntensity.getPlayStyle();
+ * double actionFrequency = currentIntensity.getFrequency();
+ * 
+ * + *

Skill-Based Intensity:

+ *

+ * 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. + *

+ * + *

Random Intensity:

+ *

+ * 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. + *

+ */ + +public enum ActivityIntensity { + VERY_LOW("Very Low", 0.6, 1.8, PlayStyle.PASSIVE), + LOW("Low", 0.4, 1.5, PlayStyle.CAUTIOUS), + MODERATE("Moderate", 0.3, 1.2, PlayStyle.AGGRESSIVE), + HIGH("High", 0.2, 1.1, PlayStyle.EXTREME_AGGRESSIVE), + EXTREME("Extreme", 0.1, 1.0, PlayStyle.EXTREME_AGGRESSIVE); + + @Getter + private final String name; + @Getter + private final double frequency; + @Getter + private final double amplitude; + @Getter + private final PlayStyle playStyle; + + + ActivityIntensity(String name, double frequency, double amplitude, PlayStyle playStyle) { + this.name = name; + this.frequency = frequency; + this.amplitude = amplitude; + this.playStyle = playStyle; + } + + public static ActivityIntensity random() { + return values()[(int) (Math.random() * values().length - 1)]; + } + + public static ActivityIntensity fromSkill(Skill skill) { + switch (skill) { + case ATTACK: + case DEFENCE: + case STRENGTH: + case RANGED: + case PRAYER: + case MAGIC: + case CONSTRUCTION: + return HIGH; + case COOKING: + case WOODCUTTING: + case FLETCHING: + case FISHING: + case FIREMAKING: + case CRAFTING: + case SMITHING: + case MINING: + case HERBLORE: + return LOW; + case AGILITY: + case THIEVING: + case SLAYER: + case RUNECRAFT: + case HUNTER: + case FARMING: + return MODERATE; + default: + return null; + } + } +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/util/antiban/enums/Category.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/util/antiban/enums/Category.java new file mode 100644 index 0000000000..0f0ee5b456 --- /dev/null +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/util/antiban/enums/Category.java @@ -0,0 +1,302 @@ +package net.runelite.client.plugins.microbot.util.antiban.enums; + +import net.runelite.api.AnimationID; +import net.runelite.client.plugins.microbot.Microbot; +import net.runelite.client.plugins.microbot.util.antiban.AntibanPlugin; +import net.runelite.client.plugins.microbot.util.antiban.Rs2Antiban; +import net.runelite.client.plugins.microbot.util.combat.Rs2Combat; +import net.runelite.client.plugins.microbot.util.inventory.Rs2Inventory; +import net.runelite.client.plugins.microbot.util.player.Rs2Player; + +/** + * The Category enum represents different categories of player activities, such as combat, skilling, and processing. + * + *

+ * 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. + *

+ * + *

Main Features:

+ *
    + *
  • Categories for Various Activities: Includes categories such as combat, skilling (e.g., fishing, cooking, magic), + * processing, and collecting, each with its own logic to determine if the player is busy.
  • + *
  • Custom Busy Logic: Each category overrides the isBusy() method, providing custom logic + * for determining if the player is engaged in the respective activity.
  • + *
  • Bot Activity Control: The bot uses these categories to manage when it should take action or pause, based + * on whether the player is currently busy performing an activity.
  • + *
+ * + *

Usage:

+ *

+ * 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. + *

+ * + *

Example:

+ *
+ * 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.
+ * }
+ * 
+ * + *

Customization:

+ *

+ * 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. + *

+ * + *

Development Notes:

+ *

+ * 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: + *

    + *
  • Whether the player is interacting with specific game objects.
  • + *
  • Other animations that might indicate a busy state.
  • + *
  • Game-specific conditions that represent the player being busy.
  • + *
+ * + * @return {@code true} if the player is animating or the inventory is full; {@code false} otherwise. + */ + @Override + public boolean isBusy() { + return !Rs2Antiban.isIdle(); + } + }, + SKILLING_HUNTER("Skilling/Hunter") { + /** + * 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: + *

    + *
  • Whether the player is interacting with specific game objects.
  • + *
  • Other animations that might indicate a busy state.
  • + *
  • Game-specific conditions that represent the player being busy.
  • + *
+ * + * @return {@code true} if the player is animating or the inventory is full; {@code false} otherwise. + */ + @Override + public boolean isBusy() { + return !Rs2Antiban.isIdle(); + } + }, + SKILLING_FARMING("Skilling/Farming") { + /** + * 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: + *

    + *
  • Whether the player is interacting with specific game objects.
  • + *
  • Other animations that might indicate a busy state.
  • + *
  • Game-specific conditions that represent the player being busy.
  • + *
+ * + * @return {@code true} if the player is animating or the inventory is full; {@code false} otherwise. + */ + @Override + public boolean isBusy() { + return Rs2Player.isAnimating() || Rs2Inventory.isFull(); + } + }, + SKILLING_PRAYER("Skilling/Prayer") { + /** + * 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: + *

    + *
  • Whether the player is interacting with specific game objects.
  • + *
  • Other animations that might indicate a busy state.
  • + *
  • Game-specific conditions that represent the player being busy.
  • + *
+ * + * @return {@code true} if the player is animating or the inventory is full; {@code false} otherwise. + */ + @Override + public boolean isBusy() { + return Rs2Player.isAnimating() || Rs2Inventory.isFull(); + } + }, + SKILLING_CONSTRUCTION("Skilling/Construction") { + /** + * 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: + *

    + *
  • Whether the player is interacting with specific game objects.
  • + *
  • Other animations that might indicate a busy state.
  • + *
  • Game-specific conditions that represent the player being busy.
  • + *
+ * + * @return {@code true} if the player is animating or the inventory is full; {@code false} otherwise. + */ + @Override + public boolean isBusy() { + return Rs2Player.isAnimating() || Rs2Inventory.isFull(); + } + }; + + private final String name; + + Category(String name) { + this.name = name; + } + + public String getName() { + return name; + } + + public abstract boolean isBusy(); +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/util/antiban/enums/PlaySchedule.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/util/antiban/enums/PlaySchedule.java new file mode 100644 index 0000000000..5c0a2f3e6b --- /dev/null +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/util/antiban/enums/PlaySchedule.java @@ -0,0 +1,81 @@ +package net.runelite.client.plugins.microbot.util.antiban.enums; + +import java.time.Duration; +import java.time.LocalTime; + +/** + * The PlaySchedule enum represents predefined play time schedules for the bot, simulating real-life play patterns. + * + *

+ * 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. + *

+ * + *

Main Features:

+ *
    + *
  • Predefined Time Ranges: Each schedule has a start and end time that corresponds to specific periods of the day + * (e.g., morning, afternoon, evening).
  • + *
  • Varied Durations: Schedules vary in length, offering short, medium, and long play periods for each time of day.
  • + *
  • Realistic Break Simulation: The bot automatically checks whether it is within or outside the defined play schedule, + * allowing for breaks and simulating a more realistic user pattern. This is managed by the Break Handler plugin.
  • + *
+ * + *

Usage:

+ *

+ * 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. + *

+ * + *

Schedule Checks:

+ *

+ * 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. + *

+ */ + +public enum PlaySchedule { + SHORT_MORNING(LocalTime.of(8, 0), LocalTime.of(9, 0)), + MEDIUM_MORNING(LocalTime.of(7, 0), LocalTime.of(10, 0)), + LONG_MORNING(LocalTime.of(6, 0), LocalTime.of(12, 0)), + + SHORT_AFTERNOON(LocalTime.of(12, 0), LocalTime.of(13, 0)), + MEDIUM_AFTERNOON(LocalTime.of(12, 0), LocalTime.of(15, 0)), + LONG_AFTERNOON(LocalTime.of(12, 0), LocalTime.of(18, 0)), + + SHORT_EVENING(LocalTime.of(18, 0), LocalTime.of(19, 0)), + MEDIUM_EVENING(LocalTime.of(17, 0), LocalTime.of(20, 0)), + LONG_EVENING(LocalTime.of(17, 0), LocalTime.of(23, 0)), + + SHORT_DAY(LocalTime.of(9, 0), LocalTime.of(17, 0)), + MEDIUM_DAY(LocalTime.of(8, 0), LocalTime.of(18, 0)), + LONG_DAY(LocalTime.of(6, 0), LocalTime.of(22, 0)); + + private final LocalTime startTime; + private final LocalTime endTime; + + PlaySchedule(LocalTime startTime, LocalTime endTime) { + this.startTime = startTime; + this.endTime = endTime; + } + + public boolean isOutsideSchedule() { + LocalTime currentTime = LocalTime.now(); + return currentTime.isBefore(startTime) || currentTime.isAfter(endTime); + } + + public Duration timeUntilNextSchedule() { + LocalTime currentTime = LocalTime.now(); + if (currentTime.isBefore(startTime)) { + return Duration.between(currentTime, startTime); + } else if (currentTime.isAfter(endTime)) { + return Duration.between(currentTime, startTime).plusDays(1); + } else { + return Duration.ZERO; + } + } + +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/util/antiban/enums/PlayStyle.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/util/antiban/enums/PlayStyle.java new file mode 100644 index 0000000000..1a00e876dd --- /dev/null +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/util/antiban/enums/PlayStyle.java @@ -0,0 +1,230 @@ +package net.runelite.client.plugins.microbot.util.antiban.enums; + +import lombok.Getter; +import lombok.Setter; +import lombok.extern.slf4j.Slf4j; +import net.runelite.client.plugins.microbot.Microbot; + +import java.time.Duration; +import java.time.Instant; +import java.util.Random; +import java.util.concurrent.ThreadLocalRandom; + +/** + * The PlayStyle enum represents different behavioral profiles for bot activity, + * each simulating varying levels of human-like behavior by adjusting the frequency + * and intensity of actions over time. + * + *

+ * 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. + *

+ * + *

Main Features:

+ *
    + *
  • Profiles: Ranges from "Extreme Aggressive" to "Passive," with varying tick intervals and breaks.
  • + *
  • Dynamic Evolution: Play styles can evolve over time, adjusting action intervals using sine wave patterns + * to simulate natural human variability.
  • + *
  • Attention Span: Each play style includes a simulated attention span, after which the profile may switch + * to another one to mimic shifts in focus or behavior.
  • + *
  • Profile Switching: Play styles can switch up or down based on probability, simulating refocusing and + * different user habits.
  • + *
  • Randomization: Random play style generation for unpredictable behavior and more realistic automation.
  • + *
+ * + *

Usage:

+ *

+ * 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. + *

+ * + *

Example:

+ *
+ * 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)
+ * 
+ * + *

Attention Span Simulation:

+ *

+ * 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. + *

+ * + *

Main Features:

+ *
    + *
  • Enable or disable anti-ban features like action cooldowns and micro-breaks.
  • + *
  • Customize the bot's behavior with random intervals, dynamic activity, and simulated fatigue.
  • + *
  • Adjust the duration and probability of micro-breaks and action cooldowns.
  • + *
  • Fine-tune mouse behavior, including natural movements and random actions.
  • + *
  • View real-time information about the current play style, activity, and bot status.
  • + *
+ * + *

+ * 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=Amulet of glory(4), getIdentifier=9, getType=CC_OP_LOW_PRIORITY, getParam0=1, getParam1=983043, getItemId=1712, isForceLeftClick=false, isDeprioritized=false) // Rs2Reflection.invokeMenu(rs2Item.slot, container, MenuAction.CC_OP.getId(), identifier, rs2Item.id, "Withdraw-1", rs2Item.name, -1, -1); } diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/util/gameobject/Rs2GameObject.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/util/gameobject/Rs2GameObject.java index 583807de2c..188756846b 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/util/gameobject/Rs2GameObject.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/util/gameobject/Rs2GameObject.java @@ -9,16 +9,15 @@ import net.runelite.client.plugins.microbot.util.camera.Rs2Camera; import net.runelite.client.plugins.microbot.util.keyboard.Rs2Keyboard; import net.runelite.client.plugins.microbot.util.menu.NewMenuEntry; +import net.runelite.client.plugins.microbot.util.misc.Rs2UiHelper; import net.runelite.client.plugins.microbot.util.player.Rs2Player; import net.runelite.client.plugins.microbot.util.reflection.Rs2Reflection; import net.runelite.client.plugins.microbot.util.tile.Rs2Tile; import net.runelite.client.plugins.microbot.util.walker.Rs2Walker; import javax.annotation.Nullable; -import java.awt.*; import java.awt.event.KeyEvent; import java.lang.reflect.Field; -import java.util.List; import java.util.*; import java.util.stream.Collectors; @@ -432,11 +431,14 @@ public static GameObject findObject(String objectName, boolean exact, int distan } for (GameObject gameObject : gameObjects) { - ObjectComposition objComp = convertGameObjectToObjectComposition(gameObject); + if (!Rs2Tile.areSurroundingTilesWalkable(gameObject.getWorldLocation(), gameObject.sizeX(), gameObject.sizeY())) + continue; if (hasLineOfSight && !hasLineOfSight(gameObject)) continue; + ObjectComposition objComp = convertGameObjectToObjectComposition(gameObject); + if (objComp == null) { continue; } @@ -1087,7 +1089,7 @@ private static boolean clickObject(TileObject object, String action) { } - Microbot.doInvoke(new NewMenuEntry(param0, param1, menuAction.getId(), object.getId(), -1, objComp.getName()), new Rectangle(object.getCanvasTilePoly().getBounds())); + Microbot.doInvoke(new NewMenuEntry(param0, param1, menuAction.getId(), object.getId(), -1, objComp.getName(), object), Rs2UiHelper.getObjectClickbox(object)); //Rs2Reflection.invokeMenu(param0, param1, menuAction.getId(), object.getId(),-1, "", "", -1, -1); diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/util/inventory/Rs2Inventory.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/util/inventory/Rs2Inventory.java index 7ec9dd6d95..07f3b626f4 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/util/inventory/Rs2Inventory.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/util/inventory/Rs2Inventory.java @@ -7,7 +7,9 @@ import net.runelite.api.widgets.WidgetInfo; import net.runelite.client.plugins.microbot.Microbot; import net.runelite.client.plugins.microbot.globval.enums.InterfaceTab; +import net.runelite.client.plugins.microbot.util.antiban.Rs2AntibanSettings; import net.runelite.client.plugins.microbot.util.bank.Rs2Bank; +import net.runelite.client.plugins.microbot.util.combat.Rs2Combat; import net.runelite.client.plugins.microbot.util.equipment.Rs2Equipment; import net.runelite.client.plugins.microbot.util.gameobject.Rs2GameObject; import net.runelite.client.plugins.microbot.util.grandexchange.Rs2GrandExchange; @@ -23,8 +25,8 @@ import java.awt.*; import java.util.ArrayList; import java.util.Arrays; +import java.util.Collections; import java.util.List; -import java.util.Optional; import java.util.function.Predicate; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -411,7 +413,8 @@ public static boolean dropAll() { items()) { if (item == null) continue; invokeMenu(item, "Drop"); - sleep(300, 600); + if (!Rs2AntibanSettings.naturalMouse) + sleep(150, 300); } return true; } @@ -427,7 +430,8 @@ public static boolean dropAll(int id) { items().stream().filter(x -> x.id == id).collect(Collectors.toList())) { if (item == null) continue; invokeMenu(item, "Drop"); - sleep(300, 600); + if (!Rs2AntibanSettings.naturalMouse) + sleep(150, 300); } return true; } @@ -443,7 +447,8 @@ public static boolean dropAll(Integer... ids) { items().stream().filter(x -> Arrays.stream(ids).anyMatch(id -> id == x.id)).collect(Collectors.toList())) { if (item == null) continue; invokeMenu(item, "Drop"); - sleep(300, 600); + if (!Rs2AntibanSettings.naturalMouse) + sleep(150, 300); } return true; } @@ -459,7 +464,8 @@ public static boolean dropAll(String name) { items().stream().filter(x -> x.name.equalsIgnoreCase(name)).collect(Collectors.toList())) { if (item == null) continue; invokeMenu(item, "Drop"); - sleep(300, 600); + if (!Rs2AntibanSettings.naturalMouse) + sleep(150, 300); } return true; } @@ -475,7 +481,8 @@ public static boolean dropAll(String... names) { items().stream().filter(x -> Arrays.stream(names).anyMatch(name -> name.equalsIgnoreCase(x.name))).collect(Collectors.toList())) { if (item == null) continue; invokeMenu(item, "Drop"); - sleep(300, 600); + if (!Rs2AntibanSettings.naturalMouse) + sleep(150, 300); } return true; } @@ -491,7 +498,8 @@ public static boolean dropAll(Predicate predicate) { items().stream().filter(predicate).collect(Collectors.toList())) { if (item == null) continue; invokeMenu(item, "Drop"); - sleep(150, 300); + if (!Rs2AntibanSettings.naturalMouse) + sleep(150, 300); } return true; } @@ -578,7 +586,8 @@ public static boolean dropAll(Predicate predicate, DropOrder dropOrder) for (Rs2Item item : itemsToDrop) { if (item == null) continue; invokeMenu(item, "Drop"); - sleep(150, 300); + if (!Rs2AntibanSettings.naturalMouse) + sleep(150, 300); } return true; } @@ -635,7 +644,8 @@ public static boolean dropAllExcept(Predicate predicate) { items().stream().filter(predicate).collect(Collectors.toList())) { if (item == null) continue; invokeMenu(item, "Drop"); - sleep(300, 600); + if (!Rs2AntibanSettings.naturalMouse) + sleep(150, 300); } return true; } @@ -667,7 +677,8 @@ public static boolean dropAllExcept(int gpValue, List ignoreItems) { if (totalPrice >= gpValue) continue; invokeMenu(item, "Drop"); - sleep(300, 600); + if (!Rs2AntibanSettings.naturalMouse) + sleep(150, 300); } return true; } @@ -1868,7 +1879,7 @@ public static void useRestoreEnergyItem() { * @return List of Potion Items in Inventory */ public static List getFilteredPotionItemsInInventory(String potionName) { - return getFilteredPotionItemsInInventory(Arrays.asList(potionName)); + return getFilteredPotionItemsInInventory(Collections.singletonList(potionName)); } /** @@ -2014,6 +2025,26 @@ public static boolean waitForInventoryChanges() { return isInventoryChanged; } + /** + * Moves the specified item to the specified slot in the inventory. + * + * @return + */ + public static boolean moveItemToSlot(Rs2Item item, int slot) { + if (item == null) return false; + if (slot < 0 || slot >= CAPACITY) return false; + if (item.slot == slot) return false; + + Widget inventory = getInventory(); + if (inventory == null) return false; + Rectangle itemBounds = itemBounds(item); + Rectangle slotBounds = inventory.getDynamicChildren()[slot].getBounds(); + + Microbot.drag(itemBounds, slotBounds); + + return true; + } + public static boolean dropEmptyVials() { return dropAll("empty vial"); } diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/util/magic/Rs2Magic.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/util/magic/Rs2Magic.java index 57c57e730b..821c41b96c 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/util/magic/Rs2Magic.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/util/magic/Rs2Magic.java @@ -3,7 +3,6 @@ import net.runelite.api.Point; import net.runelite.api.*; import net.runelite.api.widgets.Widget; -import net.runelite.api.widgets.WidgetInfo; import net.runelite.client.plugins.microbot.Microbot; import net.runelite.client.plugins.microbot.globval.enums.InterfaceTab; import net.runelite.client.plugins.microbot.util.camera.Rs2Camera; @@ -14,7 +13,6 @@ import net.runelite.client.plugins.microbot.util.tabs.Rs2Tab; import net.runelite.client.plugins.microbot.util.widget.Rs2Widget; import net.runelite.client.plugins.skillcalculator.skills.MagicAction; -import net.runelite.client.plugins.timers.GameTimer; import org.apache.commons.lang3.NotImplementedException; import java.awt.*; @@ -70,7 +68,7 @@ public static void cast(MagicAction magicSpell) { if (magicSpell.getWidgetId() == -1) throw new NotImplementedException("This spell has not been configured yet in the MagicAction.java class"); - Microbot.doInvoke(new NewMenuEntry(-1, magicSpell.getWidgetId(), menuAction.getId(), identifier, -1, "" + magicSpell.getName() + ""), new Rectangle(0, 0, Microbot.getClient().getCanvasWidth(), Microbot.getClient().getCanvasHeight())); + Microbot.doInvoke(new NewMenuEntry("cast", -1, magicSpell.getWidgetId(), menuAction.getId(), identifier, -1, magicSpell.getName()), new Rectangle(Rs2Widget.getWidget(magicSpell.getWidgetId()).getBounds())); //Rs2Reflection.invokeMenu(-1, magicSpell.getWidgetId(), menuAction.getId(), 1, -1, "Cast", "" + magicSpell.getName() + "", -1, -1); } @@ -233,6 +231,19 @@ private static void superHeat(Widget superheat, Rs2Item item, int sleepMin, int } } + // humidify + public static void humidify() { + sleepUntil(() -> { + Rs2Tab.switchToMagicTab(); + sleep(50, 150); + return Rs2Tab.getCurrentTab() == InterfaceTab.MAGIC; + }); + Widget humidify = Rs2Widget.findWidget(MagicAction.HUMIDIFY.getName()); + if (humidify.getSpriteId() == 1972) { + Microbot.click(humidify.getBounds()); + } + } + private static void alch(Widget alch) { alch(alch, null, 300, 600); } diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/util/math/Rs2Random.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/util/math/Rs2Random.java new file mode 100644 index 0000000000..dbe800d8e1 --- /dev/null +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/util/math/Rs2Random.java @@ -0,0 +1,392 @@ +package net.runelite.client.plugins.microbot.util.math; + +import net.runelite.api.Point; +import net.runelite.client.plugins.microbot.util.Global; + +import java.awt.*; +import java.util.Random; + +/** + * The {@code Rs2Random} class provides a variety of random number generation methods + * aimed at simulating human-like randomness and behavior in bots. This includes methods + * for generating random numbers using Gaussian/Normal distributions, truncated ranges, + * skewed distributions, and methods that generate random points on the game screen. + * + *

+ * 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. + *

+ * + *

Key Features:

+ *
    + *
  • Gaussian/Normal random number generation with custom mean and deviation.
  • + *
  • Truncated Gaussian distribution for generating random numbers within specific bounds.
  • + *
  • Skewed random number generation towards a certain mode within a specified range.
  • + *
  • Methods for generating random points on the game screen, weighted around a center or skewed towards a direction.
  • + *
  • Random wait times and dice roll simulations based on probability percentages.
  • + *
+ * + *

Main Methods:

+ *
    + *
  • {@code nzRandom()}: Returns a non-zero random double value, ensuring that the result + * is greater than a very small number.
  • + *
  • {@code gaussRand(double mean, double dev)}: Generates a random value based on a + * Gaussian (normal) distribution with the specified mean and standard deviation.
  • + *
  • {@code truncatedGauss(double left, double right, double cutoff)}: Generates a random + * number within the given range using a truncated Gaussian distribution.
  • + *
  • {@code skewedRand(double mode, double lo, double hi, double cutoff)}: Generates a random + * number skewed towards the specified mode within a specified range.
  • + *
  • {@code normalRange(double min, double max, double cutoff)}: Generates a random number + * within a range, with a bias towards the mean.
  • + *
  • {@code randomPoint(Point mean, int maxRad, double cutoff)}: Generates a random point + * on the screen, weighted around a central point within a maximum radius.
  • + *
  • {@code randomPoint(Rectangle rect, double cutoff)}: Generates a random point within the + * bounds of the given rectangle, biased towards the center.
  • + *
  • {@code dice(double chancePercent)}: Simulates a dice roll, returning true if the randomly + * generated number is within the chance percentage.
  • + *
  • {@code wait(double min, double max, EWaitDir weight)}: Simulates a wait with a random + * duration, biased towards the mean, left, or right of the given range.
  • + *
  • {@code waitEx(double mean, double dev)}: Waits for a random duration based on a Gaussian + * distribution.
  • + *
+ * + *

Use Cases:

+ *
    + *
  • Generate human-like randomness in bot scripts for actions such as clicking, waiting, + * or moving the mouse.
  • + *
  • Simulate random wait times to avoid predictable patterns in bot behavior.
  • + *
  • Generate random points within a specified area for simulating mouse movements.
  • + *
  • Apply randomness in decision-making processes, such as determining whether to perform + * an action based on a random chance.
  • + *
+ * + *

Dependencies:

+ *
    + *
  • {@code Global.sleep(int)}: Used in the {@code systemWait(long)} method to simulate delays.
  • + *
  • {@code Point} and {@code Rectangle}: Utilized for geometric calculations related to screen coordinates.
  • + *
+ * + *

Example Usage:

+ *
+ * // 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);
+ * 
+ * + *

Limitations:

+ *
    + *
  • The class heavily relies on randomness, which may produce unexpected results if not handled carefully.
  • + *
  • Randomness might not always be sufficient to simulate real human behavior and may require tuning for specific use cases.
  • + *
+ * + *

Enum:

+ *
    + *
  • {@code EWaitDir}: Defines the direction of bias for random waits, including left, mean, and right skew.
  • + *
+ * + *

Private Helpers:

+ *
    + *
  • {@code systemWait(long time)}: Invokes a system-level wait for the specified time in milliseconds.
  • + *
  • {@code rotatePoint(Point point, double angle, double originX, double originY)}: Rotates a point around an origin by a specified angle.
  • + *
+ */ + +public class Rs2Random { + + private static final double GAUSS_CUTOFF = 4.0; + private static final Random RANDOM = new Random(); + + /** + * Returns a non-zero random double value. + * Ensures that the result is always greater than a very small number (1.0e-320), + * preventing the generation of an exact zero. + * + * @return A non-zero random double value. + */ + public static double nzRandom() { + return Math.max(RANDOM.nextDouble(), 1.0e-320); + } + + /** + * Generates a random value based on a Gaussian (normal) distribution with a specified mean and standard deviation. + * + * @param mean The mean (center) value of the distribution. + * @param dev The standard deviation of the distribution. + * @return A random double value from the Gaussian distribution. + */ + public static double gaussRand(double mean, double dev) { + double len = dev * Math.sqrt(-2 * Math.log(nzRandom())); + return mean + len * Math.cos(2 * Math.PI * RANDOM.nextDouble()); + } + + /** + * Generates a random number within the given range using a truncated Gaussian distribution. + * This ensures that the value is within the bounds of the left and right range. + * + * @param left The minimum bound of the range. + * @param right The maximum bound of the range. + * @param cutoff The cutoff value to restrict extreme values. Defaults to GAUSS_CUTOFF(4) if less than or equal to 0. + * @return A random double value within the specified range. + */ + public static double truncatedGauss(double left, double right, double cutoff) { + if (cutoff <= 0) { + cutoff = GAUSS_CUTOFF; + } + + double result; + do { + result = Math.abs(Math.sqrt(-2 * Math.log(nzRandom())) * Math.cos(2 * Math.PI * RANDOM.nextDouble())); + } while (result >= cutoff); + + return result / cutoff * (right - left) + left; + } + + /** + * Generates a random long value within the given range using a truncated Gaussian distribution. + * + * @param left The minimum bound of the range. + * @param right The maximum bound of the range. + * @param cutoff The cutoff value to restrict extreme values. + * @return A random long value within the specified range. + */ + public static long truncatedGauss(long left, long right, double cutoff) { + return Math.round(truncatedGauss((double) left, (double) right, cutoff)); + } + + /** + * Generates a random number skewed towards the specified mode within a specified range. + * This allows for a biased distribution where the values tend to cluster around the mode. + * + * @param mode The central value around which the distribution is skewed. + * @param lo The lower bound of the range. + * @param hi The upper bound of the range. + * @param cutoff The cutoff value to restrict extreme values. Defaults to GAUSS_CUTOFF(4) if less than or equal to 0. + * @return A random double value skewed towards the mode. + */ + public static double skewedRand(double mode, double lo, double hi, double cutoff) { + if (cutoff <= 0) { + cutoff = GAUSS_CUTOFF; + } + + double top = lo; + if (RANDOM.nextDouble() * (hi - lo) > mode - lo) { + top = hi; + } + + double result; + do { + result = Math.abs(Math.sqrt(-2 * Math.log(nzRandom())) * Math.cos(2 * Math.PI * RANDOM.nextDouble())); + } while (result >= cutoff); + + return result / cutoff * (top - mode) + mode; + } + + /** + * Generates a random long value skewed towards the specified mode within a specified range. + * + * @param mode The central value around which the distribution is skewed. + * @param lo The lower bound of the range. + * @param hi The upper bound of the range. + * @param cutoff The cutoff value to restrict extreme values. + * @return A random long value skewed towards the mode. + */ + public static long skewedRand(long mode, long lo, long hi, double cutoff) { + return Math.round(skewedRand((double) mode, (double) lo, (double) hi, cutoff)); + } + + /** + * Generates a random number within the specified range, biased towards the mean. + * The distribution has a higher likelihood of generating numbers closer to the midpoint of the range. + * + * @param min The minimum bound of the range. + * @param max The maximum bound of the range. + * @param cutoff The cutoff value to restrict extreme values. Defaults to GAUSS_CUTOFF(4) if less than or equal to 0. + * @return A random double value within the specified range, biased towards the middle. + */ + public static double normalRange(double min, double max, double cutoff) { + if (cutoff <= 0) { + cutoff = GAUSS_CUTOFF; + } + + switch (RANDOM.nextInt(2)) { + case 0: + return (max + min) / 2.0 + truncatedGauss(0, (max - min) / 2, cutoff); + case 1: + return (max + min) / 2.0 - truncatedGauss(0, (max - min) / 2, cutoff); + default: + throw new IllegalStateException("Unexpected value: " + RANDOM.nextInt(2)); + } + } + + /** + * Generates a random long value within the specified range, biased towards the mean. + * + * @param min The minimum bound of the range. + * @param max The maximum bound of the range. + * @param cutoff The cutoff value to restrict extreme values. Defaults to GAUSS_CUTOFF(4) if less than or equal to 0. + * @return A random long value within the specified range, biased towards the middle. + */ + public static long normalRange(long min, long max, double cutoff) { + if (cutoff <= 0) { + cutoff = GAUSS_CUTOFF; + } + + switch (RANDOM.nextInt(2)) { + case 0: + return Math.round((max + min) / 2.0 + truncatedGauss(0, (max - min) / 2, cutoff)); + case 1: + return Math.round((max + min) / 2.0 - truncatedGauss(0, (max - min) / 2, cutoff)); + default: + throw new IllegalStateException("Unexpected value: " + RANDOM.nextInt(2)); + } + } + + /** + * Generates a random point on the screen, weighted around a central point (mean) within a maximum radius. + * The point is selected to simulate human-like randomness in mouse movement or other actions. + * + * @param mean The central point to weight the randomness around. + * @param maxRad The maximum radius away from the central point. + * @param cutoff The cutoff value for restricting extreme values. Defaults to GAUSS_CUTOFF(4) if less than or equal to 0. + * @return A random point near the central point, within the specified radius. + */ + public static Point randomPoint(Point mean, int maxRad, double cutoff) { + int x = (int) normalRange(mean.getX() - maxRad, mean.getX() + maxRad, cutoff); + int y = (int) normalRange(mean.getY() - maxRad, mean.getY() + maxRad, cutoff); + return new Point(x, y); + } + + /** + * Generates a random point within the bounds of the given rectangle, biased towards the center. + * This method is useful for simulating human-like randomness in screen interactions. + * + * @param rect The rectangular area within which to generate the random point. + * @param cutoff The cutoff value for restricting extreme values. Defaults to GAUSS_CUTOFF(4) if less than or equal to 0. + * @return A random point within the rectangle, biased towards the middle. + */ + public static Point randomPoint(Rectangle rect, double cutoff) { + double x1 = rect.getX(); + double y1 = rect.getY(); + double x2 = rect.getX() + rect.getWidth(); + double y2 = rect.getY() + rect.getHeight(); + double a = Math.atan2(rect.getHeight(), rect.getWidth()); + + int x = (int) normalRange(x1 + 1, x2 - 1, cutoff); + int y = (int) normalRange(y1 + 1, y2 - 1, cutoff); + return rotatePoint(new Point(x, y), a, (x2 + x1) / 2 + RANDOM.nextDouble() - 0.5, (y2 + y1) / 2 + RANDOM.nextDouble() - 0.5); + } + + /** + * Generates a random point within the bounds of a rectangle, skewed towards a specified 'from' point. + * Useful for simulating more human-like randomness in actions such as dragging or moving the mouse. + * + * @param from The point to bias the random point generation towards. + * @param rect The rectangular area within which to generate the random point. + * @param force A multiplier that defines how strongly the point should be skewed towards the 'from' point. + * @return A random point within the rectangle, skewed towards the 'from' point. + */ + public static Point randomPointEx(Point from, Rectangle rect, double force) { + Point p = from; + p = new Point(Math.min(Math.max(p.getX(), (int) rect.getX()), (int) (rect.getX() + rect.getWidth())), Math.min(Math.max(p.getY(), (int) rect.getY()), (int) (rect.getY() + rect.getHeight()))); + + Point c = new Point((int) (rect.getX() + rect.getWidth() / 2), (int) (rect.getY() + rect.getHeight() / 2)); + double r = Math.hypot(p.getX() - c.getX(), p.getY() - c.getY()) * force; + double x = Math.atan2(c.getY() - p.getY(), c.getX() - p.getX()); + p = new Point((int) (p.getX() + Math.round(Math.cos(x) * r)), (int) (p.getY() + Math.round(Math.sin(x) * r))); + + int resultX = (int) skewedRand(p.getX(), (int) rect.getX(), (int) (rect.getX() + rect.getWidth()), GAUSS_CUTOFF); + int resultY = (int) skewedRand(p.getY(), (int) rect.getY(), (int) (rect.getY() + rect.getHeight()), GAUSS_CUTOFF); + return new Point(resultX, resultY); + } + + /** + * Simulates a dice roll, returning true if the random number generated falls within the given chance percentage. + * + * @param chancePercent The percentage chance of returning true. Must be between 0 and 100. + * @return True if the random number falls within the chance, false otherwise. + */ + public static boolean dice(double chancePercent) { + return RANDOM.nextDouble() < (chancePercent <= 0.99 ? chancePercent * 100 : chancePercent) / 100; + } + + /** + * Simulates a wait with a random duration, biased towards the mean, left, or right of the given range. + * This method is useful for introducing randomness in bot actions to reduce predictability. + * + * @param min The minimum wait time in milliseconds. + * @param max The maximum wait time in milliseconds. + * @param weight The direction of bias for the wait time (left, mean, or right skew). + */ + public static void wait(double min, double max, EWaitDir weight) { + switch (weight) { + case wdLeft: + systemWait(Math.round(truncatedGauss(min, max, 0))); + break; + case wdMean: + systemWait(Math.round(normalRange(min, max, 0))); + break; + case wdRight: + systemWait(Math.round(truncatedGauss(max, min, 0))); + break; + } + } + + /** + * Simulates a wait with a random duration, biased towards the left side of the given range. + * + * @param min The minimum wait time in milliseconds. + * @param max The maximum wait time in milliseconds. + */ + public static void wait(int min, int max) { + wait(min, max, EWaitDir.wdLeft); + } + + /** + * Waits for a random duration based on a Gaussian distribution. + * The wait time is calculated using a normal distribution with the specified mean and standard deviation. + * + * @param mean The mean wait time in milliseconds. + * @param dev The standard deviation of the wait time. + */ + public static void waitEx(double mean, double dev) { + wait(Math.abs(Math.round(gaussRand(mean, dev))), 0, EWaitDir.wdMean); + } + + /** + * Pauses the execution for a specified amount of time in milliseconds. + * This method is a system-level wait used for simulating delays in bot actions. + * + * @param time The duration to wait in milliseconds. + */ + private static void systemWait(long time) { + Global.sleep((int) time); + } + + /** + * Rotates a given point around a specified origin by a certain angle. + * This method is used for calculating rotated positions in 2D space. + * + * @param point The point to be rotated. + * @param angle The angle to rotate the point, in radians. + * @param originX The x-coordinate of the origin point. + * @param originY The y-coordinate of the origin point. + * @return A new point representing the rotated coordinates. + */ + private static Point rotatePoint(Point point, double angle, double originX, double originY) { + double sin = Math.sin(angle); + double cos = Math.cos(angle); + double dx = point.getX() - originX; + double dy = point.getY() - originY; + int newX = (int) (cos * dx - sin * dy + originX); + int newY = (int) (sin * dx + cos * dy + originY); + return new Point(newX, newY); + } + + + enum EWaitDir { + wdLeft, wdMean, wdRight + } +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/util/menu/NewMenuEntry.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/util/menu/NewMenuEntry.java index 71c785ef99..0157399bbf 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/util/menu/NewMenuEntry.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/util/menu/NewMenuEntry.java @@ -16,6 +16,8 @@ public class NewMenuEntry implements MenuEntry { private int param1; private boolean forceLeftClick; private int itemId; + private Actor actor; + private TileObject gameObject; public NewMenuEntry(int param0, int param1, int opcode, int identifier, int itemId, String target) { this.option = "Use"; @@ -28,6 +30,30 @@ public NewMenuEntry(int param0, int param1, int opcode, int identifier, int item this.itemId = itemId; } + public NewMenuEntry(int param0, int param1, int opcode, int identifier, int itemId, String target, Actor actor) { + this.option = "Use"; + this.target = target; + this.identifier = identifier; + this.type = MenuAction.of(opcode); + this.param0 = param0; + this.param1 = param1; + this.forceLeftClick = true; + this.itemId = itemId; + this.actor = actor; + } + + public NewMenuEntry(int param0, int param1, int opcode, int identifier, int itemId, String target, TileObject gameObject) { + this.option = "Use"; + this.target = target; + this.identifier = identifier; + this.type = MenuAction.of(opcode); + this.param0 = param0; + this.param1 = param1; + this.forceLeftClick = true; + this.itemId = itemId; + this.gameObject = gameObject; + } + public NewMenuEntry(String option, String target, int identifier, MenuAction type, int param0, int param1, boolean forceLeftClick) { this.option = option; this.target = target; @@ -49,6 +75,9 @@ public NewMenuEntry(String option, int param0, int param1, int opcode, int ident this.itemId = itemId; } + public NewMenuEntry() { + } + public String getOption() { return this.option; } @@ -138,6 +167,7 @@ public MenuEntry onClick(Consumer callback) { public Consumer onClick() { return null; } + public MenuEntry getParent() { return this; } @@ -167,17 +197,23 @@ public Widget getWidget() { @Nullable public NPC getNpc() { - return null; + return actor instanceof NPC ? (NPC) actor : null; + } @Nullable public Player getPlayer() { - return null; + return actor instanceof Player ? (Player) actor : null; } @Nullable public Actor getActor() { - return null; + return actor; + } + + @Nullable + public TileObject getGameObject() { + return gameObject; } @org.jetbrains.annotations.Nullable @@ -238,14 +274,8 @@ public boolean equals(Object o) { Object this$type = this.getType(); Object other$type = other.getType(); if (this$type == null) { - if (other$type != null) { - return false; - } - } else if (!this$type.equals(other$type)) { - return false; - } - - return true; + return other$type == null; + } else return this$type.equals(other$type); } } } @@ -274,7 +304,4 @@ public String toString() { String var10000 = this.getOption(); return "NewMenuEntry(option=" + var10000 + ", target=" + this.getTarget() + ", identifier=" + this.getIdentifier() + ", type=" + this.getType() + ", param0=" + this.getParam0() + ", param1=" + this.getParam1() + ", forceLeftClick=" + this.isForceLeftClick() + ")"; } - - public NewMenuEntry() { - } } diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/util/misc/Rs2UiHelper.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/util/misc/Rs2UiHelper.java new file mode 100644 index 0000000000..a9c5aef8d7 --- /dev/null +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/util/misc/Rs2UiHelper.java @@ -0,0 +1,96 @@ +package net.runelite.client.plugins.microbot.util.misc; + +import net.runelite.api.Actor; +import net.runelite.api.Perspective; +import net.runelite.api.Point; +import net.runelite.api.TileObject; +import net.runelite.api.coords.LocalPoint; +import net.runelite.client.plugins.microbot.Microbot; +import net.runelite.client.plugins.microbot.util.antiban.Rs2AntibanSettings; +import net.runelite.client.plugins.microbot.util.math.Rs2Random; +import net.runelite.client.plugins.microbot.util.menu.NewMenuEntry; + +import java.awt.*; +import java.util.Objects; + +public class Rs2UiHelper { + public static boolean isRectangleWithinViewport(Rectangle rectangle) { + int viewportHeight = Microbot.getClient().getViewportHeight(); + int viewportWidth = Microbot.getClient().getViewportWidth(); + + return !(rectangle.getX() > (double) viewportWidth) && + !(rectangle.getY() > (double) viewportHeight) && + !(rectangle.getX() < 0.0) && + !(rectangle.getY() < 0.0); + } + + public static Point getClickingPoint(Rectangle rectangle, boolean randomize) { + if (rectangle.getX() == 1 && rectangle.getY() == 1) return new Point(1, 1); + if (rectangle.getX() == 0 && rectangle.getY() == 0) return new Point(1, 1); + + if (!randomize) return new Point((int) rectangle.getCenterX(), (int) rectangle.getCenterY()); + + //check if mouse is already within the rectangle and return current position + if (Rs2AntibanSettings.naturalMouse) { + java.awt.Point mousePos = Microbot.getMouse().getMousePosition(); + if (isMouseWithinRectangle(rectangle)) return new Point(mousePos.x, mousePos.y); + else return Rs2Random.randomPointEx(new Point(mousePos.x, mousePos.y), rectangle, 0.5); + } else + return Rs2Random.randomPointEx(Microbot.getMouse().getLastClick(), rectangle, 0.5); + } + + //check if mouse is already within the rectangle + public static boolean isMouseWithinRectangle(Rectangle rectangle) { + java.awt.Point mousePos = Microbot.getMouse().getMousePosition(); + if (rectangle.getX() == 1 && rectangle.getY() == 1) return true; + if (rectangle.getX() == 0 && rectangle.getY() == 0) return true; + return rectangle.contains(mousePos); + } + + public static Rectangle getActorClickbox(Actor actor) { + LocalPoint lp = actor.getLocalLocation(); + if (lp == null) { + Microbot.log("LocalPoint is null"); + return new Rectangle(1, 1); + } + + + Shape clickbox = Microbot.getClientThread().runOnClientThread(() -> Perspective.getClickbox(Microbot.getClient(), actor.getModel(), actor.getCurrentOrientation(), lp.getX(), lp.getY(), + Perspective.getTileHeight(Microbot.getClient(), lp, actor.getWorldLocation().getPlane()))); + + + //check if any of the values are negative and return a new rectangle with positive values + assert clickbox != null; +// if (clickbox.getBounds().getX() < 0 || clickbox.getBounds().getY() < 0 || clickbox.getBounds().getWidth() < 0 || clickbox.getBounds().getHeight() < 0) { +// return new Rectangle((int) Math.abs(clickbox.getBounds().getX()), (int) Math.abs(clickbox.getBounds().getY()), (int) Math.abs(clickbox.getBounds().getWidth()), (int) Math.abs(clickbox.getBounds().getHeight())); +// } + + return new Rectangle(clickbox.getBounds()); + } + + public static Rectangle getObjectClickbox(TileObject object) { + + if (object == null) return new Rectangle(1, 1); //return a small rectangle if object is null + Shape clickbox = Microbot.getClientThread().runOnClientThread(() -> Objects.requireNonNull(object.getClickbox())); + + + //check if any of the values are negative and return a new rectangle with positive values + assert clickbox != null; +// if (clickbox.getBounds().getX() < 0 || clickbox.getBounds().getY() < 0 || clickbox.getBounds().getWidth() < 0 || clickbox.getBounds().getHeight() < 0) { +// return new Rectangle((int) Math.abs(clickbox.getBounds().getX()), (int) Math.abs(clickbox.getBounds().getY()), (int) Math.abs(clickbox.getBounds().getWidth()), (int) Math.abs(clickbox.getBounds().getHeight())); +// } + + return new Rectangle(clickbox.getBounds()); + } + + // check if a menu entry is a actor + public static boolean hasActor(NewMenuEntry entry) { + return entry.getActor() != null; + } + + // check if a menu entry is a game object + public static boolean isGameObject(NewMenuEntry entry) { + return entry.getGameObject() != null; + } + +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/util/misc/TimeUtils.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/util/misc/TimeUtils.java new file mode 100644 index 0000000000..8cd5032b67 --- /dev/null +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/util/misc/TimeUtils.java @@ -0,0 +1,21 @@ +package net.runelite.client.plugins.microbot.util.misc; + +import java.time.Duration; +import java.time.Instant; + +public class TimeUtils { + /** + * Get formatted duration between two instants + * + * @param start + * @param finish + * @return duration as string formatted to d:mm:ss + */ + public static String getFormattedDurationBetween(Instant start, Instant finish) { + Duration duration = Duration.between(start, finish); + return String.format("%d:%02d:%02d", + duration.toHours(), + duration.toMinutesPart(), + duration.toSecondsPart()); + } +} \ No newline at end of file diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/util/mouse/Mouse.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/util/mouse/Mouse.java index f7e7066a85..a386b01989 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/util/mouse/Mouse.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/util/mouse/Mouse.java @@ -1,27 +1,56 @@ package net.runelite.client.plugins.microbot.util.mouse; +import lombok.Getter; import net.runelite.api.Point; import net.runelite.client.plugins.microbot.Microbot; +import net.runelite.client.plugins.microbot.util.math.Rs2Random; +import net.runelite.client.plugins.microbot.util.menu.NewMenuEntry; +import javax.swing.*; import java.awt.*; -import java.util.ArrayList; -import java.util.List; - -import static net.runelite.client.plugins.microbot.util.math.Random.random; +import java.util.LinkedList; +@Getter public abstract class Mouse { - + private static final int POINT_LIFETIME = 12;// Maximum number of points to store + final int MAX_POINTS = 500; + LinkedList points = new LinkedList<>(); + Point lastClick = new Point(-1, -1); // getter for last click + // getter for click before last click + Point lastClick2 = new Point(-1, -1); + Point lastMove = new Point(-1, -1); // getter for last move + float hue = 0.0f; // Initial hue value + Timer timer = new Timer(POINT_LIFETIME, e -> { + if (!points.isEmpty()) { + points.removeFirst(); + } + }); public Mouse() { } + public Color getRainbowColor() { + hue += 0.001f; // Increment hue to cycle through colors + if (hue > 1.0f) { + hue = 0.0f; // Reset hue when it exceeds 1.0 + } + return Color.getHSBColor(hue, 1.0f, 1.0f); + } + public Canvas getCanvas() { return Microbot.getClient().getCanvas(); } public int randomizeClick() { - return random(-10, 10); + return (int) Rs2Random.normalRange(-10, 10, 4); } + + public abstract void setLastClick(Point point); + + public abstract void setLastMove(Point point); + + + public abstract Mouse click(int x, int y); public abstract Mouse click(double x, double y); @@ -33,16 +62,20 @@ public int randomizeClick() { public abstract Mouse click(Point point); public abstract Mouse click(Point point, boolean rightClick); + public abstract Mouse click(Point point, NewMenuEntry entry); public abstract Mouse click(); public abstract Mouse move(Point point); public abstract Mouse move(Rectangle rect); public abstract Mouse move(int x, int y); + public abstract Mouse move(double x, double y); public abstract Mouse move(Polygon polygon); public abstract Mouse scrollDown(Point point); public abstract Mouse scrollUp(Point point); + + public abstract Mouse drag(Point startPoint, Point endPoint); public abstract java.awt.Point getMousePosition(); } diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/util/mouse/VirtualMouse.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/util/mouse/VirtualMouse.java index f6a38da072..ee26eb8e4b 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/util/mouse/VirtualMouse.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/util/mouse/VirtualMouse.java @@ -1,8 +1,11 @@ package net.runelite.client.plugins.microbot.util.mouse; +import lombok.extern.slf4j.Slf4j; import net.runelite.api.Point; import net.runelite.client.plugins.microbot.Microbot; -import net.runelite.client.plugins.microbot.util.math.Random; +import net.runelite.client.plugins.microbot.util.antiban.Rs2AntibanSettings; +import net.runelite.client.plugins.microbot.util.menu.NewMenuEntry; +import net.runelite.client.plugins.microbot.util.misc.Rs2UiHelper; import javax.inject.Inject; import java.awt.*; @@ -15,10 +18,11 @@ import static net.runelite.client.plugins.microbot.util.Global.sleep; import static net.runelite.client.plugins.microbot.util.math.Random.random; +@Slf4j public class VirtualMouse extends Mouse { - private final ScheduledExecutorService scheduledExecutorService; + private boolean exited = true; @Inject public VirtualMouse() { @@ -27,16 +31,83 @@ public VirtualMouse() { //getCanvas().setFocusable(false); } - public Mouse click(Point point, boolean rightClick) { + public void setLastClick(Point point) { + lastClick2 = lastClick; + lastClick = point; + } + public void setLastMove(Point point) { + lastMove = point; + points.add(point); + if (points.size() > MAX_POINTS) { + points.removeFirst(); + } + } + + private void handleClick(Point point, boolean rightClick) { + entered(point); + exited(point); + moved(point); + pressed(point, rightClick ? MouseEvent.BUTTON3 : MouseEvent.BUTTON1); + released(point, rightClick ? MouseEvent.BUTTON3 : MouseEvent.BUTTON1); + clicked(point, rightClick ? MouseEvent.BUTTON3 : MouseEvent.BUTTON1); + setLastClick(point); + } + public Mouse click(Point point, boolean rightClick) { if (point == null) return this; - mouseEvent(MouseEvent.MOUSE_ENTERED, point, rightClick); - mouseEvent(MouseEvent.MOUSE_EXITED, point, rightClick); - mouseEvent(MouseEvent.MOUSE_MOVED, point, rightClick); - mouseEvent(MouseEvent.MOUSE_PRESSED, point, rightClick); - mouseEvent(MouseEvent.MOUSE_RELEASED, point, rightClick); - mouseEvent(MouseEvent.MOUSE_FIRST, point, rightClick); + if (Rs2AntibanSettings.naturalMouse && (point.getX() > 1 && point.getY() > 1)) + Microbot.naturalMouse.moveTo(point.getX(), point.getY()); + + if (Microbot.getClient().isClientThread()) { + scheduledExecutorService.schedule(() -> { + handleClick(point, rightClick); + }, 0, TimeUnit.MILLISECONDS); + } else { + handleClick(point, rightClick); + } + + return this; + } + + public Mouse click(Point point, boolean rightClick, NewMenuEntry entry) { + if (point == null) return this; + if (Rs2AntibanSettings.naturalMouse && (point.getX() > 1 && point.getY() > 1)) { + Microbot.naturalMouse.moveTo(point.getX(), point.getY()); + if (Rs2UiHelper.hasActor(entry)) { + log.info("Actor found: " + entry.getActor().getName()); + Rectangle rectangle = Rs2UiHelper.getActorClickbox(entry.getActor()); + if (!Rs2UiHelper.isMouseWithinRectangle(rectangle)) { + point = Rs2UiHelper.getClickingPoint(rectangle, true); + Microbot.naturalMouse.moveTo(point.getX(), point.getY()); + } + + } + if (Rs2UiHelper.isGameObject(entry)) { + log.info("Game Object found: " + entry.getGameObject().toString()); + Rectangle rectangle = Rs2UiHelper.getObjectClickbox(entry.getGameObject()); + if (!Rs2UiHelper.isMouseWithinRectangle(rectangle)) { + point = Rs2UiHelper.getClickingPoint(rectangle, true); + Microbot.naturalMouse.moveTo(point.getX(), point.getY()); + } + } + + + } + + + + // Target menu was set before mouse movement causing some unintended behavior + // This will set the target menu after the mouse movement is finished + Microbot.targetMenu = entry; + if (Microbot.getClient().isClientThread()) { + Point finalPoint = point; + scheduledExecutorService.schedule(() -> { + handleClick(finalPoint, rightClick); + }, 0, TimeUnit.MILLISECONDS); + } else { + handleClick(point, rightClick); + } return this; } @@ -50,7 +121,7 @@ public Mouse click(double x, double y) { } public Mouse click(Rectangle rectangle) { - return click(new Point((int) rectangle.getCenterX() , (int) rectangle.getCenterY()), false); + return click(Rs2UiHelper.getClickingPoint(rectangle, true), false); } @Override @@ -63,40 +134,40 @@ public Mouse click(Point point) { return click(point, false); } + @Override + public Mouse click(Point point, NewMenuEntry entry) { + return click(point, false, entry); + } + @Override public Mouse click() { - return click(new Point((int) MouseInfo.getPointerInfo().getLocation().getX(), (int) MouseInfo.getPointerInfo().getLocation().getY())); + return click(Microbot.getClient().getMouseCanvasPosition()); } public Mouse move(Point point) { - long time = System.currentTimeMillis(); - - MouseEvent mouseMove = new MouseEvent(getCanvas(), MouseEvent.MOUSE_MOVED, time, 0, point.getX(), point.getY(), 1, false, MouseEvent.BUTTON1); - + setLastMove(point); + MouseEvent mouseMove = new MouseEvent(Microbot.getClient().getCanvas(), MouseEvent.MOUSE_MOVED, System.currentTimeMillis(), 0, point.getX(), point.getY(), 0, false); + mouseMove.setSource("Microbot"); getCanvas().dispatchEvent(mouseMove); return this; } public Mouse move(Rectangle rect) { - long time = System.currentTimeMillis(); - - MouseEvent mouseMove = new MouseEvent(getCanvas(), MouseEvent.MOUSE_MOVED, time, 0, (int) rect.getCenterX(), (int) rect.getCenterY(), 1, false, MouseEvent.BUTTON1); - + MouseEvent mouseMove = new MouseEvent(Microbot.getClient().getCanvas(), MouseEvent.MOUSE_MOVED, System.currentTimeMillis(), 0, (int) rect.getCenterX(), (int) rect.getCenterY(), 0, false); + mouseMove.setSource("Microbot"); getCanvas().dispatchEvent(mouseMove); return this; } public Mouse move(Polygon polygon) { - long time = System.currentTimeMillis(); Point point = new Point((int) polygon.getBounds().getCenterX(), (int) polygon.getBounds().getCenterY()); - MouseEvent mouseMove = new MouseEvent(getCanvas(), MouseEvent.MOUSE_MOVED, time, 0, point.getX(), point.getY(), 1, false, MouseEvent.BUTTON1); - + MouseEvent mouseMove = new MouseEvent(getCanvas(), MouseEvent.MOUSE_MOVED, System.currentTimeMillis(), 0, point.getX(), point.getY(), 0, false); + mouseMove.setSource("Microbot"); getCanvas().dispatchEvent(mouseMove); - return this; } @@ -108,10 +179,8 @@ public Mouse scrollDown(Point point) { scheduledExecutorService.schedule(() -> { MouseEvent mouseScroll = new MouseWheelEvent(getCanvas(), MouseEvent.MOUSE_WHEEL, time, 0, point.getX(), point.getY(), 0, false, 0, 10, 2); - - getCanvas().dispatchEvent(mouseScroll); - - + mouseScroll.setSource("Microbot"); + getCanvas().dispatchEvent(mouseScroll); }, random(40, 100), TimeUnit.MILLISECONDS); return this; } @@ -129,26 +198,86 @@ public Mouse scrollUp(Point point) { @Override public java.awt.Point getMousePosition() { - PointerInfo pointerInfo = MouseInfo.getPointerInfo(); - - return pointerInfo != null ? pointerInfo.getLocation() : null; + Point point = lastMove; + return new java.awt.Point(point.getX(), point.getY()); } @Override public Mouse move(int x, int y) { return move(new Point(x, y)); } + @Override public Mouse move(double x, double y) { return move(new Point((int) x, (int) y)); } - private void mouseEvent(int id, Point point, boolean rightClick) - { + @Deprecated + private void mouseEvent(int id, Point point, boolean rightClick) { int button = rightClick ? MouseEvent.BUTTON3 : MouseEvent.BUTTON1; - MouseEvent e = new MouseEvent(Microbot.getClient().getCanvas(), id, System.currentTimeMillis(), 0, point.getX(), point.getY(), 1, false, button); - getCanvas().dispatchEvent(e); } + + private synchronized void pressed(Point point, int button) { + MouseEvent event = new MouseEvent(Microbot.getClient().getCanvas(), MouseEvent.MOUSE_PRESSED, System.currentTimeMillis(), 0, point.getX(), point.getY(), 1, false, button); + event.setSource("Microbot"); + getCanvas().dispatchEvent(event); + } + + private synchronized void released(Point point, int button) { + MouseEvent event = new MouseEvent(Microbot.getClient().getCanvas(), MouseEvent.MOUSE_RELEASED, System.currentTimeMillis(), 0, point.getX(), point.getY(), 1, false, button); + event.setSource("Microbot"); + getCanvas().dispatchEvent(event); + } + + private synchronized void clicked(Point point, int button) { + MouseEvent event = new MouseEvent(Microbot.getClient().getCanvas(), MouseEvent.MOUSE_CLICKED, System.currentTimeMillis(), 0, point.getX(), point.getY(), 1, false, button); + event.setSource("Microbot"); + getCanvas().dispatchEvent(event); + } + + private synchronized void exited(Point point) { + MouseEvent event = new MouseEvent(Microbot.getClient().getCanvas(), MouseEvent.MOUSE_EXITED, System.currentTimeMillis(), 0, point.getX(), point.getY(), 0, false); + event.setSource("Microbot"); + getCanvas().dispatchEvent(event); + exited = true; + } + + private synchronized void entered(Point point) { + MouseEvent event = new MouseEvent(Microbot.getClient().getCanvas(), MouseEvent.MOUSE_ENTERED, System.currentTimeMillis(), 0, point.getX(), point.getY(), 0, false); + event.setSource("Microbot"); + getCanvas().dispatchEvent(event); + exited = false; + } + + private synchronized void moved(Point point) { + MouseEvent event = new MouseEvent(Microbot.getClient().getCanvas(), MouseEvent.MOUSE_MOVED, System.currentTimeMillis(), 0, point.getX(), point.getY(), 0, false); + event.setSource("Microbot"); + getCanvas().dispatchEvent(event); + } + + // New drag method + public Mouse drag(Point startPoint, Point endPoint) { + if (startPoint == null || endPoint == null) return this; + + if (Rs2AntibanSettings.naturalMouse && (startPoint.getX() > 1 && startPoint.getY() > 1)) + Microbot.naturalMouse.moveTo(startPoint.getX(), startPoint.getY()); + else + move(startPoint); + sleep(50, 80); + // Press the mouse button at the start point + pressed(startPoint, MouseEvent.BUTTON1); + sleep(80, 120); + // Move to the end point while holding the button down + if (Rs2AntibanSettings.naturalMouse && (endPoint.getX() > 1 && endPoint.getY() > 1)) + Microbot.naturalMouse.moveTo(endPoint.getX(), endPoint.getY()); + else + move(endPoint); + sleep(80, 120); + // Release the mouse button at the end point + released(endPoint, MouseEvent.BUTTON1); + + return this; + } } diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/util/mouse/naturalmouse/NaturalMouse.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/util/mouse/naturalmouse/NaturalMouse.java new file mode 100644 index 0000000000..17d9a78aba --- /dev/null +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/util/mouse/naturalmouse/NaturalMouse.java @@ -0,0 +1,185 @@ +package net.runelite.client.plugins.microbot.util.mouse.naturalmouse; + +import lombok.Getter; +import lombok.Setter; +import lombok.extern.slf4j.Slf4j; +import net.runelite.api.Client; +import net.runelite.client.plugins.microbot.Microbot; +import net.runelite.client.plugins.microbot.util.Global; +import net.runelite.client.plugins.microbot.util.antiban.Rs2Antiban; +import net.runelite.client.plugins.microbot.util.antiban.enums.ActivityIntensity; +import net.runelite.client.plugins.microbot.util.mouse.naturalmouse.api.MouseInfoAccessor; +import net.runelite.client.plugins.microbot.util.mouse.naturalmouse.api.MouseMotionFactory; +import net.runelite.client.plugins.microbot.util.mouse.naturalmouse.api.SystemCalls; +import net.runelite.client.plugins.microbot.util.mouse.naturalmouse.support.DefaultMouseMotionNature; +import net.runelite.client.plugins.microbot.util.mouse.naturalmouse.support.DefaultSpeedManager; +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.util.FactoryTemplates; +import net.runelite.client.plugins.microbot.util.mouse.naturalmouse.util.FlowTemplates; +import net.runelite.client.plugins.microbot.util.mouse.naturalmouse.util.Pair; + +import javax.inject.Inject; +import java.awt.*; +import java.util.Collection; +import java.util.List; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.ThreadLocalRandom; + +@Slf4j +public class NaturalMouse { + public final MouseMotionNature nature; + private final ThreadLocalRandom random = ThreadLocalRandom.current(); + private final ExecutorService executorService = Executors.newSingleThreadExecutor(); + @Inject + private Client client; + @Getter + @Setter + private List flows = List.of( + new Flow(FlowTemplates.variatingFlow()), + new Flow(FlowTemplates.slowStartupFlow()), + new Flow(FlowTemplates.slowStartup2Flow()), + new Flow(FlowTemplates.jaggedFlow()), + new Flow(FlowTemplates.interruptedFlow()), + new Flow(FlowTemplates.interruptedFlow2()), + new Flow(FlowTemplates.stoppingFlow()), + new Flow(FlowTemplates.adjustingFlow()), + new Flow(FlowTemplates.random()) + ); + + @Inject + public NaturalMouse() { + nature = new DefaultMouseMotionNature(); + nature.setSystemCalls(new SystemCallsImpl()); + nature.setMouseInfo(new MouseInfoImpl()); + } + + public synchronized void moveTo(int dx, int dy) { +// if(Rs2UiHelper.isStretchedEnabled()) +// { +// dx = Rs2UiHelper.stretchX(dx); +// dy = Rs2UiHelper.stretchY(dy); +// } + int finalDx = dx; + int finalDy = dy; + + if (!Microbot.getClient().isClientThread()) { + move(finalDx, finalDy); + } else { + + executorService.submit(() -> move(finalDx, finalDy)); + } + } + + private synchronized void move(int dx, int dy) { + var motion = getFactory().build(dx, dy); + try { + motion.move(); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + + public MouseMotionFactory getFactory() { + if (Rs2Antiban.getActivityIntensity() == ActivityIntensity.VERY_LOW) { + log.info("Creating average computer user motion factory"); + return FactoryTemplates.createAverageComputerUserMotionFactory(nature); + } else if (Rs2Antiban.getActivityIntensity() == ActivityIntensity.LOW) { + log.info("Creating normal gamer motion factory"); + return FactoryTemplates.createNormalGamerMotionFactory(nature); + } else if (Rs2Antiban.getActivityIntensity() == ActivityIntensity.MODERATE) { + log.info("Creating fast gamer motion factory"); + return FactoryTemplates.createFastGamerMotionFactory(nature); + } else if (Rs2Antiban.getActivityIntensity() == ActivityIntensity.HIGH) { + log.info("Creating fast gamer motion factory"); + return FactoryTemplates.createFastGamerMotionFactory(nature); + } else if (Rs2Antiban.getActivityIntensity() == ActivityIntensity.EXTREME) { + log.info("Creating super fast gamer motion factory"); + return FactoryTemplates.createSuperFastGamerMotionFactory(nature); + } else { + log.info("Default: Creating super fast gamer motion factory"); + return FactoryTemplates.createSuperFastGamerMotionFactory(nature); + } + +// var factory = new MouseMotionFactory(); +// factory.setNature(nature); +// factory.setRandom(random); +// +// var manager = new SpeedManagerImpl(flows); +// factory.setDeviationProvider(new SinusoidalDeviationProvider(15.0)); +// factory.setNoiseProvider(new DefaultNoiseProvider(2.0)); +// factory.getNature().setReactionTimeVariationMs(120); +// manager.setMouseMovementBaseTimeMs(130); +// +// var overshootManager = (DefaultOvershootManager) factory.getOvershootManager(); +// overshootManager.setOvershoots(2); +// factory.setSpeedManager(manager); +// +// return factory; + } + + public void moveOffScreen() { + // 1 in 4 chance of moving off screen + if (random.nextInt(4) == 0) { + // Edges of the screen + int horizontal = random.nextBoolean() ? -1 : client.getCanvasWidth() + 1; + int vertical = random.nextBoolean() ? -1 : client.getCanvasHeight() + 1; + + boolean exitHorizontally = random.nextBoolean(); + if (exitHorizontally) { + moveTo(horizontal, random.nextInt(0, client.getCanvasHeight() + 1)); + } else { + moveTo(random.nextInt(0, client.getCanvasWidth() + 1), vertical); + } + + } + } + + // Move to a random point on the screen + public void moveRandom() { + moveTo(random.nextInt(0, client.getCanvasWidth() + 1), random.nextInt(0, client.getCanvasHeight() + 1)); + } + + private static class SpeedManagerImpl extends DefaultSpeedManager { + private SpeedManagerImpl(Collection flows) { + super(flows); + } + + @Override + public Pair getFlowWithTime(double distance) { + var pair = super.getFlowWithTime(distance); + return new Pair<>(pair.x, pair.y); + } + } + + private static class MouseInfoImpl implements MouseInfoAccessor { + @Override + public Point getMousePosition() { + return Microbot.getMouse().getMousePosition(); + } + } + + private class SystemCallsImpl implements SystemCalls { + @Override + public long currentTimeMillis() { + return System.currentTimeMillis(); + } + + @Override + public void sleep(long time) { + Global.sleep((int) time); + } + + @Override + public Dimension getScreenSize() { + return Microbot.getClient().getCanvas().getSize(); + } + + @Override + public void setMousePosition(int x, int y) { + Microbot.getMouse().move(x, y); + + } + } +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/util/mouse/naturalmouse/api/DeviationProvider.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/util/mouse/naturalmouse/api/DeviationProvider.java new file mode 100644 index 0000000000..e18333c7e2 --- /dev/null +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/util/mouse/naturalmouse/api/DeviationProvider.java @@ -0,0 +1,36 @@ +package net.runelite.client.plugins.microbot.util.mouse.naturalmouse.api; + +import net.runelite.client.plugins.microbot.util.mouse.naturalmouse.support.DoublePoint; + +/** + * Creates arcs or deviation into mouse movement. + *

+ * 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 movements = movementFactory.createMovements(mousePosition); + int overshoots = movements.size() - 1; + while (mousePosition.x != xDest || mousePosition.y != yDest) { + if (movements.isEmpty()) { + // This shouldn't usually happen, but it's possible that somehow we won't end up on the target, + // Then just re-attempt from mouse new position. (There are known JDK bugs, that can cause sending the cursor + // to wrong pixel) + updateMouseInfo(); + movements = movementFactory.createMovements(mousePosition); + } + + MouseMovement movement = movements.removeFirst(); + double distance = movement.distance; + long mouseMovementMs = movement.time; + Flow flow = movement.flow; + double xDistance = movement.xDistance; + double yDistance = movement.yDistance; + + /* Number of steps is calculated from the movement time and limited by minimal amount of steps + (should have at least MIN_STEPS) and distance (shouldn't have more steps than pixels travelled) */ + int steps = (int) Math.ceil(Math.min(distance, Math.max(mouseMovementMs / timeToStepsDivider, minSteps))); + + long startTime = systemCalls.currentTimeMillis(); + long stepTime = (long) (mouseMovementMs / (double) steps); + + updateMouseInfo(); + double simulatedMouseX = mousePosition.x; + double simulatedMouseY = mousePosition.y; + + double deviationMultiplierX = (random.nextDouble() - 0.5) * 2; + double deviationMultiplierY = (random.nextDouble() - 0.5) * 2; + + double completedXDistance = 0; + double completedYDistance = 0; + double noiseX = 0; + double noiseY = 0; + + for (int i = 0; i < steps; i++) { + // All steps take equal amount of time. This is a value from 0...1 describing how far along the process is. + double timeCompletion = i / (double) steps; + + double effectFadeStep = Math.max(i - (steps - effectFadeSteps) + 1, 0); + // value from 0 to 1, when effectFadeSteps remaining steps, starts to decrease to 0 linearly + // This is here so noise and deviation wouldn't add offset to mouse final position, when we need accuracy. + double effectFadeMultiplier = (effectFadeSteps - effectFadeStep) / effectFadeSteps; + + double xStepSize = flow.getStepSize(xDistance, steps, timeCompletion); + double yStepSize = flow.getStepSize(yDistance, steps, timeCompletion); + + completedXDistance += xStepSize; + completedYDistance += yStepSize; + double completedDistance = Math.hypot(completedXDistance, completedYDistance); + double completion = Math.min(1, completedDistance / distance); + + DoublePoint noise = noiseProvider.getNoise(random, xStepSize, yStepSize); + DoublePoint deviation = deviationProvider.getDeviation(distance, completion); + + noiseX += noise.getX(); + noiseY += noise.getY(); + simulatedMouseX += xStepSize; + simulatedMouseY += yStepSize; + + long endTime = startTime + stepTime * (i + 1); + int mousePosX = MathUtil.roundTowards(simulatedMouseX + deviation.getX() * deviationMultiplierX * effectFadeMultiplier + noiseX * effectFadeMultiplier, movement.destX); + + int mousePosY = MathUtil.roundTowards(simulatedMouseY + deviation.getY() * deviationMultiplierY * effectFadeMultiplier + noiseY * effectFadeMultiplier, movement.destY); + + mousePosX = limitByScreenWidth(mousePosX); + mousePosY = limitByScreenHeight(mousePosY); + + systemCalls.setMousePosition(mousePosX, mousePosY); + + // Allow other action to take place or just observe, we'll later compensate by sleeping less. + observer.observe(mousePosX, mousePosY); + + long timeLeft = endTime - systemCalls.currentTimeMillis(); + sleepAround(Math.max(timeLeft, 0), 0); + } + updateMouseInfo(); + + if (mousePosition.x != movement.destX || mousePosition.y != movement.destY) { + // It's possible that mouse is manually moved or for some other reason. + // Let's start next step from pre-calculated location to prevent errors from accumulating. + // But print warning as this is not expected behavior. + systemCalls.setMousePosition(movement.destX, movement.destY); + // Let's wait a bit before getting mouse info. + sleepAround(SLEEP_AFTER_ADJUSTMENT_MS, 0); + updateMouseInfo(); + } + + if (mousePosition.x != xDest || mousePosition.y != yDest) { + // We are dealing with overshoot, let's sleep a bit to simulate human reaction time. + sleepAround(reactionTimeBaseMs, reactionTimeVariationMs); + } + } + } + + private int limitByScreenWidth(int value) { + return Math.max(0, Math.min(screenSize.width - 1, value)); + } + + private int limitByScreenHeight(int value) { + return Math.max(0, Math.min(screenSize.height - 1, value)); + } + + private void sleepAround(long sleepMin, long randomPart) { + long sleepTime = (long) (sleepMin + random.nextDouble() * randomPart); + if (log.isTraceEnabled() && sleepTime > 0) { + updateMouseInfo(); + } + systemCalls.sleep(sleepTime); + } + + private void updateMouseInfo() { + mousePosition = mouseInfo.getMousePosition(); + } + +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/util/mouse/naturalmouse/api/MouseMotionFactory.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/util/mouse/naturalmouse/api/MouseMotionFactory.java new file mode 100644 index 0000000000..b3f134b21e --- /dev/null +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/util/mouse/naturalmouse/api/MouseMotionFactory.java @@ -0,0 +1,200 @@ +package net.runelite.client.plugins.microbot.util.mouse.naturalmouse.api; + +import net.runelite.client.plugins.microbot.util.mouse.naturalmouse.support.DefaultMouseMotionNature; +import net.runelite.client.plugins.microbot.util.mouse.naturalmouse.support.MouseMotionNature; + +import java.util.Random; + +/** + * This class should be used for creating new MouseMotion-s + * The default instance is available via getDefault(), but can create new instance via constructor. + */ +public class MouseMotionFactory { + private static final MouseMotionFactory defaultFactory = new MouseMotionFactory(); + private MouseMotionNature nature; + private Random random = new Random(); + + public MouseMotionFactory(MouseMotionNature nature) { + this.nature = nature; + } + + public MouseMotionFactory() { + this(new DefaultMouseMotionNature()); + } + + /** + * Get the default factory implementation. + * + * @return the factory + */ + public static MouseMotionFactory getDefault() { + return defaultFactory; + } + + /** + * Builds the MouseMotion, which can be executed instantly or saved for later. + * + * @param xDest the end position x-coordinate for the mouse + * @param yDest the end position y-coordinate for the mouse + * @return the MouseMotion which can be executed instantly or saved for later. (Mouse will be moved from its + * current position, not from the position where mouse was during building.) + */ + public MouseMotion build(int xDest, int yDest) { + return new MouseMotion(nature, random, xDest, yDest); + } + + /** + * Start moving the mouse to specified location. Blocks until done. + * + * @param xDest the end position x-coordinate for the mouse + * @param yDest the end position y-coordinate for the mouse + * @throws InterruptedException if something interrupts the thread. + */ + public void move(int xDest, int yDest) throws InterruptedException { + build(xDest, yDest).move(); + } + + /** + * see {@link MouseMotionNature#getSystemCalls()} + * + * @return the systemcalls + */ + public SystemCalls getSystemCalls() { + return nature.getSystemCalls(); + } + + /** + * see {@link MouseMotionNature#setSystemCalls(SystemCalls)} + * + * @param systemCalls the systemcalls + */ + public void setSystemCalls(SystemCalls systemCalls) { + nature.setSystemCalls(systemCalls); + } + + /** + * see {@link MouseMotionNature#getDeviationProvider()} + * + * @return the deviation provider + */ + public DeviationProvider getDeviationProvider() { + return nature.getDeviationProvider(); + } + + /** + * see {@link MouseMotionNature#setDeviationProvider(DeviationProvider)} + * + * @param deviationProvider the deviation provider + */ + public void setDeviationProvider(DeviationProvider deviationProvider) { + nature.setDeviationProvider(deviationProvider); + } + + /** + * see {@link MouseMotionNature#getNoiseProvider()} + * + * @return the noise provider + */ + public NoiseProvider getNoiseProvider() { + return nature.getNoiseProvider(); + } + + /** + * see {@link MouseMotionNature#setNoiseProvider(NoiseProvider)}} + * + * @param noiseProvider the noise provider + */ + public void setNoiseProvider(NoiseProvider noiseProvider) { + nature.setNoiseProvider(noiseProvider); + } + + /** + * Get the random used whenever randomized behavior is needed in MouseMotion + * + * @return the random + */ + public Random getRandom() { + return random; + } + + /** + * Set the random used whenever randomized behavior is needed in MouseMotion + * + * @param random the random + */ + public void setRandom(Random random) { + this.random = random; + } + + /** + * see {@link MouseMotionNature#getMouseInfo()} + * + * @return the mouseInfo + */ + public MouseInfoAccessor getMouseInfo() { + return nature.getMouseInfo(); + } + + /** + * see {@link MouseMotionNature#setMouseInfo(MouseInfoAccessor)} + * + * @param mouseInfo the mouseInfo + */ + public void setMouseInfo(MouseInfoAccessor mouseInfo) { + nature.setMouseInfo(mouseInfo); + } + + /** + * see {@link MouseMotionNature#getSpeedManager()} + * + * @return the manager + */ + public SpeedManager getSpeedManager() { + return nature.getSpeedManager(); + } + + /** + * see {@link MouseMotionNature#setSpeedManager(SpeedManager)} + * + * @param speedManager the manager + */ + public void setSpeedManager(SpeedManager speedManager) { + nature.setSpeedManager(speedManager); + } + + /** + * The Nature of mousemotion covers all aspects how the mouse is moved. + * + * @return the nature + */ + public MouseMotionNature getNature() { + return nature; + } + + /** + * The Nature of mousemotion covers all aspects how the mouse is moved. + * + * @param nature the new nature + */ + public void setNature(MouseMotionNature nature) { + this.nature = nature; + } + + /** + * see {@link MouseMotionNature#getOvershootManager()} + * + * @return the manager + */ + public OvershootManager getOvershootManager() { + return nature.getOvershootManager(); + } + + /** + * see {@link MouseMotionNature#setOvershootManager(OvershootManager)} + * + * @param manager the manager + */ + public void setOvershootManager(OvershootManager manager) { + nature.setOvershootManager(manager); + } +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/util/mouse/naturalmouse/api/MouseMotionObserver.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/util/mouse/naturalmouse/api/MouseMotionObserver.java new file mode 100644 index 0000000000..004ef8e274 --- /dev/null +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/util/mouse/naturalmouse/api/MouseMotionObserver.java @@ -0,0 +1,8 @@ +package net.runelite.client.plugins.microbot.util.mouse.naturalmouse.api; + +/** + * Use to observe mouse movement in MouseMotion + */ +public interface MouseMotionObserver { + void observe(int xPos, int yPos); +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/util/mouse/naturalmouse/api/NoiseProvider.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/util/mouse/naturalmouse/api/NoiseProvider.java new file mode 100644 index 0000000000..89ca8c861b --- /dev/null +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/util/mouse/naturalmouse/api/NoiseProvider.java @@ -0,0 +1,36 @@ +package net.runelite.client.plugins.microbot.util.mouse.naturalmouse.api; + +import net.runelite.client.plugins.microbot.util.mouse.naturalmouse.support.DoublePoint; + +import java.util.Random; + +/** + * Provides noise or mistakes in the mouse movement + *

+ * 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 getFlowWithTime(double distance); +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/util/mouse/naturalmouse/api/SystemCalls.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/util/mouse/naturalmouse/api/SystemCalls.java new file mode 100644 index 0000000000..7031ef3278 --- /dev/null +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/util/mouse/naturalmouse/api/SystemCalls.java @@ -0,0 +1,16 @@ +package net.runelite.client.plugins.microbot.util.mouse.naturalmouse.api; + +import java.awt.*; + +/** + * Abstracts ordinary static System calls away + */ +public interface SystemCalls { + long currentTimeMillis(); + + void sleep(long time); + + Dimension getScreenSize(); + + void setMousePosition(int x, int y); +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/util/mouse/naturalmouse/support/DefaultMouseInfoAccessor.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/util/mouse/naturalmouse/support/DefaultMouseInfoAccessor.java new file mode 100644 index 0000000000..cac1fb8ef9 --- /dev/null +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/util/mouse/naturalmouse/support/DefaultMouseInfoAccessor.java @@ -0,0 +1,13 @@ +package net.runelite.client.plugins.microbot.util.mouse.naturalmouse.support; + +import net.runelite.client.plugins.microbot.util.mouse.naturalmouse.api.MouseInfoAccessor; + +import java.awt.*; + +public class DefaultMouseInfoAccessor implements MouseInfoAccessor { + + @Override + public Point getMousePosition() { + return MouseInfo.getPointerInfo().getLocation(); + } +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/util/mouse/naturalmouse/support/DefaultMouseMotionNature.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/util/mouse/naturalmouse/support/DefaultMouseMotionNature.java new file mode 100644 index 0000000000..56fc48cec2 --- /dev/null +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/util/mouse/naturalmouse/support/DefaultMouseMotionNature.java @@ -0,0 +1,36 @@ +package net.runelite.client.plugins.microbot.util.mouse.naturalmouse.support; + +import java.awt.*; +import java.util.Random; + +import static net.runelite.client.plugins.microbot.util.mouse.naturalmouse.support.DefaultNoiseProvider.DEFAULT_NOISINESS_DIVIDER; +import static net.runelite.client.plugins.microbot.util.mouse.naturalmouse.support.SinusoidalDeviationProvider.DEFAULT_SLOPE_DIVIDER; + + +public class DefaultMouseMotionNature extends MouseMotionNature { + + public static final int TIME_TO_STEPS_DIVIDER = 8; + public static final int MIN_STEPS = 10; + public static final int EFFECT_FADE_STEPS = 15; + public static final int REACTION_TIME_BASE_MS = 20; + public static final int REACTION_TIME_VARIATION_MS = 120; + + public DefaultMouseMotionNature() { + try { + setSystemCalls(new DefaultSystemCalls(new Robot())); + } catch (AWTException e) { + throw new RuntimeException(e); + } + + setDeviationProvider(new SinusoidalDeviationProvider(DEFAULT_SLOPE_DIVIDER)); + setNoiseProvider(new DefaultNoiseProvider(DEFAULT_NOISINESS_DIVIDER)); + setSpeedManager(new DefaultSpeedManager()); + setOvershootManager(new DefaultOvershootManager(new Random())); + setEffectFadeSteps(EFFECT_FADE_STEPS); + setMinSteps(MIN_STEPS); + setMouseInfo(new DefaultMouseInfoAccessor()); + setReactionTimeBaseMs(REACTION_TIME_BASE_MS); + setReactionTimeVariationMs(REACTION_TIME_VARIATION_MS); + setTimeToStepsDivider(TIME_TO_STEPS_DIVIDER); + } +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/util/mouse/naturalmouse/support/DefaultNoiseProvider.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/util/mouse/naturalmouse/support/DefaultNoiseProvider.java new file mode 100644 index 0000000000..a58d682479 --- /dev/null +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/util/mouse/naturalmouse/support/DefaultNoiseProvider.java @@ -0,0 +1,34 @@ +package net.runelite.client.plugins.microbot.util.mouse.naturalmouse.support; + +import net.runelite.client.plugins.microbot.util.mouse.naturalmouse.api.NoiseProvider; + +import java.util.Random; + +public class DefaultNoiseProvider implements NoiseProvider { + public static final double DEFAULT_NOISINESS_DIVIDER = 2; + private static final double SMALL_DELTA = 10e-6; + private final double noisinessDivider; + + /** + * @param noisinessDivider bigger value means less noise. + */ + public DefaultNoiseProvider(double noisinessDivider) { + this.noisinessDivider = noisinessDivider; + } + + @Override + public DoublePoint getNoise(Random random, double xStepSize, double yStepSize) { + if (Math.abs(xStepSize - 0) < SMALL_DELTA && Math.abs(yStepSize - 0) < SMALL_DELTA) { + return DoublePoint.ZERO; + } + double noiseX = 0; + double noiseY = 0; + double stepSize = Math.hypot(xStepSize, yStepSize); + double noisiness = Math.max(0, (8 - stepSize)) / 50; + if (random.nextDouble() < noisiness) { + noiseX = (random.nextDouble() - 0.5) * Math.max(0, (8 - stepSize)) / noisinessDivider; + noiseY = (random.nextDouble() - 0.5) * Math.max(0, (8 - stepSize)) / noisinessDivider; + } + return new DoublePoint(noiseX, noiseY); + } +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/util/mouse/naturalmouse/support/DefaultOvershootManager.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/util/mouse/naturalmouse/support/DefaultOvershootManager.java new file mode 100644 index 0000000000..5e1eabeb7e --- /dev/null +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/util/mouse/naturalmouse/support/DefaultOvershootManager.java @@ -0,0 +1,89 @@ +package net.runelite.client.plugins.microbot.util.mouse.naturalmouse.support; + + +import net.runelite.client.plugins.microbot.util.mouse.naturalmouse.api.OvershootManager; + +import java.awt.*; +import java.util.Random; + +public class DefaultOvershootManager implements OvershootManager { + public static final double OVERSHOOT_SPEEDUP_DIVIDER = 1.8; + public static final int MIN_OVERSHOOT_MOVEMENT_MS = 40; + public static final int OVERSHOOT_RANDOM_MODIFIER_DIVIDER = 20; + public static final int MIN_DISTANCE_FOR_OVERSHOOTS = 10; + public static final int DEFAULT_OVERSHOOT_AMOUNT = 3; + private final Random random; + private long minOvershootMovementMs = MIN_OVERSHOOT_MOVEMENT_MS; + private long minDistanceForOvershoots = MIN_DISTANCE_FOR_OVERSHOOTS; + private double overshootRandomModifierDivider = OVERSHOOT_RANDOM_MODIFIER_DIVIDER; + private double overshootSpeedupDivider = OVERSHOOT_SPEEDUP_DIVIDER; + private int overshoots = DEFAULT_OVERSHOOT_AMOUNT; + + public DefaultOvershootManager(Random random) { + this.random = random; + } + + @Override + public int getOvershoots(Flow flow, long mouseMovementMs, double distance) { + if (distance < minDistanceForOvershoots) { + return 0; + } + return overshoots; + } + + @Override + public Point getOvershootAmount(double distanceToRealTargetX, double distanceToRealTargetY, long mouseMovementMs, int overshootsRemaining) { + double distanceToRealTarget = Math.hypot(distanceToRealTargetX, distanceToRealTargetY); + + double randomModifier = distanceToRealTarget / overshootRandomModifierDivider; + //double speedPixelsPerSecond = distanceToRealTarget / mouseMovementMs * 1000; // TODO utilize speed + int x = (int) (random.nextDouble() * randomModifier - randomModifier / 2d) * overshootsRemaining; + int y = (int) (random.nextDouble() * randomModifier - randomModifier / 2d) * overshootsRemaining; + return new Point(x, y); + } + + @Override + public long deriveNextMouseMovementTimeMs(long mouseMovementMs, int overshootsRemaining) { + return Math.max((long) (mouseMovementMs / overshootSpeedupDivider), minOvershootMovementMs); + } + + public long getMinOvershootMovementMs() { + return minOvershootMovementMs; + } + + public void setMinOvershootMovementMs(long minOvershootMovementMs) { + this.minOvershootMovementMs = minOvershootMovementMs; + } + + public double getOvershootRandomModifierDivider() { + return overshootRandomModifierDivider; + } + + public void setOvershootRandomModifierDivider(double overshootRandomModifierDivider) { + this.overshootRandomModifierDivider = overshootRandomModifierDivider; + } + + public double getOvershootSpeedupDivider() { + return overshootSpeedupDivider; + } + + public void setOvershootSpeedupDivider(double overshootSpeedupDivider) { + this.overshootSpeedupDivider = overshootSpeedupDivider; + } + + public int getOvershoots() { + return overshoots; + } + + public void setOvershoots(int overshoots) { + this.overshoots = overshoots; + } + + public long getMinDistanceForOvershoots() { + return minDistanceForOvershoots; + } + + public void setMinDistanceForOvershoots(long minDistanceForOvershoots) { + this.minDistanceForOvershoots = minDistanceForOvershoots; + } +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/util/mouse/naturalmouse/support/DefaultSpeedManager.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/util/mouse/naturalmouse/support/DefaultSpeedManager.java new file mode 100644 index 0000000000..bd4e431d59 --- /dev/null +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/util/mouse/naturalmouse/support/DefaultSpeedManager.java @@ -0,0 +1,56 @@ +package net.runelite.client.plugins.microbot.util.mouse.naturalmouse.support; + + +import net.runelite.client.plugins.microbot.util.mouse.naturalmouse.api.SpeedManager; +import net.runelite.client.plugins.microbot.util.mouse.naturalmouse.util.FlowTemplates; +import net.runelite.client.plugins.microbot.util.mouse.naturalmouse.util.Pair; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.List; + +public class DefaultSpeedManager implements SpeedManager { + private static final double SMALL_DELTA = 10e-6; + private final List flows = new ArrayList<>(); + private long mouseMovementTimeMs = 500; + + public DefaultSpeedManager(Collection flows) { + this.flows.addAll(flows); + } + + public DefaultSpeedManager() { + this(Arrays.asList( + new Flow(FlowTemplates.constantSpeed()), + new Flow(FlowTemplates.variatingFlow()), + new Flow(FlowTemplates.interruptedFlow()), + new Flow(FlowTemplates.interruptedFlow2()), + new Flow(FlowTemplates.slowStartupFlow()), + new Flow(FlowTemplates.slowStartup2Flow()), + new Flow(FlowTemplates.adjustingFlow()), + new Flow(FlowTemplates.jaggedFlow()), + new Flow(FlowTemplates.stoppingFlow()) + )); + } + + @Override + public Pair getFlowWithTime(double distance) { + double time = mouseMovementTimeMs + (long) (Math.random() * mouseMovementTimeMs); + Flow flow = flows.get((int) (Math.random() * flows.size())); + + // Let's ignore waiting time, e.g 0's in flow, by increasing the total time + // by the amount of 0's there are in the flow multiplied by the time each bucket represents. + double timePerBucket = time / (double) flow.getFlowCharacteristics().length; + for (double bucket : flow.getFlowCharacteristics()) { + if (Math.abs(bucket - 0) < SMALL_DELTA) { + time += timePerBucket; + } + } + + return new Pair<>(flow, (long) time); + } + + public void setMouseMovementBaseTimeMs(long mouseMovementSpeedMs) { + this.mouseMovementTimeMs = mouseMovementSpeedMs; + } +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/util/mouse/naturalmouse/support/DefaultSystemCalls.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/util/mouse/naturalmouse/support/DefaultSystemCalls.java new file mode 100644 index 0000000000..98ce5a2aa6 --- /dev/null +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/util/mouse/naturalmouse/support/DefaultSystemCalls.java @@ -0,0 +1,49 @@ +package net.runelite.client.plugins.microbot.util.mouse.naturalmouse.support; + + +import net.runelite.client.plugins.microbot.util.Global; +import net.runelite.client.plugins.microbot.util.mouse.naturalmouse.api.SystemCalls; + +import java.awt.*; + +public class DefaultSystemCalls implements SystemCalls { + private final Robot robot; + + public DefaultSystemCalls(Robot robot) { + this.robot = robot; + } + + @Override + public long currentTimeMillis() { + return System.currentTimeMillis(); + } + + @Override + public void sleep(long time) { + Global.sleep((int) time); + } + + @Override + public Dimension getScreenSize() { + return Toolkit.getDefaultToolkit().getScreenSize(); + } + + /** + *

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.)

+ * + * @param x the x-coordinate + * @param y the y-coordinate + */ + @Override + public void setMousePosition(int x, int y) { + robot.mouseMove(x, y); + } +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/util/mouse/naturalmouse/support/DoublePoint.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/util/mouse/naturalmouse/support/DoublePoint.java new file mode 100644 index 0000000000..26185336ce --- /dev/null +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/util/mouse/naturalmouse/support/DoublePoint.java @@ -0,0 +1,20 @@ +package net.runelite.client.plugins.microbot.util.mouse.naturalmouse.support; + +public class DoublePoint { + public final static DoublePoint ZERO = new DoublePoint(0, 0); + private final double x; + private final double y; + + public DoublePoint(double x, double y) { + this.x = x; + this.y = y; + } + + public double getX() { + return x; + } + + public double getY() { + return y; + } +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/util/mouse/naturalmouse/support/Flow.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/util/mouse/naturalmouse/support/Flow.java new file mode 100644 index 0000000000..ff36094938 --- /dev/null +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/util/mouse/naturalmouse/support/Flow.java @@ -0,0 +1,121 @@ +package net.runelite.client.plugins.microbot.util.mouse.naturalmouse.support; + +/** + * Flow for the mouse movement + * Flow defines how slow or fast the cursor is moving at a particular moment, defining the characteristics + * of movement itself not the trajectory, but how jagged or smooth, accelerating or decelerating, the movement is. + */ +public class Flow { + private static final int AVERAGE_BUCKET_VALUE = 100; + + private final double[] buckets; + + /** + * @param characteristics the characteristics array, which can be any size, contain non-negative numbers. + * The values in the array are translated to flow and all values are relative. For example an + * array of [1,2,3,4] has the same meaning as [100, 200, 300, 400] or [10, 10, 20, 20, 30, 30, 40, 40] + * Every array element describes a time of the movement, so that in array of n-elements every element is + * describing (100 / n)% of the movement. In an array of [1,2,3,4] every element is responsible for + * 25% of time and the movement is accelerating - in the last 25% of time the mouse cursor is 4 times faster + * than it was in the first 25% of the time. + */ + public Flow(double[] characteristics) { + buckets = normalizeBuckets(characteristics); + } + + /** + * Normalizes the characteristics to have an average of AVERAGE_BUCKET_VALUE + * + * @param flowCharacteristics an array of values which describe how the mouse should move at each moment + * @return the normalized bucket array + */ + private double[] normalizeBuckets(double[] flowCharacteristics) { + double[] buckets = new double[flowCharacteristics.length]; + long sum = 0; + for (int i = 0; i < flowCharacteristics.length; i++) { + if (flowCharacteristics[i] < 0) { + throw new IllegalArgumentException("Invalid FlowCharacteristics at [" + i + "] : " + flowCharacteristics[i]); + } + sum += flowCharacteristics[i]; + } + + if (sum == 0) { + throw new IllegalArgumentException("Invalid FlowCharacteristics. All array elements can't be 0."); + } + /* + * By multiplying AVERAGE_BUCKET_VALUE to buckets.length we get a required fill for the buckets, + * For example if there are 5 buckets then 100 * 5 gives us 500, which is how much the buckets should + * contain on total ideally. Then we divide it by the sum which we got from adding all contents of characteristics + * array together. The resulting value describes the FlowCharacteristics array and how much is missing or + * overfilled in it. for example when we get 0.5, then we know it contains twice as much as our normalized + * buckets array should have and we multiply all characteristics values by 0.5, this preserves the + * characteristics, but reduces the values to levels our algorithm knows how to work with. + */ + double multiplier = (double) AVERAGE_BUCKET_VALUE * buckets.length / sum; + for (int i = 0; i < flowCharacteristics.length; i++) { + buckets[i] = flowCharacteristics[i] * multiplier; + } + return buckets; + } + + public double[] getFlowCharacteristics() { + return buckets; + } + + /** + * This returns step size for a single axis. + * + * @param distance the total distance current movement has on current axis from beginning to target in pixels + * @param steps number of steps the current movement involves + * @param completion value between 0 and 1, the value describes movement completion in time + * @return the step size which should be taken next + */ + public double getStepSize(double distance, int steps, double completion) { + // This is essentially how big is a single completion step, + // so we can expect next 'completion' is current completion + completionStep + double completionStep = 1d / steps; + // Define the first bucket we read from + double bucketFrom = (completion * buckets.length); + // Define the last bucket we read from + double bucketUntil = ((completion + completionStep) * buckets.length); + + double bucketContents = getBucketsContents(bucketFrom, bucketUntil); + // This shows how much distance is assigned to single contents value in the buckets. + // For example if this gets assigned to 0.4, then for every value in the bucket + // the cursor needs to travel 0.4 pixels, so for a bucket containing 50, the mouse + // travelling distance is 0.4 * 50 = 20pixels + double distancePerBucketContent = distance / (buckets.length * AVERAGE_BUCKET_VALUE); + + return bucketContents * distancePerBucketContent; + } + + /** + * Summarizes the bucket contents from bucketFrom to bucketUntil, where + * provided parameters may have decimal places. In that case the value + * from first or last bucket is just a fragment of it's full value, depending how + * large portion the decimal place contains. For example getBucketContents(0.6, 2.4) + * returns 0.4 * bucket[0] + 1 * bucket[1] + 0.4 * bucket[2] + * + * @param bucketFrom bucket from where to start reading + * @param bucketUntil bucket where to read + * @return the sum of the contents in the buckets + */ + private double getBucketsContents(double bucketFrom, double bucketUntil) { + double sum = 0; + for (int i = (int) bucketFrom; i < bucketUntil; i++) { + double value = buckets[i]; + double endMultiplier = 1; + double startMultiplier = 0; + if (bucketUntil < i + 1) { + endMultiplier = bucketUntil - (int) bucketUntil; + } + if ((int) bucketFrom == i) { + startMultiplier = bucketFrom - (int) bucketFrom; + } + value *= endMultiplier - startMultiplier; + sum += value; + } + + return sum; + } +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/util/mouse/naturalmouse/support/MouseMotionNature.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/util/mouse/naturalmouse/support/MouseMotionNature.java new file mode 100644 index 0000000000..a2686812c8 --- /dev/null +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/util/mouse/naturalmouse/support/MouseMotionNature.java @@ -0,0 +1,238 @@ +package net.runelite.client.plugins.microbot.util.mouse.naturalmouse.support; + +import net.runelite.client.plugins.microbot.util.mouse.naturalmouse.api.*; + +public class MouseMotionNature { + private double timeToStepsDivider; + private int minSteps; + + private int effectFadeSteps; + private int reactionTimeBaseMs; + private int reactionTimeVariationMs; + private DeviationProvider deviationProvider; + private NoiseProvider noiseProvider; + private OvershootManager overshootManager; + private MouseInfoAccessor mouseInfo; + private SystemCalls systemCalls; + private SpeedManager speedManager; + + /** + * Time to steps is how NaturalMouseMotion calculates how many locations need to be visited between + * start and end point. More steps means more smooth movement. Thus increasing this divider means less + * steps and decreasing means more steps. + * + * @return the divider which is used to get amount of steps from the planned movement time + */ + public double getTimeToStepsDivider() { + return timeToStepsDivider; + } + + /** + * Time to steps is how NaturalMouseMotion calculates how many locations need to be visited between + * start and end point. More steps means more smooth movement. Thus increasing this divider means less + * steps and decreasing means more steps. The default value should be as smooth as needed for any real + * purpose. So unless this really is the issue, you shouldn't touch this value. + * + * @param timeToStepsDivider the divider which is used to get amount of steps from the planned movement time + */ + public void setTimeToStepsDivider(double timeToStepsDivider) { + this.timeToStepsDivider = timeToStepsDivider; + } + + /** + * Minimum amount of steps that is taken to reach the target, this is used when calculation otherwise would + * lead to too few steps for smooth mouse movement, which can happen for very fast movements. + * + * @return the minimal amount of steps used. + */ + public int getMinSteps() { + return minSteps; + } + + /** + * Minimum amount of steps that is taken to reach the target, this is used when calculation otherwise would + * lead to too few steps for smooth mouse movement, which can happen for very fast movements. + * The default value should cover your needs, usually no need to touch this. + * + * @param minSteps the minimal amount of steps used + */ + public void setMinSteps(int minSteps) { + this.minSteps = minSteps; + } + + /** + * Effect fade decreases the noise and deviation effects linearly to 0 at the end of the mouse movement, + * so mouse would end up in the intended target pixel even when noise or deviation would otherwise + * add offset to mouse position. + * + * @return the number of steps before last the effect starts to fade + */ + public int getEffectFadeSteps() { + return effectFadeSteps; + } + + /** + * Effect fade decreases the noise and deviation effects linearly to 0 at the end of the mouse movement, + * so mouse would end up in the intended target pixel even when noise or deviation would otherwise + * add offset to mouse position. + * + * @param effectFadeSteps the number of steps before last the effect starts to fade + */ + public void setEffectFadeSteps(int effectFadeSteps) { + this.effectFadeSteps = effectFadeSteps; + } + + /** + * Get the minimal sleep time when overshoot or some other feature has caused mouse to miss the original target + * to prepare for next attempt to move the mouse to target. + * + * @return the sleep time + */ + public int getReactionTimeBaseMs() { + return reactionTimeBaseMs; + } + + /** + * Set the minimal sleep time when overshoot or some other feature has caused mouse to miss the original target + * to prepare for next attempt to move the mouse to target. + * + * @param reactionTimeBaseMs the sleep time + */ + public void setReactionTimeBaseMs(int reactionTimeBaseMs) { + this.reactionTimeBaseMs = reactionTimeBaseMs; + } + + /** + * Get the random sleep time when overshoot or some other feature has caused mouse to miss the original target + * to prepare for next attempt to move the mouse to target. Random part of this is added to the reactionTimeBaseMs. + * + * @return reactionTimeVariationMs the sleep time + */ + public int getReactionTimeVariationMs() { + return reactionTimeVariationMs; + } + + /** + * Set the random sleep time when overshoot or some other feature has caused mouse to miss the original target + * to prepare for next attempt to move the mouse to target. Random part of this is added to the reactionTimeBaseMs. + * + * @param reactionTimeVariationMs the sleep time + */ + public void setReactionTimeVariationMs(int reactionTimeVariationMs) { + this.reactionTimeVariationMs = reactionTimeVariationMs; + } + + /** + * Get the provider which is used to define how the MouseMotion trajectory is being deviated or arced + * + * @return the provider + */ + public DeviationProvider getDeviationProvider() { + return deviationProvider; + } + + /** + * Set the provider which is used to define how the MouseMotion trajectory is being deviated or arced. + * Alters the underlying nature instance in this factory. + * + * @param deviationProvider the provider + */ + public void setDeviationProvider(DeviationProvider deviationProvider) { + this.deviationProvider = deviationProvider; + } + + /** + * Get the provider which is used to make random mistakes in the trajectory of the moving mouse + * + * @return the provider + */ + public NoiseProvider getNoiseProvider() { + return noiseProvider; + } + + /** + * set the provider which is used to make random mistakes in the trajectory of the moving mouse. + * Alters the underlying nature instance in this factory. + * + * @param noiseProvider the provider + */ + public void setNoiseProvider(NoiseProvider noiseProvider) { + this.noiseProvider = noiseProvider; + } + + /** + * Get the accessor object, which MouseMotion uses to detect the position of mouse on screen. + * + * @return the accessor + */ + public MouseInfoAccessor getMouseInfo() { + return mouseInfo; + } + + /** + * Set the accessor object, which MouseMotion uses to detect the position of mouse on screen. + * + * @param mouseInfo the accessor object + */ + public void setMouseInfo(MouseInfoAccessor mouseInfo) { + this.mouseInfo = mouseInfo; + } + + /** + * Get a system call interface, which MouseMotion uses internally + * + * @return the interface + */ + public SystemCalls getSystemCalls() { + return systemCalls; + } + + /** + * Set a system call interface, which MouseMotion uses internally. + * + * @param systemCalls the interface + */ + public void setSystemCalls(SystemCalls systemCalls) { + this.systemCalls = systemCalls; + } + + /** + * Get the speed manager. SpeedManager controls how long does it take to complete a movement and within that + * time how slow or fast the cursor is moving at a particular moment, the flow of movement. + * + * @return the SpeedManager + */ + public SpeedManager getSpeedManager() { + return speedManager; + } + + /** + * Sets the speed manager. SpeedManager controls how long does it take to complete a movement and within that + * time how slow or fast the cursor is moving at a particular moment, the flow of movement. + * + * @param speedManager the SpeedManager + */ + public void setSpeedManager(SpeedManager speedManager) { + this.speedManager = speedManager; + } + + /** + * Get the manager that deals with overshoot properties. + * Overshoots provide a realistic way to simulate user trying to reach the destination with mouse, but miss. + * + * @return the manager + */ + public OvershootManager getOvershootManager() { + return overshootManager; + } + + /** + * Set the manager that deals with overshoot properties. + * Overshoots provide a realistic way to simulate user trying to reach the destination with mouse, but miss. + * + * @param overshootManager the manager + */ + public void setOvershootManager(OvershootManager overshootManager) { + this.overshootManager = overshootManager; + } +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/util/mouse/naturalmouse/support/ScreenAdjustedNature.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/util/mouse/naturalmouse/support/ScreenAdjustedNature.java new file mode 100644 index 0000000000..e7825a600d --- /dev/null +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/util/mouse/naturalmouse/support/ScreenAdjustedNature.java @@ -0,0 +1,83 @@ +package net.runelite.client.plugins.microbot.util.mouse.naturalmouse.support; + + +import net.runelite.client.plugins.microbot.util.mouse.naturalmouse.api.MouseInfoAccessor; +import net.runelite.client.plugins.microbot.util.mouse.naturalmouse.api.SystemCalls; + +import java.awt.*; + +/** + * This nature translates mouse coordinates to specified offset and screen dimension. + * Internally it wraps the SystemCalls and MouseInfoAccessor in proxies which handle the translations. + */ +public class ScreenAdjustedNature extends DefaultMouseMotionNature { + private final Point offset; + private final Dimension screenSize; + + public ScreenAdjustedNature(int x, int y, int x2, int y2) { + this(new Dimension(x2 - x, y2 - y), new Point(x, y)); + if (y2 <= y || x2 <= x) { + throw new IllegalArgumentException("Invalid range " + x + " " + y + " " + x2 + " " + y2); + } + } + + public ScreenAdjustedNature(Dimension screenSize, Point mouseOffset) { + this.screenSize = screenSize; + this.offset = mouseOffset; + } + + @Override + public void setMouseInfo(MouseInfoAccessor mouseInfo) { + super.setMouseInfo(new ProxyMouseInfo(mouseInfo)); + } + + @Override + public void setSystemCalls(SystemCalls systemCalls) { + super.setSystemCalls(new ProxySystemCalls(systemCalls)); + } + + private class ProxyMouseInfo implements MouseInfoAccessor { + private final MouseInfoAccessor underlying; + // This implementation reuses the point. + private final Point p = new Point(); + + public ProxyMouseInfo(MouseInfoAccessor underlying) { + this.underlying = underlying; + } + + @Override + public Point getMousePosition() { + Point realPointer = underlying.getMousePosition(); + p.setLocation(realPointer.x - offset.x, realPointer.y - offset.y); + return p; + } + } + + private class ProxySystemCalls implements SystemCalls { + private final SystemCalls underlying; + + public ProxySystemCalls(SystemCalls underlying) { + this.underlying = underlying; + } + + @Override + public long currentTimeMillis() { + return underlying.currentTimeMillis(); + } + + @Override + public void sleep(long time) { + underlying.sleep(time); + } + + @Override + public Dimension getScreenSize() { + return screenSize; + } + + @Override + public void setMousePosition(int x, int y) { + underlying.setMousePosition(x + offset.x, y + offset.y); + } + } +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/util/mouse/naturalmouse/support/SinusoidalDeviationProvider.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/util/mouse/naturalmouse/support/SinusoidalDeviationProvider.java new file mode 100644 index 0000000000..ef034cb16f --- /dev/null +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/util/mouse/naturalmouse/support/SinusoidalDeviationProvider.java @@ -0,0 +1,23 @@ +package net.runelite.client.plugins.microbot.util.mouse.naturalmouse.support; + + +import net.runelite.client.plugins.microbot.util.mouse.naturalmouse.api.DeviationProvider; + +public class SinusoidalDeviationProvider implements DeviationProvider { + public static final int DEFAULT_SLOPE_DIVIDER = 10; + private final double slopeDivider; + + public SinusoidalDeviationProvider(double slopeDivider) { + this.slopeDivider = slopeDivider; + } + + @Override + public DoublePoint getDeviation(double totalDistanceInPixels, double completionFraction) { + double deviationFunctionResult = (1 - Math.cos(completionFraction * Math.PI * 2)) / 2; + + double deviationX = totalDistanceInPixels / slopeDivider; + double deviationY = totalDistanceInPixels / slopeDivider; + + return new DoublePoint(deviationFunctionResult * deviationX, deviationFunctionResult * deviationY); + } +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/util/mouse/naturalmouse/support/mousemotion/MouseMovement.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/util/mouse/naturalmouse/support/mousemotion/MouseMovement.java new file mode 100644 index 0000000000..898e3ce620 --- /dev/null +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/util/mouse/naturalmouse/support/mousemotion/MouseMovement.java @@ -0,0 +1,34 @@ +package net.runelite.client.plugins.microbot.util.mouse.naturalmouse.support.mousemotion; + +import net.runelite.client.plugins.microbot.util.mouse.naturalmouse.support.Flow; + +public class MouseMovement { + public final int destX; + public final int destY; + public final double distance; + public final int xDistance; + public final int yDistance; + public final long time; + public final Flow flow; + + public MouseMovement(int destX, int destY, double distance, int xDistance, int yDistance, long time, Flow flow) { + this.destX = destX; + this.destY = destY; + this.distance = distance; + this.xDistance = xDistance; + this.yDistance = yDistance; + this.time = time; + this.flow = flow; + } + + @Override + public String toString() { + return "Movement{" + + "destX=" + destX + + ", destY=" + destY + + ", xDistance=" + xDistance + + ", yDistance=" + yDistance + + ", time=" + time + + '}'; + } +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/util/mouse/naturalmouse/support/mousemotion/MovementFactory.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/util/mouse/naturalmouse/support/mousemotion/MovementFactory.java new file mode 100644 index 0000000000..9c2803e429 --- /dev/null +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/util/mouse/naturalmouse/support/mousemotion/MovementFactory.java @@ -0,0 +1,105 @@ +package net.runelite.client.plugins.microbot.util.mouse.naturalmouse.support.mousemotion; + +import net.runelite.client.plugins.microbot.util.mouse.naturalmouse.api.OvershootManager; +import net.runelite.client.plugins.microbot.util.mouse.naturalmouse.api.SpeedManager; +import net.runelite.client.plugins.microbot.util.mouse.naturalmouse.support.Flow; +import net.runelite.client.plugins.microbot.util.mouse.naturalmouse.util.Pair; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.awt.*; +import java.util.ArrayDeque; +import java.util.Iterator; + +public class MovementFactory { + private static final Logger log = LoggerFactory.getLogger(MovementFactory.class); + private final int xDest; + private final int yDest; + private final SpeedManager speedManager; + private final OvershootManager overshootManager; + private final Dimension screenSize; + + public MovementFactory(int xDest, int yDest, SpeedManager speedManager, + OvershootManager overshootManager, Dimension screenSize) { + this.xDest = xDest; + this.yDest = yDest; + this.speedManager = speedManager; + this.overshootManager = overshootManager; + this.screenSize = screenSize; + } + + public ArrayDeque createMovements(Point currentMousePosition) { + ArrayDeque movements = new ArrayDeque<>(); + int lastMousePositionX = currentMousePosition.x; + int lastMousePositionY = currentMousePosition.y; + int xDistance = xDest - lastMousePositionX; + int yDistance = yDest - lastMousePositionY; + + double initialDistance = Math.hypot(xDistance, yDistance); + Pair flowTime = speedManager.getFlowWithTime(initialDistance); + Flow flow = flowTime.x; + long mouseMovementMs = flowTime.y; + int overshoots = overshootManager.getOvershoots(flow, mouseMovementMs, initialDistance); + + if (overshoots == 0) { + movements.add(new MouseMovement(xDest, yDest, initialDistance, xDistance, yDistance, mouseMovementMs, flow)); + return movements; + } + + for (int i = overshoots; i > 0; i--) { + Point overshoot = overshootManager.getOvershootAmount( + xDest - lastMousePositionX, yDest - lastMousePositionY, mouseMovementMs, i + ); + int currentDestinationX = limitByScreenWidth(xDest + overshoot.x); + int currentDestinationY = limitByScreenHeight(yDest + overshoot.y); + xDistance = currentDestinationX - lastMousePositionX; + yDistance = currentDestinationY - lastMousePositionY; + double distance = Math.hypot(xDistance, yDistance); + flow = speedManager.getFlowWithTime(distance).x; + movements.add( + new MouseMovement(currentDestinationX, currentDestinationY, distance, xDistance, yDistance, mouseMovementMs, flow) + ); + lastMousePositionX = currentDestinationX; + lastMousePositionY = currentDestinationY; + // Apply for the next overshoot if exists. + mouseMovementMs = overshootManager.deriveNextMouseMovementTimeMs(mouseMovementMs, i - 1); + } + + Iterator it = movements.descendingIterator(); + + boolean remove = true; + // Remove overshoots from the end, which are matching the final destination, but keep those in middle of motion. + while (it.hasNext() && remove) { + MouseMovement movement = it.next(); + if (movement.destX == xDest && movement.destY == yDest) { + lastMousePositionX = movement.destX - movement.xDistance; + lastMousePositionY = movement.destY - movement.yDistance; + it.remove(); + } else { + remove = false; + } + } + + xDistance = xDest - lastMousePositionX; + yDistance = yDest - lastMousePositionY; + double distance = Math.hypot(xDistance, yDistance); + Pair movementToTargetFlowTime = speedManager.getFlowWithTime(distance); + long finalMovementTime = overshootManager.deriveNextMouseMovementTimeMs(movementToTargetFlowTime.y, 0); + MouseMovement finalMove = new MouseMovement( + xDest, yDest, distance, xDistance, yDistance, finalMovementTime, movementToTargetFlowTime.x + ); + movements.add(finalMove); + + return movements; + } + + private int limitByScreenWidth(int value) { + return Math.max(0, Math.min(screenSize.width - 1, value)); + } + + private int limitByScreenHeight(int value) { + return Math.max(0, Math.min(screenSize.height - 1, value)); + } + + +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/util/mouse/naturalmouse/tools/SystemDiagnosis.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/util/mouse/naturalmouse/tools/SystemDiagnosis.java new file mode 100644 index 0000000000..ab8820a244 --- /dev/null +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/util/mouse/naturalmouse/tools/SystemDiagnosis.java @@ -0,0 +1,60 @@ +package net.runelite.client.plugins.microbot.util.mouse.naturalmouse.tools; + + +import net.runelite.client.plugins.microbot.util.mouse.naturalmouse.api.MouseInfoAccessor; +import net.runelite.client.plugins.microbot.util.mouse.naturalmouse.api.SystemCalls; +import net.runelite.client.plugins.microbot.util.mouse.naturalmouse.support.DefaultMouseInfoAccessor; +import net.runelite.client.plugins.microbot.util.mouse.naturalmouse.support.DefaultSystemCalls; + +import java.awt.*; + +public class SystemDiagnosis { + + /** + * Runs a diagnosis with default configuration, by setting mouse all over your screen and expecting to receive + * correct coordinates back. + * If java.awt.Robot cannot be constructed, then new RuntimeException is thrown. + * If no issues are found, then this method completes without throwing an error, otherwise IllegalStateException is + * thrown. + */ + public static void validateMouseMovement() { + try { + Robot robot = new Robot(); + validateMouseMovement(new DefaultSystemCalls(robot), new DefaultMouseInfoAccessor()); + } catch (AWTException e) { + throw new RuntimeException(e); + } + } + + /** + * Runs a diagnosis, by setting mouse all over your screen and expecting to receive correct coordinates back. + * If no issues are found, then this method completes without throwing an error, otherwise IllegalStateException is + * thrown. + * + * @param system a SystemCalls class which is used for setting the mouse position + * @param accessor a MouseInfoAccessor which is used for querying mouse position + */ + public static void validateMouseMovement(SystemCalls system, MouseInfoAccessor accessor) { + Dimension dimension = system.getScreenSize(); + for (int y = 0; y < dimension.height; y += 50) { + for (int x = 0; x < dimension.width; x += 50) { + system.setMousePosition(x, y); + + try { + Thread.sleep(1); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + } + + Point p = accessor.getMousePosition(); + if (x != p.x || y != p.y) { + throw new IllegalStateException( + "Tried to move mouse to (" + x + ", " + y + "). Actually moved to (" + p.x + ", " + p.y + ")" + + "This means NaturalMouseMotion is not able to work optimally on this system as the cursor move " + + "calls may miss the target pixels on the screen." + ); + } + } + } + } +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/util/mouse/naturalmouse/util/FactoryTemplates.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/util/mouse/naturalmouse/util/FactoryTemplates.java new file mode 100644 index 0000000000..84b18a19a7 --- /dev/null +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/util/mouse/naturalmouse/util/FactoryTemplates.java @@ -0,0 +1,279 @@ +package net.runelite.client.plugins.microbot.util.mouse.naturalmouse.util; + + +import net.runelite.client.plugins.microbot.util.antiban.Rs2Antiban; +import net.runelite.client.plugins.microbot.util.antiban.Rs2AntibanSettings; +import net.runelite.client.plugins.microbot.util.mouse.naturalmouse.api.MouseMotionFactory; +import net.runelite.client.plugins.microbot.util.mouse.naturalmouse.api.SpeedManager; +import net.runelite.client.plugins.microbot.util.mouse.naturalmouse.support.*; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +public class FactoryTemplates { + /** + *

Stereotypical 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); + List flows = new ArrayList<>(Arrays.asList( + new Flow(FlowTemplates.jaggedFlow()), + new Flow(FlowTemplates.random()), + new Flow(FlowTemplates.interruptedFlow()), + new Flow(FlowTemplates.interruptedFlow2()), + new Flow(FlowTemplates.adjustingFlow()), + new Flow(FlowTemplates.stoppingFlow()) + )); + DefaultSpeedManager manager = new DefaultSpeedManager(flows); + factory.setDeviationProvider(new SinusoidalDeviationProvider(9)); + factory.setNoiseProvider(new DefaultNoiseProvider(1.6)); + factory.getNature().setReactionTimeBaseMs(100); + + DefaultOvershootManager overshootManager = (DefaultOvershootManager) factory.getOvershootManager(); + if (Rs2AntibanSettings.simulateMistakes) + overshootManager.setOvershoots(3); + else + overshootManager.setOvershoots(0); + overshootManager.setMinDistanceForOvershoots(3); + overshootManager.setMinOvershootMovementMs(400); + overshootManager.setOvershootRandomModifierDivider(DefaultOvershootManager.OVERSHOOT_RANDOM_MODIFIER_DIVIDER / 2); + overshootManager.setOvershootSpeedupDivider(DefaultOvershootManager.OVERSHOOT_SPEEDUP_DIVIDER * 2); + + factory.getNature().setTimeToStepsDivider(DefaultMouseMotionNature.TIME_TO_STEPS_DIVIDER - 2); + manager.setMouseMovementBaseTimeMs(1000); + factory.setSpeedManager(manager); + return factory; + } + + /** + *

Robotic 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); + List flows = new ArrayList<>(Arrays.asList( + new Flow(FlowTemplates.variatingFlow()), + new Flow(FlowTemplates.slowStartupFlow()), + new Flow(FlowTemplates.slowStartup2Flow()), + new Flow(FlowTemplates.adjustingFlow()), + new Flow(FlowTemplates.jaggedFlow()) + )); + DefaultSpeedManager manager = new DefaultSpeedManager(flows); + factory.setDeviationProvider(new SinusoidalDeviationProvider(SinusoidalDeviationProvider.DEFAULT_SLOPE_DIVIDER)); + factory.setNoiseProvider(new DefaultNoiseProvider(DefaultNoiseProvider.DEFAULT_NOISINESS_DIVIDER)); + factory.getNature().setReactionTimeVariationMs(100); + manager.setMouseMovementBaseTimeMs(currentBaseTime); + + DefaultOvershootManager overshootManager = (DefaultOvershootManager) factory.getOvershootManager(); + if (Rs2AntibanSettings.simulateMistakes) + overshootManager.setOvershoots(4); + else + overshootManager.setOvershoots(0); + overshootManager.setMinDistanceForOvershoots(3); + overshootManager.setMinOvershootMovementMs(250); + + 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 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); + List flows = new ArrayList<>(Arrays.asList( + new Flow(FlowTemplates.variatingFlow()), + new Flow(FlowTemplates.slowStartupFlow()), + new Flow(FlowTemplates.slowStartup2Flow()), + new Flow(FlowTemplates.adjustingFlow()), + new Flow(FlowTemplates.jaggedFlow()) + )); + DefaultSpeedManager manager = new DefaultSpeedManager(flows); + factory.setDeviationProvider(new SinusoidalDeviationProvider(SinusoidalDeviationProvider.DEFAULT_SLOPE_DIVIDER)); + factory.setNoiseProvider(new DefaultNoiseProvider(DefaultNoiseProvider.DEFAULT_NOISINESS_DIVIDER)); + factory.getNature().setReactionTimeVariationMs(100); + manager.setMouseMovementBaseTimeMs(currentBaseTime); + + DefaultOvershootManager overshootManager = (DefaultOvershootManager) factory.getOvershootManager(); + if (Rs2AntibanSettings.simulateMistakes) + overshootManager.setOvershoots(3); + else + overshootManager.setOvershoots(0); + overshootManager.setMinDistanceForOvershoots(3); + overshootManager.setMinOvershootMovementMs(130); + + factory.setSpeedManager(manager); + return factory; + } + + // Super fast gamer + public static MouseMotionFactory createSuperFastGamerMotionFactory() { + return createSuperFastGamerMotionFactory(new DefaultMouseMotionNature()); + } + + public static MouseMotionFactory createSuperFastGamerMotionFactory(MouseMotionNature nature) { + int initialBaseTime = 90; + int maxBaseTime = 120; + int currentBaseTime = initialBaseTime; + if (Rs2AntibanSettings.simulateFatigue) + currentBaseTime = (Rs2Antiban.mouseFatigue.calculateBaseTimeWithNoise(currentBaseTime, maxBaseTime)); + + MouseMotionFactory factory = new MouseMotionFactory(nature); + List flows = new ArrayList<>(Arrays.asList( + new Flow(FlowTemplates.variatingFlow()), + new Flow(FlowTemplates.slowStartupFlow()), + new Flow(FlowTemplates.slowStartup2Flow()), + new Flow(FlowTemplates.adjustingFlow()), + new Flow(FlowTemplates.jaggedFlow()) + )); + DefaultSpeedManager manager = new DefaultSpeedManager(flows); + factory.setDeviationProvider(new SinusoidalDeviationProvider(SinusoidalDeviationProvider.DEFAULT_SLOPE_DIVIDER)); + factory.setNoiseProvider(new DefaultNoiseProvider(DefaultNoiseProvider.DEFAULT_NOISINESS_DIVIDER)); + factory.getNature().setReactionTimeVariationMs(90); + manager.setMouseMovementBaseTimeMs(currentBaseTime); + + DefaultOvershootManager overshootManager = (DefaultOvershootManager) factory.getOvershootManager(); + if (Rs2AntibanSettings.simulateMistakes) + overshootManager.setOvershoots(2); + else + overshootManager.setOvershoots(0); + overshootManager.setMinDistanceForOvershoots(3); + overshootManager.setMinOvershootMovementMs(100); + + factory.setSpeedManager(manager); + return factory; + } + + /** + *

Standard 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 flows = new ArrayList<>(Arrays.asList( + new Flow(FlowTemplates.variatingFlow()), + new Flow(FlowTemplates.interruptedFlow()), + new Flow(FlowTemplates.interruptedFlow2()), + new Flow(FlowTemplates.slowStartupFlow()), + new Flow(FlowTemplates.slowStartup2Flow()), + new Flow(FlowTemplates.adjustingFlow()), + new Flow(FlowTemplates.jaggedFlow()), + new Flow(FlowTemplates.stoppingFlow()) + )); + DefaultSpeedManager manager = new DefaultSpeedManager(flows); + factory.setDeviationProvider(new SinusoidalDeviationProvider(SinusoidalDeviationProvider.DEFAULT_SLOPE_DIVIDER)); + factory.setNoiseProvider(new DefaultNoiseProvider(DefaultNoiseProvider.DEFAULT_NOISINESS_DIVIDER)); + factory.getNature().setReactionTimeVariationMs(110); + manager.setMouseMovementBaseTimeMs(400); + + DefaultOvershootManager overshootManager = (DefaultOvershootManager) factory.getOvershootManager(); + if (Rs2AntibanSettings.simulateMistakes) + overshootManager.setOvershoots(4); + else + overshootManager.setOvershoots(0); + + factory.setSpeedManager(manager); + return factory; + } +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/util/mouse/naturalmouse/util/FlowTemplates.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/util/mouse/naturalmouse/util/FlowTemplates.java new file mode 100644 index 0000000000..622811527d --- /dev/null +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/util/mouse/naturalmouse/util/FlowTemplates.java @@ -0,0 +1,99 @@ +package net.runelite.client.plugins.microbot.util.mouse.naturalmouse.util; + +import java.util.Arrays; + +public class FlowTemplates { + public static double[] variatingFlow() { + return new double[]{ + 10, 13, 14, 19, 16, 13, 15, 22, 56, 90, 97, 97, 66, 51, 50, 66, 91, 95, 87, 96, 98, + 88, 70, 62, 57, 63, 79, 93, 98, 97, 100, 104, 83, 49, 37, 53, 68, 73, 61, 51, 64, 107, + 103, 111, 94, 88, 95, 86, 88, 97, 108, 85, 86, 74, 72, 73, 58, 50, 50, 60, 62, 61, 52, + 53, 44, 30, 21, 25, 21, 17, 16, 13, 8, 2, 6, 9, 6, 3, 7, 12, 13, 15, 11, 9, + 9, 7, 6, 4, 1, 2, 3, 2, 2, 11, 15, 7, 1, 0, 0, 1 + }; + } + + public static double[] interruptedFlow() { + return new double[]{ + 12, 11, 10, 20, 24, 19, 26, 15, 9, 9, 10, 24, 26, 30, 24, 49, 72, 60, 81, 113, 82, + 99, 67, 10, 7, 7, 7, 10, 8, 7, 9, 6, 6, 7, 10, 11, 12, 8, 7, 3, 0, 2, + 8, 10, 10, 12, 6, 4, 4, 3, 8, 11, 11, 11, 11, 13, 11, 20, 25, 18, 21, 23, 56, + 40, 36, 58, 69, 60, 63, 51, 87, 71, 86, 66, 115, 97, 80, 65, 50, 66, 57, 24, 11, 11, + 7, 3, 0, 0, 1, 3, 3, 5, 6, 12, 11, 7, 11, 17, 17, 23 + }; + } + + public static double[] interruptedFlow2() { + return new double[]{ + 12, 11, 10, 20, 24, 19, 26, 15, 9, 9, 10, 24, 26, 30, 24, 49, 72, 60, 81, 113, 82, + 99, 67, 10, 12, 8, 11, 15, 16, 17, 17, 12, 16, 37, 10, 25, 12, 11, 41, 10, 12, 11, + 40, 36, 52, 61, 60, 64, 51, 82, 71, 81, 66, 105, 92, 59, 65, 51, 66, 54, 21, 21, 12, + 40, 36, 58, 69, 60, 63, 51, 87, 71, 86, 66, 115, 97, 80, 65, 50, 66, 57, 24, 11, 11, + 7, 3, 0, 0, 1, 3, 3, 5, 6, 12, 11, 7, 11, 17, 17, 23 + }; + } + + + public static double[] slowStartupFlow() { + return new double[]{ + 8, 5, 1, 1, 1, 2, 2, 3, 3, 3, 5, 7, 9, 10, 10, 11, 11, 11, 12, 12, 13, + 15, 14, 13, 15, 15, 17, 17, 18, 18, 20, 19, 20, 20, 19, 20, 19, 20, 21, 22, 20, 17, + 20, 22, 18, 20, 21, 18, 20, 20, 18, 20, 19, 21, 19, 19, 19, 19, 20, 19, 20, 21, 19, + 19, 17, 21, 21, 17, 19, 18, 20, 18, 19, 24, 34, 43, 35, 40, 41, 42, 42, 38, 40, 40, + 37, 36, 42, 40, 63, 85, 98, 92, 103, 102, 95, 86, 70, 52, 31, 19 + }; + } + + + public static double[] slowStartup2Flow() { + return new double[]{ + 7, 2, 1, 2, 2, 3, 5, 9, 10, 10, 11, 13, 13, 10, 4, 1, 1, 2, 3, 4, 6, + 9, 11, 11, 10, 14, 11, 9, 2, 1, 2, 2, 3, 4, 8, 9, 10, 11, 11, 13, 13, 15, + 14, 15, 18, 17, 19, 21, 20, 19, 18, 20, 20, 20, 20, 19, 20, 19, 19, 18, 20, 20, 19, + 20, 18, 20, 21, 19, 21, 18, 19, 25, 37, 37, 35, 41, 43, 41, 41, 40, 48, 81, 108, 91, + 88, 74, 46, 19, 46, 84, 35, 14, 19, 12, 13, 18, 38, 35, 11, 4 + }; + } + + public static double[] jaggedFlow() { + return new double[]{ + 52, 106, 122, 8, 6, 117, 32, 2, 68, 34, 21, 81, 61, 86, 55, 4, 104, 21, 51, 8, 93, + 90, 43, 65, 82, 31, 40, 115, 107, 13, 35, 73, 81, 67, 31, 79, 57, 100, 55, 64, 13, 54, + 18, 68, 82, 61, 11, 84, 37, 20, 68, 33, 36, 55, 68, 75, 56, 20, 41, 120, 63, 72, 102, + 49, 4, 48, 69, 50, 35, 49, 54, 19, 95, 121, 26, 78, 31, 62, 53, 123, 73, 22, 39, 72, + 98, 33, 26, 5, 103, 23, 75, 35, 69, 33, 44, 12, 10, 101, 122, 19 + }; + } + + public static double[] stoppingFlow() { + return new double[]{ + 8, 20, 39, 48, 66, 71, 79, 57, 29, 5, 2, 3, 2, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 1, 3, 6, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 6, 10, 12, 15, 19, + 37, 60, 100, 103, 98, 82, 87, 74, 65, 51, 57, 54, 61, 46, 38, 16 + }; + } + + public static double[] adjustingFlow() { + return new double[]{ + 1, 1, 1, 3, 8, 7, 2, 2, 4, 8, 6, 3, 7, 13, 18, 19, 24, 35, 26, 14, 31, + 43, 49, 55, 61, 67, 61, 50, 43, 37, 30, 16, 5, 4, 4, 3, 3, 3, 4, 4, 3, + 2, 2, 3, 10, 14, 10, 7, 5, 5 + }; + } + + public static double[] random() { + double[] result = new double[100]; + for (int i = 0; i < result.length; i++) { + result[i] = (int) (Math.random() * 100); + } + return result; + } + + public static double[] constantSpeed() { + double[] flowBuckets = new double[10]; + Arrays.fill(flowBuckets, 100); + return flowBuckets; + } +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/util/mouse/naturalmouse/util/FlowUtil.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/util/mouse/naturalmouse/util/FlowUtil.java new file mode 100644 index 0000000000..aa79478cf9 --- /dev/null +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/util/mouse/naturalmouse/util/FlowUtil.java @@ -0,0 +1,113 @@ +package net.runelite.client.plugins.microbot.util.mouse.naturalmouse.util; + +import java.util.Arrays; +import java.util.function.Function; + +public class FlowUtil { + /** + * 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 + * + * @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, Function modifier) { + if (targetLength < flow.length) { + throw new IllegalArgumentException("Target bucket length smaller than flow. " + targetLength + " vs " + flow.length); + } + double[] result; + int tempLength = targetLength; + + if (flow.length != 1 && (tempLength - flow.length) % (flow.length - 1) != 0) { + tempLength = (flow.length - 1) * (tempLength - flow.length) + 1; + } + + result = new double[tempLength]; + int insider = flow.length - 2; + int stepLength = (int) ((tempLength - 2) / (double) (insider + 1)) + 1; + int countToNextStep = stepLength; + int fillValueIndex = 0; + for (int i = 0; i < tempLength; i++) { + double fillValueBottom = flow[fillValueIndex]; + double fillValueTop = fillValueIndex + 1 < flow.length ? flow[fillValueIndex + 1] : flow[fillValueIndex]; + + double completion = (stepLength - countToNextStep) / (double) stepLength; + + result[i] = fillValueBottom * (1 - completion) + fillValueTop * completion; + + countToNextStep--; + + if (countToNextStep == 0) { + countToNextStep = stepLength; + fillValueIndex++; + } + } + + if (tempLength != targetLength) { + result = reduceFlow(result, targetLength); + } + + return Arrays.stream(result).map(modifier::apply).toArray(); + } + + /** + * Reduction causes loss of information, so the resulting flow is always 'good enough', but is not quaranteed + * to be equivalent, just a shorter version of the original flow + * + * @param flow the original flow + * @param targetLength the resulting array length + * @return the resulting flow + */ + public static double[] reduceFlow(double[] flow, int targetLength) { + if (flow.length <= targetLength) { + throw new IllegalArgumentException("Bad arguments [" + flow.length + ", " + targetLength + "]"); + } + + double multiplier = targetLength / (double) flow.length; + double[] result = new double[targetLength]; + for (int i = 0; i < flow.length; i++) { + double index = (i * multiplier); + double untilIndex = (i + 1) * multiplier; + int indexInt = (int) index; + int untilIndexInt = (int) untilIndex; + if (indexInt != untilIndexInt) { + double resultIndexPortion = 1 - (index - indexInt); + double nextResultIndexPortion = untilIndex - untilIndexInt; + result[indexInt] += flow[i] * resultIndexPortion; + if (untilIndexInt < result.length) { + result[untilIndexInt] += flow[i] * nextResultIndexPortion; + } + } else { + result[indexInt] += flow[i] * (untilIndex - index); + } + } + + return result; + } +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/util/mouse/naturalmouse/util/MathUtil.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/util/mouse/naturalmouse/util/MathUtil.java new file mode 100644 index 0000000000..d24d06a044 --- /dev/null +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/util/mouse/naturalmouse/util/MathUtil.java @@ -0,0 +1,18 @@ +package net.runelite.client.plugins.microbot.util.mouse.naturalmouse.util; + +public class MathUtil { + /** + * Rounds value towards target to exact integer value. + * + * @param value the value to be rounded + * @param target the target to be rounded towards + * @return the rounded value + */ + public static int roundTowards(double value, int target) { + if (target > value) { + return (int) Math.ceil(value); + } else { + return (int) Math.floor(value); + } + } +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/util/mouse/naturalmouse/util/Pair.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/util/mouse/naturalmouse/util/Pair.java new file mode 100644 index 0000000000..8ee71dc4b3 --- /dev/null +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/util/mouse/naturalmouse/util/Pair.java @@ -0,0 +1,11 @@ +package net.runelite.client.plugins.microbot.util.mouse.naturalmouse.util; + +public class Pair { + public final X x; + public final Y y; + + public Pair(X x, Y y) { + this.x = x; + this.y = y; + } +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/util/npc/Rs2Npc.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/util/npc/Rs2Npc.java index de8f1d1990..7b0e157fd2 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/util/npc/Rs2Npc.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/util/npc/Rs2Npc.java @@ -9,13 +9,12 @@ import net.runelite.client.plugins.microbot.util.camera.Rs2Camera; import net.runelite.client.plugins.microbot.util.combat.Rs2Combat; import net.runelite.client.plugins.microbot.util.menu.NewMenuEntry; +import net.runelite.client.plugins.microbot.util.misc.Rs2UiHelper; import net.runelite.client.plugins.microbot.util.player.Rs2Player; import net.runelite.client.plugins.microbot.util.tile.Rs2Tile; import net.runelite.client.plugins.microbot.util.walker.Rs2Walker; import org.jetbrains.annotations.Nullable; -import java.awt.*; -import java.util.List; import java.util.*; import java.util.stream.Collectors; import java.util.stream.Stream; @@ -195,7 +194,7 @@ public static boolean interact(NPC npc, String action) { MenuAction menuAction = getMenuAction(index); if (menuAction != null) { - Microbot.doInvoke(new NewMenuEntry(0, 0, menuAction.getId(), npc.getIndex(), -1, npc.getName()), new Rectangle(npc.getCanvasTilePoly().getBounds())); + Microbot.doInvoke(new NewMenuEntry(0, 0, menuAction.getId(), npc.getIndex(), -1, npc.getName(), npc), Rs2UiHelper.getActorClickbox(npc)); } } catch (Exception ex) { @@ -255,7 +254,7 @@ public static boolean attack(int npcId) { } public static boolean attack(String npcName) { - return attack(Arrays.asList(npcName)); + return attack(Collections.singletonList(npcName)); } public static boolean attack(List npcNames) { diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/util/tile/Rs2Tile.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/util/tile/Rs2Tile.java index 9661b967f3..8a335a42dc 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/util/tile/Rs2Tile.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/util/tile/Rs2Tile.java @@ -1,10 +1,7 @@ package net.runelite.client.plugins.microbot.util.tile; import lombok.Getter; -import net.runelite.api.Client; -import net.runelite.api.CollisionDataFlag; -import net.runelite.api.GraphicsObject; -import net.runelite.api.Tile; +import net.runelite.api.*; import net.runelite.api.coords.LocalPoint; import net.runelite.api.coords.WorldPoint; import net.runelite.client.plugins.devtools.MovementFlag; @@ -242,6 +239,26 @@ public static boolean isTileReachable(WorldPoint targetPoint) { return isVisited(targetPoint, visited); } + public static boolean areSurroundingTilesWalkable(WorldPoint worldPoint, int sizeX, int sizeY) { + for (int dx = -1; dx <= sizeX; dx++) { + for (int dy = -1; dy <= sizeY; dy++) { + // Skip the inside tiles, only check the border + if (dx >= 0 && dx < sizeX && dy >= 0 && dy < sizeY) { + continue; + } + + int checkX = worldPoint.getX() + dx; + int checkY = worldPoint.getY() + dy; + + if (isTileReachable(new WorldPoint(checkX, checkY, worldPoint.getPlane()))) { + return true; + } + } + } + + return false; + } + private static boolean isWithinBounds(int x, int y) { return x >= 0 && y >= 0 && x < 104 && y < 104; } diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/util/walker/Rs2Walker.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/util/walker/Rs2Walker.java index 96bb0e48b5..bee41f37f4 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/util/walker/Rs2Walker.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/util/walker/Rs2Walker.java @@ -423,8 +423,11 @@ private static boolean handleDoors(List path, int index) { // Match action var action = Arrays.stream(objectComp.getActions()) - .filter(x -> x != null && doorActions.contains(x.toLowerCase())) - .min(Comparator.comparing(x -> doorActions.indexOf(x.toLowerCase()))).orElse(null); + .filter(x -> x != null && doorActions.stream().anyMatch(doorAction -> x.toLowerCase().startsWith(doorAction))) + .min(Comparator.comparing(x -> doorActions.indexOf( + doorActions.stream().filter(doorAction -> x.toLowerCase().startsWith(doorAction)).findFirst().orElse("")))) + .orElse(null); + if (action == null) continue; boolean found = false; @@ -469,6 +472,7 @@ private static boolean handleDoors(List path, int index) { if (found){ + System.out.println(action); Rs2GameObject.interact(object, action); Rs2Player.waitForWalking(); return true; diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/vorkath/VorkathScript.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/vorkath/VorkathScript.java index 3a9582835b..3f387b81a3 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/vorkath/VorkathScript.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/vorkath/VorkathScript.java @@ -17,10 +17,12 @@ import net.runelite.client.plugins.microbot.util.equipment.Rs2Equipment; import net.runelite.client.plugins.microbot.util.gameobject.Rs2GameObject; import net.runelite.client.plugins.microbot.util.grandexchange.Rs2GrandExchange; +import net.runelite.client.plugins.microbot.util.grounditem.LootingParameters; import net.runelite.client.plugins.microbot.util.grounditem.Rs2GroundItem; import net.runelite.client.plugins.microbot.util.inventory.Rs2Inventory; import net.runelite.client.plugins.microbot.util.magic.Rs2Magic; import net.runelite.client.plugins.microbot.util.math.Random; +import net.runelite.client.plugins.microbot.util.math.Rs2Random; import net.runelite.client.plugins.microbot.util.misc.Rs2Potion; import net.runelite.client.plugins.microbot.util.npc.Rs2Npc; import net.runelite.client.plugins.microbot.util.player.Rs2Player; @@ -52,31 +54,39 @@ enum State { } public class VorkathScript extends Script { - public static String version = "1.3.6"; - - State state = State.ZOMBIE_SPAWN; - - private final int whiteProjectileId = 395; - private final int redProjectileId = 1481; + public static String version = "1.3.7"; + public static VorkathConfig config; @Getter public final int acidProjectileId = 1483; + final String ZOMBIFIED_SPAWN = "Zombified Spawn"; + private final int whiteProjectileId = 395; + private final int redProjectileId = 1481; private final int acidRedProjectileId = 1482; + @Getter + private final HashSet acidPools = new HashSet<>(); + public int vorkathSessionKills = 0; + public int tempVorkathKills = 0; + State state = State.ZOMBIE_SPAWN; NPC vorkath; boolean hasEquipment = false; boolean hasInventory = false; + boolean clickedSafeTile = false; + boolean clickedVorkath = false; boolean init = true; - public static VorkathConfig config; - @Getter - private HashSet acidPools = new HashSet<>(); - String primaryBolts = ""; + Rs2InventorySetup rs2InventorySetup; - final String ZOMBIFIED_SPAWN = "Zombified Spawn"; - - public int vorkathSessionKills = 0; - public int tempVorkathKills = 0; + private static void walkToCenter() { + Rs2Walker.walkFastLocal( + LocalPoint.fromScene(48, 58, Microbot.getClient().getTopLevelWorldView().getScene()) + ); + } - Rs2InventorySetup rs2InventorySetup; + private static void drinkPrayer() { + if ((Microbot.getClient().getBoostedSkillLevel(Skill.PRAYER) * 100) / Microbot.getClient().getRealSkillLevel(Skill.PRAYER) < Random.random(25, 30)) { + Rs2Inventory.interact(Rs2Potion.getPrayerPotionsVariants(), "drink"); + } + } private void calculateState() { if (Rs2Npc.getNpc(NpcID.VORKATH_8061) != null) { @@ -103,7 +113,7 @@ public boolean run(VorkathConfig config) { state = State.BANKING; hasEquipment = false; hasInventory = false; - this.config = config; + VorkathScript.config = config; tempVorkathKills = config.SellItemsAtXKills(); Microbot.getSpecialAttackConfigs().setSpecialAttack(true); @@ -299,8 +309,20 @@ public boolean run(VorkathConfig config) { } } togglePrayer(false); + LootingParameters valueParams = new LootingParameters( + config.priceOfItemsToLoot(), + Integer.MAX_VALUE, + 20, + 1, + 0, + false, + false + ); + Rs2GroundItem.loot("Vorkath's head", 20); - Rs2GroundItem.lootAllItemBasedOnValue(config.priceOfItemsToLoot(), 20); + if (Rs2GroundItem.lootItemBasedOnValue(valueParams)) { + Microbot.pauseAllScripts = false; + } int foodInventorySize = Rs2Inventory.getInventoryFood().size(); boolean hasVenom = Rs2Inventory.hasItem("venom"); boolean hasSuperAntifire = Rs2Inventory.hasItem("super antifire"); @@ -401,12 +423,6 @@ private boolean checkSellingItems(VorkathConfig config) { return false; } - private static void walkToCenter() { - Rs2Walker.walkFastLocal( - LocalPoint.fromScene(48, 58, Microbot.getClient().getTopLevelWorldView().getScene()) - ); - } - /** * will heal and drink pray pots */ @@ -478,7 +494,6 @@ public void togglePrayer(boolean onOff) { private void handleRedBall() { if (doesProjectileExistById(redProjectileId)) { redBallWalk(); - sleep(600); Rs2Npc.interact("Vorkath", "attack"); } } @@ -488,12 +503,6 @@ private void handlePrayer() { togglePrayer(true); } - private static void drinkPrayer() { - if ((Microbot.getClient().getBoostedSkillLevel(Skill.PRAYER) * 100) / Microbot.getClient().getRealSkillLevel(Skill.PRAYER) < Random.random(25, 30)) { - Rs2Inventory.interact(Rs2Potion.getPrayerPotionsVariants(), "drink"); - } - } - private boolean doesProjectileExistById(int id) { for (Projectile projectile : Microbot.getClient().getProjectiles()) { if (projectile.getId() == id) { @@ -543,6 +552,8 @@ boolean isTileSafe(WorldPoint tile) { private void handleAcidWalk() { if (!doesProjectileExistById(acidProjectileId) && !doesProjectileExistById(acidRedProjectileId) && Rs2GameObject.getGameObjects(ObjectID.ACID_POOL_32000).isEmpty()) { Rs2Npc.interact("Vorkath", "attack"); + clickedVorkath = false; + clickedSafeTile = false; state = State.FIGHT_VORKATH; acidPools.clear(); return; @@ -559,10 +570,27 @@ private void handleAcidWalk() { if (safeTile != null) { if (playerLocation.equals(safeTile)) { - Rs2Npc.interact(vorkath, "attack"); + clickedSafeTile = false; + if (clickedVorkath) { + return; + } + WorldPoint wooxTile = new WorldPoint(safeTile.getX(), safeTile.getY() + 1, safeTile.getPlane()); + //Rs2Player.eatAt(75); + //Rs2Walker.walkFastLocal(LocalPoint.fromWorld(Microbot.getClient(), wooxTile)); + Rs2Npc.interact("Vorkath", "attack"); + clickedVorkath = true; + Microbot.log("Walking to woox tile"); + Rs2Random.wait(100, 150); } else { - Rs2Player.eatAt(75); + if (clickedSafeTile) { + clickedVorkath = false; + return; + } + Rs2Player.eatAt(60); Rs2Walker.walkFastLocal(LocalPoint.fromWorld(Microbot.getClient(), safeTile)); + clickedSafeTile = true; + Microbot.log("Walking to safe tile"); + Rs2Random.wait(100, 150); } } } diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/wintertodt/MWintertodtConfig.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/wintertodt/MWintertodtConfig.java index 5fd62b7f52..bfb51b2b24 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/wintertodt/MWintertodtConfig.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/wintertodt/MWintertodtConfig.java @@ -117,11 +117,22 @@ default int foodAmount() { return 6; } + @ConfigItem( + keyName = "MinFood", + name = "Min Food", + description = "Minimum food to start a new game", + position = 3, + section = foodSection + ) + default int minFood() { + return 2; + } + @ConfigItem( keyName = "Eat at %", name = "Eat at %", description = "Eat at specific percentage health.", - position = 3, + position = 4, section = foodSection ) default int eatAt() { @@ -132,7 +143,7 @@ default int eatAt() { keyName = "Hitpoints Tresshold", name = "HP % to run away", description = "Runs to the bank if a specific health treshhold is reached and the player does not have any food in their inventory.", - position = 4, + position = 5, section = foodSection ) default int hpTreshhold() { diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/wintertodt/MWintertodtOverlay.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/wintertodt/MWintertodtOverlay.java index dac1c0a025..0b50808a81 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/wintertodt/MWintertodtOverlay.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/wintertodt/MWintertodtOverlay.java @@ -10,10 +10,15 @@ import java.awt.*; public class MWintertodtOverlay extends OverlayPanel { + private final MWintertodtPlugin plugin; + MWintertodtConfig config; + @Inject - MWintertodtOverlay(MWintertodtPlugin plugin) + MWintertodtOverlay(MWintertodtPlugin plugin, MWintertodtConfig config) { super(plugin); + this.plugin = plugin; + this.config = config; setPosition(OverlayPosition.TOP_CENTER); setNaughty(); } @@ -28,6 +33,54 @@ public Dimension render(Graphics2D graphics) { panelComponent.getChildren().add(LineComponent.builder().build()); + panelComponent.getChildren().add(LineComponent.builder() + .left("Running: " + plugin.getTimeRunning()) + .leftColor(Color.GREEN) + .build()); + panelComponent.getChildren().add(LineComponent.builder().build()); + + panelComponent.getChildren().add(LineComponent.builder() + .left("Won: " + plugin.getWon()) + .leftColor(Color.GREEN) + .build()); + + panelComponent.getChildren().add(LineComponent.builder() + .left("Lost: " + plugin.getLost()) + .leftColor(Color.RED) + .build()); + + panelComponent.getChildren().add(LineComponent.builder() + .left("Cut: " + plugin.getLogsCut()) + .leftColor(Color.GREEN) + .build()); + + + panelComponent.getChildren().add(LineComponent.builder() + .left("Fletched: " + plugin.getLogsFletched()) + .leftColor(Color.GREEN) + .build()); + + + panelComponent.getChildren().add(LineComponent.builder() + .left("Braziers fixed: " + plugin.getBraziersFixed()) + .leftColor(Color.GREEN) + .build()); + + panelComponent.getChildren().add(LineComponent.builder() + .left("Braziers lit: " + plugin.getBraziersLit()) + .leftColor(Color.GREEN) + .build()); + + panelComponent.getChildren().add(LineComponent.builder() + .left("Food consumed: " + plugin.getFoodConsumed()) + .leftColor(Color.GREEN) + .build()); + + panelComponent.getChildren().add(LineComponent.builder() + .left("Times banked: " + plugin.getTimesBanked()) + .leftColor(Color.GREEN) + .build()); + panelComponent.getChildren().add(LineComponent.builder() .left(MWintertodtScript.state.toString()) .build()); diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/wintertodt/MWintertodtPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/wintertodt/MWintertodtPlugin.java index e9eeae88e5..7ebf85cf35 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/wintertodt/MWintertodtPlugin.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/wintertodt/MWintertodtPlugin.java @@ -1,16 +1,29 @@ package net.runelite.client.plugins.microbot.wintertodt; import com.google.inject.Provides; +import lombok.AccessLevel; +import lombok.Getter; +import lombok.Setter; import lombok.extern.slf4j.Slf4j; +import net.runelite.api.ChatMessageType; +import net.runelite.api.ItemID; +import net.runelite.api.MessageNode; +import net.runelite.api.Skill; +import net.runelite.api.events.ChatMessage; import net.runelite.api.events.HitsplatApplied; +import net.runelite.api.events.StatChanged; import net.runelite.client.config.ConfigManager; import net.runelite.client.eventbus.Subscribe; import net.runelite.client.plugins.Plugin; import net.runelite.client.plugins.PluginDescriptor; +import net.runelite.client.plugins.microbot.Microbot; +import net.runelite.client.plugins.microbot.util.inventory.Rs2Inventory; +import net.runelite.client.plugins.microbot.util.misc.TimeUtils; import net.runelite.client.ui.overlay.OverlayManager; import javax.inject.Inject; import java.awt.*; +import java.time.Instant; @PluginDescriptor( name = PluginDescriptor.Mocrosoft + "Wintertodt", @@ -20,28 +33,77 @@ ) @Slf4j public class MWintertodtPlugin extends Plugin { + @Inject + MWintertodtScript wintertodtScript; @Inject private MWintertodtConfig config; - @Provides - MWintertodtConfig provideConfig(ConfigManager configManager) { - return configManager.getConfig(MWintertodtConfig.class); - } - @Inject private OverlayManager overlayManager; @Inject private MWintertodtOverlay wintertodtOverlay; - @Inject - MWintertodtScript wintertodtScript; + @Getter(AccessLevel.PACKAGE) + private int won; + + @Getter(AccessLevel.PACKAGE) + private int lost; + + @Getter(AccessLevel.PACKAGE) + private int logsCut; + + @Getter(AccessLevel.PACKAGE) + private int logsFletched; + + @Getter(AccessLevel.PACKAGE) + private int braziersFixed; + + @Getter(AccessLevel.PACKAGE) + private int braziersLit; + @Getter + @Setter + private int foodConsumed; + + @Getter + @Setter + private int timesBanked; + + @Getter(AccessLevel.PACKAGE) + private boolean scriptStarted; + + private Instant scriptStartTime; + + @Provides + MWintertodtConfig provideConfig(ConfigManager configManager) { + return configManager.getConfig(MWintertodtConfig.class); + } + + protected String getTimeRunning() { + return scriptStartTime != null ? TimeUtils.getFormattedDurationBetween(scriptStartTime, Instant.now()) : ""; + } + + private void reset() { + this.won = 0; + this.lost = 0; + this.logsCut = 0; + this.logsFletched = 0; + this.braziersFixed = 0; + this.braziersLit = 0; + this.foodConsumed = 0; + this.timesBanked = 0; + this.scriptStartTime = null; + this.scriptStarted = false; + } @Override protected void startUp() throws AWTException { + reset(); + this.scriptStartTime = Instant.now(); + this.scriptStarted = true; if (overlayManager != null) { overlayManager.add(wintertodtOverlay); } - wintertodtScript.run(config); + wintertodtScript.run(config, this); } protected void shutDown() { @@ -49,9 +111,61 @@ protected void shutDown() { overlayManager.remove(wintertodtOverlay); } + @Subscribe + public void onChatMessage(ChatMessage chatMessage) { + ChatMessageType chatMessageType = chatMessage.getType(); + MessageNode messageNode = chatMessage.getMessageNode(); + + if (!scriptStarted + || !isInWintertodtRegion() + || chatMessageType != ChatMessageType.GAMEMESSAGE + && chatMessageType != ChatMessageType.SPAM) { + return; + } + + + if (messageNode.getValue().startsWith("You fix the brazier")) { + braziersFixed++; + } + + if (messageNode.getValue().startsWith("You light the brazier")) { + braziersLit++; + } + + if (messageNode.getValue().startsWith("You have gained a supply crate")) { + won++; + } + + if (messageNode.getValue().startsWith("You did not earn enough points")) { + lost++; + } + + } + + private boolean isInWintertodtRegion() { + return Microbot.getClient().getLocalPlayer().getWorldLocation().getRegionID() == 6462; + } + + private int getResourcesInInventory() { + return Rs2Inventory.count(ItemID.BRUMA_ROOT) + Rs2Inventory.count(ItemID.BRUMA_KINDLING); + } + @Subscribe public void onHitsplatApplied(HitsplatApplied hitsplatApplied) { - wintertodtScript.onHitsplatApplied(hitsplatApplied); + MWintertodtScript.onHitsplatApplied(hitsplatApplied); + } + + @Subscribe + public void onStatChanged(StatChanged event) { + + + if (event.getSkill() == Skill.WOODCUTTING) { + logsCut++; + } + + if (event.getSkill() == Skill.FLETCHING) { + logsFletched++; + } } } diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/wintertodt/MWintertodtScript.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/wintertodt/MWintertodtScript.java index 6df6a344c7..b2be31f4a4 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/wintertodt/MWintertodtScript.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/wintertodt/MWintertodtScript.java @@ -6,11 +6,17 @@ import net.runelite.api.widgets.Widget; import net.runelite.client.plugins.microbot.Microbot; import net.runelite.client.plugins.microbot.Script; +import net.runelite.client.plugins.microbot.breakhandler.BreakHandlerScript; +import net.runelite.client.plugins.microbot.util.antiban.Rs2Antiban; +import net.runelite.client.plugins.microbot.util.antiban.Rs2AntibanSettings; +import net.runelite.client.plugins.microbot.util.antiban.enums.Activity; +import net.runelite.client.plugins.microbot.util.antiban.enums.PlayStyle; import net.runelite.client.plugins.microbot.util.bank.Rs2Bank; import net.runelite.client.plugins.microbot.util.combat.Rs2Combat; import net.runelite.client.plugins.microbot.util.equipment.Rs2Equipment; import net.runelite.client.plugins.microbot.util.gameobject.Rs2GameObject; import net.runelite.client.plugins.microbot.util.inventory.Rs2Inventory; +import net.runelite.client.plugins.microbot.util.inventory.Rs2Item; import net.runelite.client.plugins.microbot.util.keyboard.Rs2Keyboard; import net.runelite.client.plugins.microbot.util.player.Rs2Player; import net.runelite.client.plugins.microbot.util.walker.Rs2Walker; @@ -19,6 +25,7 @@ import java.util.concurrent.TimeUnit; +import static net.runelite.api.Constants.GAME_TICK_LENGTH; import static net.runelite.api.ObjectID.BRAZIER_29312; import static net.runelite.api.ObjectID.BURNING_BRAZIER_29314; import static net.runelite.client.plugins.microbot.util.Global.sleepUntilTrue; @@ -30,28 +37,87 @@ */ public class MWintertodtScript extends Script { - public static String version = "1.4.1"; + public static String version = "1.4.3"; public static State state = State.BANKING; public static boolean resetActions = false; - - final WorldPoint BOSS_ROOM = new WorldPoint(1630, 3982, 0); - static MWintertodtConfig config; - - String axe = ""; + static MWintertodtPlugin plugin; + private static boolean lockState = false; + final WorldPoint BOSS_ROOM = new WorldPoint(1630, 3982, 0); final String SUPPLY_CRATE = "supply crate"; + String axe = ""; int wintertodtHp = -1; - private static boolean lockState = false; + private static void changeState(State scriptState) { + changeState(scriptState, false); + } - public boolean run(MWintertodtConfig config) { - this.config = config; + private static void changeState(State scriptState, boolean lock) { + if (state == scriptState || lockState) return; + System.out.println("Changing current script state from: " + state + " to " + scriptState); + state = scriptState; + resetActions = true; + setLockState(scriptState, lock); + lockState = lock; + } + + private static void setLockState(State state, boolean lock) { + if (lockState == lock) return; + lockState = lock; + System.out.println("State " + state.toString() + " has set lockState to " + lockState); + } + + private static boolean shouldFletchRoots() { + if (!config.fletchRoots()) return false; + if (!Rs2Inventory.hasItem(ItemID.BRUMA_ROOT)) { + setLockState(State.FLETCH_LOGS, false); + return false; + } + changeState(State.FLETCH_LOGS, true); + return true; + } + + public static void onHitsplatApplied(HitsplatApplied hitsplatApplied) { + Actor actor = hitsplatApplied.getActor(); + + if (actor != Microbot.getClient().getLocalPlayer()) { + return; + } + + resetActions = true; + + } + + public boolean run(MWintertodtConfig config, MWintertodtPlugin plugin) { + + MWintertodtScript.config = config; + MWintertodtScript.plugin = plugin; + Rs2Antiban.resetAntibanSettings(); + Rs2Antiban.antibanSetupTemplates.applyGeneralBasicSetup(); + Rs2Antiban.setActivity(Activity.GENERAL_WOODCUTTING); + Rs2AntibanSettings.usePlayStyle = true; + Rs2AntibanSettings.universalAntiban = false; + Rs2AntibanSettings.contextualVariability = true; + Rs2AntibanSettings.dynamicActivity = true; + Rs2AntibanSettings.behavioralVariability = true; + Rs2AntibanSettings.simulateAttentionSpan = false; + Rs2AntibanSettings.simulateFatigue = true; + Rs2AntibanSettings.simulateMistakes = true; + Rs2AntibanSettings.moveMouseRandomly = true; + Rs2AntibanSettings.moveMouseOffScreen = true; + Rs2AntibanSettings.naturalMouse = true; + Rs2AntibanSettings.takeMicroBreaks = true; + Rs2AntibanSettings.profileSwitching = false; + Rs2AntibanSettings.actionCooldownChance = 0.15; + Rs2AntibanSettings.microBreakChance = 0.05; + Rs2Antiban.setPlayStyle(PlayStyle.EXTREME_AGGRESSIVE); state = State.BANKING; mainScheduledFuture = scheduledExecutorService.scheduleWithFixedDelay(() -> { try { if (!Microbot.isLoggedIn()) return; if (!super.run()) return; + if (Rs2AntibanSettings.actionCooldownActive) return; long startTime = System.currentTimeMillis(); @@ -69,7 +135,7 @@ public boolean run(MWintertodtConfig config) { boolean isWintertodtAlive = Rs2Widget.hasWidget("Wintertodt's Energy"); GameObject brazier = Rs2GameObject.findObject(BRAZIER_29312, config.brazierLocation().getOBJECT_BRAZIER_LOCATION()); GameObject fireBrazier = Rs2GameObject.findObject(ObjectID.BURNING_BRAZIER_29314, config.brazierLocation().getOBJECT_BRAZIER_LOCATION()); - boolean needBanking = !Rs2Inventory.hasItemAmount(config.food().getName(), config.foodAmount(), false, false) + boolean needBanking = !Rs2Inventory.hasItemAmount(config.food().getName(), config.minFood(), false, false) && !isWintertodtAlive; Widget wintertodtHealthbar = Rs2Widget.getWidget(25952276); @@ -96,7 +162,7 @@ public boolean run(MWintertodtConfig config) { if (!isWintertodtAlive) { if (state != State.ENTER_ROOM && state != State.WAITING && state != State.BANKING) { setLockState(State.GLOBAL, false); - changeState(State.BANKING); + changeState(State.WAITING); } } else { handleMainLoop(); @@ -113,11 +179,19 @@ public boolean run(MWintertodtConfig config) { switch (state) { case BANKING: if (!handleBankLogic(config)) return; + if (BreakHandlerScript.isLockState()) + BreakHandlerScript.setLockState(false); + if (Rs2Player.isFullHealth() && Rs2Inventory.hasItemAmount(config.food().getName(), config.foodAmount(), false, true)) { + MWintertodtScript.plugin.setTimesBanked(plugin.getTimesBanked() + 1); + if (Rs2Antiban.takeMicroBreakByChance() || BreakHandlerScript.isBreakActive()) + break; changeState(State.ENTER_ROOM); } break; case ENTER_ROOM: + if (!BreakHandlerScript.isLockState() && !BreakHandlerScript.isBreakActive()) + BreakHandlerScript.setLockState(true); if (!wintertodtRespawning && !isWintertodtAlive) { Rs2Walker.walkTo(BOSS_ROOM, 12); } else { @@ -139,30 +213,44 @@ public boolean run(MWintertodtConfig config) { break; case CHOP_ROOTS: Rs2Combat.setSpecState(true, 1000); - if (!Rs2Player.isAnimating() || resetActions) { + if (!Rs2Player.isAnimating()) { Rs2GameObject.interact(ObjectID.BRUMA_ROOTS, "Chop"); sleepUntil(Rs2Player::isAnimating, 2000); resetActions = false; + Rs2Antiban.actionCooldown(); } break; case FLETCH_LOGS: - if (!Microbot.isGainingExp || resetActions) + if (Rs2Player.getAnimation() != AnimationID.FLETCHING_BOW_CUTTING || resetActions) { walkToBrazier(); - Rs2Inventory.combine(ItemID.KNIFE, ItemID.BRUMA_ROOT); - Rs2Player.waitForAnimation(); + + Rs2Item knife = Rs2Inventory.get("knife"); + if (Rs2Inventory.moveItemToSlot(knife, 27)) + sleepUntil(() -> Rs2Inventory.slotContains(27, "knife"), 5000); + Rs2Inventory.combineClosest(ItemID.KNIFE, ItemID.BRUMA_ROOT); resetActions = false; + sleep(GAME_TICK_LENGTH); + sleepUntil(() -> Rs2Player.getAnimation() != AnimationID.FLETCHING_BOW_CUTTING, 2000); + Rs2Antiban.actionCooldown(); + } break; case BURN_LOGS: if (!Microbot.isGainingExp || resetActions) { - TileObject burningBrazier = Rs2GameObject.findObjectById(BURNING_BRAZIER_29314); - if (burningBrazier.getWorldLocation().distanceTo(Rs2Player.getWorldLocation()) < 10) { + if (fireBrazier == null && brazier != null && config.relightBrazier()) { + Rs2GameObject.interact(brazier, "light"); + sleep(1000); + } + if (fireBrazier.getWorldLocation().distanceTo(Rs2Player.getWorldLocation()) < 10 && hasItemsToBurn()) { + Rs2GameObject.interact(BURNING_BRAZIER_29314, "feed"); - Rs2Player.waitForAnimation(); - sleep(2000); + resetActions = false; + sleep(GAME_TICK_LENGTH * 3); + Rs2Antiban.actionCooldown(); + } - resetActions = false; + } break; // case FIX_BRAZIER: // TODO: fix this state @@ -189,41 +277,14 @@ public boolean run(MWintertodtConfig config) { private void handleMainLoop() { if (isWintertodtAlmostDead()) { setLockState(State.BURN_LOGS, false); - if (shouldBurnLogs()) return; + if (shouldBurnLogs()) { + } } else { if (shouldChopRoots()) return; if (shouldFletchRoots()) return; - if (shouldBurnLogs()) return; - } - } - - private static void changeState(State scriptState) { - changeState(scriptState, false); - } - - private static void changeState(State scriptState, boolean lock) { - if (state == scriptState || lockState) return; - System.out.println("Changing current script state from: " + state + " to " + scriptState); - state = scriptState; - resetActions = true; - setLockState(scriptState, lock); - lockState = lock; - } - - private static void setLockState(State state, boolean lock) { - if (lockState == lock) return; - lockState = lock; - System.out.println("State " + state.toString() + " has set lockState to " + lockState); - } - - private static boolean shouldFletchRoots() { - if (!config.fletchRoots()) return false; - if (!Rs2Inventory.hasItem(ItemID.BRUMA_ROOT)) { - setLockState(State.FLETCH_LOGS, false); - return false; + if (shouldBurnLogs()) { + } } - changeState(State.FLETCH_LOGS, true); - return true; } private boolean shouldBurnLogs() { @@ -238,6 +299,7 @@ private boolean shouldBurnLogs() { private boolean shouldEat() { if (eatAt(config.eatAt())) { sleep(600, 800); + plugin.setFoodConsumed(plugin.getFoodConsumed() + 1); Rs2Inventory.dropAll("jug"); resetActions = true; return true; @@ -299,30 +361,21 @@ private void dropUnnecessaryItems() { @Override public void shutdown() { + Rs2Antiban.resetAntibanSettings(); super.shutdown(); } - public static void onHitsplatApplied(HitsplatApplied hitsplatApplied) { - Actor actor = hitsplatApplied.getActor(); - - if (actor != Microbot.getClient().getLocalPlayer()) { - return; - } - - resetActions = true; - - } - private void walkToBrazier() { if (Rs2Player.getWorldLocation().distanceTo(config.brazierLocation().getBRAZIER_LOCATION()) > 6) { Rs2Walker.walkTo(config.brazierLocation().getBRAZIER_LOCATION(), 2); } else if (!Rs2Player.getWorldLocation().equals(config.brazierLocation().getBRAZIER_LOCATION())) { Rs2Walker.walkFastCanvas(config.brazierLocation().getBRAZIER_LOCATION()); - if (Rs2Player.getWorldLocation().distanceTo(config.brazierLocation().getBRAZIER_LOCATION()) > 4) { - Rs2Player.waitForWalking(); - } else { - sleep(3000); - } + sleep(GAME_TICK_LENGTH); +// if (Rs2Player.getWorldLocation().distanceTo(config.brazierLocation().getBRAZIER_LOCATION()) > 4) { +// Rs2Player.waitForWalking(); +// } else { +// //sleep(3000); +// } } } @@ -335,8 +388,10 @@ private void dodgeOrbDamage() { System.out.println(WorldPoint.fromLocalInstance(Microbot.getClient(), graphicsObject.getLocation()).distanceTo(Rs2Player.getWorldLocation())); //walk south + Rs2Walker.walkFastCanvas(new WorldPoint(Rs2Player.getWorldLocation().getX(), Rs2Player.getWorldLocation().getY() - 1, Rs2Player.getWorldLocation().getPlane())); - Rs2Player.waitForWalking(4000); + Rs2Player.waitForWalking(1000); + sleep(GAME_TICK_LENGTH * 2); resetActions = true; } } diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/woodcutting/AutoWoodcuttingConfig.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/woodcutting/AutoWoodcuttingConfig.java index efe5d9bdf8..1b59b00bd9 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/woodcutting/AutoWoodcuttingConfig.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/woodcutting/AutoWoodcuttingConfig.java @@ -93,5 +93,4 @@ default WoodcuttingWalkBack walkBack() { return WoodcuttingWalkBack.LAST_LOCATION; } - } diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/woodcutting/AutoWoodcuttingOverlay.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/woodcutting/AutoWoodcuttingOverlay.java index 871722a61c..ace6e77482 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/woodcutting/AutoWoodcuttingOverlay.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/woodcutting/AutoWoodcuttingOverlay.java @@ -1,20 +1,32 @@ package net.runelite.client.plugins.microbot.woodcutting; +import net.runelite.api.Perspective; +import net.runelite.api.coords.LocalPoint; import net.runelite.client.plugins.microbot.Microbot; +import net.runelite.client.ui.overlay.OverlayLayer; import net.runelite.client.ui.overlay.OverlayPanel; import net.runelite.client.ui.overlay.OverlayPosition; +import net.runelite.client.ui.overlay.OverlayPriority; import net.runelite.client.ui.overlay.components.LineComponent; import net.runelite.client.ui.overlay.components.TitleComponent; import javax.inject.Inject; import java.awt.*; +import static net.runelite.client.ui.overlay.OverlayUtil.renderPolygon; + public class AutoWoodcuttingOverlay extends OverlayPanel { + private static final Color WHITE_TRANSLUCENT = new Color(255, 255, 255, 127); + private final AutoWoodcuttingConfig config; + @Inject - AutoWoodcuttingOverlay(AutoWoodcuttingPlugin plugin) + AutoWoodcuttingOverlay(AutoWoodcuttingPlugin plugin, AutoWoodcuttingConfig config) { super(plugin); - setPosition(OverlayPosition.TOP_LEFT); + this.config = config; + setPosition(OverlayPosition.DYNAMIC); + setLayer(OverlayLayer.ABOVE_SCENE); + setPriority(OverlayPriority.HIGH); setNaughty(); } @Override @@ -31,6 +43,17 @@ public Dimension render(Graphics2D graphics) { .left(Microbot.status) .build()); + if (config.distanceToStray() < 21) { + LocalPoint lp = LocalPoint.fromWorld(Microbot.getClient(), AutoWoodcuttingScript.initPlayerLoc(config)); + if (lp != null) { + Polygon poly = Perspective.getCanvasTileAreaPoly(Microbot.getClient(), lp, config.distanceToStray() * 2); + + if (poly != null) + { + renderPolygon(graphics, poly, WHITE_TRANSLUCENT); + } + } + } } catch(Exception ex) { System.out.println(ex.getMessage()); diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/woodcutting/AutoWoodcuttingScript.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/woodcutting/AutoWoodcuttingScript.java index dd00b6fc0d..368b7691a4 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/woodcutting/AutoWoodcuttingScript.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/woodcutting/AutoWoodcuttingScript.java @@ -28,11 +28,19 @@ enum State { public class AutoWoodcuttingScript extends Script { - public static String version = "1.6.0"; + public static String version = "1.6.1"; public boolean cannotLightFire = false; State state = State.WOODCUTTING; - private WorldPoint returnPoint; + private static WorldPoint returnPoint; + + public static WorldPoint initPlayerLoc(AutoWoodcuttingConfig config) { + if (config.walkBack() == WoodcuttingWalkBack.INITIAL_LOCATION) { + return getInitialPlayerLocation(); + } else { + return returnPoint; + } + } public boolean run(AutoWoodcuttingConfig config) { if (config.hopWhenPlayerDetected()) { @@ -49,6 +57,10 @@ public boolean run(AutoWoodcuttingConfig config) { initialPlayerLocation = Rs2Player.getWorldLocation(); } + if (returnPoint == null) { + returnPoint = Rs2Player.getWorldLocation(); + } + if (!config.TREE().hasRequiredLevel()) { Microbot.showMessage("You do not have the required woodcutting level to cut this tree."); shutdown(); @@ -72,7 +84,7 @@ public boolean run(AutoWoodcuttingConfig config) { return; } - GameObject tree = Rs2GameObject.findObject(config.TREE().getName(), true, config.distanceToStray(), true, getInitialPlayerLocation()); + GameObject tree = Rs2GameObject.findObject(config.TREE().getName(), true, config.distanceToStray(), false, getInitialPlayerLocation()); if (tree != null) { if(Rs2GameObject.interact(tree, config.TREE().getAction())) { @@ -166,4 +178,11 @@ private void walkBack(AutoWoodcuttingConfig config) { Rs2Walker.walkTo(new WorldPoint(calculateReturnPoint(config).getX() - Random.random(-1, 1), calculateReturnPoint(config).getY() - Random.random(-1, 1), calculateReturnPoint(config).getPlane())); sleepUntil(() -> Rs2Player.getWorldLocation().distanceTo(calculateReturnPoint(config)) <= 4); } + + @Override + public void shutdown() { + super.shutdown(); + returnPoint = null; + initialPlayerLocation = null; + } } \ No newline at end of file diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/nateplugins/moneymaking/natehumidifier/HumidifierScript.java b/runelite-client/src/main/java/net/runelite/client/plugins/nateplugins/moneymaking/natehumidifier/HumidifierScript.java index 166aeb4d3c..d19b8057ed 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/nateplugins/moneymaking/natehumidifier/HumidifierScript.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/nateplugins/moneymaking/natehumidifier/HumidifierScript.java @@ -3,26 +3,30 @@ import net.runelite.api.ItemID; import net.runelite.client.plugins.microbot.Microbot; import net.runelite.client.plugins.microbot.Script; +import net.runelite.client.plugins.microbot.util.antiban.Rs2Antiban; +import net.runelite.client.plugins.microbot.util.antiban.Rs2AntibanSettings; +import net.runelite.client.plugins.microbot.util.antiban.enums.Activity; import net.runelite.client.plugins.microbot.util.bank.Rs2Bank; import net.runelite.client.plugins.microbot.util.inventory.Rs2Inventory; import net.runelite.client.plugins.microbot.util.magic.Rs2Magic; -import net.runelite.client.plugins.skillcalculator.skills.MagicAction; import net.runelite.client.util.QuantityFormatter; import java.util.concurrent.TimeUnit; public class HumidifierScript extends Script { - public static String version = "1.6.1"; - private static long itemsProcessed = 0; + public static String version = "1.6.2"; public static String itemsProcessedMessage = ""; public static String profitMessage = "Calculating..."; - + private static long itemsProcessed = 0; private int profit = 0; private long timeBegan; public boolean run(HumidifierConfig config) { + Rs2Antiban.antibanSetupTemplates.applyCombatSetup(); + Rs2Antiban.setActivity(Activity.HUMIDIFYING_CLAY); + timeBegan = System.currentTimeMillis(); int unprocessedItemPrice = Microbot.getItemManager().search(config.ITEM().getName()).get(0).getPrice(); int processedItemPrice = Microbot.getItemManager().search(config.ITEM().getFinished()).get(0).getPrice(); @@ -31,13 +35,17 @@ public boolean run(HumidifierConfig config) { mainScheduledFuture = scheduledExecutorService.scheduleWithFixedDelay(() -> { if (!super.run()) return; if (!Microbot.isLoggedIn()) return; + if (Rs2AntibanSettings.actionCooldownActive) return; try { boolean hasAstralRunesInInventory = Rs2Inventory.hasItem(ItemID.ASTRAL_RUNE); if (Microbot.pauseAllScripts) return; if (Rs2Inventory.hasItem(config.ITEM().getName(), true) && hasAstralRunesInInventory) { - Rs2Magic.cast(MagicAction.HUMIDIFY); + if (!Rs2Bank.isOpen()) + Rs2Magic.humidify(); sleepUntilOnClientThread(() -> Rs2Inventory.hasItem(config.ITEM().getFinished())); + Rs2Antiban.actionCooldown(); + Rs2Antiban.takeMicroBreakByChance(); } else { bank(config, hasAstralRunesInInventory); calculateItemsProcessedPerHour(config); @@ -79,7 +87,7 @@ private void bank(HumidifierConfig config, boolean hasAstralRunes){ Rs2Bank.withdrawAll(true, config.ITEM().getName(), true); sleepUntilOnClientThread(() -> Rs2Inventory.hasItem(config.ITEM().getName())); Rs2Bank.closeBank(); - sleepUntilOnClientThread(() -> !Rs2Bank.isOpen()); + //sleepUntilOnClientThread(() -> !Rs2Bank.isOpen()); } else { Rs2Bank.openBank(); @@ -88,6 +96,7 @@ private void bank(HumidifierConfig config, boolean hasAstralRunes){ @Override public void shutdown() { + Rs2Antiban.resetAntibanSettings(); super.shutdown(); itemsProcessed = 0; } diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/stretchedmode/StretchedModePlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/stretchedmode/StretchedModePlugin.java index 2ae8369b9b..98bd13bcc1 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/stretchedmode/StretchedModePlugin.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/stretchedmode/StretchedModePlugin.java @@ -34,7 +34,6 @@ import net.runelite.client.input.MouseManager; import net.runelite.client.plugins.Plugin; import net.runelite.client.plugins.PluginDescriptor; -import net.runelite.client.plugins.microbot.Microbot; import javax.inject.Inject; @@ -76,7 +75,7 @@ protected void startUp() client.setStretchedEnabled(true); updateConfig(); - Microbot.showMessage("ALERT! Microbot has noticed that your StretchMode plugin is enabled. Please disable this plugin to avoid weird behavior."); + //Microbot.showMessage("ALERT! Microbot has noticed that your StretchMode plugin is enabled. Please disable this plugin to avoid weird behavior."); } @Override diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/stretchedmode/TranslateMouseListener.java b/runelite-client/src/main/java/net/runelite/client/plugins/stretchedmode/TranslateMouseListener.java index 83a68f8e9f..b0fcd709e2 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/stretchedmode/TranslateMouseListener.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/stretchedmode/TranslateMouseListener.java @@ -25,13 +25,15 @@ */ package net.runelite.client.plugins.stretchedmode; -import java.awt.Component; -import java.awt.Dimension; -import java.awt.event.MouseEvent; -import javax.inject.Inject; +import lombok.extern.slf4j.Slf4j; import net.runelite.api.Client; import net.runelite.client.input.MouseListener; +import javax.inject.Inject; +import java.awt.*; +import java.awt.event.MouseEvent; + +@Slf4j public class TranslateMouseListener implements MouseListener { private final Client client; @@ -86,6 +88,11 @@ public MouseEvent mouseMoved(MouseEvent mouseEvent) private MouseEvent translateEvent(MouseEvent e) { + // Check if the event source is "Microbot" + if ("Microbot".equals(e.getSource().toString())) { + // Ignore the event by returning null or the original event (decide based on your needs) + return e; // or return e; if you want to pass the event unchanged + } Dimension stretchedDimensions = client.getStretchedDimensions(); Dimension realDimensions = client.getRealDimensions(); diff --git a/runelite-client/src/main/resources/net/runelite/client/plugins/microbot/util/antiban/activity.png b/runelite-client/src/main/resources/net/runelite/client/plugins/microbot/util/antiban/activity.png new file mode 100644 index 0000000000..f620bf1da9 Binary files /dev/null and b/runelite-client/src/main/resources/net/runelite/client/plugins/microbot/util/antiban/activity.png differ diff --git a/runelite-client/src/main/resources/net/runelite/client/plugins/microbot/util/antiban/antiban.png b/runelite-client/src/main/resources/net/runelite/client/plugins/microbot/util/antiban/antiban.png new file mode 100644 index 0000000000..f88c7a6d14 Binary files /dev/null and b/runelite-client/src/main/resources/net/runelite/client/plugins/microbot/util/antiban/antiban.png differ diff --git a/runelite-client/src/main/resources/net/runelite/client/plugins/microbot/util/antiban/cooldown.png b/runelite-client/src/main/resources/net/runelite/client/plugins/microbot/util/antiban/cooldown.png new file mode 100644 index 0000000000..8f2b9095e6 Binary files /dev/null and b/runelite-client/src/main/resources/net/runelite/client/plugins/microbot/util/antiban/cooldown.png differ diff --git a/runelite-client/src/main/resources/net/runelite/client/plugins/microbot/util/antiban/general.png b/runelite-client/src/main/resources/net/runelite/client/plugins/microbot/util/antiban/general.png new file mode 100644 index 0000000000..5228bf9dcf Binary files /dev/null and b/runelite-client/src/main/resources/net/runelite/client/plugins/microbot/util/antiban/general.png differ diff --git a/runelite-client/src/main/resources/net/runelite/client/plugins/microbot/util/antiban/icons/activity.png b/runelite-client/src/main/resources/net/runelite/client/plugins/microbot/util/antiban/icons/activity.png new file mode 100644 index 0000000000..f620bf1da9 Binary files /dev/null and b/runelite-client/src/main/resources/net/runelite/client/plugins/microbot/util/antiban/icons/activity.png differ diff --git a/runelite-client/src/main/resources/net/runelite/client/plugins/microbot/util/antiban/icons/cooldown.png b/runelite-client/src/main/resources/net/runelite/client/plugins/microbot/util/antiban/icons/cooldown.png new file mode 100644 index 0000000000..cda8040273 Binary files /dev/null and b/runelite-client/src/main/resources/net/runelite/client/plugins/microbot/util/antiban/icons/cooldown.png differ diff --git a/runelite-client/src/main/resources/net/runelite/client/plugins/microbot/util/antiban/icons/general.png b/runelite-client/src/main/resources/net/runelite/client/plugins/microbot/util/antiban/icons/general.png new file mode 100644 index 0000000000..29c0bd9024 Binary files /dev/null and b/runelite-client/src/main/resources/net/runelite/client/plugins/microbot/util/antiban/icons/general.png differ diff --git a/runelite-client/src/main/resources/net/runelite/client/plugins/microbot/util/antiban/icons/microbreak.png b/runelite-client/src/main/resources/net/runelite/client/plugins/microbot/util/antiban/icons/microbreak.png new file mode 100644 index 0000000000..4366beb710 Binary files /dev/null and b/runelite-client/src/main/resources/net/runelite/client/plugins/microbot/util/antiban/icons/microbreak.png differ diff --git a/runelite-client/src/main/resources/net/runelite/client/plugins/microbot/util/antiban/icons/mistake.png b/runelite-client/src/main/resources/net/runelite/client/plugins/microbot/util/antiban/icons/mistake.png new file mode 100644 index 0000000000..e69de29bb2 diff --git a/runelite-client/src/main/resources/net/runelite/client/plugins/microbot/util/antiban/icons/mouse.png b/runelite-client/src/main/resources/net/runelite/client/plugins/microbot/util/antiban/icons/mouse.png new file mode 100644 index 0000000000..7c2b65b040 Binary files /dev/null and b/runelite-client/src/main/resources/net/runelite/client/plugins/microbot/util/antiban/icons/mouse.png differ diff --git a/runelite-client/src/main/resources/net/runelite/client/plugins/microbot/util/antiban/icons/profile.png b/runelite-client/src/main/resources/net/runelite/client/plugins/microbot/util/antiban/icons/profile.png new file mode 100644 index 0000000000..e2befb921f Binary files /dev/null and b/runelite-client/src/main/resources/net/runelite/client/plugins/microbot/util/antiban/icons/profile.png differ diff --git a/runelite-client/src/main/resources/net/runelite/client/plugins/microbot/util/antiban/icons/timeout.png b/runelite-client/src/main/resources/net/runelite/client/plugins/microbot/util/antiban/icons/timeout.png new file mode 100644 index 0000000000..e69de29bb2 diff --git a/runelite-client/src/main/resources/net/runelite/client/plugins/microbot/util/antiban/microbreak.png b/runelite-client/src/main/resources/net/runelite/client/plugins/microbot/util/antiban/microbreak.png new file mode 100644 index 0000000000..ca4a767be7 Binary files /dev/null and b/runelite-client/src/main/resources/net/runelite/client/plugins/microbot/util/antiban/microbreak.png differ diff --git a/runelite-client/src/main/resources/net/runelite/client/plugins/microbot/util/antiban/mouse.png b/runelite-client/src/main/resources/net/runelite/client/plugins/microbot/util/antiban/mouse.png new file mode 100644 index 0000000000..ac4c05a997 Binary files /dev/null and b/runelite-client/src/main/resources/net/runelite/client/plugins/microbot/util/antiban/mouse.png differ diff --git a/runelite-client/src/main/resources/net/runelite/client/plugins/microbot/util/antiban/profile.png b/runelite-client/src/main/resources/net/runelite/client/plugins/microbot/util/antiban/profile.png new file mode 100644 index 0000000000..1e8cf63cc4 Binary files /dev/null and b/runelite-client/src/main/resources/net/runelite/client/plugins/microbot/util/antiban/profile.png differ diff --git a/runelite-client/src/main/resources/net/runelite/client/plugins/microbot/util/antiban/walkingduck.gif b/runelite-client/src/main/resources/net/runelite/client/plugins/microbot/util/antiban/walkingduck.gif new file mode 100644 index 0000000000..2a6526d7d0 Binary files /dev/null and b/runelite-client/src/main/resources/net/runelite/client/plugins/microbot/util/antiban/walkingduck.gif differ diff --git a/runelite-client/src/main/resources/net/runelite/client/plugins/microbot/util/antiban/walkingduckdark.gif b/runelite-client/src/main/resources/net/runelite/client/plugins/microbot/util/antiban/walkingduckdark.gif new file mode 100644 index 0000000000..61274bd01d Binary files /dev/null and b/runelite-client/src/main/resources/net/runelite/client/plugins/microbot/util/antiban/walkingduckdark.gif differ