Skip to content

Developer API

Rudra edited this page Jan 7, 2026 · 5 revisions

Developer API

This guide explains how to integrate with LevelTools from your own plugins. You can register custom triggers, profiles, and hook into the plugin lifecycle.

Table of Contents


Getting Started

LevelTools provides a developer API for external plugins to:

  1. Register custom triggers - Define new ways for tools to gain XP
  2. Register profiles at runtime - Add trigger, reward, display, and item profiles programmatically
  3. Hook into lifecycle events - Know when LevelTools is ready for registration

Quick Example

public class MyPlugin extends JavaPlugin{

    @Override
    public void onEnable() {
        LevelToolsAPI.registerTrigger(new CropHarvestTrigger());
        registerProfiles();

        Player player = Bukkit.getPlayerExact("byteful");
        ItemStack hand = player.getInventory().getItemInMainHand();
        LevelToolsItem tool = LevelToolsUtil.createLevelToolsItem(hand);
        tool.setLevel(6);
        tool.setXp(70);
        player.getInventory().setItemInMainHand(tool.getItemStack());
    }

    private void registerProfiles() {
        // Create and register a trigger profile
        TriggerProfile triggerProfile = TriggerProfile.builder("crop_harvesting")
            .triggerId("crop_harvest")
            .xpModifier(new XpModifierConfig(1.0, 3.0, Map.of()))
            .build();

        LevelToolsAPI.registerTriggerProfile(triggerProfile);

        // Create and register an item profile
        ItemProfile itemProfile = ItemProfile.builder("custom_hoes")
            .materials(Set.of(Material.DIAMOND_HOE, Material.NETHERITE_HOE))
            .triggerProfile("crop_harvesting")
            .rewardProfile("tools")  // Use existing reward profile
            .displayProfile("default") // Use existing display profile
            .maxLevel(50)
            .build();

        RegistrationResult result = LevelToolsAPI.registerItemProfile(itemProfile);
        if (!result.isSuccess()) {
            getLogger().warning("Failed to register profile: " + result.getErrorMessage());
        }
    }
}

Dependency Setup

plugin.yml

Add LevelTools as a dependency or soft-dependency:

# Required dependency
depend: [LevelTools]

# Or optional dependency
softdepend: [LevelTools]

Maven

<repositories>
    <repository>
        <id>jitpack.io</id>
        <url>https://jitpack.io</url>
    </repository>
</repositories>

<dependencies>
    <dependency>
        <groupId>com.github.byteful</groupId>
        <artifactId>LevelTools</artifactId>
        <version>VERSION</version>
        <scope>provided</scope>
    </dependency>
</dependencies>

Gradle

repositories {
    maven { url 'https://jitpack.io' }
}

dependencies {
    compileOnly 'com.github.byteful:LevelTools:VERSION'
}

Load Event

LevelTools fires LevelToolsLoadEvent at various lifecycle phases.

Load Phases

Phase Description
PRE_LOAD Before default triggers are registered
POST_TRIGGERS After triggers, before profiles
POST_PROFILES After config profiles are loaded
COMPLETE Everything is ready

Important Notes

  • The event is also fired during plugin reload (/leveltools reload)
  • External profiles are preserved during reload
  • Always check if LevelTools is enabled before using the Bukkit/Spigot API outside of event handlers

Custom Triggers

Triggers define how a tool gains XP. LevelTools includes built-in triggers for common actions, but you can add your own.

Built-in Trigger IDs

Trigger ID Description
block_break Breaking blocks
entity_kill Killing entities
fishing Catching fish/items
right_click Right-click actions
left_click Left-click actions
consume Consuming items

Creating a Custom Trigger

Extend AbstractTrigger for convenience:

public class CropHarvestTrigger extends AbstractTrigger {

    public CropHarvestTrigger() {
        super("crop_harvest"); // Your unique trigger ID
    }

