209 lines
5.2 KiB
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();
|
|
}
|
|
}
|
|
|
|
}
|
|
}
|