diff --git a/runelite-client/pom.xml b/runelite-client/pom.xml
index cf97c83f24..3a595bbaae 100644
--- a/runelite-client/pom.xml
+++ b/runelite-client/pom.xml
@@ -54,7 +54,7 @@
net.runelit
flexo
- 1.0.1
+ 1.0.2
org.slf4j
diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/flexo/FlexoConfig.java b/runelite-client/src/main/java/net/runelite/client/plugins/flexo/FlexoConfig.java
new file mode 100644
index 0000000000..245ae886a6
--- /dev/null
+++ b/runelite-client/src/main/java/net/runelite/client/plugins/flexo/FlexoConfig.java
@@ -0,0 +1,208 @@
+/*
+ * Copyright (c) 2018, Adam
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package net.runelite.client.plugins.flexo;
+
+import net.runelite.client.config.Config;
+import net.runelite.client.config.ConfigGroup;
+import net.runelite.client.config.ConfigItem;
+
+@ConfigGroup("flexo")
+public interface FlexoConfig extends Config {
+
+ @ConfigItem(
+ position = 0,
+ keyName = "overlayEnabled",
+ name = "Overlay Enabled",
+ description = "Shows clicking area and points etc."
+ )
+ default boolean overlayEnabled() {
+ return true;
+ }
+
+ @ConfigItem(
+ position = 1,
+ keyName = "minDelayAmount",
+ name = "Min Delay",
+ description = "Minimum delay that is applied to every action at the end (ms)"
+ )
+ default int minDelayAmt() {
+ return 45;
+ }
+
+
+ @ConfigItem(
+ position = 2,
+ keyName = "reactionTime",
+ name = "Reaction Time",
+ description = "The base time between actions (ms)"
+ )
+ default int getReactionTimeVariation() {
+ return 80;
+ }
+
+ @ConfigItem(
+ position = 3,
+ keyName = "mouseDragSpeed",
+ name = "Mouse drag speed",
+ description = "The speed at which steps are executed. Keep at 49? cuz jagex mouse recorder?"
+ )
+ default int getMouseDragSpeed() {
+ return 49;
+ }
+
+
+ @ConfigItem(
+ position = 4,
+ keyName = "overshoots",
+ name = "Overshoots",
+ description = "Higher number = more overshoots"
+ )
+ default int getOvershoots() {
+ return 4;
+ }
+
+ @ConfigItem(
+ position = 5,
+ keyName = "variatingFlow",
+ name = "Flow - Variating",
+ description = ""
+ )
+ default boolean getVariatingFlow() {
+ return true;
+ }
+
+ @ConfigItem(
+ position = 6,
+ keyName = "slowStartupFlow",
+ name = "Flow - Slow startup",
+ description = ""
+ )
+ default boolean getSlowStartupFlow() {
+ return true;
+ }
+
+
+ @ConfigItem(
+ position = 7,
+ keyName = "slowStartup2Flow",
+ name = "Flow - Slow startup 2",
+ description = ""
+ )
+ default boolean getSlowStartup2Flow() {
+ return true;
+ }
+
+ @ConfigItem(
+ position = 8,
+ keyName = "jaggedFlow",
+ name = "Flow - Jagged",
+ description = ""
+ )
+ default boolean getJaggedFlow() {
+ return true;
+ }
+
+ @ConfigItem(
+ position = 9,
+ keyName = "interruptedFlow",
+ name = "Flow - Interrupted",
+ description = ""
+ )
+ default boolean getInterruptedFlow() {
+ return false;
+ }
+
+
+ @ConfigItem(
+ position = 10,
+ keyName = "interruptedFlow2",
+ name = "Flow - Interrupted 2",
+ description = ""
+ )
+ default boolean getInterruptedFlow2() {
+ return false;
+ }
+
+ @ConfigItem(
+ position = 11,
+ keyName = "stoppingFlow",
+ name = "Flow - Stopping",
+ description = ""
+ )
+ default boolean getStoppingFlow() {
+ return false;
+ }
+
+ @ConfigItem(
+ position = 12,
+ keyName = "deviationSlopeDivider",
+ name = "Deviation slope divider",
+ description = ""
+ )
+ default int getDeviationSlope() {
+ return 10;
+ }
+
+
+ @ConfigItem(
+ position = 13,
+ keyName = "noisinessDivider",
+ name = "Noisiness divider",
+ description = ""
+ )
+ default String getNoisinessDivider() {
+ return "2.0D";
+ }
+
+ @ConfigItem(
+ position = 14,
+ keyName = "debugNPCs",
+ name = "Debug NPCs",
+ description = "Draws clickArea and clickPoints across all visible npcs"
+ )
+ default boolean getDebugNPCs() {
+ return false;
+ }
+
+ @ConfigItem(
+ position = 15,
+ keyName = "debugPlayers",
+ name = "Debug Players",
+ description = "Draws clickArea and clickPoints across all visible players"
+ )
+ default boolean getDebugPlayers() {
+ return false;
+ }
+
+ @ConfigItem(
+ position = 16,
+ keyName = "debugGroundItems",
+ name = "Debug Ground Items",
+ description = "Draws clickArea and clickPoints across all visible ground items"
+ )
+ default boolean getDebugGroundItems() {
+ return false;
+ }
+}
diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/flexo/FlexoOverlay.java b/runelite-client/src/main/java/net/runelite/client/plugins/flexo/FlexoOverlay.java
new file mode 100644
index 0000000000..a3a05c2ca0
--- /dev/null
+++ b/runelite-client/src/main/java/net/runelite/client/plugins/flexo/FlexoOverlay.java
@@ -0,0 +1,65 @@
+package net.runelite.client.plugins.flexo;
+
+import net.runelite.api.Client;
+import net.runelite.client.ui.overlay.Overlay;
+import net.runelite.client.ui.overlay.OverlayLayer;
+import net.runelite.client.ui.overlay.OverlayPosition;
+
+import javax.annotation.Nullable;
+import javax.inject.Inject;
+import java.awt.*;
+import java.awt.geom.Line2D;
+import java.util.ArrayList;
+
+public class FlexoOverlay extends Overlay {
+
+ public static Rectangle clickArea;
+ public ArrayList clickAreas = new ArrayList<>();
+ public ArrayList clickPoints = new ArrayList<>();
+
+ @Inject
+ private Client client;
+
+ @Inject
+ private FlexoPlugin plugin;
+
+ @Inject
+ private FlexoConfig config;
+
+ @Inject
+ public FlexoOverlay(@Nullable Client client, FlexoPlugin plugin, FlexoConfig config) {
+ setPosition(OverlayPosition.DYNAMIC);
+ setLayer(OverlayLayer.ABOVE_WIDGETS);
+ this.client = client;
+ this.plugin = plugin;
+ this.config = config;
+ }
+
+
+ @Override
+ public Dimension render(Graphics2D graphics) {
+ if (config.getDebugNPCs() || config.getDebugGroundItems() || config.getDebugPlayers()) {
+ if (clickArea!=null)
+ graphics.draw(clickArea);
+ if (clickAreas!=null) {
+ for (Rectangle clickArea : clickAreas) {
+ if (clickArea!=null)
+ graphics.draw(clickArea);
+ }
+ }
+ if (clickPoints!=null) {
+ for (Point p : clickPoints) {
+ if (p!=null) {
+ graphics.setColor(Color.MAGENTA);
+ graphics.draw(new Line2D.Double(p.x, p.y, p.x, p.y));
+ graphics.draw(new Line2D.Double(p.x-1, p.y-1, p.x-1, p.y-1));
+ graphics.draw(new Line2D.Double(p.x+1, p.y+1, p.x+1, p.y+1));
+ graphics.draw(new Line2D.Double(p.x-1, p.y+1, p.x-1, p.y+1));
+ graphics.draw(new Line2D.Double(p.x+1, p.y-1, p.x+1, p.y-1));
+ }
+ }
+ }
+ }
+ return null;
+ }
+}
diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/flexo/FlexoPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/flexo/FlexoPlugin.java
new file mode 100644
index 0000000000..0e1bdbe4d8
--- /dev/null
+++ b/runelite-client/src/main/java/net/runelite/client/plugins/flexo/FlexoPlugin.java
@@ -0,0 +1,200 @@
+package net.runelite.client.plugins.flexo;
+
+import com.github.joonasvali.naturalmouse.api.MouseMotionFactory;
+import com.github.joonasvali.naturalmouse.support.DefaultNoiseProvider;
+import com.github.joonasvali.naturalmouse.support.DefaultOvershootManager;
+import com.github.joonasvali.naturalmouse.support.DefaultSpeedManager;
+import com.github.joonasvali.naturalmouse.support.Flow;
+import com.github.joonasvali.naturalmouse.support.SinusoidalDeviationProvider;
+import com.github.joonasvali.naturalmouse.util.FlowTemplates;
+import com.google.inject.Provides;
+import net.runelite.api.Client;
+import net.runelite.api.NPC;
+import net.runelite.api.Perspective;
+import net.runelite.api.Player;
+import net.runelite.api.coords.LocalPoint;
+import net.runelite.api.events.BeforeRender;
+import net.runelite.api.events.ConfigChanged;
+import net.runelite.api.events.GameTick;
+import net.runelite.client.config.ConfigManager;
+import net.runelite.client.eventbus.Subscribe;
+import net.runelite.client.flexo.Flexo;
+import net.runelite.client.flexo.FlexoMouse;
+import net.runelite.client.plugins.Plugin;
+import net.runelite.client.plugins.PluginDescriptor;
+import net.runelite.client.plugins.PluginType;
+import net.runelite.client.plugins.grounditems.GroundItem;
+import net.runelite.client.plugins.grounditems.GroundItemsPlugin;
+import net.runelite.client.plugins.stretchedmode.StretchedModeConfig;
+import net.runelite.client.ui.overlay.OverlayManager;
+
+import javax.inject.Inject;
+import java.awt.*;
+import java.util.ArrayList;
+import java.util.List;
+
+@PluginDescriptor(
+ name = "Flexo Config",
+ description = "Customizes the flexo api",
+ tags = {"flexo", "null"},
+ type = PluginType.UTILITY
+)
+public class FlexoPlugin extends Plugin {
+
+ private Flexo flexo;
+
+ {
+ try {
+ flexo = new Flexo();
+ } catch (AWTException e) {
+ e.printStackTrace();
+ }
+ }
+
+ @Inject
+ private Client client;
+
+ @Inject
+ private ConfigManager configManager;
+
+ @Inject
+ private OverlayManager overlayManager;
+
+ @Inject
+ private FlexoOverlay overlay;
+
+ @Provides
+ FlexoConfig getConfig(ConfigManager configManager) {
+ return configManager.getConfig(FlexoConfig.class);
+ }
+
+ @Subscribe
+ private void onConfigChanged(ConfigChanged event) {
+ if (event.getKey().compareTo("overlayEnabled")==0) {
+ if (getConfig(configManager).overlayEnabled()) {
+ overlayManager.add(overlay);
+ } else {
+ overlayManager.remove(overlay);
+ }
+ }
+ updateMouseMotionFactory();
+ }
+
+
+ @Subscribe
+ public void onBeforeRender(BeforeRender event) {
+ if (Flexo.client==null)
+ Flexo.client = client;
+ overlay.clickAreas = new ArrayList<>();
+ overlay.clickPoints = new ArrayList<>();
+ if (getConfig(configManager).getDebugNPCs()) {
+ Flexo.isStretched = client.isStretchedEnabled();
+ Flexo.scale = configManager.getConfig(StretchedModeConfig.class).scalingFactor();
+ if (flexo != null)
+ for (NPC npc : client.getNpcs()) {
+ if (npc != null)
+ if (npc.getConvexHull() != null) {
+ Rectangle r = FlexoMouse.getClickArea(npc.getConvexHull().getBounds());
+ overlay.clickAreas.add(r);
+ java.awt.Point p = FlexoMouse.getClickPoint(r);
+ overlay.clickPoints.add(p);
+ }
+ }
+ }
+
+ if (getConfig(configManager).getDebugPlayers()) {
+ Flexo.isStretched = client.isStretchedEnabled();
+ Flexo.scale = configManager.getConfig(StretchedModeConfig.class).scalingFactor();
+ if (flexo != null)
+ for (Player player : client.getPlayers()) {
+ if (player != null)
+ if (player.getConvexHull() != null) {
+ Rectangle r = FlexoMouse.getClickArea(player.getConvexHull().getBounds());
+ overlay.clickAreas.add(r);
+ java.awt.Point p = FlexoMouse.getClickPoint(r);
+ overlay.clickPoints.add(p);
+ }
+ }
+ }
+
+ //Could still use some improvement
+ if (getConfig(configManager).getDebugGroundItems()) {
+ Flexo.isStretched = client.isStretchedEnabled();
+ Flexo.scale = configManager.getConfig(StretchedModeConfig.class).scalingFactor();
+ if (flexo != null)
+ if (GroundItemsPlugin.getCollectedGroundItems()!=null)
+ for (GroundItem gi : GroundItemsPlugin.getCollectedGroundItems().values()) {
+ if (gi != null)
+ if (Perspective.getCanvasTilePoly(client, LocalPoint.fromWorld(client, gi.getLocation()))!=null) {
+ Rectangle r1 = FlexoMouse.getClickArea(Perspective.getCanvasTilePoly(client, LocalPoint.fromWorld(client, gi.getLocation())).getBounds());
+ Rectangle r2 = FlexoMouse.getClickArea(r1);
+ Rectangle r3 = FlexoMouse.getClickArea(r2);
+ overlay.clickAreas.add(r3);
+ java.awt.Point p = FlexoMouse.getClickPoint(r3);
+ overlay.clickPoints.add(p);
+ }
+ }
+ }
+ }
+
+ @Subscribe
+ public void onGameTick(GameTick event) {
+
+ }
+
+ private void updateMouseMotionFactory() {
+ Flexo.minDelay = getConfig(configManager).minDelayAmt();
+ MouseMotionFactory factory = new MouseMotionFactory();
+ //TODO:Add Options for various flows to allow more personalization
+ List flows = new ArrayList<>();
+
+ //Always add random
+ flows.add(new Flow(FlowTemplates.random()));
+
+ if (getConfig(configManager).getVariatingFlow())
+ flows.add(new Flow(FlowTemplates.variatingFlow()));
+
+ if (getConfig(configManager).getSlowStartupFlow())
+ flows.add(new Flow(FlowTemplates.slowStartupFlow()));
+
+ if (getConfig(configManager).getSlowStartup2Flow())
+ flows.add(new Flow(FlowTemplates.slowStartup2Flow()));
+
+ if (getConfig(configManager).getJaggedFlow())
+ flows.add(new Flow(FlowTemplates.jaggedFlow()));
+
+ if (getConfig(configManager).getInterruptedFlow())
+ flows.add(new Flow(FlowTemplates.interruptedFlow()));
+
+ if (getConfig(configManager).getInterruptedFlow2())
+ flows.add(new Flow(FlowTemplates.interruptedFlow2()));
+
+ if (getConfig(configManager).getStoppingFlow())
+ flows.add(new Flow(FlowTemplates.stoppingFlow()));
+
+ DefaultSpeedManager manager = new DefaultSpeedManager(flows);
+ //TODO:Add options for custom Deviation Provider and Noise Provider
+ factory.setDeviationProvider(new SinusoidalDeviationProvider(getConfig(configManager).getDeviationSlope()));
+ factory.setNoiseProvider(new DefaultNoiseProvider(Double.valueOf(getConfig(configManager).getNoisinessDivider())));
+ factory.getNature().setReactionTimeVariationMs(getConfig(configManager).getReactionTimeVariation());
+ manager.setMouseMovementBaseTimeMs(getConfig(configManager).getMouseDragSpeed());
+
+ DefaultOvershootManager overshootManager = (DefaultOvershootManager) factory.getOvershootManager();
+ overshootManager.setOvershoots(getConfig(configManager).getOvershoots());
+
+ factory.setSpeedManager(manager);
+ Flexo.currentMouseMotionFactory = factory;
+ }
+
+ @Override
+ protected void startUp() throws Exception {
+ Flexo.isStretched = client.isStretchedEnabled();
+ overlayManager.add(overlay);
+ updateMouseMotionFactory();
+ }
+
+ @Override
+ protected void shutDown() throws Exception {
+ overlayManager.remove(overlay);
+ }
+}