Jump to content
Search In
  • More options...
Find results that contain...
Find results in...
Encoded

Task Framework Tutorial

Recommended Posts

Task Framework

A set is a collection that contains no duplicate elements.
The task framework is a sorted set of tasks where each task performs a specific action.
Tasks are sorted in descending order by priority.

Each task has a validate and execute method. The validate method returns a boolean that decides whether or not the task should execute. The execute method should be called when the validate method returns true.

Priority determines which task will be returned by the getValidTask method if two or more tasks' validate methods are to return true.
If you find yourself having two tasks' validate methods returning true with the same priority level, add additional priority levels or modify the tasks' validate methods.

TaskSet is the aggregate of all the tasks. Tasks are sorted upon being added to the set. The getValidTask method returns the highest priority task with a validate method that returns true or null if no task is valid.

Don't forgot to change the packaging if you are copy/pasting the following code.

Task.java
package scripts.api.script.frameworks.task;

public interface Task {

    Priority priority();

    boolean validate();

    void execute();

}
Priority.java
package scripts.api.script.frameworks.task;

public enum Priority {

    HIGH,
    MEDIUM,
    LOW,
    NONE

}
TaskSet.java
package scripts.api.script.frameworks.task;

import java.util.Arrays;
import java.util.Collection;
import java.util.Comparator;
import java.util.List;
import java.util.TreeSet;

public class TaskSet extends TreeSet<Task> {

    public TaskSet() {
        super(Comparator.comparing(Task::priority).thenComparing(Comparator.comparing(task -> task.getClass().getName())));
    }

    public TaskSet(Task... tasks) {
        super(Comparator.comparing(Task::priority).thenComparing(Comparator.comparing(task -> task.getClass().getName())));
        addAll(tasks);
    }

    public TaskSet(Comparator<? super Task> comparator) {
        this();
    }

    public TaskSet(Collection<? extends Task> c) {
        this(c.toArray(new Task[c.size()]));
    }

    public TaskSet(SortedSet<Task> s) {
        this(s.toArray(new Task[s.size()]));
    }

    public boolean addAll(Task... tasks) {
        return super.addAll(Arrays.asList(tasks));
    }

    public Task getValidTask() {
        for (Task task : this) {
            if (task.validate()) {
                return task;
            }
        }
        return null;
    }

}
Example Task
public class ExampleTask implements Task {

    @Override
    public String toString() {
        return "Example Task";
    }

    @Override
    public Priority priority() {
        return Priority.LOW;
    }

    @Override
    public boolean validate() {
        return false;
    }

    @Override
    public void execute() {

    }
    
}
Example Script run Method
@Override
public void run() {
    TaskSet tasks = new TaskSet(new ExampleTask());
    while (isRunning) {
        Task task = tasks.getValidTask();
        if (task != null) {
            status = task.toString();
            task.execute();
        }
    }
}
Edited by Encoded
  • Like 1
  • Thanks 1

Share this post


Link to post
Share on other sites

@Encoded So can you tell me how much stuff you should include in each task? Because it seems counter-intuitive to do a new task for every small action if your script is big.

So for example if I want my script to wc and bank before doing another task that could be a quest or other skill. 

I can include my whole wcing/banking code in a single task?

Or should I spread my wcing into various tasks. (one for walking, one for cutting, one for banking)

 

Share this post


Link to post
Share on other sites
5 hours ago, Enano25 said:

@Encoded So can you tell me how much stuff you should include in each task? Because it seems counter-intuitive to do a new task for every small action if your script is big.

So for example if I want my script to wc and bank before doing another task that could be a quest or other skill. 

I can include my whole wcing/banking code in a single task?

Or should I spread my wcing into various tasks. (one for walking, one for cutting, one for banking)

 

I would separate walking, banking, and wcing into 3 tasks. They each need to be done when different conditions are met, and should be assigned different priorities based on the conditions met.

 

Share this post


Link to post
Share on other sites
8 hours ago, Azuz53487 said:

Wasn't this posted somewhere? Can't remember where I saw it.

I had it in the snippets section, but I rewrote it and moved it to tutorials since that's where the other frameworks are posted.

 

7 hours ago, Enano25 said:

@Encoded So can you tell me how much stuff you should include in each task? Because it seems counter-intuitive to do a new task for every small action if your script is big.

So for example if I want my script to wc and bank before doing another task that could be a quest or other skill. 

I can include my whole wcing/banking code in a single task?

Or should I spread my wcing into various tasks. (one for walking, one for cutting, one for banking)

