From aa7cdb345938cad59c994764d3ab9c0d7dc8d90b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=9D=8F=E9=BB=91?= Date: Mon, 19 Feb 2018 14:56:51 +0800 Subject: [PATCH] =?UTF-8?q?=E7=89=88=E6=9C=AC=E6=9B=B4=E6=96=B0=E8=87=B3?= =?UTF-8?q?=203.57?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 声明:EffLib 工具的代码来自 DarkBlade12 的开源项目 ParticleEffect 并新增 1.9+ 的一些特效 --- .../taboolib/methods/ReflectionUtils.java | 870 ++++--- .../me/skymc/taboolib/particle/EffLib.java | 2140 ++++++++++++----- 2 files changed, 2086 insertions(+), 924 deletions(-) diff --git a/src/main/src/me/skymc/taboolib/methods/ReflectionUtils.java b/src/main/src/me/skymc/taboolib/methods/ReflectionUtils.java index 9a6687a65..f87f4beee 100644 --- a/src/main/src/me/skymc/taboolib/methods/ReflectionUtils.java +++ b/src/main/src/me/skymc/taboolib/methods/ReflectionUtils.java @@ -6,311 +6,601 @@ import java.lang.reflect.Method; import java.util.HashMap; import java.util.Map; + import org.bukkit.Bukkit; /** - * Ŀ ParticleEffect + * ReflectionUtils + *

+ * This class provides useful methods which makes dealing with reflection much easier, especially when working with Bukkit + *

+ * You are welcome to use it, modify it and redistribute it under the following conditions: + *

+ *

+ * It would be nice if you provide credit to me if you use this class in a published project + * + * @author DarkBlade12 + * @version 1.1 */ public final class ReflectionUtils { - - public static Object invokeMethodByClass(Object ownder, String methodName, Object... args) { - try { - Class ownderClass = ownder.getClass(); - Class[] argsClass = new Class[args.length]; - - for (int i = 0 ; i < args.length ; i++) { - argsClass[i] = args[i].getClass(); + // Prevent accidental construction + private ReflectionUtils() {} + + /** + * Returns the constructor of a given class with the given parameter types + * + * @param clazz Target class + * @param parameterTypes Parameter types of the desired constructor + * @return The constructor of the target class with the specified parameter types + * @throws NoSuchMethodException If the desired constructor with the specified parameter types cannot be found + * @see DataType + * @see DataType#getPrimitive(Class[]) + * @see DataType#compare(Class[], Class[]) + */ + public static Constructor getConstructor(Class clazz, Class... parameterTypes) throws NoSuchMethodException { + Class[] primitiveTypes = DataType.getPrimitive(parameterTypes); + for (Constructor constructor : clazz.getConstructors()) { + if (!DataType.compare(DataType.getPrimitive(constructor.getParameterTypes()), primitiveTypes)) { + continue; } - - Method method = ownderClass.getMethod(methodName, argsClass); - return method.invoke(ownder, args); + return constructor; } - catch (Exception e) { - return null; + throw new NoSuchMethodException("There is no such constructor in this class with the specified parameter types"); + } + + /** + * Returns the constructor of a desired class with the given parameter types + * + * @param className Name of the desired target class + * @param packageType Package where the desired target class is located + * @param parameterTypes Parameter types of the desired constructor + * @return The constructor of the desired target class with the specified parameter types + * @throws NoSuchMethodException If the desired constructor with the specified parameter types cannot be found + * @throws ClassNotFoundException ClassNotFoundException If the desired target class with the specified name and package cannot be found + * @see #getClass(String, PackageType) + * @see #getConstructor(Class, Class...) + */ + public static Constructor getConstructor(String className, PackageType packageType, Class... parameterTypes) throws NoSuchMethodException, ClassNotFoundException { + return getConstructor(packageType.getClass(className), parameterTypes); + } + + /** + * Returns an instance of a class with the given arguments + * + * @param clazz Target class + * @param arguments Arguments which are used to construct an object of the target class + * @return The instance of the target class with the specified arguments + * @throws InstantiationException If you cannot create an instance of the target class due to certain circumstances + * @throws IllegalAccessException If the desired constructor cannot be accessed due to certain circumstances + * @throws IllegalArgumentException If the types of the arguments do not match the parameter types of the constructor (this should not occur since it searches for a constructor with the types of the arguments) + * @throws InvocationTargetException If the desired constructor cannot be invoked + * @throws NoSuchMethodException If the desired constructor with the specified arguments cannot be found + */ + public static Object instantiateObject(Class clazz, Object... arguments) throws InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException, NoSuchMethodException { + return getConstructor(clazz, DataType.getPrimitive(arguments)).newInstance(arguments); + } + + /** + * Returns an instance of a desired class with the given arguments + * + * @param className Name of the desired target class + * @param packageType Package where the desired target class is located + * @param arguments Arguments which are used to construct an object of the desired target class + * @return The instance of the desired target class with the specified arguments + * @throws InstantiationException If you cannot create an instance of the desired target class due to certain circumstances + * @throws IllegalAccessException If the desired constructor cannot be accessed due to certain circumstances + * @throws IllegalArgumentException If the types of the arguments do not match the parameter types of the constructor (this should not occur since it searches for a constructor with the types of the arguments) + * @throws InvocationTargetException If the desired constructor cannot be invoked + * @throws NoSuchMethodException If the desired constructor with the specified arguments cannot be found + * @throws ClassNotFoundException If the desired target class with the specified name and package cannot be found + * @see #getClass(String, PackageType) + * @see #instantiateObject(Class, Object...) + */ + public static Object instantiateObject(String className, PackageType packageType, Object... arguments) throws InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException, NoSuchMethodException, ClassNotFoundException { + return instantiateObject(packageType.getClass(className), arguments); + } + + /** + * Returns a method of a class with the given parameter types + * + * @param clazz Target class + * @param methodName Name of the desired method + * @param parameterTypes Parameter types of the desired method + * @return The method of the target class with the specified name and parameter types + * @throws NoSuchMethodException If the desired method of the target class with the specified name and parameter types cannot be found + * @see DataType#getPrimitive(Class[]) + * @see DataType#compare(Class[], Class[]) + */ + public static Method getMethod(Class clazz, String methodName, Class... parameterTypes) throws NoSuchMethodException { + Class[] primitiveTypes = DataType.getPrimitive(parameterTypes); + for (Method method : clazz.getMethods()) { + if (!method.getName().equals(methodName) || !DataType.compare(DataType.getPrimitive(method.getParameterTypes()), primitiveTypes)) { + continue; + } + return method; } + throw new NoSuchMethodException("There is no such method in this class with the specified name and parameter types"); + } + + /** + * Returns a method of a desired class with the given parameter types + * + * @param className Name of the desired target class + * @param packageType Package where the desired target class is located + * @param methodName Name of the desired method + * @param parameterTypes Parameter types of the desired method + * @return The method of the desired target class with the specified name and parameter types + * @throws NoSuchMethodException If the desired method of the desired target class with the specified name and parameter types cannot be found + * @throws ClassNotFoundException If the desired target class with the specified name and package cannot be found + * @see #getClass(String, PackageType) + * @see #getMethod(Class, String, Class...) + */ + public static Method getMethod(String className, PackageType packageType, String methodName, Class... parameterTypes) throws NoSuchMethodException, ClassNotFoundException { + return getMethod(packageType.getClass(className), methodName, parameterTypes); + } + + /** + * Invokes a method on an object with the given arguments + * + * @param instance Target object + * @param methodName Name of the desired method + * @param arguments Arguments which are used to invoke the desired method + * @return The result of invoking the desired method on the target object + * @throws IllegalAccessException If the desired method cannot be accessed due to certain circumstances + * @throws IllegalArgumentException If the types of the arguments do not match the parameter types of the method (this should not occur since it searches for a method with the types of the arguments) + * @throws InvocationTargetException If the desired method cannot be invoked on the target object + * @throws NoSuchMethodException If the desired method of the class of the target object with the specified name and arguments cannot be found + * @see #getMethod(Class, String, Class...) + * @see DataType#getPrimitive(Object[]) + */ + public static Object invokeMethod(Object instance, String methodName, Object... arguments) throws IllegalAccessException, IllegalArgumentException, InvocationTargetException, NoSuchMethodException { + return getMethod(instance.getClass(), methodName, DataType.getPrimitive(arguments)).invoke(instance, arguments); + } + + /** + * Invokes a method of the target class on an object with the given arguments + * + * @param instance Target object + * @param clazz Target class + * @param methodName Name of the desired method + * @param arguments Arguments which are used to invoke the desired method + * @return The result of invoking the desired method on the target object + * @throws IllegalAccessException If the desired method cannot be accessed due to certain circumstances + * @throws IllegalArgumentException If the types of the arguments do not match the parameter types of the method (this should not occur since it searches for a method with the types of the arguments) + * @throws InvocationTargetException If the desired method cannot be invoked on the target object + * @throws NoSuchMethodException If the desired method of the target class with the specified name and arguments cannot be found + * @see #getMethod(Class, String, Class...) + * @see DataType#getPrimitive(Object[]) + */ + public static Object invokeMethod(Object instance, Class clazz, String methodName, Object... arguments) throws IllegalAccessException, IllegalArgumentException, InvocationTargetException, NoSuchMethodException { + return getMethod(clazz, methodName, DataType.getPrimitive(arguments)).invoke(instance, arguments); + } + + /** + * Invokes a method of a desired class on an object with the given arguments + * + * @param instance Target object + * @param className Name of the desired target class + * @param packageType Package where the desired target class is located + * @param methodName Name of the desired method + * @param arguments Arguments which are used to invoke the desired method + * @return The result of invoking the desired method on the target object + * @throws IllegalAccessException If the desired method cannot be accessed due to certain circumstances + * @throws IllegalArgumentException If the types of the arguments do not match the parameter types of the method (this should not occur since it searches for a method with the types of the arguments) + * @throws InvocationTargetException If the desired method cannot be invoked on the target object + * @throws NoSuchMethodException If the desired method of the desired target class with the specified name and arguments cannot be found + * @throws ClassNotFoundException If the desired target class with the specified name and package cannot be found + * @see #getClass(String, PackageType) + * @see #invokeMethod(Object, Class, String, Object...) + */ + public static Object invokeMethod(Object instance, String className, PackageType packageType, String methodName, Object... arguments) throws IllegalAccessException, IllegalArgumentException, InvocationTargetException, NoSuchMethodException, ClassNotFoundException { + return invokeMethod(instance, packageType.getClass(className), methodName, arguments); } - - public static Constructor getConstructor(final Class clazz, final Class... array) { - final Class[] primitive = DataType.getPrimitive(array); - Constructor[] constructors = null; - for (int length = (constructors = clazz.getConstructors()).length, i = 0; i < length; ++i) { - final Constructor constructor = constructors[i]; - if (DataType.compare(DataType.getPrimitive(constructor.getParameterTypes()), primitive)) { - return (Constructor)constructor; - } - } - try { - throw new NoSuchMethodException("There is no such constructor in this class with the specified parameter types"); - } catch (NoSuchMethodException e) { - e.printStackTrace(); + + /** + * Returns a field of the target class with the given name + * + * @param clazz Target class + * @param declared Whether the desired field is declared or not + * @param fieldName Name of the desired field + * @return The field of the target class with the specified name + * @throws NoSuchFieldException If the desired field of the given class cannot be found + * @throws SecurityException If the desired field cannot be made accessible + */ + public static Field getField(Class clazz, boolean declared, String fieldName) throws NoSuchFieldException, SecurityException { + Field field = declared ? clazz.getDeclaredField(fieldName) : clazz.getField(fieldName); + field.setAccessible(true); + return field; + } + + /** + * Returns a field of a desired class with the given name + * + * @param className Name of the desired target class + * @param packageType Package where the desired target class is located + * @param declared Whether the desired field is declared or not + * @param fieldName Name of the desired field + * @return The field of the desired target class with the specified name + * @throws NoSuchFieldException If the desired field of the desired class cannot be found + * @throws SecurityException If the desired field cannot be made accessible + * @throws ClassNotFoundException If the desired target class with the specified name and package cannot be found + * @see #getField(Class, boolean, String) + */ + public static Field getField(String className, PackageType packageType, boolean declared, String fieldName) throws NoSuchFieldException, SecurityException, ClassNotFoundException { + return getField(packageType.getClass(className), declared, fieldName); + } + + /** + * Returns the value of a field of the given class of an object + * + * @param instance Target object + * @param clazz Target class + * @param declared Whether the desired field is declared or not + * @param fieldName Name of the desired field + * @return The value of field of the target object + * @throws IllegalArgumentException If the target object does not feature the desired field + * @throws IllegalAccessException If the desired field cannot be accessed + * @throws NoSuchFieldException If the desired field of the target class cannot be found + * @throws SecurityException If the desired field cannot be made accessible + * @see #getField(Class, boolean, String) + */ + public static Object getValue(Object instance, Class clazz, boolean declared, String fieldName) throws IllegalArgumentException, IllegalAccessException, NoSuchFieldException, SecurityException { + return getField(clazz, declared, fieldName).get(instance); + } + + /** + * Returns the value of a field of a desired class of an object + * + * @param instance Target object + * @param className Name of the desired target class + * @param packageType Package where the desired target class is located + * @param declared Whether the desired field is declared or not + * @param fieldName Name of the desired field + * @return The value of field of the target object + * @throws IllegalArgumentException If the target object does not feature the desired field + * @throws IllegalAccessException If the desired field cannot be accessed + * @throws NoSuchFieldException If the desired field of the desired class cannot be found + * @throws SecurityException If the desired field cannot be made accessible + * @throws ClassNotFoundException If the desired target class with the specified name and package cannot be found + * @see #getValue(Object, Class, boolean, String) + */ + public static Object getValue(Object instance, String className, PackageType packageType, boolean declared, String fieldName) throws IllegalArgumentException, IllegalAccessException, NoSuchFieldException, SecurityException, ClassNotFoundException { + return getValue(instance, packageType.getClass(className), declared, fieldName); + } + + /** + * Returns the value of a field with the given name of an object + * + * @param instance Target object + * @param declared Whether the desired field is declared or not + * @param fieldName Name of the desired field + * @return The value of field of the target object + * @throws IllegalArgumentException If the target object does not feature the desired field (should not occur since it searches for a field with the given name in the class of the object) + * @throws IllegalAccessException If the desired field cannot be accessed + * @throws NoSuchFieldException If the desired field of the target object cannot be found + * @throws SecurityException If the desired field cannot be made accessible + * @see #getValue(Object, Class, boolean, String) + */ + public static Object getValue(Object instance, boolean declared, String fieldName) throws IllegalArgumentException, IllegalAccessException, NoSuchFieldException, SecurityException { + return getValue(instance, instance.getClass(), declared, fieldName); + } + + /** + * Sets the value of a field of the given class of an object + * + * @param instance Target object + * @param clazz Target class + * @param declared Whether the desired field is declared or not + * @param fieldName Name of the desired field + * @param value New value + * @throws IllegalArgumentException If the type of the value does not match the type of the desired field + * @throws IllegalAccessException If the desired field cannot be accessed + * @throws NoSuchFieldException If the desired field of the target class cannot be found + * @throws SecurityException If the desired field cannot be made accessible + * @see #getField(Class, boolean, String) + */ + public static void setValue(Object instance, Class clazz, boolean declared, String fieldName, Object value) throws IllegalArgumentException, IllegalAccessException, NoSuchFieldException, SecurityException { + getField(clazz, declared, fieldName).set(instance, value); + } + + /** + * Sets the value of a field of a desired class of an object + * + * @param instance Target object + * @param className Name of the desired target class + * @param packageType Package where the desired target class is located + * @param declared Whether the desired field is declared or not + * @param fieldName Name of the desired field + * @param value New value + * @throws IllegalArgumentException If the type of the value does not match the type of the desired field + * @throws IllegalAccessException If the desired field cannot be accessed + * @throws NoSuchFieldException If the desired field of the desired class cannot be found + * @throws SecurityException If the desired field cannot be made accessible + * @throws ClassNotFoundException If the desired target class with the specified name and package cannot be found + * @see #setValue(Object, Class, boolean, String, Object) + */ + public static void setValue(Object instance, String className, PackageType packageType, boolean declared, String fieldName, Object value) throws IllegalArgumentException, IllegalAccessException, NoSuchFieldException, SecurityException, ClassNotFoundException { + setValue(instance, packageType.getClass(className), declared, fieldName, value); + } + + /** + * Sets the value of a field with the given name of an object + * + * @param instance Target object + * @param declared Whether the desired field is declared or not + * @param fieldName Name of the desired field + * @param value New value + * @throws IllegalArgumentException If the type of the value does not match the type of the desired field + * @throws IllegalAccessException If the desired field cannot be accessed + * @throws NoSuchFieldException If the desired field of the target object cannot be found + * @throws SecurityException If the desired field cannot be made accessible + * @see #setValue(Object, Class, boolean, String, Object) + */ + public static void setValue(Object instance, boolean declared, String fieldName, Object value) throws IllegalArgumentException, IllegalAccessException, NoSuchFieldException, SecurityException { + setValue(instance, instance.getClass(), declared, fieldName, value); + } + + /** + * Represents an enumeration of dynamic packages of NMS and CraftBukkit + *

+ * This class is part of the ReflectionUtils and follows the same usage conditions + * + * @author DarkBlade12 + * @since 1.0 + */ + public enum PackageType { + MINECRAFT_SERVER("net.minecraft.server." + getServerVersion()), + CRAFTBUKKIT("org.bukkit.craftbukkit." + getServerVersion()), + CRAFTBUKKIT_BLOCK(CRAFTBUKKIT, "block"), + CRAFTBUKKIT_CHUNKIO(CRAFTBUKKIT, "chunkio"), + CRAFTBUKKIT_COMMAND(CRAFTBUKKIT, "command"), + CRAFTBUKKIT_CONVERSATIONS(CRAFTBUKKIT, "conversations"), + CRAFTBUKKIT_ENCHANTMENS(CRAFTBUKKIT, "enchantments"), + CRAFTBUKKIT_ENTITY(CRAFTBUKKIT, "entity"), + CRAFTBUKKIT_EVENT(CRAFTBUKKIT, "event"), + CRAFTBUKKIT_GENERATOR(CRAFTBUKKIT, "generator"), + CRAFTBUKKIT_HELP(CRAFTBUKKIT, "help"), + CRAFTBUKKIT_INVENTORY(CRAFTBUKKIT, "inventory"), + CRAFTBUKKIT_MAP(CRAFTBUKKIT, "map"), + CRAFTBUKKIT_METADATA(CRAFTBUKKIT, "metadata"), + CRAFTBUKKIT_POTION(CRAFTBUKKIT, "potion"), + CRAFTBUKKIT_PROJECTILES(CRAFTBUKKIT, "projectiles"), + CRAFTBUKKIT_SCHEDULER(CRAFTBUKKIT, "scheduler"), + CRAFTBUKKIT_SCOREBOARD(CRAFTBUKKIT, "scoreboard"), + CRAFTBUKKIT_UPDATER(CRAFTBUKKIT, "updater"), + CRAFTBUKKIT_UTIL(CRAFTBUKKIT, "util"); + + private final String path; + + /** + * Construct a new package type + * + * @param path Path of the package + */ + private PackageType(String path) { + this.path = path; } - return null; - } - - public static Constructor getConstructor(final String s, final PackageType packageType, final Class... array) { - return getConstructor(packageType.getClass(s), array); - } - - public static Object instantiateObject(final Class clazz, final Object... array) { - try { - return getConstructor(clazz, DataType.getPrimitive(array)).newInstance(array); - } catch (InstantiationException e) { - return null; - } catch (IllegalAccessException e) { - return null; - } catch (IllegalArgumentException e) { - return null; - } catch (InvocationTargetException e) { - return null; + + /** + * Construct a new package type + * + * @param parent Parent package of the package + * @param path Path of the package + */ + private PackageType(PackageType parent, String path) { + this(parent + "." + path); } - } - - public static Object instantiateObject(final String s, final PackageType packageType, final Object... array) { - return instantiateObject(packageType.getClass(s), array); - } - - public static Method getMethod(final Class clazz, final String s, final Class... array) { - final Class[] primitive = DataType.getPrimitive(array); - Method[] methods; - for (int length = (methods = clazz.getMethods()).length, i = 0; i < length; ++i) { - final Method method = methods[i]; - if (method.getName().equals(s) && DataType.compare(DataType.getPrimitive(method.getParameterTypes()), primitive)) { - return method; - } - } - try { - throw new NoSuchMethodException("There is no such method in this class with the specified name and parameter types"); - } catch (NoSuchMethodException e) { - return null; + + /** + * Returns the path of this package type + * + * @return The path + */ + public String getPath() { + return path; } - } - - public static Method getMethod(final String s, final PackageType packageType, final String s2, final Class... array) { - return getMethod(packageType.getClass(s), s2, array); - } - - public static Object invokeMethod(final Object o, final String s, final Object... array) { - try { - return getMethod(o.getClass(), s, DataType.getPrimitive(array)).invoke(o, array); - } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) { - return null; + + /** + * Returns the class with the given name + * + * @param className Name of the desired class + * @return The class with the specified name + * @throws ClassNotFoundException If the desired class with the specified name and package cannot be found + */ + public Class getClass(String className) throws ClassNotFoundException { + return Class.forName(this + "." + className); } - } - - public static Object invokeMethod(final Object o, final Class clazz, final String s, final Object... array) { - try { - return getMethod(clazz, s, DataType.getPrimitive(array)).invoke(o, array); - } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) { - return null; + + // Override for convenience + @Override + public String toString() { + return path; } - } - - public static Object invokeMethod(final Object o, final String s, final PackageType packageType, final String s2, final Object... array) { - return invokeMethod(o, packageType.getClass(s), s2, array); - } - - public static Field getField(final Class clazz, final boolean b, final String s) { - Field field; - try { - field = b ? clazz.getDeclaredField(s) : clazz.getField(s); - } catch (NoSuchFieldException | SecurityException e) { - return null; + + /** + * Returns the version of your server + * + * @return The server version + */ + public static String getServerVersion() { + return Bukkit.getServer().getClass().getPackage().getName().substring(23); } - field.setAccessible(true); - return field; - } - - public static Field getField(final String s, final PackageType packageType, final boolean b, final String s2) { - return getField(packageType.getClass(s), b, s2); - } - - public static Object getValue(final Object o, final Class clazz, final boolean b, final String s) { - try { - return getField(clazz, b, s).get(o); - } catch (IllegalArgumentException | IllegalAccessException e) { - return null; + } + + /** + * Represents an enumeration of Java data types with corresponding classes + *

+ * This class is part of the ReflectionUtils and follows the same usage conditions + * + * @author DarkBlade12 + * @since 1.0 + */ + public enum DataType { + BYTE(byte.class, Byte.class), + SHORT(short.class, Short.class), + INTEGER(int.class, Integer.class), + LONG(long.class, Long.class), + CHARACTER(char.class, Character.class), + FLOAT(float.class, Float.class), + DOUBLE(double.class, Double.class), + BOOLEAN(boolean.class, Boolean.class); + + private static final Map, DataType> CLASS_MAP = new HashMap, DataType>(); + private final Class primitive; + private final Class reference; + + // Initialize map for quick class lookup + static { + for (DataType type : values()) { + CLASS_MAP.put(type.primitive, type); + CLASS_MAP.put(type.reference, type); + } } - } - - public static Object getValue(final Object o, final String s, final PackageType packageType, final boolean b, final String s2) { - return getValue(o, packageType.getClass(s), b, s2); - } - - public static Object getValue(final Object o, final boolean b, final String s) { - return getValue(o, o.getClass(), b, s); - } - - public static void setValue(final Object o, final Class clazz, final boolean b, final String s, final Object o2) { - try { - getField(clazz, b, s).set(o, o2); - } catch (IllegalArgumentException | IllegalAccessException e) { - return; + + /** + * Construct a new data type + * + * @param primitive Primitive class of this data type + * @param reference Reference class of this data type + */ + private DataType(Class primitive, Class reference) { + this.primitive = primitive; + this.reference = reference; + } + + /** + * Returns the primitive class of this data type + * + * @return The primitive class + */ + public Class getPrimitive() { + return primitive; + } + + /** + * Returns the reference class of this data type + * + * @return The reference class + */ + public Class getReference() { + return reference; + } + + /** + * Returns the data type with the given primitive/reference class + * + * @param clazz Primitive/Reference class of the data type + * @return The data type + */ + public static DataType fromClass(Class clazz) { + return CLASS_MAP.get(clazz); + } + + /** + * Returns the primitive class of the data type with the given reference class + * + * @param clazz Reference class of the data type + * @return The primitive class + */ + public static Class getPrimitive(Class clazz) { + DataType type = fromClass(clazz); + return type == null ? clazz : type.getPrimitive(); } - } - - public static void setValue(final Object o, final String s, final PackageType packageType, final boolean b, final String s2, final Object o2) { - setValue(o, packageType.getClass(s), b, s2, o2); - } - - public static void setValue(final Object o, final boolean b, final String s, final Object o2) { - setValue(o, o.getClass(), b, s, o2); - } - - public enum DataType - { - BYTE((Class)Byte.TYPE, (Class)Byte.class), - SHORT((Class)Short.TYPE, (Class)Short.class), - INTEGER((Class)Integer.TYPE, (Class)Integer.class), - LONG((Class)Long.TYPE, (Class)Long.class), - CHARACTER((Class)Character.TYPE, (Class)Character.class), - FLOAT((Class)Float.TYPE, (Class)Float.class), - DOUBLE((Class)Double.TYPE, (Class)Double.class), - BOOLEAN((Class)Boolean.TYPE, (Class)Boolean.class); - - private static final Map, DataType> CLASS_MAP; - private final Class primitive; - private final Class reference; - - static { - CLASS_MAP = new HashMap, DataType>(); - DataType[] values; - for (int length = (values = values()).length, i = 0; i < length; ++i) { - final DataType dataType = values[i]; - DataType.CLASS_MAP.put(dataType.primitive, dataType); - DataType.CLASS_MAP.put(dataType.reference, dataType); - } - } - - private DataType(final Class primitive, final Class reference) { - this.primitive = primitive; - this.reference = reference; - } - - public Class getPrimitive() { - return this.primitive; - } - - public Class getReference() { - return this.reference; - } - - public static DataType fromClass(final Class clazz) { - return DataType.CLASS_MAP.get(clazz); - } - - public static Class getPrimitive(final Class clazz) { - final DataType fromClass = fromClass(clazz); - return (fromClass == null) ? clazz : fromClass.getPrimitive(); - } - - public static Class getReference(final Class clazz) { - final DataType fromClass = fromClass(clazz); - return (fromClass == null) ? clazz : fromClass.getReference(); - } - - public static Class[] getPrimitive(final Class[] array) { - final int n = (array == null) ? 0 : array.length; - final Class[] array2 = new Class[n]; - for (int i = 0; i < n; ++i) { - array2[i] = getPrimitive(array[i]); - } - return (Class[])array2; - } - - public static Class[] getReference(final Class[] array) { - final int n = (array == null) ? 0 : array.length; - final Class[] array2 = new Class[n]; - for (int i = 0; i < n; ++i) { - array2[i] = getReference(array[i]); - } - return (Class[])array2; - } - - public static Class[] getPrimitive(final Object[] array) { - final int n = (array == null) ? 0 : array.length; - final Class[] array2 = new Class[n]; - for (int i = 0; i < n; ++i) { - array2[i] = getPrimitive(array[i].getClass()); - } - return (Class[])array2; - } - - public static Class[] getReference(final Object[] array) { - final int n = (array == null) ? 0 : array.length; - final Class[] array2 = new Class[n]; - for (int i = 0; i < n; ++i) { - array2[i] = getReference(array[i].getClass()); - } - return (Class[])array2; - } - - public static boolean compare(final Class[] array, final Class[] array2) { - if (array == null || array2 == null || array.length != array2.length) { - return false; - } - for (int i = 0; i < array.length; ++i) { - final Class clazz = array[i]; - final Class clazz2 = array2[i]; - if (!clazz.equals(clazz2) && !clazz.isAssignableFrom(clazz2)) { - return false; - } - } - return true; - } - } - - public enum PackageType - { - MINECRAFT_SERVER("MINECRAFT_SERVER", 0, "net.minecraft.server." + getServerVersion()), - CRAFTBUKKIT("CRAFTBUKKIT", 1, "org.bukkit.craftbukkit." + getServerVersion()), - CRAFTBUKKIT_BLOCK("CRAFTBUKKIT_BLOCK", 2, PackageType.CRAFTBUKKIT, "block"), - CRAFTBUKKIT_CHUNKIO("CRAFTBUKKIT_CHUNKIO", 3, PackageType.CRAFTBUKKIT, "chunkio"), - CRAFTBUKKIT_COMMAND("CRAFTBUKKIT_COMMAND", 4, PackageType.CRAFTBUKKIT, "command"), - CRAFTBUKKIT_CONVERSATIONS("CRAFTBUKKIT_CONVERSATIONS", 5, PackageType.CRAFTBUKKIT, "conversations"), - CRAFTBUKKIT_ENCHANTMENS("CRAFTBUKKIT_ENCHANTMENS", 6, PackageType.CRAFTBUKKIT, "enchantments"), - CRAFTBUKKIT_ENTITY("CRAFTBUKKIT_ENTITY", 7, PackageType.CRAFTBUKKIT, "entity"), - CRAFTBUKKIT_EVENT("CRAFTBUKKIT_EVENT", 8, PackageType.CRAFTBUKKIT, "event"), - CRAFTBUKKIT_GENERATOR("CRAFTBUKKIT_GENERATOR", 9, PackageType.CRAFTBUKKIT, "generator"), - CRAFTBUKKIT_HELP("CRAFTBUKKIT_HELP", 10, PackageType.CRAFTBUKKIT, "help"), - CRAFTBUKKIT_INVENTORY("CRAFTBUKKIT_INVENTORY", 11, PackageType.CRAFTBUKKIT, "inventory"), - CRAFTBUKKIT_MAP("CRAFTBUKKIT_MAP", 12, PackageType.CRAFTBUKKIT, "map"), - CRAFTBUKKIT_METADATA("CRAFTBUKKIT_METADATA", 13, PackageType.CRAFTBUKKIT, "metadata"), - CRAFTBUKKIT_POTION("CRAFTBUKKIT_POTION", 14, PackageType.CRAFTBUKKIT, "potion"), - CRAFTBUKKIT_PROJECTILES("CRAFTBUKKIT_PROJECTILES", 15, PackageType.CRAFTBUKKIT, "projectiles"), - CRAFTBUKKIT_SCHEDULER("CRAFTBUKKIT_SCHEDULER", 16, PackageType.CRAFTBUKKIT, "scheduler"), - CRAFTBUKKIT_SCOREBOARD("CRAFTBUKKIT_SCOREBOARD", 17, PackageType.CRAFTBUKKIT, "scoreboard"), - CRAFTBUKKIT_UPDATER("CRAFTBUKKIT_UPDATER", 18, PackageType.CRAFTBUKKIT, "updater"), - CRAFTBUKKIT_UTIL("CRAFTBUKKIT_UTIL", 19, PackageType.CRAFTBUKKIT, "util"); - - private final String path; - - private PackageType(final String s, final int n, final String path) { - this.path = path; - } - - private PackageType(final String s, final int n, final PackageType packageType, final String s2) { - this(s, n, packageType + "." + s2); - } - - public String getPath() { - return this.path; - } - - public Class getClass(final String s) { - try { - return Class.forName(this + "." + s); - } catch (ClassNotFoundException e) { - return null; + + /** + * Returns the reference class of the data type with the given primitive class + * + * @param clazz Primitive class of the data type + * @return The reference class + */ + public static Class getReference(Class clazz) { + DataType type = fromClass(clazz); + return type == null ? clazz : type.getReference(); + } + + /** + * Returns the primitive class array of the given class array + * + * @param classes Given class array + * @return The primitive class array + */ + public static Class[] getPrimitive(Class[] classes) { + int length = classes == null ? 0 : classes.length; + Class[] types = new Class[length]; + for (int index = 0; index < length; index++) { + types[index] = getPrimitive(classes[index]); + } + return types; + } + + /** + * Returns the reference class array of the given class array + * + * @param classes Given class array + * @return The reference class array + */ + public static Class[] getReference(Class[] classes) { + int length = classes == null ? 0 : classes.length; + Class[] types = new Class[length]; + for (int index = 0; index < length; index++) { + types[index] = getReference(classes[index]); + } + return types; + } + + /** + * Returns the primitive class array of the given object array + * + * @param object Given object array + * @return The primitive class array + */ + public static Class[] getPrimitive(Object[] objects) { + int length = objects == null ? 0 : objects.length; + Class[] types = new Class[length]; + for (int index = 0; index < length; index++) { + types[index] = getPrimitive(objects[index].getClass()); } - } - - @Override - public String toString() { - return this.path; - } - - public static String getServerVersion() { - return Bukkit.getServer().getClass().getPackage().getName().substring(23); - } - } -} + return types; + } + + /** + * Returns the reference class array of the given object array + * + * @param object Given object array + * @return The reference class array + */ + public static Class[] getReference(Object[] objects) { + int length = objects == null ? 0 : objects.length; + Class[] types = new Class[length]; + for (int index = 0; index < length; index++) { + types[index] = getReference(objects[index].getClass()); + } + return types; + } + + /** + * Compares two class arrays on equivalence + * + * @param primary Primary class array + * @param secondary Class array which is compared to the primary array + * @return Whether these arrays are equal or not + */ + public static boolean compare(Class[] primary, Class[] secondary) { + if (primary == null || secondary == null || primary.length != secondary.length) { + return false; + } + for (int index = 0; index < primary.length; index++) { + Class primaryClass = primary[index]; + Class secondaryClass = secondary[index]; + if (primaryClass.equals(secondaryClass) || primaryClass.isAssignableFrom(secondaryClass)) { + continue; + } + return false; + } + return true; + } + } +} \ No newline at end of file diff --git a/src/main/src/me/skymc/taboolib/particle/EffLib.java b/src/main/src/me/skymc/taboolib/particle/EffLib.java index be6240035..4bc860642 100644 --- a/src/main/src/me/skymc/taboolib/particle/EffLib.java +++ b/src/main/src/me/skymc/taboolib/particle/EffLib.java @@ -1,12 +1,5 @@ package me.skymc.taboolib.particle; -import java.lang.reflect.Constructor; -import java.lang.reflect.Field; -import java.lang.reflect.Method; -import java.util.Arrays; -import java.util.HashMap; -import java.util.List; -import java.util.Map; import org.bukkit.Bukkit; import org.bukkit.Color; import org.bukkit.Location; @@ -15,560 +8,1333 @@ import org.bukkit.util.Vector; import me.skymc.taboolib.methods.ReflectionUtils; +import me.skymc.taboolib.methods.ReflectionUtils.PackageType; + +import java.lang.reflect.Constructor; +import java.lang.reflect.Field; +import java.lang.reflect.Method; +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; /** - * Ŀ ParticleEffect + * ParticleEffect Library + *

+ * This library was created by @DarkBlade12 and allows you to display all Minecraft particle effects on a Bukkit server + *

+ * You are welcome to use it, modify it and redistribute it under the following conditions: + *

+ *

+ * Special thanks: + *

+ *

+ * It would be nice if you provide credit to me if you use this class in a published project + * + * @author DarkBlade12 + * @version 1.7 */ public enum EffLib { - - EXPLOSION_NORMAL("explode", 0, -1, new ParticleProperty[] { ParticleProperty.DIRECTIONAL }), + + /** + * A particle effect which is displayed by exploding tnt and creepers: + *

+ */ + EXPLOSION_NORMAL("explode", 0, -1, ParticleProperty.DIRECTIONAL), + /** + * A particle effect which is displayed by exploding ghast fireballs and wither skulls: + * + */ + EXPLOSION_LARGE("largeexplode", 1, -1), + /** + * A particle effect which is displayed by exploding tnt and creepers: + * + */ + EXPLOSION_HUGE("hugeexplosion", 2, -1), + /** + * A particle effect which is displayed by launching fireworks: + * + */ + FIREWORKS_SPARK("fireworksSpark", 3, -1, ParticleProperty.DIRECTIONAL), + /** + * A particle effect which is displayed by swimming entities and arrows in water: + * + */ + WATER_BUBBLE("bubble", 4, -1, ParticleProperty.DIRECTIONAL, ParticleProperty.REQUIRES_WATER), + /** + * A particle effect which is displayed by swimming entities and shaking wolves: + * + */ + WATER_SPLASH("splash", 5, -1, ParticleProperty.DIRECTIONAL), + /** + * A particle effect which is displayed on water when fishing: + * + */ + WATER_WAKE("wake", 6, 7, ParticleProperty.DIRECTIONAL), + /** + * A particle effect which is displayed by water: + * + */ + SUSPENDED("suspended", 7, -1, ParticleProperty.REQUIRES_WATER), + /** + * A particle effect which is displayed by air when close to bedrock and the in the void: + * + */ + SUSPENDED_DEPTH("depthSuspend", 8, -1, ParticleProperty.DIRECTIONAL), + /** + * A particle effect which is displayed when landing a critical hit and by arrows: + * + */ + CRIT("crit", 9, -1, ParticleProperty.DIRECTIONAL), + /** + * A particle effect which is displayed when landing a hit with an enchanted weapon: + * + */ + CRIT_MAGIC("magicCrit", 10, -1, ParticleProperty.DIRECTIONAL), + /** + * A particle effect which is displayed by primed tnt, torches, droppers, dispensers, end portals, brewing stands and monster spawners: + * + */ + SMOKE_NORMAL("smoke", 11, -1, ParticleProperty.DIRECTIONAL), + /** + * A particle effect which is displayed by fire, minecarts with furnace and blazes: + * + */ + SMOKE_LARGE("largesmoke", 12, -1, ParticleProperty.DIRECTIONAL), + /** + * A particle effect which is displayed when splash potions or bottles o' enchanting hit something: + * + */ + SPELL("spell", 13, -1), + /** + * A particle effect which is displayed when instant splash potions hit something: + * + */ + SPELL_INSTANT("instantSpell", 14, -1), + /** + * A particle effect which is displayed by entities with active potion effects: + * + */ + SPELL_MOB("mobSpell", 15, -1, ParticleProperty.COLORABLE), + /** + * A particle effect which is displayed by entities with active potion effects applied through a beacon: + * + */ + SPELL_MOB_AMBIENT("mobSpellAmbient", 16, -1, ParticleProperty.COLORABLE), + /** + * A particle effect which is displayed by witches: + * + */ + SPELL_WITCH("witchMagic", 17, -1), + /** + * A particle effect which is displayed by blocks beneath a water source: + * + */ + DRIP_WATER("dripWater", 18, -1), + /** + * A particle effect which is displayed by blocks beneath a lava source: + * + */ + DRIP_LAVA("dripLava", 19, -1), + /** + * A particle effect which is displayed when attacking a villager in a village: + * + */ + VILLAGER_ANGRY("angryVillager", 20, -1), + /** + * A particle effect which is displayed when using bone meal and trading with a villager in a village: + * + */ + VILLAGER_HAPPY("happyVillager", 21, -1, ParticleProperty.DIRECTIONAL), + /** + * A particle effect which is displayed by mycelium: + * + */ + TOWN_AURA("townaura", 22, -1, ParticleProperty.DIRECTIONAL), + /** + * A particle effect which is displayed by note blocks: + * + */ + NOTE("note", 23, -1, ParticleProperty.COLORABLE), + /** + * A particle effect which is displayed by nether portals, endermen, ender pearls, eyes of ender, ender chests and dragon eggs: + * + */ + PORTAL("portal", 24, -1, ParticleProperty.DIRECTIONAL), + /** + * A particle effect which is displayed by enchantment tables which are nearby bookshelves: + * + */ + ENCHANTMENT_TABLE("enchantmenttable", 25, -1, ParticleProperty.DIRECTIONAL), + /** + * A particle effect which is displayed by torches, active furnaces, magma cubes and monster spawners: + * + */ + FLAME("flame", 26, -1, ParticleProperty.DIRECTIONAL), + /** + * A particle effect which is displayed by lava: + * + */ + LAVA("lava", 27, -1), + /** + * A particle effect which is currently unused: + * + */ + FOOTSTEP("footstep", 28, -1), + /** + * A particle effect which is displayed when a mob dies: + * + */ + CLOUD("cloud", 29, -1, ParticleProperty.DIRECTIONAL), + /** + * A particle effect which is displayed by redstone ore, powered redstone, redstone torches and redstone repeaters: + * + */ + REDSTONE("reddust", 30, -1, ParticleProperty.COLORABLE), + /** + * A particle effect which is displayed when snowballs hit a block: + * + */ + SNOWBALL("snowballpoof", 31, -1), + /** + * A particle effect which is currently unused: + * + */ + SNOW_SHOVEL("snowshovel", 32, -1, ParticleProperty.DIRECTIONAL), + /** + * A particle effect which is displayed by slimes: + * + */ + SLIME("slime", 33, -1), + /** + * A particle effect which is displayed when breeding and taming animals: + * + */ + HEART("heart", 34, -1), + /** + * A particle effect which is displayed by barriers: + * + */ + BARRIER("barrier", 35, 8), + /** + * A particle effect which is displayed when breaking a tool or eggs hit a block: + * + */ + ITEM_CRACK("iconcrack", 36, -1, ParticleProperty.DIRECTIONAL, ParticleProperty.REQUIRES_DATA), + /** + * A particle effect which is displayed when breaking blocks or sprinting: + * + */ + BLOCK_CRACK("blockcrack", 37, -1, ParticleProperty.REQUIRES_DATA), + /** + * A particle effect which is displayed when falling: + * + */ + BLOCK_DUST("blockdust", 38, 7, ParticleProperty.DIRECTIONAL, ParticleProperty.REQUIRES_DATA), + /** + * A particle effect which is displayed when rain hits the ground: + * + */ + WATER_DROP("droplet", 39, 8), + /** + * A particle effect which is currently unused: + * + */ + ITEM_TAKE("take", 40, 8), + /** + * A particle effect which is displayed by elder guardians: + * + */ + MOB_APPEARANCE("mobappearance", 41, 8), + + /** + * Ϣ + */ + DRAGON_BREATH("dragonbreath", 42, 9, new ParticleProperty[0]), + + /** + * ĩ + */ + END_ROD("endrod", 43, 9, new ParticleProperty[0]), + + /** + * ˺ + */ + DAMAGE_INDICATOR("damageIndicator", 44, 9, new ParticleProperty[0]), + + /** + * ӿ + */ + SWEEP_ATTACK("sweepAttack", 45, 9, new ParticleProperty[0]); - EXPLOSION_LARGE("largeexplode", 1, -1, new ParticleProperty[0]), + private static final Map NAME_MAP = new HashMap(); + private static final Map ID_MAP = new HashMap(); + private final String name; + private final int id; + private final int requiredVersion; + private final List properties; - EXPLOSION_HUGE("hugeexplosion", 2, -1, new ParticleProperty[0]), + // Initialize map for quick name and id lookup + static { + for (EffLib effect : values()) { + NAME_MAP.put(effect.name, effect); + ID_MAP.put(effect.id, effect); + } + } - FIREWORKS_SPARK("fireworksSpark", 3, -1, new ParticleProperty[] { ParticleProperty.DIRECTIONAL }), - - WATER_BUBBLE("bubble", 4, -1, new ParticleProperty[] { ParticleProperty.DIRECTIONAL, ParticleProperty.REQUIRES_WATER }), + /** + * Construct a new particle effect + * + * @param name Name of this particle effect + * @param id Id of this particle effect + * @param requiredVersion Version which is required (1.x) + * @param properties Properties of this particle effect + */ + private EffLib(String name, int id, int requiredVersion, ParticleProperty... properties) { + this.name = name; + this.id = id; + this.requiredVersion = requiredVersion; + this.properties = Arrays.asList(properties); + } - WATER_SPLASH("splash", 5, -1, new ParticleProperty[] { ParticleProperty.DIRECTIONAL }), - - WATER_WAKE("wake", 6, 7, new ParticleProperty[] { ParticleProperty.DIRECTIONAL }), + /** + * Returns the name of this particle effect + * + * @return The name + */ + public String getName() { + return name; + } - SUSPENDED("suspended", 7, -1, new ParticleProperty[] { ParticleProperty.REQUIRES_WATER }), - - SUSPENDED_DEPTH("depthSuspend", 8, -1, new ParticleProperty[] { ParticleProperty.DIRECTIONAL }), + /** + * Returns the id of this particle effect + * + * @return The id + */ + public int getId() { + return id; + } - CRIT("crit", 9, -1, new ParticleProperty[] { ParticleProperty.DIRECTIONAL }), + /** + * Returns the required version for this particle effect (1.x) + * + * @return The required version + */ + public int getRequiredVersion() { + return requiredVersion; + } - CRIT_MAGIC("magicCrit", 10, -1, new ParticleProperty[] { ParticleProperty.DIRECTIONAL }), + /** + * Determine if this particle effect has a specific property + * + * @return Whether it has the property or not + */ + public boolean hasProperty(ParticleProperty property) { + return properties.contains(property); + } - SMOKE_NORMAL("smoke", 11, -1, new ParticleProperty[] { ParticleProperty.DIRECTIONAL }), + /** + * Determine if this particle effect is supported by your current server version + * + * @return Whether the particle effect is supported or not + */ + public boolean isSupported() { + if (requiredVersion == -1) { + return true; + } + return ParticlePacket.getVersion() >= requiredVersion; + } - SMOKE_LARGE("largesmoke", 12, -1, new ParticleProperty[] { ParticleProperty.DIRECTIONAL }), + /** + * Returns the particle effect with the given name + * + * @param name Name of the particle effect + * @return The particle effect + */ + public static EffLib fromName(String name) { + for (Entry entry : NAME_MAP.entrySet()) { + if (!entry.getKey().equalsIgnoreCase(name)) { + continue; + } + return entry.getValue(); + } + return null; + } - SPELL("spell", 13, -1, new ParticleProperty[0]), + /** + * Returns the particle effect with the given id + * + * @param id Id of the particle effect + * @return The particle effect + */ + public static EffLib fromId(int id) { + for (Entry entry : ID_MAP.entrySet()) { + if (entry.getKey() != id) { + continue; + } + return entry.getValue(); + } + return null; + } - SPELL_INSTANT("instantSpell", 14, -1, new ParticleProperty[0]), + /** + * Determine if water is at a certain location + * + * @param location Location to check + * @return Whether water is at this location or not + */ + private static boolean isWater(Location location) { + Material material = location.getBlock().getType(); + return material == Material.WATER || material == Material.STATIONARY_WATER; + } - SPELL_MOB("mobSpell", 15, -1, new ParticleProperty[] { ParticleProperty.COLORABLE }), + /** + * Determine if the distance between @param location and one of the players exceeds 256 + * + * @param location Location to check + * @return Whether the distance exceeds 256 or not + */ + private static boolean isLongDistance(Location location, List players) { + String world = location.getWorld().getName(); + for (Player player : players) { + Location playerLocation = player.getLocation(); + if (!world.equals(playerLocation.getWorld().getName()) || playerLocation.distanceSquared(location) < 65536) { + continue; + } + return true; + } + return false; + } - SPELL_MOB_AMBIENT("mobSpellAmbient", 16, -1, new ParticleProperty[] { ParticleProperty.COLORABLE }), + /** + * Determine if the data type for a particle effect is correct + * + * @param effect Particle effect + * @param data Particle data + * @return Whether the data type is correct or not + */ + private static boolean isDataCorrect(EffLib effect, ParticleData data) { + return ((effect == BLOCK_CRACK || effect == BLOCK_DUST) && data instanceof BlockData) || (effect == ITEM_CRACK && data instanceof ItemData); + } - SPELL_WITCH("witchMagic", 17, -1, new ParticleProperty[0]), + /** + * Determine if the color type for a particle effect is correct + * + * @param effect Particle effect + * @param color Particle color + * @return Whether the color type is correct or not + */ + private static boolean isColorCorrect(EffLib effect, ParticleColor color) { + return ((effect == SPELL_MOB || effect == SPELL_MOB_AMBIENT || effect == REDSTONE) && color instanceof OrdinaryColor) || (effect == NOTE && color instanceof NoteColor); + } - DRIP_WATER("dripWater", 18, -1, new ParticleProperty[0]), + /** + * Displays a particle effect which is only visible for all players within a certain range in the world of @param center + * + * @param offsetX Maximum distance particles can fly away from the center on the x-axis + * @param offsetY Maximum distance particles can fly away from the center on the y-axis + * @param offsetZ Maximum distance particles can fly away from the center on the z-axis + * @param speed Display speed of the particles + * @param amount Amount of particles + * @param center Center location of the effect + * @param range Range of the visibility + * @throws ParticleVersionException If the particle effect is not supported by the server version + * @throws ParticleDataException If the particle effect requires additional data + * @throws IllegalArgumentException If the particle effect requires water and none is at the center location + * @see ParticlePacket + * @see ParticlePacket#sendTo(Location, double) + */ + public void display(float offsetX, float offsetY, float offsetZ, float speed, int amount, Location center, double range) throws ParticleVersionException, ParticleDataException, IllegalArgumentException { + if (!isSupported()) { + throw new ParticleVersionException("This particle effect is not supported by your server version"); + } + if (hasProperty(ParticleProperty.REQUIRES_DATA)) { + throw new ParticleDataException("This particle effect requires additional data"); + } + if (hasProperty(ParticleProperty.REQUIRES_WATER) && !isWater(center)) { + throw new IllegalArgumentException("There is no water at the center location"); + } + new ParticlePacket(this, offsetX, offsetY, offsetZ, speed, amount, range > 256, null).sendTo(center, range); + } - DRIP_LAVA("dripLava", 19, -1, new ParticleProperty[0]), + /** + * Displays a particle effect which is only visible for the specified players + * + * @param offsetX Maximum distance particles can fly away from the center on the x-axis + * @param offsetY Maximum distance particles can fly away from the center on the y-axis + * @param offsetZ Maximum distance particles can fly away from the center on the z-axis + * @param speed Display speed of the particles + * @param amount Amount of particles + * @param center Center location of the effect + * @param players Receivers of the effect + * @throws ParticleVersionException If the particle effect is not supported by the server version + * @throws ParticleDataException If the particle effect requires additional data + * @throws IllegalArgumentException If the particle effect requires water and none is at the center location + * @see ParticlePacket + * @see ParticlePacket#sendTo(Location, List) + */ + public void display(float offsetX, float offsetY, float offsetZ, float speed, int amount, Location center, List players) throws ParticleVersionException, ParticleDataException, IllegalArgumentException { + if (!isSupported()) { + throw new ParticleVersionException("This particle effect is not supported by your server version"); + } + if (hasProperty(ParticleProperty.REQUIRES_DATA)) { + throw new ParticleDataException("This particle effect requires additional data"); + } + if (hasProperty(ParticleProperty.REQUIRES_WATER) && !isWater(center)) { + throw new IllegalArgumentException("There is no water at the center location"); + } + new ParticlePacket(this, offsetX, offsetY, offsetZ, speed, amount, isLongDistance(center, players), null).sendTo(center, players); + } - VILLAGER_ANGRY("angryVillager", 20, -1, new ParticleProperty[0]), + /** + * Displays a particle effect which is only visible for the specified players + * + * @param offsetX Maximum distance particles can fly away from the center on the x-axis + * @param offsetY Maximum distance particles can fly away from the center on the y-axis + * @param offsetZ Maximum distance particles can fly away from the center on the z-axis + * @param speed Display speed of the particles + * @param amount Amount of particles + * @param center Center location of the effect + * @param players Receivers of the effect + * @throws ParticleVersionException If the particle effect is not supported by the server version + * @throws ParticleDataException If the particle effect requires additional data + * @throws IllegalArgumentException If the particle effect requires water and none is at the center location + * @see #display(float, float, float, float, int, Location, List) + */ + public void display(float offsetX, float offsetY, float offsetZ, float speed, int amount, Location center, Player... players) throws ParticleVersionException, ParticleDataException, IllegalArgumentException { + display(offsetX, offsetY, offsetZ, speed, amount, center, Arrays.asList(players)); + } - VILLAGER_HAPPY("happyVillager", 21, -1, new ParticleProperty[] { ParticleProperty.DIRECTIONAL }), + /** + * Displays a single particle which flies into a determined direction and is only visible for all players within a certain range in the world of @param center + * + * @param direction Direction of the particle + * @param speed Display speed of the particle + * @param center Center location of the effect + * @param range Range of the visibility + * @throws ParticleVersionException If the particle effect is not supported by the server version + * @throws ParticleDataException If the particle effect requires additional data + * @throws IllegalArgumentException If the particle effect is not directional or if it requires water and none is at the center location + * @see ParticlePacket#ParticlePacket(EffLib, Vector, float, boolean, ParticleData) + * @see ParticlePacket#sendTo(Location, double) + */ + public void display(Vector direction, float speed, Location center, double range) throws ParticleVersionException, ParticleDataException, IllegalArgumentException { + if (!isSupported()) { + throw new ParticleVersionException("This particle effect is not supported by your server version"); + } + if (hasProperty(ParticleProperty.REQUIRES_DATA)) { + throw new ParticleDataException("This particle effect requires additional data"); + } + if (!hasProperty(ParticleProperty.DIRECTIONAL)) { + throw new IllegalArgumentException("This particle effect is not directional"); + } + if (hasProperty(ParticleProperty.REQUIRES_WATER) && !isWater(center)) { + throw new IllegalArgumentException("There is no water at the center location"); + } + new ParticlePacket(this, direction, speed, range > 256, null).sendTo(center, range); + } - TOWN_AURA("townaura", 22, -1, new ParticleProperty[] { ParticleProperty.DIRECTIONAL }), + /** + * Displays a single particle which flies into a determined direction and is only visible for the specified players + * + * @param direction Direction of the particle + * @param speed Display speed of the particle + * @param center Center location of the effect + * @param players Receivers of the effect + * @throws ParticleVersionException If the particle effect is not supported by the server version + * @throws ParticleDataException If the particle effect requires additional data + * @throws IllegalArgumentException If the particle effect is not directional or if it requires water and none is at the center location + * @see ParticlePacket#ParticlePacket(EffLib, Vector, float, boolean, ParticleData) + * @see ParticlePacket#sendTo(Location, List) + */ + public void display(Vector direction, float speed, Location center, List players) throws ParticleVersionException, ParticleDataException, IllegalArgumentException { + if (!isSupported()) { + throw new ParticleVersionException("This particle effect is not supported by your server version"); + } + if (hasProperty(ParticleProperty.REQUIRES_DATA)) { + throw new ParticleDataException("This particle effect requires additional data"); + } + if (!hasProperty(ParticleProperty.DIRECTIONAL)) { + throw new IllegalArgumentException("This particle effect is not directional"); + } + if (hasProperty(ParticleProperty.REQUIRES_WATER) && !isWater(center)) { + throw new IllegalArgumentException("There is no water at the center location"); + } + new ParticlePacket(this, direction, speed, isLongDistance(center, players), null).sendTo(center, players); + } - NOTE("note", 23, -1, new ParticleProperty[] { ParticleProperty.COLORABLE }), - - PORTAL("portal", 24, -1, new ParticleProperty[] { ParticleProperty.DIRECTIONAL }), - - ENCHANTMENT_TABLE("enchantmenttable", 25, -1, new ParticleProperty[] { ParticleProperty.DIRECTIONAL }), - - FLAME("flame", 26, -1, new ParticleProperty[] { ParticleProperty.DIRECTIONAL }), - - LAVA("lava", 27, -1, new ParticleProperty[0]), - - FOOTSTEP("footstep", 28, -1, new ParticleProperty[0]), - - CLOUD("cloud", 29, -1, new ParticleProperty[] { ParticleProperty.DIRECTIONAL }), - - REDSTONE("reddust", 30, -1, new ParticleProperty[] { ParticleProperty.COLORABLE }), - - SNOWBALL( "snowballpoof", 31, -1, new ParticleProperty[0]), - - SNOW_SHOVEL( "snowshovel", 32, -1, new ParticleProperty[] { ParticleProperty.DIRECTIONAL }), - - SLIME("slime", 33, -1, new ParticleProperty[0]), - - HEART("heart", 34, -1, new ParticleProperty[0]), - - BARRIER("barrier", 35, 8, new ParticleProperty[0]), - - ITEM_CRACK("iconcrack", 36, -1, new ParticleProperty[] { ParticleProperty.DIRECTIONAL, ParticleProperty.REQUIRES_DATA }), - - BLOCK_CRACK("blockcrack", 37, -1, new ParticleProperty[] { ParticleProperty.REQUIRES_DATA }), - - BLOCK_DUST("blockdust", 38, 7, new ParticleProperty[] { ParticleProperty.DIRECTIONAL, ParticleProperty.REQUIRES_DATA }), - - WATER_DROP("droplet", 39, 8, new ParticleProperty[0]), - - ITEM_TAKE("take", 40, 8, new ParticleProperty[0]), - - MOB_APPEARANCE("mobappearance", 41, 8, new ParticleProperty[0]), - - DRAGON_BREATH("dragonbreath", 42, -1, new ParticleProperty[0]), - - END_ROD("endrod", 43, -1, new ParticleProperty[0]), - - DAMAGE_INDICATOR("damageIndicator", 44, -1, new ParticleProperty[0]), - - SWEEP_ATTACK("sweepAttack", 45, 8, new ParticleProperty[0]); - - private static final Map NAME_MAP; - private static final Map ID_MAP; - private final String name; - private final int id; - private final int requiredVersion; - private final List properties; - - static - { - NAME_MAP = new HashMap<>(); - ID_MAP = new HashMap<>(); - for (EffLib localEff : values()) - { - NAME_MAP.put(localEff.name, localEff); - ID_MAP.put(Integer.valueOf(localEff.id), localEff); - } - } - - private EffLib(String paramString, int paramInt1, int paramInt2, ParticleProperty... paramVarArgs) - { - this.name = paramString; - this.id = paramInt1; - this.requiredVersion = paramInt2; - this.properties = Arrays.asList(paramVarArgs); - } - - public String getName() - { - return this.name; - } - - public int getId() - { - return this.id; - } - - public int getRequiredVersion() - { - return this.requiredVersion; - } - - public boolean hasProperty(ParticleProperty paramParticleProperty) - { - return this.properties.contains(paramParticleProperty); - } - - public boolean isSupported() - { - if (this.requiredVersion == -1) { - return true; + /** + * Displays a single particle which flies into a determined direction and is only visible for the specified players + * + * @param direction Direction of the particle + * @param speed Display speed of the particle + * @param center Center location of the effect + * @param players Receivers of the effect + * @throws ParticleVersionException If the particle effect is not supported by the server version + * @throws ParticleDataException If the particle effect requires additional data + * @throws IllegalArgumentException If the particle effect is not directional or if it requires water and none is at the center location + * @see #display(Vector, float, Location, List) + */ + public void display(Vector direction, float speed, Location center, Player... players) throws ParticleVersionException, ParticleDataException, IllegalArgumentException { + display(direction, speed, center, Arrays.asList(players)); + } + + /** + * Displays a single particle which is colored and only visible for all players within a certain range in the world of @param center + * + * @param color Color of the particle + * @param center Center location of the effect + * @param range Range of the visibility + * @throws ParticleVersionException If the particle effect is not supported by the server version + * @throws ParticleColorException If the particle effect is not colorable or the color type is incorrect + * @see ParticlePacket#ParticlePacket(EffLib, ParticleColor, boolean) + * @see ParticlePacket#sendTo(Location, double) + */ + public void display(ParticleColor color, Location center, double range) throws ParticleVersionException, ParticleColorException { + if (!isSupported()) { + throw new ParticleVersionException("This particle effect is not supported by your server version"); + } + if (!hasProperty(ParticleProperty.COLORABLE)) { + throw new ParticleColorException("This particle effect is not colorable"); } - return ParticlePacket.getVersion() >= this.requiredVersion; + if (!isColorCorrect(this, color)) { + throw new ParticleColorException("The particle color type is incorrect"); + } + new ParticlePacket(this, color, range > 256).sendTo(center, range); } - - public static EffLib fromName(String paramString) - { - for (Map.Entry localEntry : NAME_MAP.entrySet()) { - if (((String)localEntry.getKey()).equalsIgnoreCase(paramString)) { - return (EffLib)localEntry.getValue(); - } + + /** + * Displays a single particle which is colored and only visible for the specified players + * + * @param color Color of the particle + * @param center Center location of the effect + * @param players Receivers of the effect + * @throws ParticleVersionException If the particle effect is not supported by the server version + * @throws ParticleColorException If the particle effect is not colorable or the color type is incorrect + * @see ParticlePacket#ParticlePacket(EffLib, ParticleColor, boolean) + * @see ParticlePacket#sendTo(Location, List) + */ + public void display(ParticleColor color, Location center, List players) throws ParticleVersionException, ParticleColorException { + if (!isSupported()) { + throw new ParticleVersionException("This particle effect is not supported by your server version"); } - return null; + if (!hasProperty(ParticleProperty.COLORABLE)) { + throw new ParticleColorException("This particle effect is not colorable"); + } + if (!isColorCorrect(this, color)) { + throw new ParticleColorException("The particle color type is incorrect"); + } + new ParticlePacket(this, color, isLongDistance(center, players)).sendTo(center, players); } - - public static EffLib fromId(int paramInt) - { - for (Map.Entry localEntry : ID_MAP.entrySet()) { - if (((Integer)localEntry.getKey()).intValue() == paramInt) { - return (EffLib)localEntry.getValue(); - } + + /** + * Displays a single particle which is colored and only visible for the specified players + * + * @param color Color of the particle + * @param center Center location of the effect + * @param players Receivers of the effect + * @throws ParticleVersionException If the particle effect is not supported by the server version + * @throws ParticleColorException If the particle effect is not colorable or the color type is incorrect + * @see #display(ParticleColor, Location, List) + */ + public void display(ParticleColor color, Location center, Player... players) throws ParticleVersionException, ParticleColorException { + display(color, center, Arrays.asList(players)); + } + + /** + * Displays a particle effect which requires additional data and is only visible for all players within a certain range in the world of @param center + * + * @param data Data of the effect + * @param offsetX Maximum distance particles can fly away from the center on the x-axis + * @param offsetY Maximum distance particles can fly away from the center on the y-axis + * @param offsetZ Maximum distance particles can fly away from the center on the z-axis + * @param speed Display speed of the particles + * @param amount Amount of particles + * @param center Center location of the effect + * @param range Range of the visibility + * @throws ParticleVersionException If the particle effect is not supported by the server version + * @throws ParticleDataException If the particle effect does not require additional data or if the data type is incorrect + * @see ParticlePacket + * @see ParticlePacket#sendTo(Location, double) + */ + public void display(ParticleData data, float offsetX, float offsetY, float offsetZ, float speed, int amount, Location center, double range) throws ParticleVersionException, ParticleDataException { + if (!isSupported()) { + throw new ParticleVersionException("This particle effect is not supported by your server version"); } - return null; + if (!hasProperty(ParticleProperty.REQUIRES_DATA)) { + throw new ParticleDataException("This particle effect does not require additional data"); + } + if (!isDataCorrect(this, data)) { + throw new ParticleDataException("The particle data type is incorrect"); + } + new ParticlePacket(this, offsetX, offsetY, offsetZ, speed, amount, range > 256, data).sendTo(center, range); } - - private static boolean isWater(Location paramLocation) - { - Material localMaterial = paramLocation.getBlock().getType(); - return (localMaterial == Material.WATER) || (localMaterial == Material.STATIONARY_WATER); - } - - private static boolean isLongDistance(Location paramLocation, List paramList) - { - String str = paramLocation.getWorld().getName(); - for (Player localPlayer : paramList) - { - Location localLocation = localPlayer.getLocation(); - if ((str.equals(localLocation.getWorld().getName())) && (localLocation.distanceSquared(paramLocation) >= 65536.0D)) { - return true; - } + + /** + * Displays a particle effect which requires additional data and is only visible for the specified players + * + * @param data Data of the effect + * @param offsetX Maximum distance particles can fly away from the center on the x-axis + * @param offsetY Maximum distance particles can fly away from the center on the y-axis + * @param offsetZ Maximum distance particles can fly away from the center on the z-axis + * @param speed Display speed of the particles + * @param amount Amount of particles + * @param center Center location of the effect + * @param players Receivers of the effect + * @throws ParticleVersionException If the particle effect is not supported by the server version + * @throws ParticleDataException If the particle effect does not require additional data or if the data type is incorrect + * @see ParticlePacket + * @see ParticlePacket#sendTo(Location, List) + */ + public void display(ParticleData data, float offsetX, float offsetY, float offsetZ, float speed, int amount, Location center, List players) throws ParticleVersionException, ParticleDataException { + if (!isSupported()) { + throw new ParticleVersionException("This particle effect is not supported by your server version"); } - return false; + if (!hasProperty(ParticleProperty.REQUIRES_DATA)) { + throw new ParticleDataException("This particle effect does not require additional data"); + } + if (!isDataCorrect(this, data)) { + throw new ParticleDataException("The particle data type is incorrect"); + } + new ParticlePacket(this, offsetX, offsetY, offsetZ, speed, amount, isLongDistance(center, players), data).sendTo(center, players); } - - private static boolean isDataCorrect(EffLib paramEff, ParticleData paramParticleData) - { - return ((paramEff == BLOCK_CRACK) || (paramEff == BLOCK_DUST)) && (((paramParticleData instanceof BlockData)) || ((paramEff == ITEM_CRACK) && ((paramParticleData instanceof ItemData)))); + + /** + * Displays a particle effect which requires additional data and is only visible for the specified players + * + * @param data Data of the effect + * @param offsetX Maximum distance particles can fly away from the center on the x-axis + * @param offsetY Maximum distance particles can fly away from the center on the y-axis + * @param offsetZ Maximum distance particles can fly away from the center on the z-axis + * @param speed Display speed of the particles + * @param amount Amount of particles + * @param center Center location of the effect + * @param players Receivers of the effect + * @throws ParticleVersionException If the particle effect is not supported by the server version + * @throws ParticleDataException If the particle effect does not require additional data or if the data type is incorrect + * @see #display(ParticleData, float, float, float, float, int, Location, List) + */ + public void display(ParticleData data, float offsetX, float offsetY, float offsetZ, float speed, int amount, Location center, Player... players) throws ParticleVersionException, ParticleDataException { + display(data, offsetX, offsetY, offsetZ, speed, amount, center, Arrays.asList(players)); } - - private static boolean isColorCorrect(EffLib paramEff, ParticleColor paramParticleColor) - { - return ((paramEff == SPELL_MOB) || (paramEff == SPELL_MOB_AMBIENT) || (paramEff == REDSTONE)) && (((paramParticleColor instanceof OrdinaryColor)) || ((paramEff == NOTE) && ((paramParticleColor instanceof NoteColor)))); + + /** + * Displays a single particle which requires additional data that flies into a determined direction and is only visible for all players within a certain range in the world of @param center + * + * @param data Data of the effect + * @param direction Direction of the particle + * @param speed Display speed of the particles + * @param center Center location of the effect + * @param range Range of the visibility + * @throws ParticleVersionException If the particle effect is not supported by the server version + * @throws ParticleDataException If the particle effect does not require additional data or if the data type is incorrect + * @see ParticlePacket + * @see ParticlePacket#sendTo(Location, double) + */ + public void display(ParticleData data, Vector direction, float speed, Location center, double range) throws ParticleVersionException, ParticleDataException { + if (!isSupported()) { + throw new ParticleVersionException("This particle effect is not supported by your server version"); + } + if (!hasProperty(ParticleProperty.REQUIRES_DATA)) { + throw new ParticleDataException("This particle effect does not require additional data"); + } + if (!isDataCorrect(this, data)) { + throw new ParticleDataException("The particle data type is incorrect"); + } + new ParticlePacket(this, direction, speed, range > 256, data).sendTo(center, range); } - - public void display(float paramFloat1, float paramFloat2, float paramFloat3, float paramFloat4, int paramInt, Location paramLocation, double paramDouble) - { + + /** + * Displays a single particle which requires additional data that flies into a determined direction and is only visible for the specified players + * + * @param data Data of the effect + * @param direction Direction of the particle + * @param speed Display speed of the particles + * @param center Center location of the effect + * @param players Receivers of the effect + * @throws ParticleVersionException If the particle effect is not supported by the server version + * @throws ParticleDataException If the particle effect does not require additional data or if the data type is incorrect + * @see ParticlePacket + * @see ParticlePacket#sendTo(Location, List) + */ + public void display(ParticleData data, Vector direction, float speed, Location center, List players) throws ParticleVersionException, ParticleDataException { if (!isSupported()) { throw new ParticleVersionException("This particle effect is not supported by your server version"); } - if (hasProperty(ParticleProperty.REQUIRES_DATA)) { - throw new ParticleDataException("This particle effect requires additional data"); + if (!hasProperty(ParticleProperty.REQUIRES_DATA)) { + throw new ParticleDataException("This particle effect does not require additional data"); } - if ((hasProperty(ParticleProperty.REQUIRES_WATER)) && (!isWater(paramLocation))) { - throw new IllegalArgumentException("There is no water at the center location"); + if (!isDataCorrect(this, data)) { + throw new ParticleDataException("The particle data type is incorrect"); } - new ParticlePacket(this, paramFloat1, paramFloat2, paramFloat3, paramFloat4, paramInt, paramDouble > 256.0D, null).sendTo(paramLocation, paramDouble); - } - - public void display(final float paramFloat1, final float paramFloat2, final float paramFloat3, final float paramFloat4, final int paramInt, final Location paramLocation, final List paramList) { - if (!this.isSupported()) { - throw new ParticleVersionException("This particle effect is not supported by your server version"); - } - if (this.hasProperty(ParticleProperty.REQUIRES_DATA)) { - throw new ParticleDataException("This particle effect requires additional data"); - } - if (this.hasProperty(ParticleProperty.REQUIRES_WATER) && !isWater(paramLocation)) { - throw new IllegalArgumentException("There is no water at the center location"); - } - new ParticlePacket(this, paramFloat1, paramFloat2, paramFloat3, paramFloat4, paramInt, isLongDistance(paramLocation, paramList), null).sendTo(paramLocation, paramList); - } - - public void display(final float paramFloat1, final float paramFloat2, final float paramFloat3, final float paramFloat4, final int paramInt, final Location paramLocation, final Player... paramVarArgs) { - this.display(paramFloat1, paramFloat2, paramFloat3, paramFloat4, paramInt, paramLocation, Arrays.asList(paramVarArgs)); - } - - public void display(final Vector paramVector, final float paramFloat, final Location paramLocation, final double paramDouble) { - if (!this.isSupported()) { - throw new ParticleVersionException("This particle effect is not supported by your server version"); - } - if (this.hasProperty(ParticleProperty.REQUIRES_DATA)) { - throw new ParticleDataException("This particle effect requires additional data"); - } - if (!this.hasProperty(ParticleProperty.DIRECTIONAL)) { - throw new IllegalArgumentException("This particle effect is not directional"); - } - if (this.hasProperty(ParticleProperty.REQUIRES_WATER) && !isWater(paramLocation)) { - throw new IllegalArgumentException("There is no water at the center location"); - } - new ParticlePacket(this, paramVector, paramFloat, paramDouble > 256.0, null).sendTo(paramLocation, paramDouble); - } - - public void display(final Vector paramVector, final float paramFloat, final Location paramLocation, final List paramList) { - if (!this.isSupported()) { - throw new ParticleVersionException("This particle effect is not supported by your server version"); - } - if (this.hasProperty(ParticleProperty.REQUIRES_DATA)) { - throw new ParticleDataException("This particle effect requires additional data"); - } - if (!this.hasProperty(ParticleProperty.DIRECTIONAL)) { - throw new IllegalArgumentException("This particle effect is not directional"); - } - if (this.hasProperty(ParticleProperty.REQUIRES_WATER) && !isWater(paramLocation)) { - throw new IllegalArgumentException("There is no water at the center location"); - } - new ParticlePacket(this, paramVector, paramFloat, isLongDistance(paramLocation, paramList), null).sendTo(paramLocation, paramList); - } - - public void display(final Vector paramVector, final float paramFloat, final Location paramLocation, final Player... paramVarArgs) { - this.display(paramVector, paramFloat, paramLocation, Arrays.asList(paramVarArgs)); - } - - public void display(final ParticleColor paramParticleColor, final Location paramLocation, final double paramDouble) { - if (!this.isSupported()) { - throw new ParticleVersionException("This particle effect is not supported by your server version"); - } - if (!this.hasProperty(ParticleProperty.COLORABLE)) { - throw new ParticleColorException("This particle effect is not colorable"); - } - if (!isColorCorrect(this, paramParticleColor)) { - throw new ParticleColorException("The particle color type is incorrect"); - } - new ParticlePacket(this, paramParticleColor, paramDouble > 256.0).sendTo(paramLocation, paramDouble); - } - - public void display(final ParticleColor paramParticleColor, final Location paramLocation, final List paramList) { - if (!this.isSupported()) { - throw new ParticleVersionException("This particle effect is not supported by your server version"); - } - if (!this.hasProperty(ParticleProperty.COLORABLE)) { - throw new ParticleColorException("This particle effect is not colorable"); - } - if (!isColorCorrect(this, paramParticleColor)) { - throw new ParticleColorException("The particle color type is incorrect"); - } - new ParticlePacket(this, paramParticleColor, isLongDistance(paramLocation, paramList)).sendTo(paramLocation, paramList); - } - - public void display(final ParticleColor paramParticleColor, final Location paramLocation, final Player... paramVarArgs) { - this.display(paramParticleColor, paramLocation, Arrays.asList(paramVarArgs)); - } - - public void display(final ParticleData paramParticleData, final float paramFloat1, final float paramFloat2, final float paramFloat3, final float paramFloat4, final int paramInt, final Location paramLocation, final double paramDouble) { - if (!this.isSupported()) { - throw new ParticleVersionException("This particle effect is not supported by your server version"); - } - if (!this.hasProperty(ParticleProperty.REQUIRES_DATA)) { - throw new ParticleDataException("This particle effect does not require additional data"); - } - if (!isDataCorrect(this, paramParticleData)) { - throw new ParticleDataException("The particle data type is incorrect"); - } - new ParticlePacket(this, paramFloat1, paramFloat2, paramFloat3, paramFloat4, paramInt, paramDouble > 256.0, paramParticleData).sendTo(paramLocation, paramDouble); - } - - public void display(final ParticleData paramParticleData, final float paramFloat1, final float paramFloat2, final float paramFloat3, final float paramFloat4, final int paramInt, final Location paramLocation, final List paramList) { - if (!this.isSupported()) { - throw new ParticleVersionException("This particle effect is not supported by your server version"); - } - if (!this.hasProperty(ParticleProperty.REQUIRES_DATA)) { - throw new ParticleDataException("This particle effect does not require additional data"); - } - if (!isDataCorrect(this, paramParticleData)) { - throw new ParticleDataException("The particle data type is incorrect"); - } - new ParticlePacket(this, paramFloat1, paramFloat2, paramFloat3, paramFloat4, paramInt, isLongDistance(paramLocation, paramList), paramParticleData).sendTo(paramLocation, paramList); - } - - public void display(final ParticleData paramParticleData, final float paramFloat1, final float paramFloat2, final float paramFloat3, final float paramFloat4, final int paramInt, final Location paramLocation, final Player... paramVarArgs) { - this.display(paramParticleData, paramFloat1, paramFloat2, paramFloat3, paramFloat4, paramInt, paramLocation, Arrays.asList(paramVarArgs)); - } - - public void display(final ParticleData paramParticleData, final Vector paramVector, final float paramFloat, final Location paramLocation, final double paramDouble) { - if (!this.isSupported()) { - throw new ParticleVersionException("This particle effect is not supported by your server version"); - } - if (!this.hasProperty(ParticleProperty.REQUIRES_DATA)) { - throw new ParticleDataException("This particle effect does not require additional data"); - } - if (!isDataCorrect(this, paramParticleData)) { - throw new ParticleDataException("The particle data type is incorrect"); - } - new ParticlePacket(this, paramVector, paramFloat, paramDouble > 256.0, paramParticleData).sendTo(paramLocation, paramDouble); - } - - public void display(final ParticleData paramParticleData, final Vector paramVector, final float paramFloat, final Location paramLocation, final List paramList) { - if (!this.isSupported()) { - throw new ParticleVersionException("This particle effect is not supported by your server version"); - } - if (!this.hasProperty(ParticleProperty.REQUIRES_DATA)) { - throw new ParticleDataException("This particle effect does not require additional data"); - } - if (!isDataCorrect(this, paramParticleData)) { - throw new ParticleDataException("The particle data type is incorrect"); - } - new ParticlePacket(this, paramVector, paramFloat, isLongDistance(paramLocation, paramList), paramParticleData).sendTo(paramLocation, paramList); - } - - public void display(final ParticleData paramParticleData, final Vector paramVector, final float paramFloat, final Location paramLocation, final Player... paramVarArgs) { - this.display(paramParticleData, paramVector, paramFloat, paramLocation, Arrays.asList(paramVarArgs)); - } - - public static enum ParticleProperty - { - REQUIRES_WATER, REQUIRES_DATA, DIRECTIONAL, COLORABLE; - } - - public static abstract class ParticleData - { - private final Material material; - private final byte data; - private final int[] packetData; - - public ParticleData(Material paramMaterial, byte paramByte) - { - this.material = paramMaterial; - this.data = paramByte; - this.packetData = new int[] { paramMaterial.getId(), paramByte }; - } - - public Material getMaterial() - { - return this.material; - } - - public byte getData() - { - return this.data; + new ParticlePacket(this, direction, speed, isLongDistance(center, players), data).sendTo(center, players); + } + + /** + * Displays a single particle which requires additional data that flies into a determined direction and is only visible for the specified players + * + * @param data Data of the effect + * @param direction Direction of the particle + * @param speed Display speed of the particles + * @param center Center location of the effect + * @param players Receivers of the effect + * @throws ParticleVersionException If the particle effect is not supported by the server version + * @throws ParticleDataException If the particle effect does not require additional data or if the data type is incorrect + * @see #display(ParticleData, Vector, float, Location, List) + */ + public void display(ParticleData data, Vector direction, float speed, Location center, Player... players) throws ParticleVersionException, ParticleDataException { + display(data, direction, speed, center, Arrays.asList(players)); + } + + /** + * Represents the property of a particle effect + *

+ * This class is part of the ParticleEffect Library and follows the same usage conditions + * + * @author DarkBlade12 + * @since 1.7 + */ + public static enum ParticleProperty { + /** + * The particle effect requires water to be displayed + */ + REQUIRES_WATER, + /** + * The particle effect requires block or item data to be displayed + */ + REQUIRES_DATA, + /** + * The particle effect uses the offsets as direction values + */ + DIRECTIONAL, + /** + * The particle effect uses the offsets as color values + */ + COLORABLE; + } + + /** + * Represents the particle data for effects like {@link EffLib#ITEM_CRACK}, {@link EffLib#BLOCK_CRACK} and {@link EffLib#BLOCK_DUST} + *

+ * This class is part of the ParticleEffect Library and follows the same usage conditions + * + * @author DarkBlade12 + * @since 1.6 + */ + public static abstract class ParticleData { + private final Material material; + private final byte data; + private final int[] packetData; + + /** + * Construct a new particle data + * + * @param material Material of the item/block + * @param data Data value of the item/block + */ + @SuppressWarnings("deprecation") + public ParticleData(Material material, byte data) { + this.material = material; + this.data = data; + this.packetData = new int[] { material.getId(), data }; } - - public int[] getPacketData() - { - return this.packetData; - } - - public String getPacketDataString() - { - return "_" + this.packetData[0] + "_" + this.packetData[1]; - } - } - - public static final class ItemData extends EffLib.ParticleData - { - public ItemData(Material paramMaterial, byte paramByte) - { - super(paramMaterial, paramByte); - } - } - - public static final class BlockData extends EffLib.ParticleData - { - public BlockData(Material paramMaterial, byte paramByte) { - super(paramMaterial, paramByte); - - if (!paramMaterial.isBlock()) { - throw new IllegalArgumentException("The material is not a block"); - } + + /** + * Returns the material of this data + * + * @return The material + */ + public Material getMaterial() { + return material; } - - public BlockData(Material paramMaterial) - { - super(paramMaterial, (byte)0); - if (!paramMaterial.isBlock()) { + + /** + * Returns the data value of this data + * + * @return The data value + */ + public byte getData() { + return data; + } + + /** + * Returns the data as an int array for packet construction + * + * @return The data for the packet + */ + public int[] getPacketData() { + return packetData; + } + + /** + * Returns the data as a string for pre 1.8 versions + * + * @return The data string for the packet + */ + public String getPacketDataString() { + return "_" + packetData[0] + "_" + packetData[1]; + } + } + + /** + * Represents the item data for the {@link EffLib#ITEM_CRACK} effect + *

+ * This class is part of the ParticleEffect Library and follows the same usage conditions + * + * @author DarkBlade12 + * @since 1.6 + */ + public static final class ItemData extends ParticleData { + /** + * Construct a new item data + * + * @param material Material of the item + * @param data Data value of the item + * @see ParticleData#ParticleData(Material, byte) + */ + public ItemData(Material material, byte data) { + super(material, data); + } + } + + /** + * Represents the block data for the {@link EffLib#BLOCK_CRACK} and {@link EffLib#BLOCK_DUST} effects + *

+ * This class is part of the ParticleEffect Library and follows the same usage conditions + * + * @author DarkBlade12 + * @since 1.6 + */ + public static final class BlockData extends ParticleData { + /** + * Construct a new block data + * + * @param material Material of the block + * @param data Data value of the block + * @throws IllegalArgumentException If the material is not a block + * @see ParticleData#ParticleData(Material, byte) + */ + public BlockData(Material material, byte data) throws IllegalArgumentException { + super(material, data); + if (!material.isBlock()) { throw new IllegalArgumentException("The material is not a block"); } } } - - public static final class OrdinaryColor extends EffLib.ParticleColor - { + + /** + * Represents the color for effects like {@link EffLib#SPELL_MOB}, {@link EffLib#SPELL_MOB_AMBIENT}, {@link EffLib#REDSTONE} and {@link EffLib#NOTE} + *

+ * This class is part of the ParticleEffect Library and follows the same usage conditions + * + * @author DarkBlade12 + * @since 1.7 + */ + public static abstract class ParticleColor { + /** + * Returns the value for the offsetX field + * + * @return The offsetX value + */ + public abstract float getValueX(); + + /** + * Returns the value for the offsetY field + * + * @return The offsetY value + */ + public abstract float getValueY(); + + /** + * Returns the value for the offsetZ field + * + * @return The offsetZ value + */ + public abstract float getValueZ(); + } + + /** + * Represents the color for effects like {@link EffLib#SPELL_MOB}, {@link EffLib#SPELL_MOB_AMBIENT} and {@link EffLib#NOTE} + *

+ * This class is part of the ParticleEffect Library and follows the same usage conditions + * + * @author DarkBlade12 + * @since 1.7 + */ + public static final class OrdinaryColor extends ParticleColor { private final int red; private final int green; private final int blue; - - public OrdinaryColor(int paramInt1, int paramInt2, int paramInt3) - { - if (paramInt1 < 0) { + + /** + * Construct a new ordinary color + * + * @param red Red value of the RGB format + * @param green Green value of the RGB format + * @param blue Blue value of the RGB format + * @throws IllegalArgumentException If one of the values is lower than 0 or higher than 255 + */ + public OrdinaryColor(int red, int green, int blue) throws IllegalArgumentException { + if (red < 0) { throw new IllegalArgumentException("The red value is lower than 0"); } - if (paramInt1 > 255) { + if (red > 255) { throw new IllegalArgumentException("The red value is higher than 255"); } - this.red = paramInt1; - if (paramInt2 < 0) { + this.red = red; + if (green < 0) { throw new IllegalArgumentException("The green value is lower than 0"); } - if (paramInt2 > 255) { + if (green > 255) { throw new IllegalArgumentException("The green value is higher than 255"); } - this.green = paramInt2; - if (paramInt3 < 0) { + this.green = green; + if (blue < 0) { throw new IllegalArgumentException("The blue value is lower than 0"); } - if (paramInt3 > 255) { + if (blue > 255) { throw new IllegalArgumentException("The blue value is higher than 255"); } - this.blue = paramInt3; + this.blue = blue; } - - public OrdinaryColor(Color paramColor) - { - this(paramColor.getRed(), paramColor.getGreen(), paramColor.getBlue()); + + /** + * Construct a new ordinary color + * + * @param color Bukkit color + */ + public OrdinaryColor(Color color) { + this(color.getRed(), color.getGreen(), color.getBlue()); } - - public int getRed() - { - return this.red; + + /** + * Returns the red value of the RGB format + * + * @return The red value + */ + public int getRed() { + return red; } - - public int getGreen() - { - return this.green; + + /** + * Returns the green value of the RGB format + * + * @return The green value + */ + public int getGreen() { + return green; } - - public int getBlue() - { - return this.blue; + + /** + * Returns the blue value of the RGB format + * + * @return The blue value + */ + public int getBlue() { + return blue; } - - public float getValueX() - { - return this.red / 255.0F; + + /** + * Returns the red value divided by 255 + * + * @return The offsetX value + */ + @Override + public float getValueX() { + return (float) red / 255F; } - - public float getValueY() - { - return this.green / 255.0F; + + /** + * Returns the green value divided by 255 + * + * @return The offsetY value + */ + @Override + public float getValueY() { + return (float) green / 255F; } - - public float getValueZ() - { - return this.blue / 255.0F; + + /** + * Returns the blue value divided by 255 + * + * @return The offsetZ value + */ + @Override + public float getValueZ() { + return (float) blue / 255F; } } - - public static final class NoteColor extends EffLib.ParticleColor - { - private final int note; - - public NoteColor(int paramInt) - { - if (paramInt < 0) { - throw new IllegalArgumentException("The note value is lower than 0"); - } - if (paramInt > 24) { - throw new IllegalArgumentException("The note value is higher than 24"); - } - this.note = paramInt; - } - - public float getValueX() - { - return this.note / 24.0F; - } - - public float getValueY() - { - return 0.0F; - } - - public float getValueZ() - { - return 0.0F; - } - } - - private static final class ParticleDataException extends RuntimeException - { - private static final long serialVersionUID = 3203085387160737484L; - - public ParticleDataException(String paramString) - { - super(); - } - } - - private static final class ParticleColorException extends RuntimeException - { + + /** + * Represents the color for the {@link EffLib#NOTE} effect + *

+ * This class is part of the ParticleEffect Library and follows the same usage conditions + * + * @author DarkBlade12 + * @since 1.7 + */ + public static final class NoteColor extends ParticleColor { + private final int note; + + /** + * Construct a new note color + * + * @param note Note id which determines color + * @throws IllegalArgumentException If the note value is lower than 0 or higher than 24 + */ + public NoteColor(int note) throws IllegalArgumentException { + if (note < 0) { + throw new IllegalArgumentException("The note value is lower than 0"); + } + if (note > 24) { + throw new IllegalArgumentException("The note value is higher than 24"); + } + this.note = note; + } + + /** + * Returns the note value divided by 24 + * + * @return The offsetX value + */ + @Override + public float getValueX() { + return (float) note / 24F; + } + + /** + * Returns zero because the offsetY value is unused + * + * @return zero + */ + @Override + public float getValueY() { + return 0; + } + + /** + * Returns zero because the offsetZ value is unused + * + * @return zero + */ + @Override + public float getValueZ() { + return 0; + } + + } + + /** + * Represents a runtime exception that is thrown either if the displayed particle effect requires data and has none or vice-versa or if the data type is incorrect + *

+ * This class is part of the ParticleEffect Library and follows the same usage conditions + * + * @author DarkBlade12 + * @since 1.6 + */ + private static final class ParticleDataException extends RuntimeException { private static final long serialVersionUID = 3203085387160737484L; - - public ParticleColorException(String paramString) - { - super(); + + /** + * Construct a new particle data exception + * + * @param message Message that will be logged + */ + public ParticleDataException(String message) { + super(message); } } - - private static final class ParticleVersionException extends RuntimeException - { + + /** + * Represents a runtime exception that is thrown either if the displayed particle effect is not colorable or if the particle color type is incorrect + *

+ * This class is part of the ParticleEffect Library and follows the same usage conditions + * + * @author DarkBlade12 + * @since 1.7 + */ + private static final class ParticleColorException extends RuntimeException { private static final long serialVersionUID = 3203085387160737484L; - - public ParticleVersionException(String paramString) - { - super(); + + /** + * Construct a new particle color exception + * + * @param message Message that will be logged + */ + public ParticleColorException(String message) { + super(message); } } - - public static final class ParticlePacket - { + + /** + * Represents a runtime exception that is thrown if the displayed particle effect requires a newer version + *

+ * This class is part of the ParticleEffect Library and follows the same usage conditions + * + * @author DarkBlade12 + * @since 1.6 + */ + private static final class ParticleVersionException extends RuntimeException { + private static final long serialVersionUID = 3203085387160737484L; + + /** + * Construct a new particle version exception + * + * @param message Message that will be logged + */ + public ParticleVersionException(String message) { + super(message); + } + } + + /** + * Represents a particle effect packet with all attributes which is used for sending packets to the players + *

+ * This class is part of the ParticleEffect Library and follows the same usage conditions + * + * @author DarkBlade12 + * @since 1.5 + */ + public static final class ParticlePacket { private static int version; private static Class enumParticle; private static Constructor packetConstructor; @@ -583,174 +1349,280 @@ public static final class ParticlePacket private final float speed; private final int amount; private final boolean longDistance; - private final EffLib.ParticleData data; + private final ParticleData data; private Object packet; - - public ParticlePacket(EffLib paramEff, float paramFloat1, float paramFloat2, float paramFloat3, float paramFloat4, int paramInt, boolean paramBoolean, EffLib.ParticleData paramParticleData) - { + + /** + * Construct a new particle packet + * + * @param effect Particle effect + * @param offsetX Maximum distance particles can fly away from the center on the x-axis + * @param offsetY Maximum distance particles can fly away from the center on the y-axis + * @param offsetZ Maximum distance particles can fly away from the center on the z-axis + * @param speed Display speed of the particles + * @param amount Amount of particles + * @param longDistance Indicates whether the maximum distance is increased from 256 to 65536 + * @param data Data of the effect + * @throws IllegalArgumentException If the speed or amount is lower than 0 + * @see #initialize() + */ + public ParticlePacket(EffLib effect, float offsetX, float offsetY, float offsetZ, float speed, int amount, boolean longDistance, ParticleData data) throws IllegalArgumentException { initialize(); - if (paramFloat4 < 0.0F) { + if (speed < 0) { throw new IllegalArgumentException("The speed is lower than 0"); } - if (paramInt < 0) { + if (amount < 0) { throw new IllegalArgumentException("The amount is lower than 0"); } - this.effect = paramEff; - this.offsetX = paramFloat1; - this.offsetY = paramFloat2; - this.offsetZ = paramFloat3; - this.speed = paramFloat4; - this.amount = paramInt; - this.longDistance = paramBoolean; - this.data = paramParticleData; + this.effect = effect; + this.offsetX = offsetX; + this.offsetY = offsetY; + this.offsetZ = offsetZ; + this.speed = speed; + this.amount = amount; + this.longDistance = longDistance; + this.data = data; } - - public ParticlePacket(EffLib paramEff, Vector paramVector, float paramFloat, boolean paramBoolean, EffLib.ParticleData paramParticleData) - { - this(paramEff, (float)paramVector.getX(), (float)paramVector.getY(), (float)paramVector.getZ(), paramFloat, 0, paramBoolean, paramParticleData); + + /** + * Construct a new particle packet of a single particle flying into a determined direction + * + * @param effect Particle effect + * @param direction Direction of the particle + * @param speed Display speed of the particle + * @param longDistance Indicates whether the maximum distance is increased from 256 to 65536 + * @param data Data of the effect + * @throws IllegalArgumentException If the speed is lower than 0 + * @see #ParticleEffect(ParticleEffect, float, float, float, float, int, boolean, ParticleData) + */ + public ParticlePacket(EffLib effect, Vector direction, float speed, boolean longDistance, ParticleData data) throws IllegalArgumentException { + this(effect, (float) direction.getX(), (float) direction.getY(), (float) direction.getZ(), speed, 0, longDistance, data); } - - public ParticlePacket(EffLib paramEff, EffLib.ParticleColor paramParticleColor, boolean paramBoolean) - { - this(paramEff, paramParticleColor.getValueX(), paramParticleColor.getValueY(), paramParticleColor.getValueZ(), 1.0F, 0, paramBoolean, null); - if ((paramEff == EffLib.REDSTONE) && ((paramParticleColor instanceof EffLib.OrdinaryColor)) && (((EffLib.OrdinaryColor)paramParticleColor).getRed() == 0)) { - this.offsetX = 1.175494E-038F; + + /** + * Construct a new particle packet of a single colored particle + * + * @param effect Particle effect + * @param color Color of the particle + * @param longDistance Indicates whether the maximum distance is increased from 256 to 65536 + * @see #ParticleEffect(ParticleEffect, float, float, float, float, int, boolean, ParticleData) + */ + public ParticlePacket(EffLib effect, ParticleColor color, boolean longDistance) { + this(effect, color.getValueX(), color.getValueY(), color.getValueZ(), 1, 0, longDistance, null); + if (effect == EffLib.REDSTONE && color instanceof OrdinaryColor && ((OrdinaryColor) color).getRed() == 0) { + offsetX = Float.MIN_NORMAL; } } - - public static void initialize() - { + + /** + * Initializes {@link #packetConstructor}, {@link #getHandle}, {@link #playerConnection} and {@link #sendPacket} and sets {@link #initialized} to true if it succeeds + *

+ * Note: These fields only have to be initialized once, so it will return if {@link #initialized} is already set to true + * + * @throws VersionIncompatibleException if your bukkit version is not supported by this library + */ + public static void initialize() throws VersionIncompatibleException { if (initialized) { return; } - try - { - version = Integer.parseInt(ReflectionUtils.PackageType.getServerVersion().split("_")[1]); + try { + version = Integer.parseInt(Character.toString(PackageType.getServerVersion().charAt(3))); if (version > 7) { - enumParticle = ReflectionUtils.PackageType.MINECRAFT_SERVER.getClass("EnumParticle"); + enumParticle = PackageType.MINECRAFT_SERVER.getClass("EnumParticle"); } - Class localClass = ReflectionUtils.PackageType.MINECRAFT_SERVER.getClass(version < 7 ? "Packet63WorldParticles" : "PacketPlayOutWorldParticles"); - packetConstructor = ReflectionUtils.getConstructor(localClass, new Class[0]); - getHandle = ReflectionUtils.getMethod("CraftPlayer", ReflectionUtils.PackageType.CRAFTBUKKIT_ENTITY, "getHandle", new Class[0]); - playerConnection = ReflectionUtils.getField("EntityPlayer", ReflectionUtils.PackageType.MINECRAFT_SERVER, false, "playerConnection"); - sendPacket = ReflectionUtils.getMethod(playerConnection.getType(), "sendPacket", new Class[] { ReflectionUtils.PackageType.MINECRAFT_SERVER.getClass("Packet") }); - } - catch (Exception localException) - { - throw new VersionIncompatibleException("Your current bukkit version seems to be incompatible with this library", localException); + Class packetClass = PackageType.MINECRAFT_SERVER.getClass(version < 7 ? "Packet63WorldParticles" : "PacketPlayOutWorldParticles"); + packetConstructor = ReflectionUtils.getConstructor(packetClass); + getHandle = ReflectionUtils.getMethod("CraftPlayer", PackageType.CRAFTBUKKIT_ENTITY, "getHandle"); + playerConnection = ReflectionUtils.getField("EntityPlayer", PackageType.MINECRAFT_SERVER, false, "playerConnection"); + sendPacket = ReflectionUtils.getMethod(playerConnection.getType(), "sendPacket", PackageType.MINECRAFT_SERVER.getClass("Packet")); + } catch (Exception exception) { + throw new VersionIncompatibleException("Your current bukkit version seems to be incompatible with this library", exception); } initialized = true; } - - public static int getVersion() - { + + /** + * Returns the version of your server (1.x) + * + * @return The version number + */ + public static int getVersion() { if (!initialized) { initialize(); } return version; } - - private void initializePacket(final Location paramLocation) { - if (this.packet != null) { - return; - } - try { - this.packet = ParticlePacket.packetConstructor.newInstance(new Object[0]); - if (ParticlePacket.version < 8) { - Object localObject = this.effect.getName(); - if (this.data != null) { - localObject = String.valueOf(localObject) + this.data.getPacketDataString(); - } - ReflectionUtils.setValue(this.packet, true, "a", localObject); - } - else { - ReflectionUtils.setValue(this.packet, true, "a", ParticlePacket.enumParticle.getEnumConstants()[this.effect.getId()]); - ReflectionUtils.setValue(this.packet, true, "j", this.longDistance); - if (this.data != null) { - final Object localObject = this.data.getPacketData()[0]; - ReflectionUtils.setValue(this.packet, true, "k", new int[] { (int) localObject }); - } - } - ReflectionUtils.setValue(this.packet, true, "b", (float)paramLocation.getX()); - ReflectionUtils.setValue(this.packet, true, "c", (float)paramLocation.getY()); - ReflectionUtils.setValue(this.packet, true, "d", (float)paramLocation.getZ()); - ReflectionUtils.setValue(this.packet, true, "e", this.offsetX); - ReflectionUtils.setValue(this.packet, true, "f", this.offsetY); - ReflectionUtils.setValue(this.packet, true, "g", this.offsetZ); - ReflectionUtils.setValue(this.packet, true, "h", this.speed); - ReflectionUtils.setValue(this.packet, true, "i", this.amount); - } - catch (Exception localException) { - throw new PacketInstantiationException("Packet instantiation failed", localException); - } - } - - public void sendTo(final Location paramLocation, final Player paramPlayer) { - this.initializePacket(paramLocation); - try { - ParticlePacket.sendPacket.invoke(ParticlePacket.playerConnection.get(ParticlePacket.getHandle.invoke(paramPlayer, new Object[0])), this.packet); - } - catch (Exception localException) { - throw new PacketSendingException("Failed to send the packet to player '" + paramPlayer.getName() + "'", localException); - } - } - - public void sendTo(final Location paramLocation, final List paramList) { - if (paramList.isEmpty()) { - throw new IllegalArgumentException("The player list is empty"); - } - for (final Player localPlayer : paramList) { - this.sendTo(paramLocation, localPlayer); - } - } - - public void sendTo(final Location paramLocation, final double paramDouble) { - if (paramDouble < 1.0) { - throw new IllegalArgumentException("The range is lower than 1"); - } - final String str = paramLocation.getWorld().getName(); - final double d = paramDouble * paramDouble; - for (final Player localPlayer : Bukkit.getOnlinePlayers()) { - if (localPlayer.getWorld().getName().equals(str) && localPlayer.getLocation().distanceSquared(paramLocation) <= d) { - this.sendTo(paramLocation, localPlayer); - } - } - } - - private static final class VersionIncompatibleException extends RuntimeException - { - private static final long serialVersionUID = 3203085387160737484L; - - public VersionIncompatibleException(final String paramString, final Throwable paramThrowable) { - super(paramThrowable); - } - } - - private static final class PacketInstantiationException extends RuntimeException - { - private static final long serialVersionUID = 3203085387160737484L; - - public PacketInstantiationException(final String paramString, final Throwable paramThrowable) { - super(paramThrowable); - } - } - - private static final class PacketSendingException extends RuntimeException - { - private static final long serialVersionUID = 3203085387160737484L; - - public PacketSendingException(final String paramString, final Throwable paramThrowable) { - super(paramThrowable); - } - } - } - - public abstract static class ParticleColor - { - public abstract float getValueX(); - - public abstract float getValueY(); - - public abstract float getValueZ(); - } -} + + /** + * Determine if {@link #packetConstructor}, {@link #getHandle}, {@link #playerConnection} and {@link #sendPacket} are initialized + * + * @return Whether these fields are initialized or not + * @see #initialize() + */ + public static boolean isInitialized() { + return initialized; + } + + /** + * Initializes {@link #packet} with all set values + * + * @param center Center location of the effect + * @throws PacketInstantiationException If instantion fails due to an unknown error + */ + private void initializePacket(Location center) throws PacketInstantiationException { + if (packet != null) { + return; + } + try { + packet = packetConstructor.newInstance(); + if (version < 8) { + String name = effect.getName(); + if (data != null) { + name += data.getPacketDataString(); + } + ReflectionUtils.setValue(packet, true, "a", name); + } else { + ReflectionUtils.setValue(packet, true, "a", enumParticle.getEnumConstants()[effect.getId()]); + ReflectionUtils.setValue(packet, true, "j", longDistance); + if (data != null) { + int[] packetData = data.getPacketData(); + ReflectionUtils.setValue(packet, true, "k", effect == EffLib.ITEM_CRACK ? packetData : new int[] { packetData[0] | (packetData[1] << 12) }); + } + } + ReflectionUtils.setValue(packet, true, "b", (float) center.getX()); + ReflectionUtils.setValue(packet, true, "c", (float) center.getY()); + ReflectionUtils.setValue(packet, true, "d", (float) center.getZ()); + ReflectionUtils.setValue(packet, true, "e", offsetX); + ReflectionUtils.setValue(packet, true, "f", offsetY); + ReflectionUtils.setValue(packet, true, "g", offsetZ); + ReflectionUtils.setValue(packet, true, "h", speed); + ReflectionUtils.setValue(packet, true, "i", amount); + } catch (Exception exception) { + throw new PacketInstantiationException("Packet instantiation failed", exception); + } + } + + /** + * Sends the packet to a single player and caches it + * + * @param center Center location of the effect + * @param player Receiver of the packet + * @throws PacketInstantiationException If instantion fails due to an unknown error + * @throws PacketSendingException If sending fails due to an unknown error + * @see #initializePacket(Location) + */ + public void sendTo(Location center, Player player) throws PacketInstantiationException, PacketSendingException { + initializePacket(center); + try { + sendPacket.invoke(playerConnection.get(getHandle.invoke(player)), packet); + } catch (Exception exception) { + throw new PacketSendingException("Failed to send the packet to player '" + player.getName() + "'", exception); + } + } + + /** + * Sends the packet to all players in the list + * + * @param center Center location of the effect + * @param players Receivers of the packet + * @throws IllegalArgumentException If the player list is empty + * @see #sendTo(Location center, Player player) + */ + public void sendTo(Location center, List players) throws IllegalArgumentException { + if (players.isEmpty()) { + throw new IllegalArgumentException("The player list is empty"); + } + for (Player player : players) { + sendTo(center, player); + } + } + + /** + * Sends the packet to all players in a certain range + * + * @param center Center location of the effect + * @param range Range in which players will receive the packet (Maximum range for particles is usually 16, but it can differ for some types) + * @throws IllegalArgumentException If the range is lower than 1 + * @see #sendTo(Location center, Player player) + */ + public void sendTo(Location center, double range) throws IllegalArgumentException { + if (range < 1) { + throw new IllegalArgumentException("The range is lower than 1"); + } + String worldName = center.getWorld().getName(); + double squared = range * range; + for (Player player : Bukkit.getOnlinePlayers()) { + if (!player.getWorld().getName().equals(worldName) || player.getLocation().distanceSquared(center) > squared) { + continue; + } + sendTo(center, player); + } + } + + /** + * Represents a runtime exception that is thrown if a bukkit version is not compatible with this library + *

+ * This class is part of the ParticleEffect Library and follows the same usage conditions + * + * @author DarkBlade12 + * @since 1.5 + */ + private static final class VersionIncompatibleException extends RuntimeException { + private static final long serialVersionUID = 3203085387160737484L; + + /** + * Construct a new version incompatible exception + * + * @param message Message that will be logged + * @param cause Cause of the exception + */ + public VersionIncompatibleException(String message, Throwable cause) { + super(message, cause); + } + } + + /** + * Represents a runtime exception that is thrown if packet instantiation fails + *

+ * This class is part of the ParticleEffect Library and follows the same usage conditions + * + * @author DarkBlade12 + * @since 1.4 + */ + private static final class PacketInstantiationException extends RuntimeException { + private static final long serialVersionUID = 3203085387160737484L; + + /** + * Construct a new packet instantiation exception + * + * @param message Message that will be logged + * @param cause Cause of the exception + */ + public PacketInstantiationException(String message, Throwable cause) { + super(message, cause); + } + } + + /** + * Represents a runtime exception that is thrown if packet sending fails + *

+ * This class is part of the ParticleEffect Library and follows the same usage conditions + * + * @author DarkBlade12 + * @since 1.4 + */ + private static final class PacketSendingException extends RuntimeException { + private static final long serialVersionUID = 3203085387160737484L; + + /** + * Construct a new packet sending exception + * + * @param message Message that will be logged + * @param cause Cause of the exception + */ + public PacketSendingException(String message, Throwable cause) { + super(message, cause); + } + } + } +} \ No newline at end of file