Developer API
On this page(7)
SnEconomyRobots exposes a public developer API for other plugins: custom Bukkit events, a query and grant service, and a currency extension point. The API lives in the com.sn.economyrobots.api package inside the plugin jar. There is no separate artifact.
Only com.sn.economyrobots.api is a stable, kept contract. Everything else in the jar is obfuscated and internal. Do not call it.
Getting the jar
-
Download the latest release jar.
-
Install it into your local Maven repository:
mvn install:install-file -Dfile=SnEconomyRobots-<version>.jar -DgroupId=com.sn \ -DartifactId=SnEconomyRobots -Dversion=<version> -Dpackaging=jar -
Depend on it with
providedscope. Never shade it.
Quick start
Declare the dependency in your plugin.yml:
depend: [SnEconomyRobots] # or softdepend if optionalResolve the API when you need it:
SnEconomyRobotsAPI api = SnEconomyRobotsProvider.get();
if (api != null) {
List<RobotView> equipped = api.getEquippedRobots(player.getUniqueId());
}Resolve the reference when you need it. Do not cache it across a SnEconomyRobots reload.
SnEconomyRobotsProvider.get() returns null when SnEconomyRobots is missing, disabled, or failed its license check. SnEconomyRobotsProvider.isAvailable() answers the same question as a boolean.
Master switch
API events can be disabled by the server owner with api-events.enabled: false in config.yml. The query service and currency registration stay available either way. areEventsEnabled() reports the current value.
Events
Every event fires synchronously on the main thread. Payloads are read-only.
Cancellable events fire before the action. Cancelling aborts it. The plugin sends no message on a cancel, so your listener owns the player feedback.
| Event | Fired when | Cancel effect |
|---|---|---|
RobotEquipEvent | A robot is about to enter an active slot, from a robot item or the main menu | The robot stays where it was. An item goes back to the inventory. |
RobotUnequipEvent | An equipped robot is about to move back into storage from the main menu | The robot stays in its slot |
BagClaimEvent | A non-empty claim bag is about to be paid out | Nothing is paid and the bag stays untouched |
RobotUpgradeEvent | The next level of an upgrade track is about to be charged | Nothing is charged and nothing is granted |
RobotMergeEvent | A rolled merge is about to consume its input robots | Every input robot is kept and the merge closes without a result |
RobotBoxOpenEvent | One or more robot boxes are about to be rolled | Nothing opens and every consumed box is given back |
RobotUnequipEvent does not fire for robots arriving in storage from a box or a merge. It also skips robots displaced when an admin lowers a player's slot count.
Notification events fire after the fact. They cannot be cancelled.
| Event | Fired when | Thread |
|---|---|---|
BagClaimedEvent | A claim paid at least one economy. isPartial() is true when some income stayed in the bag. It is skipped when the player left before the claim settled. | Main |
RobotUpgradedEvent | An upgrade level was charged and applied | Main |
RobotMergedEvent | A merge consumed its inputs and stored the output robot | Main |
RobotBoxOpenedEvent | Box opening placed at least one robot into storage | Main |
RobotCapReachedEvent | An equipped robot hit its production cap and stopped producing | Main, shortly after the production sweep |
BagFilledEvent | Robot production filled one economy of a bag to bag.max-per-economy. It fires once per fill. | Main, shortly after the production sweep |
RobotCapReachedEvent and BagFilledEvent carry the owner's UUID, not a Player. The owner may have logged out before delivery.
Listen like any Bukkit event:
@EventHandler
public void on(BagClaimEvent event) {
if (event.getPending().getOrDefault("vault", 0.0) > 1_000_000) {
event.setCancelled(true);
event.getPlayer().sendMessage("Claims over one million are paused right now.");
}
}Event payloads are read-only. To plug in your own economy, use the extension point below instead of looking for setters.
Query service
Every facade method is synchronous and reads in-memory state. Call it on the main thread. Lists and maps are immutable snapshots.
| Method | Returns | Notes |
|---|---|---|
getApiVersion() | String | The API contract version |
areEventsEnabled() | boolean | The api-events.enabled value |
isLoaded(UUID) | boolean | True once the player's robots and bag are in memory |
getEquippedRobots(UUID) | List<RobotView> | Active slots, in slot order |
getStoredRobots(UUID) | List<RobotView> | Storage, in storage order |
getRobots(UUID) | List<RobotView> | Equipped first, then stored. Robots held as items are not included. |
getRobot(UUID, UUID) | RobotView or null | One robot by owner and instance UUID |
getUnlockedSlots(UUID) | int | slots.default when the player is not loaded |
getMaxSlots() | int | The slots.max ceiling |
getStorageUsed(UUID) | int | Robots in storage |
getStorageCapacity(Player) | int | Resolved live from the player's rank permissions |
getBagContents(UUID) | Map<String, Double> | Positive pending amounts per economy id |
getBagBalance(UUID, String) | double | One economy's pending amount |
getRobotTypes() | List<RobotTypeView> | Every type loaded from robots/*.yml |
getRobotType(String) | RobotTypeView or null | One type by id |
getTiers() | List<TierView> | The tier ladder, ascending |
getTier(int) | TierView or null | One tier by id |
getCurrencies() | List<CurrencyView> | The Vault id, registered currencies and EdTools currencies |
getCurrencyDisplayName(String) | String | From boost-display-names, or a title-cased id |
isCurrencyRegistered(String) | boolean | True when a plugin provides that id |
Player queries answer empty, zero or null for a player whose data is not loaded.
Grant methods change state through the same paths as the admin commands. They return false instead of throwing on bad input.
| Method | Returns | Notes |
|---|---|---|
giveRobotItem(Player, String, int) | boolean | A robot item of a type and tier, with a fresh multiplier roll. Same path as /robots admin give. |
giveBoxes(Player, int, int) | boolean | Robot boxes of one box tier. Same path as /robots admin givebox. |
addBagIncome(UUID, String, double) | boolean | Adds income to the claim bag. The bag cap applies. The bag must be loaded. |
Each CurrencyView names its source: VAULT, EXTERNAL for a registered currency, or EDTOOLS. ownerPlugin is set only for EXTERNAL.
Extension points
| Interface | What it influences | Neutral return |
|---|---|---|
CurrencyProvider | Adds an economy id that robots can produce, upgrades can cost, and the claim bag pays out | A false or empty future: the operation did not settle |
SyncCurrencyProvider | The same, for a currency that settles immediately. Implement three ...Now methods. | false, or an empty balance |
Register from your onEnable through the facade:
api.registerCurrency(this, "tokens", new SyncCurrencyProvider() {
public String getDisplayName() { return "&bTokens"; }
public boolean depositNow(UUID player, double amount) { return tokens.add(player, amount); }
public boolean withdrawNow(UUID player, double amount) { return tokens.take(player, amount); }
public OptionalDouble getBalanceNow(UUID player) { return OptionalDouble.of(tokens.get(player)); }
});The id is trimmed and lowercased, then it must match [a-z0-9_-]{1,32}. The reserved Vault id throws IllegalArgumentException. registerCurrency returns false when another plugin already owns the id. Registering again from the same plugin replaces the provider.
From then on, server owners use the id like any other economy id: production.tokens in a robot file, cost.tokens in an upgrade level. The display name seeds boost-display-names once, and the owner's value always wins.
The rules every provider follows:
- Every method is called on the main thread. The returned future may complete on any thread.
withdrawmust be atomic. Take the amount only when the player can afford it, and never go negative.- An empty balance means unknown, not zero.
- A provider that throws, returns
nullor completes exceptionally counts as "did not settle". It never breaks a claim or a purchase. - Amounts are always finite and strictly positive.
A future that does not complete within economy.external-timeout-seconds counts as failed. The claim keeps the income in the bag, and the upgrade is refused. A deposit or withdrawal that still succeeds later is reversed with the opposite call on your provider. A reversal that fails is logged for a manual correction.
A registered id is checked after the Vault id and before EdTools, so it shadows an EdTools currency of the same id. Your registrations are dropped automatically when your plugin disables. unregisterCurrency(Plugin, String) and unregisterCurrencies(Plugin) drop them earlier.
Versioning
Call getApiVersion() for the API contract version. It is independent of the plugin version. Additions bump the minor component. Existing members are never removed or changed; deprecated members keep working.