001    package net.minecraftforge.event;
002    
003    import java.lang.reflect.Constructor;
004    import java.lang.reflect.Method;
005    import java.util.ArrayList;
006    import java.util.Set;
007    import java.util.concurrent.ConcurrentHashMap;
008    
009    
010    
011    import com.google.common.reflect.TypeToken;
012    
013    public 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    }