TheJacob Posted January 24, 2023 Share Posted January 24, 2023 (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 Create a "DeepButler" folder in OSBot's Data folder (getDirectoryData). Create a "deepbutler.json" file in the "DeepButler" folder. Use the example decision tree (and later have fun making your own!) Modify your OSBot to allow reflection (add "-allow reflection" to run.bat). 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 January 27, 2023 by TheJacob Released a different framework that's much more practical. Linked. 2 Quote Link to comment Share on other sites More sharing options...
Czar Posted January 24, 2023 Share Posted January 24, 2023 I will check this out, respect for going away from the norm in scripting and trying new (+ better) stuff Quote Link to comment Share on other sites More sharing options...
TheJacob Posted January 25, 2023 Author Share Posted January 25, 2023 (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 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 January 25, 2023 by TheJacob 1 Quote Link to comment Share on other sites More sharing options...
Czar Posted January 25, 2023 Share Posted January 25, 2023 I am sure it is possible, especially with events, no need to worry about that tbh. I want to see what is truly possible with a framework like this, I will be trying some stuff out. Keep up the good work btw! 1 Quote Link to comment Share on other sites More sharing options...
ProjectPact Posted January 25, 2023 Share Posted January 25, 2023 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. 1 Quote Link to comment Share on other sites More sharing options...
TheJacob Posted January 25, 2023 Author Share Posted January 25, 2023 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? 1 Quote Link to comment Share on other sites More sharing options...
ProjectPact Posted January 25, 2023 Share Posted January 25, 2023 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. But still, a really cool concept and a different way to look at processing. 1 Quote Link to comment Share on other sites More sharing options...
TheJacob Posted January 27, 2023 Author Share Posted January 27, 2023 Released a different approach to creating scripts (behavior tree framework). See this thread. If a decision tree approach is used, it will be a hybrid subtree of the behavior tree framework. Quote Link to comment Share on other sites More sharing options...