You can break it down as much as you want. I've even made scripts where a Task will have its own TaskSet within it.
If you want to chain TaskSets together, I suggest adding a stopping condition and then creating a linked list of TaskSets so that you can get the next TaskSet once the current's stopping condition is met. That's what I currently do, but this post is about the basics so I didn't include that.

Edited by Encoded
  • Like 1

Share this post


Link to post
Share on other sites
3 hours ago, Encoded said:

I had it in the snippets section, but I rewrote it and moved it to tutorials since that's where the other frameworks are posted.

 

You can break it down as much as you want. I've even made scripts where a Task will have its own TaskSet within it.
If you want to chain TaskSets together, I suggest adding a stopping condition and then creating a linked list of TaskSets so that you can get the next TaskSet once the current's stopping condition is met. That's what I currently do, but this post is about the basics so I didn't include that.

Aha, I see! Great! :)

Share this post


Link to post
Share on other sites

Lets say I have a Mining task...should it be endless mining... or a task set of MineOre tasks. And what if i want to keep a record of total Ore Mined... How would you recommend keeping track of that value outside of the shortlived task class, without creating a major spaghetti mess of code..

With this system I currently have..

Mining/tasks/MineOre.java

Mining/MiningScript.java

 

Unsure how to convey success/fail information from MineOre's execution to mining script

It's really late maybe my mind is just a bit slow

Edit: ok think I understand now, fail shouldn't matter the task is about completing a task in programming sense, not the same as game sense..

Did it mine ore succesfully? No... But was the mine ore TASK completed? Yeah I guess.. makes me wonder whether it should be named AttemptMineOre would probably make more sense

 

Also static counter in another class will solve keeping track of missed ores, will give it a go tomorrow 

Edited by pudsta19

Share this post


Link to post
Share on other sites

Great tutorial @Encoded

Have you experimented with threading in this framework?

Interrupting the current the task for example based on a certain priority of a task that is being validated in another thread?

EG Person appears near you in wilderness triggers task that stops the current task.

Edited by Zapcrack
  • Like 1

Share this post


Link to post
Share on other sites
On 10/28/2019 at 4:21 PM, Zapcrack said:

Great tutorial @Encoded

Have you experimented with threading in this framework?

Interrupting the current the task for example based on a certain priority of a task that is being validated in another thread?

EG Person appears near you in wilderness triggers task that stops the current task.

Instead of dealing unnecessarily with messy threading logic, you could have a service that houses the logic for determining this state you speak of.

IE. determining if there is player next to you. You could then place a dependency on this service for all tasks that are interested in this specific state.

Basically I shouldn't be mining in the wilderness if there is a pker next to me. The mining node has a dependency on the service to determine if there is a pker next to you.

Based on the node framework design this conditional logic should be called from within your mining validator implementation.

Further down stream, while mining the rock in your dynamic sleeping/sleeping method while mining, this state should be checked, and if found the task should return/terminate.

The main loop should then pick up your node that corresponds with what actions you would want to take in this scenario. IE. teleport, run, etc.

 

Also as far as the priority system goes, I typically see this type of structure being used improperly in place of proper conditional/state logic.

Instead of clearly defining the state/validator for the node, people start using a priority system as an override.

Where it really breaks down is when you have a bunch of nodes in a "high" priority, but you want one in an even higher priority, so you add "very high" etc.

to the priority list/enum. 

Debugging this type of thing could become difficult as the states are unclear mixing in the element of priority on top of poor state logic.

Warfront1

  • Like 1

Share this post


Link to post
Share on other sites
On 10/28/2019 at 9:21 PM, Zapcrack said:

Great tutorial @Encoded

Have you experimented with threading in this framework?

Interrupting the current the task for example based on a certain priority of a task that is being validated in another thread?

EG Person appears near you in wilderness triggers task that stops the current task.

You could store your tasks, or actions how i like to call them, in a LIFO structure, like a stack. 
 

public class Task {

    private Stack<InteractableAction> actionStack = new Stack<>();
    private Goal goal;

    public Task(InteractableAction baseAction, Goal goal){
        actionStack.push(baseAction);
        this.goal = goal;
    }

    public boolean completed(){
        return goal.completed();
    }

    public void execute(){
        InteractableAction currentAction = actionStack.peek();
        if(currentAction == null)
            return;
        if(!currentAction.completed()){
            InteractableAction response = (InteractableAction) currentAction.execute();
            if(response != null){
                actionStack.push(response);
            }
        } else {
            actionStack.pop();
        }
    }

    public void end(){
        actionStack = null;
    }

}
public abstract class InteractableAction {

