mirror of
https://github.com/PaperMC/Paper.git
synced 2025-08-14 11:45:52 -07:00
[Bleeding] Changed event system into a new, much faster design. Huge thanks to @zml2008 & @lahwran.
By: Nathan Adams <dinnerbone@dinnerbone.com>
This commit is contained in:
@@ -1,11 +1,12 @@
|
||||
package org.bukkit.plugin;
|
||||
|
||||
import org.bukkit.event.Event;
|
||||
import org.bukkit.event.EventException;
|
||||
import org.bukkit.event.Listener;
|
||||
|
||||
/**
|
||||
* Interface which defines the class for event call backs to plugins
|
||||
*/
|
||||
public interface EventExecutor {
|
||||
public void execute(Listener listener, Event event);
|
||||
public void execute(Listener listener, Event event) throws EventException;
|
||||
}
|
||||
|
@@ -1,6 +1,8 @@
|
||||
package org.bukkit.plugin;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import org.bukkit.event.Event;
|
||||
@@ -51,8 +53,18 @@ public interface PluginLoader {
|
||||
* @param listener the object that will handle the eventual call back
|
||||
* @return The new executor
|
||||
*/
|
||||
@Deprecated
|
||||
public EventExecutor createExecutor(Event.Type type, Listener listener);
|
||||
|
||||
/**
|
||||
* Creates and returns registered listeners for the event classes used in this listener
|
||||
*
|
||||
* @param listener The object that will handle the eventual call back
|
||||
* @param plugin The plugin to use when creating registered listeners
|
||||
* @return The registered listeners.
|
||||
*/
|
||||
public Map<Class<? extends Event>, Set<RegisteredListener>> createRegisteredListeners(Listener listener, Plugin plugin);
|
||||
|
||||
/**
|
||||
* Enables the specified plugin
|
||||
* <p />
|
||||
|
@@ -2,9 +2,9 @@ package org.bukkit.plugin;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.Set;
|
||||
|
||||
import org.bukkit.event.Event;
|
||||
import org.bukkit.event.Event.Priority;
|
||||
import org.bukkit.event.EventPriority;
|
||||
import org.bukkit.event.Listener;
|
||||
import org.bukkit.permissions.Permissible;
|
||||
import org.bukkit.permissions.Permission;
|
||||
@@ -92,6 +92,7 @@ public interface PluginManager {
|
||||
* Calls an event with the given details
|
||||
*
|
||||
* @param event Event details
|
||||
* @return Called event
|
||||
*/
|
||||
public void callEvent(Event event);
|
||||
|
||||
@@ -103,6 +104,7 @@ public interface PluginManager {
|
||||
* @param priority Priority of this event
|
||||
* @param plugin Plugin to register
|
||||
*/
|
||||
@Deprecated
|
||||
public void registerEvent(Event.Type type, Listener listener, Priority priority, Plugin plugin);
|
||||
|
||||
/**
|
||||
@@ -114,8 +116,28 @@ public interface PluginManager {
|
||||
* @param priority Priority of this event
|
||||
* @param plugin Plugin to register
|
||||
*/
|
||||
@Deprecated
|
||||
public void registerEvent(Event.Type type, Listener listener, EventExecutor executor, Priority priority, Plugin plugin);
|
||||
|
||||
/**
|
||||
* Registers all the events in the given listener class
|
||||
*
|
||||
* @param listener Listener to register
|
||||
* @param plugin Plugin to register
|
||||
*/
|
||||
public void registerEvents(Listener listener, Plugin plugin);
|
||||
|
||||
/**
|
||||
* Registers the specified executor to the given event class
|
||||
*
|
||||
* @param event Event type to register
|
||||
* @param listener Listener to register
|
||||
* @param priority Priority to register this event at
|
||||
* @param executor EventExecutor to register
|
||||
* @param plugin Plugin to register
|
||||
*/
|
||||
public void registerEvent(Class<? extends Event> event, Listener listener, EventPriority priority, EventExecutor executor, Plugin plugin);
|
||||
|
||||
/**
|
||||
* Enables the specified plugin
|
||||
* <p />
|
||||
|
@@ -1,6 +1,8 @@
|
||||
package org.bukkit.plugin;
|
||||
|
||||
import org.bukkit.event.Event;
|
||||
import org.bukkit.event.EventException;
|
||||
import org.bukkit.event.EventPriority;
|
||||
import org.bukkit.event.Listener;
|
||||
|
||||
/**
|
||||
@@ -8,24 +10,17 @@ import org.bukkit.event.Listener;
|
||||
*/
|
||||
public class RegisteredListener {
|
||||
private final Listener listener;
|
||||
private final Event.Priority priority;
|
||||
private final EventPriority priority;
|
||||
private final Plugin plugin;
|
||||
private final EventExecutor executor;
|
||||
|
||||
public RegisteredListener(final Listener pluginListener, final EventExecutor eventExecutor, final Event.Priority eventPriority, final Plugin registeredPlugin) {
|
||||
public RegisteredListener(final Listener pluginListener, final EventExecutor eventExecutor, final EventPriority eventPriority, final Plugin registeredPlugin) {
|
||||
listener = pluginListener;
|
||||
priority = eventPriority;
|
||||
plugin = registeredPlugin;
|
||||
executor = eventExecutor;
|
||||
}
|
||||
|
||||
public RegisteredListener(final Listener pluginListener, final Event.Priority eventPriority, final Plugin registeredPlugin, Event.Type type) {
|
||||
listener = pluginListener;
|
||||
priority = eventPriority;
|
||||
plugin = registeredPlugin;
|
||||
executor = registeredPlugin.getPluginLoader().createExecutor(type, pluginListener);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the listener for this registration
|
||||
*
|
||||
@@ -49,7 +44,7 @@ public class RegisteredListener {
|
||||
*
|
||||
* @return Registered Priority
|
||||
*/
|
||||
public Event.Priority getPriority() {
|
||||
public EventPriority getPriority() {
|
||||
return priority;
|
||||
}
|
||||
|
||||
@@ -58,7 +53,7 @@ public class RegisteredListener {
|
||||
*
|
||||
* @param event The event
|
||||
*/
|
||||
public void callEvent(Event event) {
|
||||
public void callEvent(Event event) throws EventException {
|
||||
executor.execute(listener, event);
|
||||
}
|
||||
}
|
||||
|
@@ -3,36 +3,20 @@ package org.bukkit.plugin;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import java.io.File;
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Comparator;
|
||||
import java.util.EnumMap;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.SortedSet;
|
||||
import java.util.TreeSet;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedList;
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.WeakHashMap;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.*;
|
||||
import java.util.logging.Level;
|
||||
import java.util.regex.Matcher;
|
||||
import org.bukkit.Server;
|
||||
import java.util.regex.Pattern;
|
||||
import org.bukkit.Server;
|
||||
import org.bukkit.command.Command;
|
||||
import org.bukkit.command.PluginCommandYamlParser;
|
||||
import org.bukkit.command.SimpleCommandMap;
|
||||
|
||||
import org.bukkit.event.Event;
|
||||
import org.bukkit.event.Event.Priority;
|
||||
import org.bukkit.event.Listener;
|
||||
import org.bukkit.event.*;
|
||||
import org.bukkit.permissions.Permissible;
|
||||
import org.bukkit.permissions.Permission;
|
||||
import org.bukkit.permissions.PermissionDefault;
|
||||
|
||||
import org.bukkit.util.FileUtil;
|
||||
|
||||
/**
|
||||
@@ -43,24 +27,12 @@ public final class SimplePluginManager implements PluginManager {
|
||||
private final Map<Pattern, PluginLoader> fileAssociations = new HashMap<Pattern, PluginLoader>();
|
||||
private final List<Plugin> plugins = new ArrayList<Plugin>();
|
||||
private final Map<String, Plugin> lookupNames = new HashMap<String, Plugin>();
|
||||
private final Map<Event.Type, SortedSet<RegisteredListener>> listeners = new EnumMap<Event.Type, SortedSet<RegisteredListener>>(Event.Type.class);
|
||||
private static File updateDirectory = null;
|
||||
private final SimpleCommandMap commandMap;
|
||||
private final Map<String, Permission> permissions = new HashMap<String, Permission>();
|
||||
private final Map<Boolean, Set<Permission>> defaultPerms = new LinkedHashMap<Boolean, Set<Permission>>();
|
||||
private final Map<String, Map<Permissible, Boolean>> permSubs = new HashMap<String, Map<Permissible, Boolean>>();
|
||||
private final Map<Boolean, Map<Permissible, Boolean>> defSubs = new HashMap<Boolean, Map<Permissible, Boolean>>();
|
||||
private final Comparator<RegisteredListener> comparer = new Comparator<RegisteredListener>() {
|
||||
public int compare(RegisteredListener i, RegisteredListener j) {
|
||||
int result = i.getPriority().compareTo(j.getPriority());
|
||||
|
||||
if ((result == 0) && (i != j)) {
|
||||
result = 1;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
};
|
||||
|
||||
public SimplePluginManager(Server instance, SimpleCommandMap commandMap) {
|
||||
server = instance;
|
||||
@@ -281,6 +253,8 @@ public final class SimplePluginManager implements PluginManager {
|
||||
} catch (Throwable ex) {
|
||||
server.getLogger().log(Level.SEVERE, "Error occurred (in the plugin loader) while enabling " + plugin.getDescription().getFullName() + " (Is it up to date?): " + ex.getMessage(), ex);
|
||||
}
|
||||
|
||||
HandlerList.bakeAll();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -309,6 +283,12 @@ public final class SimplePluginManager implements PluginManager {
|
||||
} catch (Throwable ex) {
|
||||
server.getLogger().log(Level.SEVERE, "Error occurred (in the plugin loader) while unregistering services for " + plugin.getDescription().getFullName() + " (Is it up to date?): " + ex.getMessage(), ex);
|
||||
}
|
||||
|
||||
try {
|
||||
HandlerList.unregisterAll(plugin);
|
||||
} catch (Throwable ex) {
|
||||
server.getLogger().log(Level.SEVERE, "Error occurred (in the plugin loader) while unregistering events for " + plugin.getDescription().getFullName() + " (Is it up to date?): " + ex.getMessage(), ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -317,7 +297,7 @@ public final class SimplePluginManager implements PluginManager {
|
||||
disablePlugins();
|
||||
plugins.clear();
|
||||
lookupNames.clear();
|
||||
listeners.clear();
|
||||
HandlerList.unregisterAll();
|
||||
fileAssociations.clear();
|
||||
permissions.clear();
|
||||
defaultPerms.get(true).clear();
|
||||
@@ -331,35 +311,59 @@ public final class SimplePluginManager implements PluginManager {
|
||||
* @param event Event details
|
||||
*/
|
||||
public synchronized void callEvent(Event event) {
|
||||
for (RegisteredListener registration : getEventListeners(event.getType())) {
|
||||
if (!registration.getPlugin().isEnabled()) {
|
||||
continue;
|
||||
}
|
||||
HandlerList handlers = event.getHandlers();
|
||||
handlers.bake();
|
||||
RegisteredListener[][] listeners = handlers.getRegisteredListeners();
|
||||
|
||||
try {
|
||||
long start = System.nanoTime();
|
||||
registration.callEvent(event);
|
||||
registration.getPlugin().incTiming(event.getType(), System.nanoTime() - start);
|
||||
} catch (AuthorNagException ex) {
|
||||
Plugin plugin = registration.getPlugin();
|
||||
|
||||
if (plugin.isNaggable()) {
|
||||
plugin.setNaggable(false);
|
||||
|
||||
String author = "<NoAuthorGiven>";
|
||||
|
||||
if (plugin.getDescription().getAuthors().size() > 0) {
|
||||
author = plugin.getDescription().getAuthors().get(0);
|
||||
if (listeners != null) {
|
||||
for (int i = 0; i < listeners.length; i++) {
|
||||
for (RegisteredListener registration : listeners[i]) {
|
||||
if (!registration.getPlugin().isEnabled()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
try {
|
||||
long start = System.nanoTime();
|
||||
registration.callEvent(event);
|
||||
registration.getPlugin().incTiming(event.getType(), System.nanoTime() - start);
|
||||
} catch (AuthorNagException ex) {
|
||||
Plugin plugin = registration.getPlugin();
|
||||
|
||||
if (plugin.isNaggable()) {
|
||||
plugin.setNaggable(false);
|
||||
|
||||
String author = "<NoAuthorGiven>";
|
||||
|
||||
if (plugin.getDescription().getAuthors().size() > 0) {
|
||||
author = plugin.getDescription().getAuthors().get(0);
|
||||
}
|
||||
server.getLogger().log(Level.SEVERE, String.format(
|
||||
"Nag author: '%s' of '%s' about the following: %s",
|
||||
author,
|
||||
plugin.getDescription().getName(),
|
||||
ex.getMessage()
|
||||
));
|
||||
}
|
||||
} catch (Throwable ex) {
|
||||
server.getLogger().log(Level.SEVERE, "Could not pass event " + event.getEventName() + " to " + registration.getPlugin().getDescription().getName(), ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// This is an ugly hack to handle old-style custom events in old plugins without breakage. All in the name of plugin compatibility.
|
||||
if (event.getType() == Event.Type.CUSTOM_EVENT) {
|
||||
TransitionalCustomEvent.getHandlerList().bake();
|
||||
listeners = TransitionalCustomEvent.getHandlerList().getRegisteredListeners();
|
||||
if (listeners != null) {
|
||||
for (int i = 0; i < listeners.length; i++) {
|
||||
for (RegisteredListener registration : listeners[i]) {
|
||||
try {
|
||||
registration.callEvent(event);
|
||||
} catch (Throwable ex) {
|
||||
server.getLogger().log(Level.SEVERE, "Could not pass event " + event.getEventName() + " to " + registration.getPlugin().getDescription().getName(), ex);
|
||||
}
|
||||
}
|
||||
server.getLogger().log(Level.SEVERE, String.format(
|
||||
"Nag author: '%s' of '%s' about the following: %s",
|
||||
author,
|
||||
plugin.getDescription().getName(),
|
||||
ex.getMessage()
|
||||
));
|
||||
}
|
||||
} catch (Throwable ex) {
|
||||
server.getLogger().log(Level.SEVERE, "Could not pass event " + event.getType() + " to " + registration.getPlugin().getDescription().getName(), ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -389,7 +393,7 @@ public final class SimplePluginManager implements PluginManager {
|
||||
throw new IllegalPluginAccessException("Plugin attempted to register " + type + " while not enabled");
|
||||
}
|
||||
|
||||
getEventListeners(type).add(new RegisteredListener(listener, priority, plugin, type));
|
||||
getEventListeners(type.getEventClass()).register(new RegisteredListener(listener, plugin.getPluginLoader().createExecutor(type, listener), priority.getNewPriority(), plugin));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -418,25 +422,61 @@ public final class SimplePluginManager implements PluginManager {
|
||||
throw new IllegalPluginAccessException("Plugin attempted to register " + type + " while not enabled");
|
||||
}
|
||||
|
||||
getEventListeners(type).add(new RegisteredListener(listener, executor, priority, plugin));
|
||||
getEventListeners(type.getEventClass()).register(new RegisteredListener(listener, executor, priority.getNewPriority(), plugin));
|
||||
}
|
||||
|
||||
public void registerEvents(Listener listener, Plugin plugin) {
|
||||
if (!plugin.isEnabled()) {
|
||||
throw new IllegalPluginAccessException("Plugin attempted to register " + listener + " while not enabled");
|
||||
}
|
||||
for (Map.Entry<Class<? extends Event>, Set<RegisteredListener>> entry : plugin.getPluginLoader().createRegisteredListeners(listener, plugin).entrySet()) {
|
||||
Class<? extends Event> delegatedClass = getRegistrationClass(entry.getKey());
|
||||
if (!entry.getKey().equals(delegatedClass)) {
|
||||
plugin.getServer().getLogger().severe("Plugin attempted to register delegated event class " + entry.getKey() + ". It should be using " + delegatedClass + "!");
|
||||
continue;
|
||||
}
|
||||
getEventListeners(delegatedClass).registerAll(entry.getValue());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public void registerEvent(Class<? extends Event> event, Listener listener, EventPriority priority, EventExecutor executor, Plugin plugin) {
|
||||
if (!plugin.isEnabled()) {
|
||||
throw new IllegalPluginAccessException("Plugin attempted to register " + event + " while not enabled");
|
||||
}
|
||||
|
||||
getEventListeners(event).register(new RegisteredListener(listener, executor, priority, plugin));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a SortedSet of RegisteredListener for the specified event type creating a new queue if needed
|
||||
* Returns the specified event type's HandlerList
|
||||
*
|
||||
* @param type EventType to lookup
|
||||
* @return SortedSet<RegisteredListener> the looked up or create queue matching the requested type
|
||||
* @return HandlerList The list of registered handlers for the event.
|
||||
*/
|
||||
private SortedSet<RegisteredListener> getEventListeners(Event.Type type) {
|
||||
SortedSet<RegisteredListener> eventListeners = listeners.get(type);
|
||||
|
||||
if (eventListeners != null) {
|
||||
return eventListeners;
|
||||
private HandlerList getEventListeners(Class<? extends Event> type) {
|
||||
try {
|
||||
Method method = getRegistrationClass(type).getDeclaredMethod("getHandlerList");
|
||||
method.setAccessible(true);
|
||||
return (HandlerList)method.invoke(null);
|
||||
} catch (Exception e) {
|
||||
throw new IllegalPluginAccessException(e.toString());
|
||||
}
|
||||
}
|
||||
|
||||
eventListeners = new TreeSet<RegisteredListener>(comparer);
|
||||
listeners.put(type, eventListeners);
|
||||
return eventListeners;
|
||||
private Class<? extends Event> getRegistrationClass(Class<? extends Event> clazz) {
|
||||
try {
|
||||
clazz.getDeclaredMethod("getHandlerList");
|
||||
return clazz;
|
||||
} catch (NoSuchMethodException e) {
|
||||
if (clazz.getSuperclass() != null
|
||||
&& !clazz.getSuperclass().equals(Event.class)
|
||||
&& clazz.getSuperclass().isAssignableFrom(Event.class)) {
|
||||
return getRegistrationClass(clazz.getSuperclass().asSubclass(Event.class));
|
||||
} else {
|
||||
throw new IllegalPluginAccessException("Unable to find handler list for event " + clazz.getName());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public Permission getPermission(String name) {
|
||||
|
@@ -5,21 +5,23 @@ import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.Method;
|
||||
import java.net.URL;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.ArrayList;
|
||||
import java.util.*;
|
||||
import java.util.jar.JarEntry;
|
||||
import java.util.jar.JarFile;
|
||||
import java.util.logging.Level;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Server;
|
||||
|
||||
import org.bukkit.configuration.serialization.ConfigurationSerializable;
|
||||
import org.bukkit.configuration.serialization.ConfigurationSerialization;
|
||||
import org.bukkit.event.CustomEventListener;
|
||||
import org.bukkit.event.Event;
|
||||
import org.bukkit.event.Listener;
|
||||
import org.bukkit.event.*;
|
||||
import org.bukkit.event.block.*;
|
||||
import org.bukkit.event.painting.*;
|
||||
import org.bukkit.event.entity.*;
|
||||
@@ -262,7 +264,7 @@ public class JavaPluginLoader implements PluginLoader {
|
||||
}
|
||||
|
||||
public EventExecutor createExecutor(Event.Type type, Listener listener) {
|
||||
// TODO: remove multiple Listener type and hence casts
|
||||
// TODONE: remove multiple Listener type and hence casts
|
||||
|
||||
switch (type) {
|
||||
// Player Events
|
||||
@@ -971,6 +973,46 @@ public class JavaPluginLoader implements PluginLoader {
|
||||
throw new IllegalArgumentException("Event " + type + " is not supported");
|
||||
}
|
||||
|
||||
public Map<Class<? extends Event>, Set<RegisteredListener>> createRegisteredListeners(Listener listener, final Plugin plugin) {
|
||||
Map<Class<? extends Event>, Set<RegisteredListener>> ret = new HashMap<Class<? extends Event>, Set<RegisteredListener>>();
|
||||
Method[] methods;
|
||||
try {
|
||||
methods = listener.getClass().getDeclaredMethods();
|
||||
} catch (NoClassDefFoundError e) {
|
||||
Bukkit.getServer().getLogger().severe("Plugin " + plugin.getDescription().getName() + " is attempting to register event " + e.getMessage() + ", which does not exist. Ignoring events registered in " + listener.getClass());
|
||||
return ret;
|
||||
}
|
||||
for (int i = 0; i < methods.length; i++) {
|
||||
final Method method = methods[i];
|
||||
final EventHandler eh = method.getAnnotation(EventHandler.class);
|
||||
if (eh == null) continue;
|
||||
final Class<?> checkClass = method.getParameterTypes()[0];
|
||||
if (!checkClass.isAssignableFrom(eh.event()) || method.getParameterTypes().length != 1) {
|
||||
plugin.getServer().getLogger().severe("Wrong method arguments used for event type registered");
|
||||
continue;
|
||||
}
|
||||
method.setAccessible(true);
|
||||
Set<RegisteredListener> eventSet = ret.get(eh.event());
|
||||
if (eventSet == null) {
|
||||
eventSet = new HashSet<RegisteredListener>();
|
||||
ret.put(eh.event(), eventSet);
|
||||
}
|
||||
eventSet.add(new RegisteredListener(listener, new EventExecutor() {
|
||||
public void execute(Listener listener, Event event) throws EventException {
|
||||
try {
|
||||
if (!checkClass.isAssignableFrom(event.getClass())) {
|
||||
throw new EventException("Wrong event type passed to registered method");
|
||||
}
|
||||
method.invoke(listener, event);
|
||||
} catch (Throwable t) {
|
||||
throw new EventException(t);
|
||||
}
|
||||
}
|
||||
}, eh.priority(), plugin));
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
public void enablePlugin(final Plugin plugin) {
|
||||
if (!(plugin instanceof JavaPlugin)) {
|
||||
throw new IllegalArgumentException("Plugin is not associated with this PluginLoader");
|
||||
|
@@ -164,7 +164,7 @@ public interface Messenger {
|
||||
* <p>
|
||||
* A registration is considered valid if it has not be unregistered and that the plugin
|
||||
* is still enabled.
|
||||
*
|
||||
*
|
||||
* @param registration Registration to check.
|
||||
* @return True if the registration is valid, otherwise false.
|
||||
*/
|
||||
|
Reference in New Issue
Block a user