Reimplement enchantmnet glint, fix NCP compatibility

This commit is contained in:
NotAlexNoyle committed 2026-05-25 18:28:50 -04:00
1 parent 3bedc7448c
commit dd9bd5f291
6 files changed
+179 -24

No files matched your search

@@ -2,18 +2,13 @@
// Authors: Barny1094875, NotAlexNoyle.
package net.trueog.flyingbowog.Commands;
import java.util.Collections;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.format.TextColor;
import net.kyori.adventure.text.format.TextDecoration;
import net.trueog.flyingbowog.FlyingBowOG;
import org.bukkit.Material;
import org.bukkit.command.Command;
import org.bukkit.command.CommandExecutor;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.ItemMeta;
public class GiveCommand implements CommandExecutor {
@@ -33,17 +28,7 @@ public class GiveCommand implements CommandExecutor {
// give bows
if (player.hasPermission("flyingbow.cangive")) {
// create the flying bow item
ItemStack flyingBowItem = new ItemStack(Material.BOW);
ItemMeta bowMeta = flyingBowItem.getItemMeta();
bowMeta.displayName(Component.text("Flying Bow").color(TextColor.color(0, 255, 255))
.decorate(TextDecoration.ITALIC));
bowMeta.lore(Collections.singletonList(Component.text(FlyingBowOG.LORE_MARKER)));
// Tag as a Flying Bow via PersistentDataContainer (Panilla-legal NBT).
FlyingBowOG.tagFlyingBow(bowMeta);
flyingBowItem.setItemMeta(bowMeta);
player.getInventory().addItem(flyingBowItem);
player.getInventory().addItem(FlyingBowOG.createFlyingBowItem());
}
// tell the player that they don't have permission to use this command
@@ -10,13 +10,16 @@ import net.trueog.flyingbowog.Commands.CommandsTabCompleter;
import net.trueog.flyingbowog.Commands.GiveCommand;
import net.trueog.flyingbowog.Listeners.OnAnvilUpdateResultEvent;
import net.trueog.flyingbowog.Listeners.OnEntityDamageEvent;
import net.trueog.flyingbowog.Listeners.OnEntityDismountEvent;
import net.trueog.flyingbowog.Listeners.OnEntityShootBowEvent;
import net.trueog.flyingbowog.Listeners.OnGenericGameEvent;
import net.trueog.flyingbowog.Listeners.OnPrepareAnvilEvent;
import org.bukkit.Bukkit;
import org.bukkit.Material;
import org.bukkit.NamespacedKey;
import org.bukkit.enchantments.Enchantment;
import org.bukkit.event.Listener;
import org.bukkit.inventory.ItemFlag;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.ShapedRecipe;
import org.bukkit.inventory.meta.ItemMeta;
@@ -43,14 +46,7 @@ public final class FlyingBowOG extends JavaPlugin implements Listener {
flyingBowKey = new NamespacedKey(this, "flying_bow");
// create the flying bow item
ItemStack flyingBowItem = new ItemStack(Material.BOW);
ItemMeta bowMeta = flyingBowItem.getItemMeta();
bowMeta.displayName(
Component.text("Flying Bow").color(TextColor.color(0, 255, 255)).decorate(TextDecoration.ITALIC));
bowMeta.lore(Collections.singletonList(Component.text(LORE_MARKER)));
// Tag as a Flying Bow via PersistentDataContainer (Panilla-legal NBT).
tagFlyingBow(bowMeta);
flyingBowItem.setItemMeta(bowMeta);
ItemStack flyingBowItem = createFlyingBowItem();
// add the recipe into the game
ShapedRecipe flyingBowRecipe = new ShapedRecipe(flyingBowKey, flyingBowItem);
@@ -64,6 +60,7 @@ public final class FlyingBowOG extends JavaPlugin implements Listener {
getServer().getPluginManager().registerEvents(new OnEntityShootBowEvent(), this);
getServer().getPluginManager().registerEvents(new OnGenericGameEvent(), this);
getServer().getPluginManager().registerEvents(new OnEntityDamageEvent(), this);
getServer().getPluginManager().registerEvents(new OnEntityDismountEvent(), this);
getServer().getPluginManager().registerEvents(new OnPrepareAnvilEvent(), this);
getServer().getPluginManager().registerEvents(new OnAnvilUpdateResultEvent(), this);
@@ -78,6 +75,33 @@ public final class FlyingBowOG extends JavaPlugin implements Listener {
}
// Builds a fresh Flying Bow: cyan name, lore marker, PDC identity tag, and a
// hidden Unbreaking I enchant that exists only for the enchantment glint. This
// is the same glint trick DiamondBank-OG uses on its Diamond Shards, and it
// clears every item validator on the stack: Unbreaking is bow-legal at level 1
// (IllegalStack only strips wrong-type or over-max enchants), HIDE_ENCHANTS
// keeps
// the tooltip clean, and the bow's identity still lives in the PDC -- so even a
// strict Panilla config that strips HideFlags only costs the glint, never the
// bow. Single source of truth for both the recipe result and /flyingbow give.
public static ItemStack createFlyingBowItem() {
ItemStack flyingBowItem = new ItemStack(Material.BOW);
ItemMeta bowMeta = flyingBowItem.getItemMeta();
bowMeta.displayName(
Component.text("Flying Bow").color(TextColor.color(0, 255, 255)).decorate(TextDecoration.ITALIC));
bowMeta.lore(Collections.singletonList(Component.text(LORE_MARKER)));
// Tag as a Flying Bow via PersistentDataContainer (Panilla-legal NBT).
tagFlyingBow(bowMeta);
// Enchantment glint only: hidden, bow-legal Unbreaking I.
bowMeta.addEnchant(Enchantment.DURABILITY, 1, false);
bowMeta.addItemFlags(ItemFlag.HIDE_ENCHANTS);
flyingBowItem.setItemMeta(bowMeta);
return flyingBowItem;
}
// Stamps a Flying Bow marker into an item's PersistentDataContainer.
public static void tagFlyingBow(ItemMeta meta) {
@@ -0,0 +1,39 @@
// This is free and unencumbered software released into the public domain.
// Authors: NotAlexNoyle.
package net.trueog.flyingbowog.Listeners;
import net.trueog.flyingbowog.NCPHook;
import org.bukkit.Color;
import org.bukkit.entity.Arrow;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.potion.PotionType;
import org.spigotmc.event.entity.EntityDismountEvent;
// Single cleanup point for the NoCheatPlus MOVING_CREATIVEFLY exemption taken in
// OnEntityShootBowEvent. EntityDismountEvent fires for every way a ride ends -- the
// arrow landing and being removed, the self-hit removal, manual dismount, or death --
// so restoring the check here guarantees the exemption never leaks past the ride.
public class OnEntityDismountEvent implements Listener {
@EventHandler
public void onEntityDismount(EntityDismountEvent event) {
if (!(event.getEntity() instanceof Player player))
return;
if (!(event.getDismounted() instanceof Arrow arrow))
return;
// Only react to our cyan, UNCRAFTABLE Flying Bow arrows.
Color color = arrow.getColor();
if (color == null || color.asRGB() != 0x00FFFF)
return;
if (arrow.getBasePotionData().getType() != PotionType.UNCRAFTABLE)
return;
NCPHook.unexemptCreativeFly(player);
}
}
@@ -5,6 +5,7 @@ package net.trueog.flyingbowog.Listeners;
import com.destroystokyo.paper.event.player.PlayerArmorChangeEvent; // Purpur 1.19
import java.util.Map;
import net.trueog.flyingbowog.FlyingBowOG;
import net.trueog.flyingbowog.NCPHook;
import net.trueog.utilitiesog.UtilitiesOG;
import org.bukkit.Bukkit;
import org.bukkit.Color;
@@ -75,6 +76,10 @@ public class OnEntityShootBowEvent implements Listener {
rideArrow.addPassenger(shooter);
// Stop NoCheatPlus from flagging the arrow ride as illegal flight
// (MOVING_CREATIVEFLY). Cleared on dismount in OnEntityDismountEvent.
NCPHook.exemptCreativeFly(shooter);
}, 1L);
// Strip Infinity from the bow (too OP for this item).
@@ -0,0 +1,101 @@
// This is free and unencumbered software released into the public domain.
// Authors: NotAlexNoyle.
package net.trueog.flyingbowog;
import java.lang.reflect.Method;
import org.bukkit.Bukkit;
import org.bukkit.entity.Player;
// Soft integration with NoCheatPlus. While a player rides a Flying Bow arrow they
// move through the air faster than survival movement allows, and NCP's CreativeFly
// check (MOVING_CREATIVEFLY) flags that as illegal flight, setting the player back or
// kicking them. We exempt that single check for the duration of the ride.
//
// NCP is an optional dependency (softdepend). The exemption API is reached by
// reflection rather than a compile-time dependency: NoCheatPlus publishes a broken
// Maven artifact (its POM points at an unpublished parent), and reflection also binds
// to whatever NCP version is actually installed at runtime. If NoCheatPlus is absent
// or its API ever changes shape, every call here is a silent no-op and the Flying Bow
// keeps working.
public final class NCPHook {
// Cached reflection handles, resolved once on first use. ready == true means
// all
// handles bound and exemption calls will be attempted.
private static boolean resolved = false;
private static boolean ready = false;
private static Method exemptMethod;
private static Method unexemptMethod;
private static Object creativeFlyCheckType;
private NCPHook() {
}
// Exempt the player from MOVING_CREATIVEFLY while riding a Flying Bow arrow.
public static void exemptCreativeFly(Player player) {
if (!resolve())
return;
try {
exemptMethod.invoke(null, player, creativeFlyCheckType);
} catch (Throwable ignored) {
// NCP unavailable or API mismatch: leave checking as-is.
}
}
// Restore MOVING_CREATIVEFLY checking once the ride ends.
public static void unexemptCreativeFly(Player player) {
if (!resolve())
return;
try {
unexemptMethod.invoke(null, player, creativeFlyCheckType);
} catch (Throwable ignored) {
// NCP unavailable or API mismatch: leave checking as-is.
}
}
// Bind the NCP exemption API on first use. Returns whether the hook is usable.
private static synchronized boolean resolve() {
if (resolved)
return ready;
resolved = true;
if (Bukkit.getPluginManager().getPlugin("NoCheatPlus") == null)
return false;
try {
Class<?> checkType = Class.forName("fr.neatmonster.nocheatplus.checks.CheckType");
Class<?> exemptionManager = Class.forName("fr.neatmonster.nocheatplus.hooks.NCPExemptionManager");
creativeFlyCheckType = Enum.valueOf(checkType.asSubclass(Enum.class), "MOVING_CREATIVEFLY");
exemptMethod = exemptionManager.getMethod("exemptPermanently", Player.class, checkType);
unexemptMethod = exemptionManager.getMethod("unexempt", Player.class, checkType);
ready = true;
} catch (Throwable ignored) {
// Missing classes / renamed API: disable the hook quietly.
ready = false;
}
return ready;
}
}
+1
View File
@@ -4,6 +4,7 @@ main: net.trueog.flyingbowog.FlyingBowOG
authors: [barny1094875, NotAlexNoyle]
api-version: 1.19
depend: [Item-NBT-API]
softdepend: [NoCheatPlus]
commands:
flyingbow:
usage: /flyingbow