Malcolm Posted April 3, 2021 Share Posted April 3, 2021 Just a cool concept that I had thought of that may come in handy for people attempting to do large projects. This is relatively beginner Java but I thought I'd share because I found it to be somewhat interesting when I thought of the idea. Below is a snippet of code of the Main Script subclass with the @ScriptManifest annotation and a TestScript class. You should only ever use the annotation once in the Main class. You can set the runnable script either with a GUI or CLI args. This concept would enable large projects sorted by packages that contain multiple different scripts to be accessed this way in the same script. I would consider doing something like this for an Ironman kind of script that did a lot of different activities. package core; import org.osbot.rs07.script.Script; import org.osbot.rs07.script.ScriptManifest; import java.awt.*; @ScriptManifest(version = 0.0, logo = "", info = "", name = "Ironman", author = "Malcolm") public class Main extends Script { private Script runnableScript; public void onStart() throws InterruptedException { this.runnableScript = new TestScript(); this.runnableScript.exchangeContext(getBot()); this.runnableScript.onStart(); } @Override public int onLoop() throws InterruptedException { return this.runnableScript.onLoop(); } public void onExit() throws InterruptedException { this.runnableScript.onExit(); } public void onPaint(Graphics2D g) { this.runnableScript.onPaint(g); } } package core; import org.osbot.rs07.script.Script; import java.awt.*; public class TestScript extends Script { private Paint paint; @Override public void onStart() { this.paint = new Paint(this); log("Test Script onStart"); } @Override public void onExit() { log("Test Script onExit"); } @Override public int onLoop() throws InterruptedException { log("RUNNING TEST SCRIPT"); return 100; } @Override public void onPaint(Graphics2D g) { this.paint.paint(g); } } 4 Quote Link to comment Share on other sites More sharing options...
Explv Posted April 3, 2021 Share Posted April 3, 2021 (edited) This is cool, although I would recommend using your own class instead of the Script class. Using your own class would let you extend the MethodProvider and supply additional functionality to all your subclasses, which can be useful in a big script. Can provide example if helpful Edited April 3, 2021 by Explv Quote Link to comment Share on other sites More sharing options...
ez11 Posted April 3, 2021 Share Posted April 3, 2021 30 minutes ago, Explv said: Can provide example if helpful Please do Quote Link to comment Share on other sites More sharing options...
Camaro Posted April 3, 2021 Share Posted April 3, 2021 I'd have to recommend against doing this. Should either do as Explv said and extend MethodProvider, or take advantage of the Event system. import org.osbot.rs07.script.Script; import org.osbot.rs07.script.ScriptManifest; @ScriptManifest(version = 0.0, author = "", info = "", logo = "", name = "Script Class") public class Main extends Script { @Override public int onLoop() throws InterruptedException { execute(new ExtensionClass()); return 600; } } import org.osbot.rs07.canvas.paint.Painter; import org.osbot.rs07.event.Event; import java.awt.*; public class ExtensionClass extends Event implements Painter { @Override public void onStart() throws InterruptedException { log("Looping class starting"); getBot().addPainter(this); } @Override public int execute() throws InterruptedException { log("I am a self contained looping class"); return 600; } @Override public void onEnd() throws InterruptedException { log("Looping class ending"); getBot().removePainter(this); } @Override public void onPaint(Graphics2D g) { g.drawString("Looping class painting", 10, 330); } } 1 Quote Link to comment Share on other sites More sharing options...
Explv Posted April 3, 2021 Share Posted April 3, 2021 (edited) 4 hours ago, ez11 said: Please do 1. Define your custom method provider, this extends OSBot's MethodProvider class, and then adds on / overrides functionality. In this example, I am overriding getInventory() with my own class which adds a "use" function. The CustomMethodProvider class defined below also supplies a custom "execute" function, which runs an Executable (a different class I have defined later) class CustomMethodProvider extends MethodProvider { private ExtendedInventory extendedInventory; private boolean hasContext; public void init(final Bot bot) { super.exchangeContext(bot); this.extendedInventory = new ExtendedInventory(); extendedInventory.exchangeContext(bot); hasContext = true; } public boolean hasContext() { return hasContext; } // Deprecated as exchangeContext(Bot bot, CustomMethodProvider methodProvider) should be used instead. @Deprecated public MethodProvider exchangeContext(final Bot bot) { return super.exchangeContext(bot); } public CustomMethodProvider exchangeContext(final Bot bot, final CustomMethodProvider methodProvider) { this.extendedInventory = methodProvider.extendedInventory; super.exchangeContext(bot); hasContext = true; return this; } @Override public ExtendedInventory getInventory() { return extendedInventory; } /** * Helper function which exchanges context with an Executable * (if not already exchanged), and then calls Executable::run * @param executable The Executable to execute * @throws InterruptedException */ public void execute(final Executable executable) throws InterruptedException { if (!executable.hasContext()) { executable.exchangeContext(getBot(), this); } executable.run(); } } Here is my "ExtendedInventory" class: class ExtendedInventory extends Inventory { public boolean isUsing(final String itemName) { return itemName.equals(getSelectedItemName()); } public boolean use(final String itemName) { if (isUsing(itemName)) { return true; } if (getInventory().interact("Use", itemName)) { Sleep.sleepUntil(() -> itemName.equals(getSelectedItemName()), 1000); return true; } return false; } } 2. Define the Executable class, this is what we will use for other classes in our script that have a common "onStart" / "onLoop" / "onEnd" pattern: abstract class Executable extends CustomMethodProvider { public void onStart() throws InterruptedException {} public abstract void run() throws InterruptedException; public void onEnd() throws InterruptedException {} } Note how this class extends our CustomMethodProvider, which means anything we define in the CustomMethodProvider class will be available to subclasses of "Executable" 3. In the main script class, set everything up (create an instance of CustomMethodProvider, and exchange context) @ScriptManifest(author = "Explv", name = "Example", info="", logo = "", version = 0.1) public class Example extends Script { private final CustomMethodProvider customMethodProvider = new CustomMethodProvider(); @Override public void onStart() { customMethodProvider.init(getBot()); } @Override public int onLoop() throws InterruptedException { return 0; } } 4. Finally, whenever you want some other class with an onStart / onLoop / onEnd, just extend the Executable class, and then run it using "execute". Here is a very contrived example: class ExampleExecutable extends Executable { private static final String TINDERBOX = "Tinderbox"; private final Executable someOtherExecutable = new SomeOtherExecutable(); @Override public void run() throws InterruptedException { if (!getInventory().isUsing(TINDERBOX)) { getInventory().use(TINDERBOX); } else { execute(someOtherExecutable); } } } class SomeOtherExecutable extends Executable { @Override public void run() throws InterruptedException { getWalking().webWalk(new Area(1, 2, 3, 4)); } } @ScriptManifest(author = "Explv", name = "Example", info="", logo = "", version = 0.1) public class Example extends Script { private final CustomMethodProvider customMethodProvider = new CustomMethodProvider(); private final Executable exampleExecutable = new ExampleExecutable(); @Override public void onStart() { customMethodProvider.init(getBot()); } @Override public int onLoop() throws InterruptedException { customMethodProvider.execute(exampleExecutable); return 600; } } 5. If you want an "Executable" that blocks until completion, then you can either use OSBot's Event class, or define your own "BlockingExecutable" which utlises OSBot's Event, for example: public abstract class BlockingExecutable extends Executable { private boolean finished; private ExecutionFailedException executionFailedException; @Override public final void run() throws InterruptedException { finished = false; executionFailedException = null; onStart(); execute(new Event() { @Override public int execute() throws InterruptedException { if (finished) { setFinished(); } else { try { blockingRun(); } catch (ExecutionFailedException executionFailedException) { BlockingExecutable.this.executionFailedException = executionFailedException; setFailed(); } } return 0; } }); onEnd(); if (executionFailedException != null) { throw executionFailedException; } } protected abstract void blockingRun() throws InterruptedException; protected void setFinished() { finished = true; } } public class ExecutionFailedException extends RuntimeException { public ExecutionFailedException(String message) { super(message); } } Edited April 3, 2021 by Explv 6 Quote Link to comment Share on other sites More sharing options...
Malcolm Posted April 3, 2021 Author Share Posted April 3, 2021 (edited) I understand what you guys are saying but I somewhat disagree with you only because I don't think the concept isn't quite understood and the logic as to why I'd personally do it that way. The Script superclass already extends the MethodProvider so by extending the Script superclass multiple times you're already extending the Method Provider and you're getting the structuring to go along with it. The logic is to have say, 5 large different scripts set up in the same script. You'd want to separate each script into it's own package so everything is easy to follow. Each package would have it's own Script subclass and you can set the executable script with some sort of GUI or CLI parameters. I feel like this structuring would be easier to work with if you were working with hundreds of different classes across multiple different scripts. You guys bring up good points and your methods have the same effect. Probably just me liking my own concept Edited April 3, 2021 by Malcolm Quote Link to comment Share on other sites More sharing options...