diff --git a/src/main/java/net/minestom/server/event/EventNodeImpl.java b/src/main/java/net/minestom/server/event/EventNodeImpl.java index 4f9b3cd67..28e2561c2 100644 --- a/src/main/java/net/minestom/server/event/EventNodeImpl.java +++ b/src/main/java/net/minestom/server/event/EventNodeImpl.java @@ -20,7 +20,13 @@ import java.util.function.Consumer; non-sealed class EventNodeImpl implements EventNode { private static final Object GLOBAL_CHILD_LOCK = new Object(); - private final Map, Handle> handleMap = new ConcurrentHashMap<>(); + private final ClassValue> handleMap = new ClassValue<>() { + @Override + protected Handle computeValue(Class type) { + //noinspection unchecked + return new Handle<>((Class) type); + } + }; private final Map, ListenerEntry> listenerMap = new ConcurrentHashMap<>(); private final Set> children = new CopyOnWriteArraySet<>(); private final Map> mappedNodeCache = new WeakHashMap<>(); @@ -44,11 +50,7 @@ non-sealed class EventNodeImpl implements EventNode { @Override @SuppressWarnings("unchecked") public @NotNull ListenerHandle getHandle(@NotNull Class handleType) { - Handle handle = (Handle) handleMap.get(handleType); - if (handle != null) return handle; - var tmp = new Handle<>(this, (Class) handleType); - handle = (Handle) handleMap.putIfAbsent(handleType, tmp); - return handle != null ? handle : (ListenerHandle) tmp; + return (ListenerHandle) handleMap.get(handleType); } @Override @@ -273,8 +275,8 @@ non-sealed class EventNodeImpl implements EventNode { private void invalidateEvent(Class eventClass) { forTargetEvents(eventClass, type -> { - Handle handle = handleMap.get(type); - if (handle != null) Handle.UPDATED.setRelease(handle, false); + ListenerHandle handle = getHandle((Class) type); + Handle.UPDATED.setRelease(handle, false); }); final EventNodeImpl parent = this.parent; if (parent != null) parent.invalidateEvent(eventClass); @@ -304,25 +306,24 @@ non-sealed class EventNodeImpl implements EventNode { final Set> bindingConsumers = new CopyOnWriteArraySet<>(); } - static final class Handle implements ListenerHandle { + @SuppressWarnings("unchecked") + final class Handle implements ListenerHandle { private static final VarHandle UPDATED; static { try { - UPDATED = MethodHandles.lookup().findVarHandle(Handle.class, "updated", boolean.class); + UPDATED = MethodHandles.lookup().findVarHandle(EventNodeImpl.Handle.class, "updated", boolean.class); } catch (NoSuchFieldException | IllegalAccessException e) { throw new IllegalStateException(e); } } - private final EventNodeImpl node; private final Class eventType; private Consumer listener = null; @SuppressWarnings("unused") private boolean updated; // Use the UPDATED var handle - Handle(EventNodeImpl node, Class eventType) { - this.node = node; + Handle(Class eventType) { this.eventType = eventType; } @@ -354,6 +355,7 @@ non-sealed class EventNodeImpl implements EventNode { } private @Nullable Consumer createConsumer() { + var node = (EventNodeImpl) EventNodeImpl.this; // Standalone listeners List> listeners = new ArrayList<>(); forTargetEvents(eventType, type -> { @@ -444,6 +446,7 @@ non-sealed class EventNodeImpl implements EventNode { * The goal is to limit the amount of map lookup. */ private @Nullable Consumer mappedConsumer() { + var node = (EventNodeImpl) EventNodeImpl.this; final var mappedNodeCache = node.mappedNodeCache; if (mappedNodeCache.isEmpty()) return null; Set> filters = new HashSet<>(mappedNodeCache.size()); @@ -486,6 +489,7 @@ non-sealed class EventNodeImpl implements EventNode { } void callListener(@NotNull EventListener listener, E event) { + var node = (EventNodeImpl) EventNodeImpl.this; EventListener.Result result = listener.run(event); if (result == EventListener.Result.EXPIRED) { node.removeListener(listener);