SimpleJavaEngine/src/main/java/speiger/src/coreengine/utils/eventbus/EventBus.java

209 lines
5.2 KiB
Java

package speiger.src.coreengine.utils.eventbus;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodHandles.Lookup;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.List;
import java.util.Map;
import java.util.function.Consumer;
import speiger.src.collections.objects.lists.ObjectArrayList;
import speiger.src.collections.objects.maps.impl.hash.Object2ObjectOpenHashMap;
import speiger.src.collections.objects.maps.interfaces.Object2ObjectMap;
import speiger.src.collections.objects.utils.ObjectLists;
import speiger.src.collections.objects.utils.maps.Object2ObjectMaps;
public class EventBus
{
private static final Lookup LOOKUP = MethodHandles.lookup();
Object2ObjectMap<Class<? extends Event>, Listeners> listeners = Object2ObjectMaps.synchronize(new Object2ObjectOpenHashMap<>());
Map<Object, List<EventListener>> instances = Object2ObjectMaps.synchronize(new Object2ObjectOpenHashMap<>());
public <T extends Event> void register(Class<T> event, Consumer<T> listener)
{
register(event, EventPriority.MEDIUM, listener);
}
public <T extends Event> void register(Class<T> event, EventPriority priority, Consumer<T> listener)
{
if(instances.containsKey(listener)) return;
getListeners(event).addListener(priority, (Consumer<Event>)listener);
instances.put(listener, ObjectLists.singleton(new EventListener(event, (Consumer<Event>)listener)));
}
public void register(Object obj)
{
register(obj, false);
}
public void register(Object obj, boolean superClasses)
{
if(instances.containsKey(obj)) return;
final List<EventListener> list = new ObjectArrayList<>();
try
{
register(obj.getClass().getDeclaredAnnotation(SubscribeEvent.class), obj, list);
findMethods(obj.getClass(), superClasses, new Consumer<Method>() {
@Override
public void accept(Method t) {
try
{
t.setAccessible(true);
SubscribeEvent data = t.getAnnotation(SubscribeEvent.class);
if(data == null) return;
Consumer<Event> listener = new MethodListener(LOOKUP.unreflect(t).bindTo(obj));
getListeners((Class<? extends Event>)t.getParameterTypes()[0]).addListener(data.priority(), listener);
list.add(new EventListener(data.value(), listener));
}
catch(Exception e) { e.printStackTrace(); }
}
});
findFields(obj.getClass(), superClasses, new Consumer<Field>() {
@Override
public void accept(Field t) {
try
{
t.setAccessible(true);
register(t.getAnnotation(SubscribeEvent.class), t.get(obj), list);
}
catch(Exception e) { e.printStackTrace(); }
}
});
}
catch(Exception e) { e.printStackTrace(); }
if(list.isEmpty()) return;
instances.put(obj, list);
}
private void register(SubscribeEvent data, Object obj, List<EventListener> listeners)
{
if(data == null || !(obj instanceof Consumer))
{
return;
}
getListeners(data.value()).addListener(data.priority(), (Consumer<Event>)obj);
listeners.add(new EventListener(data.value(), (Consumer<Event>)obj));
}
private void findFields(Class<?> clz, boolean superClasses, Consumer<Field> fields)
{
do
{
for(Field field : clz.getDeclaredFields())
{
fields.accept(field);
}
clz = clz.getSuperclass();
}
while(clz != Object.class && superClasses);
}
private void findMethods(Class<?> clz, boolean superClasses, Consumer<Method> methods)
{
do
{
for(Method field : clz.getDeclaredMethods())
{
methods.accept(field);
}
clz = clz.getSuperclass();
}
while(clz != Object.class && superClasses);
}
public void unregister(Object obj)
{
List<EventListener> instance = instances.remove(obj);
if(instance == null)
{
return;
}
for(EventListener entry : instance)
{
getListeners(entry.getEvent()).removeListeners(entry.getListener());
}
}
public void post(Event event)
{
Consumer<Event>[] listeners = getListeners(event.getClass()).getListeners();
if(listeners.length <= 0)
{
return;
}
int index = 0;
try
{
for(;index<listeners.length && !event.isCanceled();index++)
{
listeners[index].accept(event);
}
}
catch(Exception e)
{
e.printStackTrace();
}
}
protected Listeners getListeners(Class<? extends Event> event)
{
Listeners entry = listeners.get(event);
if(entry == null)
{
if(event == Event.class) entry = new Listeners();
else entry = new Listeners(getListeners((Class<? extends Event>)event.getSuperclass()));
listeners.put(event, entry);
}
return entry;
}
public static class EventListener
{
Class<? extends Event> event;
Consumer<Event> listener;
public EventListener(Class<? extends Event> event, Consumer<Event> listener)
{
this.event = event;
this.listener = listener;
}
public Class<? extends Event> getEvent()
{
return event;
}
public Consumer<Event> getListener()
{
return listener;
}
}
public static class MethodListener implements Consumer<Event>
{
MethodHandle handle;
public MethodListener(MethodHandle handle)
{
this.handle = handle;
}
@Override
public void accept(Event t)
{
try
{
handle.invoke(t);
}
catch(Throwable e)
{
e.printStackTrace();
}
}
}
}