Jump to content
TacoManStan

TacoManStan's Scripting Guide

Recommended Posts

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
  • Like 5

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

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

  • Our picks

    • This release will:

      Fix Settings UI placement bug


      Fix game object location bug


      Fix small layout bug making the client shift up and down


      Fix client crashing bug where loading the client with a small display area will cause the client to crash


      Fix annoying Linux bug relating to painting events and peers


      Fix settings saving bug where settings are saved to disk more often than they should


      Fix RSInterface#isBeingDrawn bug affecting a limited amount of people


      Drop Java 1.7 bytecode version for 1.8


      Important: Since the downloadable RS client uses Java 7, it will no longer be compatible with Looking Glass. To make up for this, we will add support for using other clients such as RuneLite (at a later date).


      This change was necessary to allow us to use Java 8 syntax. It also paves the way for Java 9/10/11 support.
        • Like
      • 29 replies
    • This update will:

      Fix the RSMenuNode bug which also fixes the bug with bank opening


      Fix the incorrect object positions bug


      Fix and re-enable the LG Objects API Accelerator


      Fix the RSObject#getAllTiles bug
        • Like
      • 22 replies
    • Try our development release by checking "Development Release" on the TRiBot Loader. Note that these new features are currently in beta.

      This release features:

      Re-sizable mode support for both LG and the regular client


      Slightly improved login bot


      Removed final access modifiers from API classes


      Added RSServer hook wrapper to get the client's cached list of server/world info


      [NEW] Bug fix for intelligent banking


      [NEW] Improvement to the stability of LG over time


      [NEW] Vastly improved the reliability and speed of Screen#getColorAt on both LG and the regular client


      [NEW] Fix LG login problems


      [NEW] Fixed re-sizable mode container bug


      [NEW] Fixed re-sizable mode mouse bug


      [NEW] Use of public constants in the Banking API


      [NEW] Use of other various constants such as Projection#NULL_PT and Screen#EMPTY_COLOR



      More features to come very soon!

      Please test it and let us know here if there are any new bugs introduced in this release.
        • Thanks
        • Like
      • 12 replies
    • Try our development release by checking "Development Release" on the TRiBot Loader. Note that these new features are currently in beta.

      This release features:

      Re-sizable mode support for both LG and the regular client


      Slightly improved login bot


      Removed final access modifiers from API classes


      Added RSServer hook wrapper to get the client's cached list of server/world info


      Bug fix for intelligent banking


      Improvement to the stability of LG over time



      More features to come very soon!

      Please test it and let us know here if there are any new bugs introduced in this release.
        • Thanks
        • Like
      • 10 replies
    • - Updated the banking API to use the game item cache instead of interfaces. This will result in less delay, greater efficiency, and greater reliability. LG will especially benefit from this update.
      - Fixed a bug with the Grand Exchange API relating to searching for items.
        • Like
      • 5 replies
  • Recently Browsing   0 members

    No registered users viewing this page.

×