Archived
0

Simple bukkit-like event loop implementation

This commit is contained in:
Daniil
2018-07-25 20:30:49 +07:00
parent 1bd0e6aafe
commit 1456a8c1ee
8 changed files with 159 additions and 0 deletions

View File

@@ -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) {

View 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;
}

View File

@@ -0,0 +1,7 @@
package mc.core.events;
public interface EventLoop {
void callEvent(Event event);
void addEventHandler(Object object);
}

View 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;
}
}

View 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;
}
}

View File

@@ -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){
}
}

View File

@@ -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());
}
}

View File

@@ -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')