-
Notifications
You must be signed in to change notification settings - Fork 1
Plugin Development
AquariusProxy's automation modules are native built-ins, but the proxy also keeps ZenithProxy's plugin system: drop-in jars that add your own modules and commands without rebuilding the proxy.
🧩 Template repo: aquariusnetwork9/aquariusproxy-plugin-template — a working example plugin you can clone and build. This page is the companion guide.
Plugins are supported on the
javarelease channel only. The native (linux) GraalVM build can't load jars at runtime and will log a warning instead.
- Put the plugin jar in the
pluginsfolder next to the AquariusProxy launcher. It's created automatically on first launch. - Restart AquariusProxy. Plugins are loaded once at startup — there is no hot-reload.
- A plugin's config (if it has one) is written to
plugins/config/<plugin_id>.json.
Run the plugins command in the proxy console to list what loaded.
A plugin registers the same building blocks the proxy uses internally:
- Modules — toggleable units that listen to events, run on the client tick loop, and register packet handlers (inbound from the player, outbound to the server, in either direction).
- Commands — Brigadier commands usable from the terminal, in-game chat, and Discord, with embed responses.
- Configs — JSON-backed POJOs that load and save automatically.
Modules and commands are written exactly as they are in the AquariusProxy source — the best reference is the proxy's own code:
# 1. Clone the template (or hit "Use this template" on GitHub)
git clone https://github.com/aquariusnetwork9/aquariusproxy-plugin-template
cd aquariusproxy-plugin-template
# 2. Provide the AquariusProxy API jar (the same jar the launcher runs)
gh release download --repo aquariusnetwork9/AquariusProxy --pattern 'AquariusProxy.jar' --dir libs
# or: cp /path/to/install/AquariusProxy.jar libs/AquariusProxy.jar
# 3. Build
./gradlew build # Windows: gradlew.bat buildThe plugin jar lands in build/libs/. Copy it into your proxy's plugins folder and restart.
- JDK 25 — the same JDK AquariusProxy is built with. It's required because compilation runs AquariusProxy's bundled annotation processor. The Gradle toolchain auto-provisions it if it's missing.
-
The AquariusProxy fat jar (
AquariusProxy.jar) to compile against. That's how you get the API — AquariusProxy is not published to a public Maven repository, so you supply the jar the launcher already runs. The template looks for it atlibs/AquariusProxy.jar, overridable with-Paquarius_jar=/path/to/AquariusProxy.jar.
Every plugin has one main class that implements AquariusProxyPlugin and carries the @Plugin annotation:
import com.aquarius.plugin.api.AquariusProxyPlugin;
import com.aquarius.plugin.api.Plugin;
import com.aquarius.plugin.api.PluginAPI;
@Plugin(
id = "my-plugin", // lowercase letters, numbers, dashes; must start with a letter
version = "1.0.0",
description = "My AquariusProxy plugin",
authors = {"you"},
mcVersions = {"1.21.4"} // or "*" for any MC version
)
public class MyPlugin implements AquariusProxyPlugin {
@Override
public void onLoad(PluginAPI api) {
MyConfig config = api.registerConfig("my-plugin", MyConfig.class);
api.registerModule(new MyModule());
api.registerCommand(new MyCommand());
}
}The @Plugin annotation is read at build time by an annotation processor that generates the zenithproxy.plugin.json metadata file the proxy loads — you never write that file by hand.
onLoad receives a PluginAPI:
| Method | Purpose |
|---|---|
registerConfig(fileName, ConfigClass.class) |
Loads/creates a JSON config and returns the live instance. Stored at plugins/config/<fileName>.json. |
registerConfig(fileName, ConfigClass.class, serializer) |
Same, with a custom serializer (NBT/YAML/TOML/etc.). |
registerModule(module) |
Registers a Module. |
registerCommand(command) |
Registers a Command. |
getLogger() |
A ComponentLogger scoped to your plugin. |
getPluginInfo() |
The data from your @Plugin annotation. |
A config is a plain POJO with public, mutable fields. Nested static classes become nested JSON objects. It is saved/loaded automatically (on command execution, proxy start/stop, etc.):
public class MyConfig {
public boolean enabled = true;
public int delayTicks = 250;
}A Module can gate itself on a config flag, subscribe to events, and (optionally) register packet handlers:
public class MyModule extends Module {
private final Timer timer = Timers.tickTimer();
@Override public boolean enabledSetting() { return MyPlugin.CONFIG.enabled; }
@Override public List<EventConsumer<?>> registerEvents() {
return List.of(of(ClientBotTick.class, this::onTick));
}
private void onTick(ClientBotTick event) {
if (timer.tick(MyPlugin.CONFIG.delayTicks)) info("tick!");
}
}The example plugin also shows a packet-handling module (outbound entity-metadata edit for a glowing-ESP effect) and a pathfinding module (driving Baritone to wander). Note packet classes change between MC versions, so packet-handling plugins generally need a separate build per MC version.
Commands are Brigadier-based, identical to the proxy's own:
public class MyCommand extends Command {
@Override public CommandUsage commandUsage() {
return CommandUsage.builder()
.name("myplugin").category(CommandCategory.MODULE)
.description("Toggle my plugin").usageLines("on/off").build();
}
@Override public LiteralArgumentBuilder<CommandContext> register() {
return command("myplugin").then(argument("toggle", toggle()).executes(c -> {
MyPlugin.CONFIG.enabled = getToggle(c, "toggle");
MODULE.get(MyModule.class).syncEnabledFromConfig(); // apply the toggle
c.getSource().getEmbed().title("My Plugin " + toggleStrCaps(MyPlugin.CONFIG.enabled));
}));
}
}./gradlew build # plugin jar -> build/libs/<plugin_name>.jar
./gradlew run # launch AquariusProxy with the plugin loaded in ./runrun installs your freshly built jar into run/plugins and starts the proxy from ./run; the first run walks you through normal proxy setup. You can equally just copy the built jar into an existing install's plugins folder and restart.
- Edit
gradle.properties—plugin_name,plugin_id,mc,maven_group. - Move sources from
org.exampleto your own package (under bothsrc/main/javaandsrc/main/templates). IntelliJ's refactor handles imports. - Update the
@Pluginannotation (or replaceExamplePluginwith your own main class).
Unlike rfresh2's upstream example, the template does not use a *.plugin.dev Gradle convention plugin (there is no AquariusProxy equivalent). It's self-contained:
- It compiles
compileOnlyandannotationProcessoragainst the AquariusProxy fat jar. That single jar bundles every API and transitive class plus the@Pluginannotation processor (auto-registered via SPI), so there's no Maven publishing or transitive dependency resolution to set up. -
BuildConstantsis generated fromsrc/main/templatesby a GradleCopy/expandtask. - The Shadow plugin builds the final jar and can bundle/relocate any extra dependencies you declare with
implementation(...).
A plugin jar built for ZenithProxy will not load on AquariusProxy as-is. AquariusProxy renamed the whole API package com.zenith.* → com.aquarius.* (including ZenithProxyPlugin → AquariusProxyPlugin), so a compiled ZenithProxy plugin references classes that don't exist here, and the loader requires AquariusProxyPlugin.
Porting is mechanical, because the API shape is identical:
- Replace imports
com.zenith.→com.aquarius.(andZenithProxyPlugin→AquariusProxyPlugin). - Compile against
AquariusProxy.jarinstead of ZenithProxy — the template already does.
External imports (com.github.rfresh2.*, com.mojang.brigadier.*, org.geysermc.mcprotocollib.*, net.kyori.*) are unchanged.
| Symptom | Cause / fix |
|---|---|
AquariusProxy API jar not found |
Put AquariusProxy.jar at libs/AquariusProxy.jar or pass -Paquarius_jar=.... |
cannot find symbol for com.aquarius.*
|
The API jar is missing or is an older version than your mc target — supply the matching AquariusProxy.jar. |
| Compile fails with "release 21 not supported" / toolchain errors | Use JDK 25 (the toolchain auto-provisions it if your machine allows downloads). |
| Plugin jar isn't loaded at startup | You're on the linux/native channel (use the java jar), the jar isn't in plugins/, or it doesn't implement AquariusProxyPlugin. Check the console for plugin-loader errors. |
No zenithproxy.plugin.json in the built jar |
The @Plugin-annotated class is missing or the API jar wasn't on the annotationProcessor path — rebuild after fixing the jar path. |
See also: Installation · Command Reference · The ShiftClick fix
- What's New — 5.x Beta 🧪
- Installation
- Command Reference
- Movement & Transport
- The ShiftClick fix
- Notifications (ntfy)
- FAQ
Remote control & access 🧪 (5.x beta)
Built-in modules
- AquariusMiner
- AquariusSniffer
- PearlPlus
- VillagerTrader
- PearlDrop
- KitMaker
- Regear
- ElytraPilot
- Enchanter
Stash system
Extending