mirror of
https://github.com/PolyhedralDev/Terra.git
synced 2026-04-09 17:26:07 +00:00
implement FunctionalEventHandler
This commit is contained in:
@@ -0,0 +1,76 @@
|
||||
package com.dfsek.terra.event;
|
||||
|
||||
import com.dfsek.terra.api.addon.TerraAddon;
|
||||
import com.dfsek.terra.api.event.events.Event;
|
||||
import com.dfsek.terra.api.event.events.PackEvent;
|
||||
import com.dfsek.terra.api.event.functional.EventContext;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
public class EventContextImpl<T extends Event> implements EventContext<T>, Comparable<EventContextImpl<T>> {
|
||||
private final List<Consumer<T>> actions = new ArrayList<>();
|
||||
private int priority;
|
||||
private boolean failThrough = false;
|
||||
private boolean global = false;
|
||||
|
||||
private final TerraAddon addon;
|
||||
|
||||
public EventContextImpl(TerraAddon addon) {
|
||||
this.addon = addon;
|
||||
}
|
||||
|
||||
public void handle(T event) {
|
||||
if(event instanceof PackEvent) {
|
||||
|
||||
}
|
||||
actions.forEach(action -> action.accept(event));
|
||||
}
|
||||
|
||||
@Override
|
||||
public EventContext<T> then(Consumer<T> action) {
|
||||
actions.add(action);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public EventContext<T> priority(int priority) {
|
||||
this.priority = priority;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public EventContext<T> failThrough() {
|
||||
this.failThrough = true;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public EventContext<T> global() {
|
||||
this.global = true;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compareTo(@NotNull EventContextImpl<T> o) {
|
||||
return this.priority - o.priority;
|
||||
}
|
||||
|
||||
public boolean isGlobal() {
|
||||
return global;
|
||||
}
|
||||
|
||||
public int getPriority() {
|
||||
return priority;
|
||||
}
|
||||
|
||||
public TerraAddon getAddon() {
|
||||
return addon;
|
||||
}
|
||||
|
||||
public boolean isFailThrough() {
|
||||
return failThrough;
|
||||
}
|
||||
}
|
||||
@@ -2,110 +2,45 @@ package com.dfsek.terra.event;
|
||||
|
||||
import com.dfsek.terra.api.TerraPlugin;
|
||||
import com.dfsek.terra.api.addon.TerraAddon;
|
||||
import com.dfsek.terra.api.event.EventHandler;
|
||||
import com.dfsek.terra.api.event.EventListener;
|
||||
import com.dfsek.terra.api.event.EventManager;
|
||||
import com.dfsek.terra.api.event.annotations.Global;
|
||||
import com.dfsek.terra.api.event.annotations.Priority;
|
||||
import com.dfsek.terra.api.event.events.Cancellable;
|
||||
import com.dfsek.terra.api.event.events.Event;
|
||||
import com.dfsek.terra.api.event.events.PackEvent;
|
||||
import com.dfsek.terra.api.util.reflection.ReflectionUtil;
|
||||
import com.dfsek.terra.api.event.functional.EventContext;
|
||||
import com.dfsek.terra.api.event.functional.FunctionalEventHandler;
|
||||
import com.dfsek.terra.api.util.reflection.TypeKey;
|
||||
|
||||
import java.io.PrintWriter;
|
||||
import java.io.StringWriter;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public class EventManagerImpl implements EventManager {
|
||||
private final Map<Class<? extends Event>, List<ListenerHolder>> listeners = new HashMap<>();
|
||||
private final Map<Class<?>, EventHandler> handlers = new HashMap<>();
|
||||
private final TerraPlugin main;
|
||||
|
||||
public EventManagerImpl(TerraPlugin main) {
|
||||
this.main = main;
|
||||
registerHandler(FunctionalEventHandler.class, new FunctionalEventHandlerImpl(main)); // default handler
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean callEvent(Event event) {
|
||||
listeners.getOrDefault(event.getClass(), Collections.emptyList()).forEach(listenerHolder -> {
|
||||
try {
|
||||
if(event instanceof PackEvent && !listenerHolder.global) {
|
||||
PackEvent packEvent = (PackEvent) event;
|
||||
if(packEvent
|
||||
.getPack()
|
||||
.addons()
|
||||
.contains(listenerHolder.addon)) {
|
||||
listenerHolder.method.invoke(listenerHolder.listener, event);
|
||||
}
|
||||
} else {
|
||||
listenerHolder.method.invoke(listenerHolder.listener, event);
|
||||
}
|
||||
} catch(InvocationTargetException e) {
|
||||
StringWriter writer = new StringWriter();
|
||||
e.getTargetException().printStackTrace(new PrintWriter(writer));
|
||||
main.logger().warning("Exception occurred during event handling:");
|
||||
main.logger().warning(writer.toString());
|
||||
main.logger().warning("Report this to the maintainers of " + listenerHolder.method.getName());
|
||||
} catch(Exception e) {
|
||||
StringWriter writer = new StringWriter();
|
||||
e.printStackTrace(new PrintWriter(writer));
|
||||
main.logger().warning("Exception occurred during event handling:");
|
||||
main.logger().warning(writer.toString());
|
||||
main.logger().warning("Report this to the maintainers of " + listenerHolder.method.getName());
|
||||
}
|
||||
}
|
||||
);
|
||||
if(event instanceof Cancellable) return !((Cancellable) event).isCancelled();
|
||||
return true;
|
||||
public void callEvent(Event event) {
|
||||
handlers.values().forEach(handler -> handler.handle(event));
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T extends EventHandler> void registerHandler(Class<T> clazz, T handler) {
|
||||
handlers.put(clazz, handler);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public void registerListener(TerraAddon addon, EventListener listener) {
|
||||
Class<? extends EventListener> listenerClass = listener.getClass();
|
||||
Method[] methods = ReflectionUtil.getMethods(listenerClass);
|
||||
|
||||
for(Method method : methods) {
|
||||
if(method.getParameterCount() != 1) continue; // Check that parameter count is only 1.
|
||||
Class<?> eventParam = method.getParameterTypes()[0];
|
||||
if(!Event.class.isAssignableFrom(eventParam)) continue; // Check that parameter is an Event.
|
||||
|
||||
Priority p = method.getAnnotation(Priority.class);
|
||||
|
||||
int priority = p == null ? 0 : p.value();
|
||||
|
||||
method.setAccessible(true);
|
||||
|
||||
List<ListenerHolder> holders = listeners.computeIfAbsent((Class<? extends Event>) eventParam, e -> new ArrayList<>());
|
||||
|
||||
holders.add(new ListenerHolder(method, listener, priority, addon, method.getAnnotation(Global.class) != null));
|
||||
|
||||
holders.sort(Comparator.comparingInt(ListenerHolder::getPriority)); // Sort priorities.
|
||||
}
|
||||
}
|
||||
|
||||
private static final class ListenerHolder {
|
||||
private final Method method;
|
||||
private final EventListener listener;
|
||||
private final int priority;
|
||||
private final TerraAddon addon;
|
||||
private final boolean global;
|
||||
|
||||
private ListenerHolder(Method method, EventListener listener, int priority, TerraAddon addon, boolean global) {
|
||||
this.method = method;
|
||||
this.listener = listener;
|
||||
this.priority = priority;
|
||||
this.addon = addon;
|
||||
this.global = global;
|
||||
}
|
||||
|
||||
public int getPriority() {
|
||||
return priority;
|
||||
}
|
||||
public <T extends EventHandler> T getHandler(Class<T> clazz) {
|
||||
return (T) handlers.computeIfAbsent(clazz, c -> {
|
||||
throw new IllegalArgumentException("No event handler registered for class " + clazz.getCanonicalName());
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,65 @@
|
||||
package com.dfsek.terra.event;
|
||||
|
||||
import com.dfsek.terra.api.TerraPlugin;
|
||||
import com.dfsek.terra.api.addon.TerraAddon;
|
||||
import com.dfsek.terra.api.event.events.Event;
|
||||
import com.dfsek.terra.api.event.events.PackEvent;
|
||||
import com.dfsek.terra.api.event.functional.EventContext;
|
||||
import com.dfsek.terra.api.event.functional.FunctionalEventHandler;
|
||||
import com.dfsek.terra.api.util.reflection.TypeKey;
|
||||
|
||||
import java.io.PrintWriter;
|
||||
import java.io.StringWriter;
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public class FunctionalEventHandlerImpl implements FunctionalEventHandler {
|
||||
private final Map<Type, List<EventContextImpl<?>>> contextMap = new HashMap<>();
|
||||
|
||||
private final TerraPlugin main;
|
||||
|
||||
public FunctionalEventHandlerImpl(TerraPlugin main) {
|
||||
this.main = main;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public void handle(Event event) {
|
||||
contextMap.getOrDefault(event.getClass(), Collections.emptyList()).forEach(context -> {
|
||||
try {
|
||||
if(event instanceof PackEvent) {
|
||||
if((context.isGlobal() || ((PackEvent) event).getPack().addons().contains(context.getAddon()))) {
|
||||
((EventContextImpl<Event>) context).handle(event);
|
||||
}
|
||||
} else {
|
||||
((EventContextImpl<Event>) context).handle(event);
|
||||
}
|
||||
} catch(Exception e) {
|
||||
if(context.isFailThrough()) throw e; // Rethrow if it's fail-through.
|
||||
StringWriter writer = new StringWriter();
|
||||
e.printStackTrace(new PrintWriter(writer));
|
||||
main.logger().warning("Exception occurred during event handling:");
|
||||
main.logger().warning(writer.toString());
|
||||
main.logger().warning("Report this to the maintainers of " + context.getAddon().getName() + ", " + context.getAddon().getAuthor());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T extends Event> EventContext<T> register(TerraAddon addon, Class<T> clazz) {
|
||||
EventContextImpl<T> eventContext = new EventContextImpl<>(addon);
|
||||
contextMap.computeIfAbsent(clazz, c -> new ArrayList<>()).add(eventContext);
|
||||
return eventContext;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T extends Event> EventContext<T> register(TerraAddon addon, TypeKey<T> clazz) {
|
||||
EventContextImpl<T> eventContext = new EventContextImpl<>(addon);
|
||||
contextMap.computeIfAbsent(clazz.getType(), c -> new ArrayList<>()).add(eventContext);
|
||||
return eventContext;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user