From f79736b8b759b4d7d0de36c87bbdebb579ada69d Mon Sep 17 00:00:00 2001 From: Andrew Steinborn Date: Mon, 12 Jul 2021 08:37:26 -0400 Subject: [PATCH] Fix event ordering. --- .../proxy/event/VelocityEventManager.java | 4 ++- .../proxy/event/EventTest.java | 28 +++++++++++++++++++ 2 files changed, 31 insertions(+), 1 deletion(-) diff --git a/proxy/src/main/java/com/velocitypowered/proxy/event/VelocityEventManager.java b/proxy/src/main/java/com/velocitypowered/proxy/event/VelocityEventManager.java index 212acd166..ac337aa5f 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/event/VelocityEventManager.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/event/VelocityEventManager.java @@ -22,7 +22,9 @@ import static java.util.Objects.requireNonNull; import com.github.benmanes.caffeine.cache.Caffeine; import com.github.benmanes.caffeine.cache.LoadingCache; import com.google.common.base.VerifyException; +import com.google.common.collect.ArrayListMultimap; import com.google.common.collect.HashMultimap; +import com.google.common.collect.ListMultimap; import com.google.common.collect.Multimap; import com.google.common.reflect.TypeToken; import com.google.common.util.concurrent.ThreadFactoryBuilder; @@ -87,7 +89,7 @@ public class VelocityEventManager implements EventManager { private final ExecutorService asyncExecutor; private final PluginManager pluginManager; - private final Multimap, HandlerRegistration> handlersByType = HashMultimap.create(); + private final ListMultimap, HandlerRegistration> handlersByType = ArrayListMultimap.create(); private final LoadingCache, HandlersCache> handlersCache = Caffeine.newBuilder().build(this::bakeHandlers); diff --git a/proxy/src/test/java/com/velocitypowered/proxy/event/EventTest.java b/proxy/src/test/java/com/velocitypowered/proxy/event/EventTest.java index 6a7f96de5..aec0fa12e 100644 --- a/proxy/src/test/java/com/velocitypowered/proxy/event/EventTest.java +++ b/proxy/src/test/java/com/velocitypowered/proxy/event/EventTest.java @@ -27,6 +27,7 @@ import com.velocitypowered.api.event.PostOrder; import com.velocitypowered.api.event.Subscribe; import com.velocitypowered.proxy.testutil.FakePluginManager; import java.util.concurrent.atomic.AtomicInteger; +import java.util.concurrent.atomic.AtomicLong; import org.checkerframework.checker.nullness.qual.MonotonicNonNull; import org.junit.jupiter.api.AfterAll; import org.junit.jupiter.api.Test; @@ -59,6 +60,33 @@ public class EventTest { } } + @Test + void listenerOrderPreserved() throws Exception { + final AtomicLong listenerAInvoked = new AtomicLong(); + final AtomicLong listenerBInvoked = new AtomicLong(); + final AtomicLong listenerCInvoked = new AtomicLong(); + + eventManager.register(FakePluginManager.PLUGIN_A, TestEvent.class, event -> { + listenerAInvoked.set(System.nanoTime()); + }); + eventManager.register(FakePluginManager.PLUGIN_B, TestEvent.class, event -> { + listenerBInvoked.set(System.nanoTime()); + }); + eventManager.register(FakePluginManager.PLUGIN_A, TestEvent.class, event -> { + listenerCInvoked.set(System.nanoTime()); + }); + + try { + eventManager.fire(new TestEvent()).get(); + } finally { + eventManager.unregisterListeners(FakePluginManager.PLUGIN_A); + } + + // Check that the order is A < B < C. Check only that A < B and B < C as B < C and A < B => A < C. + assertTrue(listenerAInvoked.get() < listenerBInvoked.get(), "Listener B invoked before A!"); + assertTrue(listenerBInvoked.get() < listenerCInvoked.get(), "Listener C invoked before B!"); + } + @Test void testAlwaysAsync() throws Exception { final AlwaysAsyncListener listener = new AlwaysAsyncListener();