-
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 |
If your enchant breaks many blocks at once, extend AreaBreakEnchant
(dev.drawethree.xprison.api.enchants.area) instead of implementing onBlockBreak yourself. You
override selectTargets(...) to say which blocks are affected; drops, auto-sell, Fortune,
prestige scaling, currency payout, the proc message, mine-reset accounting, pickaxe progression and
packet-mine support are all handled by the shared pipeline.
Full guide, including the available hooks and the eventStrategy performance trade-off:
Area Enchants: AreaBreakEnchant.
If you cannot extend AreaBreakEnchant — for example your enchant already extends something else —
these API methods expose the individual pieces. All of them are default, so an addon compiled
against 1.9 still loads on an older core (the feature simply becomes a no-op).
XPrisonEnchantsAPI enchants = api.getEnchantsApi();
// The cuboid an area enchant may affect (highest-priority region that permits enchants).
Optional<AreaBounds> region = enchants.getEnchantRegionBounds(location);
// Fortune level on a pickaxe, and blocks Fortune must not multiply.
int fortune = enchants.getItemFortuneLevel(pickaxe);
boolean skip = enchants.isFortuneBlacklisted(block);
// Suppress X-Prison's own gated listeners for a synthetic BlockBreakEvent you fire.
enchants.ignoreBlockBreakEvent(event);
XPrisonBlocksAPI blocks = api.getBlocksApi();
// Run the shared post-break pipeline once for a set of blocks: blocks-broken statistic,
// lucky blocks, and the aggregate XPrisonBlockBreakEvent that quests / battle pass /
// block boosters consume. Call this ONLY when you are not firing a Bukkit event per
// block — otherwise X-Prison's own listener already ran it and you would double-count.
blocks.handleBlockBreak(player, brokenBlocks, countBlocksBroken);
// Bulk form for breaks too large to enumerate (a whole packet mine): O(block types).
blocks.handleBulkBlockBreak(player, typeCounts);
// Credit the pickaxe with blocks and XP from a named source.
api.getPickaxeLevelsApi()
.addBlocksAndExp(player, pickaxe, blockCount, exp, PickaxeExpSource.AREA_ENCHANTS);
// Read a pickaxe's permanent quality tier and what it multiplies. Absent tag = tier 0 = 1.0x.
XPrisonPickaxeQualityAPI quality = api.getPickaxeQualityApi();
double tokenBonus = quality.getCurrencyMultiplier(pickaxe, "tokens");
// PlayerPickaxeQualityUpgradeEvent is cancellable and its cost is mutable, so an addon can
// block an upgrade or discount it before the player is charged.
// Currencies can be capped, so credit and report what was ACTUALLY added — otherwise a
// "you earned %amount%" message overstates the payout whenever the cap clamps it.
BigDecimal credited = api.getCurrencyApi()
.addBalance(player, currency, amount, ReceiveCause.MINING);
// Drops belong in the backpack, not the inventory, when this is on. Note UltraBackpacks
// reads real world state, so bypass it whenever the affected blocks are virtual.
boolean backpacks = api.isUltraBackpacksEnabled();Use this instead of depending on Adventure directly. X-Prison does not shade Adventure — it uses
the copy Paper bundles, and on servers that provide none (Spigot, CraftBukkit) it renders MiniMessage
down to classic colour codes instead. An addon that imports net.kyori itself therefore works on
Paper but fails to link on Spigot, and nothing warns you at compile time, because Paper's API pulls
Adventure in transitively.
XPrisonTextAPI text = api.getTextApi();
// Sending — PlaceholderAPI placeholders are resolved for you
text.sendMessage(player, "<gradient:#FFD700:#FFAA00>Well mined!</gradient>");
text.sendMessage(player, List.of("<gray>Line one", "<gray>Line two"));
text.sendActionBar(player, "<green>+100 tokens");
text.sendTitle(player, "<gold><bold>LEVEL UP", "<gray>You reached level %level%", 10, 40, 10);
// Rendering to a String, for sinks that take coloured text rather than sending it
String hologramLine = text.toLegacySection(configLine); // legacy section codes
String plain = text.stripTags(gangName); // no tags at all
// Feature check — hover and click cannot be shown on Spigot
if (text.isRich()) {
text.sendMessage(player, "<click:open_url:'https://example.com'>Click me</click>");
} else {
text.sendMessage(player, "<gray>Visit https://example.com");
}| Method | Description |
|---|---|
sendMessage(CommandSender, String) |
Send one message |
sendMessage(CommandSender, List<String>) |
Send several lines |
sendActionBar(Player, String) |
Send an action bar message |
sendTitle(Player, String, String, int, int, int) |
Title, subtitle and timings in ticks |
toLegacySection(String) |
Render to legacy § codes for holograms, scoreboards, PAPI returns |
stripTags(String) |
Plain text, for length limits and name comparisons |
isRich() |
true when hover, click and fonts are available (Paper-family servers) |
Pass raw config text. MiniMessage tags and legacy
&codes are both accepted, and X-Prison renders once, for whichever server it is on. Do not pre-render before passing it in — rendering twice is how player-supplied values (names, nicknames) end up recolouring the message around them.
Never use
ChatColor.stripColoron config text. It does nothing to MiniMessage tags, so a name written as<gradient:#FFD700:#FFAA00>Elite</gradient>measures 5 characters throughstripTags()and 46 throughstripColor. UsestripTags()for every length check and name comparison.
All methods are thread-safe and never throw on malformed input.
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);
// 1.9 — exact-precision pricing. Prefer this when multiplying one type's price by a
// large count (an area enchant prices per block *type* and multiplies by how many were
// broken), where a double would lose precision on OP-scale servers.
BigDecimal exact = autoSell.getSellPriceForBlockExact(mineBlock);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 getTokenCostExact() (BigDecimal, mutable via setTokenCostExact) and getLevel(). getTokenCost()/setTokenCost() remain as a saturating long view. Cancelling prevents the purchase. |
XPrisonEnchantDisenchantEvent |
Yes | Fired when a player refunds enchant levels. Exposes the enchantment, getCurrentLevel(), getLevelsRemoved(), isAdmin() and getRefundAmountExact() (BigDecimal, mutable via setRefundAmountExact). getRefundAmount()/setRefundAmount() remain as a saturating long view. 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 |
XPrisonBulkBlockBreakEvent |
Yes |
(1.9) Fired once for a break too large to enumerate block-by-block — notably a whole packet ("virtual") mine, whose blocks have no real Block handles. Carries a Map<MineBlock, Long> of type → count plus getTotalBlocks(), so consumers scale in O(distinct block types) instead of O(blocks). Listen to this in addition to XPrisonBlockBreakEvent if your plugin tracks mined volume. |
| 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. Since 2026.2.8.0 the map is Map<AutoSellItemStack, BigDecimal> (was Double) for exact OP-scale prices — recompile addons that listen to these events. |
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.
Since X-Prison 2026.3.3.0. The enchant menus are paginated, and two interfaces gained a page accessor to go with the existing slot accessor:
// dev.drawethree.xprison.api.enchants.model.XPrisonEnchantmentGuiProperties
int getGuiSlot();
default int getGuiPage() { return 1; } // 1-based
// dev.drawethree.xprison.api.enchants.model.RefundableEnchant
int getRefundGuiSlot();
default int getRefundGuiPage() { return 1; } // 1-basedBoth are default methods, so existing addons keep compiling and running unchanged — they simply
report page 1. If you extend XPrisonEnchantmentBase, both values are read from your enchant's JSON
for free: gui.page and refund.guiPage, each optional and defaulting to 1.
Pages are 1-based. You do not need to guarantee a free slot: if the slot or page you ask for is already taken, or falls outside the menu's configured content region, the core moves your enchant to the next free slot and onto a later page if required. An out-of-range slot can no longer throw and break the menu.
refund.guiSlot is now optional too (defaulting to -1), so an enchant JSON that omits it still
loads instead of failing outright.
- 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
- Pickaxe Quality
- Pickaxe Settings
- Gangs
- Multipliers
- Blocks
- Bombs
- History
- Mining Stats
- Nicknames
- Battle Pass
- Quests
- Daily Rewards
- Milestones
- 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
- pickaxe-quality.yml
- gangs.yml
- mines.yml
- bombs.yml
- blocks.yml
- history.yml
- logging.yml
- mining-stats.yml
- rebirths.yml
- battlepass.yml
- quests.yml
- dailyrewards.yml
- milestones.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
