ScriptingCompiled .jar extensions¶
For people who want a type checker, an IDE and a real build. Put the jar in ~/.bitchos/extensions/ and turn on AllowExtensions in the Scripts module.
An extension is not sandboxed
It is ordinary Java on the game's class loader: it can read any file your account can read, open any socket, and call anything in the game. Only load extensions from sources you trust. A jar can be decompiled and read before you trust it. That is why extensions are off by default and why turning them on prints a warning.
Implementing one¶
Implement gg.bitchos.script.ext.BitchosExtension on a public class with a public no-argument constructor:
import gg.bitchos.script.ext.*;
public final class Example implements BitchosExtension {
public String name() { return "Example"; }
public void init(final ExtensionApi api) {
api.settings().bool("Loud", true, "Shout about it.");
api.on("gameStart", new ExtensionHandler() {
public Object run(Object[] args) {
api.chat().print("§bgame on");
return null;
}
});
api.hud("state", "Example", new ExtensionHandler() {
public Object run(Object[] args) {
return java.util.Arrays.asList("§bexample");
}
});
api.command("example", new ExtensionHandler() {
public Object run(Object[] args) {
api.log().info("ran with " + api.string(args[0], "?"));
return null;
}
});
}
}
ExtensionApi exposes exactly the same objects a script gets: api.chat(), api.settings(), api.hud(), api.commands(), api.render(), api.bitchos(), api.player(), api.world(), api.modules(), api.storage(), api.bridge(), api.http(), api.json(), api.keybinds(), api.util(), api.providers(), api.events().
There is no extension-only capability and nothing a script can do is missing. Anywhere a script passes a function, an extension passes an ExtensionHandler wrapped with api.wrap(label, handler); api.on, api.hud, api.command and api.schedule do that for you.
An extension appears in the Scripts category exactly like a script, with the same settings, the same error handling and the same watchdog.
Compiling¶
Compile against a bitchos jar, and refer only to types under gg.bitchos.script. Everything else in the mod has its class and method names rewritten by ProGuard in the shipped build, so an extension compiled against them would work in development and fail with NoSuchMethodError in the build people actually run.
Two limitations¶
- No mixins. Extensions are loaded at runtime, after class transformation. If you need to transform bytecode, you need your own mod.
- A changed extension needs a game restart. Its class loader is never closed, because unloading one that still has live objects in it produces
NoClassDefFoundErrorat a random later moment, which is far worse than holding the loader open for the session./bitchos script reload <jar>says so rather than pretending, and reloading everything leaves loaded extensions alone.
An extension's name comes from its jar and is a module name like any other, so the same rule applies: a jar named after an existing module is refused with a message instead of replacing it.