Skip to content

Developer API

Jan Kluka edited this page Jul 9, 2026 · 31 revisions

Developer API

The X-Prison public API lives in a dedicated project: X-PrisonAPI on GitHub


Adding X-PrisonAPI as a Dependency

Add the API artifact to your plugin's build tool. The API is published to the Drawethree Maven repository.

Maven:

<repository>
    <id>drawethree-repo</id>
    <url>https://repo.drawethree.dev/releases</url>
</repository>

<dependency>
    <groupId>dev.drawethree</groupId>
    <artifactId>X-PrisonAPI</artifactId>
    <version>LATEST</version>
    <scope>provided</scope>
</dependency>

Gradle (Kotlin DSL):

repositories {
    maven("https://repo.drawethree.dev/releases")
}

dependencies {
    compileOnly("dev.drawethree:X-PrisonAPI:LATEST")
}

Declare X-Prison as a dependency in your plugin.yml:

depend: [X-Prison]
# or if optional:
softdepend: [X-Prison]

Accessing the API

import dev.drawethree.xprison.api.XPrisonAPI;

XPrisonAPI api = XPrisonAPI.getInstance();

Each module exposes its own sub-API through the main API instance:

api.getEnchantsAPI()      // Enchant system
api.getRanksAPI()         // Ranks
api.getPrestigesAPI()     // Prestiges
api.getRebirthAPI()       // Rebirths
api.getBlocksAPI()        // Block tracking
api.getCurrencyApi()      // Currency balances
api.getGangsAPI()         // Gangs
api.getMultipliersApi()   // Global, player, and rank multipliers
api.getAutoSellApi()      // Auto-sell prices and regions
api.getMinesApi()         // Mine management
api.getBombsApi()         // Bomb items
api.getAutoMinerApi()     // Auto-miner time
api.getBattlePassApi()    // Battle Pass tiers, XP and premium
api.getQuestsApi()        // Quests progress and rerolls
api.getDailyRewardsApi()  // Daily login streaks and claims

Battle Pass / Quests / Daily Rewards each expose read and write access plus their own Bukkit events (e.g. BattlePassXpGainEvent, BattlePassTierUpEvent, QuestCompleteEvent, QuestClaimEvent, PlayerDailyRewardClaimEvent):

// Battle Pass
api.getBattlePassApi().addXp(uuid, 500, XpSource.OTHER);
int tier = api.getBattlePassApi().getTier(uuid);
boolean premium = api.getBattlePassApi().isPremium(uuid);

// Quests
List<ActiveQuest> daily = api.getQuestsApi().getActiveQuests(uuid, QuestCategory.DAILY);
api.getQuestsApi().addProgress(uuid, "daily_mine_blocks", 100);

// Daily Rewards
int streak = api.getDailyRewardsApi().getStreak(uuid);
boolean claimed = api.getDailyRewardsApi().claim(uuid);

Dashboard integration (requires Dashboard addon):

api.setDashboardUrl(String url)   // called by the Dashboard addon on startup
api.getDashboardUrl()             // returns the active panel URL, or null if not running

Module and addon management:

api.getModules()                        // List<XPrisonModule> — all registered modules
api.isModuleEnabled(String configKey)   // true if module is active
api.enableModule(String configKey)
api.disableModule(String configKey)

api.getLoadedAddons()                          // List<XPrisonAddon>
api.enableAddon(String name)
api.disableAddon(String name)
api.loadAddonFromFile(File jar)                // runtime load without restart

Building an Addon (XPrisonAddonContext)

Addons are JARs placed in plugins/X-Prison/addons/. Declare the main class and metadata in the JAR manifest:

X-Prison-Addon-Class: com.example.MyAddon
X-Prison-Addon-Name: MyAddon
X-Prison-Addon-Description: Does something useful
X-Prison-Addon-Version: 1.0.0
X-Prison-Addon-Author: YourName
X-Prison-Min-Version: 2026.2.2.4-BETA
X-Prison-Priority: 50
X-Prison-Depends: OtherAddon, AnotherAddon
Attribute Required Description
X-Prison-Addon-Class Yes Fully-qualified class name implementing XPrisonAddon
X-Prison-Addon-Name No Display name shown in the addon manager GUI and logs
X-Prison-Addon-Version No Version string
X-Prison-Addon-Author No Author name
X-Prison-Addon-Description No Short description
X-Prison-Min-Version No Minimum X-Prison version (e.g. 2026.2.0). A warning is printed if the running version is older.
X-Prison-Priority No Integer load-order priority. Lower values load first. Default: 50.
X-Prison-Depends No Comma-separated list of addon names that must be loaded before this one. The addon is skipped if any dependency is missing.

