Developer API
Hook your own plugin into MoneyRace money, teams, events and placeholders
This page is for plugin developers. Server owners do not need it.
Start with Vault
If you only need to read or change balances, use the Vault API. In MONEYRACE mode MoneyRace is the Vault economy, so your plugin works without touching MoneyRace classes. The rest of this page is for deeper integration.
Getting the plugin
Add MoneyRace as a depend or softdepend in your plugin.yml, compile against the jar you bought, and get the main class:
MoneyRace plugin = (MoneyRace) Bukkit.getPluginManager().getPlugin("MoneyRace");The package is cc.arrowtan.moneyrace. The API is reached through the main class and has not been published to a Maven repository, so use the jar from your download as a provided dependency. Classes outside the api package are internal and can change.
Money
plugin.money() is a MoneyService.
| Call | What it does |
|---|---|
balance(uuid), has(uuid, amount) | Read a balance |
add, take | Change a balance. take is all or nothing |
takeUpTo | Take what is there and return how much |
set | Set a balance |
transfer(from, to, amount, Reason, text) | Move money between players |
payTeam(team, amount, PayoutMode, Reason, text) | Pay a team |
chargeTeam(...) | Charge a team, in proportion to member balances in split modes, and return what was taken |
vaultBalance(team), addVault, takeVault, setVault | Team vault balance |
format(amount) | The configured currency format |
Every call writes one row to the ledger, so pass the right Reason. There are reasons for capture points, altars, world events, vaults, rituals, insurance, seasons and events. plugin.ledger().listen(entry -> ...) sees every change, which is handy for daily caps and stats.
Payout helpers do not apply multipliers. Multiply first:
double amount = base * plugin.multipliers().payout(team);Offline players are loaded from the database on demand, blocking for up to 10 seconds. Prefer online players on the main thread.
Teams
plugin.teams() is a TeamService.
| Call | What it does |
|---|---|
team(uuid), byId(id), byName(name), teams() | Find teams |
members(team), onlineMembers(team) | Players in a team |
color(team), displayName(team) | Colour object and a coloured name in MiniMessage |
score(team), rank(team), sorted(), leading(), medianScore() | Standings. Ranks refresh every leaderboard.refresh-seconds, so call resort() after a big change |
sameTeam(a, b) | Same team |
isFriendly(actor, target) | Same team, or the actor trusts the target. Use this for "no damage from MoneyRace mechanics" |
tagBeside(team, playerName) | The coloured team name to print next to a player, or an empty string for a solo team |
A Team also keeps a free string map, data(key) and data(key, value), for your own values. Call plugin.teams().save(team) after changing it.
Multipliers
plugin.multipliers().set(Multipliers.Scope.PAYOUT, "my_plugin", 1.5);
plugin.multipliers().clear("my_plugin");World events use the same call for Double Money. kill(team) and payout(team) are what every payout asks, and payout includes the underdog bonus.
addKillHook(Consumer<KillContext>) lets you change reward, victimLoss and bonus, or call cancel() on a kill transfer.
Registering a module
A module is a small unit with a lifecycle. MoneyRace enables them after every core service exists and disables them in reverse order before storage closes.
public final class MyModule implements RaceModule {
public String id() { return "my-module"; }
public void enable() { }
public void disable() { }
public void reload() { }
}Register it with plugin.registerModule(new MyModule()). Use plugin.scheduler().group() for your own timers, so cancelAll() in disable() only touches yours.
Commands
plugin.routes() adds subcommands:
plugin.routes().admin("point", route); // /moneyrace admin point ...
plugin.routes().player("vault", route); // /moneyrace vault ...A CommandRoute gives permission(), execute(sender, label, args) and complete(sender, args). The args start after the route name.
Placeholders
plugin.placeholders().register("world_event", (player, params) -> "...");This answers any %moneyrace_<name>% that starts with the prefix you registered.
Give items
plugin.giveItems().register("my_item", (target, extra) -> itemStack);This makes /moneyrace admin give my_item [player] [extra...] work, with tab completion. Tag your items with Keys.tag(meta, kind) and recognise them only through Keys.kind(item).
Menus, bossbars and the wand
plugin.menus().registerMenu("id", player -> ...)letsaction: MENUbuttons inmenus.ymlopen a coded menu. Plain menus can be added straight tomenus.ymland opened withmenus().open(player, id).plugin.bossbars()keeps one bar per key. Usebar,update,show,hide,viewers,showAllandremove. Quitting removes a player from every bar.plugin.selections().get(player)returns the player's wand selection.
Season clock
Core code reads the season through plugin.seasonClock(), with active(), day(), finalWeek(), pvpMoney(), phase() and timeLeftMillis(). The default is SeasonClock.NONE.
Main events
Extend MainEvent and register it with plugin.events().register(...).
public final class MyEvent extends MainEvent {
public MyEvent(MoneyRace plugin) { super(plugin, "my-event"); }
protected void onStart() { }
protected void onTick(int secondsRunning) { }
protected void onPlayerEliminated(Player player, Player killer) { }
protected void onEnd(EndReason reason) { }
}Core handles joining, countdown, saving and restoring inventories, bossbars and prizes. Read your own settings with config(), which is events.<id> in events.yml. Placements are paid through the ledger with a payout reason and the team multiplier.
Compatibility rules
One jar runs on every supported server version, so keep these in mind when you build on it:
- Do not call methods on
Sound,Attributeor other enums that became interfaces. Use string keys. - Look potion effects and attributes up from the registry by key.
- Put anything that needs a newer server than the oldest supported one in a separate class behind a version check.
- Never listen to
PlayerLoginEvent. Load data inAsyncPlayerPreLoginEvent.