Skip to content

Commit

Permalink
Dynamically register inventory events
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
PseudoKnight committed Jul 14, 2024
1 parent 2a31201 commit a9c7239
Show file tree
Hide file tree
Showing 5 changed files with 51 additions and 52 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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<? extends Event> eventClass;
final Class<? extends Event> eventClass;
if(defaultHandler != null) {
priority = defaultHandler.priority();
}
if(identifier == null) {
// Look for normal EventHandler
if(defaultHandler != null && method.getParameterTypes().length == 1) {
try {
eventClass = (Class<? extends Event>) method.getParameterTypes()[0];
Expand All @@ -455,6 +461,7 @@ public void registerEventsDynamic(Listener listener) {
continue;
}
} else {
// Dynamically register EventIdentifier
if(!identifier.event().existsInCurrent()) {
continue;
}
Expand All @@ -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<? extends Event> 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()) {
Expand Down
2 changes: 1 addition & 1 deletion src/main/java/com/laytonsmith/core/events/Driver.java
Original file line number Diff line number Diff line change
Expand Up @@ -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
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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)}"
+ " {}";
Expand Down Expand Up @@ -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"
Expand Down Expand Up @@ -1123,7 +1125,9 @@ public Map<String, Mixed> 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));

Expand Down Expand Up @@ -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."
Expand Down

0 comments on commit a9c7239

Please sign in to comment.