diff --git a/src/main/java/ch/njol/skript/registrations/EventValues.java b/src/main/java/ch/njol/skript/registrations/EventValues.java index 7201dc86081..82089400a71 100644 --- a/src/main/java/ch/njol/skript/registrations/EventValues.java +++ b/src/main/java/ch/njol/skript/registrations/EventValues.java @@ -203,7 +203,7 @@ public static T getEventValue(E e, Class c, int time) { *

* Can print an error if the event value is blocked for the given event. * - * @param e the event class the getter will be getting from + * @param event the event class the getter will be getting from * @param c type of getter * @param time the event-value's time * @return A getter to get values for a given type of events @@ -211,118 +211,139 @@ public static T getEventValue(E e, Class c, int time) { * @see EventValueExpression#EventValueExpression(Class) */ @Nullable - public static Getter getEventValueGetter(Class e, Class c, int time) { - return getEventValueGetter(e, c, time, true); + public static Getter getEventValueGetter(Class event, Class c, int time) { + return getEventValueGetter(event, c, time, true); } @SuppressWarnings("unchecked") @Nullable - private static Getter getEventValueGetter(Class e, Class c, int time, boolean allowDefault) { + private static Getter getEventValueGetter(Class event, Class c, int time, boolean allowDefault) { List> eventValues = getEventValuesList(time); // First check for exact classes matching the parameters. - for (EventValueInfo ev : eventValues) { - if (!c.equals(ev.c)) + for (EventValueInfo eventValueInfo : eventValues) { + if (!c.equals(eventValueInfo.c)) continue; - if (!checkExcludes(ev, e)) + if (!checkExcludes(eventValueInfo, event)) return null; - if (ev.event.isAssignableFrom(e)) - return (Getter) ev.getter; + if (eventValueInfo.event.isAssignableFrom(event)) + return (Getter) eventValueInfo.getter; } // Second check for assignable subclasses. - for (EventValueInfo ev : eventValues) { - if (!c.isAssignableFrom(ev.c)) + for (EventValueInfo eventValueInfo : eventValues) { + if (!c.isAssignableFrom(eventValueInfo.c)) continue; - if (!checkExcludes(ev, e)) + if (!checkExcludes(eventValueInfo, event)) return null; - if (ev.event.isAssignableFrom(e)) - return (Getter) ev.getter; - if (!e.isAssignableFrom(ev.event)) + if (eventValueInfo.event.isAssignableFrom(event)) + return (Getter) eventValueInfo.getter; + if (!event.isAssignableFrom(eventValueInfo.event)) continue; return new Getter() { @Override @Nullable public T get(E event) { - if (!ev.event.isInstance(event)) + if (!eventValueInfo.event.isInstance(event)) return null; - return ((Getter) ev.getter).get(event); + return ((Getter) eventValueInfo.getter).get(event); } }; } // Most checks have returned before this below is called, but Skript will attempt to convert or find an alternative. // Third check is if the returned object matches the class. - for (EventValueInfo ev : eventValues) { - if (!ev.c.isAssignableFrom(c)) + for (EventValueInfo eventValueInfo : eventValues) { + if (!eventValueInfo.c.isAssignableFrom(c)) continue; - boolean checkInstanceOf = !ev.event.isAssignableFrom(e); - if (checkInstanceOf && !e.isAssignableFrom(ev.event)) + boolean checkInstanceOf = !eventValueInfo.event.isAssignableFrom(event); + if (checkInstanceOf && !event.isAssignableFrom(eventValueInfo.event)) continue; - if (!checkExcludes(ev, e)) + if (!checkExcludes(eventValueInfo, event)) return null; return new Getter() { @Override @Nullable public T get(E event) { - if (checkInstanceOf && !ev.event.isInstance(event)) + if (checkInstanceOf && !eventValueInfo.event.isInstance(event)) return null; - Object object = ((Getter) ev.getter).get(event); + Object object = ((Getter) eventValueInfo.getter).get(event); if (c.isInstance(object)) return (T) object; return null; } }; } - // Fourth check will attempt to convert the event value to the type. - for (EventValueInfo ev : eventValues) { - boolean checkInstanceOf = !ev.event.isAssignableFrom(e); - if (checkInstanceOf && !e.isAssignableFrom(ev.event)) + // Fourth check will attempt to convert the event value to the requesting type. + // This first for loop will check that the events are exact. See issue #5016 + for (EventValueInfo eventValueInfo : eventValues) { + if (!event.equals(eventValueInfo.event)) continue; - Getter getter = (Getter) getConvertedGetter(ev, c, checkInstanceOf); + Getter getter = (Getter) getConvertedGetter(eventValueInfo, c, false); if (getter == null) continue; - if (!checkExcludes(ev, e)) + if (!checkExcludes(eventValueInfo, event)) + return null; + return getter; + } + // This loop will attempt to look for converters assignable to the class of the provided event. + for (EventValueInfo eventValueInfo : eventValues) { + // The requesting event must be assignable to the event value's event. Otherwise it'll throw an error. + if (!event.isAssignableFrom(eventValueInfo.event)) + continue; + + Getter getter = (Getter) getConvertedGetter(eventValueInfo, c, true); + if (getter == null) + continue; + + if (!checkExcludes(eventValueInfo, event)) return null; return getter; } // If the check should try again matching event values with a 0 time (most event values). if (allowDefault && time != 0) - return getEventValueGetter(e, c, 0, false); + return getEventValueGetter(event, c, 0, false); return null; } /** * Check if the event value states to exclude events. * - * @param ev - * @param e + * @param info The event value info that will be used to grab the value from + * @param event The event class to check the excludes against. * @return boolean if true the event value passes for the events. */ - @SuppressWarnings("unchecked") - private static boolean checkExcludes(EventValueInfo ev, Class e) { - if (ev.excludes == null) + private static boolean checkExcludes(EventValueInfo info, Class event) { + if (info.excludes == null) return true; - for (Class ex : (Class[]) ev.excludes) { - if (ex.isAssignableFrom(e)) { - Skript.error(ev.excludeErrorMessage); + for (Class ex : (Class[]) info.excludes) { + if (ex.isAssignableFrom(event)) { + Skript.error(info.excludeErrorMessage); return false; } } return true; } - + + /** + * Return a converter wrapped in a getter that will grab the requested value by converting from the given event value info. + * + * @param info The event value info that will be used to grab the value from + * @param to The class that the converter will look for to convert the type from the event value to + * @param checkInstanceOf If the event must be an exact instance of the event value info's event or not. + * @return The found Converter wrapped in a Getter object, or null if no Converter was found. + */ @Nullable - private static Getter getConvertedGetter(EventValueInfo i, Class to, boolean checkInstanceOf) { - Converter converter = Converters.getConverter(i.c, to); + private static Getter getConvertedGetter(EventValueInfo info, Class to, boolean checkInstanceOf) { + Converter converter = Converters.getConverter(info.c, to); if (converter == null) return null; return new Getter() { @Override @Nullable public T get(E e) { - if (checkInstanceOf && !i.event.isInstance(e)) + if (checkInstanceOf && !info.event.isInstance(e)) return null; - F f = i.getter.get(e); + F f = info.getter.get(e); if (f == null) return null; return converter.convert(f);