    001package net.minecraftforge.event;
    002
    003import java.lang.reflect.Constructor;
    004import java.lang.reflect.Method;
    005import java.util.ArrayList;
    006import java.util.Set;
    007import java.util.concurrent.ConcurrentHashMap;
    008
    009
    010
    011import com.google.common.reflect.TypeToken;
    012
    013public class EventBus
    014{
    015    private static int maxID = 0;
    016
    017    private ConcurrentHashMap<Object, ArrayList<IEventListener>> listeners = new ConcurrentHashMap<Object, ArrayList<IEventListener>>();
    018    private final int busID = maxID++;
    019
    020    public EventBus()
    021    {
    022        ListenerList.resize(busID + 1);
    023    }
    024
    025    public void register(Object target)
    026    {
    027        Set<? extends Class<?>> supers = TypeToken.of(target.getClass()).getTypes().rawTypes();
    028        for (Method method : target.getClass().getMethods())
    029        {
    030            for (Class<?> cls : supers)
    031            {
    032                try
    033                {
    034                    Method real = cls.getDeclaredMethod(method.getName(), method.getParameterTypes());
    035                    if (real.isAnnotationPresent(ForgeSubscribe.class))
    036                    {
    037                        Class<?>[] parameterTypes = method.getParameterTypes();
    038                        if (parameterTypes.length != 1)
    039                        {
    040                            throw new IllegalArgumentException(
    041                                "Method " + method + " has @ForgeSubscribe annotation, but requires " + parameterTypes.length +
    042                                " arguments.  Event handler methods must require a single argument."
    043                            );
    044                        }
    045
    046                        Class<?> eventType = parameterTypes[0];
    047
    048                        if (!Event.class.isAssignableFrom(eventType))
    049                        {
    050                            throw new IllegalArgumentException("Method " + method + " has @ForgeSubscribe annotation, but takes a argument that is not a Event " + eventType);
    051                        }
    052
    053                        register(eventType, target, method);
    054                        break;
    055                    }
    056                }
    057                catch (NoSuchMethodException e)
    058                {
    059                    ;
    060                }
    061            }
    062        }
    063    }
    064
    065    private void register(Class<?> eventType, Object target, Method method)
    066    {
    067        try
    068        {
    069            Constructor<?> ctr = eventType.getConstructor();
    070            ctr.setAccessible(true);
    071            Event event = (Event)ctr.newInstance();
    072            ASMEventHandler listener = new ASMEventHandler(target, method);
    073            event.getListenerList().register(busID, listener.getPriority(), listener);
    074
    075            ArrayList<IEventListener> others = listeners.get(target);
    076            if (others == null)
    077            {
    078                others = new ArrayList<IEventListener>();
    079                listeners.put(target, others);
    080            }
    081            others.add(listener);
    082        }
    083        catch (Exception e)
    084        {
    085            e.printStackTrace();
    086        }
    087    }
    088
    089    public void unregister(Object object)
    090    {
    091        ArrayList<IEventListener> list = listeners.remove(object);
    092        for (IEventListener listener : list)
    093        {
    094            ListenerList.unregiterAll(busID, listener);
    095        }
    096    }
    097
    098    public boolean post(Event event)
    099    {
    100        IEventListener[] listeners = event.getListenerList().getListeners(busID);
    101        for (IEventListener listener : listeners)
    102        {
    103            listener.invoke(event);
    104        }
    105        return (event.isCancelable() ? event.isCanceled() : false);
    106    }
    107}