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.
This commit is contained in:
bundabrg 2020-06-15 16:21:28 +08:00
parent ef20c0fa3a
commit 14564dde5d
3 changed files with 88 additions and 49 deletions

View file

@ -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<Class<? extends GeyserEvent>, PriorityQueue<EventHandler<? extends GeyserEvent>>> eventHandlers = new HashMap<>();
private final Map<Object, ArrayList<EventHandler<?>>> 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<EventHandler<?>> 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<? extends GeyserEvent>)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;

View file

@ -24,7 +24,7 @@
*
*/
package org.geysermc.connector.plugin.annotations;
package org.geysermc.connector.event.annotations;
import org.geysermc.connector.event.EventHandler;

View file

@ -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<Object, ArrayList<EventHandler<?>>> classEventHandlers = new HashMap<>();
// List of EventHandlers associated with this Plugin
private final List<EventHandler<?>> 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 <T extends GeyserEvent> EventHandler<T> on(Class<? extends T> cls, EventHandler.Executor<T> executor, int priority, boolean ignoreCancelled) {
EventHandler<T> 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 <T extends GeyserEvent> EventHandler<T> on(Class<? extends T> cls, EventHandler.Executor<T> 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 <T extends GeyserEvent> EventHandler<T> on(Class<? extends T> cls, EventHandler.Executor<T> executor, boolean ignoreCancelled) {
return on(cls, executor, EventHandler.PRIORITY.NORMAL, ignoreCancelled);
}
//noinspection unchecked
EventHandler<?> handler = pluginManager.getConnector().getEventManager()
.on((Class<? extends GeyserEvent>)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 <T extends GeyserEvent> EventHandler<T> on(Class<? extends T> cls, EventHandler.Executor<T> 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);
}
}
}