mirror of
https://github.com/DiscordSRV/Ascension.git
synced 2025-01-19 21:11:50 +01:00
Improve event bus priorities, use method handles
This commit is contained in:
parent
05aedf2067
commit
bed92a3450
@ -23,47 +23,19 @@
|
||||
|
||||
package com.discordsrv.api.eventbus;
|
||||
|
||||
import com.discordsrv.api.events.Processable;
|
||||
|
||||
/**
|
||||
* A simple enum to dictate the order that event listeners will be executed, going from {@link #POST} to {@link #POST}.
|
||||
*/
|
||||
public enum EventPriority {
|
||||
@SuppressWarnings("unused") // "API"
|
||||
public class EventPriorities {
|
||||
|
||||
/**
|
||||
* This is the first in the priority order, this should be used to observe the event before any processing.
|
||||
*/
|
||||
PRE,
|
||||
|
||||
/**
|
||||
* This is the earliest in the processing. This should be used to cancel events.
|
||||
*/
|
||||
EARLIEST,
|
||||
|
||||
/**
|
||||
* This should be used to modify events.
|
||||
*/
|
||||
EARLY,
|
||||
|
||||
/**
|
||||
* The default priority, right in the middle of the priority order. Use this if you need to override
|
||||
* one of DiscordSRV's implementations for {@link Processable}s.
|
||||
*/
|
||||
DEFAULT,
|
||||
|
||||
/**
|
||||
* This is where DiscordSRV's integrations for other plugins will process {@link Processable}'s.
|
||||
*/
|
||||
LATE,
|
||||
|
||||
/**
|
||||
* This is where DiscordSRV's default implementations for {@link Processable}'s will run.
|
||||
*/
|
||||
LAST,
|
||||
|
||||
/**
|
||||
* This is the last in the priority order, this should be used to observe the event after all processing is complete.
|
||||
*/
|
||||
POST
|
||||
public static final byte PRE = Byte.MIN_VALUE;
|
||||
public static final byte EARLIEST = (byte) -96;
|
||||
public static final byte EARLY = (byte) -48;
|
||||
public static final byte DEFAULT = (byte) 0;
|
||||
public static final byte LATE = (byte) 48;
|
||||
public static final byte LAST = (byte) 96;
|
||||
public static final byte POST = Byte.MAX_VALUE;
|
||||
|
||||
private EventPriorities() {}
|
||||
}
|
@ -33,7 +33,7 @@ import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* Placed on a public non-abstract non-static method that has only 1 parameters,
|
||||
* Placed on a public non-abstract non-static method that has only 1 parameter,
|
||||
* being an event extending {@link Event} or {@link net.dv8tion.jda.api.events.GenericEvent}.
|
||||
*
|
||||
* You can register a listener through {@link EventBus#subscribe(Object)}, {@link DiscordSRVApi#eventBus()} to get the event bus.
|
||||
@ -52,7 +52,8 @@ public @interface Subscribe {
|
||||
/**
|
||||
* The priority for this event listener, this determines the order that event listeners receive events.
|
||||
* @return the priority of this event listener
|
||||
* @see EventPriorities
|
||||
*/
|
||||
EventPriority priority() default EventPriority.DEFAULT;
|
||||
byte priority() default 0;
|
||||
|
||||
}
|
||||
|
@ -24,7 +24,7 @@
|
||||
package com.discordsrv.api.events.channel;
|
||||
|
||||
import com.discordsrv.api.channel.GameChannel;
|
||||
import com.discordsrv.api.eventbus.EventPriority;
|
||||
import com.discordsrv.api.eventbus.EventPriorities;
|
||||
import com.discordsrv.api.events.Processable;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
@ -32,7 +32,7 @@ import org.jetbrains.annotations.Nullable;
|
||||
/**
|
||||
* This event is used to lookup {@link GameChannel}s by their name (and optionally plugin name).
|
||||
* This is also used to determine which plugin's channel should take priority when multiple plugins
|
||||
* define channels with the same name ({@link EventPriority}).
|
||||
* define channels with the same name ({@link EventPriorities}).
|
||||
*
|
||||
* @see #isDefault()
|
||||
*/
|
||||
|
@ -23,20 +23,20 @@
|
||||
|
||||
package com.discordsrv.api.events.lifecycle;
|
||||
|
||||
import com.discordsrv.api.eventbus.EventPriority;
|
||||
import com.discordsrv.api.eventbus.EventPriorities;
|
||||
import com.discordsrv.api.events.Event;
|
||||
|
||||
/**
|
||||
* Indicates that DiscordSRV is shutting down.
|
||||
* <p>
|
||||
* DiscordSRV's own systems will shut down at the following times:
|
||||
* {@link EventPriority#EARLY}<br/>
|
||||
* {@link EventPriorities#EARLY}<br/>
|
||||
* - DiscordSRV's own modules shutdown<br/>
|
||||
*
|
||||
* {@link EventPriority#LATE}<br/>
|
||||
* {@link EventPriorities#LATE}<br/>
|
||||
* - Discord connections are shutdown<br/>
|
||||
*
|
||||
* {@link EventPriority#LAST}<br/>
|
||||
* {@link EventPriorities#LAST}<br/>
|
||||
* - DiscordSRV's scheduler is shutdown<br/>
|
||||
*/
|
||||
public class DiscordSRVShuttingDownEvent implements Event {
|
||||
|
@ -25,7 +25,7 @@ package com.discordsrv.api.events.message.receive.game;
|
||||
|
||||
import com.discordsrv.api.channel.GameChannel;
|
||||
import com.discordsrv.api.component.MinecraftComponent;
|
||||
import com.discordsrv.api.eventbus.EventPriority;
|
||||
import com.discordsrv.api.eventbus.EventPriorities;
|
||||
import com.discordsrv.api.events.PlayerEvent;
|
||||
import com.discordsrv.api.player.DiscordSRVPlayer;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
@ -33,7 +33,7 @@ import org.jetbrains.annotations.Nullable;
|
||||
|
||||
/**
|
||||
* Indicates that an advancement or achievement message was received will be processed
|
||||
* at {@link EventPriority#DEFAULT} unless cancelled or processed by a 3rd party.
|
||||
* at {@link EventPriorities#DEFAULT} unless cancelled or processed by a 3rd party.
|
||||
*/
|
||||
public class AwardMessageReceiveEvent extends AbstractGameMessageReceiveEvent implements PlayerEvent {
|
||||
|
||||
|
@ -25,7 +25,7 @@ package com.discordsrv.api.events.message.receive.game;
|
||||
|
||||
import com.discordsrv.api.channel.GameChannel;
|
||||
import com.discordsrv.api.component.MinecraftComponent;
|
||||
import com.discordsrv.api.eventbus.EventPriority;
|
||||
import com.discordsrv.api.eventbus.EventPriorities;
|
||||
import com.discordsrv.api.events.PlayerEvent;
|
||||
import com.discordsrv.api.player.DiscordSRVPlayer;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
@ -33,7 +33,7 @@ import org.jetbrains.annotations.Nullable;
|
||||
|
||||
/**
|
||||
* Indicates that a death message was received and will be processed
|
||||
* at {@link EventPriority#DEFAULT} unless cancelled or processed by a 3rd party.
|
||||
* at {@link EventPriorities#DEFAULT} unless cancelled or processed by a 3rd party.
|
||||
*/
|
||||
public class DeathMessageReceiveEvent extends AbstractGameMessageReceiveEvent implements PlayerEvent {
|
||||
|
||||
|
@ -25,7 +25,7 @@ package com.discordsrv.api.events.message.receive.game;
|
||||
|
||||
import com.discordsrv.api.channel.GameChannel;
|
||||
import com.discordsrv.api.component.MinecraftComponent;
|
||||
import com.discordsrv.api.eventbus.EventPriority;
|
||||
import com.discordsrv.api.eventbus.EventPriorities;
|
||||
import com.discordsrv.api.events.PlayerEvent;
|
||||
import com.discordsrv.api.player.DiscordSRVPlayer;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
@ -33,7 +33,7 @@ import org.jetbrains.annotations.Nullable;
|
||||
|
||||
/**
|
||||
* Indicates that a chat message was received and will be processed
|
||||
* at {@link EventPriority#DEFAULT} unless cancelled or processed by a 3rd party.
|
||||
* at {@link EventPriorities#DEFAULT} unless cancelled or processed by a 3rd party.
|
||||
*/
|
||||
public class GameChatMessageReceiveEvent extends AbstractGameMessageReceiveEvent implements PlayerEvent {
|
||||
|
||||
|
@ -25,7 +25,7 @@ package com.discordsrv.api.events.message.receive.game;
|
||||
|
||||
import com.discordsrv.api.channel.GameChannel;
|
||||
import com.discordsrv.api.component.MinecraftComponent;
|
||||
import com.discordsrv.api.eventbus.EventPriority;
|
||||
import com.discordsrv.api.eventbus.EventPriorities;
|
||||
import com.discordsrv.api.events.PlayerEvent;
|
||||
import com.discordsrv.api.player.DiscordSRVPlayer;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
@ -33,7 +33,7 @@ import org.jetbrains.annotations.Nullable;
|
||||
|
||||
/**
|
||||
* Indicates that a join message was received and will be processed
|
||||
* at {@link EventPriority#DEFAULT} unless cancelled or processed by a 3rd party.
|
||||
* at {@link EventPriorities#DEFAULT} unless cancelled or processed by a 3rd party.
|
||||
*/
|
||||
public class JoinMessageReceiveEvent extends AbstractGameMessageReceiveEvent implements PlayerEvent {
|
||||
|
||||
|
@ -25,7 +25,7 @@ package com.discordsrv.api.events.message.receive.game;
|
||||
|
||||
import com.discordsrv.api.channel.GameChannel;
|
||||
import com.discordsrv.api.component.MinecraftComponent;
|
||||
import com.discordsrv.api.eventbus.EventPriority;
|
||||
import com.discordsrv.api.eventbus.EventPriorities;
|
||||
import com.discordsrv.api.events.PlayerEvent;
|
||||
import com.discordsrv.api.player.DiscordSRVPlayer;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
@ -33,7 +33,7 @@ import org.jetbrains.annotations.Nullable;
|
||||
|
||||
/**
|
||||
* Indicates that a leave message was received and will be processed
|
||||
* at {@link EventPriority#DEFAULT} unless cancelled or processed by a 3rd party.
|
||||
* at {@link EventPriorities#DEFAULT} unless cancelled or processed by a 3rd party.
|
||||
*/
|
||||
public class LeaveMessageReceiveEvent extends AbstractGameMessageReceiveEvent implements PlayerEvent {
|
||||
|
||||
|
@ -24,7 +24,7 @@
|
||||
package com.discordsrv.api.events.message.receive.game;
|
||||
|
||||
import com.discordsrv.api.component.MinecraftComponent;
|
||||
import com.discordsrv.api.eventbus.EventPriority;
|
||||
import com.discordsrv.api.eventbus.EventPriorities;
|
||||
import com.discordsrv.api.events.PlayerEvent;
|
||||
import com.discordsrv.api.player.DiscordSRVPlayer;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
@ -32,7 +32,7 @@ import org.jetbrains.annotations.Nullable;
|
||||
|
||||
/**
|
||||
* Indicates that a server switch message was received and will be processed
|
||||
* at {@link EventPriority#DEFAULT} unless cancelled or processed by a 3rd party.
|
||||
* at {@link EventPriorities#DEFAULT} unless cancelled or processed by a 3rd party.
|
||||
*/
|
||||
public class ServerSwitchMessageReceiveEvent extends AbstractGameMessageReceiveEvent implements PlayerEvent {
|
||||
|
||||
|
@ -20,7 +20,7 @@ package com.discordsrv.bukkit.integration;
|
||||
|
||||
import com.discordsrv.api.channel.GameChannel;
|
||||
import com.discordsrv.api.component.MinecraftComponent;
|
||||
import com.discordsrv.api.eventbus.EventPriority;
|
||||
import com.discordsrv.api.eventbus.EventPriorities;
|
||||
import com.discordsrv.api.eventbus.Subscribe;
|
||||
import com.discordsrv.api.events.channel.GameChannelLookupEvent;
|
||||
import com.discordsrv.api.events.message.receive.game.GameChatMessageReceiveEvent;
|
||||
@ -149,7 +149,7 @@ public class EssentialsXIntegration
|
||||
));
|
||||
}
|
||||
|
||||
@Subscribe(priority = EventPriority.LAST)
|
||||
@Subscribe(priority = EventPriorities.LAST)
|
||||
public void onGameChannelLookup(GameChannelLookupEvent event) {
|
||||
if (checkProcessor(event) || !discordSRV.server().getPluginManager().isPluginEnabled("EssentialsChat")) {
|
||||
return;
|
||||
|
@ -18,7 +18,7 @@
|
||||
|
||||
package com.discordsrv.bukkit.integration.chat;
|
||||
|
||||
import com.discordsrv.api.eventbus.EventPriority;
|
||||
import com.discordsrv.api.eventbus.EventPriorities;
|
||||
import com.discordsrv.api.eventbus.Subscribe;
|
||||
import com.discordsrv.api.events.message.receive.game.GameChatMessageReceiveEvent;
|
||||
import com.discordsrv.api.player.DiscordSRVPlayer;
|
||||
@ -50,7 +50,7 @@ public class GriefPreventionChatIntegration extends PluginIntegration<BukkitDisc
|
||||
return super.isEnabled();
|
||||
}
|
||||
|
||||
@Subscribe(priority = EventPriority.EARLY)
|
||||
@Subscribe(priority = EventPriorities.EARLY)
|
||||
public void onGameChatMessageReceive(GameChatMessageReceiveEvent event) {
|
||||
GriefPrevention griefPrevention = (GriefPrevention) discordSRV.server().getPluginManager().getPlugin(
|
||||
getIntegrationId());
|
||||
|
@ -20,7 +20,7 @@ package com.discordsrv.bukkit.integration.chat;
|
||||
|
||||
import com.discordsrv.api.channel.GameChannel;
|
||||
import com.discordsrv.api.component.MinecraftComponent;
|
||||
import com.discordsrv.api.eventbus.EventPriority;
|
||||
import com.discordsrv.api.eventbus.EventPriorities;
|
||||
import com.discordsrv.api.eventbus.Subscribe;
|
||||
import com.discordsrv.api.events.channel.GameChannelLookupEvent;
|
||||
import com.discordsrv.api.events.message.receive.game.GameChatMessageReceiveEvent;
|
||||
@ -80,7 +80,7 @@ public class McMMOChatIntegration extends PluginIntegration<BukkitDiscordSRV> im
|
||||
HandlerList.unregisterAll(this);
|
||||
}
|
||||
|
||||
@Subscribe(priority = EventPriority.EARLY)
|
||||
@Subscribe(priority = EventPriorities.EARLY)
|
||||
public void onGameChatMessageReceive(GameChatMessageReceiveEvent event) {
|
||||
Player player = discordSRV.server().getPlayer(event.getPlayer().uniqueId());
|
||||
if (!player.hasMetadata("mcMMO: Player Data")) {
|
||||
|
@ -20,7 +20,6 @@ package com.discordsrv.common.core.eventbus;
|
||||
|
||||
import com.discordsrv.api.eventbus.EventBus;
|
||||
import com.discordsrv.api.eventbus.EventListener;
|
||||
import com.discordsrv.api.eventbus.EventPriority;
|
||||
import com.discordsrv.api.eventbus.Subscribe;
|
||||
import com.discordsrv.api.eventbus.internal.EventStateHolder;
|
||||
import com.discordsrv.api.events.Cancellable;
|
||||
@ -37,36 +36,40 @@ import net.dv8tion.jda.api.events.GenericEvent;
|
||||
import org.apache.commons.lang3.tuple.Pair;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.invoke.MethodHandle;
|
||||
import java.lang.invoke.MethodHandles;
|
||||
import java.lang.invoke.MethodType;
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.CopyOnWriteArrayList;
|
||||
import java.util.function.Function;
|
||||
import java.util.function.Predicate;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static com.discordsrv.common.util.ExceptionUtil.minifyException;
|
||||
|
||||
public class EventBusImpl implements EventBus {
|
||||
|
||||
private static final List<Pair<Function<Object, Boolean>, ThreadLocal<EventListener>>> STATES = Arrays.asList(
|
||||
Pair.of(event -> event instanceof Cancellable && ((Cancellable) event).isCancelled(), EventStateHolder.CANCELLED),
|
||||
Pair.of(event -> event instanceof Processable && ((Processable) event).isProcessed(), EventStateHolder.PROCESSED)
|
||||
private static final List<State<?>> STATES = Arrays.asList(
|
||||
new State<>(Cancellable.class, Cancellable::isCancelled, EventStateHolder.CANCELLED),
|
||||
new State<>(Processable.class, Processable::isProcessed, EventStateHolder.PROCESSED)
|
||||
);
|
||||
|
||||
private final Map<Object, List<EventListenerImpl>> listeners = new ConcurrentHashMap<>();
|
||||
private final List<EventListenerImpl> allListeners = new CopyOnWriteArrayList<>();
|
||||
private final Map<Class<?>, List<EventListenerImpl>> listenersByEvent = new ConcurrentHashMap<>();
|
||||
private final Logger logger;
|
||||
|
||||
public EventBusImpl(DiscordSRV discordSRV) {
|
||||
this.logger = new NamedLogger(discordSRV, "EVENT_BUS");
|
||||
|
||||
// For debug generation
|
||||
subscribe(this);
|
||||
}
|
||||
|
||||
public void shutdown() {
|
||||
listeners.clear();
|
||||
allListeners.clear();
|
||||
listenersByEvent.clear();
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -87,7 +90,10 @@ public class EventBusImpl implements EventBus {
|
||||
}
|
||||
|
||||
listeners.put(eventListener, methods);
|
||||
allListeners.addAll(methods);
|
||||
for (EventListenerImpl method : methods) {
|
||||
listenersByEvent.computeIfAbsent(method.eventClass(), key -> new CopyOnWriteArrayList<>())
|
||||
.add(method);
|
||||
}
|
||||
logger.debug("Listener " + eventListener.getClass().getName() + " subscribed");
|
||||
}
|
||||
|
||||
@ -123,7 +129,8 @@ public class EventBusImpl implements EventBus {
|
||||
int parameters = parameterTypes.length;
|
||||
List<Throwable> suppressed = new ArrayList<>();
|
||||
|
||||
if (Void.class.isAssignableFrom(method.getReturnType())) {
|
||||
Class<?> returnType = method.getReturnType();
|
||||
if (Void.class.isAssignableFrom(returnType)) {
|
||||
suppressed.add(createReasonException("Must return void"));
|
||||
}
|
||||
|
||||
@ -149,6 +156,14 @@ public class EventBusImpl implements EventBus {
|
||||
}
|
||||
}
|
||||
|
||||
MethodHandle handle = null;
|
||||
MethodType methodType = MethodType.methodType(method.getReturnType(), method.getParameterTypes());
|
||||
try {
|
||||
handle = MethodHandles.lookup().findVirtual(listenerClass, method.getName(), methodType);
|
||||
} catch (ReflectiveOperationException e) {
|
||||
suppressedMethods.add(e);
|
||||
}
|
||||
|
||||
if (!suppressed.isEmpty()) {
|
||||
Exception methodException = new InvalidListenerMethodException("Method " + method.getName() + "(" +
|
||||
(parameters > 0 ? Arrays.stream(method.getParameterTypes())
|
||||
@ -159,7 +174,7 @@ public class EventBusImpl implements EventBus {
|
||||
return;
|
||||
}
|
||||
|
||||
EventListenerImpl listener = new EventListenerImpl(eventListener, listenerClass, annotation, firstParameter, method);
|
||||
EventListenerImpl listener = new EventListenerImpl(eventListener, listenerClass, annotation, firstParameter, method, handle);
|
||||
methods.add(listener);
|
||||
}
|
||||
|
||||
@ -172,7 +187,14 @@ public class EventBusImpl implements EventBus {
|
||||
public void unsubscribe(@NotNull Object eventListener) {
|
||||
List<EventListenerImpl> removed = listeners.remove(eventListener);
|
||||
if (removed != null) {
|
||||
allListeners.removeAll(removed);
|
||||
for (EventListenerImpl listener : removed) {
|
||||
Class<?> eventClass = listener.eventClass();
|
||||
List<EventListenerImpl> listeners = listenersByEvent.get(eventClass);
|
||||
listeners.remove(listener);
|
||||
if (listeners.isEmpty()) {
|
||||
listenersByEvent.remove(eventClass);
|
||||
}
|
||||
}
|
||||
logger.debug("Listener " + eventListener.getClass().getName() + " unsubscribed");
|
||||
}
|
||||
}
|
||||
@ -187,86 +209,102 @@ public class EventBusImpl implements EventBus {
|
||||
publishEvent(event);
|
||||
}
|
||||
|
||||
private void publishEvent(Object event) {
|
||||
List<Boolean> states = new ArrayList<>(STATES.size());
|
||||
for (Pair<Function<Object, Boolean>, ThreadLocal<EventListener>> entry : STATES) {
|
||||
if (entry.getKey().apply(event)) {
|
||||
// If the state is already set before listeners, we mark it as being changed by a 'unknown' event listener
|
||||
states.add(true);
|
||||
entry.getValue().set(EventStateHolder.UNKNOWN_LISTENER);
|
||||
continue;
|
||||
private void gatherListeners(Class<?> eventClass, List<EventListenerImpl> listeners) {
|
||||
List<EventListenerImpl> listenersForEvent = this.listenersByEvent.get(eventClass);
|
||||
if (listenersForEvent == null) {
|
||||
return;
|
||||
}
|
||||
states.add(false);
|
||||
listeners.addAll(listenersForEvent);
|
||||
}
|
||||
|
||||
private void publishEvent(Object event) {
|
||||
Class<?> eventClass = event.getClass();
|
||||
for (EventPriority priority : EventPriority.values()) {
|
||||
for (EventListenerImpl eventListener : allListeners) {
|
||||
|
||||
Map<State<?>, Boolean> states = new HashMap<>(STATES.size());
|
||||
for (State<?> state : STATES) {
|
||||
if (state.eventClass().isAssignableFrom(eventClass)) {
|
||||
boolean value = state.statePredicate().test(event);
|
||||
states.put(state, value);
|
||||
|
||||
if (value) {
|
||||
state.stateHolder().set(EventStateHolder.UNKNOWN_LISTENER);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
List<EventListenerImpl> listeners = new ArrayList<>();
|
||||
while (!Object.class.equals(eventClass)) {
|
||||
gatherListeners(eventClass, listeners);
|
||||
for (Class<?> anInterface : eventClass.getInterfaces()) {
|
||||
gatherListeners(anInterface, listeners);
|
||||
}
|
||||
|
||||
eventClass = eventClass.getSuperclass();
|
||||
}
|
||||
|
||||
listeners.sort(Comparator.comparingInt(EventListenerImpl::priority));
|
||||
|
||||
for (EventListenerImpl eventListener : listeners) {
|
||||
if (eventListener.isIgnoringCancelled() && event instanceof Cancellable && ((Cancellable) event).isCancelled()) {
|
||||
continue;
|
||||
}
|
||||
if (eventListener.priority() != priority) {
|
||||
continue;
|
||||
}
|
||||
if (!eventListener.eventClass().isAssignableFrom(eventClass)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
long startTime = System.currentTimeMillis();
|
||||
try {
|
||||
Object listener = eventListener.listener();
|
||||
eventListener.method().invoke(listener, event);
|
||||
} catch (IllegalAccessException e) {
|
||||
logger.error("Failed to access listener method: " + eventListener.methodName() + " in " + eventListener.className(), e);
|
||||
TestHelper.fail(e);
|
||||
} catch (InvocationTargetException e) {
|
||||
eventListener.handle().invoke(listener, event);
|
||||
} catch (Throwable e) {
|
||||
String eventClassName = eventClass.getName();
|
||||
Throwable cause = e.getCause();
|
||||
if (eventListener.className().startsWith("com.discordsrv")) {
|
||||
logger.error("Failed to pass " + eventClassName + " to " + eventListener, cause);
|
||||
logger.error("Failed to pass " + eventClassName + " to " + eventListener, e);
|
||||
} else {
|
||||
// Print the listener failing without references to the DiscordSRV event bus
|
||||
// as it isn't relevant to the exception, and often causes users to suspect DiscordSRV is doing something wrong when it isn't
|
||||
//noinspection CallToPrintStackTrace
|
||||
e.getCause().printStackTrace();
|
||||
e.printStackTrace();
|
||||
}
|
||||
TestHelper.fail(cause);
|
||||
TestHelper.fail(e);
|
||||
}
|
||||
long timeTaken = System.currentTimeMillis() - startTime;
|
||||
logger.trace(eventListener + " took " + timeTaken + "ms to execute");
|
||||
|
||||
for (int index = 0; index < STATES.size(); index++) {
|
||||
Pair<Function<Object, Boolean>, ThreadLocal<EventListener>> state = STATES.get(index);
|
||||
for (Map.Entry<State<?>, Boolean> entry : states.entrySet()) {
|
||||
State<?> state = entry.getKey();
|
||||
boolean currentValue = entry.getValue();
|
||||
boolean newValue = state.statePredicate().test(event);
|
||||
|
||||
boolean current = states.get(index);
|
||||
boolean updated = state.getKey().apply(event);
|
||||
states.set(index, updated);
|
||||
if (currentValue == newValue) {
|
||||
continue;
|
||||
}
|
||||
|
||||
ThreadLocal<EventListener> stateHolder = state.getValue();
|
||||
if (current != updated) {
|
||||
if (updated) {
|
||||
stateHolder.set(eventListener);
|
||||
if (currentValue) {
|
||||
state.stateHolder().set(eventListener);
|
||||
} else {
|
||||
stateHolder.remove();
|
||||
}
|
||||
}
|
||||
state.stateHolder().set(EventStateHolder.UNKNOWN_LISTENER);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Clear the states
|
||||
for (Pair<Function<Object, Boolean>, ThreadLocal<EventListener>> state : STATES) {
|
||||
state.getValue().remove();
|
||||
for (State<?> state : states.keySet()) {
|
||||
state.stateHolder().remove();
|
||||
}
|
||||
}
|
||||
|
||||
@Subscribe
|
||||
public void onDebugGenerate(DebugGenerateEvent event) {
|
||||
StringBuilder builder = new StringBuilder("Registered listeners (" + listeners.size() + "/" + allListeners.size() + "):\n");
|
||||
StringBuilder builder = new StringBuilder("Registered listeners\n");
|
||||
builder.append(" (").append(listeners.size()).append(" listeners classes)\n");
|
||||
builder.append(" (for ").append(listenersByEvent.size()).append(" events)\n");
|
||||
builder.append(" (for a total of ")
|
||||
.append(listeners.values().stream().mapToInt(List::size).sum())
|
||||
.append(" individual listeners methods)\n");
|
||||
|
||||
for (Map.Entry<Object, List<EventListenerImpl>> entry : listeners.entrySet()) {
|
||||
Object listener = entry.getKey();
|
||||
List<EventListenerImpl> eventListeners = entry.getValue();
|
||||
eventListeners.sort(Comparator.comparingInt(EventListenerImpl::priority));
|
||||
|
||||
builder.append('\n')
|
||||
.append(listener)
|
||||
.append(" (")
|
||||
@ -280,11 +318,37 @@ public class EventBusImpl implements EventBus {
|
||||
.append(": ")
|
||||
.append(eventListener.methodName())
|
||||
.append(" @ ")
|
||||
.append(eventListener.priority().name())
|
||||
.append(eventListener.priority())
|
||||
.append('\n');
|
||||
}
|
||||
}
|
||||
|
||||
event.addFile(new TextDebugFile("event-bus.txt", builder));
|
||||
}
|
||||
|
||||
private static class State<T> {
|
||||
|
||||
private final Class<T> eventClass;
|
||||
private final Predicate<Object> statePredicate;
|
||||
private final ThreadLocal<EventListener> stateHolder;
|
||||
|
||||
@SuppressWarnings("unchecked") // Converting generic to Object is easier down the line
|
||||
public State(Class<T> eventClass, Predicate<T> statePredicate, ThreadLocal<EventListener> stateHolder) {
|
||||
this.eventClass = eventClass;
|
||||
this.statePredicate = (Predicate<Object>) statePredicate;
|
||||
this.stateHolder = stateHolder;
|
||||
}
|
||||
|
||||
public Class<T> eventClass() {
|
||||
return eventClass;
|
||||
}
|
||||
|
||||
public Predicate<Object> statePredicate() {
|
||||
return statePredicate;
|
||||
}
|
||||
|
||||
public ThreadLocal<EventListener> stateHolder() {
|
||||
return stateHolder;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -19,10 +19,10 @@
|
||||
package com.discordsrv.common.core.eventbus;
|
||||
|
||||
import com.discordsrv.api.eventbus.EventListener;
|
||||
import com.discordsrv.api.eventbus.EventPriority;
|
||||
import com.discordsrv.api.eventbus.Subscribe;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.lang.invoke.MethodHandle;
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
public class EventListenerImpl implements EventListener {
|
||||
@ -32,20 +32,22 @@ public class EventListenerImpl implements EventListener {
|
||||
private final Subscribe annotation;
|
||||
private final Class<?> eventClass;
|
||||
private final Method method;
|
||||
private final MethodHandle handle;
|
||||
|
||||
public EventListenerImpl(Object listener, Class<?> listenerClass, Subscribe annotation, Class<?> eventClass, Method method) {
|
||||
public EventListenerImpl(Object listener, Class<?> listenerClass, Subscribe annotation, Class<?> eventClass, Method method, MethodHandle handle) {
|
||||
this.listener = listener;
|
||||
this.listenerClass = listenerClass;
|
||||
this.annotation = annotation;
|
||||
this.eventClass = eventClass;
|
||||
this.method = method;
|
||||
this.handle = handle;
|
||||
}
|
||||
|
||||
public boolean isIgnoringCancelled() {
|
||||
return annotation.ignoreCancelled();
|
||||
}
|
||||
|
||||
public EventPriority priority() {
|
||||
public byte priority() {
|
||||
return annotation.priority();
|
||||
}
|
||||
|
||||
@ -72,6 +74,10 @@ public class EventListenerImpl implements EventListener {
|
||||
return method.getName();
|
||||
}
|
||||
|
||||
public MethodHandle handle() {
|
||||
return handle;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "EventListenerImpl{" + className() + "#" + methodName() + "}";
|
||||
|
@ -21,7 +21,7 @@ package com.discordsrv.common.core.module;
|
||||
import com.discordsrv.api.discord.connection.details.DiscordCacheFlag;
|
||||
import com.discordsrv.api.discord.connection.details.DiscordGatewayIntent;
|
||||
import com.discordsrv.api.discord.connection.details.DiscordMemberCachePolicy;
|
||||
import com.discordsrv.api.eventbus.EventPriority;
|
||||
import com.discordsrv.api.eventbus.EventPriorities;
|
||||
import com.discordsrv.api.eventbus.Subscribe;
|
||||
import com.discordsrv.api.events.lifecycle.DiscordSRVReadyEvent;
|
||||
import com.discordsrv.api.events.lifecycle.DiscordSRVShuttingDownEvent;
|
||||
@ -200,7 +200,7 @@ public class ModuleManager {
|
||||
}
|
||||
}
|
||||
|
||||
@Subscribe(priority = EventPriority.EARLY)
|
||||
@Subscribe(priority = EventPriorities.EARLY)
|
||||
public void onShuttingDown(DiscordSRVShuttingDownEvent event) {
|
||||
modules.stream()
|
||||
.sorted((m1, m2) -> Integer.compare(m2.shutdownOrder(), m1.shutdownOrder()))
|
||||
|
@ -18,7 +18,7 @@
|
||||
|
||||
package com.discordsrv.common.core.scheduler;
|
||||
|
||||
import com.discordsrv.api.eventbus.EventPriority;
|
||||
import com.discordsrv.api.eventbus.EventPriorities;
|
||||
import com.discordsrv.api.eventbus.Subscribe;
|
||||
import com.discordsrv.api.events.lifecycle.DiscordSRVShuttingDownEvent;
|
||||
import com.discordsrv.common.DiscordSRV;
|
||||
@ -82,7 +82,7 @@ public class StandardScheduler implements Scheduler {
|
||||
this.forkJoinPool = forkJoinPool;
|
||||
}
|
||||
|
||||
@Subscribe(priority = EventPriority.LAST)
|
||||
@Subscribe(priority = EventPriorities.LAST)
|
||||
public void onShuttingDown(DiscordSRVShuttingDownEvent event) {
|
||||
executorService.shutdownNow();
|
||||
scheduledExecutorService.shutdownNow();
|
||||
|
@ -25,7 +25,7 @@ import com.discordsrv.api.discord.connection.details.DiscordMemberCachePolicy;
|
||||
import com.discordsrv.api.discord.connection.jda.errorresponse.ErrorCallbackContext;
|
||||
import com.discordsrv.api.discord.entity.DiscordUser;
|
||||
import com.discordsrv.api.discord.entity.guild.DiscordGuildMember;
|
||||
import com.discordsrv.api.eventbus.EventPriority;
|
||||
import com.discordsrv.api.eventbus.EventPriorities;
|
||||
import com.discordsrv.api.eventbus.Subscribe;
|
||||
import com.discordsrv.api.events.lifecycle.DiscordSRVShuttingDownEvent;
|
||||
import com.discordsrv.api.events.placeholder.PlaceholderLookupEvent;
|
||||
@ -221,7 +221,7 @@ public class JDAConnectionManager implements DiscordConnectionManager {
|
||||
event.addFile(new TextDebugFile("jda_connection_manager.txt", builder));
|
||||
}
|
||||
|
||||
@Subscribe(priority = EventPriority.EARLIEST)
|
||||
@Subscribe(priority = EventPriorities.EARLIEST)
|
||||
public void onPlaceholderLookup(PlaceholderLookupEvent event) {
|
||||
if (event.isProcessed()) {
|
||||
return;
|
||||
@ -433,7 +433,7 @@ public class JDAConnectionManager implements DiscordConnectionManager {
|
||||
}
|
||||
}
|
||||
|
||||
@Subscribe(priority = EventPriority.LATE)
|
||||
@Subscribe(priority = EventPriorities.LATE)
|
||||
public void onDSRVShuttingDown(DiscordSRVShuttingDownEvent event) {
|
||||
shutdown(DEFAULT_SHUTDOWN_TIMEOUT);
|
||||
}
|
||||
|
@ -18,7 +18,7 @@
|
||||
|
||||
package com.discordsrv.common.feature;
|
||||
|
||||
import com.discordsrv.api.eventbus.EventPriority;
|
||||
import com.discordsrv.api.eventbus.EventPriorities;
|
||||
import com.discordsrv.api.eventbus.Subscribe;
|
||||
import com.discordsrv.api.events.lifecycle.DiscordSRVShuttingDownEvent;
|
||||
import com.discordsrv.api.reload.ReloadResult;
|
||||
@ -56,7 +56,7 @@ public class PresenceUpdaterModule extends AbstractModule<DiscordSRV> {
|
||||
setPresenceOrSchedule();
|
||||
}
|
||||
|
||||
@Subscribe(priority = EventPriority.EARLIEST)
|
||||
@Subscribe(priority = EventPriorities.EARLIEST)
|
||||
public void onDiscordSRVShuttingDown(DiscordSRVShuttingDownEvent event) {
|
||||
serverState.set(ServerState.STOPPING);
|
||||
setPresenceOrSchedule();
|
||||
|
@ -18,7 +18,7 @@
|
||||
|
||||
package com.discordsrv.common.feature.channel.global;
|
||||
|
||||
import com.discordsrv.api.eventbus.EventPriority;
|
||||
import com.discordsrv.api.eventbus.EventPriorities;
|
||||
import com.discordsrv.api.eventbus.Subscribe;
|
||||
import com.discordsrv.api.events.channel.GameChannelLookupEvent;
|
||||
import com.discordsrv.common.DiscordSRV;
|
||||
@ -30,7 +30,7 @@ public class GlobalChannelLookupModule extends AbstractModule<DiscordSRV> {
|
||||
super(discordSRV);
|
||||
}
|
||||
|
||||
@Subscribe(priority = EventPriority.LATE)
|
||||
@Subscribe(priority = EventPriorities.LATE)
|
||||
public void onGameChannelLookup(GameChannelLookupEvent event) {
|
||||
if (event.getChannelName().equalsIgnoreCase("global")) {
|
||||
if (checkProcessor(event)) {
|
||||
|
@ -22,7 +22,7 @@ import com.discordsrv.api.channel.GameChannel;
|
||||
import com.discordsrv.api.component.MinecraftComponent;
|
||||
import com.discordsrv.api.discord.entity.message.ReceivedDiscordMessageCluster;
|
||||
import com.discordsrv.api.discord.entity.message.SendableDiscordMessage;
|
||||
import com.discordsrv.api.eventbus.EventPriority;
|
||||
import com.discordsrv.api.eventbus.EventPriorities;
|
||||
import com.discordsrv.api.eventbus.Subscribe;
|
||||
import com.discordsrv.api.events.message.forward.game.AwardMessageForwardedEvent;
|
||||
import com.discordsrv.api.events.message.receive.game.AwardMessageReceiveEvent;
|
||||
@ -65,7 +65,7 @@ public class AwardMessageModule extends AbstractGameMessageModule<AwardMessageCo
|
||||
return permit;
|
||||
}
|
||||
|
||||
@Subscribe(priority = EventPriority.LAST)
|
||||
@Subscribe(priority = EventPriorities.LAST)
|
||||
public void onAwardMessageReceive(AwardMessageReceiveEvent event) {
|
||||
if (checkCancellation(event) || checkProcessor(event)) {
|
||||
return;
|
||||
|
@ -22,7 +22,7 @@ import com.discordsrv.api.channel.GameChannel;
|
||||
import com.discordsrv.api.component.MinecraftComponent;
|
||||
import com.discordsrv.api.discord.entity.message.ReceivedDiscordMessageCluster;
|
||||
import com.discordsrv.api.discord.entity.message.SendableDiscordMessage;
|
||||
import com.discordsrv.api.eventbus.EventPriority;
|
||||
import com.discordsrv.api.eventbus.EventPriorities;
|
||||
import com.discordsrv.api.eventbus.Subscribe;
|
||||
import com.discordsrv.api.events.message.forward.game.DeathMessageForwardedEvent;
|
||||
import com.discordsrv.api.events.message.receive.game.DeathMessageReceiveEvent;
|
||||
@ -39,7 +39,7 @@ public class DeathMessageModule extends AbstractGameMessageModule<DeathMessageCo
|
||||
super(discordSRV, "DEATH_MESSAGES");
|
||||
}
|
||||
|
||||
@Subscribe(priority = EventPriority.LAST)
|
||||
@Subscribe(priority = EventPriorities.LAST)
|
||||
public void onDeathMessageReceive(DeathMessageReceiveEvent event) {
|
||||
if (checkCancellation(event) || checkProcessor(event)) {
|
||||
return;
|
||||
|
@ -22,7 +22,7 @@ import com.discordsrv.api.channel.GameChannel;
|
||||
import com.discordsrv.api.component.MinecraftComponent;
|
||||
import com.discordsrv.api.discord.entity.message.ReceivedDiscordMessageCluster;
|
||||
import com.discordsrv.api.discord.entity.message.SendableDiscordMessage;
|
||||
import com.discordsrv.api.eventbus.EventPriority;
|
||||
import com.discordsrv.api.eventbus.EventPriorities;
|
||||
import com.discordsrv.api.eventbus.Subscribe;
|
||||
import com.discordsrv.api.events.message.forward.game.JoinMessageForwardedEvent;
|
||||
import com.discordsrv.api.events.message.receive.game.JoinMessageReceiveEvent;
|
||||
@ -52,7 +52,7 @@ public class JoinMessageModule extends AbstractGameMessageModule<IMessageConfig,
|
||||
super(discordSRV, "JOIN_MESSAGES");
|
||||
}
|
||||
|
||||
@Subscribe(priority = EventPriority.LAST)
|
||||
@Subscribe(priority = EventPriorities.LAST)
|
||||
public void onJoinMessageReceive(JoinMessageReceiveEvent event) {
|
||||
if (checkCancellation(event) || checkProcessor(event)) {
|
||||
return;
|
||||
|
@ -22,7 +22,7 @@ import com.discordsrv.api.channel.GameChannel;
|
||||
import com.discordsrv.api.component.MinecraftComponent;
|
||||
import com.discordsrv.api.discord.entity.message.ReceivedDiscordMessageCluster;
|
||||
import com.discordsrv.api.discord.entity.message.SendableDiscordMessage;
|
||||
import com.discordsrv.api.eventbus.EventPriority;
|
||||
import com.discordsrv.api.eventbus.EventPriorities;
|
||||
import com.discordsrv.api.eventbus.Subscribe;
|
||||
import com.discordsrv.api.events.message.forward.game.LeaveMessageForwardedEvent;
|
||||
import com.discordsrv.api.events.message.receive.game.LeaveMessageReceiveEvent;
|
||||
@ -75,7 +75,7 @@ public class LeaveMessageModule extends AbstractGameMessageModule<LeaveMessageCo
|
||||
}
|
||||
}
|
||||
|
||||
@Subscribe(priority = EventPriority.LAST)
|
||||
@Subscribe(priority = EventPriorities.LAST)
|
||||
public void onLeaveMessageReceive(LeaveMessageReceiveEvent event) {
|
||||
if (checkCancellation(event) || checkProcessor(event)) {
|
||||
return;
|
||||
|
@ -25,7 +25,7 @@ import com.discordsrv.api.discord.entity.message.AllowedMention;
|
||||
import com.discordsrv.api.discord.entity.message.ReceivedDiscordMessage;
|
||||
import com.discordsrv.api.discord.entity.message.ReceivedDiscordMessageCluster;
|
||||
import com.discordsrv.api.discord.entity.message.SendableDiscordMessage;
|
||||
import com.discordsrv.api.eventbus.EventPriority;
|
||||
import com.discordsrv.api.eventbus.EventPriorities;
|
||||
import com.discordsrv.api.eventbus.Subscribe;
|
||||
import com.discordsrv.api.events.message.forward.game.GameChatMessageForwardedEvent;
|
||||
import com.discordsrv.api.events.message.receive.game.GameChatMessageReceiveEvent;
|
||||
@ -54,7 +54,7 @@ public class MinecraftToDiscordChatModule extends AbstractGameMessageModule<Mine
|
||||
super(discordSRV, "MINECRAFT_TO_DISCORD");
|
||||
}
|
||||
|
||||
@Subscribe(priority = EventPriority.LAST)
|
||||
@Subscribe(priority = EventPriorities.LAST)
|
||||
public void onChatReceive(GameChatMessageReceiveEvent event) {
|
||||
if (checkProcessor(event) || checkCancellation(event) || !discordSRV.isReady()) {
|
||||
return;
|
||||
|
@ -22,7 +22,7 @@ import com.discordsrv.api.channel.GameChannel;
|
||||
import com.discordsrv.api.component.MinecraftComponent;
|
||||
import com.discordsrv.api.discord.entity.message.ReceivedDiscordMessageCluster;
|
||||
import com.discordsrv.api.discord.entity.message.SendableDiscordMessage;
|
||||
import com.discordsrv.api.eventbus.EventPriority;
|
||||
import com.discordsrv.api.eventbus.EventPriorities;
|
||||
import com.discordsrv.api.eventbus.Subscribe;
|
||||
import com.discordsrv.api.events.message.forward.game.ServerSwitchMessageForwardedEvent;
|
||||
import com.discordsrv.api.events.message.receive.game.ServerSwitchMessageReceiveEvent;
|
||||
@ -40,7 +40,7 @@ public class ServerSwitchMessageModule extends AbstractGameMessageModule<ServerS
|
||||
super(discordSRV, "SERVER_SWITCH_MESSAGES");
|
||||
}
|
||||
|
||||
@Subscribe(priority = EventPriority.LAST)
|
||||
@Subscribe(priority = EventPriorities.LAST)
|
||||
public void onServerSwitchMessageReceive(ServerSwitchMessageReceiveEvent event) {
|
||||
if (checkCancellation(event) || checkProcessor(event)) {
|
||||
return;
|
||||
|
Loading…
Reference in New Issue
Block a user