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

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

4 changes: 2 additions & 2 deletions .idea/modules/VanillaPlus.main.iml

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

4 changes: 2 additions & 2 deletions .idea/modules/VanillaPlus.test.iml

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

24 changes: 22 additions & 2 deletions src/main/kotlin/org/xodium/vanillaplus/VanillaPlusBootstrap.kt
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,10 @@ import io.papermc.paper.registry.RegistryKey
import io.papermc.paper.registry.event.RegistryEvents
import io.papermc.paper.registry.keys.tags.EnchantmentTagKeys
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.PickupEnchantment
import org.xodium.vanillaplus.enchantments.ReplantEnchantment

/** Main bootstrap class of the plugin. */
Expand All @@ -17,16 +21,32 @@ internal class VanillaPlusBootstrap : PluginBootstrap {
companion object {
const val INSTANCE = "vanillaplus"
val REPLANT = ReplantEnchantment.key
val ENCHANTS = setOf(REPLANT)
val PICKUP = PickupEnchantment.key
val ENCHANTS = setOf(REPLANT, PICKUP)
val TOOLS = TagKey.create(RegistryKey.ITEM, Key.key(INSTANCE, "tools"))
}

override fun bootstrap(ctx: BootstrapContext) {
ctx.lifecycleManager.apply {
registerEventHandler(LifecycleEvents.TAGS.preFlatten(RegistryKey.ITEM)) { event ->
event.registrar().setTag(
TOOLS,
setOf(
TagEntry.tagEntry(ItemTypeTagKeys.PICKAXES),
TagEntry.tagEntry(ItemTypeTagKeys.AXES),
TagEntry.tagEntry(ItemTypeTagKeys.SHOVELS),
TagEntry.tagEntry(ItemTypeTagKeys.HOES),
),
)
}
registerEventHandler(
RegistryEvents.ENCHANTMENT.compose().newHandler { event ->
val hoeTag = event.getOrCreateTag(ItemTypeTagKeys.HOES)
val toolsTag = event.getOrCreateTag(TOOLS)

event.registry().apply {
register(REPLANT) { ReplantEnchantment.init(it).supportedItems(hoeTag) }
register(REPLANT) { ReplantEnchantment.builder(it).supportedItems(hoeTag) }
register(PICKUP) { PickupEnchantment.builder(it).supportedItems(toolsTag) }
}
},
)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
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.VanillaPlusBootstrap.Companion.PICKUP
import org.xodium.vanillaplus.interfaces.EnchantmentInterface
import org.xodium.vanillaplus.utils.ExtUtils.mm

@Suppress("UnstableApiUsage")
internal object PickupEnchantment : EnchantmentInterface {
override val key: TypedKey<Enchantment> = TypedKey.create(RegistryKey.ENCHANTMENT, Key.key(INSTANCE, "pickup"))

override fun builder(builder: EnchantmentRegistryEntry.Builder): EnchantmentRegistryEntry.Builder =
builder
.description(PICKUP.value().replaceFirstChar { it.uppercase() }.mm())
// TODO: Adjust costs and levels as needed
.anvilCost(8)
.maxLevel(1)
.weight(5)
.minimumCost(EnchantmentRegistryEntry.EnchantmentCost.of(1, 10))
.maximumCost(EnchantmentRegistryEntry.EnchantmentCost.of(8, 20))
.activeSlots(EquipmentSlotGroup.MAINHAND)

/**
* Handles the block break event to automatically pick up drops when the tool has the Pickup enchantment.
* @param event The BlockBreakEvent triggered when a block is broken.
*/
fun pickup(event: BlockBreakEvent) {
val player = event.player
val itemInHand = player.inventory.itemInMainHand

if (!itemInHand.hasItemMeta() || !itemInHand.itemMeta.hasEnchant(get())) return

event.isDropItems = false

for (drop in event.block.drops) {
Copy link

Copilot AI Nov 13, 2025

Choose a reason for hiding this comment

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

The code uses event.block.drops which may not properly account for tool-specific enchantments like Fortune or Silk Touch. Consider using event.block.getDrops(itemInHand, event.player) instead to ensure the drops are calculated correctly based on the tool's properties and enchantments.

Suggested change
for (drop in event.block.drops) {
for (drop in event.block.getDrops(itemInHand, player)) {

Copilot uses AI. Check for mistakes.
val remaining = player.inventory.addItem(drop)

for (item in remaining.values) player.world.dropItemNaturally(player.location, item)
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,11 @@ 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.VanillaPlusBootstrap.Companion.REPLANT
import org.xodium.vanillaplus.interfaces.EnchantmentInterface
Expand All @@ -15,13 +18,40 @@ import org.xodium.vanillaplus.utils.ExtUtils.mm
internal object ReplantEnchantment : EnchantmentInterface {
override val key: TypedKey<Enchantment> = TypedKey.create(RegistryKey.ENCHANTMENT, Key.key(INSTANCE, "replant"))

override fun init(builder: EnchantmentRegistryEntry.Builder): EnchantmentRegistryEntry.Builder =
override fun builder(builder: EnchantmentRegistryEntry.Builder): EnchantmentRegistryEntry.Builder =
builder
.description(REPLANT.value().replaceFirstChar { it.uppercase() }.mm())
// TODO: Adjust costs and levels as needed
.anvilCost(8)
.maxLevel(1)
.weight(5)
.minimumCost(EnchantmentRegistryEntry.EnchantmentCost.of(1, 10))
.maximumCost(EnchantmentRegistryEntry.EnchantmentCost.of(8, 20))
.activeSlots(EquipmentSlotGroup.MAINHAND)

/**
* Automatically replants a crop block after it has been fully grown and harvested.
* @param event The BlockBreakEvent triggered when a block is broken.
*/
fun replant(event: BlockBreakEvent) {
val block = event.block
val ageable = block.blockData as? Ageable ?: return
val itemInHand = event.player.inventory.itemInMainHand

if (ageable.age < ageable.maximumAge) return
if (!itemInHand.hasItemMeta() || !itemInHand.itemMeta.hasEnchant(get())) return

// TODO: take seed out of drop. since planting would require a seed being used.

instance.server.scheduler.runTaskLater(
instance,
Runnable {
val blockType = block.type

block.type = blockType
block.blockData = ageable.apply { age = 0 }
},
2,
)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,11 @@ internal interface EnchantmentInterface {
val key: TypedKey<Enchantment>

/**
* Initializes the Drift enchantment.
* Configures the properties of the enchantment using the provided builder.
* @param builder The builder used to define the enchantment properties.
* @return The builder for method chaining.
*/
fun init(builder: EnchantmentRegistryEntry.Builder): EnchantmentRegistryEntry.Builder
fun builder(builder: EnchantmentRegistryEntry.Builder): EnchantmentRegistryEntry.Builder

/**
* Retrieves the enchantment from the registry.
Expand Down
32 changes: 3 additions & 29 deletions src/main/kotlin/org/xodium/vanillaplus/modules/PlayerModule.kt
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,6 @@ import io.papermc.paper.datacomponent.item.ItemLore
import io.papermc.paper.datacomponent.item.ResolvableProfile
import net.kyori.adventure.text.minimessage.tag.resolver.Placeholder
import org.bukkit.Material
import org.bukkit.block.Block
import org.bukkit.block.data.Ageable
import org.bukkit.entity.Player
import org.bukkit.event.EventHandler
import org.bukkit.event.EventPriority
Expand All @@ -26,6 +24,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.PickupEnchantment
import org.xodium.vanillaplus.enchantments.ReplantEnchantment
import org.xodium.vanillaplus.interfaces.ModuleInterface
import org.xodium.vanillaplus.pdcs.PlayerPDC.nickname
Expand Down Expand Up @@ -165,33 +164,8 @@ internal class PlayerModule(
fun on(event: BlockBreakEvent) {
if (!enabled()) return

replant(event.block, event.player.inventory.itemInMainHand)
}

/**
* Automatically replants a crop block after it has been fully grown and harvested.
* @param block The block that was broken.
* @param tool The tool used to break the block.
*/
private fun replant(
block: Block,
tool: ItemStack,
) {
val ageable = block.blockData as? Ageable ?: return

if (ageable.age < ageable.maximumAge) return
if (!tool.hasItemMeta() || !tool.itemMeta.hasEnchant(ReplantEnchantment.get())) return

instance.server.scheduler.runTaskLater(
instance,
Runnable {
val blockType = block.type

block.type = blockType
block.blockData = ageable.apply { age = 0 }
},
2,
)
ReplantEnchantment.replant(event)
PickupEnchantment.pickup(event)
}

/**
Expand Down
Loading