From 04be72c42979b6da909b51108cc539f58ab5860c Mon Sep 17 00:00:00 2001 From: TheMode Date: Fri, 20 Aug 2021 03:00:25 +0200 Subject: [PATCH] Support listener expiration --- .../minestom/server/event/EventNodeImpl.java | 84 ++++++++++++------- 1 file changed, 52 insertions(+), 32 deletions(-) diff --git a/src/main/java/net/minestom/server/event/EventNodeImpl.java b/src/main/java/net/minestom/server/event/EventNodeImpl.java index f4c2dd926..e5fe1d960 100644 --- a/src/main/java/net/minestom/server/event/EventNodeImpl.java +++ b/src/main/java/net/minestom/server/event/EventNodeImpl.java @@ -1,5 +1,6 @@ package net.minestom.server.event; +import net.minestom.server.MinecraftServer; import net.minestom.server.utils.validate.Check; import org.jetbrains.annotations.Contract; import org.jetbrains.annotations.NotNull; @@ -42,11 +43,11 @@ class EventNodeImpl implements EventNode { Check.stateCondition(castedHandle.node != this, "Invalid handle owner"); List> listeners = castedHandle.listeners; if (!castedHandle.updated) { - listeners.clear(); synchronized (GLOBAL_CHILD_LOCK) { - handle(castedHandle.eventType, castedHandle.listeners); + listeners.clear(); + castedHandle.update(this); + castedHandle.updated = true; } - castedHandle.updated = true; } if (listeners.isEmpty()) return; for (Consumer listener : listeners) { @@ -60,35 +61,6 @@ class EventNodeImpl implements EventNode { aClass -> new Handle<>(this, (Class) aClass)); } - private void handle(Class handleType, List> listeners) { - ListenerEntry entry = listenerMap.get(handleType); - if (entry != null) { - // Add normal listeners - for (var listener : entry.listeners) { - if (predicate != null) { - // Ensure that the event is valid before running - listeners.add(event -> { - final var value = filter.getHandler(event); - if (!predicate.test(event, value)) return; - listener.run(event); - }); - } else { - // No predicate, run directly - listeners.add(listener::run); - } - } - // Add bindings - listeners.addAll(entry.bindingConsumers); - // TODO mapped node - } - // Add children - if (children.isEmpty()) return; - this.children.stream() - .sorted(Comparator.comparing(EventNode::getPriority)) - .filter(child -> child.eventType.isAssignableFrom(handleType)) // Invalid event type - .forEach(child -> child.handle(handleType, listeners)); - } - @Override public @NotNull List> findChildren(@NotNull String name, Class eventType) { synchronized (GLOBAL_CHILD_LOCK) { @@ -291,5 +263,53 @@ class EventNodeImpl implements EventNode { this.node = node; this.eventType = eventType; } + + void update(EventNodeImpl targetNode) { + final var handleType = eventType; + ListenerEntry entry = targetNode.listenerMap.get(handleType); + if (entry != null) appendEntry(listeners, entry, targetNode); + // Add children + final var children = targetNode.children; + if (children.isEmpty()) return; + children.stream() + .filter(child -> child.eventType.isAssignableFrom(handleType)) // Invalid event type + .sorted(Comparator.comparing(EventNode::getPriority)) + .forEach(this::update); + } + + static void appendEntry(List> handleListeners, ListenerEntry entry, EventNodeImpl targetNode) { + final var filter = targetNode.filter; + final var predicate = targetNode.predicate; + // Add normal listeners + for (var listener : entry.listeners) { + if (predicate != null) { + // Ensure that the event is valid before running + handleListeners.add(e -> { + final var value = filter.getHandler(e); + if (!predicate.test(e, value)) return; + callListener(targetNode, listener, e); + }); + } else { + // No predicate, run directly + handleListeners.add(e -> callListener(targetNode, listener, e)); + } + } + // Add bindings + handleListeners.addAll(entry.bindingConsumers); + // TODO mapped node + } + + static void callListener(EventNodeImpl targetNode, EventListener listener, E event) { + EventListener.Result result; + try { + result = listener.run(event); + } catch (Exception e) { + result = EventListener.Result.EXCEPTION; + MinecraftServer.getExceptionManager().handleException(e); + } + if (result == EventListener.Result.EXPIRED) { + targetNode.removeListener(listener); + } + } } }