Welcome!

By registering with us, you'll be able to discuss, share and private message with other members of our community.

Sign up now!

Tutorial An Introduction to the TaskScript

Status
Not open for further replies.
Joined
Dec 10, 2014
Messages
3,260
An Introduction to the TaskScript

Contents:
  • Introduction
  • Overview
  • Pros and Cons
    • Pros
    • Cons
  • The Framework
    • TaskScript
    • Task
  • Example Script (Willow PowerChopper)
    • Identifying the required Tasks
    • Filling out the Tasks
      • Chop
      • Drop
    • Adding the Tasks to the TaskScript
  • Parting words
Introduction
Welcome to my tutorial, in this tutorial we will learn about the TaskScript. I'll try to break it down as much as possible without making it too long. TaskScripts are probably the most common type of script used nowadays.
Overview
We will identify the pros/cons of the TaskScript, go through the parts of a TaskScript and then create a simple powerchopper.
Pros and Cons
Pros
  • Breaks scripts up into modular parts
  • Reduced clutter due to modularity
  • Easier debugging, due to modularity
  • Reusable Tasks, due to modularity
Cons
  • Large projects can become messy if you don't package correctly
  • It's probably overkill for simple scripts
The Framework
TaskScript (Documentation)
The TaskScript is the main class of your Script. You add Tasks to it within the onStart method and then it will run the Tasks it needs to every loop.​
Task (Documentation)
Tasks are classes that extend the Task abstract class. The Task class has two abstract methods;
  1. validate(): This determines if the Task should be executed or not.
  2. execute(): This is the running code of the Task.
Example Script (Willow Powerchopper)
Identifying the required Tasks
Powerchoppers are pretty simple, and can be broken up into 2 Tasks; Chop and Drop.
So what we do is create the main script class and the 2 Tasks, I prefer to have my Tasks in a tasks package.
Project overview:
893f2ee8b5.png
Main Script Class:
Code:
package com.slashnhax.tutorials.task_script_tutorial;

import com.runemate.game.api.script.framework.task.TaskScript;

public class ExamplePowerchopper extends TaskScript {
    @Override
    public void onStart(String... args){

    }
}
The 3 Task stubs:
Code:
package com.slashnhax.tutorials.task_script_tutorial.tasks;

import com.runemate.game.api.script.framework.task.Task;

public class Chop extends Task {
    @Override
    public boolean validate() {
        return false;
    }

    @Override
    public void execute() {

    }
}
Code:
package com.slashnhax.tutorials.task_script_tutorial.tasks;

import com.runemate.game.api.script.framework.task.Task;

public class Drop extends Task {
    @Override
    public boolean validate() {
        return false;
    }

    @Override
    public void execute() {

    }
}
Filling out the Tasks
  • Chop
We want Chop to execute when either our Player's animation is -1 and when our Inventory isn't full and there are valid willow trees around. This goes in our validate() method.
Our validate method now looks like this:
Code:
@Override
public boolean validate() {
    return Players.getLocal().getAnimationId() == -1 && !Inventory.isFull() && !GameObjects.newQuery().names("Willow").actions("Chop down").results().isEmpty();
}
What we want to do when Chop executes is find the nearest tree, walk to it if needed and then chop it. This goes in our execute() method.
Our execute method now looks like this:
Code:
@Override
public void execute() {
    GameObject tree = GameObjects.newQuery().names("Willow").actions("Chop down").results().nearest();
    if (tree != null) {
        if (!tree.isVisible()){
            Camera.turnTo(tree);
            if(!tree.isVisible()){
                Path p = BresenhamPath.buildTo(tree);
                if(p != null)
                    p.step();
            }
        } else if(tree.interact("Chop down")){
            Execution.delayUntil(()->Players.getLocal().getAnimationId() != -1, 5000);
        }
    }
}

  • Drop
We want Drop to execute when our Inventory is full, that's the only criteria.
Our validate should look like this:
Code:
@Override
public boolean validate() {
    return Inventory.isFull();
}
When drop executes we will drop all of the logs in the Inventory. If the Inventory is open we will loop through all of the items in the inventory with the name "Willow logs" and drop them, otherwise we will open the inventory.
Our execute method will look like this:
Code:
@Override
public void execute() {
    if(InterfaceWindows.getInventory().isOpen()) {
        for(SpriteItem item: Inventory.getItems("Willow logs")){
            if(item.interact("Drop"))
                Execution.delayUntil(()->!item.isValid(), 1000);
        }
    } else {
        InterfaceWindows.getInventory().open();
    }
}
Adding the Tasks to the TaskScript
Adding the Tasks to your script is simple, you just use the add(Task... tasks) method supplied by TaskScript. And while we're doing that we may as well set the loop delay to something reasonable.
Our main script class should look similar to:
Code:
import com.runemate.game.api.script.framework.task.TaskScript;
import com.slashnhax.tutorials.task_script_tutorial.tasks.Chop;
import com.slashnhax.tutorials.task_script_tutorial.tasks.Drop;

