Jump to content

Updated Brainfree's Spline Walking


exuals

Recommended Posts

Credits go to Brainfree, his original thread can be found here:

http://osbot.org/forum/topic/3356-a-patch-for-walking-into-neighboring-regions/

 

I simply updated his methods and fixed the class inheritance shit.

Let me know if there's any issues.

 

PackedSplineWalk:

package API;

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 static 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 client) {
            this.bot = client;
        }

        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 static 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()]);
            nodeUtils.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 class nodeUtils {
    	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 static 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 static 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();
        }
    }
} 

SplineWalkExample:

import org.osbot.script.Script;
import org.osbot.script.rs2.map.Position;

import API.PackedSplineWalk.BitPathfinder;
import API.PackedSplineWalk.Conditional;
import API.PackedSplineWalk.SplineWalk;
import API.PackedSplineWalk.nodeUtils;


 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);
            nodeUtils.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;
        }
    } 
Link to comment
Share on other sites

Since when was walking so complicated? ohmy.png

 

 

 

Since when was walking so complicated? ohmy.png

 

It isn't. This code was needlessly overcomplicated.

 

 

While it could be simplified, this is meant to be in conjunction with the tool on his old topic.

 

It also provides a hell of a lot more than the average walking API, once again, please see his topic, I use it for my scripting and it's excellent.

Link to comment
Share on other sites

 

Since when was walking so complicated? ohmy.png

 

 

 

Since when was walking so complicated? ohmy.png

 

It isn't. This code was needlessly overcomplicated.

 

 

While it could be simplified, this is meant to be in conjunction with the tool on his old topic.

 

It also provides a hell of a lot more than the average walking API, once again, please see his topic, I use it for my scripting and it's excellent.

 

 

Not saying anything against it. Just that the same quality can come out of half the code.

 

Link to comment
Share on other sites

 

 

Since when was walking so complicated? ohmy.png

 

 

 

Since when was walking so complicated? ohmy.png

 

It isn't. This code was needlessly overcomplicated.

 

 

While it could be simplified, this is meant to be in conjunction with the tool on his old topic.

 

It also provides a hell of a lot more than the average walking API, once again, please see his topic, I use it for my scripting and it's excellent.

 

 

Not saying anything against it. Just that the same quality can come out of half the code.

 

 

With only having to change a couple lines up and switch it from bot to client, I like it for the amount of fail-safes it provides.

Link to comment
Share on other sites

  • 2 weeks later...
Guest
This topic is now closed to further replies.
  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...