Jump to content
Frequently Asked Questions
  • Are you not able to open the client? Try following our getting started guide
  • Still not working? Try downloading and running JarFix
  • Help! My bot doesn't do anything! Enable fresh start in client settings and restart the client
  • How to purchase with PayPal/OSRS/Crypto gold? You can purchase vouchers from other users
  • [In Progress] Mad Framework


    Mad Moxxi

    Recommended Posts

    Mad Moxxi's Mad Framework

     

        So I've decided that most approaches to script development, presented in the public domain, are utter garbage. Constantly back and forth through classes in numerous packages, I needed a way to contain this code along with my sanity. 

     

        With IntelliJ in hand, I set out to conjure up a framework with which I can achieve most any script with relative ease. I started with a sort of backend, produced and open-sourced by fellow scripter. Sadly, they closed the github repo, but I continued to build on the code. I worked tirelessly to produce something robust, manageable and feature-packed.

     

        I present to the community, Mad Framework. My solution to a number of script-related problems. Think of the remainder of this thread as a kind of JavaDoc, as I find the structure and style more concise and informal. Anything applications of the Mad Framework are entirely up to the imagination of the person using it.

     

       In the near future, I will show how it is used more in-depth, as well as how you can create your own custom tasks. Custom tasks will allow much more control over the script's behaviour along with access to far more features than are present.

     

    Front end features

    Logic

     - Execute on Condition

         Execute a node only when a provided condition is met.

            new ExecuteOnConditionTask(getContext(),
                    () -> !getContext().getInventory().isFull(),
                    new WebWalkTask(getContext(), FISHING_SPOT));
    

     - Selection by Condition

         Select between two ChainableTasks with a provided condition. The first will be executed when the condition returns true.

            new SelectionTask(getContext(),
                    () -> getContext().getInventory().isFull(),
                    new WebWalkTask(getContext(), BANK)),
                    new WebWalkTask(getContext(), FISHING_SPOT); 

     - Wait for Condition

         Halts execution until a condition or the provided timeout is met.

            new WaitForConditionTask(getContext(), 3600
                    () -> getContext().isIdle());
    

    Banking

     - Withdraw

         Withdraws a specified number of a given item. Use -1 as an amount to withdraw all.

            new WithdrawTask(getContext(), "Lobster", -1); 

     - Deposit All

         Deposits all items specified by a varargs argument. A boolean specifies if deposit boxes should be used.

            new DepositAllTask(getContext(), true, "Iron ore");
    

     - Deposit All Except

         Deposits all items except for those passed through a varargs argument. A boolean specifies whether or not to use deposit boxes.

            new DepositAllExceptTask(getContext(), false, "Lobster");

    Interaction

     - Interact with Entity

         Interacts with a nearby entity. Takes a name or filter, along with an action.

            new InteractEntityTask(getContext(), "Flesh crawler", "Bloom");
            new InteractEntityTask(getContext(),
                    (entity -> entity.getName().contains("Kalphite")), "Attack");
    

     

     - Interact with Item

         Interacts with an item in the inventory. Takes a name or filter, along with an action.

            new InteractItemTask(getContext(), "Silver sickle (b)", "Bloom");
            new InteractItemTask(getContext(),
                    (item -> item.getName().contains("Amulet of glory")),
                    "Edgeville");
    

     - Item on Entity

         Uses an item on an entity. Takes a pair of names or filters.

            new ItemOnEntityTask(getContext(), "Rune essence", "Altar");
            new ItemOnEntityTask(getContext(),
                    (item -> item.getName().contains("essence"))
                    ,(entity -> entity.getName().equalsIgnoreCase("Altar")));
    

     

     - Item-on-Item

         Uses an item on another item (in the inventory). Takes a pair of names or filters. Also takes a boolean argument to randomize the order.

            new ItemOnItemTask(getContext(), false,
                    (first -> first.getName().contains("Pestle and mortar")),
                    (second -> getName().contains("Chocolate")));
            new ItemOnItemTask(getContext(), false, "Pestle and mortar", "Chocolate");
    

    Traversal

     - Web Walk

         Walks to a specified location using the web walker. Location can be specified with a name (varargs, will find the closest), coordinates or a filter.

            new WebWalkTask(getContext(), 2313, 3242, 0);
            new WebWalkTask(getContext(), 2313, 3242);
            new WebWalkTask(getContext(), "First name", "Second name");
            new WebWalkTask(getContext(),
                    (webNode -> webNode.getName().equalsIgnoreCase("First name"))); 

     - Local Walk

         Walks to a specified location within the current region. Location can be specified with a Tile argument or coordinates.

            new LocalWalkTask(getContext(), new Tile(2313, 3242, 0));
            new LocalWalkTask(getContext(), 2313, 3242, 0);
            new LocalWalkTask(getContext(), 2313, 3242);

    Back End Features

    Context

          The Context class provides a way to pass the game instance around the back end. Generally replaces any usages of the AbstractScript class e.g.

    Item food = script.getInventory().get("Lobster");
    

    would become

    Item food = getContext().getInventory().get("Lobster");
    

    Managers

         Also referred to as loadouts or configs, managers store and handle the usage of particular categorical sets of information within the Runescape world. They use a Map<String, T> in order to store this information. T would be the thing you are storing (e.g. Potion).

     

         The manager will check its respective container for T instances matching those in the provided generic. When they are loaded, they will be stored in the map, keyed by their name or String value.

     

    The manager will drink the potion given to manager.perform(Potion potion). You would have to implement a custom node for this; one that checks if any potions can be drank and passes them to the potion manager appropriately.

     

    Available Managers: 

     - Potion Manager

     - Prayer Manager

     - Teleport Manager

     - Item Manager

     

    Web Walker

         The web walker provides almost completely unhindered traversal across the RuneScape world. It features stair traversal for both cross-plane and "Y ladders" (The ones that teleport across the map). It also uses an implementation of the Teleport Manager in order to provide teleporting int any script. It is used in much the same way as the DreamBot webwalker, so much of it will seem familiar.

     

    Custom Nodes

         You can also create custom Tasks and use them as you would the Tasks provided (InteractEntityTask etc). Here is an example one might use for the Banking class.

    public class BankingTask extends ChainableTask {
        private final String axeName;
        private boolean hasAxe;
    
        public BankingTask(Context context, String axeName) {
            super(context);
            this.axeName = axeName;
        }
    
        @Override
        public boolean execute() {
            // Standard processing method
            return getContext().getTaskExecutor().execute(
                    hasAxe ? new DepositAllExceptTask(getContext(), false, axeName)
                           : new WithdrawTask(getContext(), axeName, 1));
        }
    
        @Override
        public void prepare() {
            // This executes if canExecute returns false
        }
    
        @Override
        public boolean canExecute() {
            // Can it execute?
            hasAxe = getContext().getInventory().contains(axeName) || getContext().getEquipment().contains(axeName);
            return getContext().getInventory().isFull() || !hasAxe;
        }
    }
    

    Script Examples

    import ...
    
    @ScriptManifest(category = Category.WOODCUTTING, name = "Mad Flesh Killer", author = "Mad Moxxi", version = 1.0)
    public class FleshKiller extends MadScript {
    
        private static final String FOOD = "Lobster";
        private static final boolean DEPOSIT_BOX = false;
        private static final String BANK = DEPOSIT_BOX ? "Bank deposit box" : "Bank booth";
        private static final String MONSTER = "Flesh crawler";
        private static final String ATTACK = "Attack";
        private static final String EAT = "Eat";
    
        private ChainableTask task;
    
        @Override
        public int process() {
            if (task != null && getContext().getTaskExecutor().execute(task))
                return 1200;
            return 600;
        }
    
        @Override
        public boolean start() {
            this.task = buildTask();
            getContext().setTaskExecutor(new ChainExecutor(getContext()));
            return true;
        }
    
        @Override
        public ChainableTask buildTask() {
            return new SelectionTask(getContext(), // IF
                    () -> !getContext().getInventory().contains(FOOD),// INVENTORY CONTAINS food
                    new WebWalkTask(getContext(), getContext().getWebWalker().getClosest(BANK)) // WALK TO CLOSEST bank
                            .chain(new DepositAllExceptTask(getContext(), DEPOSIT_BOX, FOOD)) // DEPOSIT ALL EXCEPT food
                            .chain(new WithdrawTask(getContext(), FOOD, -1)), // WITHDRAW food, -1
                    // ELSE
                    new ExecuteOnConditionTask(getContext(), // EXECUTE IF
                            getContext()::isIdle, // context.isIdle
                            new WebWalkTask(getContext(), getContext().getWebWalker().getClosest(MONSTER)) // WALK TO CLOSEST monster
                                    .chain(new InteractEntityTask(getContext(), MONSTER, ATTACK)) // INTERACT monster, attack
                                    .chain(new WaitForConditionTask(getContext(), // WAIT UNTIL
                                            () -> !getContext().isIdle())) // context.isIdle
                    )).chain(new ExecuteOnConditionTask(getContext(), // EXECUTE IF
                             () -> getContext().getCombat().getHealthPercent() < 25, // LOW HP
                                     new InteractItemTask(getContext(), FOOD, EAT))); // INTERACT food, eat
        }
    
        @Override
        public void finish() {
    
        }
    }
    
    import ...
    
    @ScriptManifest(category = Category.COMBAT, name = "Mad Willow Chopper", author = "Mad Moxxi", version = 1.0)
    public class MadwillowChopper extends MadScript {
    
        private static final boolean DEPOSIT_BOX = true;
        private static final String BANK = DEPOSIT_BOX ? "Bank deposit box" : "Bank booth";
        private static final Tree TREE = Tree.WILLOW;
        private static final String CHOP = "Chop-down";
    
        private ChainableTask task;
    
        @Override
        public int process() {
            if (task != null && getContext().getTaskExecutor().execute(task))
                return 1200;
            return 600;
        }
    
        @Override
        public boolean start() {
            this.task = buildTask();
            getContext().setTaskExecutor(new ChainExecutor(getContext()));
            return true;
        }
    
        @Override
        public ChainableTask buildTask() {
            return new SelectionTask(getContext(),
                    () -> getContext().getInventory().isFull(),
                    new DepositAllTask(getContext(), true, TREE.getLogName()),
                    new SelectionTask(getContext(),
                            () -> getContext().getTaskExecutor().execute(new InteractEntityTask(getContext(),
                                    (entity -> entity.getName().equalsIgnoreCase(TREE.getTreeName())), CHOP)),
                            new WebWalkTask(getContext(), (webNode -> webNode.getName().contains(TREE.getTreeName()))),
                            new WaitForConditionTask(getContext(), () -> getContext().isIdle())));
        }
    
        @Override
        public void finish() {
    
        }
    }
    
    Link to comment
    Share on other sites

    How memory intensive is it?

     

    Seems like we're playing tricky games with the Garbage Collector =p

     

    It shouldn't be very memory intensive. It'd be highly advisable to know how to use lambdas for Conditions and Filters, otherwise you'll end up with code like this:

            new WaitForConditionTask(getContext(),
                    new Condition() {
                        @Override
                        public boolean verify() {
                            return getContext().isIdle();
                        }
                    }); 
            new InteractEntityTask(getContext(), new Filter<Entity>() {
                @Override
                public boolean match(Entity entity) {
                    return entity.getName().equals("Flesh crawler");
                }
            }, "Attack");
    
    Link to comment
    Share on other sites

    Archived

    This topic is now archived and is closed to further replies.

    ×
    ×
    • Create New...

    Important Information

    We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.