diff --git a/annotation-processor/src/main/java/com/velocitypowered/annotationprocessor/ApiAnnotationProcessor.java b/annotation-processor/src/main/java/com/velocitypowered/annotationprocessor/ApiAnnotationProcessor.java
index 52975056d..2021543b0 100644
--- a/annotation-processor/src/main/java/com/velocitypowered/annotationprocessor/ApiAnnotationProcessor.java
+++ b/annotation-processor/src/main/java/com/velocitypowered/annotationprocessor/ApiAnnotationProcessor.java
@@ -17,7 +17,6 @@
package com.velocitypowered.annotationprocessor;
-import static com.velocitypowered.annotationprocessor.AnnotationProcessorConstants.EVENTTASK_CLASS;
import static com.velocitypowered.annotationprocessor.AnnotationProcessorConstants.EVENT_INTERFACE;
import static com.velocitypowered.annotationprocessor.AnnotationProcessorConstants.PLUGIN_ANNOTATION_CLASS;
import static com.velocitypowered.annotationprocessor.AnnotationProcessorConstants.SUBSCRIBE_ANNOTATION_CLASS;
@@ -30,9 +29,7 @@ import java.io.IOException;
import java.io.Writer;
import java.util.ArrayList;
import java.util.List;
-import java.util.Objects;
import java.util.Set;
-import javax.annotation.Nullable;
import javax.annotation.processing.AbstractProcessor;
import javax.annotation.processing.Messager;
import javax.annotation.processing.RoundEnvironment;
@@ -45,7 +42,6 @@ import javax.lang.model.element.Modifier;
import javax.lang.model.element.Name;
import javax.lang.model.element.TypeElement;
import javax.lang.model.element.VariableElement;
-import javax.lang.model.type.TypeKind;
import javax.lang.model.type.TypeMirror;
import javax.lang.model.util.Elements;
import javax.lang.model.util.Types;
@@ -91,10 +87,6 @@ public class ApiAnnotationProcessor extends AbstractProcessor {
msg.printMessage(Diagnostic.Kind.ERROR,
"interfaces cannot declare listeners", method);
}
- if (method.getReturnType().getKind() != TypeKind.VOID
- && !this.isTypeSubclass(method.getReturnType(), EVENTTASK_CLASS)) {
- msg.printMessage(Kind.ERROR, "method must return void or EventTask", method);
- }
final List extends VariableElement> parameters = method.getParameters();
if (parameters.isEmpty()
|| !this.isTypeSubclass(parameters.get(0), EVENT_INTERFACE)) {
diff --git a/api/src/main/java/com/velocitypowered/api/event/EventTask.java b/api/src/main/java/com/velocitypowered/api/event/EventTask.java
index 3f72820c4..7471ba06f 100644
--- a/api/src/main/java/com/velocitypowered/api/event/EventTask.java
+++ b/api/src/main/java/com/velocitypowered/api/event/EventTask.java
@@ -17,13 +17,10 @@ import java.util.function.Consumer;
* be suspended and resumed at a later time, and executing event handlers completely or partially
* asynchronously.
*
- *
By default will all event handlers be executed on the thread the event was posted, using
- * event tasks this behavior can be altered.
+ *
By default will all event handlers be executed on the thread the event was posted, this
+ * behavior can be altered by using event tasks.
*/
-public abstract class EventTask {
-
- EventTask() {
- }
+public interface EventTask {
/**
* Whether this {@link EventTask} is required to be called asynchronously.
@@ -34,65 +31,22 @@ public abstract class EventTask {
*
* @return Requires async
*/
- public abstract boolean requiresAsync();
+ boolean requiresAsync();
/**
- * Represents a basic {@link EventTask}. The execution of the event handlers will resume after
- * this basic task is executed using {@link #run()}.
- */
- public abstract static class Basic extends EventTask {
-
- /**
- * Runs the task.
- */
- public abstract void run();
- }
-
- /**
- * Represents an {@link EventTask} which receives a {@link Continuation} through
- * {@link #run(Continuation)}. The continuation must be notified when the task is
- * completed, either with {@link Continuation#resume()} if the task was successful or
- * {@link Continuation#resumeWithException(Throwable)} if an exception occurred.
+ * Runs this event task with the given {@link Continuation}. The continuation must be notified
+ * when the task is completed, either with {@link Continuation#resume()} if the task was
+ * successful or {@link Continuation#resumeWithException(Throwable)} if an exception occurred.
*
*
The {@link Continuation} may only be resumed once, or an
- * {@link IllegalStateException} is expected.
+ * {@link IllegalStateException} will be thrown.
*
- *
The {@link Continuation} doesn't need to be notified during the execution of
- * {@link #run(Continuation)}, this can happen at a later point in time and from another
- * thread.
- */
- public abstract static class WithContinuation extends EventTask {
-
- /**
- * Runs this async task with the given continuation.
- *
- * @param continuation The continuation
- */
- public abstract void run(Continuation continuation);
- }
-
- /**
- * Creates a basic {@link EventTask} from the given {@link Runnable}. The task isn't guaranteed
- * to be executed asynchronously ({@link #requiresAsync()} always returns {@code false}).
+ *
The {@link Continuation} doesn't need to be notified during the execution of this method,
+ * this can happen at a later point in time and from another thread.
*
- * @param task The task
- * @return The event task
+ * @param continuation The continuation
*/
- public static EventTask.Basic of(final Runnable task) {
- requireNonNull(task, "task");
- return new Basic() {
-
- @Override
- public void run() {
- task.run();
- }
-
- @Override
- public boolean requiresAsync() {
- return false;
- }
- };
- }
+ void execute(Continuation continuation);
/**
* Creates a basic async {@link EventTask} from the given {@link Runnable}. The task is guaranteed
@@ -101,13 +55,14 @@ public abstract class EventTask {
* @param task The task
* @return The async event task
*/
- public static EventTask.Basic async(final Runnable task) {
+ static EventTask async(final Runnable task) {
requireNonNull(task, "task");
- return new Basic() {
+ return new EventTask() {
@Override
- public void run() {
+ public void execute(Continuation continuation) {
task.run();
+ continuation.resume();
}
@Override
@@ -125,13 +80,12 @@ public abstract class EventTask {
* @param task The task to execute
* @return The event task
*/
- public static EventTask.WithContinuation withContinuation(
- final Consumer task) {
+ static EventTask withContinuation(final Consumer task) {
requireNonNull(task, "task");
- return new WithContinuation() {
+ return new EventTask() {
@Override
- public void run(final Continuation continuation) {
+ public void execute(final Continuation continuation) {
task.accept(continuation);
}
@@ -142,31 +96,6 @@ public abstract class EventTask {
};
}
- /**
- * Creates an async continuation based {@link EventTask} from the given {@link Consumer}. The task
- * is guaranteed to be executed asynchronously ({@link #requiresAsync()} always returns
- * {@code false}).
- *
- * @param task The task to execute
- * @return The event task
- */
- public static EventTask.WithContinuation asyncWithContinuation(
- final Consumer task) {
- requireNonNull(task, "task");
- return new WithContinuation() {
-
- @Override
- public void run(final Continuation continuation) {
- task.accept(continuation);
- }
-
- @Override
- public boolean requiresAsync() {
- return true;
- }
- };
- }
-
/**
* Creates an continuation based {@link EventTask} for the given {@link CompletableFuture}. The
* continuation will be notified once the given future is completed.
@@ -177,8 +106,7 @@ public abstract class EventTask {
// The Error Prone annotation here is spurious. The Future is handled via the CompletableFuture
// API, which does NOT use the traditional blocking model.
@SuppressWarnings("FutureReturnValueIgnored")
- public static EventTask.WithContinuation resumeWhenComplete(
- final CompletableFuture> future) {
+ static EventTask resumeWhenComplete(final CompletableFuture> future) {
requireNonNull(future, "future");
return withContinuation(continuation -> future.whenComplete((result, cause) -> {
if (cause != null) {
diff --git a/proxy/build.gradle b/proxy/build.gradle
index 089379d54..879eb6815 100644
--- a/proxy/build.gradle
+++ b/proxy/build.gradle
@@ -87,7 +87,7 @@ dependencies {
implementation 'com.electronwill.night-config:toml:3.6.3'
implementation 'org.bstats:bstats-base:2.2.0'
- implementation 'org.lanternpowered:lmbda:2.0.0-SNAPSHOT'
+ implementation 'org.lanternpowered:lmbda:2.0.0'
implementation 'com.github.ben-manes.caffeine:caffeine:2.8.8'
implementation 'com.vdurmont:semver4j:3.1.0'
diff --git a/proxy/src/main/java/com/velocitypowered/proxy/event/CustomHandlerAdapter.java b/proxy/src/main/java/com/velocitypowered/proxy/event/CustomHandlerAdapter.java
new file mode 100644
index 000000000..1bf86efee
--- /dev/null
+++ b/proxy/src/main/java/com/velocitypowered/proxy/event/CustomHandlerAdapter.java
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2018 Velocity Contributors
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+package com.velocitypowered.proxy.event;
+
+import com.google.common.reflect.TypeToken;
+import com.velocitypowered.api.event.Event;
+import com.velocitypowered.api.event.EventHandler;
+import com.velocitypowered.api.event.EventTask;
+import java.lang.invoke.MethodHandle;
+import java.lang.invoke.MethodHandles;
+import java.lang.reflect.Method;
+import java.util.List;
+import java.util.function.BiConsumer;
+import java.util.function.BiFunction;
+import java.util.function.Function;
+import java.util.function.Predicate;
+import org.checkerframework.checker.nullness.qual.Nullable;
+import org.lanternpowered.lmbda.LambdaFactory;
+import org.lanternpowered.lmbda.LambdaType;
+
+final class CustomHandlerAdapter {
+
+ final String name;
+ private final Function> handlerBuilder;
+ final Predicate filter;
+ final BiConsumer> validator;
+ private final LambdaType functionType;
+ private final MethodHandles.Lookup methodHandlesLookup;
+
+ @SuppressWarnings("unchecked")
+ CustomHandlerAdapter(
+ final String name,
+ final Predicate filter,
+ final BiConsumer> validator,
+ final TypeToken invokeFunctionType,
+ final Function> handlerBuilder,
+ final MethodHandles.Lookup methodHandlesLookup) {
+ this.name = name;
+ this.filter = filter;
+ this.validator = validator;
+ this.functionType = (LambdaType) LambdaType.of(invokeFunctionType.getRawType());
+ this.handlerBuilder = handlerBuilder;
+ this.methodHandlesLookup = methodHandlesLookup;
+ }
+
+ UntargetedEventHandler buildUntargetedHandler(final Method method)
+ throws IllegalAccessException {
+ final MethodHandle methodHandle = methodHandlesLookup.unreflect(method);
+ final MethodHandles.Lookup defineLookup = MethodHandles.privateLookupIn(
+ method.getDeclaringClass(), methodHandlesLookup);
+ final LambdaType lambdaType = functionType.defineClassesWith(defineLookup);
+ final F invokeFunction = LambdaFactory.create(lambdaType, methodHandle);
+ final BiFunction