NexusPrism Developer API¶
This guide walks through integrating with NexusPrism from an external Bukkit/Paper plugin or a native addon JAR. You only ever compile against nexusprism-api — never against concrete module JARs.
Step 1 — Add the dependency¶
NexusPrism is published through JitPack. Add the repository and the API artifact to your pom.xml:
<repositories>
<repository>
<id>jitpack.io</id>
<url>https://jitpack.io</url>
</repository>
</repositories>
<dependencies>
<dependency>
<groupId>com.github.O-Tiger.NexusPrismModularizado</groupId>
<artifactId>nexusprism-api</artifactId>
<version>master-SNAPSHOT</version> <!-- or a specific commit hash -->
<scope>provided</scope>
</dependency>
</dependencies>
providedscope is required. NexusPrism ships the API at runtime — do not shade it into your JAR.
For Gradle (Kotlin DSL):
repositories {
maven("https://jitpack.io")
}
dependencies {
compileOnly("com.github.O-Tiger.NexusPrismModularizado:nexusprism-api:master-SNAPSHOT")
}
Step 2 — Declare the dependency in plugin.yml¶
Because NexusPrism is optional for most integrations, use softdepend. Use depend only if your plugin cannot function at all without it.
name: MyPlugin
version: 1.0.0
main: com.example.MyPlugin
api-version: "1.21"
softdepend:
- NexusPrism
Step 3 — Get the API instance¶
Always obtain the API inside onEnable(), after the server is fully started (or listen for ServerLoadEvent). Never call it from a static initializer or constructor.
import io.github.otiger.nexusprism.api.NexusPrismAPI;
public class MyPlugin extends JavaPlugin {
private NexusPrismAPI nexus;
@Override
public void onEnable() {
nexus = NexusPrismAPI.get();
if (nexus == null) {
getLogger().warning("NexusPrism not found — integration disabled.");
return;
}
if (!nexus.isReady()) {
// NexusPrism loaded but hasn't finished startup yet
// Listen to ServerLoadEvent or use Bukkit.getScheduler().runTaskLater(...)
getLogger().warning("NexusPrism is still starting up.");
return;
}
getLogger().info("Hooked into NexusPrism " + nexus.getVersion());
}
}
Step 4 — Module providers¶
Each optional NexusPrism module exposes a typed provider through a static registry. All providers return Optional — if the module is disabled or not installed, the Optional is empty. Always use ifPresent or orElse to handle this safely.
Economy¶
import io.github.otiger.nexusprism.api.NexusPrismAPI;
UUID uuid = player.getUniqueId();
// Read balance
double balance = NexusPrismAPI.economy()
.map(eco -> eco.getBalance(uuid))
.orElse(0.0);
// Add money
NexusPrismAPI.economy().ifPresent(eco -> eco.addMoney(uuid, 500.0));
// Charge player (returns false if insufficient funds)
boolean success = NexusPrismAPI.economy()
.map(eco -> eco.withdrawMoney(uuid, 100.0))
.orElse(false);
// Top balances
NexusPrismAPI.economy().ifPresent(eco -> {
eco.getTopBalances(10).forEach(entry ->
System.out.println(entry.uuid() + " → " + entry.balance()));
});
Authentication / Security¶
// Check if a player is logged in (defaults to true when auth module absent)
boolean loggedIn = NexusPrismAPI.auth()
.map(auth -> auth.isAuthenticated(uuid))
.orElse(true);
Clans¶
// Get a player's clan tag
String tag = NexusPrismAPI.clans()
.flatMap(c -> c.getClanTag(uuid))
.orElse("");
// Check clan membership
boolean hasClan = NexusPrismAPI.clans()
.map(c -> c.isInClan(uuid))
.orElse(false);
Essentials¶
// Teleport a player to their home named "base"
NexusPrismAPI.essentials().ifPresent(ess ->
ess.teleportHome(player, "base"));
// Check AFK status
boolean isAfk = NexusPrismAPI.essentials()
.map(ess -> ess.isAfk(uuid))
.orElse(false);
Votes¶
// Get a player's total vote count
int votes = NexusPrismAPI.votes()
.map(v -> v.getTotalVotes(uuid))
.orElse(0);
// Get current vote streak
int streak = NexusPrismAPI.votes()
.map(v -> v.getStreak(uuid))
.orElse(0);
Custom Enchantments¶
// Check if a tool has a specific custom enchant applied
boolean hasEnchant = NexusPrismAPI.enchants()
.map(e -> e.hasEnchant(item, "SOUL_MENDER"))
.orElse(false);
// Get the level of a custom enchant on an item
int level = NexusPrismAPI.enchants()
.map(e -> e.getLevel(item, "SOUL_MENDER"))
.orElse(0);
Crates¶
// Give a player a crate key
NexusPrismAPI.crates().ifPresent(c ->
c.giveKey(player, "VOTE_CRATE", 1));
MMO¶
import io.github.otiger.nexusprism.api.mmo.MmoRegistry;
UUID uuid = player.getUniqueId();
MmoRegistry.get().ifPresent(mmo -> {
int level = mmo.getLevel(uuid);
int mana = mmo.getCurrentMana(uuid);
int maxMana = mmo.getMaxMana(uuid);
// Consume mana (returns false if not enough)
if (mmo.hasMana(uuid, 20) && mmo.consumeMana(uuid, 20)) {
// ability triggered
}
// Add XP to a skill tree
mmo.addSkillXp(player, "warrior", 100L);
// Add XP to a profession
mmo.addProfessionXp(player, "mining", 50L);
// Stat access
int strength = mmo.getStat(uuid, "STRENGTH");
List<String> abilities = mmo.getUnlockedAbilityIds(uuid);
});
Chat¶
import io.github.otiger.nexusprism.api.chat.ChatRegistry;
ChatRegistry.get().ifPresent(chat -> {
// Mute checks
boolean muted = chat.isMuted(uuid);
// Mute for 10 minutes
chat.mute(uuid, 10 * 60 * 1000L, "Spam", "Console");
// Broadcast to a channel
chat.broadcastToChannel("global", "[MyAddon] Server announcement!");
// Get which channel a player is currently active in
String activeChannel = chat.getActiveChannel(uuid);
});
Protections¶
import io.github.otiger.nexusprism.api.protections.ProtectionsRegistry;
ProtectionsRegistry.get().ifPresent(prot -> {
// PvP check at a location
boolean pvp = prot.isPvpAllowed(location);
// Duel state
boolean inDuel = prot.isInDuel(uuid);
prot.getDuelOpponent(uuid).ifPresent(opponentUuid -> { /* ... */ });
// Region info
List<String> regions = prot.getRegionNamesAt(location);
prot.getRegionOwnerAt(location).ifPresent(ownerUuid -> { /* ... */ });
int claimed = prot.getRegionCount(uuid);
});
Events (Blood Moon, Sacrifice Arc, Isekai Boss)¶
import io.github.otiger.nexusprism.api.events.EventsRegistry;
EventsRegistry.get().ifPresent(events -> {
boolean moonActive = events.isBloodMoonActive();
boolean inWorld = events.isBloodMoonActive(player.getWorld());
int streak = events.getSacrificeStreak(uuid);
boolean inSacrifice = events.isInSacrifice(uuid);
boolean hasBoss = events.hasActiveBossFight(uuid);
// Check if player needs to sacrifice (streak milestone reached)
boolean mustSacrifice = events.needsSacrifice(uuid);
});
Holograms¶
import io.github.otiger.nexusprism.api.holograms.HologramRegistry;
HologramRegistry.get().ifPresent(holo -> {
holo.create("my_holo", location);
holo.addLine("my_holo", "§aHello from my addon!");
holo.setLine("my_holo", 0, "§eUpdated line");
holo.removeLine("my_holo", 0);
holo.moveTo("my_holo", newLocation);
// Per-player visibility
holo.showToPlayer("my_holo", player);
holo.hideFromPlayer("my_holo", player);
// Cleanup
holo.delete("my_holo");
});
Backpacks¶
import io.github.otiger.nexusprism.api.backpack.BackpackRegistry;
BackpackRegistry.get().ifPresent(bp -> {
int count = bp.getBackpackCount(uuid);
int maxCount = bp.getMaxBackpacks(uuid);
boolean can = bp.canCreateBackpack(player);
List<UUID> ids = bp.getBackpackIds(uuid);
// Open GUIs
bp.openFirstBackpack(player); // opens first backpack
bp.openBackpack(player, ids.get(0)); // opens specific one
});
Traits (Tarot cards)¶
import io.github.otiger.nexusprism.api.traits.TraitsRegistry;
TraitsRegistry.get().ifPresent(traits -> {
List<String> cards = traits.getCards(uuid); // card names the player holds
boolean hasCard = traits.hasCard(uuid, "The Tower");
int researchLevel = traits.getResearchLevel(uuid);
traits.setResearchLevel(uuid, 5);
// All available card names
List<String> allCards = traits.getCardNames();
// Cooldown info (ms remaining)
long rerollMs = traits.fullRerollCooldownRemainingMs(uuid);
});
Discord¶
import io.github.otiger.nexusprism.api.discord.DiscordRegistry;
DiscordRegistry.get().ifPresent(discord -> {
// Link status
boolean linked = discord.isLinked(uuid);
discord.getDiscordId(uuid).ifPresent(discordId -> { /* ... */ });
discord.getMinecraftUuid("123456789").ifPresent(mcUuid -> { /* ... */ });
// Send a plain message to a configured channel
discord.sendMessage("server-log", "[MyAddon] Something happened!");
// Send a webhook-style message with custom display name and avatar
discord.sendWebhook("server-log", "MyAddon Bot", null, "Player did a thing.");
// Generate a link code for a player
String code = discord.generateLinkCode(uuid);
player.sendMessage("Your link code: " + code);
});
Jobs¶
import io.github.otiger.nexusprism.api.economy.JobRegistry;
JobRegistry.get().ifPresent(jobs -> {
Optional<String> jobId = jobs.getActiveJob(uuid);
boolean hasJob = jobs.hasJob(uuid);
if (hasJob) {
int level = jobs.getLevel(uuid, jobId.get());
long xp = jobs.getXp(uuid, jobId.get());
}
List<String> allJobs = jobs.getAllJobIds(); // e.g. ["miner", "farmer", "hunter"]
// Force-join a job
jobs.joinJob(uuid, "miner");
// Leave current job
jobs.leaveJob(uuid);
});
Energy networks¶
import io.github.otiger.nexusprism.api.energy.EnergyRegistry;
EnergyRegistry.get().ifPresent(energy -> {
energy.getNetworkAt(location).ifPresent(net -> {
long stored = net.getTotalStoredEnergy();
long cap = net.getTotalCapacity();
int netFlow = net.getNetFlow(); // positive = surplus
});
// Register / unregister a custom EnergyComponent
energy.registerComponent(myComponent); // call in onEnable / block-place listener
energy.unregisterComponent(myComponent); // call in onDisable / block-break listener
});
Step 5 — Custom items¶
Use NexusItemBuilder to inspect any ItemStack and check whether it is a NexusPrism custom item.
import io.github.otiger.nexusprism.api.items.builder.NexusItemBuilder;
ItemStack item = player.getInventory().getItemInMainHand();
// Get the internal item ID (e.g. "COPPER_DUST", "CELESTIAL_SWORD")
String id = NexusItemBuilder.getItemId(item); // null if not a NexusPrism item
if ("CELESTIAL_SWORD".equals(id)) {
player.sendMessage("You are holding the Celestial Sword!");
}
You can also resolve a custom item from the registry via getService:
import io.github.otiger.nexusprism.api.registry.ItemRegistry;
ItemRegistry registry = nexus.getService(ItemRegistry.class);
if (registry != null) {
registry.getItem("COPPER_DUST").ifPresent(nexusItem -> {
ItemStack stack = nexusItem.buildStack(1);
player.getInventory().addItem(stack);
});
}
Step 6 — Territory API¶
If you are building a land-claiming or region system and want it to integrate with NexusPrism's protection checks (machine placement, clan building rules, etc.), implement TerritoryProvider and register it.
import io.github.otiger.nexusprism.api.territory.TerritoryProvider;
import io.github.otiger.nexusprism.api.territory.TerritoryRegistry;
import org.bukkit.Location;
import org.bukkit.entity.Player;
public class MyRegionProvider implements TerritoryProvider {
@Override
public boolean isClaimed(Location location) {
return MyRegionManager.isClaimed(location);
}
@Override
public boolean canBuild(Player player, Location location) {
return MyRegionManager.canBuild(player, location);
}
@Override
public boolean canInteract(Player player, Location location) {
return MyRegionManager.canInteract(player, location);
}
@Override
public java.util.Optional<String> getClaimName(Location location) {
return MyRegionManager.getRegionName(location);
}
}
Register and unregister in your plugin's lifecycle:
private final MyRegionProvider provider = new MyRegionProvider();
@Override
public void onEnable() {
TerritoryRegistry.register(provider);
}
@Override
public void onDisable() {
TerritoryRegistry.unregister(provider);
}
NexusPrism uses deny-wins aggregation: if any registered provider denies
canBuild, the action is blocked.
Step 7 — Event flags¶
EventFlags exposes live server-state flags from the Events module. Read these to react to Blood Moon and economy multipliers.
import io.github.otiger.nexusprism.api.events.EventFlags;
// Is the Blood Moon currently active?
if (EventFlags.bloodMoonActive) {
// Double your boss spawn rates, apply particle effects, etc.
}
// Current economy kill-pay multiplier (1.0 = normal, 1.5 = +50% during Blood Moon)
double multiplier = EventFlags.killPayMultiplier;
double reward = baseReward * multiplier;
Step 8 — Structure loot injection¶
Register a StructureProvider to inject custom loot into vanilla structures when they are generated.
import io.github.otiger.nexusprism.api.structures.StructureProvider;
import io.github.otiger.nexusprism.api.structures.StructureRegistry;
import org.bukkit.NamespacedKey;
import org.bukkit.inventory.ItemStack;
import java.util.List;
public class MyLootProvider implements StructureProvider {
@Override
public NamespacedKey structure() {
return NamespacedKey.minecraft("village/plains/houses/plains_small_house_1");
}
@Override
public List<ItemStack> loot() {
// Return items to inject into chests inside this structure
return List.of(new ItemStack(Material.DIAMOND, 1));
}
}
Step 9 — Writing a native addon¶
Native addons are JAR files dropped into plugins/NexusPrism/addons/. They are loaded by NexusPrism directly and do not need their own plugin.yml.
1. Create the addon class¶
import io.github.otiger.nexusprism.api.addon.AbstractNexusAddon;
import io.github.otiger.nexusprism.api.NexusPrismAPI;
public class MyAddon extends AbstractNexusAddon {
@Override
public void onEnable() {
// Load config (reads config.yml from JAR if not yet extracted)
saveDefaultConfig();
String welcomeMsg = getConfig().getString("welcome-message", "Hello!");
getLogger().info(welcomeMsg);
// Use the API
NexusPrismAPI api = getAPI();
getLogger().info("Hooked — NexusPrism " + api.getVersion());
// Register a territory provider
TerritoryRegistry.register(new MyRegionProvider());
}
@Override
public void onDisable() {
TerritoryRegistry.unregister(myProvider);
getLogger().info(getName() + " disabled.");
}
}
2. Create addon.yml inside the JAR¶
id: my-addon
name: My Addon
version: 1.0.0
description: Demonstrates the NexusPrism addon API.
authors:
- YourName
main: com.example.MyAddon
min-nexus-version: 1.0.0
# Hard dependencies (must be present):
dependencies: []
# Optional dependencies (loaded first if present):
soft-dependencies: []
3. Build and install¶
Restart the server. You should see:
Starter template
A ready-to-clone Maven project is available at O-Tiger/NexusPrism-Addon-Example. It includes working examples of every API surface described in this guide.
Step 10 — Content loading from addons¶
Native addons can register custom items, machines, crafting recipes, and infinity recipes directly from YAML files bundled in their JAR. NexusPrism merges this content into the server registry at load time.
import io.github.otiger.nexusprism.api.content.ContentLoadResult;
@Override
public void onEnable() {
// content() returns a fluent builder scoped to this addon.
// Files are read from the addon's data folder first,
// then extracted from the JAR if not found on disk.
ContentLoadResult result = content()
.items("items.yml") // custom item definitions
.machines("machines.yml") // custom machine type definitions
.recipes("recipes.yml") // standard crafting recipes
.infinityRecipes("infinity_recipes") // all *.yml in this directory
.register();
result.logTo(getLogger()); // prints counts & errors
}
Machine processing recipes (programmatic)¶
If you want to add input→output rules to an existing machine type from code (rather than YAML), use MachineProcessingRegistry. The engine checks these alongside YAML-defined recipes.
import io.github.otiger.nexusprism.api.machines.recipe.MachineProcessingRecipe;
import io.github.otiger.nexusprism.api.machines.recipe.MachineProcessingRegistry;
@Override
public void onEnable() {
MachineProcessingRegistry.register(
MachineProcessingRecipe.builder("my_addon_recipe", "EXAMPLE_FURNACE")
.input("DIAMOND", 1)
.input("EXAMPLE_DUST", 4)
.output("EXAMPLE_INGOT", 3)
.time(120) // ticks; 0 = machine default
.source(getId()) // used for cleanup on disable
.build()
);
}
@Override
public void onDisable() {
// Always clean up — avoids stale entries after reload
MachineProcessingRegistry.unregisterBySource(getId());
}
Complete integration example¶
Below is a full minimal plugin that hooks into NexusPrism, rewards players with money on kill, and respects Blood Moon multipliers.
package com.example;
import io.github.otiger.nexusprism.api.NexusPrismAPI;
import io.github.otiger.nexusprism.api.events.EventFlags;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.entity.PlayerDeathEvent;
import org.bukkit.plugin.java.JavaPlugin;
public class KillRewardPlugin extends JavaPlugin implements Listener {
@Override
public void onEnable() {
if (NexusPrismAPI.get() == null) {
getLogger().warning("NexusPrism not found — disabling kill rewards.");
return;
}
getServer().getPluginManager().registerEvents(this, this);
getLogger().info("Kill rewards enabled.");
}
@EventHandler
public void onPlayerKill(PlayerDeathEvent event) {
if (!(event.getEntity().getKiller() instanceof Player killer)) return;
double base = 25.0;
double reward = base * EventFlags.killPayMultiplier; // scales with Blood Moon
NexusPrismAPI.economy().ifPresent(eco -> {
eco.addMoney(killer.getUniqueId(), reward);
killer.sendMessage("§a+$" + String.format("%.0f", reward) + " §7for the kill!");
});
}
}
Quick-reference¶
| API surface | Class / method |
|---|---|
| Get API instance | NexusPrismAPI.get() |
| Core providers | |
| Economy | NexusPrismAPI.economy() → EconomyProvider |
| Auth | NexusPrismAPI.auth() → AuthProvider |
| Clans | NexusPrismAPI.clans() → ClanProvider |
| Essentials | NexusPrismAPI.essentials() → EssentialsProvider |
| Votes | NexusPrismAPI.votes() → VoteProvider |
| Enchantments | NexusPrismAPI.enchants() → CustomEnchantProvider |
| Crates | NexusPrismAPI.crates() → CrateProvider |
| Module providers | |
| MMO (level, stats, mana, skills, professions) | MmoRegistry.get() → MmoProvider |
| Chat (mute, channels, broadcast) | ChatRegistry.get() → ChatProvider |
| Protections (PvP, regions, duels) | ProtectionsRegistry.get() → ProtectionsProvider |
| Events (Blood Moon, Sacrifice, Isekai) | EventsRegistry.get() → EventsProvider |
| Holograms (create, update, show/hide) | HologramRegistry.get() → HologramProvider |
| Backpacks (count, open GUI) | BackpackRegistry.get() → BackpackProvider |
| Traits / Tarot cards | TraitsRegistry.get() → TraitsProvider |
| Discord (link, send message/webhook) | DiscordRegistry.get() → DiscordProvider |
| Jobs (active job, level, XP) | JobRegistry.get() → JobProvider |
| Energy networks | EnergyRegistry.get() → EnergyProvider |
| Content & extensibility | |
| Addon content loading | content().items().machines().recipes().register() |
| Machine processing recipes | MachineProcessingRegistry.register(MachineProcessingRecipe) |
| Item ID lookup | NexusItemBuilder.getItemId(ItemStack) |
| Item registry | nexus.getService(ItemRegistry.class) |
| Territory | TerritoryRegistry.register(TerritoryProvider) |
| Event state flags | EventFlags.bloodMoonActive, EventFlags.killPayMultiplier |
| Structure loot | StructureRegistry.register(StructureProvider) |
| Native addon base | AbstractNexusAddon + addon.yml |
| Starter template | O-Tiger/NexusPrism-Addon-Example |
Best practices¶
- Always null-check
NexusPrismAPI.get()before using any provider. - Use
softdependunless your plugin is literally an addon JAR — this lets your plugin load even if NexusPrism is absent. - Never shade
nexusprism-api— useprovided/compileOnlyscope. - Unregister providers in
onDisable()to avoid ghost listeners after reload. - Use
Optionalchains (ifPresent,orElse) — never call.get()on an empty Optional. - Check
isReady()if you call the API immediately on enable; NexusPrism loads modules asynchronously.