Welcome to TRiBot Forums

Register now to gain access to all of our features. Once registered and logged in, you will be able to contribute to this site by submitting your own content or replying to existing content. You'll be able to customize your profile, receive reputation points as a reward for submitting content, while also communicating with other members via your own private inbox, plus much more! This message will be removed once you have signed in.

TacoManStan

TacoManStan's Scripting Guide

5 posts in this topic

TacoManStan's Scripting Guide

 

If anyone notices any issues with code, please PM me so I can fix it. Please don't comment on this thread about issues with code. This is meant to be a tutorial, and the thread should be used only to ask questions.
Even experienced scripters might learn something here!
 
Hello everyone. I am going to go over the very basics on how to get started with scripting. It is HIGHLY recommended that you already know at least a little bit about Java before writing any sort of script, so if you don't know Java, again, I would HIGHLY recommend that you learn it first.
 
I am going to be slowly adding more to this tutorial as I get more time. Hopefully those on TRiBot will find this information useful.
 
The TRiBot API
I won't go into the details of what an API means, but all you need to know is that an API is a collection of tools that allow you to interact with TRiBot. You can find a link to the TRIBot API here: https://tribot.org/doc/
 
The TRiBot API is a scripting API. That makes it quite a bit different from most APIs that you will see, because it is almost entirely static. That means that almost every method in the API can be used anywhere, and without first creating an object. This makes it very easy to use, and very efficient in communicating with the RuneScape client.
 
Don't Make Your API Static!
You are not making an extension of TRiBot. You are using TRiBot as a tool. You are going to want to avoid using static frameworks as much as you can. While static methods are completely safe, static variables can lead to some strange bugs.
 
Why Are Static Methods Safe?
Static methods are safe because they do not store any information. Static methods can be set up to execute a series of TRiBot methods, and that can be extremely useful when scripting.
 
Why Aren't Static Variables Safe?
​There is nothing inherently wrong with static variables. In many cases, static variables can be extremely useful, but not within TRiBot. If you use static variables to hold any essential information, you immediately remove the option for users to open you script using tabs. The reason for this is that those static variables are attached to the JVM instance (AKA each TRiBot client), not each script instance.
 
In short, all of the scripts that you open in different tabs will be using and modifying the same static variable.
 
What Should I Do Instead?
You want to make a class that you can still access in a static context, but that isn't by nature static. It's a tricky concept, I know, but it's an important one. Refer to the following class:

public class Data {    //A static HashMap that stores the data for all the scripts running    //in different tabs.    private static final HashMap<String, Data> data = new HashMap<>();    //The instance variables that pertain to each individual script running in each tab.    private Point position;    private int value1;    private int value2;        private Data() {        String playerName;        while ((playerName = Player.getRSPlayer().getName()) == null) {            General.sleep(5);        }        //Reset the old data before adding the new data.        resetData();        //Add the new data to the HashMap.        data.put(playerName, this);    }        /**     * Call this at the beginning of every script you make, and the rest will be taken      * cared of automatically.     */    public static void initData() {        new Data();    }    /**     * Returns true if the data has been loaded, false otherwise.     * <p>     * @[member=Return] True if the data has been loaded, false otherwise.     */    private static boolean isDataLoaded() {        //The ONLY reason a null check isn't necessary here is because "containsKey(...)"        //allows a null parameter.        //This is not always the case. If you aren't sure if a method allows for null parameters, ALWAYS do        //a null check.        return data.containsKey(Player.getRSPlayer().getName());    }    /**     * Resets the data of the currently running script. Returns true if the script data     * has been removed at the end of the method, false otherwise.     * <p>     * @[member=Return] True if the script data has been removed at the end of the method,     * false otherwise.     */    private static boolean resetData() {        String playerName = Player.getRSPlayer().getName();        if (playerName != null) {            data.remove(playerName);            return !data.containsKey(playerName);        } else {            return false;        }    }    /**     * Returns the proper data that is to be used in your methods.     * <p>     * @[member=Return] The proper data that is to be used in your methods.     */    private static Data getData() {        if (isDataLoaded()) {            String playerName = Player.getRSPlayer().getName();            return playerName == null ? null : data.get(playerName);        } else {            throw new RuntimeException("Data has not been loaded");        }    }    /**     * Returns the data attached to the specified key, or null if the key is null.     * <p>     * @param key The key that is used to retrieve the Data from the HashMap.     * @[member=Return] The data attached to the specified key, or null if the key is null.     */    private static Data getData(String key) {        if (key == null) {            return null;        } else {            return data.get(key);        }    }    //You can also make these methods "blocking methods". That means that they will not return a value    //until a condition is met, hence blocking further execution. Instead of throwing an exception    //(which might cause issues if the script logs out), you could instead wait for the name of the    //player to not be null before returning a value.    //Methods that you will be calling in your scripts:    public static Point getPosition() {        if (isDataLoaded()) {            return getData().position;        } else {            throw new RuntimeException("Data has not been loaded");        }    }    public static int getValue1() {        if (isDataLoaded()) {            return getData().value1;        } else {            throw new RuntimeException("Data has not been loaded");        }    }    public static int getValue2() {        if (isDataLoaded()) {            return getData().value2;        } else {            throw new RuntimeException("Data has not been loaded");        }    }} 

By using the above class, you can call any of the static methods provided without fear of having concurrency issues with running multiple clients. Additionally, using this class will ensure that the "Re-run Script" button will always work properly. Note that the data will only function properly once the player has logged in.
 
Also notice how all of the methods that manage the internal workings of the class are declared to be "private". This prevents you from accidentally calling them during your script, and potentially corrupting data.
 
That is the end of the tutorial so far. Stay tuned for more, and if there is anything that you would like to learn, comment below and I will see what I can do!

Edited by tacomanstan
5 people like this

Share this post


Link to post
Share on other sites

"Fixed" ? 

 

For example one line I was referring to:

return Player.getRSPlayer().getName() != null && data.containsKey(Player.getRSPlayer().getName());

containsKey allows a null value for its parameter.  In addition the Player.getRSPlayer().getName() left hand could be true, and on the right hand side of the logical AND null.

 

Warfront1

Has been fixed. Thank you for pointing that out.

Edited by tacomanstan

Share this post


Link to post
Share on other sites

"Fixed" ? 

 

For example one line I was referring to:

return Player.getRSPlayer().getName() != null && data.containsKey(Player.getRSPlayer().getName());

containsKey allows a null value for its parameter.  In addition the Player.getRSPlayer().getName() left hand could be true, and on the right hand side of the logical AND null.

 

Warfront1

If the entity is loaded, calling getName will no longer return null at a random is what I'm saying.

Share this post


Link to post
Share on other sites

If the entity is loaded, calling getName will no longer return null at a random is what I'm saying.

 

Gotcha, Thanks for the clarification, It wasn't mentioned in the docs.

 

Warfront1

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!


Register a new account

Sign in

Already have an account? Sign in here.


Sign In Now

  • Recently Browsing   0 members

    No registered users viewing this page.