Tutorial An Introduction to the TaskScript

Discussion in 'Tutorials & Resources' started by SlashnHax, Mar 1, 2015.

Thread Status:
Not open for further replies.
  1. SlashnHax

    SlashnHax The Chosen One

    Joined:
    Dec 10, 2014
    Messages:
    2,951
    Likes Received:
    861
    An Introduction to the TaskScript

    Contents:
    • Introduction
    • Overview
    • Pros and Cons
      • Pros
      • Cons
    • The Framework
      • TaskScript
      • Task
    • Example script bot (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 bot 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 bots 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 bots
    The Framework
    TaskScript (Documentation)
    The TaskScript is the main class of your script bot. 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 bot (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 bot class and the 2 Tasks, I prefer to have my Tasks in a tasks package.
    Project overview:
    [​IMG]
    Main script bot Class:
    Code (Text):
    1.  
    2. package com.slashnhax.tutorials.task_script_tutorial;
    3.  
    4. import com.runemate.game.api.script.framework.task.TaskScript;
    5.  
    6. public class ExamplePowerchopper extends TaskScript {
    7.     @Override
    8.     public void onStart(String... args){
    9.  
    10.     }
    11. }
    12.  
    The 3 Task stubs:
    Code (Text):
    1.  
    2. package com.slashnhax.tutorials.task_script_tutorial.tasks;
    3.  
    4. import com.runemate.game.api.script.framework.task.Task;
    5.  
    6. public class Chop extends Task {
    7.     @Override
    8.     public boolean validate() {
    9.         return false;
    10.     }
    11.  
    12.     @Override
    13.     public void execute() {
    14.  
    15.     }
    16. }
    17.  
    Code (Text):
    1.  
    2. package com.slashnhax.tutorials.task_script_tutorial.tasks;
    3.  
    4. import com.runemate.game.api.script.framework.task.Task;
    5.  
    6. public class Drop extends Task {
    7.     @Override
    8.     public boolean validate() {
    9.         return false;
    10.     }
    11.  
    12.     @Override
    13.     public void execute() {
    14.  
    15.     }
    16. }
    17.  
    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 (Text):
    1.  
    2. @Override
    3. public boolean validate() {
    4.     return Players.getLocal().getAnimationId() == -1 && !Inventory.isFull() && !GameObjects.newQuery().names("Willow").actions("Chop down").results().isEmpty();
    5. }
    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 (Text):
    1.  
    2. @Override
    3. public void execute() {
    4.     GameObject tree = GameObjects.newQuery().names("Willow").actions("Chop down").results().nearest();
    5.     if (tree != null) {
    6.         if (!tree.isVisible()){
    7.             Camera.turnTo(tree);
    8.             if(!tree.isVisible()){
    9.                 Path p = BresenhamPath.buildTo(tree);
    10.                 if(p != null)
    11.                     p.step();
    12.             }
    13.         } else if(tree.interact("Chop down")){
    14.             Execution.delayUntil(()->Players.getLocal().getAnimationId() != -1, 5000);
    15.         }
    16.     }
    17. }
    18.  

    • Drop
    We want Drop to execute when our Inventory is full, that's the only criteria.
    Our validate should look like this:
    Code (Text):
    1.  
    2. @Override
    3. public boolean validate() {
    4.     return Inventory.isFull();
    5. }
    6.  
    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 (Text):
    1.  
    2. @Override
    3. public void execute() {
    4.     if(InterfaceWindows.getInventory().isOpen()) {
    5.         for(SpriteItem item: Inventory.getItems("Willow logs")){
    6.             if(item.interact("Drop"))
    7.                 Execution.delayUntil(()->!item.isValid(), 1000);
    8.         }
    9.     } else {
    10.         InterfaceWindows.getInventory().open();
    11.     }
    12. }
    13.  
    Adding the Tasks to the TaskScript
    Adding the Tasks to your script bot 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 bot class should look similar to:
    Code (Text):
    1.  
    2. import com.runemate.game.api.script.framework.task.TaskScript;
    3. import com.slashnhax.tutorials.task_script_tutorial.tasks.Chop;
    4. import com.slashnhax.tutorials.task_script_tutorial.tasks.Drop;
    5.  
    6. public class ExamplePowerchopper extends TaskScript {
    7.     @Override
    8.     public void onStart(String... args){
    9.         setLoopDelay(250, 500);
    10.         add(new Chop(), new Drop());
    11.     }
    12. }
    13.  
    The Manifest
    Nothing special about the Manifest, here's mine:
    Code (Text):
    1.  
    2. <manifest>
    3.     <main-class>com.slashnhax.tutorials.task_script_tutorial.ExamplePowerchopper</main-class>
    4.     <name>Example Powerchopper</name>
    5.      <description>Example Powerchopper, uses TaskScript. Chops and drops, nothing special</description>
    6.     <version>1.0.0</version>
    7.     <compatibility>
    8.         <game-type>RS3</game-type>
    9.         <game-type>OSRS</game-type>
    10.     </compatibility>
    11.     <categories>
    12.         <category>WOODCUTTING</category>
    13.     </categories>
    14.     <!--Required to publish on the bot store-->
    15.     <internal-id>HaxExamplePowerchopper</internal-id>
    16.     <!--The rest are optional-->
    17.     <hidden>false</hidden>
    18.     <open-source>true</open-source>
    19. </manifest>
    20.  

    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​
     
    #1 SlashnHax, Mar 1, 2015
    Last edited: Jan 21, 2017
  2. KAB11

    Joined:
    Feb 17, 2015
    Messages:
    113
    Likes Received:
    7
    Thanks for giving the community more tutorials, really helps new programmers like myself!
     
  3. Geashaw

    Joined:
    Jan 8, 2015
    Messages:
    1,275
    Likes Received:
    217
  4. Dellgenius

    Joined:
    Dec 27, 2014
    Messages:
    285
    Likes Received:
    39
    Awesome. Absolutely Awesome
     
  5. Zallen93

    Joined:
    Jul 17, 2014
    Messages:
    9
    Likes Received:
    0
    Thanks for this tutorial, great resource to get up and running with scripting for RuneMate!
     
  6. greyb3ast

    Joined:
    Aug 7, 2015
    Messages:
    13
    Likes Received:
    0
    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.
     
    #6 greyb3ast, Aug 24, 2015
    Last edited: Aug 24, 2015
  7. SlashnHax

    SlashnHax The Chosen One

    Joined:
    Dec 10, 2014
    Messages:
    2,951
    Likes Received:
    861
    newQuery is better and more powerful, I used getLoaded cause I was tired and it's less typing xD
     
  8. Aidden

    Aidden The better executive ;)

    Joined:
    Dec 3, 2013
    Messages:
    3,398
    Likes Received:
    683
    @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
     
    NZL likes this.
  9. CodeNinja

    Joined:
    Dec 20, 2016
    Messages:
    12
    Likes Received:
    1
    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
     
  10. sreno

    sreno Learning Java

    Joined:
    Dec 24, 2016
    Messages:
    22
    Likes Received:
    1
  11. SlashnHax

    SlashnHax The Chosen One

    Joined:
    Dec 10, 2014
    Messages:
    2,951
    Likes Received:
    861
    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.
    --- Double Post Merged, Jan 21, 2017, Original Post Date: Jan 21, 2017 ---
    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.
     
  12. sreno

    sreno Learning Java

    Joined:
    Dec 24, 2016
    Messages:
    22
    Likes Received:
    1
    I tried changing the bot directory to what you said and many other options and none of them worked.

    Is is something to do with the line "public class ExampleBot extends TaskScript?

    Gyazo - db4da85f7d39feb15005c999c1827cd7.png
     
  13. Serene

    Serene ( ͡° ͜ʖ ͡°)

    Joined:
    Mar 30, 2015
    Messages:
    1,143
    Likes Received:
    258
    TaskScript is deprecated, change it to TaskBot
     
    sreno likes this.
  14. sreno

    sreno Learning Java

    Joined:
    Dec 24, 2016
    Messages:
    22
    Likes Received:
    1
  15. Savior

    Savior I'm your motherfucking conscience

    Joined:
    Nov 17, 2014
    Messages:
    3,060
    Likes Received:
    1,192
  16. sreno

    sreno Learning Java

    Joined:
    Dec 24, 2016
    Messages:
    22
    Likes Received:
    1
    Thanks that fixed it, in my manifest I had com.sreno.bots.Powerchopper not com.sreno.bots.Powerchopper(project).Powerchopper(mainclass)
     
  17. Savior

    Savior I'm your motherfucking conscience

    Joined:
    Nov 17, 2014
    Messages:
    3,060
    Likes Received:
    1,192
    Glad you could fix it, feel free to join us on slack btw :)
     
    sreno likes this.
  18. MateRune

    Joined:
    Feb 10, 2017
    Messages:
    15
    Likes Received:
    2
    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 (Text):
    1.  
    2. "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:
    3. [Debug] RuneMate Version: 2.4.18
    4. [Debug] Java Version: 8u121 x86 (Oracle Corporation)
    5. [Debug] Operating System: Windows 7 x64
    6. 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]
    7.     at nul.iIiIIIiiiiIi.for(pqb:138)
    8.     at com.runemate.game.api.hybrid.Environment.getBot(emb:71)
    9.     at nul.iiiIiIiiiIii.run(pbb:147)
    10.     at java.util.concurrent.Executors$RunnableAdapter.call(Unknown Source)
    11.     at java.util.concurrent.FutureTask.runAndReset(Unknown Source)
    12.     at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access$301(Unknown Source)
    13.     at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(Unknown Source)
    14.     at java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source)
    15.     at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
    16.     at java.lang.Thread.run(Unknown Source)
    17. 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>.
    18. 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
    19. [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.
    20. 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]
    21.     at nul.iIiIIIiiiiIi.for(pqb:138)
    22.     at com.runemate.game.api.hybrid.Environment.getGameType(emb:160)
    23.     at com.runemate.game.api.hybrid.Environment.isRS3(emb:194)
    24.     at nul.iiIIIIiIiiii.for(nab:75)
    25.     at nul.iiIIIIiIiiii.validate(nab:143)
    26.     at com.runemate.game.api.script.framework.LoopingBot.run(wxa:96)
    27.     at java.util.concurrent.Executors$RunnableAdapter.call(Unknown Source)
    28.     at java.util.concurrent.FutureTask.run(Unknown Source)
    29.     at java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source)
    30.     at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
    31.     at java.lang.Thread.run(Unknown Source)
    32.  
    33. Exception: java.lang.NullPointerException thrown from the UncaughtExceptionHandler in thread "Thread-19"
    34.  
    35. Process finished with exit code 0
    36.  

    Project Structure
    [​IMG]

    This is the
    PowerChopper.java
    Code (Text):
    1.  
    2. package com.materune.bots.PowerChopper;
    3.  
    4. import com.runemate.game.api.script.framework.task.TaskScript;
    5. import com.materune.bots.PowerChopper.tasks.Chop;
    6. import com.materune.bots.PowerChopper.tasks.Drop;
    7.  
    8. public class PowerChopper extends TaskScript {
    9.     @Override
    10.     public void onStart(String... args){
    11.         setLoopDelay(250, 500);
    12.         add(new Chop(), new Drop());
    13.     }
    14. }
    15.  

    Chop.java
    Code (Text):
    1.  
    2. package com.materune.bots.PowerChopper.tasks;
    3.  
    4. import com.runemate.game.api.hybrid.entities.GameObject;
    5. import com.runemate.game.api.hybrid.local.hud.interfaces.Inventory;
    6. import com.runemate.game.api.hybrid.location.navigation.Path;
    7. import com.runemate.game.api.hybrid.location.navigation.basic.BresenhamPath;
    8. import com.runemate.game.api.hybrid.region.GameObjects;
    9. import com.runemate.game.api.hybrid.region.Players;
    10. import com.runemate.game.api.script.Execution;
    11. import com.runemate.game.api.script.framework.task.Task;
    12. import com.runemate.game.api.hybrid.local.Camera;
    13.  
    14. public class Chop extends Task {
    15.     @Override
    16.     public boolean validate() {
    17.         return Players.getLocal().getAnimationId() == -1 && !Inventory.isFull() && !GameObjects.newQuery().names("Tree").actions("Chop down").results().isEmpty();
    18.     }
    19.  
    20.     @Override
    21.     public void execute() {
    22.         GameObject tree = GameObjects.newQuery().names("Tree").actions("Chop down").results().nearest();
    23.         if (tree != null) {
    24.             if (!tree.isVisible()) {
    25.                 Camera.turnTo(tree);
    26.                 if (!tree.isVisible()) {
    27.                     Path p = BresenhamPath.buildTo(tree);
    28.                     if (p != null)
    29.                         p.step();
    30.                 } else if (tree.interact("Chop down")) {
    31.                     Execution.delayUntil(() -> Players.getLocal().getAnimationId() != -1, 5000);
    32.                 }
    33.             }
    34.         }
    35.     }
    36. }
    37.  

    Drop.java
    Code (Text):
    1.  
    2. package com.materune.bots.PowerChopper.tasks;
    3.  
    4. import com.runemate.game.api.hybrid.local.hud.interfaces.InterfaceWindows;
    5. import com.runemate.game.api.hybrid.local.hud.interfaces.Inventory;
    6. import com.runemate.game.api.hybrid.local.hud.interfaces.SpriteItem;
    7. import com.runemate.game.api.script.Execution;
    8. import com.runemate.game.api.script.framework.task.Task;
    9.  
    10. public class Drop extends Task {
    11.     @Override
    12.     public boolean validate() {
    13.         return Inventory.isFull();
    14.  
    15.     }
    16.  
    17.     @Override
    18.     public void execute() {
    19.         if(InterfaceWindows.getInventory().isOpen()) {
    20.             for(SpriteItem item: Inventory.getItems("Logs")){
    21.                 if(item.interact("Drop"))
    22.                     Execution.delayUntil(()->!item.isValid(), 1000);
    23.             }
    24.         } else {
    25.             InterfaceWindows.getInventory().open();
    26.         }
    27.     }
    28. }
    29.  

    PowerChopper.manifest.xml
    Code (Text):
    1.  
    2. <manifest>
    3.     <main-class>com.materune.bots.PowerChopper.PowerChopper</main-class>
    4.     <name>Powerchopper</name>
    5.     <description>Example Powerchopper, uses TaskScript. Chops and drops, nothing special</description>
    6.     <version>1.0.0</version>
    7.     <compatibility>
    8.         <game-type>RS3</game-type>
    9.         <game-type>OSRS</game-type>
    10.     </compatibility>
    11.     <categories>
    12.         <category>WOODCUTTING</category>
    13.     </categories>
    14.     <!--Required to publish on the bot store-->
    15.     <internal-id>HaxExamplePowerchopper</internal-id>
    16.     <!--The rest are optional-->
    17.     <hidden>false</hidden>
    18.     <open-source>true</open-source>
    19. </manifest>
    20.  
     
  19. Serene

    Serene ( ͡° ͜ʖ ͡°)

    Joined:
    Mar 30, 2015
    Messages:
    1,143
    Likes Received:
    258
    For one, TaskScript is deprecated so you should be extending TaskBot. Also, EavesDropping errors sometimes just happen. Try reloading the client and running again.
     
  20. MateRune

    Joined:
    Feb 10, 2017
    Messages:
    15
    Likes Received:
    2
    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 ?
    [​IMG]
     
Thread Status:
Not open for further replies.

Share This Page

Loading...