From c4c324aa1935d0a921ca66b3d1d9c7ac5175f3ec Mon Sep 17 00:00:00 2001 From: Illyrius Date: Fri, 14 Nov 2025 10:46:00 +0100 Subject: [PATCH 1/6] init Signed-off-by: Illyrius --- .../vanillaplus/VanillaPlusBootstrap.kt | 19 +++++++++++--- .../enchantments/NightVisionEnchantment.kt | 26 +++++++++++++++++++ 2 files changed, 42 insertions(+), 3 deletions(-) create mode 100644 src/main/kotlin/org/xodium/vanillaplus/enchantments/NightVisionEnchantment.kt diff --git a/src/main/kotlin/org/xodium/vanillaplus/VanillaPlusBootstrap.kt b/src/main/kotlin/org/xodium/vanillaplus/VanillaPlusBootstrap.kt index 809cd4a96..9252a4009 100644 --- a/src/main/kotlin/org/xodium/vanillaplus/VanillaPlusBootstrap.kt +++ b/src/main/kotlin/org/xodium/vanillaplus/VanillaPlusBootstrap.kt @@ -13,6 +13,7 @@ import io.papermc.paper.registry.keys.tags.ItemTypeTagKeys import io.papermc.paper.registry.tag.TagKey import io.papermc.paper.tag.TagEntry import net.kyori.adventure.key.Key +import org.xodium.vanillaplus.enchantments.NightVisionEnchantment import org.xodium.vanillaplus.enchantments.PickupEnchantment import org.xodium.vanillaplus.enchantments.ReplantEnchantment @@ -23,7 +24,8 @@ internal class VanillaPlusBootstrap : PluginBootstrap { const val INSTANCE = "vanillaplus" val REPLANT = ReplantEnchantment.key val PICKUP = PickupEnchantment.key - val ENCHANTS = setOf(REPLANT, PICKUP) + val NIGHT_VISION = NightVisionEnchantment.key + val ENCHANTS = setOf(REPLANT, PICKUP, NIGHT_VISION) val TOOLS = TagKey.create(RegistryKey.ITEM, Key.key(INSTANCE, "tools")) } @@ -47,9 +49,20 @@ internal class VanillaPlusBootstrap : PluginBootstrap { RegistryEvents.ENCHANTMENT.compose().newHandler { event -> event.registry().apply { register(REPLANT) { - ReplantEnchantment.builder(it).supportedItems(event.getOrCreateTag(ItemTypeTagKeys.HOES)) + ReplantEnchantment + .builder(it) + .supportedItems(event.getOrCreateTag(ItemTypeTagKeys.HOES)) + } + register(PICKUP) { + PickupEnchantment + .builder(it) + .supportedItems(event.getOrCreateTag(TOOLS)) + } + register(NIGHT_VISION) { + NightVisionEnchantment + .builder(it) + .supportedItems(event.getOrCreateTag(ItemTypeTagKeys.HEAD_ARMOR)) } - register(PICKUP) { PickupEnchantment.builder(it).supportedItems(event.getOrCreateTag(TOOLS)) } } }, ) diff --git a/src/main/kotlin/org/xodium/vanillaplus/enchantments/NightVisionEnchantment.kt b/src/main/kotlin/org/xodium/vanillaplus/enchantments/NightVisionEnchantment.kt new file mode 100644 index 000000000..a5b187f07 --- /dev/null +++ b/src/main/kotlin/org/xodium/vanillaplus/enchantments/NightVisionEnchantment.kt @@ -0,0 +1,26 @@ +package org.xodium.vanillaplus.enchantments + +import io.papermc.paper.registry.RegistryKey +import io.papermc.paper.registry.TypedKey +import io.papermc.paper.registry.data.EnchantmentRegistryEntry +import net.kyori.adventure.key.Key +import org.bukkit.enchantments.Enchantment +import org.xodium.vanillaplus.VanillaPlusBootstrap.Companion.INSTANCE +import org.xodium.vanillaplus.interfaces.EnchantmentInterface +import org.xodium.vanillaplus.utils.ExtUtils.mm + +/** Represents a object handling night vision enchantment implementation within the system. */ +internal object NightVisionEnchantment : EnchantmentInterface { + override val key: TypedKey = + TypedKey.create(RegistryKey.ENCHANTMENT, Key.key(INSTANCE, "night_vision")) + + override fun builder(builder: EnchantmentRegistryEntry.Builder): EnchantmentRegistryEntry.Builder = + builder + .description(key.value().replaceFirstChar { it.uppercase() }.mm()) + .anvilCost(TODO()) + .maxLevel(TODO()) + .weight(TODO()) + .minimumCost(EnchantmentRegistryEntry.EnchantmentCost.of(TODO())) + .maximumCost(EnchantmentRegistryEntry.EnchantmentCost.of(TODO())) + .activeSlots(TODO()) +} From 9b7705125f05d8499f2f5002ac9420a7315df703 Mon Sep 17 00:00:00 2001 From: Illyrius Date: Fri, 14 Nov 2025 10:56:35 +0100 Subject: [PATCH 2/6] feat: refactor enchantment key generation in EnchantmentInterface and related classes Signed-off-by: Illyrius --- .../enchantments/NightVisionEnchantment.kt | 11 ++--------- .../enchantments/PickupEnchantment.kt | 8 +------- .../enchantments/ReplantEnchantment.kt | 8 +------- .../interfaces/EnchantmentInterface.kt | 17 ++++++++++++++++- 4 files changed, 20 insertions(+), 24 deletions(-) diff --git a/src/main/kotlin/org/xodium/vanillaplus/enchantments/NightVisionEnchantment.kt b/src/main/kotlin/org/xodium/vanillaplus/enchantments/NightVisionEnchantment.kt index a5b187f07..586037f51 100644 --- a/src/main/kotlin/org/xodium/vanillaplus/enchantments/NightVisionEnchantment.kt +++ b/src/main/kotlin/org/xodium/vanillaplus/enchantments/NightVisionEnchantment.kt @@ -1,19 +1,12 @@ package org.xodium.vanillaplus.enchantments -import io.papermc.paper.registry.RegistryKey -import io.papermc.paper.registry.TypedKey import io.papermc.paper.registry.data.EnchantmentRegistryEntry -import net.kyori.adventure.key.Key -import org.bukkit.enchantments.Enchantment -import org.xodium.vanillaplus.VanillaPlusBootstrap.Companion.INSTANCE import org.xodium.vanillaplus.interfaces.EnchantmentInterface import org.xodium.vanillaplus.utils.ExtUtils.mm -/** Represents a object handling night vision enchantment implementation within the system. */ +/** Represents an object handling night vision enchantment implementation within the system. */ +@Suppress("UnstableApiUsage") internal object NightVisionEnchantment : EnchantmentInterface { - override val key: TypedKey = - TypedKey.create(RegistryKey.ENCHANTMENT, Key.key(INSTANCE, "night_vision")) - override fun builder(builder: EnchantmentRegistryEntry.Builder): EnchantmentRegistryEntry.Builder = builder .description(key.value().replaceFirstChar { it.uppercase() }.mm()) diff --git a/src/main/kotlin/org/xodium/vanillaplus/enchantments/PickupEnchantment.kt b/src/main/kotlin/org/xodium/vanillaplus/enchantments/PickupEnchantment.kt index b858921ce..e96b11658 100644 --- a/src/main/kotlin/org/xodium/vanillaplus/enchantments/PickupEnchantment.kt +++ b/src/main/kotlin/org/xodium/vanillaplus/enchantments/PickupEnchantment.kt @@ -1,20 +1,14 @@ package org.xodium.vanillaplus.enchantments -import io.papermc.paper.registry.RegistryKey -import io.papermc.paper.registry.TypedKey import io.papermc.paper.registry.data.EnchantmentRegistryEntry -import net.kyori.adventure.key.Key -import org.bukkit.enchantments.Enchantment import org.bukkit.event.block.BlockBreakEvent import org.bukkit.inventory.EquipmentSlotGroup -import org.xodium.vanillaplus.VanillaPlusBootstrap.Companion.INSTANCE import org.xodium.vanillaplus.interfaces.EnchantmentInterface import org.xodium.vanillaplus.utils.ExtUtils.mm +/** Represents an object handling pickup enchantment implementation within the system. */ @Suppress("UnstableApiUsage") internal object PickupEnchantment : EnchantmentInterface { - override val key: TypedKey = TypedKey.create(RegistryKey.ENCHANTMENT, Key.key(INSTANCE, "pickup")) - override fun builder(builder: EnchantmentRegistryEntry.Builder): EnchantmentRegistryEntry.Builder = builder .description(key.value().replaceFirstChar { it.uppercase() }.mm()) diff --git a/src/main/kotlin/org/xodium/vanillaplus/enchantments/ReplantEnchantment.kt b/src/main/kotlin/org/xodium/vanillaplus/enchantments/ReplantEnchantment.kt index 9a7fb9c2f..ed150bbf1 100644 --- a/src/main/kotlin/org/xodium/vanillaplus/enchantments/ReplantEnchantment.kt +++ b/src/main/kotlin/org/xodium/vanillaplus/enchantments/ReplantEnchantment.kt @@ -1,22 +1,16 @@ package org.xodium.vanillaplus.enchantments -import io.papermc.paper.registry.RegistryKey -import io.papermc.paper.registry.TypedKey import io.papermc.paper.registry.data.EnchantmentRegistryEntry -import net.kyori.adventure.key.Key import org.bukkit.block.data.Ageable -import org.bukkit.enchantments.Enchantment import org.bukkit.event.block.BlockBreakEvent import org.bukkit.inventory.EquipmentSlotGroup import org.xodium.vanillaplus.VanillaPlus.Companion.instance -import org.xodium.vanillaplus.VanillaPlusBootstrap.Companion.INSTANCE import org.xodium.vanillaplus.interfaces.EnchantmentInterface import org.xodium.vanillaplus.utils.ExtUtils.mm +/** Represents an object handling replant enchantment implementation within the system. */ @Suppress("UnstableApiUsage") internal object ReplantEnchantment : EnchantmentInterface { - override val key: TypedKey = TypedKey.create(RegistryKey.ENCHANTMENT, Key.key(INSTANCE, "replant")) - override fun builder(builder: EnchantmentRegistryEntry.Builder): EnchantmentRegistryEntry.Builder = builder .description(key.value().replaceFirstChar { it.uppercase() }.mm()) diff --git a/src/main/kotlin/org/xodium/vanillaplus/interfaces/EnchantmentInterface.kt b/src/main/kotlin/org/xodium/vanillaplus/interfaces/EnchantmentInterface.kt index 3c972a266..e63d42b67 100644 --- a/src/main/kotlin/org/xodium/vanillaplus/interfaces/EnchantmentInterface.kt +++ b/src/main/kotlin/org/xodium/vanillaplus/interfaces/EnchantmentInterface.kt @@ -4,17 +4,32 @@ import io.papermc.paper.registry.RegistryAccess import io.papermc.paper.registry.RegistryKey import io.papermc.paper.registry.TypedKey import io.papermc.paper.registry.data.EnchantmentRegistryEntry +import net.kyori.adventure.key.Key import org.bukkit.enchantments.Enchantment +import org.xodium.vanillaplus.VanillaPlusBootstrap.Companion.INSTANCE /** Represents a contract for enchantments within the system. */ @Suppress("UnstableApiUsage") internal interface EnchantmentInterface { /** - * The unique typed key that identifies this enchantment in the registry. + * The unique typed key identifies this enchantment in the registry. * @see TypedKey * @see RegistryKey.ENCHANTMENT */ val key: TypedKey + get() = + TypedKey.create( + RegistryKey.ENCHANTMENT, + Key.key( + INSTANCE, + this::class + .simpleName + ?.removeSuffix("Enchantment") + ?.split(Regex("(?=[A-Z])")) + ?.joinToString("_") { it.lowercase() } + .toString(), + ), + ) /** * Configures the properties of the enchantment using the provided builder. From d7f6e1ac379bef09498cf297b2f5d5e24976f8ae Mon Sep 17 00:00:00 2001 From: Illyrius Date: Fri, 14 Nov 2025 11:06:52 +0100 Subject: [PATCH 3/6] feat: implement night vision effect handling for helmet enchantment Signed-off-by: Illyrius --- .../enchantments/NightVisionEnchantment.kt | 22 +++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/src/main/kotlin/org/xodium/vanillaplus/enchantments/NightVisionEnchantment.kt b/src/main/kotlin/org/xodium/vanillaplus/enchantments/NightVisionEnchantment.kt index 586037f51..7ab2d4081 100644 --- a/src/main/kotlin/org/xodium/vanillaplus/enchantments/NightVisionEnchantment.kt +++ b/src/main/kotlin/org/xodium/vanillaplus/enchantments/NightVisionEnchantment.kt @@ -1,6 +1,10 @@ package org.xodium.vanillaplus.enchantments +import io.papermc.paper.event.entity.EntityEquipmentChangedEvent import io.papermc.paper.registry.data.EnchantmentRegistryEntry +import org.bukkit.entity.Player +import org.bukkit.potion.PotionEffect +import org.bukkit.potion.PotionEffectType import org.xodium.vanillaplus.interfaces.EnchantmentInterface import org.xodium.vanillaplus.utils.ExtUtils.mm @@ -16,4 +20,22 @@ internal object NightVisionEnchantment : EnchantmentInterface { .minimumCost(EnchantmentRegistryEntry.EnchantmentCost.of(TODO())) .maximumCost(EnchantmentRegistryEntry.EnchantmentCost.of(TODO())) .activeSlots(TODO()) + + /** + * Handles the equipment change event to apply or remove night vision effect based on the helmet enchantment. + * @param event The EntityEquipmentChangedEvent triggered when an entity's equipment changes. + */ + fun nightVision(event: EntityEquipmentChangedEvent) { + val player = event.entity as Player + val helmet = player.inventory.helmet ?: return + + if (!helmet.hasItemMeta()) return + if (helmet.itemMeta.hasEnchant(get())) { + player.addPotionEffect(PotionEffect(PotionEffectType.NIGHT_VISION, Int.MAX_VALUE, 0, true, false, true)) + } else { + if (player.hasPotionEffect(PotionEffectType.NIGHT_VISION)) { + player.removePotionEffect(PotionEffectType.NIGHT_VISION) + } + } + } } From 5782eea16a7bb704e6ee0222484c78b2162b75e1 Mon Sep 17 00:00:00 2001 From: Illyrius Date: Fri, 14 Nov 2025 11:23:28 +0100 Subject: [PATCH 4/6] feat: add event handler for night vision enchantment equipment changes Signed-off-by: Illyrius --- .../org/xodium/vanillaplus/modules/PlayerModule.kt | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/main/kotlin/org/xodium/vanillaplus/modules/PlayerModule.kt b/src/main/kotlin/org/xodium/vanillaplus/modules/PlayerModule.kt index e11671b6a..ce9c27ee6 100644 --- a/src/main/kotlin/org/xodium/vanillaplus/modules/PlayerModule.kt +++ b/src/main/kotlin/org/xodium/vanillaplus/modules/PlayerModule.kt @@ -5,6 +5,7 @@ import io.papermc.paper.command.brigadier.Commands import io.papermc.paper.datacomponent.DataComponentTypes import io.papermc.paper.datacomponent.item.ItemLore import io.papermc.paper.datacomponent.item.ResolvableProfile +import io.papermc.paper.event.entity.EntityEquipmentChangedEvent import net.kyori.adventure.text.minimessage.tag.resolver.Placeholder import org.bukkit.Material import org.bukkit.entity.Player @@ -24,6 +25,7 @@ import org.bukkit.permissions.Permission import org.bukkit.permissions.PermissionDefault import org.xodium.vanillaplus.VanillaPlus.Companion.instance import org.xodium.vanillaplus.data.CommandData +import org.xodium.vanillaplus.enchantments.NightVisionEnchantment import org.xodium.vanillaplus.enchantments.PickupEnchantment import org.xodium.vanillaplus.enchantments.ReplantEnchantment import org.xodium.vanillaplus.interfaces.ModuleInterface @@ -168,6 +170,13 @@ internal class PlayerModule( PickupEnchantment.pickup(event) } + @EventHandler + fun on(event: EntityEquipmentChangedEvent) { + if (!enabled()) return + + NightVisionEnchantment.nightVision(event) + } + /** * Handles the interaction event where a player can convert their experience points into an experience bottle * if specific conditions are met. From 5962821fa04726dc337577f23ec2e78e15196fac Mon Sep 17 00:00:00 2001 From: Illyrius Date: Fri, 14 Nov 2025 14:17:39 +0100 Subject: [PATCH 5/6] feat: update enchantment costs and levels for Night Vision, Pickup, and Replant enchantments Signed-off-by: Illyrius --- .../enchantments/NightVisionEnchantment.kt | 13 +++++++------ .../vanillaplus/enchantments/PickupEnchantment.kt | 9 ++++----- .../vanillaplus/enchantments/ReplantEnchantment.kt | 9 ++++----- 3 files changed, 15 insertions(+), 16 deletions(-) diff --git a/src/main/kotlin/org/xodium/vanillaplus/enchantments/NightVisionEnchantment.kt b/src/main/kotlin/org/xodium/vanillaplus/enchantments/NightVisionEnchantment.kt index 7ab2d4081..a3d2dc7c9 100644 --- a/src/main/kotlin/org/xodium/vanillaplus/enchantments/NightVisionEnchantment.kt +++ b/src/main/kotlin/org/xodium/vanillaplus/enchantments/NightVisionEnchantment.kt @@ -3,6 +3,7 @@ package org.xodium.vanillaplus.enchantments import io.papermc.paper.event.entity.EntityEquipmentChangedEvent import io.papermc.paper.registry.data.EnchantmentRegistryEntry import org.bukkit.entity.Player +import org.bukkit.inventory.EquipmentSlotGroup import org.bukkit.potion.PotionEffect import org.bukkit.potion.PotionEffectType import org.xodium.vanillaplus.interfaces.EnchantmentInterface @@ -14,12 +15,12 @@ internal object NightVisionEnchantment : EnchantmentInterface { override fun builder(builder: EnchantmentRegistryEntry.Builder): EnchantmentRegistryEntry.Builder = builder .description(key.value().replaceFirstChar { it.uppercase() }.mm()) - .anvilCost(TODO()) - .maxLevel(TODO()) - .weight(TODO()) - .minimumCost(EnchantmentRegistryEntry.EnchantmentCost.of(TODO())) - .maximumCost(EnchantmentRegistryEntry.EnchantmentCost.of(TODO())) - .activeSlots(TODO()) + .anvilCost(2) + .maxLevel(1) + .weight(2) + .minimumCost(EnchantmentRegistryEntry.EnchantmentCost.of(25, 0)) + .maximumCost(EnchantmentRegistryEntry.EnchantmentCost.of(75, 0)) + .activeSlots(EquipmentSlotGroup.ARMOR) /** * Handles the equipment change event to apply or remove night vision effect based on the helmet enchantment. diff --git a/src/main/kotlin/org/xodium/vanillaplus/enchantments/PickupEnchantment.kt b/src/main/kotlin/org/xodium/vanillaplus/enchantments/PickupEnchantment.kt index e96b11658..ab82f4edb 100644 --- a/src/main/kotlin/org/xodium/vanillaplus/enchantments/PickupEnchantment.kt +++ b/src/main/kotlin/org/xodium/vanillaplus/enchantments/PickupEnchantment.kt @@ -12,12 +12,11 @@ internal object PickupEnchantment : EnchantmentInterface { override fun builder(builder: EnchantmentRegistryEntry.Builder): EnchantmentRegistryEntry.Builder = builder .description(key.value().replaceFirstChar { it.uppercase() }.mm()) - // TODO: Adjust costs and levels as needed - .anvilCost(8) + .anvilCost(2) .maxLevel(1) - .weight(5) - .minimumCost(EnchantmentRegistryEntry.EnchantmentCost.of(1, 10)) - .maximumCost(EnchantmentRegistryEntry.EnchantmentCost.of(8, 20)) + .weight(2) + .minimumCost(EnchantmentRegistryEntry.EnchantmentCost.of(25, 0)) + .maximumCost(EnchantmentRegistryEntry.EnchantmentCost.of(75, 0)) .activeSlots(EquipmentSlotGroup.MAINHAND) /** diff --git a/src/main/kotlin/org/xodium/vanillaplus/enchantments/ReplantEnchantment.kt b/src/main/kotlin/org/xodium/vanillaplus/enchantments/ReplantEnchantment.kt index ed150bbf1..1e5d7b69e 100644 --- a/src/main/kotlin/org/xodium/vanillaplus/enchantments/ReplantEnchantment.kt +++ b/src/main/kotlin/org/xodium/vanillaplus/enchantments/ReplantEnchantment.kt @@ -14,12 +14,11 @@ internal object ReplantEnchantment : EnchantmentInterface { override fun builder(builder: EnchantmentRegistryEntry.Builder): EnchantmentRegistryEntry.Builder = builder .description(key.value().replaceFirstChar { it.uppercase() }.mm()) - // TODO: Adjust costs and levels as needed - .anvilCost(8) + .anvilCost(2) .maxLevel(1) - .weight(5) - .minimumCost(EnchantmentRegistryEntry.EnchantmentCost.of(1, 10)) - .maximumCost(EnchantmentRegistryEntry.EnchantmentCost.of(8, 20)) + .weight(2) + .minimumCost(EnchantmentRegistryEntry.EnchantmentCost.of(25, 0)) + .maximumCost(EnchantmentRegistryEntry.EnchantmentCost.of(75, 0)) .activeSlots(EquipmentSlotGroup.MAINHAND) /** From 7b9bc0875068673f8fdd57f74c3493c6688c5f83 Mon Sep 17 00:00:00 2001 From: Illyrius Date: Fri, 14 Nov 2025 14:32:33 +0100 Subject: [PATCH 6/6] feat: improve night vision enchantment handling and null safety Signed-off-by: Illyrius --- .../enchantments/NightVisionEnchantment.kt | 15 +++++++-------- .../interfaces/EnchantmentInterface.kt | 1 + 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/main/kotlin/org/xodium/vanillaplus/enchantments/NightVisionEnchantment.kt b/src/main/kotlin/org/xodium/vanillaplus/enchantments/NightVisionEnchantment.kt index a3d2dc7c9..de5abbd47 100644 --- a/src/main/kotlin/org/xodium/vanillaplus/enchantments/NightVisionEnchantment.kt +++ b/src/main/kotlin/org/xodium/vanillaplus/enchantments/NightVisionEnchantment.kt @@ -27,16 +27,15 @@ internal object NightVisionEnchantment : EnchantmentInterface { * @param event The EntityEquipmentChangedEvent triggered when an entity's equipment changes. */ fun nightVision(event: EntityEquipmentChangedEvent) { - val player = event.entity as Player - val helmet = player.inventory.helmet ?: return + val player = event.entity as? Player ?: return + val helmet = player.inventory.helmet - if (!helmet.hasItemMeta()) return - if (helmet.itemMeta.hasEnchant(get())) { - player.addPotionEffect(PotionEffect(PotionEffectType.NIGHT_VISION, Int.MAX_VALUE, 0, true, false, true)) + if (helmet != null && helmet.hasItemMeta() && helmet.itemMeta.hasEnchant(get())) { + player.addPotionEffect(PotionEffect(PotionEffectType.NIGHT_VISION, -1, 0, true, false, true)) } else { - if (player.hasPotionEffect(PotionEffectType.NIGHT_VISION)) { - player.removePotionEffect(PotionEffectType.NIGHT_VISION) - } + player.activePotionEffects + .filter { it.type == PotionEffectType.NIGHT_VISION } + .forEach { if (it.duration == -1) player.removePotionEffect(PotionEffectType.NIGHT_VISION) } } } } diff --git a/src/main/kotlin/org/xodium/vanillaplus/interfaces/EnchantmentInterface.kt b/src/main/kotlin/org/xodium/vanillaplus/interfaces/EnchantmentInterface.kt index e63d42b67..d345b0ee3 100644 --- a/src/main/kotlin/org/xodium/vanillaplus/interfaces/EnchantmentInterface.kt +++ b/src/main/kotlin/org/xodium/vanillaplus/interfaces/EnchantmentInterface.kt @@ -26,6 +26,7 @@ internal interface EnchantmentInterface { .simpleName ?.removeSuffix("Enchantment") ?.split(Regex("(?=[A-Z])")) + ?.filter { it.isNotEmpty() } ?.joinToString("_") { it.lowercase() } .toString(), ),