From 14564dde5d41ad02c584cea7f6a904abf1c52561 Mon Sep 17 00:00:00 2001 From: bundabrg Date: Mon, 15 Jun 2020 16:21:28 +0800 Subject: [PATCH] Implement annotation based registration for EventManager The EventManager will now allow classes to be registered and all methods of the class annotated with @Event will be added as event handlers. PluginManager provides a proxy to some of the registration functions in EventManager to allow it to track EventHandlers that belong to a plugin. --- .../connector/event/EventManager.java | 59 ++++++++++++++ .../{plugin => event}/annotations/Event.java | 2 +- .../connector/plugin/GeyserPlugin.java | 76 +++++++------------ 3 files changed, 88 insertions(+), 49 deletions(-) rename connector/src/main/java/org/geysermc/connector/{plugin => event}/annotations/Event.java (97%) diff --git a/connector/src/main/java/org/geysermc/connector/event/EventManager.java b/connector/src/main/java/org/geysermc/connector/event/EventManager.java index 1d3a1ad98..7a34d34f8 100644 --- a/connector/src/main/java/org/geysermc/connector/event/EventManager.java +++ b/connector/src/main/java/org/geysermc/connector/event/EventManager.java @@ -29,10 +29,15 @@ package org.geysermc.connector.event; import lombok.AllArgsConstructor; import lombok.Getter; import org.geysermc.connector.GeyserConnector; +import org.geysermc.connector.event.annotations.Event; import org.geysermc.connector.event.events.CancellableGeyserEvent; import org.geysermc.connector.event.events.GeyserEvent; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.ArrayList; import java.util.HashMap; +import java.util.List; import java.util.Map; import java.util.PriorityQueue; @@ -40,6 +45,7 @@ import java.util.PriorityQueue; @AllArgsConstructor public class EventManager { private final Map, PriorityQueue>> eventHandlers = new HashMap<>(); + private final Map>> classEventHandlers = new HashMap<>(); private final GeyserConnector connector; @@ -125,6 +131,59 @@ public class EventManager { } } + /** + * Register all Events contained in an instantiated class. The methods must be annotated by @Event + */ + public EventHandler[] registerEvents(Object obj) { + List> handlers = new ArrayList<>(); + for (Method method : obj.getClass().getMethods()) { + Event eventAnnotation = method.getAnnotation(Event.class); + + // Check that the method is annotated with @Event + if (eventAnnotation == null) { + continue; + } + + // Make sure it only has a single Event parameter + if (method.getParameterCount() != 2 || !GeyserEvent.class.isAssignableFrom(method.getParameters()[1].getType())) { + continue; + } + + //noinspection unchecked + EventHandler handler = on((Class)method.getParameters()[1].getType(), (ctx, event) -> { + try { + method.invoke(obj, ctx, event); + } catch (IllegalAccessException | InvocationTargetException e) { + e.printStackTrace(); + } + }, eventAnnotation.priority(), eventAnnotation.ignoreCancelled()); + + if (!classEventHandlers.containsKey(obj.getClass())) { + classEventHandlers.put(obj, new ArrayList<>()); + } + + classEventHandlers.get(obj).add(handler); + handlers.add(handler); + } + + return handlers.toArray(new EventHandler[0]); + } + + /** + * Unregister all events in class + */ + public void unregisterEvents(Object obj) { + if (!classEventHandlers.containsKey(obj)) { + return; + } + + for (EventHandler handler : classEventHandlers.get(obj)) { + unregister(handler); + } + + classEventHandlers.remove(obj); + } + @AllArgsConstructor public static class Context implements EventContext { private final EventManager manager; diff --git a/connector/src/main/java/org/geysermc/connector/plugin/annotations/Event.java b/connector/src/main/java/org/geysermc/connector/event/annotations/Event.java similarity index 97% rename from connector/src/main/java/org/geysermc/connector/plugin/annotations/Event.java rename to connector/src/main/java/org/geysermc/connector/event/annotations/Event.java index 442b88ad0..1261baafd 100644 --- a/connector/src/main/java/org/geysermc/connector/plugin/annotations/Event.java +++ b/connector/src/main/java/org/geysermc/connector/event/annotations/Event.java @@ -24,7 +24,7 @@ * */ -package org.geysermc.connector.plugin.annotations; +package org.geysermc.connector.event.annotations; import org.geysermc.connector.event.EventHandler; diff --git a/connector/src/main/java/org/geysermc/connector/plugin/GeyserPlugin.java b/connector/src/main/java/org/geysermc/connector/plugin/GeyserPlugin.java index b706e3dbe..ea51249b6 100644 --- a/connector/src/main/java/org/geysermc/connector/plugin/GeyserPlugin.java +++ b/connector/src/main/java/org/geysermc/connector/plugin/GeyserPlugin.java @@ -30,13 +30,10 @@ import lombok.AllArgsConstructor; import lombok.Getter; import org.geysermc.connector.event.EventHandler; import org.geysermc.connector.event.events.GeyserEvent; -import org.geysermc.connector.plugin.annotations.Event; -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; import java.util.ArrayList; -import java.util.HashMap; -import java.util.Map; +import java.util.Arrays; +import java.util.List; /** * All GeyserPlugins extend from this @@ -44,67 +41,50 @@ import java.util.Map; @Getter @AllArgsConstructor public abstract class GeyserPlugin { - private final Map>> classEventHandlers = new HashMap<>(); + // List of EventHandlers associated with this Plugin + private final List> pluginEventHandlers = new ArrayList<>(); private final PluginManager pluginManager; private final PluginClassLoader pluginClassLoader; + // We provide some methods already provided in EventManager as we want to keep track of which EventHandlers + // belong to a particular plugin. That way we can unregister them all easily. + /** - * Register all Events contained in a class + * Create a new EventHandler using an Executor */ - public void registerEvents(Object obj) { - for (Method method : obj.getClass().getMethods()) { - Event eventAnnotation = method.getAnnotation(Event.class); + public EventHandler on(Class cls, EventHandler.Executor executor, int priority, boolean ignoreCancelled) { + EventHandler handler = pluginManager.getConnector().getEventManager().on(cls, executor, priority, ignoreCancelled); + pluginEventHandlers.add(handler); + return handler; + } - // Check that the method is annotated with @Event - if (eventAnnotation == null) { - continue; - } + public EventHandler on(Class cls, EventHandler.Executor executor) { + return on(cls, executor, EventHandler.PRIORITY.NORMAL, true); + } - // Make sure it only has a single Event parameter - if (method.getParameterCount() != 2 || !GeyserEvent.class.isAssignableFrom(method.getParameters()[1].getType())) { - continue; - } + public EventHandler on(Class cls, EventHandler.Executor executor, boolean ignoreCancelled) { + return on(cls, executor, EventHandler.PRIORITY.NORMAL, ignoreCancelled); + } - //noinspection unchecked - EventHandler handler = pluginManager.getConnector().getEventManager() - .on((Class)method.getParameters()[1].getType(), (ctx, event) -> { - try { - method.invoke(obj, ctx, event); - } catch (IllegalAccessException | InvocationTargetException e) { - e.printStackTrace(); - } - }); - - if (!classEventHandlers.containsKey(obj.getClass())) { - classEventHandlers.put(obj, new ArrayList<>()); - } - - classEventHandlers.get(obj).add(handler); - } + public EventHandler on(Class cls, EventHandler.Executor executor, int priority) { + return on(cls, executor, priority, true); } /** - * Unregister events in class + * Register all Events contained in an instantiated class. The methods must be annotated by @Event */ - public void unregisterEvents(Object obj) { - if (!classEventHandlers.containsKey(obj)) { - return; - } - - for (EventHandler handler : classEventHandlers.get(obj)) { - pluginManager.getConnector().getEventManager().unregister(handler); - } - - classEventHandlers.remove(obj); + public void registerEvents(Object obj) { + EventHandler[] handlers = pluginManager.getConnector().getEventManager().registerEvents(obj); + pluginEventHandlers.addAll(Arrays.asList(handlers)); } /** * Unregister all events for a plugin */ - public void unregisterPluginEvents(Class plugin) { - for (Object obj : classEventHandlers.keySet()) { - unregisterEvents(obj); + public void unregisterAllEvents() { + for (EventHandler handler : pluginEventHandlers) { + pluginManager.getConnector().getEventManager().unregister(handler); } } }