From a9c72393f5d24cc90bedbbba3efc95eefaaca78a Mon Sep 17 00:00:00 2001 From: PseudoKnight Date: Sun, 14 Jul 2024 04:34:01 -0700 Subject: [PATCH] Dynamically register inventory events Fixes PrepareGrindstoneEvent failing to register in versions prior to 1.19.3. Also fixes some inventory event documentation and slot counts in old smithing events from previous commit. --- .../abstraction/bukkit/BukkitConvertor.java | 2 +- .../drivers/BukkitInventoryListener.java | 8 +- .../commandhelper/CommandHelperPlugin.java | 76 +++++++++---------- .../com/laytonsmith/core/events/Driver.java | 2 +- .../core/events/drivers/InventoryEvents.java | 15 ++-- 5 files changed, 51 insertions(+), 52 deletions(-) diff --git a/src/main/java/com/laytonsmith/abstraction/bukkit/BukkitConvertor.java b/src/main/java/com/laytonsmith/abstraction/bukkit/BukkitConvertor.java index 7c513bbee..ee1d6eee1 100644 --- a/src/main/java/com/laytonsmith/abstraction/bukkit/BukkitConvertor.java +++ b/src/main/java/com/laytonsmith/abstraction/bukkit/BukkitConvertor.java @@ -357,7 +357,7 @@ public MCMetadataValue GetMetadataValue(Object value, MCPlugin plugin) { public void Startup(CommandHelperPlugin chp) { chp.registerEvents(BLOCK_LISTENER); chp.registerEvents(ENTITY_LISTENER); - chp.registerEvents(INVENTORY_LISTENER); + chp.registerEventsDynamic(INVENTORY_LISTENER); chp.registerEvents(PLAYER_LISTENER); chp.registerEvents(SERVER_LISTENER); chp.registerEvents(VEHICLE_LISTENER); diff --git a/src/main/java/com/laytonsmith/abstraction/bukkit/events/drivers/BukkitInventoryListener.java b/src/main/java/com/laytonsmith/abstraction/bukkit/events/drivers/BukkitInventoryListener.java index b6a594821..fdd54e952 100644 --- a/src/main/java/com/laytonsmith/abstraction/bukkit/events/drivers/BukkitInventoryListener.java +++ b/src/main/java/com/laytonsmith/abstraction/bukkit/events/drivers/BukkitInventoryListener.java @@ -13,8 +13,10 @@ import com.laytonsmith.abstraction.bukkit.events.BukkitInventoryEvents.BukkitMCPrepareItemCraftEvent; import com.laytonsmith.abstraction.bukkit.events.BukkitInventoryEvents.BukkitMCPrepareItemEnchantEvent; import com.laytonsmith.abstraction.bukkit.events.BukkitInventoryEvents.BukkitMCPrepareSmithingEvent; +import com.laytonsmith.annotations.EventIdentifier; import com.laytonsmith.core.events.Driver; import com.laytonsmith.core.events.EventUtils; +import org.bukkit.event.Event; import org.bukkit.event.EventHandler; import org.bukkit.event.EventPriority; import org.bukkit.event.Listener; @@ -99,9 +101,9 @@ public void onPreSmithing(PrepareSmithingEvent event) { EventUtils.TriggerListener(Driver.ITEM_PRE_SMITHING, "item_pre_smithing", ps); } - @EventHandler(priority = EventPriority.LOWEST) - public void onPreGrindstone(PrepareGrindstoneEvent event) { - BukkitMCPrepareGrindstoneEvent pg = new BukkitInventoryEvents.BukkitMCPrepareGrindstoneEvent(event); + @EventIdentifier(event = Driver.ITEM_PRE_GRINDSTONE, className = "org.bukkit.event.inventory.PrepareGrindstoneEvent") + public void onPreGrindstone(Event event) { + BukkitMCPrepareGrindstoneEvent pg = new BukkitInventoryEvents.BukkitMCPrepareGrindstoneEvent((PrepareGrindstoneEvent) event); EventUtils.TriggerListener(Driver.ITEM_PRE_GRINDSTONE, "item_pre_grindstone", pg); } } diff --git a/src/main/java/com/laytonsmith/commandhelper/CommandHelperPlugin.java b/src/main/java/com/laytonsmith/commandhelper/CommandHelperPlugin.java index 784c8be44..061728b14 100644 --- a/src/main/java/com/laytonsmith/commandhelper/CommandHelperPlugin.java +++ b/src/main/java/com/laytonsmith/commandhelper/CommandHelperPlugin.java @@ -431,20 +431,26 @@ public void registerEvents(Listener listener) { getServer().getPluginManager().registerEvents(listener, this); } - /* - * This method is based on Bukkit's JavaPluginLoader:createRegisteredListeners - * Part of this code would be run normally using the other register method + /** + * Dynamically registers events in a Listener class. + * Registers all methods annotated with @EventHandler. + * Registers methods annotated with @EventIdentifier if the event exists in this version according to the Driver. + * This method is based on Bukkit's JavaPluginLoader:createRegisteredListeners. + * Part of this code would be run normally using the other register method. + * + * @param listener */ public void registerEventsDynamic(Listener listener) { for(final java.lang.reflect.Method method : listener.getClass().getMethods()) { EventIdentifier identifier = method.getAnnotation(EventIdentifier.class); EventHandler defaultHandler = method.getAnnotation(EventHandler.class); EventPriority priority = EventPriority.LOWEST; - Class eventClass; + final Class eventClass; if(defaultHandler != null) { priority = defaultHandler.priority(); } if(identifier == null) { + // Look for normal EventHandler if(defaultHandler != null && method.getParameterTypes().length == 1) { try { eventClass = (Class) method.getParameterTypes()[0]; @@ -455,6 +461,7 @@ public void registerEventsDynamic(Listener listener) { continue; } } else { + // Dynamically register EventIdentifier if(!identifier.event().existsInCurrent()) { continue; } @@ -468,47 +475,32 @@ public void registerEventsDynamic(Listener listener) { continue; } } - HandlerList handler; - try { - handler = (HandlerList) ReflectionUtils.invokeMethod(eventClass, null, "getHandlerList"); - } catch (ReflectionUtils.ReflectionException ref) { - Class eventSuperClass = eventClass.getSuperclass(); - if(eventSuperClass != null) { - try { - handler = (HandlerList) ReflectionUtils.invokeMethod(eventSuperClass, null, "getHandlerList"); - } catch (ReflectionUtils.ReflectionException refInner) { - MSLog.GetLogger().e(MSLog.Tags.RUNTIME, "Could not listen for " + identifier.event().name() - + " because the handler for class " + identifier.className() - + " could not be found. An attempt has already been made to find the" - + " correct handler, but" + eventSuperClass.getName() - + " did not have it either. Please report this on the bug tracker.", - Target.UNKNOWN); - continue; - } - } else { - MSLog.GetLogger().e(MSLog.Tags.RUNTIME, "Could not listen for " + identifier.event().name() - + " because the handler for class " + identifier.className() - + " could not be found. An attempt has already been made to find the" - + " correct handler, but no superclass could be found." - + " Please report this on the bug tracker.", - Target.UNKNOWN); - continue; + HandlerList handler = null; + Class handlerClass = eventClass; + while(handlerClass != null) { + try { + handler = ReflectionUtils.invokeMethod(handlerClass, null, "getHandlerList"); + break; + } catch (ReflectionUtils.ReflectionException ref) { + handlerClass = handlerClass.getSuperclass(); } } - final Class finalEventClass = eventClass; - EventExecutor executor = new EventExecutor() { - @Override - public void execute(Listener listener, Event event) throws EventException { - try { - if(!finalEventClass.isAssignableFrom(event.getClass())) { - return; - } - method.invoke(listener, event); - } catch (InvocationTargetException ex) { - throw new EventException(ex.getCause()); - } catch (Throwable t) { - throw new EventException(t); + if(handler == null) { + MSLog.GetLogger().e(MSLog.Tags.RUNTIME, "Could not listen for " + eventClass.getName() + + " because the handler could not be found. Please report this on the bug tracker.", + Target.UNKNOWN); + continue; + } + EventExecutor executor = (thisListener, event) -> { + try { + if(!eventClass.isAssignableFrom(event.getClass())) { + return; } + method.invoke(thisListener, event); + } catch (InvocationTargetException ex) { + throw new EventException(ex.getCause()); + } catch (Throwable t) { + throw new EventException(t); } }; if(this.getServer().getPluginManager().useTimings()) { diff --git a/src/main/java/com/laytonsmith/core/events/Driver.java b/src/main/java/com/laytonsmith/core/events/Driver.java index 4fadc8061..3bddc83bc 100644 --- a/src/main/java/com/laytonsmith/core/events/Driver.java +++ b/src/main/java/com/laytonsmith/core/events/Driver.java @@ -69,7 +69,7 @@ public enum Driver { ITEM_PRE_ENCHANT, ITEM_PRE_ANVIL, ITEM_PRE_SMITHING, - ITEM_PRE_GRINDSTONE, + ITEM_PRE_GRINDSTONE(MCVersion.MC1_19_3), /** * Player events */ diff --git a/src/main/java/com/laytonsmith/core/events/drivers/InventoryEvents.java b/src/main/java/com/laytonsmith/core/events/drivers/InventoryEvents.java index 2b892c03b..dd43fdf6b 100644 --- a/src/main/java/com/laytonsmith/core/events/drivers/InventoryEvents.java +++ b/src/main/java/com/laytonsmith/core/events/drivers/InventoryEvents.java @@ -83,7 +83,8 @@ public String docs() { + " | creativeclick: true/false if this action could only be performed in creative mode" + " | slot: the slot number | rawslot: the slot number in whole inventory window | slottype" + " | slotitem | inventorytype | inventorysize: number of slots in opened inventory | cursoritem" - + " | inventory: all the items in the (top) inventory | clicktype | action}" + + " | inventory: all the items in the (top) inventory | clicktype | action" + + " | hotbarbutton: the hotbar slot (0-8) corresponding to the number key pressed, or -1 if none.}" + " {slotitem: the item currently in the clicked slot | cursoritem: the item on the cursor" + " (may cause unexpected behavior)}" + " {}"; @@ -1089,11 +1090,12 @@ public String getName() { @Override public String docs() { return "{}" - + " Fires when a recipe is formed in a smithing table, but the result has not yet been clicked." + + " Fires when a slot is clicked in a smithing table other than the result." + + " Can fire multiple times per click." + " { player: the player using the smithing table." + " | first_item: the first item being used in the recipe." + " | second_item: the second item being used in the recipe." - + " | third_item: the third item being used in the recipe." + + " | third_item: the third item being used in the recipe. (MC 1.20+)" + " | recipe: information about the formed recipe, or null if there's not one." + " | result: the result of the recipe. }" + " { result: the result of the smithing table recipe. While the result will appear on the" @@ -1123,7 +1125,9 @@ public Map evaluate(BindableEvent event) throws EventException { ret.put("player", new CString(e.getPlayer().getName(), Target.UNKNOWN)); ret.put("first_item", ObjectGenerator.GetGenerator().item(smithing.getInputTemplate(), Target.UNKNOWN)); ret.put("second_item", ObjectGenerator.GetGenerator().item(smithing.getInputEquipment(), Target.UNKNOWN)); - ret.put("third_item", ObjectGenerator.GetGenerator().item(smithing.getInputMaterial(), Target.UNKNOWN)); + if(Static.getServer().getMinecraftVersion().gte(MCVersion.MC1_20)) { + ret.put("third_item", ObjectGenerator.GetGenerator().item(smithing.getInputMaterial(), Target.UNKNOWN)); + } ret.put("recipe", ObjectGenerator.GetGenerator().recipe(smithing.getRecipe(), Target.UNKNOWN)); ret.put("result", ObjectGenerator.GetGenerator().item(smithing.getResult(), Target.UNKNOWN)); @@ -1167,7 +1171,8 @@ public String getName() { @Override public String docs() { return "{}" - + " Fires when a recipe is formed in a grindstone, but the result has not yet been clicked." + + " Fires when a slot is clicked in a grindstone other than the result. (MC 1.19.3+)" + + " Can fire multiple times per click." + " { player: the player using the grindstone." + " | upper_item: the first item being used in the recipe." + " | lower_item: the second item being used in the recipe."