l = lazy.get(index);
+ if (l != null) l.send(value);
+ }
+
+ @Override
+ public String toString() {
+ return "Pair{" +
+ "key='" + key + '\'' +
+ ", value=" + value +
+ '}';
+ }
+ }
+}
diff --git a/src/main/java/com/github/manolo8/darkbot/core/objects/swf/SwfPtrCollection.java b/src/main/java/com/github/manolo8/darkbot/core/objects/swf/SwfPtrCollection.java
new file mode 100644
index 00000000..7488c2e7
--- /dev/null
+++ b/src/main/java/com/github/manolo8/darkbot/core/objects/swf/SwfPtrCollection.java
@@ -0,0 +1,95 @@
+package com.github.manolo8.darkbot.core.objects.swf;
+
+import com.github.manolo8.darkbot.core.itf.Updatable;
+import com.github.manolo8.darkbot.core.itf.UpdatableAuto;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.function.Consumer;
+import java.util.function.Predicate;
+import java.util.function.Supplier;
+
+/**
+ * Represents a collection of pointers in SWF.
+ * Contains an utility method for syncing the pointers with java object collections.
+ */
+public abstract class SwfPtrCollection extends Updatable {
+ private long lastPointer;
+
+ /**
+ * @return size of the SWF collection
+ */
+ public abstract int getSize();
+
+ /**
+ * @param i The index to search
+ * @return The pointer the index points to to
+ */
+ public abstract long getPtr(int i);
+
+ /**
+ * Iterates over pointers in collection
+ * starting from last iterated + 1
+ *
+ * For example, if collection wasn't changed,
+ * order and pointers are the same,
+ * consumer wont be executed even once.
+ *
+ * @param consumer to execute
+ */
+ public void forEachIncremental(Consumer consumer) {
+ for (int i = indexOf(lastPointer) + 1; i < getSize(); i++)
+ consumer.accept(lastPointer = getPtr(i));
+ }
+
+ /**
+ * Iterates over all pointers in collection.
+ * @param consumer to execute
+ */
+ public void forEach(Consumer consumer) {
+ for (int i = 0; i < getSize(); i++)
+ consumer.accept(getPtr(i));
+ }
+
+ /**
+ * Search backwards pointer's index in collection
+ *
+ * @param value pointer to search
+ * @return index of pointer or -1 if doesnt exist
+ */
+ public int indexOf(long value) {
+ for (int i = getSize() - 1; i >= 0; i--)
+ if (value == getPtr(i)) return i;
+ return -1;
+ }
+
+ /**
+ * Syncs a java list to this SWF collection.
+ * @param list The java list to sync
+ * @param constructor The constructor for new instances of the object
+ * @param filter The filter to apply, if any objects should be ignored from the list
+ * @param The type the pointer is mapped to in java
+ * @return The leftover items that didn't match the filter
+ */
+ public List sync(List list,
+ Supplier constructor,
+ Predicate filter) {
+ int currSize = getSize(), listIdx = 0;
+ List ignored = new ArrayList<>();
+ for (int arrIdx = 0; arrIdx < currSize; listIdx++, arrIdx++) {
+ boolean newItem = list.size() <= listIdx;
+ T item = newItem ? constructor.get() : list.get(listIdx);
+ item.update(getPtr(arrIdx));
+ if (filter != null && !filter.test(item)) {
+ if (!newItem) list.remove(listIdx);
+ ignored.add(item);
+ listIdx--;
+ continue;
+ }
+ if (newItem) list.add(item);
+ }
+ while (list.size() > listIdx)
+ list.remove(list.size() - 1);
+ return ignored;
+ }
+}
diff --git a/src/main/java/com/github/manolo8/darkbot/core/objects/swf/VectorInt.java b/src/main/java/com/github/manolo8/darkbot/core/objects/swf/VectorInt.java
deleted file mode 100644
index f6bf5047..00000000
--- a/src/main/java/com/github/manolo8/darkbot/core/objects/swf/VectorInt.java
+++ /dev/null
@@ -1,46 +0,0 @@
-package com.github.manolo8.darkbot.core.objects.swf;
-
-import com.github.manolo8.darkbot.core.itf.Updatable;
-import com.github.manolo8.darkbot.core.utils.ByteUtils;
-
-import static com.github.manolo8.darkbot.Main.API;
-
-public class VectorInt extends Updatable {
-
- public int[] elements;
- public int size;
-
- public VectorInt() {
- this.elements = new int[0];
- this.size = 0;
- }
-
- public VectorInt(long address) {
- this();
- this.address = address;
- }
-
- @Override
- public void update() {
-
- int size = API.readMemoryInt(address + 64);
-
- if (size < 1 || size > 512) return;
-
- if (this.size < size) {
- elements = new int[size];
- }
-
- this.size = size;
-
- byte[] data = API.readMemory(API.readMemoryLong(address + 48) + 4, size * 4);
-
- int count = 0;
-
- for (int i = 0; i < data.length; i += 4) {
- elements[count++] = ByteUtils.getInt(data, i);
- }
-
- }
-
-}
diff --git a/src/main/java/com/github/manolo8/darkbot/core/utils/ByteUtils.java b/src/main/java/com/github/manolo8/darkbot/core/utils/ByteUtils.java
index bc228fc6..d60612ac 100644
--- a/src/main/java/com/github/manolo8/darkbot/core/utils/ByteUtils.java
+++ b/src/main/java/com/github/manolo8/darkbot/core/utils/ByteUtils.java
@@ -1,16 +1,19 @@
package com.github.manolo8.darkbot.core.utils;
public class ByteUtils {
+ public static final long FIX = 0xfffffffffff8L;
public static int getInt(byte[] data, int offset) {
- return data.length < offset + 4 ? 0 : ((data[offset + 3]) << 24) |
+ return data.length < offset + 4 ? 0 :
+ ((data[offset + 3]) << 24) |
((data[offset + 2] & 0xff) << 16) |
((data[offset + 1] & 0xff) << 8) |
((data[offset] & 0xff));
}
public static long getLong(byte[] data, int offset) {
- return data.length < offset + 8 ? 0 : (((long) data[offset + 7]) << 56) |
+ return data.length < offset + 8 ? 0 :
+ (((long) data[offset + 7]) << 56) |
(((long) data[offset + 6] & 0xff) << 48) |
(((long) data[offset + 5] & 0xff) << 40) |
(((long) data[offset + 4] & 0xff) << 32) |
@@ -20,23 +23,39 @@ public static long getLong(byte[] data, int offset) {
(((long) data[offset] & 0xff));
}
- public static byte[] getBytes(long... values) {
+ public static double getDouble(byte[] data, int offset) {
+ return Double.longBitsToDouble(getLong(data, offset));
+ }
- byte[] b = new byte[values.length * 8];
+ public static byte[] getBytes(int... values) {
+ byte[] b = new byte[values.length * 4];
int i = 0;
+ for (int v : values) {
+ b[i++] = (byte) ((v) & 0xff);
+ b[i++] = (byte) ((v >>> 8) & 0xff);
+ b[i++] = (byte) ((v >>> 16) & 0xff);
+ b[i++] = (byte) ((v >>> 24) & 0xff);
+ }
- for (long value : values) {
- b[i++] = (byte) value;
- b[i++] = (byte) (value >> 8);
- b[i++] = (byte) (value >> 16);
- b[i++] = (byte) (value >> 24);
- b[i++] = (byte) (value >> 32);
- b[i++] = (byte) (value >> 40);
- b[i++] = (byte) (value >> 48);
- b[i++] = (byte) (value >> 56);
+ return b;
+ }
+
+ public static byte[] getBytes(long... values) {
+ byte[] b = new byte[values.length * 8];
+
+ int i = 0;
+ for (long v : values) {
+ b[i++] = (byte) v;
+ b[i++] = (byte) (v >> 8);
+ b[i++] = (byte) (v >> 16);
+ b[i++] = (byte) (v >> 24);
+ b[i++] = (byte) (v >> 32);
+ b[i++] = (byte) (v >> 40);
+ b[i++] = (byte) (v >> 48);
+ b[i++] = (byte) (v >> 56);
}
return b;
}
-}
+}
\ No newline at end of file
diff --git a/src/main/java/com/github/manolo8/darkbot/core/utils/ClickPoint.java b/src/main/java/com/github/manolo8/darkbot/core/utils/ClickPoint.java
new file mode 100644
index 00000000..135723d9
--- /dev/null
+++ b/src/main/java/com/github/manolo8/darkbot/core/utils/ClickPoint.java
@@ -0,0 +1,14 @@
+package com.github.manolo8.darkbot.core.utils;
+
+public class ClickPoint {
+ public int x, y;
+ public ClickPoint(int x, int y) {
+ this.x = x;
+ this.y = y;
+ }
+
+ public synchronized void set(int x, int y) {
+ this.x = x;
+ this.y = y;
+ }
+}
diff --git a/src/main/java/com/github/manolo8/darkbot/core/utils/Drive.java b/src/main/java/com/github/manolo8/darkbot/core/utils/Drive.java
index de47e643..6e2a1d02 100644
--- a/src/main/java/com/github/manolo8/darkbot/core/utils/Drive.java
+++ b/src/main/java/com/github/manolo8/darkbot/core/utils/Drive.java
@@ -1,86 +1,156 @@
package com.github.manolo8.darkbot.core.utils;
+import com.github.manolo8.darkbot.Main;
+import com.github.manolo8.darkbot.config.ConfigEntity;
+import com.github.manolo8.darkbot.config.ZoneInfo;
import com.github.manolo8.darkbot.core.entities.Entity;
import com.github.manolo8.darkbot.core.manager.HeroManager;
import com.github.manolo8.darkbot.core.manager.MapManager;
+import com.github.manolo8.darkbot.core.manager.MouseManager;
import com.github.manolo8.darkbot.core.objects.LocationInfo;
import com.github.manolo8.darkbot.core.utils.pathfinder.PathFinder;
+import com.github.manolo8.darkbot.core.utils.pathfinder.PathPoint;
+import com.github.manolo8.darkbot.utils.MathUtils;
+
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Random;
-import static java.lang.Math.min;
import static java.lang.Math.random;
public class Drive {
- private final MapManager map;
+ private static final Random RANDOM = new Random();
+ private boolean force = false;
- private final LocationInfo heroLocation;
+ private final MapManager map;
+ private final MouseManager mouse;
+ private final HeroManager hero;
+ private final LocationInfo heroLoc;
public PathFinder pathFinder;
+ public LinkedList paths = new LinkedList<>();
- private Location destination;
+ private Location tempDest, endLoc, lastSegment = new Location();
+
+ private long lastDirChange;
+ private long lastClick;
+ public long lastMoved;
public Drive(HeroManager hero, MapManager map) {
this.map = map;
- this.heroLocation = hero.locationInfo;
- this.pathFinder = new PathFinder(map.entities.obstacles);
+ this.mouse = new MouseManager(map);
+ this.hero = hero;
+ this.heroLoc = hero.locationInfo;
+ this.pathFinder = new PathFinder(map);
}
public void checkMove() {
-
- if (destination != null) {
- pathFinder.createRote(heroLocation.now, destination);
- destination = null;
+ // Path-finder changed and bot is already traveling, re-create route
+ if (endLoc != null && pathFinder.changed() && tempDest == null) tempDest = endLoc;
+
+ boolean newPath = tempDest != null;
+ if (newPath) { // Calculate new path
+ if (endLoc == null) endLoc = tempDest; // Should never happen
+ paths = pathFinder.createRote(heroLoc.now, tempDest);
+ tempDest = null;
}
- if (pathFinder.isEmpty() || !heroLocation.isLoaded())
+ if (paths.isEmpty() || !heroLoc.isLoaded())
return;
- Location now = heroLocation.now;
- Location destination = pathFinder.current();
-
- double distance = now.distance(destination);
-
- if (!heroLocation.isMoving())
- map.translateMousePress(now.x, now.y);
-
- if (distance > 100) {
-
- distance = min(distance, 200);
-
- double angle = destination.angle(now);
-
- map.translateMouseMove(
- Math.cos(angle) * distance + now.x,
- Math.sin(angle) * distance + now.y
- );
-
+ lastMoved = System.currentTimeMillis();
+
+ Location now = heroLoc.now, last = heroLoc.last, next = current();
+ if (next == null) return;
+ newPath |= !next.equals(lastSegment);
+ if (newPath) {
+ // If direction roughly similar, and changed dir little ago, and you're still gonna be moving, ignore change
+ // This smooths out paths in short distances
+ if (next.distance(lastSegment) + (System.currentTimeMillis() - lastDirChange) < 500 &&
+ hero.timeTo(now.distance(lastSegment)) > 50) return;
+ lastDirChange = System.currentTimeMillis();
+ }
+ lastSegment = next;
+
+ if (newPath || hero.timeTo(now.distance(next)) > 25) {
+ double dirAngle = next.angle(last),
+ maxDiff = Math.max(0.02, MathUtils.angleDiff(next.angle(Location.of(heroLoc.last, dirAngle + (Math.PI / 2), 100)), dirAngle));
+ if (!newPath && heroLoc.isMoving() && MathUtils.angleDiff(heroLoc.angle, dirAngle) < maxDiff) {
+ if (System.currentTimeMillis() - lastDirChange > 2000) {
+ click(next);
+ lastDirChange = System.currentTimeMillis();
+ }
+ return;
+ }
+
+ if (!force && heroLoc.isMoving() && System.currentTimeMillis() - lastDirChange > 350) stop(false);
+ else {
+ if (!newPath && System.currentTimeMillis() - lastDirChange > 300) tempDest = endLoc; // Re-calculate path next tick
+ if (now.distance(next) < 100) click(Location.of(heroLoc.now, heroLoc.now.angle(next), 150));
+ else click(next);
+ }
} else {
+ synchronized (Main.UPDATE_LOCKER) {
+ paths.removeFirst();
+ }
+ if (paths.isEmpty()) {
+ if (this.endLoc.equals(lastRandomMove)) lastRandomMove = null;
+ this.endLoc = this.tempDest = null;
+ }
+ }
+ }
- pathFinder.currentCompleted();
+ private Location current() {
+ if (paths.isEmpty()) return null;
+ PathPoint point = paths.getFirst();
+ return new Location(point.x, point.y);
+ }
- map.translateMouseMoveRelease(
- destination.x,
- destination.y
- );
+ private void click(Location loc) {
+ if (System.currentTimeMillis() - lastClick > 150) {
+ lastClick = System.currentTimeMillis();
+ mouse.clickLoc(loc);
}
-
}
public boolean canMove(Location location) {
- return pathFinder.canMove(location);
+ return !map.isOutOfMap(location.x, location.y) && pathFinder.canMove((int) location.x, (int) location.y);
}
- public void stop() {
- map.translateMouseMoveRelease(heroLocation.now.x, heroLocation.now.y);
+ public double closestDistance(Location location) {
+ PathPoint closest = pathFinder.fixToClosest(new PathPoint((int) location.x, (int) location.y));
+ return location.distance(closest.toLocation());
+ }
- if (!pathFinder.isEmpty()) {
- pathFinder.path().clear();
+ public double distanceBetween(Location loc, int x, int y) {
+ double sum = 0;
+ PathPoint begin = new PathPoint((int) loc.x, (int) loc.y);
+ for (PathPoint curr : pathFinder.createRote(begin, new PathPoint(x, y)))
+ sum += Math.sqrt(Math.pow(begin.x - curr.x, 2) + Math.pow(begin.y - curr.y, 2));
+ return sum;
+ }
+
+ public void toggleRunning(boolean running) {
+ this.force = running;
+ stop(true);
+ }
+
+ public void stop(boolean current) {
+ if (heroLoc.isMoving() && current) {
+ Location stopLoc = heroLoc.now.copy();
+ stopLoc.toAngle(heroLoc.now, heroLoc.last.angle(heroLoc.now), 100);
+ mouse.clickLoc(stopLoc);
}
+
+ endLoc = tempDest = null;
+ if (!paths.isEmpty()) paths = new LinkedList<>();
}
- public void clickCenter(int times) {
- for (int i = 0; i != times; i++)
- map.translateMouseClick(heroLocation.now.x, heroLocation.now.y);
+ public void clickCenter(boolean single, Location aim) {
+ mouse.clickCenter(single, aim);
}
public void move(Entity entity) {
@@ -92,18 +162,54 @@ public void move(Location location) {
}
public void move(double x, double y) {
- destination = new Location(x, y);
+ Location newDir = new Location(x, y);
+ if (movingTo().distance(newDir) > 10) tempDest = endLoc = newDir;
}
+ private Location lastRandomMove;
+ private List lastZones;
+ private int lastZoneIdx;
public void moveRandom() {
- move(random() * MapManager.internalWidth, random() * MapManager.internalHeight);
+ ZoneInfo area = map.preferred;
+ boolean sequential = hero.main.config.GENERAL.ROAMING.SEQUENTIAL;
+
+ List zones = area == null ? Collections.emptyList() :
+ sequential ? area.getSortedZones() : area.getZones();
+ boolean changed = !zones.equals(lastZones);
+ lastZones = zones;
+
+ if ( hero.main.config.GENERAL.ROAMING.KEEP && !changed && lastRandomMove != null) {
+ move(lastRandomMove);
+ return;
+ }
+
+ if (changed && !lastZones.isEmpty()) {
+ Location search = lastRandomMove != null ? lastRandomMove : movingTo();
+ ZoneInfo.Zone closest = lastZones.stream().min(Comparator.comparingDouble(zone ->
+ zone.innerPoint(0.5, 0.5, MapManager.internalWidth, MapManager.internalHeight).distance(search))).orElse(null);
+ lastZoneIdx = lastZones.indexOf(closest);
+ }
+
+ if (lastZones.isEmpty()) {
+ lastRandomMove = new Location(random() * MapManager.internalWidth, random() * MapManager.internalHeight);
+ } else {
+ if (lastZoneIdx >= lastZones.size()) lastZoneIdx = 0;
+ ZoneInfo.Zone zone = lastZones.get(sequential ? lastZoneIdx++ : RANDOM.nextInt(zones.size()));
+
+ lastRandomMove = zone.innerPoint(random(), random(), MapManager.internalWidth, MapManager.internalHeight);
+ }
+ move(lastRandomMove);
}
public boolean isMoving() {
- return !pathFinder.isEmpty() || heroLocation.isMoving();
+ return !paths.isEmpty() || heroLoc.isMoving();
+ }
+
+ public Location movingTo() {
+ return endLoc == null ? heroLoc.now.copy() : endLoc.copy();
}
public boolean isOutOfMap() {
- return map.isOutOfMap(heroLocation.now.x, heroLocation.now.y);
+ return map.isOutOfMap(heroLoc.now.x, heroLoc.now.y);
}
}
diff --git a/src/main/java/com/github/manolo8/darkbot/core/utils/EntityList.java b/src/main/java/com/github/manolo8/darkbot/core/utils/EntityList.java
index 84eb1016..f4e69d04 100644
--- a/src/main/java/com/github/manolo8/darkbot/core/utils/EntityList.java
+++ b/src/main/java/com/github/manolo8/darkbot/core/utils/EntityList.java
@@ -1,208 +1,158 @@
package com.github.manolo8.darkbot.core.utils;
import com.github.manolo8.darkbot.Main;
-import com.github.manolo8.darkbot.core.entities.*;
+import com.github.manolo8.darkbot.config.NpcInfo;
+import com.github.manolo8.darkbot.core.entities.Barrier;
+import com.github.manolo8.darkbot.core.entities.BasePoint;
+import com.github.manolo8.darkbot.core.entities.BattleStation;
+import com.github.manolo8.darkbot.core.entities.Box;
+import com.github.manolo8.darkbot.core.entities.Entity;
+import com.github.manolo8.darkbot.core.entities.FakeNpc;
+import com.github.manolo8.darkbot.core.entities.Mine;
+import com.github.manolo8.darkbot.core.entities.NoCloack;
+import com.github.manolo8.darkbot.core.entities.Npc;
+import com.github.manolo8.darkbot.core.entities.Pet;
+import com.github.manolo8.darkbot.core.entities.Portal;
+import com.github.manolo8.darkbot.core.entities.Ship;
import com.github.manolo8.darkbot.core.itf.Obstacle;
import com.github.manolo8.darkbot.core.itf.Updatable;
-import com.github.manolo8.darkbot.core.objects.swf.Array;
+import com.github.manolo8.darkbot.core.objects.swf.ObjArray;
+import com.github.manolo8.darkbot.core.utils.factory.EntityFactory;
+import com.github.manolo8.darkbot.core.utils.factory.EntityRegistry;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
+import java.util.Set;
import java.util.function.Consumer;
import static com.github.manolo8.darkbot.Main.API;
+import static com.github.manolo8.darkbot.core.utils.factory.EntityFactory.*;
public class EntityList extends Updatable {
+ public final EntityRegistry entityRegistry = new EntityRegistry();
+
+ public final List obstacles = new ArrayList<>();
+ public final List> allEntities = new ArrayList<>();
+
+ public final List barriers = register(BARRIER);
+ public final List noCloack = register(MIST_ZONE);
+ public final List boxes = register(BOX, ORE);
+ public final List