commit ec4329fcc10ced0e713131c8f789b8e5fa8bde07 Author: bunchy7s Date: Tue May 19 16:04:33 2026 -0500 Initial commit: Folia compatibility and cleanup diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..1c069a2 --- /dev/null +++ b/.gitignore @@ -0,0 +1,8 @@ +target/ +plans/ +*.class +*.jar +.vscode/ +.idea/ +*.iml +.DS_Store diff --git a/README.md b/README.md new file mode 100644 index 0000000..cdf8df9 --- /dev/null +++ b/README.md @@ -0,0 +1,7 @@ +# EzBoner +this is really fucking hard to explain, +when you use bonemeal, it affects all nearby crops (up to 32) using the proper amount of bonemeal, super duper fast and easy + +## Features +- Supports foila! +- **Connected Growth**: Look upwards diff --git a/pom.xml b/pom.xml new file mode 100644 index 0000000..73b14cb --- /dev/null +++ b/pom.xml @@ -0,0 +1,68 @@ + + + 4.0.0 + + boner + EzBoner + 1.0 + + EzBoner + https://coldfiles.dev/ + + + UTF-8 + 21 + 21 + + + + + papermc + https://repo.papermc.io/repository/maven-public/ + + + + + + dev.folia + folia-api + 1.20.1-R0.1-SNAPSHOT + provided + + + + + ${project.basedir}/src/main/java + + + ${project.basedir}/src/main/resources + + plugin.yml + + + + + + org.apache.maven.plugins + maven-antrun-plugin + 3.1.0 + + + package + + run + + + + + + + + + + + + \ No newline at end of file diff --git a/src/main/java/boner/EzBoner.java b/src/main/java/boner/EzBoner.java new file mode 100644 index 0000000..79cdd19 --- /dev/null +++ b/src/main/java/boner/EzBoner.java @@ -0,0 +1,26 @@ +package boner; + +import org.bukkit.plugin.java.JavaPlugin; +import boner.managers.PluginManager; +import boner.listeners.PlayerListener; + +public class EzBoner extends JavaPlugin { + + @Override + public void onEnable() { + + // Initialize managers + PluginManager.getInstance().initialize(); + + // Register listeners + getServer().getPluginManager().registerEvents(new PlayerListener(), this); + + getLogger().info("EzBoner has been enabled!"); + } + + @Override + public void onDisable() { + getLogger().info("EzBoner has been disabled!"); + } + +} \ No newline at end of file diff --git a/src/main/java/boner/listeners/PlayerListener.java b/src/main/java/boner/listeners/PlayerListener.java new file mode 100644 index 0000000..a7c7706 --- /dev/null +++ b/src/main/java/boner/listeners/PlayerListener.java @@ -0,0 +1,74 @@ +package boner.listeners; + +import boner.EzBoner; +import boner.utils.Utils; +import org.bukkit.Material; +import org.bukkit.Particle; +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; +import org.bukkit.event.Listener; +import org.bukkit.event.block.Action; +import org.bukkit.event.player.PlayerInteractEvent; +import org.bukkit.inventory.ItemStack; +import org.bukkit.plugin.java.JavaPlugin; + +import java.util.List; + +public class PlayerListener implements Listener { + + private final EzBoner plugin = JavaPlugin.getPlugin(EzBoner.class); + + @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) + public void onPlayerInteract(PlayerInteractEvent event) { + if (event.getAction() != Action.RIGHT_CLICK_BLOCK) return; + + Player player = event.getPlayer(); + if (!player.isSneaking()) return; + + ItemStack item = event.getItem(); + if (item == null || item.getType() != Material.BONE_MEAL) return; + + Block clickedBlock = event.getClickedBlock(); + if (clickedBlock == null || !Utils.isBonemealable(clickedBlock)) return; + + // Cancel the original event to handle it ourselves + event.setCancelled(true); + + // Find connected crops (limit 32) + List targets = Utils.findConnectedCrops(clickedBlock, 32); + if (targets.isEmpty()) return; + + // Folia-safe execution on the region of the clicked block + org.bukkit.Bukkit.getRegionScheduler().execute(plugin, clickedBlock.getLocation(), () -> { + int appliedCount = 0; + for (Block target : targets) { + if (Utils.isBonemealable(target)) { + // Apply bonemeal effect + if (target.getBlockData() instanceof Ageable ageable) { + ageable.setAge(ageable.getMaximumAge()); + target.setBlockData(ageable); + } else { + // Fallback for saplings or other non-ageable but bonemealable blocks + target.applyBoneMeal(org.bukkit.block.BlockFace.UP); + } + + appliedCount++; + } + } + + if (appliedCount > 0) { + // Consume items from player + final int finalAppliedCount = appliedCount; + player.getScheduler().execute(plugin, () -> { + ItemStack handItem = player.getInventory().getItem(event.getHand()); + if (handItem != null && handItem.getType() == Material.BONE_MEAL) { + handItem.setAmount(Math.max(0, handItem.getAmount() - finalAppliedCount)); + } + }, null, 0); + } + }); + } +} \ No newline at end of file diff --git a/src/main/java/boner/managers/PluginManager.java b/src/main/java/boner/managers/PluginManager.java new file mode 100644 index 0000000..e4c7a86 --- /dev/null +++ b/src/main/java/boner/managers/PluginManager.java @@ -0,0 +1,16 @@ +package boner.managers; + +public class PluginManager { + private static PluginManager instance; + + public static PluginManager getInstance() { + if (instance == null) { + instance = new PluginManager(); + } + return instance; + } + + public void initialize() { + // Initialize your managers here + } +} \ No newline at end of file diff --git a/src/main/java/boner/utils/Utils.java b/src/main/java/boner/utils/Utils.java new file mode 100644 index 0000000..5aef6f7 --- /dev/null +++ b/src/main/java/boner/utils/Utils.java @@ -0,0 +1,66 @@ +package boner.utils; + +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.minimessage.MiniMessage; +import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer; +import org.bukkit.Material; +import org.bukkit.block.Block; +import org.bukkit.block.data.Ageable; +import org.bukkit.block.data.BlockData; + +import java.util.*; + +public class Utils { + + public static Component colorize(String msg) { + if (msg.contains("<") && msg.contains(">")) { + return MiniMessage.miniMessage().deserialize(msg); + } + return LegacyComponentSerializer.legacyAmpersand().deserialize(msg); + } + + public static String legacyColorize(String msg) { + return LegacyComponentSerializer.legacyAmpersand().serialize( + LegacyComponentSerializer.legacyAmpersand().deserialize(msg) + ); + } + + public static boolean isBonemealable(Block block) { + BlockData data = block.getBlockData(); + if (data instanceof Ageable ageable) { + return ageable.getAge() < ageable.getMaximumAge(); + } + // Support for saplings which might not be Ageable in some versions but are bonemealable + return block.getType().name().contains("SAPLING"); + } + + public static List findConnectedCrops(Block start, int limit) { + List found = new ArrayList<>(); + Queue queue = new LinkedList<>(); + Set visited = new HashSet<>(); + + if (isBonemealable(start)) { + queue.add(start); + visited.add(start); + } + + while (!queue.isEmpty() && found.size() < limit) { + Block current = queue.poll(); + found.add(current); + + for (int x = -1; x <= 1; x++) { + for (int z = -1; z <= 1; z++) { + if (x == 0 && z == 0) continue; + + Block neighbor = current.getRelative(x, 0, z); + if (!visited.contains(neighbor) && isBonemealable(neighbor)) { + visited.add(neighbor); + queue.add(neighbor); + } + } + } + } + + return found; + } +} \ No newline at end of file diff --git a/src/main/resources/plugin.yml b/src/main/resources/plugin.yml new file mode 100644 index 0000000..d2af4ae --- /dev/null +++ b/src/main/resources/plugin.yml @@ -0,0 +1,6 @@ +main: boner.EzBoner +version: 1.0 +name: EzBoner +author: bunchy7s +api-version: 1.21 +folia-supported: true \ No newline at end of file