From 6056e962d696a645c7df58a0041d0e8233e4cf81 Mon Sep 17 00:00:00 2001 From: KingRainbow44 Date: Sat, 23 Apr 2022 01:58:37 -0400 Subject: [PATCH] Implement an event handler --- .../emu/grasscutter/plugin/PluginManager.java | 44 +++++++++++++++++-- .../grasscutter/server/event/Cancellable.java | 8 ++++ .../emu/grasscutter/server/event/Event.java | 33 ++++++++++++++ .../server/event/EventHandler.java | 11 +++++ .../grasscutter/server/event/Listener.java | 7 +++ .../grasscutter/server/event/ServerEvent.java | 17 +++++++ 6 files changed, 116 insertions(+), 4 deletions(-) create mode 100644 src/main/java/emu/grasscutter/server/event/Cancellable.java create mode 100644 src/main/java/emu/grasscutter/server/event/Event.java create mode 100644 src/main/java/emu/grasscutter/server/event/EventHandler.java create mode 100644 src/main/java/emu/grasscutter/server/event/Listener.java create mode 100644 src/main/java/emu/grasscutter/server/event/ServerEvent.java diff --git a/src/main/java/emu/grasscutter/plugin/PluginManager.java b/src/main/java/emu/grasscutter/plugin/PluginManager.java index 3e55e4ad8..7b54f460f 100644 --- a/src/main/java/emu/grasscutter/plugin/PluginManager.java +++ b/src/main/java/emu/grasscutter/plugin/PluginManager.java @@ -1,23 +1,25 @@ package emu.grasscutter.plugin; import emu.grasscutter.Grasscutter; +import emu.grasscutter.server.event.Event; +import emu.grasscutter.server.event.EventHandler; +import emu.grasscutter.server.event.Listener; import emu.grasscutter.utils.Utils; +import org.reflections.Reflections; import java.io.File; import java.io.InputStreamReader; import java.lang.reflect.Method; import java.net.URL; import java.net.URLClassLoader; -import java.util.Arrays; -import java.util.HashMap; -import java.util.List; -import java.util.Map; +import java.util.*; /** * Manages the server's plugins & the event system. */ public final class PluginManager { private final Map plugins = new HashMap<>(); + private final Map> listeners = new HashMap<>(); public PluginManager() { this.loadPlugins(); // Load all plugins from the plugins directory. @@ -113,4 +115,38 @@ public final class PluginManager { plugin.onDisable(); }); } + + /** + * Registers a plugin's event listener. + * @param plugin The plugin instance. + * @param listener The event listener. + */ + public void registerListener(Plugin plugin, Listener listener) { + this.listeners.computeIfAbsent(plugin, k -> new ArrayList<>()).add(listener); + } + + /** + * Invoke the provided event on all registered event listeners. + * @param event The event to invoke. + */ + public void invokeEvent(Event event) { + this.listeners.values().stream() + .flatMap(Collection::stream) + .forEach(listener -> this.invokeOnListener(listener, event)); + } + + /** + * Attempts to invoke the event on the provided listener. + */ + private void invokeOnListener(Listener listener, Event event) { + try { + Class listenerClass = listener.getClass(); + Method[] methods = listenerClass.getMethods(); + for (Method method : methods) { + if(!method.isAnnotationPresent(EventHandler.class)) return; + if(!method.getParameterTypes()[0].isAssignableFrom(event.getClass())) return; + method.invoke(listener, event); + } + } catch (Exception ignored) { } + } } \ No newline at end of file diff --git a/src/main/java/emu/grasscutter/server/event/Cancellable.java b/src/main/java/emu/grasscutter/server/event/Cancellable.java new file mode 100644 index 000000000..0296f0b36 --- /dev/null +++ b/src/main/java/emu/grasscutter/server/event/Cancellable.java @@ -0,0 +1,8 @@ +package emu.grasscutter.server.event; + +/** + * Implementing this interface marks an event as cancellable. + */ +public interface Cancellable { + void cancel(); +} diff --git a/src/main/java/emu/grasscutter/server/event/Event.java b/src/main/java/emu/grasscutter/server/event/Event.java new file mode 100644 index 000000000..7dd67b84d --- /dev/null +++ b/src/main/java/emu/grasscutter/server/event/Event.java @@ -0,0 +1,33 @@ +package emu.grasscutter.server.event; + +import emu.grasscutter.Grasscutter; + +/** + * A generic server event. + */ +public abstract class Event { + private boolean cancelled = false; + + /** + * Return the cancelled state of the event. + */ + public boolean isCanceled() { + return this.cancelled; + } + + /** + * Cancels the event if possible. + */ + public void cancel() throws IllegalAccessException { + if(!(this instanceof Cancellable)) + throw new IllegalAccessException("Event is not cancellable."); + this.cancelled = true; + } + + /** + * Pushes this event to all listeners. + */ + public void call() { + Grasscutter.getPluginManager().invokeEvent(this); + } +} diff --git a/src/main/java/emu/grasscutter/server/event/EventHandler.java b/src/main/java/emu/grasscutter/server/event/EventHandler.java new file mode 100644 index 000000000..d924933f2 --- /dev/null +++ b/src/main/java/emu/grasscutter/server/event/EventHandler.java @@ -0,0 +1,11 @@ +package emu.grasscutter.server.event; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + +/** + * Declares a class as an event listener/handler. + */ +@Retention(RetentionPolicy.RUNTIME) +public @interface EventHandler { +} \ No newline at end of file diff --git a/src/main/java/emu/grasscutter/server/event/Listener.java b/src/main/java/emu/grasscutter/server/event/Listener.java new file mode 100644 index 000000000..2949cfe4a --- /dev/null +++ b/src/main/java/emu/grasscutter/server/event/Listener.java @@ -0,0 +1,7 @@ +package emu.grasscutter.server.event; + +/** + * Implementing this interface declares a class as an event listener. + */ +public interface Listener { +} diff --git a/src/main/java/emu/grasscutter/server/event/ServerEvent.java b/src/main/java/emu/grasscutter/server/event/ServerEvent.java new file mode 100644 index 000000000..e87abae0d --- /dev/null +++ b/src/main/java/emu/grasscutter/server/event/ServerEvent.java @@ -0,0 +1,17 @@ +package emu.grasscutter.server.event; + +/** + * An event that is related to the internals of the server. + */ +public abstract class ServerEvent extends Event { + protected final Type type; + + public ServerEvent(Type type) { + this.type = type; + } + + public enum Type { + DISPATCH, + GAME + } +}