Skip to content

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>

provided scope 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));
    }
}
// Register on enable, unregister on disable
StructureRegistry.register(new MyLootProvider());

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

mvn package
cp target/my-addon-1.0.0.jar plugins/NexusPrism/addons/

Restart the server. You should see:

[NexusPrism] [MyAddon] Hello!
[NexusPrism] [MyAddon] Hooked — NexusPrism 1.0.0-DEV

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 softdepend unless your plugin is literally an addon JAR — this lets your plugin load even if NexusPrism is absent.
  • Never shade nexusprism-api — use provided/compileOnly scope.
  • Unregister providers in onDisable() to avoid ghost listeners after reload.
  • Use Optional chains (ifPresent, orElse) — never call .get() on an empty Optional.
  • Check isReady() if you call the API immediately on enable; NexusPrism loads modules asynchronously.