Jump to content

Leaderboard

Popular Content

Showing content with the highest reputation on 07/01/13 in all areas

  1. Hello, Seemingly people have been requesting me for my mythology for walking threw regions, without having the clients pathfinder break. The reason why it breaks it because your destination, is as close to your current region as you can get (Collision dependent) , and most likely you're right next to it, so you've reached the maximum 'farthest' position that your current region can support path finding to. So you're suck, because you must be right before the area were runescape will load your next region (bad luck), and thus restricts the client from being able to find a path for the next position (Which would be within a neighboring region). How my method works is by combing the reliability of a pre-build path, with the optimization and randomcy of a regional flood agent (Pathfinder). It'll use the pre-build tile path (I call it a spline), when path finding is impossible, or you're within the 'zone' of were runescape is about to load the next region, this is to avoid you're player from pausing, or breaking when runescape loads you're new region (more human). It uses the spline, as way points and hints to were it should work to get to next. It also allow you to break the walking, conditionally based (like while this is true, keep working, else stop.) Example of it in work: http://youtu.be/tvNGQB3m_UE What I use for my flood agent, is a shortest distance tree, which is optimized for speed, and does not require a heuristics function, unlike A*, you can use something different, it does not matter really. The drawback of this method is the spline must be FULLY WALKABLE from A to B, and to get from B to A you must reverse the spline. I clone and reverse the elements, since i'm lazy . Most preferably I use a map utility called OMU (Overload Map Utility), made for p****bot, under some dude, what it does it'll make a tile path from A to B, as compact as you want (1) (The less space within the 'spline' from neighbor to neighbor, the better; ex: Tile(1,1,0), Tile(1, 2, 0), Tile(1,3,0)). Example of a spline (note: not checked to ensure every position is walkable): Download link to jar (google if you don't true me): https://dl.dropboxusercontent.com/u/58848692/OMU.jar What must be going through you're head is, 'I have to check every dam tile to be walkable...?'. But I have to say, have not fear, path finding is hear. Pathfinding is cool, because it if it can't find a path, then it's just not walkable (let's hope). So you can for loop it, like this: public boolean isRegional(Position position) { int baseX = position.getX() - client.getMapBaseX(); int baseY = position.getY() - client.getMapBaseY(); return baseX >= 16 && baseX <= 88 && baseY >= 16 && baseY <= 88; //I think runescape loads @ 16 and nulls collisions at the borders? } public void whatIsNotWalkableWithinMyRegion(Position[] mySpline) { for(Position node : mySpline) { if(!isRegional(node)) continue; //Can't truly verify if it's walkable, since we don't have the collision data for it. //So we would need make that position regional to correctly verify. if (pathfinder.findPath(myPosition(), node, false).length == 0) { System.out.println("Oww darn, this regional position is not walkable, plz fix: " + node); } } } Cool beans? Now for the googies? Please keep in mind this entire method was made to just work, and I'm sure there is methods to improve it's performances and structure, but the bellow code is all the methods I used in the above video. Take note of the TODO's for you'll have to do some housekeeping adjustments, mainly for randomcy. Also, I would split the sub classes for obvious reasons, I just did this so I don't have to post all 4 classes (so lazy right now ). Keep tuned for an exact replica of the videos use of this method. import org.osbot.script.mouse.MinimapTileDestination; import org.osbot.script.rs2.Client; import org.osbot.script.rs2.map.Position; import java.util.*; /** * @author Brainfree * It'll get the job done. */ public class PackedSplineWalk { public static final int BASE_LENGTH = 104; public static final int BASE_BOUNDARY = BASE_LENGTH - 1; public static final int WALL_NORTH_WEST = 0x1; public static final int WALL_NORTH = 0x2; public static final int WALL_NORTH_EAST = 0x4; public static final int WALL_EAST = 0x8; public static final int WALL_SOUTH_EAST = 0x10; public static final int WALL_SOUTH = 0x20; public static final int WALL_SOUTH_WEST = 0x40; public static final int WALL_WEST = 0x80; public static final int BLOCKED = 0x100; public interface Conditional { //All hail public boolean isActive(); } public abstract class FloodAgent { public int[][] flags; public int base_x, base_maxX, base_y, base_maxY, curr_plane; public final Client bot; public FloodAgent(Client bot) { this.bot = bot; } public void updateBase() { if (base_x != bot.getMapBaseX() || base_y != bot.getClient().getMapBaseY() || curr_plane != bot.getClient().getPlane()) { base_x = bot.getClient().getMapBaseX(); base_maxX = base_x + 104; base_y = bot.getClient().getMapBaseY(); base_maxY = base_y + 104; curr_plane = bot.getClient().getPlane(); flags = adjustCollisionFlags(bot.getClient().getClippingPlanes() [bot.getClient().getPlane()].getTileFlags()); } } private int[][] adjustCollisionFlags(final int[][] flags) { final int lx = flags.length - 1; final int lx_m = lx - 5; for (int x = 0; x <= lx; x++) { final int ly = flags[x].length - 1; final int ly_m = ly - 5; for (int y = 0; y <= ly; y++) { if (x <= 5 || y <= 5 || x >= lx_m || y >= ly_m) { flags[x][y] = -1; } } } return flags; } public abstract Position[] findPath(Position from, Position to, boolean fullFlood); } public enum DirectionalOrientation { NORTH_WEST(-1, 1, 135) { @Override public boolean walkable(int[][] flags, int f_x, int f_y, int here) { return (f_x > 0 && f_y < BASE_BOUNDARY && (here & (WALL_NORTH_WEST | WALL_NORTH | WALL_WEST)) == 0 && (flags[f_x - 1][f_y + 1] & BLOCKED) == 0 && (flags[f_x][f_y + 1] & (BLOCKED | WALL_WEST)) == 0 && (flags[f_x - 1][f_y] & (BLOCKED | WALL_NORTH)) == 0); } }, NORTH(0, 1, 90) { @Override public boolean walkable(int[][] flags, int f_x, int f_y, int here) { return (f_y < BASE_BOUNDARY && (here & WALL_NORTH) == 0 && (flags[f_x][f_y + 1] & BLOCKED) == 0); } }, NORTH_EAST(1, 1, 45) { @Override public boolean walkable(int[][] flags, int f_x, int f_y, int here) { return (f_x > 0 && f_y < BASE_BOUNDARY && (here & (WALL_NORTH_EAST | WALL_NORTH | WALL_EAST)) == 0 && (flags[f_x + 1][f_y + 1] & BLOCKED) == 0 && (flags[f_x][f_y + 1] & (BLOCKED | WALL_EAST)) == 0 && (flags[f_x + 1][f_y] & (BLOCKED | WALL_NORTH)) == 0); } ; }, EAST(1, 0, 0) { @Override public boolean walkable(int[][] flags, int f_x, int f_y, int here) { return (f_x < BASE_BOUNDARY && (here & WALL_EAST) == 0 && (flags[f_x + 1][f_y] & BLOCKED) == 0); } }, SOUTH_EAST(1, -1, 315) { @Override public boolean walkable(int[][] flags, int f_x, int f_y, int here) { return (f_x < BASE_BOUNDARY && f_y > 0 && (here & (WALL_SOUTH_EAST | WALL_SOUTH | WALL_EAST)) == 0 && (flags[f_x + 1][f_y - 1] & BLOCKED) == 0 && (flags[f_x][f_y - 1] & (BLOCKED | WALL_EAST)) == 0 && (flags[f_x + 1][f_y] & (BLOCKED | WALL_SOUTH)) == 0); } }, SOUTH(0, -1, 270) { @Override public boolean walkable(int[][] flags, int f_x, int f_y, int here) { return (f_y > 0 && (here & WALL_SOUTH) == 0 && (flags[f_x][f_y - 1] & BLOCKED) == 0); } }, SOUTH_WEST(-1, -1, 225) { @Override public boolean walkable(int[][] flags, int f_x, int f_y, int here) { return (f_x > 0 && f_y > 0 && (here & (WALL_SOUTH_WEST | WALL_SOUTH | WALL_WEST)) == 0 && (flags[f_x - 1][f_y - 1] & BLOCKED) == 0 && (flags[f_x][f_y - 1] & (BLOCKED | WALL_WEST)) == 0 && (flags[f_x - 1][f_y] & (BLOCKED | WALL_SOUTH)) == 0); } }, WEST(-1, 0, 180) { @Override public boolean walkable(int[][] flags, int f_x, int f_y, int here) { return (f_x > 0 && (here & WALL_WEST) == 0 && (flags[f_x - 1][f_y] & BLOCKED) == 0); } }; public abstract boolean walkable(int[][] flags, int f_x, int f_y, int here); public final int x_shift, y_shift, angle; DirectionalOrientation(int x_shift, int y_shift, int angle) { this.x_shift = x_shift; this.y_shift = y_shift; this.angle = angle; } } public class BitPathfinder extends FloodAgent { public static final int INFINITE_DISTANCE = Integer.MAX_VALUE; private static final int INITIAL_CAPACITY = 8; //what ever floats your boat private final Set<Integer> settledNodes; private final Map<Integer, Double> shortestDistances; private final double Cross = Math.sqrt(2); private final Comparator<Integer> shortestDistanceComparator = new Comparator<Integer>() { public int compare(Integer left, Integer right) { return Double.compare(getShortestDistance(left), getShortestDistance(right)); } }; private final PriorityQueue<Integer> unsettledNodes = new PriorityQueue<>( INITIAL_CAPACITY, shortestDistanceComparator ); private final Map<Integer, Integer> predecessors = new HashMap<>(); public BitPathfinder(Client client) { super(client); this.settledNodes = new HashSet<>(); this.shortestDistances = new HashMap<>(); } private void init(Integer start) { clear(); setShortestDistance(start, 0); unsettledNodes.add(start); } public void execute(Integer start, Integer destination, boolean fullFlood) { init(start); Integer u; while ((u = unsettledNodes.poll()) != null) { if (!fullFlood && u == destination) break; settledNodes.add(u); relaxNeighbors(u); } } //TODO so lazy, overkill bit shifting, does not matter tbh. public int makePositionHash(int x, int y, int z) { return (z << 28 | x << 14 | y); } public int[] getDestinations(int hash) { int x = (hash >> 14) & 0xFF; int y = hash & 0xFF; int[] nodes = new int[0]; for (DirectionalOrientation orientation : DirectionalOrientation.values()) { if (orientation.walkable(flags, x, y, flags[x][y])) { nodes = Arrays.copyOf(nodes, nodes.length + 1); //fk lists nodes[nodes.length - 1] = makePositionHash(x + orientation.x_shift, y + orientation.y_shift, curr_plane); } } return nodes; } private void relaxNeighbors(Integer u) { for (int v : getDestinations(u)) { if (isSettled(v)) continue; int x = (v >> 14) & 0xFF - (u >> 14) & 0xFF; int y = v & 0xFF - u & 0xFF; double shortDist = getShortestDistance(u) + ( (Math.abs(x) > 0 && Math.abs(y) > 0) ? Cross : 1); if (shortDist < getShortestDistance(v)) { setShortestDistance(v, shortDist); setPredecessor(v, u); } } } private boolean isSettled(Integer v) { return settledNodes.contains(v); } private void setShortestDistance(int node, double distance) { unsettledNodes.remove(node); shortestDistances.put(node, distance); unsettledNodes.add(node); } private Integer getPredecessor(int node) { return predecessors.get(node); } private void setPredecessor(int a, int b) { predecessors.put(a, b); } public double getShortestDistance(int node) { Double d = shortestDistances.get(node); return (d == null) ? INFINITE_DISTANCE : d; } public Integer[] extractPath(int destination) { ArrayDeque<Integer> holder = new ArrayDeque<>(); for (Integer node = destination; node != null; node = getPredecessor(node)) holder.add(node); Integer[] a = holder.toArray(new Integer[holder.size()]); reverseOrder(a); return a; } public Position[] findPath(Position start, Position end, boolean fullFlood) { updateBase(); int Start = makePositionHash(start.getX() - base_x, start.getY() - base_y, curr_plane); int End = makePositionHash(end.getX() - base_x, end.getY() - base_y, curr_plane); if (Start == End) return new Position[0]; execute(Start, End, fullFlood); return convert(extractPath(End)); } public Position[] convert(Integer[] nodes) { Position[] real = new Position[nodes.length]; for (int i = 0; i < nodes.length; i++) { int hash = nodes[i]; real[i] = new Position(((hash >> 14) & 0xFF) + base_x, (hash & 0xFF) + base_y, curr_plane); } return real; } public void clear() { settledNodes.clear(); unsettledNodes.clear(); shortestDistances.clear(); predecessors.clear(); } } public static <T> void reverseOrder(T[] nodes) { int l = nodes.length; for (int j = 0; j < l / 2; j++) { T temp = nodes[j]; nodes[j] = nodes[l - j - 1]; nodes[l - j - 1] = temp; } } public class Timer { private long end; private final long start; private final long period; public Timer(final long period) { this.period = period; start = System.currentTimeMillis(); end = start + period; } public boolean isRunning() { return System.currentTimeMillis() < end; } public void reset() { end = System.currentTimeMillis() + period; } } public class SplineWalk { private final Client client; int runningSessionEnableRunThresh; final int MINIMAL_RUN_ENERGY = 30; final int LOCAL_BASE_COMPRESS = 16; final int compressionIndex = 7; public SplineWalk(Client client) { this.client = client; } public int myX() { return client.getMyPlayer().getPosition().getX(); } public int myY() { return client.getMyPlayer().getPosition().getY(); } public Position myPosition() { return client.getMyPlayer().getPosition(); } public double positionDistance(Position A, Position B) { return Math.hypot(A.getX() - B.getX(), A.getY() - B.getY()); } public double distanceTo(Position position) { return positionDistance(client.getMyPlayer().getPosition(), position); } public Position getFarthest(Position[] path) { if (path == null || path.length == 0) return null; Position best = null; Position destination = path[path.length - 1]; double bd = Integer.MAX_VALUE, hold; int distance = (int) (9 + (3 * Math.random() + 1.5)); for (Position node : path) { if ((hold = Math.hypot( node.getX() - destination.getX(), node.getY() - destination.getY())) < bd && distanceTo(node) < distance) { best = node; bd = hold; } } return best; } public boolean withinPreLoadZone(int x, int y, final int baseX, final int baseY) { int realX = baseX + LOCAL_BASE_COMPRESS; int realY = baseY + LOCAL_BASE_COMPRESS; //could clean this up.. int with = 104 - (2 * LOCAL_BASE_COMPRESS); int realX0 = baseX + LOCAL_BASE_COMPRESS + compressionIndex; int realY0 = baseY + LOCAL_BASE_COMPRESS + compressionIndex; int with0 = 104 - (2 * (LOCAL_BASE_COMPRESS + compressionIndex)); return x >= realX && x <= realX + with && y >= realY && y <= realY + with && !(x >= realX0 && x <= realX0 + with0 && y >= realY0 && y <= realY0 + with0); } public boolean isRegional(Position position) { int baseX = position.getX() - client.getMapBaseX(); int baseY = position.getY() - client.getMapBaseY(); return baseX >= LOCAL_BASE_COMPRESS && baseX <= 104 - LOCAL_BASE_COMPRESS && baseY >= LOCAL_BASE_COMPRESS && baseY <= 104 - LOCAL_BASE_COMPRESS; } public Position getRegionalNext(Position[] spline) { //We want the last element of the path. //TODO you can randomize it! Position goal = spline[spline.length - 1], best = spline[0]; //worst double bd = Integer.MAX_VALUE, hold; for (Position step : spline) { if (isRegional(step) && (hold = Math.hypot( goal.getX() - step.getX(), goal.getY() - step.getY())) < bd) { bd = hold; best = step; } } return best; } public boolean canOperate() { return client.getGameState() == 10 && client.getLoginState() == 30; } public boolean checkGameState() throws InterruptedException { if (!canOperate()) { Timer timer = new Timer(5500); while (timer.isRunning() && !canOperate()) Thread.sleep(0, 1); if (!timer.isRunning()) ; //Stop the script.. else return true; } return false; } public boolean splineWalk( FloodAgent pathfinder, Conditional keepWalking, Position[] spline) throws InterruptedException { Position[] path = null; Position next; int regionX = 0, regionY = 0; MinimapTileDestination mouseDestination; runningSessionEnableRunThresh = MINIMAL_RUN_ENERGY; //TODO you can randomize this while (keepWalking.isActive()) { checkGameState(); if (!withinPreLoadZone(myX(), myY(), regionX, regionY)) { if (regionX != client.getMapBaseX() || regionY != client.getMapBaseY() || path == null || path.length == 0) { regionX = client.getMapBaseX(); regionY = client.getMapBaseY(); path = pathfinder.findPath(myPosition(), getRegionalNext(spline), Math.random() > 0.65); if (path.length <= 1) next = getFarthest(spline); else next = getFarthest(path); } else next = getFarthest(path); } else next = getFarthest(spline); if (next == null) { path = null; mouseDestination = new MinimapTileDestination(client.getBot(), (next = getFarthest(spline))); } else mouseDestination = new MinimapTileDestination(client.getBot(), next); if (client.moveMouse(mouseDestination, true)) { client.pressMouse(); int breakDist = (int) (3 * Math.random() + 1.5); Timer timeout = new Timer(1550); while (keepWalking.isActive() && distanceTo( client.getDestination()) > breakDist && timeout.isRunning() && Math.hypot( next.getX() - client.getDestination().getX(), next.getY() - client.getDestination().getY() ) < 4) { //TODO your set run method here if (client.getMyPlayer().isMoving() || checkGameState()) timeout.reset(); Thread.sleep(0, 1); } } } return !keepWalking.isActive(); } } } Whoa!? How do I use this monstrosity? Well here is an example: /** * * This class is from within the packed class, so I would split them, since they are not enclosing classes. */ public class SplineWalkExample extends Script { BitPathfinder pathfinder; SplineWalk splineWalk; public final Position[] splineFromBankToSawMill = new Position[]{ new Position(3252, 3425, 0), new Position(3252, 3426, 0), new Position(3252, 3427, 0), new Position(3252, 3428, 0), new Position(3253, 3428, 0), new Position(3254, 3428, 0), new Position(3255, 3428, 0), new Position(3256, 3428, 0), new Position(3256, 3429, 0), new Position(3257, 3429, 0), new Position(3258, 3429, 0), new Position(3259, 3429, 0), new Position(3260, 3429, 0), new Position(3261, 3429, 0), new Position(3261, 3428, 0), new Position(3262, 3428, 0), new Position(3263, 3428, 0), new Position(3264, 3428, 0), new Position(3265, 3428, 0), new Position(3266, 3428, 0), new Position(3267, 3428, 0), new Position(3268, 3428, 0), new Position(3269, 3428, 0), new Position(3270, 3428, 0), new Position(3271, 3428, 0), new Position(3272, 3428, 0), new Position(3273, 3428, 0), new Position(3274, 3428, 0), new Position(3275, 3428, 0), new Position(3276, 3428, 0), new Position(3277, 3428, 0), new Position(3278, 3428, 0), new Position(3278, 3429, 0), new Position(3279, 3429, 0), new Position(3280, 3429, 0), new Position(3281, 3429, 0), new Position(3282, 3429, 0), new Position(3282, 3430, 0), new Position(3283, 3430, 0), new Position(3283, 3431, 0), new Position(3284, 3431, 0), new Position(3284, 3432, 0), new Position(3285, 3432, 0), new Position(3285, 3433, 0), new Position(3285, 3434, 0), new Position(3285, 3435, 0), new Position(3285, 3436, 0), new Position(3285, 3437, 0), new Position(3285, 3438, 0), new Position(3285, 3439, 0), new Position(3285, 3440, 0), new Position(3285, 3441, 0), new Position(3285, 3442, 0), new Position(3285, 3443, 0), new Position(3285, 3444, 0), new Position(3285, 3445, 0), new Position(3285, 3446, 0), new Position(3285, 3447, 0), new Position(3285, 3448, 0), new Position(3285, 3449, 0), new Position(3285, 3450, 0), new Position(3285, 3451, 0), new Position(3285, 3452, 0), new Position(3285, 3453, 0), new Position(3285, 3454, 0), new Position(3285, 3455, 0), new Position(3285, 3456, 0), new Position(3285, 3457, 0), new Position(3285, 3458, 0), new Position(3285, 3459, 0), new Position(3285, 3460, 0), new Position(3285, 3461, 0), new Position(3286, 3461, 0), new Position(3286, 3462, 0), new Position(3287, 3462, 0), new Position(3288, 3462, 0), new Position(3288, 3463, 0), new Position(3289, 3463, 0), new Position(3290, 3463, 0), new Position(3291, 3463, 0), new Position(3291, 3464, 0), new Position(3292, 3464, 0), new Position(3296, 3464, 0), new Position(3293, 3465, 0), new Position(3294, 3465, 0), new Position(3294, 3466, 0), new Position(3294, 3467, 0), new Position(3295, 3467, 0), new Position(3295, 3468, 0), new Position(3295, 3469, 0), new Position(3296, 3469, 0), new Position(3296, 3470, 0), new Position(3296, 3471, 0), new Position(3297, 3472, 0), new Position(3297, 3473, 0), new Position(3297, 3474, 0), new Position(3297, 3475, 0), new Position(3297, 3476, 0), new Position(3298, 3476, 0), new Position(3298, 3477, 0), new Position(3298, 3480, 0), new Position(3298, 3480, 0), new Position(3298, 3480, 0), new Position(3298, 3481, 0), new Position(3298, 3482, 0), new Position(3298, 3483, 0), new Position(3298, 3484, 0), new Position(3298, 3485, 0), new Position(3298, 3486, 0), new Position(3299, 3490, 0), new Position(3299, 3491, 0), new Position(3299, 3489, 0), new Position(3299, 3490, 0) }; public Position[] splineFromSawToBank; final Conditional thisMustBeTrueToKeepWalking = new Conditional() { @Override public boolean isActive() { return !(myX() > 234234 && myZ() < 234234234); // while NOT between.. those.. bounds, keep chugging. } }; public void onStart() { pathfinder = new BitPathfinder(client); splineWalk = new SplineWalk(client); reverseOrder(splineFromSawToBank = splineFromBankToSawMill.clone()); } public int onLoop() { try { if(splineWalk.splineWalk(pathfinder, thisMustBeTrueToKeepWalking, splineFromBankToSawMill)) { System.out.println("My condition is not true anymore, and broken, so I have met it. that means," + "based on my condition im (myX() > 234234 && myZ() < 234234234)"); //Im here! lets do something } } catch (InterruptedException ignored) { // :'( } return 500; } } I hope this helps, sorry for the lack of depth, I'll try to fix it up tomorrow, but I'm running on fumes posting this.
    1 point
  2. 8/10 Dat Avatarrrrrrrrrrr
    1 point
  3. 1 point
  4. I hope it is during a time that I am around.
    1 point
  5. I wanna see it made
    1 point
  6. Thanks :p I got a Wocom drawing tablet. Start to expect some vectors from me
    1 point
  7. scrappy doesn't even have an avatar... how can I rate it?
    1 point
  8. Hello community! On top of our new company and our soon to be new dedicated server hosting OSBot.org, I'm going to present to you some of the new features 1.8.x will include... One of the most requested features has been the implementation of web walking. Well, while this might not be fully implemented by 1.8.x, we our proud to announce that we will be providing global map data in the API. This allows us to analyze maps that haven't even been loaded by the client. A web walker can easily interpret this data to construct a collision map to make decisions about the paths it takes. Along with this will also be the ability to load item, NPC, and object definitions on demand. This will fix the issue with NPCs, objects, and items having "null" for their names in game. This will also allow us to make stronger and less breakable anti-randoms. Along with these updates, I'ed like to implement automatic door handling to OSBot. This means that if you try to walk to a position that is blocked off by multiple obstacles (doors, gates, anything open-able), OSBot will be able to handle it automatically within the walk() methods. Expect these updates soon! Sincerely, Laz and the OSBot Team.
    1 point
×
×
  • Create New...