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