-
Notifications
You must be signed in to change notification settings - Fork 7
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.
LevelTools provides a developer API for external plugins to:
- Register custom triggers - Define new ways for tools to gain XP
- Register profiles at runtime - Add trigger, reward, display, and item profiles programmatically
- Hook into lifecycle events - Know when LevelTools is ready for registration
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());
}
}
}Add LevelTools as a dependency or soft-dependency:
# Required dependency
depend: [LevelTools]
# Or optional dependency
softdepend: [LevelTools]<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>repositories {
maven { url 'https://jitpack.io' }
}
dependencies {
compileOnly 'com.github.byteful:LevelTools:VERSION'
}LevelTools fires LevelToolsLoadEvent at various lifecycle 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 |
- 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
Triggers define how a tool gains XP. LevelTools includes built-in triggers for common actions, but you can add your own.
| 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 |
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());
}
}// Make sure LevelTools is enabled!
LevelToolsAPI.registerTrigger(new CropHarvestTrigger());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();Profiles define what happens when tools are used. There are 4 types of profiles:
| 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 |
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);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);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);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());
}Register profiles in this order:
- Trigger profiles - No dependencies
- Reward profiles - No dependencies
- Display profiles - No dependencies
- Item profiles - Must reference existing trigger, reward, and display profiles
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
Static utility class for all API operations.
LevelToolsPlugin getPlugin() // Get plugin instance
boolean isEnabled() // Check if LevelTools is enabledvoid 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 triggersRegistrationResult registerTriggerProfile(TriggerProfile)
RegistrationResult registerRewardProfile(RewardProfile)
RegistrationResult registerDisplayProfile(DisplayProfile)
RegistrationResult registerItemProfile(ItemProfile)
boolean unregisterTriggerProfile(String)
boolean unregisterRewardProfile(String)
boolean unregisterDisplayProfile(String)
boolean unregisterItemProfile(String)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()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 accessFired when XP is about to be added (cancellable).
Player getPlayer()
ItemStack getItem()
double getNewXp()
void setNewXp(double)
boolean isModified()Fired when a level-up occurs (cancellable).
Player getPlayer()
ItemStack getItem()
int getNewLevel()
void setNewLevel(int)For questions or issues with the API, please:
- Check the GitHub Issues
- Join the Discord Server