Add support for listener expiration count

This commit is contained in:
TheMode 2021-06-02 12:12:14 +02:00
parent bdfa164695
commit 305aa3e8d9
3 changed files with 38 additions and 6 deletions

View File

@ -1,20 +1,23 @@
package net.minestom.server.event; package net.minestom.server.event;
import net.minestom.server.utils.time.UpdateOption;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.Consumer; import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Predicate; import java.util.function.Predicate;
public class EventListener<T extends Event> { public class EventListener<T extends Event> {
protected final Class<T> type; protected final Class<T> type;
protected final Consumer<T> combined; protected final Function<T, Result> executor;
private EventListener(@NotNull Class<T> type, @NotNull Consumer<T> combined) { private EventListener(@NotNull Class<T> type, @NotNull Function<T, Result> executor) {
this.type = type; this.type = type;
this.combined = combined; this.executor = executor;
} }
public static <T extends Event> EventListener.Builder<T> of(@NotNull Class<T> eventType) { public static <T extends Event> EventListener.Builder<T> of(@NotNull Class<T> eventType) {
@ -26,6 +29,8 @@ public class EventListener<T extends Event> {
private final Class<T> eventType; private final Class<T> eventType;
private List<Predicate<T>> filters = new ArrayList<>(); private List<Predicate<T>> filters = new ArrayList<>();
private int expirationCount;
private UpdateOption expirationTime;
private Consumer<T> handler; private Consumer<T> handler;
protected Builder(Class<T> eventType) { protected Builder(Class<T> eventType) {
@ -37,25 +42,47 @@ public class EventListener<T extends Event> {
return this; return this;
} }
public EventListener.Builder<T> expirationCount(int expirationCount) {
this.expirationCount = expirationCount;
return this;
}
public EventListener.Builder<T> handler(Consumer<T> handler) { public EventListener.Builder<T> handler(Consumer<T> handler) {
this.handler = handler; this.handler = handler;
return this; return this;
} }
public EventListener<T> build() { public EventListener<T> build() {
AtomicInteger expirationCount = new AtomicInteger(this.expirationCount);
final boolean hasExpirationCount = expirationCount.get() > 0;
final var filters = new ArrayList<>(this.filters);
final var handler = this.handler;
return new EventListener<>(eventType, event -> { return new EventListener<>(eventType, event -> {
// Filtering // Filtering
if (!filters.isEmpty()) { if (!filters.isEmpty()) {
if (filters.stream().anyMatch(filter -> !filter.test(event))) { if (filters.stream().anyMatch(filter -> !filter.test(event))) {
// Cancelled // Cancelled
return; return Result.INVALID;
} }
} }
// Handler // Handler
if (handler != null) { if (handler != null) {
handler.accept(event); handler.accept(event);
} }
// Expiration check
if (hasExpirationCount && expirationCount.decrementAndGet() == 0) {
return Result.EXPIRED;
}
return Result.SUCCESS;
}); });
} }
} }
enum Result {
SUCCESS,
INVALID,
EXPIRED
}
} }

View File

@ -51,8 +51,12 @@ public class EventNode<T extends Event> {
} }
final var listeners = listenerMap.get(event.getClass()); final var listeners = listenerMap.get(event.getClass());
if (listeners != null && !listeners.isEmpty()) { if (listeners != null && !listeners.isEmpty()) {
listeners.forEach(eventListener -> listeners.forEach(listener -> {
eventListener.combined.accept(event)); final EventListener.Result result = listener.executor.apply(event);
if (result == EventListener.Result.EXPIRED) {
listeners.remove(listener);
}
});
} }
this.children.forEach(eventNode -> eventNode.call(event)); this.children.forEach(eventNode -> eventNode.call(event));
} }

View File

@ -140,6 +140,7 @@ public class PlayerInit {
var node = EventNode.create(PlayerEvent.class); var node = EventNode.create(PlayerEvent.class);
node.addListener(EventListener.of(PlayerTickEvent.class) node.addListener(EventListener.of(PlayerTickEvent.class)
.handler(playerTickEvent -> System.out.println("Player tick!")) .handler(playerTickEvent -> System.out.println("Player tick!"))
.expirationCount(2)
.build()); .build());
var empty = EventNode.create(); var empty = EventNode.create();