+ * 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 ParticleEffect { + /** + * A particle effect which is displayed by exploding tnt and creepers: + *
+ * 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 ParticleEffect#ITEM_CRACK}, {@link ParticleEffect#BLOCK_CRACK} and {@link ParticleEffect#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}; + } + + /** + * Returns the material of this data + * + * @return The material + */ + public Material getMaterial() { + return material; + } + + /** + * 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 ParticleEffect#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 ParticleEffect#BLOCK_CRACK} and {@link ParticleEffect#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"); + } + } + } + + /** + * Represents the color for effects like {@link ParticleEffect#SPELL_MOB}, {@link ParticleEffect#SPELL_MOB_AMBIENT}, {@link ParticleEffect#REDSTONE} and {@link ParticleEffect#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 ParticleEffect#SPELL_MOB}, {@link ParticleEffect#SPELL_MOB_AMBIENT} and {@link ParticleEffect#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; + + /** + * 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 (red > 255) { + throw new IllegalArgumentException("The red value is higher than 255"); + } + this.red = red; + if (green < 0) { + throw new IllegalArgumentException("The green value is lower than 0"); + } + if (green > 255) { + throw new IllegalArgumentException("The green value is higher than 255"); + } + this.green = green; + if (blue < 0) { + throw new IllegalArgumentException("The blue value is lower than 0"); + } + if (blue > 255) { + throw new IllegalArgumentException("The blue value is higher than 255"); + } + this.blue = blue; + } + + /** + * Construct a new ordinary color + * + * @param color Bukkit color + */ + public OrdinaryColor(Color color) { + this(color.getRed(), color.getGreen(), color.getBlue()); + } + + /** + * Returns the red value of the RGB format + * + * @return The red value + */ + public int getRed() { + return red; + } + + /** + * Returns the green value of the RGB format + * + * @return The green value + */ + public int getGreen() { + return green; + } + + /** + * Returns the blue value of the RGB format + * + * @return The blue value + */ + public int getBlue() { + return blue; + } + + /** + * Returns the red value divided by 255 + * + * @return The offsetX value + */ + @Override + public float getValueX() { + return (float) red / 255F; + } + + /** + * Returns the green value divided by 255 + * + * @return The offsetY value + */ + @Override + public float getValueY() { + return (float) green / 255F; + } + + /** + * Returns the blue value divided by 255 + * + * @return The offsetZ value + */ + @Override + public float getValueZ() { + return (float) blue / 255F; + } + } + + /** + * Represents the color for the {@link ParticleEffect#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; + + /** + * Construct a new particle data exception + * + * @param message Message that will be logged + */ + public ParticleDataException(String message) { + super(message); + } + } + + /** + * 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; + + /** + * Construct a new particle color exception + * + * @param message Message that will be logged + */ + public ParticleColorException(String message) { + super(message); + } + } + + /** + * 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;
+ private static Method getHandle;
+ private static Field playerConnection;
+ private static Method sendPacket;
+ private static boolean initialized;
+ private final ParticleEffect effect;
+ private final float offsetY;
+ private final float offsetZ;
+ private final float speed;
+ private final int amount;
+ private final boolean longDistance;
+ private final ParticleData data;
+ private float offsetX;
+ private Object packet;
+
+ /**
+ * 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(ParticleEffect effect, float offsetX, float offsetY, float offsetZ, float speed, int amount, boolean longDistance, ParticleData data) throws IllegalArgumentException {
+ initialize();
+ if (speed < 0) {
+ throw new IllegalArgumentException("The speed is lower than 0");
+ }
+ if (amount < 0) {
+ throw new IllegalArgumentException("The amount is lower than 0");
+ }
+ 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(ParticleEffect 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(ParticleEffect effect, ParticleColor color, boolean longDistance) {
+ this(effect, color.getValueX(), color.getValueY(), color.getValueZ(), 1, 0, longDistance, null);
+ if (effect == ParticleEffect.REDSTONE && color instanceof OrdinaryColor && ((OrdinaryColor) color).getRed() == 0) {
+ offsetX = Float.MIN_NORMAL;
+ }
+ }
+
+ /**
+ * 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
+ * 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
diff --git a/src/main/java/com/massivecraft/factions/zcore/util/particles/ReflectionUtils.java b/src/main/java/com/massivecraft/factions/zcore/util/particles/ReflectionUtils.java
new file mode 100644
index 00000000..0fca3e0d
--- /dev/null
+++ b/src/main/java/com/massivecraft/factions/zcore/util/particles/ReflectionUtils.java
@@ -0,0 +1,605 @@
+package com.massivecraft.factions.zcore.util.particles;
+
+
+import org.bukkit.Bukkit;
+
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Field;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * com.prosavage.savagecore.particle.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 Araos
+ * @version 1.1
+ */
+public final class ReflectionUtils {
+ // 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;
+ }
+ return constructor;
+ }
+ 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 #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 #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 #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 #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);
+ }
+
+ /**
+ * 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 com.prosavage.savagecore.particle.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;
+ }
+
+ /**
+ * 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);
+ }
+
+ /**
+ * Returns the version of your server
+ *
+ * @return The server version
+ */
+ public static String getServerVersion() {
+ return Bukkit.getServer().getClass().getPackage().getName().substring(23);
+ }
+
+ /**
+ * Returns the path of this package type
+ *
+ * @return The path
+ */
+ public String getPath() {
+ return path;
+ }
+
+ /**
+ * 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);
+ }
+
+ // Override for convenience
+ @Override
+ public String toString() {
+ return path;
+ }
+ }
+
+ /**
+ * Represents an enumeration of Java data types with corresponding classes
+ *
+ * This class is part of the com.prosavage.savagecore.particle.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 Maptrue
+ *
+ * @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(Character.toString(ReflectionUtils.PackageType.getServerVersion().charAt(3)));
+
+ if (version > 7 || (version == 1) && Integer.parseInt(Character.toString(ReflectionUtils.PackageType.getServerVersion().charAt(5))) == 2) {
+ enumParticle = ReflectionUtils.PackageType.MINECRAFT_SERVER.getClass("EnumParticle");
+ }
+ Class> packetClass = ReflectionUtils.PackageType.MINECRAFT_SERVER.getClass(version < 7 ? "Packet63WorldParticles" : "PacketPlayOutWorldParticles");
+ packetConstructor = ReflectionUtils.getConstructor(packetClass);
+ getHandle = ReflectionUtils.getMethod("CraftPlayer", ReflectionUtils.PackageType.CRAFTBUKKIT_ENTITY, "getHandle");
+ playerConnection = ReflectionUtils.getField("EntityPlayer", ReflectionUtils.PackageType.MINECRAFT_SERVER, false, "playerConnection");
+ sendPacket = ReflectionUtils.getMethod(playerConnection.getType(), "sendPacket", ReflectionUtils.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;
+ }
+
+ /**
+ * Returns the version of your server (1.x)
+ *
+ * @return The version number
+ */
+ public static int getVersion() {
+ if (!initialized) {
+ initialize();
+ }
+ return version;
+ }
+
+ /**
+ * 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 == ParticleEffect.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
+ *
+ *