Implement XPrisonAddon:

public class MyAddon implements XPrisonAddon {

    private XPrisonAddonContext context;

    @Override
    public void onEnable(XPrisonAddonContext context) {
        this.context = context;

        XPrisonAPI api = context.getAPI();           // full X-Prison API
        File dataFolder = context.getDataFolder();   // plugins/X-Prison/addons/MyAddon/
        Logger log = context.getLogger();            // prefixed logger
        String name = context.getAddonName();
        String version = context.getAddonVersion();

        // Register Bukkit event listeners
        context.registerEvents(new MyListener());

        log.info("MyAddon enabled.");
    }

    @Override
    public void onDisable() {
        context.getLogger().info("MyAddon disabled.");
    }
}

Tip: Use context.getDataFolder() for your own config files. Do not read or write to X-Prison's own data folder.


Addon Load Order

X-Prison resolves load order across all addon JARs before instantiating any of them. The rules, in priority order:

  1. Dependencies first — if your manifest declares X-Prison-Depends: CoreAddon, CoreAddon is always loaded before your addon, regardless of priority numbers.
  2. Lower priority number loads first — among addons with no dependency relationship, the one with the smaller X-Prison-Priority value loads first. Default is 50.
  3. Alphabetical tiebreak — addons sharing the same priority and no dependency relationship are loaded alphabetically by name for determinism.

Skipped addons — an addon is skipped (with a console warning) if:

  • A declared dependency is not present in the addons folder.
  • A dependency was itself skipped (cascade).
  • The addon is part of a circular dependency chain (A depends on B, B depends on A).

Unload order is the exact reverse of load order — dependents are always shut down before the addons they rely on.

Example manifest for an addon that must load after a hypothetical CoreAddon foundation:

X-Prison-Addon-Class: com.example.MyFeatureAddon
X-Prison-Addon-Name: MyFeatureAddon
X-Prison-Addon-Version: 1.0.0
X-Prison-Depends: CoreAddon
X-Prison-Priority: 60

Registering a Custom Enchant

Custom enchants must extend XPrisonEnchantment and are driven by JSON config files (placed in plugins/X-Prison/enchants/), just like built-in enchants.

@Override
public void onEnable(XPrisonAddonContext context) {
    MyCustomEnchant enchant = new MyCustomEnchant();
    context.getAPI().getEnchantsAPI().registerEnchant(enchant);
}

@Override
public void onDisable() {
    // unregister if needed
}

Your enchant class overrides these methods:

Method Called when
onEquip(Player, ItemStack, int) Player picks up or equips the pickaxe
onUnequip(Player, ItemStack, int) Player removes or drops the pickaxe
onBlockBreak(BlockBreakEvent, int) A block is broken in a mine with this enchant active
reload() The plugin is reloaded — re-read your config values here

Ranks API

XPrisonRanksAPI ranks = api.getRanksAPI();

// Online and offline reads
Rank rank = ranks.getPlayerRank(player);
Rank rank = ranks.getPlayerRankOffline(uuid);           // DB lookup, works for offline players
Rank next = ranks.getNextPlayerRank(player);
double progress = ranks.getRankupProgress(player);      // 0.0 – 1.0
boolean isMax = ranks.isMaxRank(player);

// Writes
ranks.setPlayerRank(player, rank);
ranks.setPlayerRankOffline(uuid, rank);                 // persists to DB immediately
ranks.resetPlayerRank(player);

// Leaderboard
List<RankLeaderboardEntry> top = ranks.getTopByRank(10);

// All player UUIDs that have rank data
Set<UUID> uuids = ranks.getAllPlayerUUIDs();

// Rank list
List<Rank> allRanks = ranks.getAllRanks();
Rank max = ranks.getMaxRank();
Rank defaultRank = ranks.getDefaultRank();
Rank byId = ranks.getRankById(id);

Prestiges API

