Jump to content

OSBot Scripting Decision Tree Framework


Recommended Posts

Posted (edited)

 

 

Hey folks, here's a decision tree framework for writing Scripts on OSBot. My intent is to simplify the process of making iterative decisions and provide flexibility to the user should they wish to change the decision model. I will be using something similar to this in order to build a F2P PKing Script, so let me know your thoughts on where it can be improved!

OUTDATED: CLICK HERE (for a behavior tree framework)

Source

Download: FastUpload - 1.1 (25 11:00 Jan 2023)

Changes

  • 1.1 - removed redundant if condition in deserialize method.
  • 1.0 - initial release.

Setup

  1. Create a "DeepButler" folder in OSBot's Data folder (getDirectoryData).
  2. Create a "deepbutler.json" file in the "DeepButler" folder.
  3. Use the example decision tree (and later have fun making your own!)
  4. Modify your OSBot to allow reflection (add "-allow reflection" to run.bat).
  5. Enter W326 and a secondary world to test the framework.

Remarks

  • This framework has not been tested on any scripts yet. I intend to use a similar iteration of this framework on a F2P PKing Script.
  • Create new Conditions and Tasks, and change the decision tree as required.
  • The decision tree doesn't necessarily have to be processed in "onLoop". In fact, I think there's great potential by listening for game tick events.
  • Every Task is a Condition. It makes sense to simply return "true" in Tasks that do not branch anywhere (prompt a re-loop), otherwise use them as a condition & a task if there's subsequent decisions to be processed.
  • The "Cond" annotation is something I was trialing in lieu of reflection. Not integrated at the moment.

Snippets

deepbutler.json

Spoiler
{
  "name": "conditions.CheckWorld",
  "no": {
    "name": "conditions.tasks.LogToHop",
    "no": null,
    "yes": null
  },
  "yes": {
    "name": "conditions.IsMoving",
    "no": {
      "name": "conditions.tasks.LogNotMoving",
      "no": null,
      "yes": null
    },
    "yes": {
      "name": "conditions.tasks.LogMoving",
      "no": null,
      "yes": null
    }
  }
}

 

DeepButler.java

Spoiler
public final class DeepButler extends Script {
    private Condition dto;
    @Override
    public void onStart() {
        DecisionTreeParser dtp = new DecisionTreeParser(getBot());
        dtp.load(getDirectoryData());
        dto = dtp.parse();
    }
    @Override
    public int onLoop() {
        Condition parser = dto;
        int opcode = 1;
        // Terminate by reaching end of decision tree
        // or on any opcode of 0 or less.
        while ((parser != null) && opcode > 0) {
            if (parser.check()) {
                if (parser instanceof Task) {
                    opcode = ((Task) parser).execute();
                    // Affect decision tree based on opcode.
                    // ...
                }
                parser = parser.getYes();
            } else {
                parser = parser.getNo();
            }
        }
        return 600;
    }
}

 

Decision Tree Parser (deserialize method)

Spoiler
private Condition deserialize(JsonElement node) {
    if (node.isJsonNull()) {
        return null;
    }
    Condition task;
    JsonObject jObj = node.getAsJsonObject();
    try {
        task = (Condition) Class.forName(jObj.get("name").getAsString()).
                getConstructor(Bot.class).
                newInstance(bot);
    } catch (ClassNotFoundException e) {
        bot.getMethods().log("Reflection: Mistake in class name or type, see deepbutler.json.");
        throw new RuntimeException(e);
    } catch (NoSuchMethodException e) {
        bot.getMethods().log("Reflection: Condition or Task instructor implemented incorrectly.");
        throw new RuntimeException(e);
    } catch (InstantiationException | IllegalAccessException | InvocationTargetException e) {
        bot.getMethods().log("Reflection: Other issue.");
        throw new RuntimeException(e);
    }
    task.setNo(deserialize((jObj.get("no"))));
    task.setYes(deserialize((jObj.get("yes"))));
    return task;
}

 

Edited by TheJacob
Released a different framework that's much more practical. Linked.
  • Like 2
Posted (edited)
8 hours ago, Czar said:

I will check this out, respect for going away from the norm in scripting and trying new (+ better) stuff :doge: 

Thanks @Czar! I'm still figuring out a few more things about the OSBot api, but I'm aiming within the next two weeks to have a script released demonstrating this framework (more complicated than the simple one I included with this release).

I'm sure there's still some drawbacks with it's current design, so definitely give it a look and let me know what you think. Open to all feedback.

For example, I don't know how well this framework will perform when more than one decision is needed in a tick, or how to handle running concurrent tasks (such as moving and eating -- maybe hooking in to OSBot's Event API).

Edited by TheJacob
  • Like 1
Posted

Interesting concept! My only concerns are the following. 
 

1. I don’t think reflection will work on the SDN. So this would only be useful for scripts not going on OSBots repository. (I experienced this issue when I made Script Factory).
 

2. Make sure to cache the entire JSON during runtime instead of calling the JSON in a loop. This will fix any bogging of the script if either your JSON file gets extremely large, or needing to loop your script faster.

  • Like 1
Posted
17 minutes ago, ProjectPact said:

Interesting concept! My only concerns are the following. 
 

1. I don’t think reflection will work on the SDN. So this would only be useful for scripts not going on OSBots repository. (I experienced this issue when I made Script Factory).
 

2. Make sure to cache the entire JSON during runtime instead of calling the JSON in a loop. This will fix any bogging of the script if either your JSON file gets extremely large, or needing to loop your script faster.

Oh ok, I didn't know about that! I think I can change the design such that it doesn't use reflection. The reason I decided to go with that design in the first place was to reduce code clutter while parsing the decision tree (making the assumption that the script does not know about all the conditions & tasks). In order to get rid of reflection, I can make the script aware of all conditions & tasks while still leaving the decision tree to be dynamic to the user.

The 'parser' variable in 'onLoop' should be holding a reference to a spot in the tree at all times rather than a copy of the tree. If I'm not mistaken, this line passes a reference by value rather than copying the whole tree.

Condition parser = dto;

I might be wrong though, where do you see it copying the whole decision tree or JSON parser every loop?

  • Like 1
Posted
3 hours ago, TheJacob said:

Oh ok, I didn't know about that! I think I can change the design such that it doesn't use reflection. The reason I decided to go with that design in the first place was to reduce code clutter while parsing the decision tree (making the assumption that the script does not know about all the conditions & tasks). In order to get rid of reflection, I can make the script aware of all conditions & tasks while still leaving the decision tree to be dynamic to the user.

The 'parser' variable in 'onLoop' should be holding a reference to a spot in the tree at all times rather than a copy of the tree. If I'm not mistaken, this line passes a reference by value rather than copying the whole tree.

Condition parser = dto;

I might be wrong though, where do you see it copying the whole decision tree or JSON parser every loop?

I was just referring to your comment:

  • The decision tree doesn't necessarily have to be processed in "onLoop". In fact, I think there's great potential by listening for game tick events.

:D But still, a really cool concept and a different way to look at processing.

  • Like 1

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
  • Recently Browsing   0 members

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