    001package net.minecraftforge.event;
    002
    003import static java.lang.annotation.ElementType.TYPE;
    004import static java.lang.annotation.RetentionPolicy.RUNTIME;
    005
    006import java.lang.annotation.Retention;
    007import java.lang.annotation.Target;
    008import java.util.Map;
    009import java.util.concurrent.ConcurrentHashMap;
    010
    011
    012/**
    013 * Base Event class that all other events are derived from
    014 */
    015public class Event
    016{
    017    @Retention(value = RUNTIME)
    018    @Target(value = TYPE)
    019    public @interface HasResult{}
    020
    021    public enum Result
    022    {
    023        DENY,
    024        DEFAULT,
    025        ALLOW
    026    }
    027
    028    private boolean isCanceled = false;
    029    private final boolean isCancelable;
    030    private Result result = Result.DEFAULT;
    031    private final boolean hasResult;
    032    private static ListenerList listeners = new ListenerList();
    033
    034    private static final Map<Class, Map<Class, Boolean>> annotationMap = new ConcurrentHashMap<Class, Map<Class, Boolean>>();
    035
    036    public Event()
    037    {
    038        setup();
    039        isCancelable = hasAnnotation(Cancelable.class);
    040        hasResult = hasAnnotation(HasResult.class);
    041    }
    042
    043    private boolean hasAnnotation(Class annotation)
    044    {
    045        Class me = this.getClass();
    046        Map<Class, Boolean> list = annotationMap.get(me);
    047        if (list == null)
    048        {
    049            list = new ConcurrentHashMap<Class, Boolean>();
    050            annotationMap.put(me, list);
    051        }
    052
    053        Boolean cached = list.get(annotation);
    054        if (cached != null)
    055        {
    056            return cached;
    057        }
    058
    059        Class cls = me;
    060        while (cls != Event.class)
    061        {
    062            if (cls.isAnnotationPresent(annotation))
    063            {
    064                list.put(annotation, true);
    065                return true;
    066            }
    067            cls = cls.getSuperclass();
    068        }
    069
    070        list.put(annotation, false);
    071        return false;
    072    }
    073
    074    /**
    075     * Determine if this function is cancelable at all.
    076     * @return If access to setCanceled should be allowed
    077     */
    078    public boolean isCancelable()
    079    {
    080        return isCancelable;
    081    }
    082
    083    /**
    084     * Determine if this event is canceled and should stop executing.
    085     * @return The current canceled state
    086     */
    087    public boolean isCanceled()
    088    {
    089        return isCanceled;
    090    }
    091
    092    /**
    093     * Sets the state of this event, not all events are cancelable, and any attempt to
    094     * cancel a event that can't be will result in a IllegalArgumentException.
    095     *
    096     * The functionality of setting the canceled state is defined on a per-event bases.
    097     *
    098     * @param cancel The new canceled value
    099     */
    100    public void setCanceled(boolean cancel)
    101    {
    102        if (!isCancelable())
    103        {
    104            throw new IllegalArgumentException("Attempted to cancel a uncancelable event");
    105        }
    106        isCanceled = cancel;
    107    }
    108
    109    /**
    110     * Determines if this event expects a significant result value.
    111     */
    112    public boolean hasResult()
    113    {
    114        return hasResult;
    115    }
    116
    117    /**
    118     * Returns the value set as the result of this event
    119     */
    120    public Result getResult()
    121    {
    122        return result;
    123    }
    124
    125    /**
    126     * Sets the result value for this event, not all events can have a result set, and any attempt to
    127     * set a result for a event that isn't expecting it will result in a IllegalArgumentException.
    128     *
    129     * The functionality of setting the result is defined on a per-event bases.
    130     *
    131     * @param value The new result
    132     */
    133    public void setResult(Result value)
    134    {
    135        result = value;
    136    }
    137    /**
    138     * Called by the base constructor, this is used by ASM generated
    139     * event classes to setup various functionality such as the listener's list.
    140     */
    141    protected void setup()
    142    {
    143    }
    144
    145    /**
    146     * Returns a ListenerList object that contains all listeners
    147     * that are registered to this event.
    148     *
    149     * @return Listener List
    150     */
    151    public ListenerList getListenerList()
    152    {
    153        return listeners;
    154    }
    155}