Jump to content

Basic example of State-Node Scripting


Joseph

Recommended Posts

i had a few people questioning how State-Node scripting is different from regular getState()

 

the method getState() loops through an array of a type<?> and finds the one type<?> that returns true.

 

getState():

~every single time onLoop reloops. GetState() is called which then has to loop through his own array of types<?>

~so pretty much its a double consistently . onLoop will execute another getState() loop.

 

State-Node

~every since time onLoop reloops. It refs back to the TaskTracker class. If the private field return null or false. It will loop and find the correct task.

~so pretty much it a double loop every so often. Whenever the current task is null or false

 

 

A Scripting Example. I really did not type to as much but very informative.

ps: i hope you like my convention of having many nested classes

Also you could have the tracker class in a different place. I put it inside this class was for example purposes 


 

import org.osbot.rs07.script.Script;

@ScriptManifest()
public class Example extends Script	{

	private Activity[] taskList = new Activity[] { new CutTree(), new Drop()};
	private TaskTracker taskTracker;
	private Script script;
		
	@Override
	public void onStart() throws InterruptedException {
		this.script = this;
		this.taskTracker = new TaskTracker(taskList);
	}

	@Override
	public int onLoop() throws InterruptedException {
		/** onLoop() always loops
		 * currentTask is null or false, we look for a new task. //we loop thought task array
		 * if currentTask is true, we keep the same currentTask. //it doesnt loop, it has a valid task still
		 * and we only repeat the run() method until boolean return false.
		 * Now that currentTask is false we look for a new task. //we loop throught array 
		 * and it repeats.
		 * 
		 * The taskTracker does all the work for you. 
		 */
		Activity currentTask = this.taskTracker.getActive();
		String status = currentTask.status();
		currentTask.run();
		return 1000;
	}
	
	private class CutTree implements Activity	{

		@Override
		public String status() {
			return "Cut tree";
		}

		@Override
		public boolean validate() throws InterruptedException {
			return !script.inventory.isFull();
		}

		@Override
		public void run() throws InterruptedException {
			//if not animating
			//find tree.
			//cut it
		}}

	private class Drop implements Activity	{

		@Override
		public String status() {
			return "Drop log";
		}

		@Override
		public boolean validate() throws InterruptedException {
			return script.inventory.contains("log");
		}

		@Override
		public void run() throws InterruptedException {
			//look for first item named log
			//if you dont want to keep it
			//drop it
		}}
	
	//does all the work for you
	public class TaskTracker	{
		private Activity[] taskList;
		private Activity activeTask;
		
		public TaskTracker(Activity[] taskList)	{
			this.taskList = taskList;
		}
		
		//return the stated task. Reloops if state return false or null.
		public Activity getActive() throws InterruptedException	{
			if (this.activeTask == null || !this.activeTask.validate())	{
				for (Activity task: taskList)	{
					if (task != null && task.validate())	{
						this.activeTask = task;
						break;
					}
				}
			}		
			return this.activeTask;
		}
		
		//in case you want to force a new current task
		//you can set it null if you want to just it to reloop task.
		public void getAcitive(Activity task)	{
			this.activeTask = task;
		}}
}
 

 

Edited by josedpay
Link to comment
Share on other sites

Only thing I would do different is to make the currentTask a field rather than in the onLoop. Other than that looks sweet, might add a priority system for like when you get into combat it won't continue trying to do the current task?

im actually typing that up i have it in my head already..

So what advantage does this give? Lower processing requirements? Or does it make it easier to refactor code? Or its modular so the task tracker allows for more dynamic options?

Lower processing requirements? yes 

Make the class more organized imagine my crafter script it has sub classes for every script mode. SO this helps me out a lot

Link to comment
Share on other sites

  • 3 weeks later...

I am having a problem with my state node combat script. I have nodes for eating, attacking, and looting so far. It attacks perfectly fine, and eats when health goes below a certain %, but after it kills the monster it does not do anything. I am unsure if the problem lies in my attack node, or my node controller. Although I am assuming the problem is with the attack node. (Possibly not returning true? or getting stuck within the execute method). I will attach my Attack node source code to better help with debugging this issue. 

public class Attack extends Node {
    Constants c = new Constants();
    NPC monster = sA.npcs.closest(" ");

    public Attack(Script sA) {
        super(sA);
    }


    @Override
    public String status() {
        return "Attacking!";
    }


    @Override
    public boolean validate() throws InterruptedException {
        //If in area, and health is > 60, and inv contains lobs
        if (sA.inventory.contains(c.LOBSTER_ID) && sA.myPlayer().getHealth() > 60 && !sA.myPlayer().isUnderAttack()) {
            return true;
        } else {
            return false;
        }
    }


    @Override
    public boolean execute() throws InterruptedException {
        if (monster != null && monster.getHealth() > 0) {
            if (monster.isVisible()) {
                sA.camera.toEntity(monster);
                monster.interact("Attack");
                sA.sleep(sA.random(1000, 3000));
            }
                if (sA.myPlayer().isUnderAttack()) {
                    return true;
                }
            }

        return false;
    }
}

Replaced the monster I am fighting with "monster", in order to keep some form of secrecy ;)

Link to comment
Share on other sites

I am having a problem with my state node combat script. I have nodes for eating, attacking, and looting so far. It attacks perfectly fine, and eats when health goes below a certain %, but after it kills the monster it does not do anything. I am unsure if the problem lies in my attack node, or my node controller. Although I am assuming the problem is with the attack node. (Possibly not returning true? or getting stuck within the execute method). I will attach my Attack node source code to better help with debugging this issue. 

 

Replaced the monster I am fighting with "monster", in order to keep some form of secrecy wink.png

sA.myPlayer().getHealth() > 60 this is what killing you because use the skill hp.

 

method above only updated data when hp bar is visible i believe 

Link to comment
Share on other sites

  • 3 weeks later...

Ye it is, public and abstract modifiers can be omitted in interface method declarations though ;)

  

where's the 'Activity' class?

 

I want to see how it's set up.

 

EDIT:

 

It's an interface like this?

public interface Activity{
	
	public abstract boolean activate();
	public abstract void execute();
	public abstract String status();

}
Link to comment
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.

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...