Merge branch 'master' into ver/4.3.0

This commit is contained in:
dfsek 2021-02-17 10:37:14 -07:00
commit d670fc904f
9 changed files with 107 additions and 17 deletions

View File

@ -1,4 +0,0 @@
package com.dfsek.terra.api.core.event;
public interface Event {
}

View File

@ -1,7 +1,14 @@
package com.dfsek.terra.api.core.event;
import com.dfsek.terra.api.core.event.events.Event;
public interface EventManager {
void callEvent(Event event);
/**
* Call an event, and return the execution status.
* @param event Event to pass to all registered EventListeners.
* @return False if the event is cancellable and has been cancelled, otherwise true.
*/
boolean callEvent(Event event);
void registerListener(EventListener listener);
}

View File

@ -1,6 +1,9 @@
package com.dfsek.terra.api.core.event;
import com.dfsek.terra.api.core.TerraPlugin;
import com.dfsek.terra.api.core.event.annotations.Priority;
import com.dfsek.terra.api.core.event.events.Cancellable;
import com.dfsek.terra.api.core.event.events.Event;
import com.dfsek.terra.api.util.ReflectionUtil;
import java.io.PrintWriter;
@ -8,12 +11,14 @@ import java.io.StringWriter;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
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 TerraEventManager implements EventManager {
private final Map<Class<? extends Event>, Map<EventListener, List<Method>>> listeners = new HashMap<>();
private final Map<Class<? extends Event>, List<ListenerHolder>> listeners = new HashMap<>();
private final TerraPlugin main;
public TerraEventManager(TerraPlugin main) {
@ -21,26 +26,27 @@ public class TerraEventManager implements EventManager {
}
@Override
public void callEvent(Event event) {
if(!listeners.containsKey(event.getClass())) return;
listeners.get(event.getClass()).forEach((eventListener, methods) -> methods.forEach(method -> {
public boolean callEvent(Event event) {
listeners.getOrDefault(event.getClass(), Collections.emptyList()).forEach(listenerHolder -> {
try {
method.invoke(eventListener, event);
listenerHolder.method.invoke(listenerHolder.listener, event);
} catch(InvocationTargetException e) {
StringWriter writer = new StringWriter();
e.getTargetException().printStackTrace(new PrintWriter(writer));
main.getLogger().warning("Exception occurred during event handling:");
main.getLogger().warning(writer.toString());
main.getLogger().warning("Report this to the maintainers of " + eventListener.getClass().getCanonicalName());
main.getLogger().warning("Report this to the maintainers of " + listenerHolder.method.getName());
} catch(Exception e) {
StringWriter writer = new StringWriter();
e.printStackTrace(new PrintWriter(writer));
main.getLogger().warning("Exception occurred during event handling:");
main.getLogger().warning(writer.toString());
main.getLogger().warning("Report this to the maintainers of " + eventListener.getClass().getCanonicalName());
main.getLogger().warning("Report this to the maintainers of " + listenerHolder.method.getName());
}
})
}
);
if(event instanceof Cancellable) return !((Cancellable) event).isCancelled();
return true;
}
@SuppressWarnings("unchecked")
@ -53,8 +59,34 @@ public class TerraEventManager implements EventManager {
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);
listeners.computeIfAbsent((Class<? extends Event>) eventParam, e -> new HashMap<>()).computeIfAbsent(listener, l -> new ArrayList<>()).add(method);
List<ListenerHolder> holders = listeners.computeIfAbsent((Class<? extends Event>) eventParam, e -> new ArrayList<>());
holders.add(new ListenerHolder(method, listener, priority));
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 ListenerHolder(Method method, EventListener listener, int priority) {
this.method = method;
this.listener = listener;
this.priority = priority;
}
public int getPriority() {
return priority;
}
}
}

View File

@ -0,0 +1,38 @@
package com.dfsek.terra.api.core.event.annotations;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* Annotated listener methods will have a specific priority set.
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface Priority {
/**
* Highest possible priority. Listeners with this priority will always be invoked first.
*/
int HIGHEST = Integer.MAX_VALUE;
/**
* Lowest possible priority. Listeners with this priority will always be invoked last.
*/
int LOWEST = Integer.MIN_VALUE;
/**
* Default priority.
*/
int NORMAL = 0;
/**
* High priority.
*/
int HIGH = 1;
/**
* Low Priority.
*/
int LOW = -1;
/**
* @return Priority of this event. Events are executed from lowest to highest priorities.
*/
int value();
}

View File

@ -0,0 +1,11 @@
package com.dfsek.terra.api.core.event.events;
/**
* Events that implement this interface may be cancelled.
*
* Cancelling an event is assumed to stop the execution of whatever action triggered the event.
*/
public interface Cancellable extends Event {
boolean isCancelled();
void setCancelled();
}

View File

@ -0,0 +1,4 @@
package com.dfsek.terra.api.core.event.events;
public interface Event {
}

View File

@ -1,6 +1,6 @@
package com.dfsek.terra.api.core.event.events.config;
import com.dfsek.terra.api.core.event.Event;
import com.dfsek.terra.api.core.event.events.Event;
import com.dfsek.terra.config.pack.ConfigPack;
public abstract class ConfigPackLoadEvent implements Event {

View File

@ -1,6 +1,6 @@
package com.dfsek.terra.api.core.event.events.world;
import com.dfsek.terra.api.core.event.Event;
import com.dfsek.terra.api.core.event.events.Event;
import com.dfsek.terra.world.TerraWorld;
/**

View File

@ -2,7 +2,8 @@ package event;
import com.dfsek.tectonic.loading.TypeRegistry;
import com.dfsek.terra.api.core.TerraPlugin;
import com.dfsek.terra.api.core.event.Event;
import com.dfsek.terra.api.core.event.annotations.Priority;
import com.dfsek.terra.api.core.event.events.Event;
import com.dfsek.terra.api.core.event.EventListener;
import com.dfsek.terra.api.core.event.EventManager;
import com.dfsek.terra.api.core.event.TerraEventManager;
@ -127,6 +128,7 @@ public class EventTest {
}
static class TestListener2 implements EventListener {
@Priority(Priority.LOWEST)
public void doThing(TestEvent event) {
System.out.println("Event value 2: " + event.value);
}