Jump to content
Malcolm

Extending the Script superclass multiple times

Recommended Posts

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);
    }
}
  • Like 4
Link to post
Share on other sites

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 by Explv
Link to post
Share on other sites

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);
    }
}
  • Like 1
Link to post
Share on other sites
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 by Explv
  • Like 5
Link to post
Share on other sites
Posted (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 :doge:

Edited by Malcolm
  • Doge 1
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.

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...