public class ExamplePowerchopper extends TaskScript {
    @Override
    public void onStart(String... args){
        setLoopDelay(250, 500);
        add(new Chop(), new Drop());
    }
}
The Manifest
Nothing special about the Manifest, here's mine:
Code:
<manifest>
    <main-class>com.slashnhax.tutorials.task_script_tutorial.ExamplePowerchopper</main-class>
    <name>Example Powerchopper</name>
     <description>Example Powerchopper, uses TaskScript. Chops and drops, nothing special</description>
    <version>1.0.0</version>
    <compatibility>
        <game-type>RS3</game-type>
        <game-type>OSRS</game-type>
    </compatibility>
    <categories>
        <category>WOODCUTTING</category>
    </categories>
    <!--Required to publish on the bot store-->
    <internal-id>HaxExamplePowerchopper</internal-id>
    <!--The rest are optional-->
    <hidden>false</hidden>
    <open-source>true</open-source>
</manifest>

Parting Words
Thanks for reading my tutorial, if you have any questions feel free to leave a comment. I know that the example is extremely basic, but the purpose of this tutorial is to demonstrate the functionality of TaskScript​
 
Last edited:
Joined
Feb 17, 2015
Messages
112
Thanks for giving the community more tutorials, really helps new programmers like myself!
 
Joined
Jul 17, 2014
Messages
9
Thanks for this tutorial, great resource to get up and running with scripting for RuneMate!
 
Joined
Aug 7, 2015
Messages
28
I found that this code a litle bit different than your example bot in store.
In store: Task Chop Validate method: used newQuery
In tutorial: Task Chop Validate method: used getLoaded

Thank you very much for making this tutorial it helps to start to newbies like i am.
 
Last edited:
Joined
Dec 10, 2014
Messages
3,260
I found that this code a litle bit different than your example bot in store.
In store: Task Chop Validate method: used newQuery
In tutorial: Task Chop Validate method: used getLoaded

Thank you very much for making this tutorial it helps to start to newbies like i am.
newQuery is better and more powerful, I used getLoaded cause I was tired and it's less typing xD
 
Author of MaxiBots
Joined
Dec 3, 2013
Messages
6,869
@SlashnHax Please take the time to handle objects correctly if you're going to write a tutorial. New programmers will follow this and not realize they need to store things like player and null check it before calling a method on it.

#crackingdown
 
  • Like
Reactions: NZL
Joined
Dec 20, 2016
Messages
37
Awesome guide, however there is a small bug within Chop.java > execute() method.

It seems there are two conditions that check if a tree is visible, and there is a missing bracket.

Did you purposely add two of the same conditional or should it only be one?

Thanks
 
Joined
Dec 10, 2014
Messages
3,260
Awesome guide, however there is a small bug within Chop.java > execute() method.

It seems there are two conditions that check if a tree is visible, and there is a missing bracket.

Did you purposely add two of the same conditional or should it only be one?

Thanks
The two conditionals were on purpose, as it moves the Camera in between them. The missing bracket is a typo.

On another note, reading my own tutorial made me cringe a little. I'll try to create a better one when I find the time.
 
Any idea why this error keeps happening? I have tried multiple different locations for the "Local Bot Directory" but none of them fix the issue.

Gyazo - 77b074e61cbdb60d65d27ddfab832212.png
You've selected the wrong folder as your bot folder, notice how it says com/com? Select the parent folder to the one you currently have selected.
 
Learning Java
Joined
Dec 24, 2016
Messages
24
Make sure you're manifest refers to the correct path of your mainclass.
Thanks that fixed it, in my manifest I had com.sreno.bots.Powerchopper not com.sreno.bots.Powerchopper(project).Powerchopper(mainclass)
 
Java Warlord
Joined
Nov 17, 2014
Messages
4,906
Thanks that fixed it, in my manifest I had com.sreno.bots.Powerchopper not com.sreno.bots.Powerchopper(project).Powerchopper(mainclass)
Glad you could fix it, feel free to join us on slack btw :)
 
Joined
Feb 10, 2017
Messages
15
Thank you so much for this tutorial, wonderful job !
i have some issues trying to do this
maybe someone can help me ?
Thank you in advance for anyone willing to help me on this :)

got this error upon clicking Play