XPrisonPrestigesAPI prestiges = api.getPrestigesAPI();

Prestige prestige = prestiges.getPlayerPrestige(player);
Prestige prestige = prestiges.getPlayerPrestigeOffline(uuid);   // offline lookup
double progress = prestiges.getPrestigeProgress(player);
boolean isMax = prestiges.isMaxPrestige(player);
Prestige next = prestiges.getNextPlayerPrestige(player);

prestiges.setPlayerPrestige(player, prestige);
prestiges.setPlayerPrestigeOffline(uuid, prestige);             // persists to DB immediately
prestiges.resetPlayerPrestige(player);

List<PrestigeLeaderboardEntry> top = prestiges.getTopByPrestige(10);
Set<UUID> uuids = prestiges.getAllPlayerUUIDs();

List<Prestige> all = prestiges.getAllPrestiges();
Prestige max = prestiges.getMaxPrestige();

Rebirth API

XPrisonRebirthAPI rebirth = api.getRebirthAPI();

Rebirth r = rebirth.getPlayerRebirth(player);
Rebirth r = rebirth.getPlayerRebirthOffline(uuid);   // offline lookup
boolean isMax = rebirth.isMaxRebirth(player);
Rebirth next = rebirth.getNextPlayerRebirth(player);

rebirth.setPlayerRebirth(player, r);
rebirth.setPlayerRebirthOffline(uuid, r);            // persists to DB immediately
rebirth.resetPlayerRebirth(player);
rebirth.tryRebirth(player);                          // attempts rebirth, checks requirements

List<RebirthLeaderboardEntry> top = rebirth.getTopByRebirth(10);
Set<UUID> uuids = rebirth.getAllPlayerUUIDs();

List<Rebirth> all = rebirth.getAllRebirths();
Rebirth max = rebirth.getMaxRebirth();

Currency API

XPrisonCurrencyAPI currency = api.getCurrencyApi();

// Balance operations — all work for online AND offline players
BigDecimal balance = currency.getBalance(uuid, currencyName);
currency.addBalance(uuid, currencyName, amount);
currency.removeBalance(uuid, currencyName, amount);    // clamped to 0
currency.setBalance(uuid, currencyName, amount);
boolean has = currency.has(uuid, currencyName, amount);
currency.transferBalance(fromUuid, toUuid, currencyName, amount);

// Leaderboard
List<CurrencyLeaderboardEntry> top = currency.getTopByBalance(currencyName, 10);
List<CurrencyLeaderboardEntry> top = currency.getTopByBalance(currencyName, 10, offset);

// Currency CRUD (live — changes apply immediately and persist to currencies.yml)
currency.createCurrency(name, displayName, prefix, suffix, format, startingBalance);
currency.updateCurrency(name, displayName, prefix, suffix, format);
currency.deleteCurrency(name);
XPrisonCurrency c = currency.getCurrency(name);
List<XPrisonCurrency> all = currency.getAllCurrencies();

Multipliers API

XPrisonMultipliersAPI multipliers = api.getMultipliersApi();

// Global multipliers (server-wide, per currency)
GlobalMultiplier g = multipliers.getGlobalMultiplier(currencyName);
multipliers.setGlobalMultiplier(currencyName, value, duration, unit);
multipliers.addGlobalMultiplier(currencyName, value, duration, unit);  // extends if active
multipliers.resetGlobalMultiplier(currencyName);

// Player multipliers (per player, per currency)
PlayerMultiplier p = multipliers.getPlayerMultiplier(player, currencyName);
multipliers.setPlayerMultiplier(player, currencyName, value, duration, unit);

// Rank multipliers (assigned via permission node xprison.multiplier.<rank>)
RankMultiplier r = multipliers.getRankMultiplier(player, currencyName);

Mines API

XPrisonMinesAPI mines = api.getMinesApi();

List<Mine> allMines = mines.getMines();
Mine mine = mines.getMine(name);

// Mine interface — key methods
String name = mine.getName();
World world = mine.getWorld();
int filled = mine.getFilledBlocks();
int total = mine.getTotalBlocks();
double pct = mine.getPercentageFull();            // 0.0 – 1.0
int players = mine.getPlayerCount();

// Added for Dashboard / addon support:
Map<String, Integer> effects = mine.getEffects();         // uppercase effect name → amplifier
String resetType = mine.getResetTypeName();               // "INSTANT" or "GRADUAL"

