mirror of
https://github.com/PaperMC/Paper.git
synced 2025-01-04 10:11:29 +01:00
08b01ae4df
Upstream has released updates that appears to apply and compile correctly. This update has not been tested by PaperMC and as with ANY update, please do your own testing Warning: this commit contains more mapping changes from upstream, As always, ensure that you have working backups and test this build before deployment; Developers working on paper will, yet again, need to delete their work/Minecraft/1.13.2 folder Bukkit Changes: 7fca5fd4 SPIGOT-4558: Preserve user order in the face of copied defaults in configurations 15c9b1eb Ignore spurious slot IDs sent by client, e.g. in enchanting tables 5d2a10c5 SPIGOT-3747: Add API for force loaded chunks d6dd2bb3 SPIGOT-3538: Add getHitBlockFace for ProjectileHitEvent 771db4aa SPIGOT-794: Call EntityPlaceEvent for Minecart placement 55462509 Add InventoryView#getSlotType 2f3ce5b6 Remove EntityTransformEvent and CustomItemTagContainer from draft API f04ad7b6 Make ProjectileLaunchEvent extend EntitySpawnEvent ccb85808 Define EntitySpawnEvent b8cc3ebe Add PlayerItemDamageEvent 184a495d Ease ClassLoader Deadlocks Where Possible 11ac4728 Expand Boolean Prompt Values in Conversation API aae62d51 Added getAllSessionData() to the Conversation API. 9290ff91 Add InventoryView#getInventory API 995e530f Add API to get / set base arrow damage CraftBukkit Changes:c4a67eed
SPIGOT-4556: Fix plugins closing inventory during drop events5be2ddcb
Replace version constants with methods to prevent compiler inlininga5b9c7b3
Use API method to create offset command completions2bc7d1df
SPIGOT-3747: Add API for force loaded chunksa408f375
SPIGOT-3538: Add getHitBlockFace for ProjectileHitEventb54b9409
SPIGOT-2864: Make Arrow / Item setTicksLived behave like FallingBlock79ded7a8
SPIGOT-1811: Death message not shown on respawn screenb4a4f15d
SPIGOT-943: InventoryCloseEvent called on death regardless of open inventory0afed592
SPIGOT-794: Call EntityPlaceEvent for Minecart placement2b2d084a
Add InventoryView#getSlotType01a9959a
Do not use deprecated ItemSpawnEvent constructor9642498d
SPIGOT-4547: Call EntitySpawnEvent as general spawn fallback event963f4a5f
Add PlayerItemDamageEvent63db0445
Add API to get / set base arrow damage531c25d7
Add CraftMagicNumbers.MAPPINGS_VERSION for use by NMS pluginsd05c8b14
Mappings Updatebd36e200
SPIGOT-4551: Ignore invalid attribute modifier slots Spigot Changes: 518206a1 Remove redundant trove depend 1959ad21 MC-11211,SPIGOT-4552: Fix placing double slabs at y = 255 29ab5e43 SPIGOT-3661: Allow arguments in restart-script 7cc46316 SPIGOT-852: Growth modifiers for beetroots, potatoes, carrots 82e117e1 Squelch "fatal: Resolve operation not in progress" message 0a1a68e7 Mappings Update & Patch Rebuild
429 lines
No EOL
18 KiB
Diff
429 lines
No EOL
18 KiB
Diff
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
|
From: Techcable <Techcable@outlook.com>
|
|
Date: Thu, 3 Mar 2016 13:20:33 -0700
|
|
Subject: [PATCH] Use ASM for event executors.
|
|
|
|
Uses method handles for private or static methods.
|
|
|
|
diff --git a/pom.xml b/pom.xml
|
|
index f9fbc40a..1d42d42a 100644
|
|
--- a/pom.xml
|
|
+++ b/pom.xml
|
|
@@ -0,0 +0,0 @@
|
|
<version>1.3</version>
|
|
<scope>test</scope>
|
|
</dependency>
|
|
+ <!-- ASM -->
|
|
+ <dependency>
|
|
+ <groupId>org.ow2.asm</groupId>
|
|
+ <artifactId>asm</artifactId>
|
|
+ <version>6.1.1</version>
|
|
+ </dependency>
|
|
+ <dependency>
|
|
+ <groupId>org.ow2.asm</groupId>
|
|
+ <artifactId>asm-commons</artifactId>
|
|
+ <version>6.1.1</version>
|
|
+ </dependency>
|
|
</dependencies>
|
|
|
|
<build>
|
|
diff --git a/src/main/java/com/destroystokyo/paper/event/executor/MethodHandleEventExecutor.java b/src/main/java/com/destroystokyo/paper/event/executor/MethodHandleEventExecutor.java
|
|
new file mode 100644
|
|
index 00000000..9ff99e3b
|
|
--- /dev/null
|
|
+++ b/src/main/java/com/destroystokyo/paper/event/executor/MethodHandleEventExecutor.java
|
|
@@ -0,0 +0,0 @@
|
|
+package com.destroystokyo.paper.event.executor;
|
|
+
|
|
+import java.lang.invoke.MethodHandle;
|
|
+import java.lang.invoke.MethodHandles;
|
|
+import java.lang.reflect.Method;
|
|
+
|
|
+import org.bukkit.event.Event;
|
|
+import org.bukkit.event.EventException;
|
|
+import org.bukkit.event.Listener;
|
|
+import org.bukkit.plugin.EventExecutor;
|
|
+
|
|
+public class MethodHandleEventExecutor implements EventExecutor {
|
|
+ private final Class<? extends Event> eventClass;
|
|
+ private final MethodHandle handle;
|
|
+
|
|
+ public MethodHandleEventExecutor(Class<? extends Event> eventClass, MethodHandle handle) {
|
|
+ this.eventClass = eventClass;
|
|
+ this.handle = handle;
|
|
+ }
|
|
+
|
|
+ public MethodHandleEventExecutor(Class<? extends Event> eventClass, Method m) {
|
|
+ this.eventClass = eventClass;
|
|
+ try {
|
|
+ m.setAccessible(true);
|
|
+ this.handle = MethodHandles.lookup().unreflect(m);
|
|
+ } catch (IllegalAccessException e) {
|
|
+ throw new AssertionError("Unable to set accessible", e);
|
|
+ }
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public void execute(Listener listener, Event event) throws EventException {
|
|
+ if (!eventClass.isInstance(event)) return;
|
|
+ try {
|
|
+ handle.invoke(listener, event);
|
|
+ } catch (Throwable t) {
|
|
+ throw new EventException(t);
|
|
+ }
|
|
+ }
|
|
+}
|
|
diff --git a/src/main/java/com/destroystokyo/paper/event/executor/StaticMethodHandleEventExecutor.java b/src/main/java/com/destroystokyo/paper/event/executor/StaticMethodHandleEventExecutor.java
|
|
new file mode 100644
|
|
index 00000000..f60f0100
|
|
--- /dev/null
|
|
+++ b/src/main/java/com/destroystokyo/paper/event/executor/StaticMethodHandleEventExecutor.java
|
|
@@ -0,0 +0,0 @@
|
|
+package com.destroystokyo.paper.event.executor;
|
|
+
|
|
+import java.lang.invoke.MethodHandle;
|
|
+import java.lang.invoke.MethodHandles;
|
|
+import java.lang.reflect.Method;
|
|
+import java.lang.reflect.Modifier;
|
|
+
|
|
+import com.google.common.base.Preconditions;
|
|
+
|
|
+import org.bukkit.event.Event;
|
|
+import org.bukkit.event.EventException;
|
|
+import org.bukkit.event.Listener;
|
|
+import org.bukkit.plugin.EventExecutor;
|
|
+
|
|
+public class StaticMethodHandleEventExecutor implements EventExecutor {
|
|
+ private final Class<? extends Event> eventClass;
|
|
+ private final MethodHandle handle;
|
|
+
|
|
+ public StaticMethodHandleEventExecutor(Class<? extends Event> eventClass, Method m) {
|
|
+ Preconditions.checkArgument(Modifier.isStatic(m.getModifiers()), "Not a static method: %s", m);
|
|
+ this.eventClass = eventClass;
|
|
+ try {
|
|
+ m.setAccessible(true);
|
|
+ this.handle = MethodHandles.lookup().unreflect(m);
|
|
+ } catch (IllegalAccessException e) {
|
|
+ throw new AssertionError("Unable to set accessible", e);
|
|
+ }
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public void execute(Listener listener, Event event) throws EventException {
|
|
+ if (!eventClass.isInstance(event)) return;
|
|
+ try {
|
|
+ handle.invoke(event);
|
|
+ } catch (Throwable t) {
|
|
+ throw new EventException(t);
|
|
+ }
|
|
+ }
|
|
+}
|
|
diff --git a/src/main/java/com/destroystokyo/paper/event/executor/asm/ASMEventExecutorGenerator.java b/src/main/java/com/destroystokyo/paper/event/executor/asm/ASMEventExecutorGenerator.java
|
|
new file mode 100644
|
|
index 00000000..140cf0ad
|
|
--- /dev/null
|
|
+++ b/src/main/java/com/destroystokyo/paper/event/executor/asm/ASMEventExecutorGenerator.java
|
|
@@ -0,0 +0,0 @@
|
|
+package com.destroystokyo.paper.event.executor.asm;
|
|
+
|
|
+import java.lang.reflect.Method;
|
|
+import java.util.concurrent.atomic.AtomicInteger;
|
|
+
|
|
+import org.bukkit.plugin.EventExecutor;
|
|
+import org.objectweb.asm.ClassWriter;
|
|
+import org.objectweb.asm.Type;
|
|
+import org.objectweb.asm.commons.GeneratorAdapter;
|
|
+
|
|
+import static org.objectweb.asm.Opcodes.*;
|
|
+
|
|
+public class ASMEventExecutorGenerator {
|
|
+ public static byte[] generateEventExecutor(Method m, String name) {
|
|
+ ClassWriter writer = new ClassWriter(ClassWriter.COMPUTE_FRAMES | ClassWriter.COMPUTE_MAXS);
|
|
+ writer.visit(V1_8, ACC_PUBLIC, name.replace('.', '/'), null, Type.getInternalName(Object.class), new String[] {Type.getInternalName(EventExecutor.class)});
|
|
+ // Generate constructor
|
|
+ GeneratorAdapter methodGenerator = new GeneratorAdapter(writer.visitMethod(ACC_PUBLIC, "<init>", "()V", null, null), ACC_PUBLIC, "<init>", "()V");
|
|
+ methodGenerator.loadThis();
|
|
+ methodGenerator.visitMethodInsn(INVOKESPECIAL, Type.getInternalName(Object.class), "<init>", "()V", false); // Invoke the super class (Object) constructor
|
|
+ methodGenerator.returnValue();
|
|
+ methodGenerator.endMethod();
|
|
+ // Generate the execute method
|
|
+ methodGenerator = new GeneratorAdapter(writer.visitMethod(ACC_PUBLIC, "execute", "(Lorg/bukkit/event/Listener;Lorg/bukkit/event/Event;)V", null, null), ACC_PUBLIC, "execute", "(Lorg/bukkit/event/Listener;Lorg/bukkit/event/Listener;)V");;
|
|
+ methodGenerator.loadArg(0);
|
|
+ methodGenerator.checkCast(Type.getType(m.getDeclaringClass()));
|
|
+ methodGenerator.loadArg(1);
|
|
+ methodGenerator.checkCast(Type.getType(m.getParameterTypes()[0]));
|
|
+ methodGenerator.visitMethodInsn(m.getDeclaringClass().isInterface() ? INVOKEINTERFACE : INVOKEVIRTUAL, Type.getInternalName(m.getDeclaringClass()), m.getName(), Type.getMethodDescriptor(m), m.getDeclaringClass().isInterface());
|
|
+ if (m.getReturnType() != void.class) {
|
|
+ methodGenerator.pop();
|
|
+ }
|
|
+ methodGenerator.returnValue();
|
|
+ methodGenerator.endMethod();
|
|
+ writer.visitEnd();
|
|
+ return writer.toByteArray();
|
|
+ }
|
|
+
|
|
+ public static AtomicInteger NEXT_ID = new AtomicInteger(1);
|
|
+ public static String generateName() {
|
|
+ int id = NEXT_ID.getAndIncrement();
|
|
+ return "com.destroystokyo.paper.event.executor.asm.generated.GeneratedEventExecutor" + id;
|
|
+ }
|
|
+}
|
|
diff --git a/src/main/java/com/destroystokyo/paper/event/executor/asm/ClassDefiner.java b/src/main/java/com/destroystokyo/paper/event/executor/asm/ClassDefiner.java
|
|
new file mode 100644
|
|
index 00000000..6941d9fb
|
|
--- /dev/null
|
|
+++ b/src/main/java/com/destroystokyo/paper/event/executor/asm/ClassDefiner.java
|
|
@@ -0,0 +0,0 @@
|
|
+package com.destroystokyo.paper.event.executor.asm;
|
|
+
|
|
+import com.destroystokyo.paper.utils.UnsafeUtils;
|
|
+
|
|
+public interface ClassDefiner {
|
|
+
|
|
+ /**
|
|
+ * Returns if the defined classes can bypass access checks
|
|
+ *
|
|
+ * @return if classes bypass access checks
|
|
+ */
|
|
+ public default boolean isBypassAccessChecks() {
|
|
+ return false;
|
|
+ }
|
|
+
|
|
+ /**
|
|
+ * Define a class
|
|
+ *
|
|
+ * @param parentLoader the parent classloader
|
|
+ * @param name the name of the class
|
|
+ * @param data the class data to load
|
|
+ * @return the defined class
|
|
+ * @throws ClassFormatError if the class data is invalid
|
|
+ * @throws NullPointerException if any of the arguments are null
|
|
+ */
|
|
+ public Class<?> defineClass(ClassLoader parentLoader, String name, byte[] data);
|
|
+
|
|
+ public static ClassDefiner getInstance() {
|
|
+ return SafeClassDefiner.INSTANCE;
|
|
+ }
|
|
+
|
|
+}
|
|
diff --git a/src/main/java/com/destroystokyo/paper/event/executor/asm/SafeClassDefiner.java b/src/main/java/com/destroystokyo/paper/event/executor/asm/SafeClassDefiner.java
|
|
new file mode 100644
|
|
index 00000000..1473ff8c
|
|
--- /dev/null
|
|
+++ b/src/main/java/com/destroystokyo/paper/event/executor/asm/SafeClassDefiner.java
|
|
@@ -0,0 +0,0 @@
|
|
+package com.destroystokyo.paper.event.executor.asm;
|
|
+
|
|
+import java.util.concurrent.ConcurrentHashMap;
|
|
+import java.util.concurrent.ConcurrentMap;
|
|
+
|
|
+import com.google.common.base.Preconditions;
|
|
+
|
|
+import com.google.common.collect.MapMaker;
|
|
+import org.objectweb.asm.Type;
|
|
+
|
|
+public class SafeClassDefiner implements ClassDefiner {
|
|
+ /* default */ static final SafeClassDefiner INSTANCE = new SafeClassDefiner();
|
|
+
|
|
+ private SafeClassDefiner() {}
|
|
+
|
|
+ private final ConcurrentMap<ClassLoader, GeneratedClassLoader> loaders = new MapMaker().weakKeys().makeMap();
|
|
+
|
|
+ @Override
|
|
+ public Class<?> defineClass(ClassLoader parentLoader, String name, byte[] data) {
|
|
+ GeneratedClassLoader loader = loaders.computeIfAbsent(parentLoader, GeneratedClassLoader::new);
|
|
+ synchronized (loader.getClassLoadingLock(name)) {
|
|
+ Preconditions.checkState(!loader.hasClass(name), "%s already defined", name);
|
|
+ Class<?> c = loader.define(name, data);
|
|
+ assert c.getName().equals(name);
|
|
+ return c;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ private static class GeneratedClassLoader extends ClassLoader {
|
|
+ static {
|
|
+ ClassLoader.registerAsParallelCapable();
|
|
+ }
|
|
+
|
|
+ protected GeneratedClassLoader(ClassLoader parent) {
|
|
+ super(parent);
|
|
+ }
|
|
+
|
|
+ private Class<?> define(String name, byte[] data) {
|
|
+ synchronized (getClassLoadingLock(name)) {
|
|
+ assert !hasClass(name);
|
|
+ Class<?> c = defineClass(name, data, 0, data.length);
|
|
+ resolveClass(c);
|
|
+ return c;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public Object getClassLoadingLock(String name) {
|
|
+ return super.getClassLoadingLock(name);
|
|
+ }
|
|
+
|
|
+ public boolean hasClass(String name) {
|
|
+ synchronized (getClassLoadingLock(name)) {
|
|
+ try {
|
|
+ Class.forName(name);
|
|
+ return true;
|
|
+ } catch (ClassNotFoundException e) {
|
|
+ return false;
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+}
|
|
diff --git a/src/main/java/com/destroystokyo/paper/utils/UnsafeUtils.java b/src/main/java/com/destroystokyo/paper/utils/UnsafeUtils.java
|
|
new file mode 100644
|
|
index 00000000..62acbf82
|
|
--- /dev/null
|
|
+++ b/src/main/java/com/destroystokyo/paper/utils/UnsafeUtils.java
|
|
@@ -0,0 +0,0 @@
|
|
+package com.destroystokyo.paper.utils;
|
|
+
|
|
+import sun.misc.Unsafe;
|
|
+
|
|
+import java.lang.reflect.Field;
|
|
+
|
|
+public class UnsafeUtils {
|
|
+ private UnsafeUtils() {}
|
|
+
|
|
+ private static final Unsafe UNSAFE;
|
|
+ static {
|
|
+ Unsafe unsafe;
|
|
+ try {
|
|
+ Class c = Class.forName("sun.misc.Unsafe");
|
|
+ Field f = c.getDeclaredField("theUnsafe");
|
|
+ f.setAccessible(true);
|
|
+ unsafe = (Unsafe) f.get(null);
|
|
+ } catch (ClassNotFoundException | NoSuchFieldException | SecurityException e) {
|
|
+ unsafe = null;
|
|
+ } catch (IllegalAccessException e) {
|
|
+ throw new AssertionError(e);
|
|
+ }
|
|
+ UNSAFE = unsafe;
|
|
+ }
|
|
+
|
|
+ public static boolean isUnsafeSupported() {
|
|
+ return UNSAFE != null;
|
|
+ }
|
|
+
|
|
+ public static Unsafe getUnsafe() {
|
|
+ return UNSAFE;
|
|
+ }
|
|
+}
|
|
diff --git a/src/main/java/org/bukkit/plugin/EventExecutor.java b/src/main/java/org/bukkit/plugin/EventExecutor.java
|
|
index 3b2c99ea..b45b6c1c 100644
|
|
--- a/src/main/java/org/bukkit/plugin/EventExecutor.java
|
|
+++ b/src/main/java/org/bukkit/plugin/EventExecutor.java
|
|
@@ -0,0 +0,0 @@ import org.bukkit.event.Event;
|
|
import org.bukkit.event.EventException;
|
|
import org.bukkit.event.Listener;
|
|
|
|
+// Paper start
|
|
+import java.lang.reflect.Method;
|
|
+import java.lang.reflect.Modifier;
|
|
+import java.util.HashMap;
|
|
+import java.util.concurrent.ConcurrentHashMap;
|
|
+import java.util.concurrent.ConcurrentMap;
|
|
+import java.util.function.Function;
|
|
+
|
|
+import com.destroystokyo.paper.event.executor.MethodHandleEventExecutor;
|
|
+import com.destroystokyo.paper.event.executor.StaticMethodHandleEventExecutor;
|
|
+import com.destroystokyo.paper.event.executor.asm.ASMEventExecutorGenerator;
|
|
+import com.destroystokyo.paper.event.executor.asm.ClassDefiner;
|
|
+import com.google.common.base.Preconditions;
|
|
+// Paper end
|
|
+
|
|
/**
|
|
* Interface which defines the class for event call backs to plugins
|
|
*/
|
|
public interface EventExecutor {
|
|
public void execute(Listener listener, Event event) throws EventException;
|
|
+
|
|
+ // Paper start
|
|
+ ConcurrentMap<Method, Class<? extends EventExecutor>> eventExecutorMap = new ConcurrentHashMap<Method, Class<? extends EventExecutor>>() {
|
|
+ @Override
|
|
+ public Class<? extends EventExecutor> computeIfAbsent(Method key, Function<? super Method, ? extends Class<? extends EventExecutor>> mappingFunction) {
|
|
+ Class<? extends EventExecutor> executorClass = get(key);
|
|
+ if (executorClass != null)
|
|
+ return executorClass;
|
|
+
|
|
+ //noinspection SynchronizationOnLocalVariableOrMethodParameter
|
|
+ synchronized (key) {
|
|
+ executorClass = get(key);
|
|
+ if (executorClass != null)
|
|
+ return executorClass;
|
|
+
|
|
+ return super.computeIfAbsent(key, mappingFunction);
|
|
+ }
|
|
+ }
|
|
+ };
|
|
+
|
|
+ public static EventExecutor create(Method m, Class<? extends Event> eventClass) {
|
|
+ Preconditions.checkNotNull(m, "Null method");
|
|
+ Preconditions.checkArgument(m.getParameterCount() != 0, "Incorrect number of arguments %s", m.getParameterCount());
|
|
+ Preconditions.checkArgument(m.getParameterTypes()[0] == eventClass, "First parameter %s doesn't match event class %s", m.getParameterTypes()[0], eventClass);
|
|
+ ClassDefiner definer = ClassDefiner.getInstance();
|
|
+ if (Modifier.isStatic(m.getModifiers())) {
|
|
+ return new StaticMethodHandleEventExecutor(eventClass, m);
|
|
+ } else if (definer.isBypassAccessChecks() || Modifier.isPublic(m.getDeclaringClass().getModifiers()) && Modifier.isPublic(m.getModifiers())) {
|
|
+ // get the existing generated EventExecutor class for the Method or generate one
|
|
+ Class<? extends EventExecutor> executorClass = eventExecutorMap.computeIfAbsent(m, (__) -> {
|
|
+ String name = ASMEventExecutorGenerator.generateName();
|
|
+ byte[] classData = ASMEventExecutorGenerator.generateEventExecutor(m, name);
|
|
+ return definer.defineClass(m.getDeclaringClass().getClassLoader(), name, classData).asSubclass(EventExecutor.class);
|
|
+ });
|
|
+
|
|
+ try {
|
|
+ EventExecutor asmExecutor = executorClass.newInstance();
|
|
+ // Define a wrapper to conform to bukkit stupidity (passing in events that don't match and wrapper exception)
|
|
+ return new EventExecutor() {
|
|
+ @Override
|
|
+ public void execute(Listener listener, Event event) throws EventException {
|
|
+ if (!eventClass.isInstance(event)) return;
|
|
+ try {
|
|
+ asmExecutor.execute(listener, event);
|
|
+ } catch (Exception e) {
|
|
+ throw new EventException(e);
|
|
+ }
|
|
+ }
|
|
+ };
|
|
+ } catch (InstantiationException | IllegalAccessException e) {
|
|
+ throw new AssertionError("Unable to initialize generated event executor", e);
|
|
+ }
|
|
+ } else {
|
|
+ return new MethodHandleEventExecutor(eventClass, m);
|
|
+ }
|
|
+ }
|
|
+ // Paper end
|
|
}
|
|
diff --git a/src/main/java/org/bukkit/plugin/java/JavaPluginLoader.java b/src/main/java/org/bukkit/plugin/java/JavaPluginLoader.java
|
|
index bf972302..77207f14 100644
|
|
--- a/src/main/java/org/bukkit/plugin/java/JavaPluginLoader.java
|
|
+++ b/src/main/java/org/bukkit/plugin/java/JavaPluginLoader.java
|
|
@@ -0,0 +0,0 @@ public final class JavaPluginLoader implements PluginLoader {
|
|
}
|
|
}
|
|
|
|
- EventExecutor executor = new co.aikar.timings.TimedEventExecutor(new EventExecutor() { // Spigot
|
|
- public void execute(Listener listener, Event event) throws EventException {
|
|
- try {
|
|
- if (!eventClass.isAssignableFrom(event.getClass())) {
|
|
- return;
|
|
- }
|
|
- method.invoke(listener, event);
|
|
- } catch (InvocationTargetException ex) {
|
|
- throw new EventException(ex.getCause());
|
|
- } catch (Throwable t) {
|
|
- throw new EventException(t);
|
|
- }
|
|
- }
|
|
- }, plugin, method, eventClass); // Spigot
|
|
+ EventExecutor executor = new co.aikar.timings.TimedEventExecutor(EventExecutor.create(method, eventClass), plugin, method, eventClass); // Spigot // Paper - Use factory method `EventExecutor.create()`
|
|
if (false) { // Spigot - RL handles useTimings check now
|
|
eventSet.add(new TimedRegisteredListener(listener, executor, eh.priority(), plugin, eh.ignoreCancelled()));
|
|
} else {
|
|
--
|