Code:
"C:\Program Files (x86)\Java\jre1.8.0_121\bin\java" -Didea.launcher.port=7534 "-Didea.launcher.bin.path=F:\Software\Dev\Java\IntelliJ IDEA Community Edition 2016.3.4\bin" -Dfile.encoding=UTF-8 -classpath "C:\Program Files (x86)\Java\jre1.8.0_121\lib\charsets.jar;C:\Program Files (x86)\Java\jre1.8.0_121\lib\deploy.jar;C:\Program Files (x86)\Java\jre1.8.0_121\lib\ext\access-bridge-32.jar;C:\Program Files (x86)\Java\jre1.8.0_121\lib\ext\cldrdata.jar;C:\Program Files (x86)\Java\jre1.8.0_121\lib\ext\dnsns.jar;C:\Program Files (x86)\Java\jre1.8.0_121\lib\ext\jaccess.jar;C:\Program Files (x86)\Java\jre1.8.0_121\lib\ext\jfxrt.jar;C:\Program Files (x86)\Java\jre1.8.0_121\lib\ext\localedata.jar;C:\Program Files (x86)\Java\jre1.8.0_121\lib\ext\nashorn.jar;C:\Program Files (x86)\Java\jre1.8.0_121\lib\ext\sunec.jar;C:\Program Files (x86)\Java\jre1.8.0_121\lib\ext\sunjce_provider.jar;C:\Program Files (x86)\Java\jre1.8.0_121\lib\ext\sunmscapi.jar;C:\Program Files (x86)\Java\jre1.8.0_121\lib\ext\sunpkcs11.jar;C:\Program Files (x86)\Java\jre1.8.0_121\lib\ext\zipfs.jar;C:\Program Files (x86)\Java\jre1.8.0_121\lib\javaws.jar;C:\Program Files (x86)\Java\jre1.8.0_121\lib\jce.jar;C:\Program Files (x86)\Java\jre1.8.0_121\lib\jfr.jar;C:\Program Files (x86)\Java\jre1.8.0_121\lib\jfxswt.jar;C:\Program Files (x86)\Java\jre1.8.0_121\lib\jsse.jar;C:\Program Files (x86)\Java\jre1.8.0_121\lib\management-agent.jar;C:\Program Files (x86)\Java\jre1.8.0_121\lib\plugin.jar;C:\Program Files (x86)\Java\jre1.8.0_121\lib\resources.jar;C:\Program Files (x86)\Java\jre1.8.0_121\lib\rt.jar;C:\Users\x\IdeaProjects\PowerChopper\out\production\PowerChopper;F:\RS\Runemate\RuneMate\RuneMate.jar;F:\Software\Dev\Java\IntelliJ IDEA Community Edition 2016.3.4\lib\idea_rt.jar" com.intellij.rt.execution.application.AppMain com.runemate.boot.Boot -sdk -login=materune:
[Debug] RuneMate Version: 2.4.18
[Debug] Java Version: 8u121 x86 (Oracle Corporation)
[Debug] Operating System: Windows 7 x64
java.lang.UnsupportedOperationException: Only a Thread within a bot's ThreadGroup may eavesdrop on the game client. Current Thread=Thread[pool-5-thread-1,2,[t-g]6112 - Powerchopper]
    at nul.iIiIIIiiiiIi.for(pqb:138)
    at com.runemate.game.api.hybrid.Environment.getBot(emb:71)
    at nul.iiiIiIiiiIii.run(pbb:147)
    at java.util.concurrent.Executors$RunnableAdapter.call(Unknown Source)
    at java.util.concurrent.FutureTask.runAndReset(Unknown Source)
    at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access$301(Unknown Source)
    at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(Unknown Source)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
    at java.lang.Thread.run(Unknown Source)
SDK mode is intended for active bot development only. As such, there is a three hour runtime limit while in SDK mode for users who are not Bot Authors. If you are an aspiring Bot Author, please continue on and best of luck! The moment you publish your first bot this limit will be removed. If you are an end user please contact your bot provider and ask them to publish the bot via the Bot Store, so it can be reviewed for safety. For more information please visit <a href="https://www.runemate.com/community/threads/restrict-sdk-runtime-for-end-users.4277/">the discussion thread</a>.
00:00:00 [ DEBUG ] Logger Initialised - this log file can be found at C:\Users\x\RuneMate\logs\02-16  10 37 21 - Powerchopper.txt
[Caution: Limited API usage] You're only using a small portion of the api, we recommend you look into some of our EventListeners such as the InventoryListener.
java.lang.UnsupportedOperationException: Only a Thread within a bot's ThreadGroup may eavesdrop on the game client. Current Thread=Thread[pool-6-thread-1,5,[t-g]6112 - Powerchopper]
    at nul.iIiIIIiiiiIi.for(pqb:138)
    at com.runemate.game.api.hybrid.Environment.getGameType(emb:160)
    at com.runemate.game.api.hybrid.Environment.isRS3(emb:194)
    at nul.iiIIIIiIiiii.for(nab:75)
    at nul.iiIIIIiIiiii.validate(nab:143)
    at com.runemate.game.api.script.framework.LoopingBot.run(wxa:96)
    at java.util.concurrent.Executors$RunnableAdapter.call(Unknown Source)
    at java.util.concurrent.FutureTask.run(Unknown Source)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
    at java.lang.Thread.run(Unknown Source)

