Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .idea/dictionaries/project.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

14 changes: 13 additions & 1 deletion src/main/kotlin/org/xodium/vanillaplus/VanillaPlusBootstrap.kt
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ 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.NimbusEnchantment
import org.xodium.vanillaplus.enchantments.PickupEnchantment
import org.xodium.vanillaplus.enchantments.ReplantEnchantment

Expand Down Expand Up @@ -81,12 +82,23 @@ internal class VanillaPlusBootstrap : PluginBootstrap {
.invoke(builder)
.supportedItems(event.getOrCreateTag(ItemTypeTagKeys.HEAD_ARMOR))
}
register(NimbusEnchantment.key) { builder ->
NimbusEnchantment
.invoke(builder)
.supportedItems(event.getOrCreateTag(ItemTypeTagKeys.HARNESSES))
}
}
},
)
registerEventHandler(LifecycleEvents.TAGS.postFlatten(RegistryKey.ENCHANTMENT)) { event ->
event.registrar().apply {
val enchants = setOf(ReplantEnchantment.key, PickupEnchantment.key, NightVisionEnchantment.key)
val enchants =
setOf(
ReplantEnchantment.key,
PickupEnchantment.key,
NightVisionEnchantment.key,
NimbusEnchantment.key,
)
addToTag(EnchantmentTagKeys.TRADEABLE, enchants)
addToTag(EnchantmentTagKeys.NON_TREASURE, enchants)
addToTag(EnchantmentTagKeys.IN_ENCHANTING_TABLE, enchants)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
package org.xodium.vanillaplus.enchantments

import io.papermc.paper.event.entity.EntityEquipmentChangedEvent
import io.papermc.paper.registry.data.EnchantmentRegistryEntry
import org.bukkit.attribute.Attribute
import org.bukkit.entity.HappyGhast
import org.bukkit.inventory.EquipmentSlot
import org.bukkit.inventory.EquipmentSlotGroup
import org.xodium.vanillaplus.interfaces.EnchantmentInterface
import org.xodium.vanillaplus.utils.ExtUtils.mm

/** Represents an object handling nimbus enchantment implementation within the system. */
@Suppress("UnstableApiUsage")
internal object NimbusEnchantment : EnchantmentInterface {
const val DEFAULT_FLY_SPEED = 0.05

override fun invoke(builder: EnchantmentRegistryEntry.Builder): EnchantmentRegistryEntry.Builder =
builder
.description(key.value().replaceFirstChar { it.uppercase() }.mm())
.anvilCost(2)
.maxLevel(5)
.weight(2)
.minimumCost(EnchantmentRegistryEntry.EnchantmentCost.of(25, 5))
.maximumCost(EnchantmentRegistryEntry.EnchantmentCost.of(75, 10))
.activeSlots(EquipmentSlotGroup.SADDLE)

/**
* Handles the event when an entity's equipment changes, specifically for Happy Ghasts with the nimbus enchantment.
* @param event The event representing the change in entity equipment.
*/
fun nimbus(event: EntityEquipmentChangedEvent) {
Copy link

Copilot AI Nov 17, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The code doesn't verify that the changed equipment slot is actually the BODY slot. This means the function performs unnecessary work on every equipment change (helmet, boots, etc.). Consider adding a check like if (event.slot != EquipmentSlot.BODY) return early in the function to avoid processing irrelevant equipment changes, consistent with how other enchantments in the codebase filter their events.

Suggested change
fun nimbus(event: EntityEquipmentChangedEvent) {
fun nimbus(event: EntityEquipmentChangedEvent) {
if (event.slot != EquipmentSlot.BODY) return

Copilot uses AI. Check for mistakes.
val entity = event.entity as? HappyGhast ?: return
val harness = entity.equipment.getItem(EquipmentSlot.BODY)
val attribute = entity.getAttribute(Attribute.FLYING_SPEED)

if (harness.hasItemMeta() && harness.itemMeta.hasEnchant(get())) {
val level = harness.itemMeta.getEnchantLevel(get())
val speedMultiplier = getSpeedMultiplier(level)
attribute?.baseValue = DEFAULT_FLY_SPEED * speedMultiplier
} else {
attribute?.baseValue = DEFAULT_FLY_SPEED
Comment on lines +35 to +41
Copy link

Copilot AI Nov 17, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[nitpick] Using a nullable safe-call operator (?.) silently ignores the case where the attribute is null. If the FLYING_SPEED attribute is expected to always exist for HappyGhast entities, this could mask potential issues. Consider adding a null check with early return or logging if the attribute is unexpectedly null.

Suggested change
if (harness.hasItemMeta() && harness.itemMeta.hasEnchant(get())) {
val level = harness.itemMeta.getEnchantLevel(get())
val speedMultiplier = getSpeedMultiplier(level)
attribute?.baseValue = DEFAULT_FLY_SPEED * speedMultiplier
} else {
attribute?.baseValue = DEFAULT_FLY_SPEED
if (attribute == null) {
org.bukkit.Bukkit.getLogger().warning("HappyGhast entity missing FLYING_SPEED attribute in NimbusEnchantment.")
return
}
if (harness.hasItemMeta() && harness.itemMeta.hasEnchant(get())) {
val level = harness.itemMeta.getEnchantLevel(get())
val speedMultiplier = getSpeedMultiplier(level)
attribute.baseValue = DEFAULT_FLY_SPEED * speedMultiplier
} else {
attribute.baseValue = DEFAULT_FLY_SPEED

Copilot uses AI. Check for mistakes.
}
Comment on lines +36 to +42
Copy link

Copilot AI Nov 17, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The code resets the flying speed to DEFAULT_FLY_SPEED whenever equipment changes, regardless of whether the harness was actually removed or changed. This could overwrite custom speed values set by other plugins or game mechanics. The reset should only occur when the harness is removed or the enchantment is specifically removed, not on every equipment change event. Consider checking if event.slot == EquipmentSlot.BODY before modifying the speed, similar to how NightVisionEnchantment checks the specific slot.

Copilot uses AI. Check for mistakes.
}

/**
* Calculates the flying speed multiplier based on the enchantment level.
* @param level The enchantment level (1-5)
* @return The flying speed multiplier for the given level
*/
private fun getSpeedMultiplier(level: Int): Double =
when (level) {
1 -> 1.5
2 -> 2.0
3 -> 2.5
4 -> 3.0
5 -> 3.5
else -> 1.0
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,15 @@

package org.xodium.vanillaplus.modules

import io.papermc.paper.event.entity.EntityEquipmentChangedEvent
import org.bukkit.Material
import org.bukkit.entity.*
import org.bukkit.event.EventHandler
import org.bukkit.event.entity.EntityChangeBlockEvent
import org.bukkit.event.entity.EntityDeathEvent
import org.bukkit.event.entity.EntityExplodeEvent
import org.bukkit.inventory.ItemStack
import org.xodium.vanillaplus.enchantments.NimbusEnchantment
import org.xodium.vanillaplus.interfaces.ModuleInterface
import kotlin.random.Random

Expand Down Expand Up @@ -36,6 +38,13 @@ internal class EntityModule : ModuleInterface<EntityModule.Config> {
}
}

@EventHandler
fun on(event: EntityEquipmentChangedEvent) {
if (!enabled()) return

NimbusEnchantment.nimbus(event)
}

/**
* Determines whether an entity's griefing behaviour should be cancelled based on configuration settings.
* @param entity The entity whose griefing behaviour is being evaluated.
Expand Down
Loading