### Plugin Installation and Dependencies Source: https://context7.com/nulli0n/excellentenchants-spigot/llms.txt Instructions for installing ExcellentEnchants and its required/optional dependencies. Ensure correct placement in the server's plugins folder and avoid using `/reload` or PlugMan. ```text # Required dependency (must be installed alongside ExcellentEnchants) NightCore: https://nightexpressdev.com/nightcore/ # Optional dependencies for enchantment description tooltips (install one): PacketEvents: https://spigotmc.org/resources/80279/ ProtocolLib: https://ci.dmulloy2.net/job/ProtocolLib/ # Supported server versions and platforms: # MC 1.21.8, 1.21.10, 1.21.11 on Paper or Spigot # Java 21+ # Installation steps: # 1. Stop the server # 2. Drop ExcellentEnchants.jar, NightCore.jar (and optionally PacketEvents/ProtocolLib) into /plugins/ # 3. Start the server # 4. Configure enchantments in /plugins/ExcellentEnchants/enchants/ # NEVER use /reload or PlugMan to load/unload this plugin ``` -------------------------------- ### CustomEnchantment Interface Source: https://context7.com/nulli0n/excellentenchants-spigot/llms.txt The central API interface for enchantments. Provides methods to get enchantment details, check item compatibility, manage charges, and retrieve descriptions. ```APIDOC ## `CustomEnchantment` Interface The central API interface representing any ExcellentEnchants enchantment. All 80+ built-in enchantments implement this interface through `GameEnchantment`. Other plugins can cast a Bukkit `Enchantment` to `CustomEnchantment` after a lookup via `EnchantRegistry`. ```java import su.nightexpress.excellentenchants.api.enchantment.CustomEnchantment; import su.nightexpress.excellentenchants.enchantment.EnchantRegistry; import org.bukkit.NamespacedKey; import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.meta.ItemMeta; // --- Lookup an enchantment --- CustomEnchantment enchant = EnchantRegistry.getById("vampire"); // by config file ID // or NamespacedKey key = new NamespacedKey("excellentenchants", "vampire"); CustomEnchantment enchant2 = EnchantRegistry.getByKey(key); if (enchant == null) return; // not found / not loaded // --- Metadata --- String id = enchant.getId(); // "vampire" String name = enchant.getDisplayName(); // "<#279CF5>Vampire" int maxLevel = enchant.getDefinition().getMaxLevel(); // 3 boolean isCurse = enchant.isCurse(); // false boolean isHidden = enchant.isHiddenFromList(); // false // --- Item-slot compatibility --- enchant.getPrimaryItems(); // ItemSet: items valid for enchanting table enchant.getSupportedItems(); // ItemSet: items valid for anvil / /enchant command // --- Charges API (only relevant when charges system is enabled) --- ItemStack sword = player.getInventory().getItemInMainHand(); int current = enchant.getCharges(sword); // current charge count int max = enchant.getMaxCharges(1); // max charges at level 1 boolean empty = enchant.isOutOfCharges(sword); // true if 0 charges boolean full = enchant.isFullOfCharges(sword); // true if at maximum enchant.setCharges(sword, 1, 100); // set charges to 100 at level 1 enchant.restoreCharges(sword, 1); // restore to max enchant.consumeCharges(sword, 1); // deduct one use enchant.fuelCharges(sword, 1); // add recharge amount from one fuel item // --- Description with level-scaled placeholders resolved --- List desc = enchant.getDescription(2); // e.g., ["16.0% chance to heal for 0.75❤ on hit."] // --- Apply placeholder replacements to a custom string --- UnaryOperator replacer = enchant.replacePlaceholders(3); String resolved = replacer.apply("Trigger: %enchantment_trigger_chance%% "); ``` ``` -------------------------------- ### Probability Component: Multiplier Chance Source: https://context7.com/nulli0n/excellentenchants-spigot/llms.txt Attaches a level-scaled trigger chance using a multiplier model. This example sets a base chance of 5.0, multiplied by 1.5 for each level. ```java import su.nightexpress.excellentenchants.api.enchantment.meta.Probability; import su.nightexpress.excellentenchants.api.enchantment.component.EnchantComponent; // Multiplier-based probability: this.addComponent(EnchantComponent.PROBABILITY, Probability.multiplier(5.0, 1.5)); ``` -------------------------------- ### Charges Component for Enchantment Fuel System Source: https://context7.com/nulli0n/excellentenchants-spigot/llms.txt The Charges component adds a fuel-based usage counter to enchantments. When enabled, each item tracks remaining charges in its PersistentDataContainer. Recharging is done by combining the enchanted item with a fuel item on an anvil, costing 1 XP level per recharged enchantment. This example shows enabling charges globally, per-enchantment configuration, default and custom charge settings, and runtime checks. ```java import su.nightexpress.excellentenchants.api.enchantment.meta.Charges; import su.nightexpress.excellentenchants.api.Modifier; import su.nightexpress.nightcore.util.bukkit.NightItem; import org.bukkit.Material; // ---- Enabling charges globally (config.yml) ---- // Enchantments: // Charges: // Enabled: true // Fuel: // Item: // Material: LAPIS_LAZULI // ---- Per-enchantment config (enchants/vampire.yml) ---- // Settings: // Charges: true ← must be true to activate charges for this enchantment // ---- Default charges in code (100 base, +25 per level; 1 consumed, 25 restored) ---- Charges normal = Charges.normal(); // maxAmount at level 1: 125, level 2: 150, level 3: 175 // consumeAmount: 1 per trigger // rechargeAmount: 25 per fuel item // fuel: LAPIS_LAZULI (from global config) // ---- Custom charges with a specific fuel ---- Charges custom = Charges.custom( Modifier.addictive(50).perLevel(10), // 60 at L1, 70 at L2 … 2, // consume 2 per use 10, // restore 10 per fuel item NightItem.fromType(Material.GLOWSTONE_DUST) ); // ---- Runtime checks ---- CustomEnchantment enchant = EnchantRegistry.getById("vampire"); ItemStack sword = player.getInventory().getItemInMainHand(); System.out.println("Charges left : " + enchant.getCharges(sword)); System.out.println("Max at level 2: " + enchant.getMaxCharges(2)); System.out.println("Out of charges: " + enchant.isOutOfCharges(sword)); // Manually manipulate charges enchant.setCharges(sword, 2, 50); // set to 50 at level 2 enchant.restoreCharges(sword, 2); // fill to max enchant.consumeCharges(sword, 2); // deduct consumeAmount enchant.fuelCharges(sword, 2); // add rechargeAmount (as if using one fuel in anvil) // Check whether an item qualifies as a valid fuel for this enchantment ItemStack lapis = new ItemStack(Material.LAPIS_LAZULI); boolean isFuel = enchant.isChargesFuel(lapis); // true (matches global default) // Per-enchant charges YAML (auto-generated if Charges: true in Settings): // Charges: // Max_Amount: // Base: 100 // Per_Level: 25 // Capacity: -1 // Action: ADD // Consume_Amount: 1 // Recharge_Amount: 25 // CustomFuel: // Enabled: false // Item: // Material: LAPIS_LAZULI ``` -------------------------------- ### PotionEffects Component for Applying Potion Effects Source: https://context7.com/nulli0n/excellentenchants-spigot/llms.txt The PotionEffects component simplifies enchantments that apply a potion effect to a target. The effect type, amplifier, and duration all scale via Modifier. This example shows how to configure Poison effect with duration and amplifier scaling. ```java import su.nightexpress.excellentenchants.api.enchantment.meta.PotionEffects; import su.nightexpress.excellentenchants.api.enchantment.component.EnchantComponent; import org.bukkit.potion.PotionEffectType; // In constructor: apply Poison that lasts 3s base, +1s per level, amplifier = level - 1 this.addComponent(EnchantComponent.POTION_EFFECT, new PotionEffects( PotionEffectType.POISON, Modifier.addictive(3).perLevel(1).build(), // duration in seconds Modifier.addictive(0).perLevel(1).build() // amplifier (0-based) ) ); // In the trigger method — apply effect to victim: PotionEffects effects = this.getComponent(EnchantComponent.POTION_EFFECT); effects.addEffect(victim, level, true); // true = show particles // YAML section auto-generated by the component: // PotionEffect: // Type: POISON // Duration: // Base: 3.0 // Per_Level: 1.0 // Capacity: -1 // Action: ADD // Amplifier: // Base: 0.0 // Per_Level: 1.0 // Capacity: -1 // Action: ADD ``` -------------------------------- ### Probability Component: Addictive Chance Source: https://context7.com/nulli0n/excellentenchants-spigot/llms.txt Attaches a level-scaled trigger chance to an enchantment using an additive model. This example registers an 8% base chance, increasing by 4% per level, capped at 100%. ```java import su.nightexpress.excellentenchants.api.enchantment.meta.Probability; import su.nightexpress.excellentenchants.api.enchantment.component.EnchantComponent; // In constructor: register probability (8% base, +4% per level, capped 100%) this.addComponent(EnchantComponent.PROBABILITY, Probability.addictive(8.0, 4.0)); // Level 1: 12%, Level 2: 16%, ..., Level 23+: 100% ``` -------------------------------- ### Main Configuration (config.yml) Source: https://context7.com/nulli0n/excellentenchants-spigot/llms.txt Configuration options for enabling the tooltip module and the charges system globally. The charges system requires a master switch and can be configured with default fuel items. ```yaml # plugins/ExcellentEnchants/config.yml Modules: # Requires PacketEvents or ProtocolLib to be installed EnchantTooltip: true Enchantments: Charges: Enabled: false # Master switch; must be true before per-enchant charges work Fuel: Ignore_Meta: false # If true, ignores item meta when checking fuel match Item: Material: LAPIS_LAZULI # Default fuel item for all chargeable enchants ``` -------------------------------- ### Tooltip System Integration Source: https://context7.com/nulli0n/excellentenchants-spigot/llms.txt This section details how to integrate with the ExcellentEnchants tooltip system to dynamically display enchantment descriptions in item lore. It shows how to access the TooltipController and use its methods to add descriptions to items and manage tooltip updates for players. ```APIDOC ## Tooltip System Integration When PacketEvents or ProtocolLib is installed and `Modules.EnchantTooltip: true` in `config.yml`, the plugin intercepts outgoing inventory packets and injects enchantment descriptions into item lore dynamically — without writing to the item data permanently. ```java import su.nightexpress.excellentenchants.api.tooltip.TooltipController; // Access the controller through the plugin instance TooltipController tooltip = EnchantsAPI.getPlugin().getTooltipController(); if (tooltip != null && tooltip.hasHandler()) { // Manually add enchant description lore to a copy of an item (non-destructive) ItemStack withDesc = tooltip.addDescription(originalItem); // Stop tooltip updates for a player during a custom inventory operation tooltip.addToUpdateStopList(player); // ... perform inventory actions ... tooltip.removeFromUpdateStopList(player); // Or use the convenience wrapper: tooltip.runInStopList(player, () -> { player.getInventory().setItem(9, someItem); }); } // The tooltip system respects ItemFlag.HIDE_ENCHANTS — items with that flag // will NOT receive injected description lines. ``` ``` -------------------------------- ### Plugin Commands Source: https://context7.com/nulli0n/excellentenchants-spigot/llms.txt List of available commands for managing enchantments, including help, reloading configs, giving enchanted books, and applying/removing enchantments. Permissions are required for most commands. ```text # Syntax: [] = optional, <> = required /excellentenchants [help] # Displays the full command list /excellentenchants reload # Reloads all plugin and enchantment configs without restarting # Permission: excellentenchants.command.reload /excellentenchants book # Gives an enchanted book to a player # Use -1 for level to randomize # Example: /eenchants book Steve vampire 2 # Permission: excellentenchants.command.book /excellentenchants tierbook # Gives a book with a random enchantment of the specified tier # Use -1 for level to randomize # Permission: excellentenchants.command.tierbook /excellentenchants enchant [player] [slot] # (Dis)Enchants the held/target item # Use 0 to remove the enchantment, -1 for random level # Example: /eenchants enchant thunder 3 Steve HAND # Permission: excellentenchants.command.enchant /excellentenchants list # Opens a GUI showing all registered enchantments and their descriptions # Permission: excellentenchants.command.list ``` -------------------------------- ### EnchantsAPI: Access Plugin and Manager Source: https://context7.com/nulli0n/excellentenchants-spigot/llms.txt Serves as the main entry point to the ExcellentEnchants plugin, allowing access to the plugin instance and the EnchantManager for advanced integrations. ```java import su.nightexpress.excellentenchants.EnchantsAPI; import su.nightexpress.excellentenchants.manager.EnchantManager; // Access the plugin instance (throws IllegalStateException if not loaded) EnchantsPlugin plugin = EnchantsAPI.getPlugin(); // Access the central enchantment manager EnchantManager manager = EnchantsAPI.getEnchantManager(); // Check enchantments on an item ItemStack item = player.getInventory().getItemInMainHand(); Map enchants = EnchantsUtils.getCustomEnchantments(item); enchants.forEach((enchant, level) -> { System.out.printf("%s level %d%n", enchant.getDisplayName(), level); }); ``` -------------------------------- ### Tooltip System Integration with PacketEvents/ProtocolLib Source: https://context7.com/nulli0n/excellentenchants-spigot/llms.txt Integrates with PacketEvents or ProtocolLib to dynamically inject enchantment descriptions into item lore without permanent modification. Use this to display enchantments in a player's inventory. Ensure 'Modules.EnchantTooltip: true' is set in config.yml. ```java import su.nightexpress.excellentenchants.api.tooltip.TooltipController; // Access the controller through the plugin instance TooltipController tooltip = EnchantsAPI.getPlugin().getTooltipController(); if (tooltip != null && tooltip.hasHandler()) { // Manually add enchant description lore to a copy of an item (non-destructive) ItemStack withDesc = tooltip.addDescription(originalItem); // Stop tooltip updates for a player during a custom inventory operation tooltip.addToUpdateStopList(player); // ... perform inventory actions ... tooltip.removeFromUpdateStopList(player); // Or use the convenience wrapper: tooltip.runInStopList(player, () -> { player.getInventory().setItem(9, someItem); }); } // The tooltip system respects ItemFlag.HIDE_ENCHANTS — items with that flag // will NOT receive injected description lines. ``` -------------------------------- ### Implementing DefendEnchant Interface Source: https://context7.com/nulli0n/excellentenchants-spigot/llms.txt Implement the DefendEnchant interface for enchantments that trigger when the holder takes damage. The onDefend method allows modification of incoming damage. ```java import su.nightexpress.excellentenchants.api.enchantment.type.*; import su.nightexpress.excellentenchants.api.EnchantPriority; import org.bukkit.entity.LivingEntity; import org.bukkit.event.entity.EntityDamageByEntityEvent; import org.bukkit.inventory.ItemStack; // --- DefendEnchant: fires on EntityDamageByEntityEvent when the holder takes damage --- public class MyDefendEnchant extends GameEnchantment implements DefendEnchant { @Override public boolean onDefend(EntityDamageByEntityEvent event, LivingEntity damager, LivingEntity victim, ItemStack armor, int level) { event.setDamage(event.getDamage() * 0.9); // 10% damage reduction return true; } @Override public EnchantPriority getProtectPriority() { return EnchantPriority.HIGH; } } ``` -------------------------------- ### Lookup and Use CustomEnchantment API Source: https://context7.com/nulli0n/excellentenchants-spigot/llms.txt Demonstrates how to find enchantments by ID or key, access their properties, check item compatibility, manage charges, and retrieve descriptions or apply placeholder replacements. ```java import su.nightexpress.excellentenchants.api.enchantment.CustomEnchantment; import su.nightexpress.excellentenchants.enchantment.EnchantRegistry; import org.bukkit.NamespacedKey; import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.meta.ItemMeta; // --- Lookup an enchantment --- CustomEnchantment enchant = EnchantRegistry.getById("vampire"); // by config file ID // or NamespacedKey key = new NamespacedKey("excellentenchants", "vampire"); CustomEnchantment enchant2 = EnchantRegistry.getByKey(key); if (enchant == null) return; // not found / not loaded // --- Metadata --- String id = enchant.getId(); // "vampire" String name = enchant.getDisplayName(); // "<#279CF5>Vampire" int maxLevel = enchant.getDefinition().getMaxLevel(); // 3 boolean isCurse = enchant.isCurse(); // false boolean isHidden = enchant.isHiddenFromList(); // false // --- Item-slot compatibility --- enchant.getPrimaryItems(); // ItemSet: items valid for enchanting table enchant.getSupportedItems(); // ItemSet: items valid for anvil / /enchant command // --- Charges API (only relevant when charges system is enabled) --- ItemStack sword = player.getInventory().getItemInMainHand(); int current = enchant.getCharges(sword); // current charge count int max = enchant.getMaxCharges(1); // max charges at level 1 boolean empty = enchant.isOutOfCharges(sword); // true if 0 charges boolean full = enchant.isFullOfCharges(sword); // true if at maximum enchant.setCharges(sword, 1, 100); // set charges to 100 at level 1 enchant.restoreCharges(sword, 1); // restore to max enchant.consumeCharges(sword, 1); // deduct one use enchant.fuelCharges(sword, 1); // add recharge amount from one fuel item // --- Description with level-scaled placeholders resolved --- List desc = enchant.getDescription(2); // e.g., ["16.0% chance to heal for 0.75❤ on hit."] // --- Apply placeholder replacements to a custom string --- UnaryOperator replacer = enchant.replacePlaceholders(3); String resolved = replacer.apply("Trigger: %enchantment_trigger_chance%% "); ``` -------------------------------- ### Implementing BowEnchant Interface Source: https://context7.com/nulli0n/excellentenchants-spigot/llms.txt Implement the BowEnchant interface for enchantments that trigger when a bow is shot. The onShoot method allows modification of the projectile's velocity. ```java import su.nightexpress.excellentenchants.api.enchantment.type.*; import su.nightexpress.excellentenchants.api.EnchantPriority; import org.bukkit.entity.LivingEntity; import org.bukkit.event.entity.EntityShootBowEvent; import org.bukkit.inventory.ItemStack; // --- BowEnchant: fires on EntityShootBowEvent --- public class MyBowEnchant extends GameEnchantment implements BowEnchant { @Override public boolean onShoot(EntityShootBowEvent event, LivingEntity shooter, ItemStack bow, int level) { event.getProjectile().setVelocity( event.getProjectile().getVelocity().multiply(1.0 + level * 0.25)); return true; } @Override public EnchantPriority getShootPriority() { return EnchantPriority.NORMAL; } } ``` -------------------------------- ### Implement Custom Attack Enchantment in Java Source: https://context7.com/nulli0n/excellentenchants-spigot/llms.txt This Java code demonstrates a minimal implementation of a custom attack enchantment. It extends `GameEnchantment`, implements `AttackEnchant`, and defines custom logic for damage modification and visual effects. Configuration values like drain amount and probability are loaded from YAML. ```java package com.example.myenchants; import org.bukkit.Particle; import org.bukkit.entity.LivingEntity; import org.bukkit.event.entity.EntityDamageByEntityEvent; import org.bukkit.inventory.ItemStack; import org.jetbrains.annotations.NotNull; import su.nightexpress.excellentenchants.EnchantsPlaceholders; import su.nightexpress.excellentenchants.EnchantsPlugin; import su.nightexpress.excellentenchants.api.EnchantPriority; import su.nightexpress.excellentenchants.api.Modifier; import su.nightexpress.excellentenchants.api.enchantment.component.EnchantComponent; import su.nightexpress.excellentenchants.api.enchantment.meta.Probability; import su.nightexpress.excellentenchants.api.enchantment.type.AttackEnchant; import su.nightexpress.excellentenchants.enchantment.EnchantContext; import su.nightexpress.excellentenchants.enchantment.GameEnchantment; import su.nightexpress.excellentenchants.manager.EnchantManager; import su.nightexpress.nightcore.config.ConfigValue; import su.nightexpress.nightcore.config.FileConfig; import su.nightexpress.nightcore.util.NumberUtil; import su.nightexpress.nightcore.util.wrapper.UniParticle; import java.nio.file.Path; public class SoulDrainEnchant extends GameEnchantment implements AttackEnchant { private Modifier drainAmount; public SoulDrainEnchant(@NotNull EnchantsPlugin plugin, @NotNull EnchantManager manager, @NotNull Path file, @NotNull EnchantContext context) { super(plugin, manager, file, context); // 10% base chance, +5% per level, capped at 100% this.addComponent(EnchantComponent.PROBABILITY, Probability.addictive(10, 5)); } @Override protected void loadAdditional(@NotNull FileConfig config) { // Load scaling drain amount from YAML; default: 2.0 base, +0.5 per level, cap 10.0 this.drainAmount = Modifier.load(config, "SoulDrain.Amount", Modifier.addictive(2.0).perLevel(0.5).capacity(10.0), "Damage dealt to victim's max health per use."); // Register %generic_amount% placeholder used in Description this.addPlaceholder(EnchantsPlaceholders.GENERIC_AMOUNT, level -> NumberUtil.format(this.drainAmount.getValue(level))); } @Override public boolean onAttack(@NotNull EntityDamageByEntityEvent event, @NotNull LivingEntity damager, @NotNull LivingEntity victim, @NotNull ItemStack weapon, int level) { double drain = this.drainAmount.getValue(level); double newDmg = event.getDamage() + drain; event.setDamage(newDmg); if (this.hasVisualEffects()) { UniParticle.of(Particle.SOUL).play(victim.getLocation(), 0.3, 0.5, 8); } return true; // true → charges consumed (if enabled) } @Override public @NotNull EnchantPriority getAttackPriority() { return EnchantPriority.NORMAL; } } ``` ```yaml Definition: DisplayName: "<#279CF5>Soul Drain" Description: - "%enchantment_trigger_chance%% chance to deal +%generic_amount% bonus damage." Weight: 3 MaxLevel: 4 SupportedItems: swords_axes PrimaryItems: sword Exclusives: [] Distribution: Treasure: false Tradeable: true Discoverable: true On_Mob_Spawn_Equipment: true On_Random_Loot: true Probability: Trigger_Chance: Base: 10.0 Per_Level: 5.0 Capacity: 100.0 Action: ADD SoulDrain: Amount: Base: 2.0 Per_Level: 0.5 Capacity: 10.0 Action: ADD ``` -------------------------------- ### EnchantsAPI Source: https://context7.com/nulli0n/excellentenchants-spigot/llms.txt The plugin-level API entry point. Use this to obtain the EnchantManager for advanced integration and access plugin information. ```APIDOC ## `EnchantsAPI` The plugin-level API entry point. Use this to obtain the `EnchantManager` for advanced integration. ```java import su.nightexpress.excellentenchants.EnchantsAPI; import su.nightexpress.excellentenchants.manager.EnchantManager; // Access the plugin instance (throws IllegalStateException if not loaded) EnchantsPlugin plugin = EnchantsAPI.getPlugin(); // Access the central enchantment manager EnchantManager manager = EnchantsAPI.getEnchantManager(); // Check enchantments on an item ItemStack item = player.getInventory().getItemInMainHand(); Map enchants = EnchantsUtils.getCustomEnchantments(item); enchants.forEach((enchant, level) -> { System.out.printf("%s level %d%n", enchant.getDisplayName(), level); }); ``` ``` -------------------------------- ### Implementing AttackEnchant Interface Source: https://context7.com/nulli0n/excellentenchants-spigot/llms.txt Implement the AttackEnchant interface for enchantments that trigger when the holder deals damage. The onAttack method should return true if the effect fires successfully. ```java import su.nightexpress.excellentenchants.api.enchantment.type.*; import su.nightexpress.excellentenchants.api.EnchantPriority; import org.bukkit.entity.LivingEntity; import org.bukkit.event.entity.EntityDamageByEntityEvent; import org.bukkit.inventory.ItemStack; // --- AttackEnchant: fires on EntityDamageByEntityEvent when the holder deals damage --- public class MyAttackEnchant extends GameEnchantment implements AttackEnchant { @Override public boolean onAttack(EntityDamageByEntityEvent event, LivingEntity damager, LivingEntity victim, ItemStack weapon, int level) { victim.setFireTicks(level * 40); // ignite for 2s per level return true; // return true = charges consumed, effect fired } @Override public EnchantPriority getAttackPriority() { return EnchantPriority.NORMAL; } } ``` -------------------------------- ### Configure Enchantment Distribution with EnchantDistribution Source: https://context7.com/nulli0n/excellentenchants-spigot/llms.txt Use EnchantDistribution to control where enchantments appear: enchanting tables, loot chests, villager trades, or mob equipment. Choose between regular distribution (discoverable, tradable, mob/loot) or treasure distribution (loot chests/fishing/trading only). ```java import su.nightexpress.excellentenchants.api.EnchantDistribution; import su.nightexpress.excellentenchants.api.wrapper.TradeType; // Standard distribution — appears everywhere, sold by specific villager biome types EnchantDistribution regular = EnchantDistribution.regular( TradeType.PLAINS_COMMON, TradeType.SAVANNA_COMMON ); // regular.isTreasure() → false // regular.isDiscoverable() → true (enchanting table) // regular.isTradable() → true (villager trades) // regular.isOnMobSpawnEquipment()→ true (mob gear) // regular.isOnRandomLoot() → true (loot chests) // Treasure distribution — only from loot chests/fishing/trading, not enchanting table EnchantDistribution treasure = EnchantDistribution.treasure( TradeType.DESERT_SPECIAL ); // treasure.isTreasure() → true // treasure.isDiscoverable() → false // treasure.isOnMobSpawnEquipment()→ false // Available TradeType values (village biome zones): // PLAINS_COMMON, PLAINS_SPECIAL // DESERT_COMMON, DESERT_SPECIAL // SAVANNA_COMMON, SAVANNA_SPECIAL // SNOW_COMMON, SNOW_SPECIAL // JUNGLE_COMMON, JUNGLE_SPECIAL // SWAMP_COMMON, SWAMP_SPECIAL // TAIGA_COMMON, TAIGA_SPECIAL // Read distribution flags at runtime EnchantDistribution dist = enchant.getDistribution(); System.out.println("Discoverable: " + dist.isDiscoverable()); System.out.println("Tradable in: " + dist.getTrades()); // Set ``` -------------------------------- ### Build EnchantDefinition with Builder Pattern Source: https://context7.com/nulli0n/excellentenchants-spigot/llms.txt Use EnchantDefinition.builder() to create immutable enchantment metadata. Configure name, max level, description, rarity weight, item compatibility, and costs. Access properties like getDisplayName() and getMaxLevel() at runtime. ```java import su.nightexpress.excellentenchants.api.EnchantDefinition; import su.nightexpress.excellentenchants.api.item.ItemSetDefaults; import org.bukkit.NamespacedKey; // Build a definition for a custom enchantment EnchantDefinition definition = EnchantDefinition.builder("Soul Rend", 4) .description( "%enchantment_trigger_chance%% chance to drain %generic_amount% souls on hit.", "Souls restore %generic_amount% health." ) .weight(3) // rare: 1=very rare … 10=common .primaryItems(ItemSetDefaults.SWORD) // appears in enchanting table for swords .supportedItems(ItemSetDefaults.SWORDS_AXES) // anvil/command works on swords & axes .anvilCost(4) .build(); // Access at runtime System.out.println(definition.getDisplayName()); // "<#279CF5>Soul Rend" System.out.println(definition.getMaxLevel()); // 4 System.out.println(definition.getWeight()); // 3 System.out.println(definition.getSupportedItemSet().getId()); // "swords_axes" ``` ```java // Conflicts: prevent combining with Sharpness and Smite EnchantDefinition withConflicts = EnchantDefinition.builder("Soul Rend", 4) .supportedItems(ItemSetDefaults.SWORDS_AXES) .exclusives( new NamespacedKey("minecraft", "sharpness"), new NamespacedKey("minecraft", "smite") ) .build(); ``` -------------------------------- ### Implementing MiningEnchant Interface Source: https://context7.com/nulli0n/excellentenchants-spigot/llms.txt Implement the MiningEnchant interface for enchantments that trigger when a block is broken. The onBreak method is called with block break event details. ```java import su.nightexpress.excellentenchants.api.enchantment.type.*; import su.nightexpress.excellentenchants.api.EnchantPriority; import org.bukkit.entity.LivingEntity; import org.bukkit.event.block.BlockBreakEvent; import org.bukkit.inventory.ItemStack; // --- MiningEnchant: fires on BlockBreakEvent --- public class MyMiningEnchant extends GameEnchantment implements MiningEnchant { @Override public boolean onBreak(BlockBreakEvent event, LivingEntity player, ItemStack tool, int level) { player.giveExp(level * 5); return true; } @Override public EnchantPriority getBreakPriority() { return EnchantPriority.LOW; } } ``` -------------------------------- ### EnchantDefinition Builder Source: https://context7.com/nulli0n/excellentenchants-spigot/llms.txt Defines the static metadata for an enchantment, including its name, description, rarity, max level, costs, and compatibility. ```APIDOC ## EnchantDefinition and the Builder Pattern `EnchantDefinition` captures the static metadata of an enchantment: name, description, rarity weight, max level, enchanting-table costs, anvil cost, compatible item sets, and exclusive conflicts. It is built once and is immutable at runtime. ```java import su.nightexpress.excellentenchants.api.EnchantDefinition; import su.nightexpress.excellentenchants.api.item.ItemSetDefaults; import org.bukkit.NamespacedKey; // Build a definition for a custom enchantment EnchantDefinition definition = EnchantDefinition.builder("Soul Rend", 4) .description( "%enchantment_trigger_chance%% chance to drain %generic_amount% souls on hit.", "Souls restore %generic_amount% health." ) .weight(3) // rare: 1=very rare … 10=common .primaryItems(ItemSetDefaults.SWORD) // appears in enchanting table for swords .supportedItems(ItemSetDefaults.SWORDS_AXES) // anvil/command works on swords & axes .anvilCost(4) .build(); // Access at runtime System.out.println(definition.getDisplayName()); // "<#279CF5>Soul Rend" System.out.println(definition.getMaxLevel()); // 4 System.out.println(definition.getWeight()); // 3 System.out.println(definition.getSupportedItemSet().getId()); // "swords_axes" // Conflicts: prevent combining with Sharpness and Smite EnchantDefinition withConflicts = EnchantDefinition.builder("Soul Rend", 4) .supportedItems(ItemSetDefaults.SWORDS_AXES) .exclusives( new NamespacedKey("minecraft", "sharpness"), new NamespacedKey("minecraft", "smite") ) .build(); ``` ``` -------------------------------- ### EnchantRegistry: Lookup and Filter Enchantments Source: https://context7.com/nulli0n/excellentenchants-spigot/llms.txt Provides methods to find enchantments by their string ID or NamespacedKey, retrieve all registered enchantments, or filter them by specific types like AttackEnchant. ```java import su.nightexpress.excellentenchants.enchantment.EnchantRegistry; import su.nightexpress.excellentenchants.api.enchantment.CustomEnchantment; import su.nightexpress.excellentenchants.api.enchantment.type.AttackEnchant; // --- Lookup by string ID (matches config filename without extension) --- CustomEnchantment vampire = EnchantRegistry.getById("vampire"); // --- Lookup by NamespacedKey --- NamespacedKey key = new NamespacedKey("excellentenchants", "thunder"); CustomEnchantment thunder = EnchantRegistry.getByKey(key); // --- Get all registered enchantments --- Set all = EnchantRegistry.getRegistered(); System.out.println("Loaded enchantments: " + all.size()); // ~80+ // --- Filter to a specific category (typed holders) --- // Each holder exposes a Set of enchants of that type: EnchantRegistry.ATTACK.getEnchants().forEach(atk -> { System.out.println("Attack enchant: " + atk.getId() + " priority=" + atk.getAttackPriority()); }); // Available typed holders: // EnchantRegistry.ATTACK → Set // EnchantRegistry.DEFEND → Set // EnchantRegistry.MINING → Set // EnchantRegistry.BOW → Set // EnchartRegistry.PASSIVE → Set // ... (ARROW, TRIDENT, FISHING, DEATH, KILL, INTERACT, etc.) ``` -------------------------------- ### Probability Component: Manual Check (Rarely Needed) Source: https://context7.com/nulli0n/excellentenchants-spigot/llms.txt Demonstrates how to manually test the trigger chance for an enchantment level. This is typically handled automatically by the enchantment manager. ```java import su.nightexpress.excellentenchants.api.enchantment.meta.Probability; import su.nightexpress.excellentenchants.api.enchantment.component.EnchantComponent; // Manual check (rarely needed; the manager handles this automatically): boolean fires = enchant.testTriggerChance(level); ``` -------------------------------- ### EnchantRegistry Source: https://context7.com/nulli0n/excellentenchants-spigot/llms.txt Static registry for all loaded enchantments. Used for looking up, enumerating, and filtering enchantments at runtime. ```APIDOC ## `EnchantRegistry` The static registry for all loaded enchantments. Use it to look up, enumerate, and filter enchantments at runtime. ```java import su.nightexpress.excellentenchants.enchantment.EnchantRegistry; import su.nightexpress.excellentenchants.api.enchantment.CustomEnchantment; import su.nightexpress.excellentenchants.api.enchantment.type.AttackEnchant; // --- Lookup by string ID (matches config filename without extension) --- CustomEnchantment vampire = EnchantRegistry.getById("vampire"); // --- Lookup by NamespacedKey --- NamespacedKey key = new NamespacedKey("excellentenchants", "thunder"); CustomEnchantment thunder = EnchantRegistry.getByKey(key); // --- Get all registered enchantments --- Set all = EnchantRegistry.getRegistered(); System.out.println("Loaded enchantments: " + all.size()); // ~80+ // --- Filter to a specific category (typed holders) --- // Each holder exposes a Set of enchants of that type: EnchantRegistry.ATTACK.getEnchants().forEach(atk -> { System.out.println("Attack enchant: " + atk.getId() + " priority=" + atk.getAttackPriority()); }); // Available typed holders: // EnchantRegistry.ATTACK → Set // EnchantRegistry.DEFEND → Set // EnchantRegistry.MINING → Set // EnchantRegistry.BOW → Set // EnchartRegistry.PASSIVE → Set // ... (ARROW, TRIDENT, FISHING, DEATH, KILL, INTERACT, etc.) ``` ``` -------------------------------- ### Permission Nodes Source: https://context7.com/nulli0n/excellentenchants-spigot/llms.txt Defines the permission nodes for ExcellentEnchants, granting access to all plugin functionality, specific commands, and sub-commands. ```yaml excellentenchants.* excellentenchants.command.* excellentenchants.command.book excellentenchants.command.enchant excellentenchants.command.list excellentenchants.command.tierbook excellentenchants.command.reload ``` -------------------------------- ### Implementing PassiveEnchant Interface Source: https://context7.com/nulli0n/excellentenchants-spigot/llms.txt Implement the PassiveEnchant interface for enchantments that trigger periodically. The onTrigger method is called on a timed interval, controlled by a Period component. ```java import su.nightexpress.excellentenchants.api.enchantment.type.*; import org.bukkit.entity.LivingEntity; import org.bukkit.inventory.ItemStack; import org.bukkit.potion.PotionEffect; import org.bukkit.potion.PotionEffectType; // --- PassiveEnchant: fires on a periodic tick (controlled by Period component) --- public class MyPassiveEnchant extends GameEnchantment implements PassiveEnchant { @Override public boolean onTrigger(LivingEntity entity, ItemStack item, int level) { entity.addPotionEffect(new PotionEffect( PotionEffectType.SPEED, 60, level - 1, true, false)); return true; } // No priority method needed for PassiveEnchant } ``` -------------------------------- ### Probability Component: Fixed 100% Chance Source: https://context7.com/nulli0n/excellentenchants-spigot/llms.txt Configures an enchantment to always trigger by setting a fixed 100% probability. This is useful for enchantments that should not have a chance-based activation. ```java import su.nightexpress.excellentenchants.api.enchantment.meta.Probability; import su.nightexpress.excellentenchants.api.enchantment.component.EnchantComponent; // Fixed 100% chance (always fires): this.addComponent(EnchantComponent.PROBABILITY, Probability.oneHundred()); ``` -------------------------------- ### EnchantDistribution Source: https://context7.com/nulli0n/excellentenchants-spigot/llms.txt Controls the distribution of an enchantment across various in-game sources like enchanting tables, loot chests, villager trades, and mob equipment. ```APIDOC ## `EnchantDistribution` Controls where and how an enchantment is distributed in the game world: enchanting tables, loot chests, villager trades, and mob equipment. ```java import su.nightexpress.excellentenchants.api.EnchantDistribution; import su.nightexpress.excellentenchants.api.wrapper.TradeType; // Standard distribution — appears everywhere, sold by specific villager biome types EnchantDistribution regular = EnchantDistribution.regular( TradeType.PLAINS_COMMON, TradeType.SAVANNA_COMMON ); // regular.isTreasure() → false // regular.isDiscoverable() → true (enchanting table) // regular.isTradable() → true (villager trades) // regular.isOnMobSpawnEquipment()→ true (mob gear) // regular.isOnRandomLoot() → true (loot chests) // Treasure distribution — only from loot chests/fishing/trading, not enchanting table EnchantDistribution treasure = EnchantDistribution.treasure( TradeType.DESERT_SPECIAL ); // treasure.isTreasure() → true // treasure.isDiscoverable() → false // treasure.isOnMobSpawnEquipment()→ false // Available TradeType values (village biome zones): // PLAINS_COMMON, PLAINS_SPECIAL // DESERT_COMMON, DESERT_SPECIAL // SAVANNA_COMMON, SAVANNA_SPECIAL // SNOW_COMMON, SNOW_SPECIAL // JUNGLE_COMMON, JUNGLE_SPECIAL // SWAMP_COMMON, SWAMP_SPECIAL // TAIGA_COMMON, TAIGA_SPECIAL // Read distribution flags at runtime EnchantDistribution dist = enchant.getDistribution(); System.out.println("Discoverable: " + dist.isDiscoverable()); System.out.println("Tradable in: " + dist.getTrades()); // Set ``` ``` -------------------------------- ### Create Level-Scaling Values with Modifier Source: https://context7.com/nulli0n/excellentenchants-spigot/llms.txt Use Modifier to define numeric enchantment values that scale with level. Supports additive and multiplicative actions, with optional caps. Values can be loaded from YAML configurations. ```java import su.nightexpress.excellentenchants.api.Modifier; import su.nightexpress.excellentenchants.api.ModifierAction; // ADD action: result = base + (perLevel * level), capped at capacity Modifier healAmount = Modifier.addictive(0.25) // base .perLevel(0.25) // +0.25 per level .capacity(10.0) // never exceeds 10.0 .build(); System.out.println(healAmount.getValue(1)); // 0.5 (0.25 + 0.25*1) System.out.println(healAmount.getValue(3)); // 1.0 (0.25 + 0.25*3) System.out.println(healAmount.getValue(40)); // 10.0 (capped) ``` ```java // MULTIPLY action: result = base * (perLevel * level) Modifier damageMultiplier = Modifier.multiplier(1.0) .perLevel(0.1) .capacity(2.0) .build(); System.out.println(damageMultiplier.getValue(5)); // 1.0 * (0.1 * 5) = 0.5 (not intuitive; use ADD for most cases) ``` ```java // Load from a YAML config section (used inside GameEnchantment.loadAdditional) // YAML: // MyEnchant.HealAmount: // Base: 0.25 // Per_Level: 0.25 // Capacity: 10.0 // Action: ADD Modifier loaded = Modifier.load(config, "MyEnchant.HealAmount", Modifier.addictive(0.25).perLevel(0.25).capacity(10.0), "Amount of health restored per hit."); int intVal = loaded.getIntValue(2); // 1 (truncated double) ``` -------------------------------- ### Disable Custom Enchantments in config.yml Source: https://github.com/nulli0n/excellentenchants-spigot/wiki/FAQ To disable custom enchantments, list their file names (without extension) in the `Enchantments.Disabled` section of your `config.yml`. Changes require a server restart. ```yaml Enchantments: # List of disabled custom enchantments. # Use enchantment file names from the 'enchants' folder without the file extension. # For example, to disable 'Explosive Arrows' enchantment you have to add 'explosive_arrows' to this list. Disabled: - enchant_name - other_enchant ``` -------------------------------- ### Period Component for Timed Enchantments Source: https://context7.com/nulli0n/excellentenchants-spigot/llms.txt Use the Period component to restrict passive enchantments to fire at a fixed tick interval. This avoids per-tick spam and is used exclusively with PassiveEnchant implementations. The interval is specified in seconds. ```java import su.nightexpress.excellentenchants.api.enchantment.meta.Period; import su.nightexpress.excellentenchants.api.enchantment.component.EnchantComponent; // In constructor: fire every 5 seconds (100 ticks) this.addComponent(EnchantComponent.PERIODIC, new Period(5L)); // interval in seconds // The YAML section generated: // Period: // Interval: 5 // Manual trigger-time check (performed automatically by the manager): boolean isTime = enchant.isTriggerTime(entity); // True when: (int)(entity.getTicksLived() / 20) % interval == 0 ```