-
Notifications
You must be signed in to change notification settings - Fork 58
Developer API
The X-Prison public API lives in a dedicated project: X-PrisonAPI on GitHub
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]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 claimsBattle 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 runningModule 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 restartAddons 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.
X-Prison resolves load order across all addon JARs before instantiating any of them. The rules, in priority order:
-
Dependencies first — if your manifest declares
X-Prison-Depends: CoreAddon,CoreAddonis always loaded before your addon, regardless of priority numbers. -
Lower priority number loads first — among addons with no dependency relationship, the one with the smaller
X-Prison-Priorityvalue loads first. Default is50. - 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
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 |
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);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();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();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();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);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();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);Listen to X-Prison events like any Bukkit event. All events are in the dev.drawethree.xprison.api package hierarchy.
| 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. |
| Event | Cancellable | Description |
|---|---|---|
XPrisonRankupEvent |
Yes | Player ranks up |
XPrisonPrestigeEvent |
Yes | Player prestiges |
XPrisonRebirthEvent |
Yes | Player rebirths |
| Event | Cancellable | Description |
|---|---|---|
XPrisonBlockBreakEvent |
No | Fired for every block broken by an X-Prison pickaxe |
| 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(). |
| 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(). |
| 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(). |
| 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). |
| 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. |
| 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(). |
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(). |
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.
- The API jar is
providedscope — 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.
- Currencies
- Ranks
- Prestiges
- Rebirths
- Mines
- AutoSell
- AutoMiner
- Enchants
- Pickaxe Levels
- Pickaxe Skins
- Gangs
- Multipliers
- Blocks
- Bombs
- History
- Mining Stats
- Nicknames
- Battle Pass
- Quests
- Daily Rewards
- config.yml
- autominer.yml
- autosell.yml
- block-rewards.yml
- enchants.yml
- currencies.yml
- multipliers.yml
- ranks.yml
- prestiges.yml
- pickaxe-levels.yml
- pickaxe-skins.yml
- gangs.yml
- mines.yml
- bombs.yml
- blocks.yml
- history.yml
- mining-stats.yml
- rebirths.yml
- battlepass.yml
- quests.yml
- dailyrewards.yml
- efficiency.json
- fortune.json
- unbreaking.json
- haste.json
- speed.json
- fly.json
- nightvision.json
- jumpboost.json
- autosell.json
- tokenfinder.json
- gemfinder.json
- salary.json
- charity.json
- blessing.json
- gangvaluefinder.json
- prestigefinder.json