Exception: java.lang.NullPointerException thrown from the UncaughtExceptionHandler in thread "Thread-19"

Process finished with exit code 0

Project Structure
NZfuHlu.png

This is the
PowerChopper.java
Code:
package com.materune.bots.PowerChopper;

import com.runemate.game.api.script.framework.task.TaskScript;
import com.materune.bots.PowerChopper.tasks.Chop;
import com.materune.bots.PowerChopper.tasks.Drop;

public class PowerChopper extends TaskScript {
    @Override
    public void onStart(String... args){
        setLoopDelay(250, 500);
        add(new Chop(), new Drop());
    }
}

Chop.java
Code:
package com.materune.bots.PowerChopper.tasks;

import com.runemate.game.api.hybrid.entities.GameObject;
import com.runemate.game.api.hybrid.local.hud.interfaces.Inventory;
import com.runemate.game.api.hybrid.location.navigation.Path;
import com.runemate.game.api.hybrid.location.navigation.basic.BresenhamPath;
import com.runemate.game.api.hybrid.region.GameObjects;
import com.runemate.game.api.hybrid.region.Players;
import com.runemate.game.api.script.Execution;
import com.runemate.game.api.script.framework.task.Task;
import com.runemate.game.api.hybrid.local.Camera;

public class Chop extends Task {
    @Override
    public boolean validate() {
        return Players.getLocal().getAnimationId() == -1 && !Inventory.isFull() && !GameObjects.newQuery().names("Tree").actions("Chop down").results().isEmpty();
    }

    @Override
    public void execute() {
        GameObject tree = GameObjects.newQuery().names("Tree").actions("Chop down").results().nearest();
        if (tree != null) {
            if (!tree.isVisible()) {
                Camera.turnTo(tree);
                if (!tree.isVisible()) {
                    Path p = BresenhamPath.buildTo(tree);
                    if (p != null)
                        p.step();
                } else if (tree.interact("Chop down")) {
                    Execution.delayUntil(() -> Players.getLocal().getAnimationId() != -1, 5000);
                }
            }
        }
    }
}

Drop.java
Code:
package com.materune.bots.PowerChopper.tasks;

import com.runemate.game.api.hybrid.local.hud.interfaces.InterfaceWindows;
import com.runemate.game.api.hybrid.local.hud.interfaces.Inventory;
import com.runemate.game.api.hybrid.local.hud.interfaces.SpriteItem;
import com.runemate.game.api.script.Execution;
import com.runemate.game.api.script.framework.task.Task;

public class Drop extends Task {
    @Override
    public boolean validate() {
        return Inventory.isFull();

    }

    @Override
    public void execute() {
        if(InterfaceWindows.getInventory().isOpen()) {
            for(SpriteItem item: Inventory.getItems("Logs")){
                if(item.interact("Drop"))
                    Execution.delayUntil(()->!item.isValid(), 1000);
            }
        } else {
            InterfaceWindows.getInventory().open();
        }
    }
}

PowerChopper.manifest.xml
Code:
<manifest>
    <main-class>com.materune.bots.PowerChopper.PowerChopper</main-class>
    <name>Powerchopper</name>
    <description>Example Powerchopper, uses TaskScript. Chops and drops, nothing special</description>
    <version>1.0.0</version>
    <compatibility>
        <game-type>RS3</game-type>
        <game-type>OSRS</game-type>
    </compatibility>
    <categories>
        <category>WOODCUTTING</category>
    </categories>
    <!--Required to publish on the bot store-->
    <internal-id>HaxExamplePowerchopper</internal-id>
    <!--The rest are optional-->
    <hidden>false</hidden>
    <open-source>true</open-source>
</manifest>
 
( ͡° ͜ʖ ͡°)
Joined
Mar 30, 2015
Messages
2,416
For one, TaskScript is deprecated so you should be extending TaskBot. Also, EavesDropping errors sometimes just happen. Try reloading the client and running again.
 
Joined
Feb 10, 2017
Messages
15
For one, TaskScript is deprecated so you should be extending TaskBot. Also, EavesDropping errors sometimes just happen. Try reloading the client and running again.

Thank you for the help !
about
TaskScript is deprecated so you should be extending TaskBot

im not really sure on how to do this, caould you maybe give a little bit more hint ?
like this ?
oCjqWOY.png
 
Status
Not open for further replies.
Top