// Block palette
BlockPalette palette = mine.getBlockPalette();
List<MineBlock> blocks = palette.getBlocks();
palette.setPaletteByIds(Map<String, Double> blockIdToPercentage);  // save and apply new palette

mine.reset();

Auto-Sell API

XPrisonAutoSellAPI autoSell = api.getAutoSellApi();

// Global prices
Map<String, Double> global = autoSell.getGlobalPrices();
autoSell.addSellPrice(MineBlock block, double price);
autoSell.removeSellPrice(MineBlock block);

// Sell regions (per WorldGuard region)
List<SellRegion> regions = autoSell.getSellRegions();
SellRegion region = regions.get(i);
String id = region.getId();
World world = region.getWorld();
String permission = region.getRequiredPermission();
Map<String, Double> prices = region.getPrices();

autoSell.addRegionSellPrice(String regionId, MineBlock block, double price);
autoSell.removeRegionSellPrice(String regionId, MineBlock block);

Events

Listen to X-Prison events like any Bukkit event. All events are in the dev.drawethree.xprison.api package hierarchy.

Enchant Events

Event Cancellable Description
XPrisonEnchantPreTriggerEvent Yes Fired before a chance-based enchant rolls to trigger. Exposes the enchantment, getLevel() and getChanceToTrigger() (mutable) — adjust the proc chance or cancel the trigger. Also fired for reward-multiplier enchants (Token/Gem Merchant).
XPrisonEnchantTriggerEvent No Fired when an enchant successfully triggers. Exposes the enchantment and getLevel().
XPrisonPlayerEnchantEvent Yes Fired when a player buys enchant levels. Exposes getTokenCost() (mutable) and getLevel(). Cancelling prevents the purchase.
XPrisonEnchantDisenchantEvent Yes Fired when a player refunds enchant levels. Exposes the enchantment, getCurrentLevel(), getLevelsRemoved(), isAdmin() and getRefundAmount() (mutable). Cancelling prevents the disenchant.
XPrisonEnchantPrestigeEvent Yes Fired when a player prestiges an enchant. Exposes getOldPrestige(), getNewPrestige() (mutable), and the enchantment. Cancelling prevents the prestige.
XPrisonEnchantRegisterEvent / XPrisonEnchantUnregisterEvent No Fired when an enchant is registered/unregistered in the repository (e.g. by an addon).
PickaxeSoulbindEvent Yes Fired when a pickaxe is soulbound to a player (including automatic bind-on-first-hold). Exposes getPlayer() (new owner) and getItemStack(). Cancelling prevents the bind.
PickaxeUnsoulbindEvent Yes Fired when a pickaxe's soulbind is cleared (e.g. /unsoulbind). Exposes getPreviousOwner() (nullable) and getItemStack(). Cancelling keeps the soulbind.

Progression Events

Event Cancellable Description
XPrisonRankupEvent Yes Player ranks up
XPrisonPrestigeEvent Yes Player prestiges
XPrisonRebirthEvent Yes Player rebirths

Block Events

Event Cancellable Description
XPrisonBlockBreakEvent No Fired for every block broken by an X-Prison pickaxe

Gang Events

Event Cancellable Description
GangCreateEvent Yes A gang is created. Exposes getGangLeader() and getGang().
GangDisbandEvent Yes A gang is disbanded. Exposes getGang().
GangJoinEvent / GangLeaveEvent Yes A player joins/leaves a gang (GangLeaveEvent also covers kicks via getLeaveReason()).
GangInviteEvent Yes A player is invited to a gang. Exposes getInviter(), getPlayer() (the invited) and getGang().
GangRenameEvent Yes A gang is renamed. Exposes getGang(), getOldName(), getNewName() (mutable) and getWhoRenamed().
GangValueChangeEvent Yes A gang's value changes (admin modify/set/add). Exposes getGang(), getOldValue() and getNewValue() (mutable).
GangOwnershipTransferEvent Yes Gang ownership is transferred. Exposes getGang(), getOldOwner() and getNewOwner().

Mine Events