    /*
        return a new action if a new action is required, (e.g walking)
        return null if no new action is required.
     */
    public abstract Action execute();

    /*
        return true if the action has been completed,
        return false otherwise.
     */
    public abstract boolean completed();

}



In this case your base action would be a mining action which is used to mine your rocks, the mining action returns a bankaction when your inventory is full, the bank action returns a walking action when its completed, etc.

in your mining action, you could add a player check, which if true returns a fleeing action to the action stack in the task. this fleeing action has to be completed before any other action can get executed

Share this post


Link to post
Share on other sites
3 hours ago, gef30 said:

You could store your tasks, or actions how i like to call them, in a LIFO structure, like a stack. 
 

public class Task {

    private Stack<InteractableAction> actionStack = new Stack<>();
    private Goal goal;

    public Task(InteractableAction baseAction, Goal goal){
        actionStack.push(baseAction);
        this.goal = goal;
    }

    public boolean completed(){
        return goal.completed();
    }

    public void execute(){
        InteractableAction currentAction = actionStack.peek();
        if(currentAction == null)
            return;
        if(!currentAction.completed()){
            InteractableAction response = (InteractableAction) currentAction.execute();
            if(response != null){
                actionStack.push(response);
            }
        } else {
            actionStack.pop();
        }
    }

    public void end(){
        actionStack = null;
    }

}
public abstract class InteractableAction {

    /*
        return a new action if a new action is required, (e.g walking)
        return null if no new action is required.
     */
    public abstract Action execute();

    /*
        return true if the action has been completed,
        return false otherwise.
     */
    public abstract boolean completed();

}



In this case your base action would be a mining action which is used to mine your rocks, the mining action returns a bankaction when your inventory is full, the bank action returns a walking action when its completed, etc.

in your mining action, you could add a player check, which if true returns a fleeing action to the action stack in the task. this fleeing action has to be completed before any other action can get executed

This looks look a tree framework to me, i have been trying to experiment with the Task framework. I might give this a go after i get a working script running with the Task Framework.

 

11 hours ago, warfront1 said:

Instead of dealing unnecessarily with messy threading logic, you could have a service that houses the logic for determining this state you speak of.

IE. determining if there is player next to you. You could then place a dependency on this service for all tasks that are interested in this specific state.

Basically I shouldn't be mining in the wilderness if there is a pker next to me. The mining node has a dependency on the service to determine if there is a pker next to you.

Based on the node framework design this conditional logic should be called from within your mining validator implementation.

Further down stream, while mining the rock in your dynamic sleeping/sleeping method while mining, this state should be checked, and if found the task should return/terminate.

The main loop should then pick up your node that corresponds with what actions you would want to take in this scenario. IE. teleport, run, etc.

 

Also as far as the priority system goes, I typically see this type of structure being used improperly in place of proper conditional/state logic.

Instead of clearly defining the state/validator for the node, people start using a priority system as an override.

Where it really breaks down is when you have a bunch of nodes in a "high" priority, but you want one in an even higher priority, so you add "very high" etc.

to the priority list/enum. 

Debugging this type of thing could become difficult as the states are unclear mixing in the element of priority on top of poor state logic.

Warfront1

Yeah this seems like a cleaner approach compared to my threading idea, will try this out for my script. Thanks!

Share this post


Link to post
Share on other sites
19 hours ago, Zapcrack said:

This looks look a tree framework to me, i have been trying to experiment with the Task framework. I might give this a go after i get a working script running with the Task Framework.

Its not a tree framework, tho it does not use priority. By using a LIFO structure like a stack, you can push a new task/action to your stack at any given time, which has to be executed first. Since Stack.peek returns the newest entry to the stack.

Share this post