    @Override
    public boolean canHandle(@NotNull TriggerContext context) {
        // Get the source (in this case, a block from BlockBreakEvent)
        Block block = context.getSourceAs(Block.class);
        if (block == null) return false;

        // Check if it's a mature crop
        BlockData data = block.getBlockData();
        if (data instanceof Ageable) {
            Ageable ageable = (Ageable) data;
            if (ageable.getAge() < ageable.getMaximumAge()) {
                return false; // Not fully grown
            }
        }

        // Use the built-in filter from the trigger profile
        String blockType = block.getType().name();
        return isSourceAllowed(context, blockType);
    }

    @Override
    public double calculateXpModifier(@NotNull TriggerContext context) {
        Block block = context.getSourceAs(Block.class);
        if (block == null) return 0;

        // Use the built-in XP modifier from the trigger profile
        return calculateDefaultXpModifier(context, block.getType().name());
    }
}

Registering the Trigger

// Make sure LevelTools is enabled!
LevelToolsAPI.registerTrigger(new CropHarvestTrigger());

TriggerContext

The TriggerContext provides all information about the triggering event:

// Player who triggered the action
Player player = context.getPlayer();

// The tool item being leveled
ItemStack item = context.getItem();

// The trigger ID
String triggerId = context.getTriggerId();

// The source object (Block, Entity, ItemStack, etc.)
Block block = context.getSourceAs(Block.class);
Entity entity = context.getSourceAs(Entity.class);

// The original Bukkit event
BlockBreakEvent event = context.getOriginalEventAs(BlockBreakEvent.class);

// Associated profiles
ItemProfile itemProfile = context.getItemProfile();
TriggerProfile triggerProfile = context.getTriggerProfile();

Profile Registration

Profiles define what happens when tools are used. There are 4 types of profiles:

Profile Types

Type Description
Trigger Profile Defines XP amounts, filters, and settings for a trigger
Reward Profile Defines rewards (enchants, commands, attributes) for each level
Display Profile Defines how level/XP is displayed on items
Item Profile Links materials to trigger, reward, and display profiles

Creating Profiles

Trigger Profile

TriggerProfile triggerProfile = TriggerProfile.builder("my_trigger_profile")
    .triggerId("crop_harvest")  // Your custom trigger ID
    .xpModifier(new XpModifierConfig(
        1.0,  // Default min XP
        2.0,  // Default max XP
        Map.of(
            "WHEAT", new XpModifierConfig.XpModifierRange(2.0, 4.0),
            "CARROTS", new XpModifierConfig.XpModifierRange(1.5, 3.0)
        )
    ))
    .filter(new TriggerFilter(
        true,  // true = whitelist, false = blacklist
        Set.of("WHEAT", "CARROTS", "POTATOES", "BEETROOTS")
    ))
    .build();

RegistrationResult result = LevelToolsAPI.registerTriggerProfile(triggerProfile);

Reward Profile

Map<Integer, List<RewardEntry>> rewards = new HashMap<>();

// Level 5 rewards
rewards.put(5, List.of(
    new RewardEntry(RewardType.ENCHANT, "EFFICIENCY", "1"),
    new RewardEntry(RewardType.COMMAND, "give {player} diamond 1")
));

// Level 10 rewards
rewards.put(10, List.of(
    new RewardEntry(RewardType.ENCHANT, "EFFICIENCY", "2"),
    new RewardEntry(RewardType.ENCHANT, "UNBREAKING", "1")
));

RewardProfile rewardProfile = new RewardProfile("my_rewards", rewards);
LevelToolsAPI.registerRewardProfile(rewardProfile);

Display Profile

DisplayProfile displayProfile = DisplayProfile.builder("my_display")
    .nameDisplay(new DisplayProfile.NameDisplay(true, " &7[&bLv{level}&7]"))
    .actionBarDisplay(new DisplayProfile.ActionBarDisplay(true, "&eXP: &b{xp}&7/&b{max_xp} {progress_bar}"))
    .loreDisplay(new DisplayProfile.LoreDisplay(true, List.of(
        "&7Level: &b{level}",
        "&7XP: &b{xp}&7/&b{max_xp}"
    )))
    .progressBar(new ProgressBarConfig(
        "&a", // Filled color
        "&7", // Empty color
        "|",  // Filled char
        "|",  // Empty char
        20    // Length
    ))
    .build();

LevelToolsAPI.registerDisplayProfile(displayProfile);