Event Cancellable Description
MineCreateEvent / MineDeleteEvent Yes A mine is created/deleted.
MineRenameEvent Yes A mine is renamed. Exposes getOldName() / getNewName().
MinePreResetEvent / MinePostResetEvent Pre only Fired before/after a mine resets.
MineTeleportEvent Yes A player is about to be teleported into a mine. Exposes getPlayer() and getMine().
MineRedefineEvent Yes A mine's region (bounds) is about to be redefined from a new selection. Exposes getPlayer() and getMine().

Multiplier Events

Event Cancellable Description
PlayerMultiplierReceiveEvent No A player receives a personal multiplier.
PlayerMultiplierExpireEvent No A player's multiplier expires.
PlayerMultiplierResetEvent Yes A player's personal multiplier is reset. Exposes getPlayer(), getCurrency() and getPreviousMultiplier().
GlobalMultiplierSetEvent Yes A server-wide multiplier is set. Exposes getCurrency(), getMultiplier() (mutable), getTimeUnit() and getDuration().
GlobalMultiplierResetEvent Yes A server-wide multiplier is reset. Exposes getCurrency() and getPreviousMultiplier().

Auto-Sell Events

Event Cancellable Description
XPrisonAutoSellEvent / XPrisonSellAllEvent Yes Items are auto-sold on mine / via /sellall. Exposes the mutable itemsToSell map and the sell region.
AutoSellToggleEvent Yes A player's AutoSell preference is about to change. Exposes getPlayer() and isNewState() (true = enabled).

Currency Events

Event Cancellable Description
PlayerCurrencyReceiveEvent Yes A player receives currency. Exposes the cause and getAmount() (mutable).
PlayerCurrencyLoseEvent No A player loses currency. Exposes the cause and getAmount() (mutable).
PlayerCurrencyBalanceSetEvent Yes A player's balance is set. Exposes getOldAmount() and getNewAmount() (mutable).
PlayerCurrencyPayEvent Yes A player pays currency to another player (single transaction). Exposes getSender(), getReceiver(), getCurrency() and getAmount() (mutable). Cancelling blocks the whole pay.

Bomb Events

Event Cancellable Description
BombThrowEvent Yes A player throws a bomb, before its explosion timer starts. Exposes getPlayer(), getBomb() and getLocation().
BombExplodeEvent Yes A bomb explodes. Listeners approve affected blocks via addAffectedBlocks(...).
BombGiveEvent Yes A player is given bomb item(s). Exposes getPlayer(), getBomb() and getAmount().

Battle Pass / Quests / Daily Rewards Events

These modules fire their events via Bukkit's callEvent.

Event Cancellable Description
BattlePassXpGainEvent Yes A player gains Battle Pass XP. Exposes the XpSource and getAmount() (mutable).
BattlePassTierUpEvent No A player advances one or more tiers.
BattlePassRewardClaimEvent Yes A player is about to claim a tier reward. Exposes getPlayer(), getTier() and getTrack().
BattlePassPremiumChangeEvent No A player's premium status changes. Exposes getUuid() and isPremium(). May fire off the main thread.
BattlePassSeasonResetEvent No A new season starts. Exposes the old/new season ids.
QuestCompleteEvent / QuestClaimEvent / QuestAssignEvent No A quest is completed / claimed / assigned.
PlayerDailyRewardClaimEvent No A daily reward is claimed. Exposes getStreak() and getCycleDay().

PrestigeableEnchant Interface

Enchants that support prestiging implement dev.drawethree.xprison.api.enchants.model.PrestigeableEnchant:

public interface PrestigeableEnchant {
    boolean isPrestigeEnabled();
    int getMaxPrestige();
    double getMultiplierPerPrestige();
    long getRequiredActivations(int currentPrestige);
}

Use this to check whether an enchant supports prestiging and read its configuration at runtime.


Notes

  • The API jar is provided scope — do not shade it into your plugin or addon.
  • Check the X-PrisonAPI GitHub repository for the most up-to-date interface definitions.
  • For questions about the API, open a ticket in the Discord server.

XPrison Logo

General

Modules

Default Configs

Enchant Configs — Passive

Enchant Configs — Currency Rewards

Enchant Configs — Key & Item Rewards

Enchant Configs — Area of Effect

Enchant Configs — Multipliers

Enchant Configs — Templates

Enchant Configs — Addons

Addons

Support

For Developers

Others

Clone this wiki locally