Link to post
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.


  • Our picks

    • [CONTEST ANNOUNCEMENT] 2019 Botter's Choice Awards
      2019 Botter’s Choice Awards

      To celebrate the launch of our TRiBot Official RuneScape Bot Blog,

      we’re doing a giveaway! 

      The TRiBot Official RuneScape Bot Blog: 

      Teaching you how to do more advanced botting, faster.
      Contest Details

      Prize: 3 winners will be selected to win 25 TRiBot credits.

      How to enter:

      Respond to this forum post by November 12th tagging the thread for: 

      Your favorite script

      Provide a brief explanation (1-2 sentences) why you think that script should be put in the top 5. 

      Who can enter?

      Botter’s who are not currently scripters. Sorry scripters, the people are going to vote. Your contest is here.

      The top 5 in each category will be showcased on our TRiBot Official RuneScape Bot Blog in a “People’s Choice” section and promoted across the TRiBot website. 

      -- Credits will be awarded based on thoughtfulness and humor -- 

      Bonus points

      Use a meme in your explanation. Because we all love memes.

      *no purchase necessary. Winners will be announced on Friday, November 15, 2019 at 4:00 p.m. on our News and Announcements forum. 

      -- Vote Below -- 
        • Like
      • 28 replies
    • [READ TO THE END FOR A TEASER]

      I've noticed some new TRiBotters have had some troubles finding out sources of how to do certain things, such as using advanced scripts and often get lost in the forums.

      We are still getting posts asking where to start, what to do, recommended scripts, etc. 

      As many of you know, I am new to the team, and had troubles myself learning how to bot, let alone script. 

      So, what our team decided to do was make it easier to learn how to bot, how to script, and just become an overall better botter and scripter faster. 

      As some of you might have seen, I've posted 3 new blogs, you can check it out by clicking on the following picture or here.


      These first 3 blogs are the first of many blogs that will be TRiBot official. They are encouraged to be challenged, improved upon and act as A Best Practices Guide for Botters.

      What information would you like to see in the blogs?

      👇 [TEASER] 👇

      .

      .

      .

      We are going to be hosting a  CONTEST  this  OCTOBER.

      Its scary to think how soon you'll find out.👻

      Stay tuned.


      - RileyZ
      • 8 replies
    • Today marks a big day for TRiBot! To make it easier for users to use TRiBot, we've created installers available for every platform! These installers are all bundled with the latest version of OpenJDK 1.8 (Java 😎, which is LG compatible.

      Using TRiBot is now easy. Simply download the installer for your platform, install TRiBot, and run it. The TRiBot Loader will correctly identify the bundled JDK so there's no need to change the Java selection.

      Windows

      EXE installer: TRiBot-windows-x64-4.0.3.exe


      MSI installer: TRiBot-windows-x64-4.0.3.msi


      Portable version: TRiBot-windows-x64-4.0.3.zip


      Mac OS

      Installer: TRiBot-macos-4.0.3.dmg


      Portable version: TRiBot-macos-4.0.3.tgz


      Unix/Linux

      Installer: TRiBot-unix-4.0.3.sh


      RPM installer (CentOS/Fedora): TRiBot-linux-4.0.3.rpm


      DEB installer (Debian): TRiBot-linux-4.0.3.deb


      Portable version: TRiBot-unix-4.0.3.tar.gz


      Platform Independent

      JAR file: tribot-loader-4.0.3.jar


      Note that this jar file does not include the bundled JDK.



      Windows and Mac OS users may notice a warning message stating that the installer/application is un-recognized or un-trusted. Please ignore this message and proceed with running the installer/application. We need to acquire a code signing certificate so that we can sign the installers letting the operating system know that these files can be trusted. It will take a week or more to acquire one, so please hold tight.

      Other notable changes to the TRiBot Loader:

      Support getting the version from OpenJDK distributions


      Add check for bundled JDK


      Copy OpenJDK tools.jar to the bundled JDK if not present


      Set the current java as the first available list entry


      Ignore Java versions which are symbolic links


      Make the bundled JDK the preferred Java version


      Update icon images


      Reduce the number of HTTP calls
      • 26 replies
    • TRiBot is looking to improve a lot of its customer relationship management, customer on boarding process, customer experience, design elements, community engagement and pretty much everything else you can imagine when it comes to marketing.

      Our goal: To ensure that the marketing done TRULY reflects the experience and does not shine an inaccurate light on what TRiBot is lacking in.

      So I ask, what do you love about TRiBot and what do you hate about TRiBot? What does O S Bot, Rune M8, PowR Bot and Dre amBot do better? (yes I purposely didn't spell it right 😂).

      Love, 

      RileyZ
        • Like
      • 18 replies
    • Hello TRiBot,

      Today we have a significant release that has been in the works for the last month addressing several key issues, features and bugs in the backlog.

      With these changes, we are also including a new TRiBot Loader which will allow you to select any version that is released. This adds the flexibility of allowing you to revert to a previous version should an issue arise, run development only builds, view an accurate change log between versions etc. we are very proud to offer this feature and think it will add a lot more functionality down the road as we continue to release new versions.

      These changes include 80+ commits by our development team, a list of them is summarized below and also available for your viewing pleasure in the new TRiBot Loader.

      In addition, we have taken additional steps to improve as a development team by adding continuous integration and deployment into our workflow to assist in delivering timely releases such as bug fixes as well as new features on a weekly basis depending on our development cycle.
      • 39 replies
  • Recently Browsing   0 members

    No registered users viewing this page.

×
×
  • Create New...