Implement Event Management and move Plugins to utilize that

Instead of plugins being the focus Geyser instead implements an Event Management system that can be used internally. Plugins are then able to utilize this through the convenience of an external jar and registering annotated classes.
This commit is contained in:
bundabrg 2020-06-15 10:08:20 +08:00
parent c88469e322
commit ef20c0fa3a
12 changed files with 405 additions and 168 deletions

View file

@ -35,6 +35,7 @@ import org.geysermc.common.AuthType;
import org.geysermc.common.PlatformType;
import org.geysermc.connector.bootstrap.GeyserBootstrap;
import org.geysermc.connector.command.CommandManager;
import org.geysermc.connector.event.EventManager;
import org.geysermc.connector.metrics.Metrics;
import org.geysermc.connector.network.ConnectorServerEventHandler;
import org.geysermc.connector.network.remote.RemoteServer;
@ -50,8 +51,8 @@ import org.geysermc.connector.network.translators.world.block.BlockTranslator;
import org.geysermc.connector.network.translators.effect.EffectRegistry;
import org.geysermc.connector.network.translators.world.block.entity.BlockEntityTranslator;
import org.geysermc.connector.plugin.PluginManager;
import org.geysermc.connector.plugin.events.DisableEvent;
import org.geysermc.connector.plugin.events.EnableEvent;
import org.geysermc.connector.event.events.DisableEvent;
import org.geysermc.connector.event.events.EnableEvent;
import org.geysermc.connector.utils.DimensionUtils;
import org.geysermc.connector.utils.DockerCheck;
import org.geysermc.connector.utils.LocaleUtils;
@ -92,6 +93,7 @@ public class GeyserConnector {
private PlatformType platformType;
private GeyserBootstrap bootstrap;
private final EventManager eventManager;
private final PluginManager pluginManager;
private Metrics metrics;
@ -102,6 +104,7 @@ public class GeyserConnector {
instance = this;
this.bootstrap = bootstrap;
this.eventManager = new EventManager(this);
this.pluginManager = new PluginManager(this, new File(bootstrap.getDataFolder(), "plugins"));
GeyserLogger logger = bootstrap.getGeyserLogger();
@ -163,7 +166,7 @@ public class GeyserConnector {
}
// Trigger all plugins Enable Events
pluginManager.triggerEvent(new EnableEvent());
eventManager.triggerEvent(new EnableEvent());
double completeTime = (System.currentTimeMillis() - startupTime) / 1000D;
logger.info(String.format("Done (%ss)! Run /geyser help for help!", new DecimalFormat("#.###").format(completeTime)));
@ -174,7 +177,7 @@ public class GeyserConnector {
shuttingDown = true;
// Trigger all plugins Disable Events
pluginManager.triggerEvent(new DisableEvent());
eventManager.triggerEvent(new DisableEvent());
if (players.size() >= 1) {
bootstrap.getGeyserLogger().info("Kicking " + players.size() + " player(s)");

View file

@ -0,0 +1,31 @@
/*
* Copyright (c) 2019-2020 GeyserMC. http://geysermc.org
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
* @author GeyserMC
* @link https://github.com/GeyserMC/Geyser
*
*/
package org.geysermc.connector.event;
public interface EventContext {
void unregister();
}

View file

@ -0,0 +1,70 @@
/*
* Copyright (c) 2019-2020 GeyserMC. http://geysermc.org
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
* @author GeyserMC
* @link https://github.com/GeyserMC/Geyser
*
*/
package org.geysermc.connector.event;
import jdk.nashorn.internal.ir.annotations.Immutable;
import lombok.AllArgsConstructor;
import lombok.Getter;
import org.geysermc.connector.event.events.GeyserEvent;
import java.util.Comparator;
@Getter
@AllArgsConstructor
public class EventHandler<T extends GeyserEvent> implements Comparator<EventHandler<T>>, Comparable<EventHandler<T>> {
public final Class<? extends T> eventClass;
public final Executor<T> executor;
public final int priority;
public final boolean ignoreCancelled;
public void execute(EventContext ctx, T event) {
executor.run(ctx, event);
}
@Override
public int compare(EventHandler<T> left, EventHandler<T> right) {
return left.getPriority() - right.getPriority();
}
@Override
public int compareTo(EventHandler<T> other) {
return getPriority() - other.getPriority();
}
public interface Executor<T extends GeyserEvent> {
void run(EventContext ctx, T event);
}
@Immutable
public static final class PRIORITY {
public final static int LOWEST = 10;
public final static int LOW = 4;
public final static int NORMAL = 50;
public final static int HIGH = 60;
public final static int HIGHEST = 90;
}
}

View file

@ -0,0 +1,141 @@
/*
* Copyright (c) 2019-2020 GeyserMC. http://geysermc.org
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
* @author GeyserMC
* @link https://github.com/GeyserMC/Geyser
*
*/
package org.geysermc.connector.event;
import lombok.AllArgsConstructor;
import lombok.Getter;
import org.geysermc.connector.GeyserConnector;
import org.geysermc.connector.event.events.CancellableGeyserEvent;
import org.geysermc.connector.event.events.GeyserEvent;
import java.util.HashMap;
import java.util.Map;
import java.util.PriorityQueue;
@Getter
@AllArgsConstructor
public class EventManager {
private final Map<Class<? extends GeyserEvent>, PriorityQueue<EventHandler<? extends GeyserEvent>>> eventHandlers = new HashMap<>();
private final GeyserConnector connector;
/**
* Trigger a new event
*
* This will be executed with all registered handlers in order of priority
*/
public void triggerEvent(GeyserEvent event) {
if (!eventHandlers.containsKey(event.getClass())) {
return;
}
for (EventHandler<? extends GeyserEvent> handler : eventHandlers.get(event.getClass())) {
Context ctx = new Context(this, handler);
//noinspection unchecked
((EventHandler<GeyserEvent>)handler).execute(ctx, event);
}
}
/**
* Trigger a new cancellable event
*
* This will be executed with all registered handlers in order of priority ignoring those who
* do not wish to process events that are cancelled
*/
public void triggerEvent(CancellableGeyserEvent event) {
if (!eventHandlers.containsKey(event.getClass())) {
return;
}
boolean cancelled = event.isCancelled();
for (EventHandler<? extends GeyserEvent> handler : eventHandlers.get(event.getClass())) {
if (!cancelled || !handler.isIgnoreCancelled()) {
Context ctx = new Context(this, handler);
//noinspection unchecked
((EventHandler<GeyserEvent>) handler).execute(ctx, event);
cancelled = event.isCancelled();
}
}
}
/**
* Create a new EventHandler using an Executor
*/
public <T extends GeyserEvent> EventHandler<T> on(Class<? extends T> cls, EventHandler.Executor<T> executor, int priority, boolean ignoreCancelled) {
EventHandler<T> handler = new EventHandler<>(cls, executor, priority, ignoreCancelled);
register(handler);
return handler;
}
public <T extends GeyserEvent> EventHandler<T> on(Class<? extends T> cls, EventHandler.Executor<T> executor) {
return on(cls, executor, EventHandler.PRIORITY.NORMAL, true);
}
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);
}
public <T extends GeyserEvent> EventHandler<T> on(Class<? extends T> cls, EventHandler.Executor<T> executor, int priority) {
return on(cls, executor, priority, true);
}
/**
* Register an EventHandler
*/
public void register(EventHandler<?> handler) {
if (!eventHandlers.containsKey(handler.getEventClass())) {
eventHandlers.put(handler.getEventClass(), new PriorityQueue<>());
}
eventHandlers.get(handler.getEventClass()).add(handler);
}
/**
* Unregister an EventHandler
*/
public void unregister(EventHandler<?> handler) {
if (eventHandlers.containsKey(handler.getEventClass())) {
eventHandlers.get(handler.getEventClass()).remove(handler);
}
}
@AllArgsConstructor
public static class Context implements EventContext {
private final EventManager manager;
private final EventHandler<?> handler;
/**
* Unregister an EventHandler from within an Event execution
*/
@Override
public void unregister() {
manager.unregister(handler);
}
}
}

View file

@ -24,7 +24,7 @@
*
*/
package org.geysermc.connector.plugin.api;
package org.geysermc.connector.event.events;
import lombok.Getter;
import lombok.Setter;

View file

@ -24,10 +24,7 @@
*
*/
package org.geysermc.connector.plugin.events;
import lombok.ToString;
import org.geysermc.connector.plugin.api.GeyserEvent;
package org.geysermc.connector.event.events;
/**
* DisableEvent is triggered for each plugin when disabling it

View file

@ -24,9 +24,7 @@
*
*/
package org.geysermc.connector.plugin.events;
import org.geysermc.connector.plugin.api.CancellableGeyserEvent;
package org.geysermc.connector.event.events;
/**
* EnableEvent is triggered for each plugin when enabling it

View file

@ -24,7 +24,7 @@
*
*/
package org.geysermc.connector.plugin.api;
package org.geysermc.connector.event.events;
public abstract class GeyserEvent {

View file

@ -0,0 +1,110 @@
/*
* Copyright (c) 2019-2020 GeyserMC. http://geysermc.org
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
* @author GeyserMC
* @link https://github.com/GeyserMC/Geyser
*
*/
package org.geysermc.connector.plugin;
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;
/**
* All GeyserPlugins extend from this
*/
@Getter
@AllArgsConstructor
public abstract class GeyserPlugin {
private final Map<Object, ArrayList<EventHandler<?>>> classEventHandlers = new HashMap<>();
private final PluginManager pluginManager;
private final PluginClassLoader pluginClassLoader;
/**
* Register all Events contained in a class
*/
public void registerEvents(Object obj) {
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 = 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);
}
}
/**
* Unregister events in class
*/
public void unregisterEvents(Object obj) {
if (!classEventHandlers.containsKey(obj)) {
return;
}
for (EventHandler<?> handler : classEventHandlers.get(obj)) {
pluginManager.getConnector().getEventManager().unregister(handler);
}
classEventHandlers.remove(obj);
}
/**
* Unregister all events for a plugin
*/
public void unregisterPluginEvents(Class<?> plugin) {
for (Object obj : classEventHandlers.keySet()) {
unregisterEvents(obj);
}
}
}

View file

@ -52,16 +52,16 @@ public class PluginClassLoader extends URLClassLoader {
private final Map<String, Class<?>> classes = new ConcurrentHashMap<>();
@Getter
private final Object plugin;
private final Class<? extends GeyserPlugin> pluginClass;
PluginClassLoader(PluginManager pluginManager, ClassLoader parent, File pluginFile) throws IOException, InvalidPluginClassLoaderException {
super(new URL[] {pluginFile.toURI().toURL()}, parent);
this.jar = new JarFile(pluginFile);
this.pluginManager = pluginManager;
this.plugin = findPlugin();
this.pluginClass = findPlugin();
if (this.plugin == null) {
if (this.pluginClass == null) {
throw new InvalidPluginClassLoaderException("Unable to find class annotated by @Plugin");
}
}
@ -69,7 +69,7 @@ public class PluginClassLoader extends URLClassLoader {
/**
* Find first class annotated by @Plugin
*/
private Object findPlugin() {
private Class<? extends GeyserPlugin> findPlugin() {
for (Enumeration<JarEntry> entries = jar.entries(); entries.hasMoreElements();) {
JarEntry entry = entries.nextElement();
if (!entry.getName().endsWith(".class")) {
@ -83,9 +83,10 @@ public class PluginClassLoader extends URLClassLoader {
continue;
}
if (cls.getAnnotation(Plugin.class) != null) {
if (GeyserPlugin.class.isAssignableFrom(cls) && cls.getAnnotation(Plugin.class) != null) {
cacheClass(cls, true);
return cls;
//noinspection unchecked
return (Class<? extends GeyserPlugin>) cls;
}
}
return null;
@ -98,7 +99,7 @@ public class PluginClassLoader extends URLClassLoader {
classes.put(cls.getName(), cls);
if (global) {
pluginManager.getPluginClasses().put(cls.getName(), cls);
pluginManager.getGlobalClasses().put(cls.getName(), cls);
}
}
@ -157,11 +158,11 @@ public class PluginClassLoader extends URLClassLoader {
return classes.get(name);
}
boolean global = plugin.getClass().getAnnotation(Plugin.class).global();
boolean global = pluginClass.getAnnotation(Plugin.class).global();
// Now try load from global if permitted
if (global) {
Class<?> cls = pluginManager.getPluginClasses().get(name);
Class<?> cls = pluginManager.getGlobalClasses().get(name);
if (cls != null) {
return cls;
}

View file

@ -29,26 +29,19 @@ package org.geysermc.connector.plugin;
import lombok.Getter;
import lombok.ToString;
import org.geysermc.connector.GeyserConnector;
import org.geysermc.connector.plugin.annotations.Event;
import org.geysermc.connector.plugin.api.CancellableGeyserEvent;
import org.geysermc.connector.plugin.api.GeyserEvent;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.PriorityQueue;
import java.util.Objects;
import java.util.concurrent.ConcurrentHashMap;
/**
* Handles 3rd party plugins for Geyser
* Handles 3rd party plugins for Geyser and will hook into our Event system using annotations
*/
@Getter
@ToString
@ -57,9 +50,8 @@ public class PluginManager {
private final GeyserConnector connector;
private final File pluginPath;
private final Map<String, Class<?>> pluginClasses = new ConcurrentHashMap<>();
private final List<PluginClassLoader> loaders = new ArrayList<>();
private final Map<Class<?>, PriorityQueue<EventHandler>> eventHandlers = new HashMap<>();
private final Map<String, Class<?>> globalClasses = new ConcurrentHashMap<>();
private final List<GeyserPlugin> plugins = new ArrayList<>();
public PluginManager(GeyserConnector connector, File pluginPath) {
this.connector = connector;
@ -70,15 +62,16 @@ public class PluginManager {
/**
* Load all plugins in the defined pluginPath
*/
@SuppressWarnings("ResultOfMethodCallIgnored")
public void loadPlugins() {
pluginPath.mkdirs();
for (File entry : pluginPath.listFiles()) {
for (File entry : Objects.requireNonNull(pluginPath.listFiles())) {
if (entry.isDirectory() || !entry.getName().toLowerCase().endsWith(".jar")) {
continue;
}
try {
loadPlugin(entry);
} catch (IOException | PluginClassLoader.InvalidPluginClassLoaderException e) {
} catch (IOException | PluginManagerException e) {
e.printStackTrace();
}
}
@ -87,139 +80,40 @@ public class PluginManager {
/**
* Load a specific plugin and register its events
*/
private void loadPlugin(File pluginFile) throws IOException, PluginClassLoader.InvalidPluginClassLoaderException {
private void loadPlugin(File pluginFile) throws IOException, PluginManagerException {
if (!pluginFile.exists()) {
throw new FileNotFoundException(String.format("%s does not exist", pluginFile.getName()));
}
PluginClassLoader loader = new PluginClassLoader(this, getClass().getClassLoader(), pluginFile);
registerEvents(loader.getPlugin(), loader.getPlugin());
loaders.add(loader);
PluginClassLoader loader = null;
try {
loader = new PluginClassLoader(this, getClass().getClassLoader(), pluginFile);
} catch (PluginClassLoader.InvalidPluginClassLoaderException e) {
throw new PluginManagerException(e.getMessage(), e);
}
GeyserPlugin plugin;
try {
plugin = loader.getPluginClass().getConstructor(PluginManager.class, PluginClassLoader.class).newInstance(this, loader);
} catch (InstantiationException | NoSuchMethodException | InvocationTargetException | IllegalAccessException e) {
throw new PluginManagerException(e.getMessage(), e);
}
plugins.add(plugin);
plugin.registerEvents(plugin);
}
/**
* Register all Events contained in class
*/
public void registerEvents(Object plugin, Object cls) {
for (Method method : cls.getClass().getMethods()) {
Event eventAnnotation = method.getAnnotation(Event.class);
public static class PluginManagerException extends Exception {
// Check that the method is annotated with @Event
if (eventAnnotation == null) {
continue;
}
// Make sure it only has a single Event parameter
if (method.getParameterCount() != 1 || !GeyserEvent.class.isAssignableFrom(method.getParameters()[0].getType())) {
continue;
}
if (!eventHandlers.containsKey(method.getParameters()[0].getType())) {
eventHandlers.put(method.getParameters()[0].getType(), new PriorityQueue<>());
}
eventHandlers.get(method.getParameters()[0].getType()).add(
new EventHandler(
plugin,
cls,
method,
eventAnnotation
)
);
}
}
/**
* Unregister events in class
*/
public void unregisterEvents(Class<?> cls) {
for (Map.Entry<Class<?>, PriorityQueue<EventHandler>> entry : eventHandlers.entrySet()) {
List<EventHandler> remove = new ArrayList<>();
for (EventHandler handler : entry.getValue()) {
if (handler.cls == cls) {
remove.add(handler);
}
}
entry.getValue().removeAll(remove);
}
}
/**
* Unregister all events for a plugin
*/
public void unregisterPluginEvents(Class<?> plugin) {
for (Map.Entry<Class<?>, PriorityQueue<EventHandler>> entry : eventHandlers.entrySet()) {
List<EventHandler> remove = new ArrayList<>();
for (EventHandler handler : entry.getValue()) {
if (handler.plugin == plugin) {
remove.add(handler);
}
}
entry.getValue().removeAll(remove);
}
}
/**
* Trigger a new event
*
* This will be executed with all registered handlers in order of priority
*/
public void triggerEvent(GeyserEvent event) {
if (!eventHandlers.containsKey(event.getClass())) {
return;
public PluginManagerException(String message, Throwable ex) {
super(message, ex);
}
for (EventHandler handler : eventHandlers.get(event.getClass())) {
try {
handler.method.invoke(handler.cls, event);
} catch (IllegalAccessException | InvocationTargetException e) {
e.printStackTrace();
}
}
}
public PluginManagerException(Throwable ex) {
/**
* Trigger a new cancellable event
*
* This will be executed with all registered handlers in order of priority ignoring those who
* do not wish to process events that are cancelled
*/
public void triggerEvent(CancellableGeyserEvent event) {
if (!eventHandlers.containsKey(event.getClass())) {
return;
}
boolean cancelled = event.isCancelled();
for (EventHandler handler : eventHandlers.get(event.getClass())) {
if (cancelled && handler.annotation.ignoreCancelled()) {
continue;
}
try {
handler.method.invoke(handler.cls, event);
} catch (IllegalAccessException | InvocationTargetException e) {
e.printStackTrace();
}
cancelled = event.isCancelled();
}
}
static class EventHandler implements Comparator<EventHandler> {
Object plugin;
Object cls;
Method method;
Event annotation;
EventHandler(Object plugin, Object cls, Method method, Event annotation) {
this.plugin = plugin;
this.cls = cls;
this.method = method;
this.annotation = annotation;
}
@Override
public int compare(EventHandler left, EventHandler right) {
return left.annotation.priority() - right.annotation.priority();
}
}
}

View file

@ -26,7 +26,7 @@
package org.geysermc.connector.plugin.annotations;
import lombok.Getter;
import org.geysermc.connector.event.EventHandler;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
@ -43,16 +43,8 @@ import java.lang.annotation.Target;
@Target({ElementType.METHOD})
public @interface Event {
// Events are processed from lowest to highest priority
int priority() default 50;
int priority() default EventHandler.PRIORITY.NORMAL;
// If ignoreCancelled is true then the handler will not be executed
boolean ignoreCancelled() default false;
class PRIORITY {
public static int LOWEST = 10;
public static int LOW = 40;
public static int NORMAL = 50;
public static int HIGH = 60;
public static int HIGHEST = 90;
}
}