Simple bukkit-like event loop implementation
This commit is contained in:
@@ -33,6 +33,8 @@ subprojects {
|
||||
|
||||
/* Components */
|
||||
compile (group: 'org.projectlombok', name: 'lombok', version: '1.16.16')
|
||||
|
||||
testCompile 'junit:junit:4.12'
|
||||
}
|
||||
|
||||
task copyDep(type: Copy) {
|
||||
|
||||
13
event-loop/src/main/java/mc/core/events/EventHandler.java
Normal file
13
event-loop/src/main/java/mc/core/events/EventHandler.java
Normal file
@@ -0,0 +1,13 @@
|
||||
package mc.core.events;
|
||||
|
||||
import java.lang.annotation.*;
|
||||
|
||||
@Documented
|
||||
@Target(ElementType.METHOD)
|
||||
@Inherited
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface EventHandler {
|
||||
EventPriority priority() default EventPriority.NORMAL;
|
||||
|
||||
boolean ignoreCancelled() default false;
|
||||
}
|
||||
7
event-loop/src/main/java/mc/core/events/EventLoop.java
Normal file
7
event-loop/src/main/java/mc/core/events/EventLoop.java
Normal file
@@ -0,0 +1,7 @@
|
||||
package mc.core.events;
|
||||
|
||||
public interface EventLoop {
|
||||
void callEvent(Event event);
|
||||
|
||||
void addEventHandler(Object object);
|
||||
}
|
||||
19
event-loop/src/main/java/mc/core/events/EventPriority.java
Normal file
19
event-loop/src/main/java/mc/core/events/EventPriority.java
Normal file
@@ -0,0 +1,19 @@
|
||||
package mc.core.events;
|
||||
|
||||
import lombok.Getter;
|
||||
|
||||
public enum EventPriority {
|
||||
LOWEST(0),
|
||||
LOW(1),
|
||||
NORMAL(2),
|
||||
HIGH(3),
|
||||
HIGHEST(4),
|
||||
MONITOR(5);
|
||||
|
||||
@Getter
|
||||
private int value;
|
||||
|
||||
EventPriority(int value) {
|
||||
this.value = value;
|
||||
}
|
||||
}
|
||||
74
event-loop/src/main/java/mc/core/events/SimpleEventLoop.java
Normal file
74
event-loop/src/main/java/mc/core/events/SimpleEventLoop.java
Normal file
@@ -0,0 +1,74 @@
|
||||
package mc.core.events;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.util.*;
|
||||
|
||||
@Slf4j
|
||||
public class SimpleEventLoop implements EventLoop {
|
||||
private Map<Class<? extends Event>, List<ExecutorLink>> handlers = new HashMap<>();
|
||||
|
||||
@Override
|
||||
public void callEvent(Event event) {
|
||||
Class<? extends Event> eventType = event.getClass();
|
||||
if (handlers.containsKey(eventType)) {
|
||||
for (ExecutorLink link : handlers.get(eventType)) {
|
||||
try {
|
||||
link.getMethod().invoke(link.object, event);
|
||||
} catch (IllegalAccessException | InvocationTargetException e) {
|
||||
log.error("Exception caught while attempting to dispatch {}.", eventType.getSimpleName(), e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addEventHandler(Object object) {
|
||||
for (Method method : object.getClass().getDeclaredMethods()) {
|
||||
EventHandler annotation = method.getAnnotation(EventHandler.class);
|
||||
if (annotation == null)
|
||||
continue; // We are not interested in methods without @EventHandler annotation
|
||||
|
||||
if (!Modifier.isPublic(method.getModifiers())) {
|
||||
log.error("Unable to register {} as an EventHandler. Method must have a 'private' access modifier.", method.toString());
|
||||
continue;
|
||||
|
||||
}
|
||||
|
||||
if (method.getParameterCount() != 1) {
|
||||
log.error("Unable to register {} as an EventHandler. Method must have exactly one argument.", method.toString());
|
||||
continue;
|
||||
}
|
||||
|
||||
Class<?> firstParamType = method.getParameterTypes()[0];
|
||||
if (!Event.class.isAssignableFrom(firstParamType)) {
|
||||
log.error("Unable to register {} as an EventHandler. First parameter type must implement 'Event' interface.", method.toString());
|
||||
continue;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked") Class<? extends Event> eventType = (Class<? extends Event>) firstParamType;
|
||||
|
||||
List<ExecutorLink> eventHandlers = handlers.computeIfAbsent(eventType, s -> new ArrayList<>());
|
||||
eventHandlers.add(new ExecutorLink(annotation.priority().getValue(), annotation.ignoreCancelled(), method, object));
|
||||
eventHandlers.sort(Comparator.comparingInt(o -> o.priority));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* This class describes
|
||||
*/
|
||||
@RequiredArgsConstructor
|
||||
@Getter
|
||||
private static class ExecutorLink {
|
||||
private final int priority;
|
||||
private final boolean ignoreCancelled;
|
||||
private final Method method;
|
||||
private final Object object;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
package ru.core.events;
|
||||
|
||||
import mc.core.events.EventHandler;
|
||||
import mc.core.events.LoginEvent;
|
||||
|
||||
public class SampleEventHandler {
|
||||
@EventHandler
|
||||
public void onPlayerLogin(LoginEvent event) {
|
||||
event.setDenyReason("Hello from SampleEventHandler!");
|
||||
}
|
||||
|
||||
public void notHandler(LoginEvent event){
|
||||
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void invalidParam(Object object){
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
package ru.core.events;
|
||||
|
||||
import mc.core.events.LoginEvent;
|
||||
import mc.core.events.SimpleEventLoop;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
public class SimpleEventLoopTest {
|
||||
|
||||
@Test
|
||||
public void loopWorks() {
|
||||
SimpleEventLoop simpleEventLoop = new SimpleEventLoop();
|
||||
simpleEventLoop.addEventHandler(new SampleEventHandler());
|
||||
LoginEvent testEvent = new LoginEvent(null);
|
||||
testEvent.setDenyReason("none");
|
||||
|
||||
simpleEventLoop.callEvent(testEvent);
|
||||
|
||||
Assert.assertEquals("Event handler was not called", "Hello from SampleEventHandler!", testEvent.getDenyReason());
|
||||
|
||||
}
|
||||
}
|
||||
@@ -5,3 +5,5 @@ include('flat_world')
|
||||
include('vanilla_commands')
|
||||
include('proto_1.12.2') // Protocol 1.12.2
|
||||
include('proto_1.12.2_netty') // Protocol 1.12.2 (Netty impl.)
|
||||
include('event-loop')
|
||||
|
||||
|
||||
Reference in New Issue
Block a user