Item Profile

ItemProfile itemProfile = ItemProfile.builder("farming_hoes")
    .materials(Set.of(
        Material.WOODEN_HOE,
        Material.STONE_HOE,
        Material.IRON_HOE,
        Material.GOLDEN_HOE,
        Material.DIAMOND_HOE,
        Material.NETHERITE_HOE
    ))
    .triggerProfile("my_trigger_profile")  // Reference to trigger profile
    .rewardProfile("my_rewards")           // Reference to reward profile
    .displayProfile("my_display")          // Reference to display profile
    .maxLevel(100)
    .levelXpFormula("100 * {current_level}") // Optional custom formula
    .build();

RegistrationResult result = LevelToolsAPI.registerItemProfile(itemProfile);
if (!result.isSuccess()) {
    getLogger().warning("Registration failed: " + result.getErrorMessage());
}

Registration Order

Register profiles in this order:

  1. Trigger profiles - No dependencies
  2. Reward profiles - No dependencies
  3. Display profiles - No dependencies
  4. Item profiles - Must reference existing trigger, reward, and display profiles

RegistrationResult

All profile registration methods return a RegistrationResult:

RegistrationResult result = LevelToolsAPI.registerItemProfile(profile);

if (result.isSuccess()) {
    getLogger().info("Successfully registered: " + result.getProfileId());
} else {
    getLogger().warning("Failed: " + result.getErrorMessage());
}

Possible error types:

  • Profile already exists
  • Missing referenced profile (trigger, reward, or display)
  • Material already registered to another profile

API Reference

LevelToolsAPI

Static utility class for all API operations.

Plugin Access

LevelToolsPlugin getPlugin()       // Get plugin instance
boolean isEnabled()                // Check if LevelTools is enabled

Trigger Methods

void registerTrigger(Trigger)              // Register a trigger
boolean unregisterTrigger(String)          // Unregister by ID
Trigger getTrigger(String)                 // Get by ID (nullable)
Optional<Trigger> findTrigger(String)      // Get by ID (optional)
boolean hasTrigger(String)                 // Check if exists
Set<String> getRegisteredTriggerIds()      // Get all IDs
Collection<Trigger> getAllTriggers()       // Get all triggers

Profile Registration

RegistrationResult registerTriggerProfile(TriggerProfile)
RegistrationResult registerRewardProfile(RewardProfile)
RegistrationResult registerDisplayProfile(DisplayProfile)
RegistrationResult registerItemProfile(ItemProfile)

boolean unregisterTriggerProfile(String)
boolean unregisterRewardProfile(String)
boolean unregisterDisplayProfile(String)
boolean unregisterItemProfile(String)

Profile Queries

TriggerProfile getTriggerProfile(String)
RewardProfile getRewardProfile(String)
DisplayProfile getDisplayProfile(String)
ItemProfile getItemProfile(String)
ItemProfile getItemProfileForMaterial(Material)

Collection<TriggerProfile> getAllTriggerProfiles()
Collection<RewardProfile> getAllRewardProfiles()
Collection<DisplayProfile> getAllDisplayProfiles()
Collection<ItemProfile> getAllItemProfiles()

Set<String> getTriggerProfileIds()
Set<String> getRewardProfileIds()
Set<String> getDisplayProfileIds()
Set<String> getItemProfileIds()

Events

LevelToolsLoadEvent

Fired during plugin startup and reload.

LevelToolsPlugin getPlugin()           // Get plugin instance
LoadPhase getPhase()                   // Get current phase
TriggerRegistry getTriggerRegistry()   // Direct registry access
ProfileManager getProfileManager()     // Direct manager access

LevelToolsXPIncreaseEvent

Fired when XP is about to be added (cancellable).

Player getPlayer()
ItemStack getItem()
double getNewXp()
void setNewXp(double)
boolean isModified()

LevelToolsLevelIncreaseEvent

Fired when a level-up occurs (cancellable).

Player getPlayer()
ItemStack getItem()
int getNewLevel()
void setNewLevel(int)

Support

For questions or issues with the API, please:

  1. Check the GitHub Issues
  2. Join the Discord Server