Jump to content
Search In
  • More options...
Find results that contain...
Find results in...
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:

      Add new internal framework for capturing exceptions


      Fix issue with not selecting the last column in world hopper (Thanks @Todd)


      Add a message about pin usage in Banking#openBank (Thanks @Todd)


      Disable the firewall by default (Thanks @Todd)


      Fix handling of the welcome screen after login (Thanks @Encoded)


      Fix wrong amount bank withdrawal (Thanks @Encoded)


      Fix Screen#isInViewport


      Fix Game#isInViewport (Thanks @Encoded)


      Call onBreakEnd for ListenerManager Breaking Listeners (Thanks @Encoded)


      Fix Prayer#getPrayerPoints NumberFormatException (Thanks @JoeDezzy1)



      Note: If you are using LG, please restart both the RS client and TRiBot.
        • Thanks
        • Like
      • 19 replies
    • This release will:

      Fix LG for both OSBuddy and RuneLite


      Fix issue where the resizable client isn't able to be made smaller (Thanks @JoeDezzy1)


      Fix detection of the logout game tab when resizable mode and side panels are enabled (Thanks @JoeDezzy1)


      Add initial support for Sentry to allow us to identify and easily debug exceptions happening with all TRiBot users


      Add methods to determine if the bank is actually loaded, and not just the overarching interface (Thanks @wastedbro)



      Upcoming updates:

      Improved CLI support


      Full Sentry support


      Much more
        • Like
      • 64 replies
    • This release will:

      Fix NPE in Camera API (Thanks @wastedbro)


      Update deposit box interface ids (Thanks @Encoded)


      Add various bank methods (Thanks @wastedbro)


      Banking#getWithdrawXQuantity


      Banking#getDefaultWithdrawQuantity


      Banking#arePlaceholdersOn




      Fix resizeable minimap bug (Thanks @wastedbro)


      Remove Java 8 requirement


      Please note: TRiBot is not yet fully compatible with Java 10+




      Fix the break handler issues by ensuring the break handler thread never gets paused


      Fix broken settings hooks



      Upcoming updates:

      Improved CLI support


      Much more



      Note: If you are using LG, please restart both the RS client and TRiBot
        • Like
      • 68 replies
    • This release will:

      Add support for using custom F key bindings to switch between game tabs (Thanks @erickho123)


      Fix tab opening for "Skills" and "Kourend Tasks" (Thanks @erickho123)



      Note: If you are using LG, please restart both the RS client and TRiBot
        • Like
      • 34 replies
    • This release will:

      Fix an issue where breaks would stop firing


      Fix Combat#getWildernessLevel, use dynamic search for text and cache ID for later calls


      Fix an NPE in the Combat API


      Fix Mouse#leaveGame bug where the mouse wouldn't actually leave the game screen
        • Like
      • 21 replies
  • Recently Browsing   0 members

    No registered users viewing this page.

×