From af67dfbf0f67686907a8da59e6de35152c4a14a6 Mon Sep 17 00:00:00 2001 From: Olof Larsson Date: Wed, 8 Oct 2014 09:52:20 +0200 Subject: [PATCH] Updated Particle Effect system. --- .../cmd/massivecore/CmdMassiveCoreCmdurl.java | 1 - .../particleeffect/BlockCrackData.java | 56 - .../particleeffect/BlockDustData.java | 62 - .../particleeffect/IconCrackData.java | 56 - .../particleeffect/NormalEffectData.java | 59 - .../particleeffect/ParticleEffect.java | 1454 ++++++++++------- .../particleeffect/ParticleEffectData.java | 48 - .../particleeffect/ReflectionHandler.java | 548 ------- .../particleeffect/ReflectionUtils.java | 758 +++++++++ 9 files changed, 1577 insertions(+), 1465 deletions(-) delete mode 100644 src/main/java/com/massivecraft/massivecore/particleeffect/BlockCrackData.java delete mode 100644 src/main/java/com/massivecraft/massivecore/particleeffect/BlockDustData.java delete mode 100644 src/main/java/com/massivecraft/massivecore/particleeffect/IconCrackData.java delete mode 100644 src/main/java/com/massivecraft/massivecore/particleeffect/NormalEffectData.java delete mode 100644 src/main/java/com/massivecraft/massivecore/particleeffect/ParticleEffectData.java delete mode 100644 src/main/java/com/massivecraft/massivecore/particleeffect/ReflectionHandler.java create mode 100644 src/main/java/com/massivecraft/massivecore/particleeffect/ReflectionUtils.java diff --git a/src/main/java/com/massivecraft/massivecore/cmd/massivecore/CmdMassiveCoreCmdurl.java b/src/main/java/com/massivecraft/massivecore/cmd/massivecore/CmdMassiveCoreCmdurl.java index 86fa2834..e97d9543 100644 --- a/src/main/java/com/massivecraft/massivecore/cmd/massivecore/CmdMassiveCoreCmdurl.java +++ b/src/main/java/com/massivecraft/massivecore/cmd/massivecore/CmdMassiveCoreCmdurl.java @@ -5,7 +5,6 @@ import java.net.URL; import java.util.List; import org.bukkit.Bukkit; -import org.bukkit.command.CommandSender; import org.bukkit.entity.Player; import com.massivecraft.massivecore.MassiveCore; diff --git a/src/main/java/com/massivecraft/massivecore/particleeffect/BlockCrackData.java b/src/main/java/com/massivecraft/massivecore/particleeffect/BlockCrackData.java deleted file mode 100644 index 8873fff4..00000000 --- a/src/main/java/com/massivecraft/massivecore/particleeffect/BlockCrackData.java +++ /dev/null @@ -1,56 +0,0 @@ -package com.massivecraft.massivecore.particleeffect; - -import org.bukkit.Location; -import org.bukkit.entity.Player; - -/** - * This class is part of the ParticleEffect library and follows the same usage conditions - * - * @author DarkBlade12 - */ -public class BlockCrackData extends ParticleEffectData { - private static final String FORMAT = "\\d+@\\d+(@\\d+(\\.\\d+)?){3}@\\d+"; - private final int id; - private final byte data; - - public BlockCrackData(int id, byte data, float offsetX, float offsetY, float offsetZ, int amount) { - super(offsetX, offsetY, offsetZ, amount); - this.id = id; - this.data = data; - } - - public static BlockCrackData fromString(String s) throws IllegalArgumentException { - if (!s.matches(FORMAT)) - throw new IllegalArgumentException("Invalid format"); - String[] p = s.split("@"); - return new BlockCrackData(Integer.parseInt(p[0]), Byte.parseByte(p[1]), Float.parseFloat(p[2]), Float.parseFloat(p[3]), Float.parseFloat(p[4]), Integer.parseInt(p[5])); - } - - @Override - public void displayEffect(Location center, Player... players) { - ParticleEffect.displayBlockCrack(center, id, data, offsetX, offsetY, offsetZ, amount, players); - } - - @Override - public void displayEffect(Location center) { - ParticleEffect.displayBlockCrack(center, id, data, offsetX, offsetY, offsetZ, amount); - } - - @Override - public void displayEffect(Location center, double range) { - ParticleEffect.displayBlockCrack(center, range, id, data, offsetX, offsetY, offsetZ, amount); - } - - public int getId() { - return this.id; - } - - public byte getData() { - return this.data; - } - - @Override - public String toString() { - return id + "@" + data + "@" + super.toString(); - } -} diff --git a/src/main/java/com/massivecraft/massivecore/particleeffect/BlockDustData.java b/src/main/java/com/massivecraft/massivecore/particleeffect/BlockDustData.java deleted file mode 100644 index 2e87162d..00000000 --- a/src/main/java/com/massivecraft/massivecore/particleeffect/BlockDustData.java +++ /dev/null @@ -1,62 +0,0 @@ -package com.massivecraft.massivecore.particleeffect; - -import org.bukkit.Location; -import org.bukkit.entity.Player; - -/** - * This class is part of the ParticleEffect library and follows the same usage conditions - * - * @author DarkBlade12 - */ -public class BlockDustData extends ParticleEffectData { - private static final String FORMAT = "\\d+@\\d+(@\\d+(\\.\\d+)?){3}@\\d+@\\d+(\\.\\d+)?"; - private final int id; - private final byte data; - private final float speed; - - public BlockDustData(int id, byte data, float offsetX, float offsetY, float offsetZ, int amount, float speed) { - super(offsetX, offsetY, offsetZ, amount); - this.id = id; - this.data = data; - this.speed = speed; - } - - public static BlockDustData fromString(String s) throws IllegalArgumentException { - if (!s.matches(FORMAT)) - throw new IllegalArgumentException("Invalid format"); - String[] p = s.split("@"); - return new BlockDustData(Integer.parseInt(p[0]), Byte.parseByte(p[1]), Float.parseFloat(p[2]), Float.parseFloat(p[3]), Float.parseFloat(p[4]), Integer.parseInt(p[5]), Float.parseFloat(p[6])); - } - - @Override - public void displayEffect(Location center, Player... players) { - ParticleEffect.displayBlockDust(center, id, data, offsetX, offsetY, offsetZ, speed, amount, players); - } - - @Override - public void displayEffect(Location center) { - ParticleEffect.displayBlockDust(center, id, data, offsetX, offsetY, offsetZ, speed, amount); - } - - @Override - public void displayEffect(Location center, double range) { - ParticleEffect.displayBlockDust(center, range, id, data, offsetX, offsetY, offsetZ, speed, amount); - } - - public int getId() { - return this.id; - } - - public byte getData() { - return this.data; - } - - public float getSpeed() { - return this.speed; - } - - @Override - public String toString() { - return id + "@" + data + "@" + super.toString() + "@" + speed; - } -} diff --git a/src/main/java/com/massivecraft/massivecore/particleeffect/IconCrackData.java b/src/main/java/com/massivecraft/massivecore/particleeffect/IconCrackData.java deleted file mode 100644 index 87538251..00000000 --- a/src/main/java/com/massivecraft/massivecore/particleeffect/IconCrackData.java +++ /dev/null @@ -1,56 +0,0 @@ -package com.massivecraft.massivecore.particleeffect; - -import org.bukkit.Location; -import org.bukkit.entity.Player; - -/** - * This class is part of the ParticleEffect library and follows the same usage conditions - * - * @author DarkBlade12 - */ -public class IconCrackData extends ParticleEffectData { - private static final String FORMAT = "\\d+(@\\d+(\\.\\d+)?){3}@\\d+@\\d+(\\.\\d+)?"; - private final int id; - private final float speed; - - public IconCrackData(int id, float offsetX, float offsetY, float offsetZ, int amount, float speed) { - super(offsetX, offsetY, offsetZ, amount); - this.id = id; - this.speed = speed; - } - - public static IconCrackData fromString(String s) throws IllegalArgumentException { - if (!s.matches(FORMAT)) - throw new IllegalArgumentException("Invalid format"); - String[] p = s.split("@"); - return new IconCrackData(Integer.parseInt(p[0]), Float.parseFloat(p[1]), Float.parseFloat(p[2]), Float.parseFloat(p[3]), Integer.parseInt(p[4]), Float.parseFloat(p[5])); - } - - @Override - public void displayEffect(Location center, Player... players) { - ParticleEffect.displayIconCrack(center, id, offsetX, offsetY, offsetZ, speed, amount, players); - } - - @Override - public void displayEffect(Location center) { - ParticleEffect.displayIconCrack(center, id, offsetX, offsetY, offsetZ, speed, amount); - } - - @Override - public void displayEffect(Location center, double range) { - ParticleEffect.displayIconCrack(center, range, id, offsetX, offsetY, offsetZ, speed, amount); - } - - public int getId() { - return this.id; - } - - public float getSpeed() { - return this.speed; - } - - @Override - public String toString() { - return id + "@" + super.toString() + "@" + speed; - } -} diff --git a/src/main/java/com/massivecraft/massivecore/particleeffect/NormalEffectData.java b/src/main/java/com/massivecraft/massivecore/particleeffect/NormalEffectData.java deleted file mode 100644 index a1d0489f..00000000 --- a/src/main/java/com/massivecraft/massivecore/particleeffect/NormalEffectData.java +++ /dev/null @@ -1,59 +0,0 @@ -package com.massivecraft.massivecore.particleeffect; - -import org.bukkit.Location; -import org.bukkit.entity.Player; - -/** - * This class is part of the ParticleEffect library and follows the same usage conditions - * - * @author DarkBlade12 - */ -public class NormalEffectData extends ParticleEffectData { - private static final String FORMAT = "\\w+(@\\d+(\\.\\d+)?){3}@\\d+@\\d+(\\.\\d+)?"; - private final ParticleEffect effect; - private final float speed; - - public NormalEffectData(ParticleEffect effect, float offsetX, float offsetY, float offsetZ, int amount, float speed) { - super(offsetX, offsetY, offsetZ, amount); - this.effect = effect; - this.speed = speed; - } - - public static NormalEffectData fromString(String s) throws IllegalArgumentException { - if (!s.matches(FORMAT)) - throw new IllegalArgumentException("Invalid format"); - String[] p = s.split("@"); - ParticleEffect effect = ParticleEffect.fromName(p[0]); - if (effect == null) - throw new IllegalArgumentException("Contains an invalid particle effect name"); - return new NormalEffectData(effect, Float.parseFloat(p[1]), Float.parseFloat(p[2]), Float.parseFloat(p[3]), Integer.parseInt(p[4]), Float.parseFloat(p[5])); - } - - @Override - public void displayEffect(Location center, Player... players) { - effect.display(center, offsetX, offsetY, offsetZ, speed, amount, players); - } - - @Override - public void displayEffect(Location center) { - effect.display(center, offsetX, offsetY, offsetZ, speed, amount); - } - - @Override - public void displayEffect(Location center, double range) { - effect.display(center, range, offsetX, offsetY, offsetZ, speed, amount); - } - - public ParticleEffect getEffect() { - return this.effect; - } - - public float getSpeed() { - return this.speed; - } - - @Override - public String toString() { - return effect.getName() + "@" + super.toString() + "@" + speed; - } -} diff --git a/src/main/java/com/massivecraft/massivecore/particleeffect/ParticleEffect.java b/src/main/java/com/massivecraft/massivecore/particleeffect/ParticleEffect.java index f4e58830..daf11768 100644 --- a/src/main/java/com/massivecraft/massivecore/particleeffect/ParticleEffect.java +++ b/src/main/java/com/massivecraft/massivecore/particleeffect/ParticleEffect.java @@ -1,635 +1,819 @@ -package com.massivecraft.massivecore.particleeffect; - -import java.lang.reflect.Constructor; -import java.lang.reflect.Field; -import java.lang.reflect.Method; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collection; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Map.Entry; - -import org.bukkit.Bukkit; -import org.bukkit.Location; -import org.bukkit.entity.Player; - -import com.massivecraft.massivecore.particleeffect.ReflectionHandler.PackageType; -import com.massivecraft.massivecore.particleeffect.ReflectionHandler.PacketType; -import com.massivecraft.massivecore.particleeffect.ReflectionHandler.SubPackageType; - -/** - * ParticleEffect Library v1.4 - * - * This library was created by @DarkBlade12 based on content related to particles of @microgeek (names and packet values), it 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: - * 1. Don't claim this class as your own - * 2. Don't remove this text - * - * (Would be nice if you provide credit to me) - * - * @author DarkBlade12 - */ -public enum ParticleEffect { - /** - * @appearance Huge explosions - * @displayed by TNT and creepers - */ - HUGE_EXPLOSION("hugeexplosion"), - /** - * @appearance Smaller explosions - * @displayed by TNT and creepers - */ - LARGE_EXPLODE("largeexplode"), - /** - * @appearance Little white sparkling stars - * @displayed by Fireworks - */ - FIREWORKS_SPARK("fireworksSpark"), - /** - * @appearance Bubbles - * @displayed in water - */ - BUBBLE("bubble"), - /** - * @appearance Unknown - */ - SUSPEND("suspend"), - /** - * @appearance Little gray dots - * @displayed in the Void and water - */ - DEPTH_SUSPEND("depthSuspend"), - /** - * @appearance Little gray dots - * @displayed by Mycelium - */ - TOWN_AURA("townaura"), - /** - * @appearance Light brown crosses - * @displayed by critical hits - */ - CRIT("crit"), - /** - * @appearance Cyan stars - * @displayed by hits with an enchanted weapon - */ - MAGIC_CRIT("magicCrit"), - /** - * @appearance Little black/gray clouds - * @displayed by torches, primed TNT and end portals - */ - SMOKE("smoke"), - /** - * @appearance Colored swirls - * @displayed by potion effects - */ - MOB_SPELL("mobSpell"), - /** - * @appearance Transparent colored swirls - * @displayed by beacon effect - */ - MOB_SPELL_AMBIENT("mobSpellAmbient"), - /** - * @appearance Colored swirls - * @displayed by splash potions - */ - SPELL("spell"), - /** - * @appearance Colored crosses - * @displayed by instant splash potions (instant health/instant damage) - */ - INSTANT_SPELL("instantSpell"), - /** - * @appearance Colored crosses - * @displayed by witches - */ - WITCH_MAGIC("witchMagic"), - /** - * @appearance Colored notes - * @displayed by note blocks - */ - NOTE("note"), - /** - * @appearance Little purple clouds - * @displayed by nether portals, endermen, ender pearls, eyes of ender and ender chests - */ - PORTAL("portal"), - /** - * @appearance: White letters - * @displayed by enchantment tables that are near bookshelves - */ - ENCHANTMENT_TABLE("enchantmenttable"), - /** - * @appearance White clouds - */ - EXPLODE("explode"), - /** - * @appearance Little flames - * @displayed by torches, furnaces, magma cubes and monster spawners - */ - FLAME("flame"), - /** - * @appearance Little orange blobs - * @displayed by lava - */ - LAVA("lava"), - /** - * @appearance Gray transparent squares - */ - FOOTSTEP("footstep"), - /** - * @appearance Blue drops - * @displayed by water, rain and shaking wolves - */ - SPLASH("splash"), - /** - * @appearance Blue droplets - * @displayed on water when fishing - */ - WAKE("wake"), - /** - * @appearance Black/Gray clouds - * @displayed by fire, minecarts with furance and blazes - */ - LARGE_SMOKE("largesmoke"), - /** - * @appearance Large white clouds - * @displayed on mob death - */ - CLOUD("cloud"), - /** - * @appearance Little colored clouds - * @displayed by active redstone wires and redstone torches - */ - RED_DUST("reddust"), - /** - * @appearance Little white parts - * @displayed by cracking snowballs and eggs - */ - SNOWBALL_POOF("snowballpoof"), - /** - * @appearance Blue drips - * @displayed by blocks below a water source - */ - DRIP_WATER("dripWater"), - /** - * @appearance Orange drips - * @displayed by blocks below a lava source - */ - DRIP_LAVA("dripLava"), - /** - * @appearance White clouds - */ - SNOW_SHOVEL("snowshovel"), - /** - * @appearance Little green parts - * @displayed by slimes - */ - SLIME("slime"), - /** - * @appearance Red hearts - * @displayed when breeding - */ - HEART("heart"), - /** - * @appearance Dark gray cracked hearts - * @displayed when attacking a villager in a village - */ - ANGRY_VILLAGER("angryVillager"), - /** - * @appearance Green stars - * @displayed by bone meal and when trading with a villager - */ - HAPPY_VILLAGER("happyVillager"); - - private static final Map NAME_MAP = new HashMap(); - private static final double MAX_RANGE = 16; - private static Constructor packetPlayOutWorldParticles; - private static Method getHandle; - private static Field playerConnection; - private static Method sendPacket; - private final String name; - - static { - for (ParticleEffect p : values()) - NAME_MAP.put(p.name, p); - try { - packetPlayOutWorldParticles = ReflectionHandler.getConstructor(PacketType.PLAY_OUT_WORLD_PARTICLES.getPacket(), String.class, float.class, float.class, float.class, float.class, float.class, - float.class, float.class, int.class); - getHandle = ReflectionHandler.getMethod("CraftPlayer", SubPackageType.ENTITY, "getHandle"); - playerConnection = ReflectionHandler.getField("EntityPlayer", PackageType.MINECRAFT_SERVER, "playerConnection"); - sendPacket = ReflectionHandler.getMethod(playerConnection.getType(), "sendPacket", ReflectionHandler.getClass("Packet", PackageType.MINECRAFT_SERVER)); - } catch (Exception e) { - e.printStackTrace(); - } - } - - /** - * @param name Name of this particle effect - */ - private ParticleEffect(String name) { - this.name = name; - } - - /** - * @return The name of this particle effect - */ - public String getName() { - return this.name; - } - - /** - * Gets a particle effect from name - * - * @param name Name of the particle effect - * @return The particle effect - */ - public static ParticleEffect fromName(String name) { - if (name != null) - for (Entry e : NAME_MAP.entrySet()) - if (e.getKey().equalsIgnoreCase(name)) - return e.getValue(); - return null; - } - - /** - * Gets a list of players in a certain range - * - * @param center Center location - * @param range Range - * @return The list of players in the specified range - */ - private static List getPlayers(Location center, double range) { - List players = new ArrayList(); - String name = center.getWorld().getName(); - double squared = range * range; - for (Player p : Bukkit.getOnlinePlayers()) - if (p.getWorld().getName().equals(name) && p.getLocation().distanceSquared(center) <= squared) - players.add(p); - return players; - } - - /** - * Instantiates a new @PacketPlayOutWorldParticles object through reflection - * - * @param center Center location 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 - * @return The packet object - * @throws #PacketInstantiationException if the amount is lower than 1 or if the @PacketPlayOutWorldParticles has changed its name or constructor parameters - */ - private static Object instantiatePacket(String name, Location center, float offsetX, float offsetY, float offsetZ, float speed, int amount) { - if (amount < 1) - throw new PacketInstantiationException("Amount cannot be lower than 1"); - try { - return packetPlayOutWorldParticles.newInstance(name, (float) center.getX(), (float) center.getY(), (float) center.getZ(), offsetX, offsetY, offsetZ, speed, amount); - } catch (Exception e) { - throw new PacketInstantiationException("Packet instantiation failed", e); - } - } - - /** - * Instantiates a new @PacketPlayOutWorldParticles object through reflection especially for the "iconcrack" effect - * - * @param id Id of the icon - * @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 - * @return The packet object - * @throws #PacketInstantiationException if the amount is lower than 1 or if the @PacketPlayOutWorldParticles has changed its name or constructor parameters - * @see #instantiatePacket - */ - private static Object instantiateIconCrackPacket(int id, Location center, float offsetX, float offsetY, float offsetZ, float speed, int amount) { - return instantiatePacket("iconcrack_" + id, center, offsetX, offsetY, offsetZ, speed, amount); - } - - /** - * Instantiates a new @PacketPlayOutWorldParticles object through reflection especially for the "blockcrack" effect - * - * @param id Id of the block - * @param data Data value - * @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 amount Amount of particles - * @return The packet object - * @throws #PacketInstantiationException if the amount is lower than 1 or if the @PacketPlayOutWorldParticles has changed its name or constructor parameters - * @see #instantiatePacket - */ - private static Object instantiateBlockCrackPacket(int id, byte data, Location center, float offsetX, float offsetY, float offsetZ, int amount) { - return instantiatePacket("blockcrack_" + id + "_" + data, center, offsetX, offsetY, offsetZ, 0, amount); - } - - /** - * Instantiates a new @PacketPlayOutWorldParticles object through reflection especially for the "blockdust" effect - * - * @param id Id of the block - * @param data Data value - * @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 - * @return The packet object - * @throws #PacketInstantiationException if the amount is lower than 1 or if the name or the constructor of @PacketPlayOutWorldParticles have changed - * @see #instantiatePacket - */ - private static Object instantiateBlockDustPacket(int id, byte data, Location center, float offsetX, float offsetY, float offsetZ, float speed, int amount) { - return instantiatePacket("blockdust_" + id + "_" + data, center, offsetX, offsetY, offsetZ, speed, amount); - } - - /** - * Sends a packet through reflection to a player - * - * @param p Receiver of the packet - * @param packet Packet that is sent - * @throws #PacketSendingException if the packet is null or some methods which are accessed through reflection have changed - */ - private static void sendPacket(Player p, Object packet) { - try { - sendPacket.invoke(playerConnection.get(getHandle.invoke(p)), packet); - } catch (Exception e) { - throw new PacketSendingException("Failed to send a packet to player '" + p.getName() + "'", e); - } - } - - /** - * Sends a packet through reflection to a collection of players - * - * @param players Receivers of the packet - * @param packet Packet that is sent - * @throws #PacketSendingException if the sending to a single player fails - * @see #sendPacket - */ - private static void sendPacket(Collection players, Object packet) { - for (Player p : players) - sendPacket(p, packet); - } - - /** - * Displays a particle effect which is only visible for the specified players - * - * @param center Center location 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 players Receivers of the effect - * @see #sendPacket - * @see #instantiatePacket - */ - public void display(Location center, float offsetX, float offsetY, float offsetZ, float speed, int amount, Player... players) { - sendPacket(Arrays.asList(players), instantiatePacket(name, center, offsetX, offsetY, offsetZ, speed, amount)); - } - - /** - * Displays a particle effect which is only visible for all players within a certain range in the world of @param center - * - * @param center Center location of the effect - * @param range Range of the visibility - * @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 players Receivers of the effect - * @throws @IllegalArgumentException if the range is higher than 20 - * @see #sendPacket - * @see #instantiatePacket - */ - public void display(Location center, double range, float offsetX, float offsetY, float offsetZ, float speed, int amount) { - if (range > MAX_RANGE) - throw new IllegalArgumentException("Range cannot exceed the maximum value of 16"); - sendPacket(getPlayers(center, range), instantiatePacket(name, center, offsetX, offsetY, offsetZ, speed, amount)); - } - - /** - * Displays a particle effect which is only visible for all players within a range of 20 in the world of @param center - * - * @param center Center location 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 players Receivers of the effect - * @see #display(Location, double, float, float, float, float, int) - */ - public void display(Location center, float offsetX, float offsetY, float offsetZ, float speed, int amount) { - display(center, MAX_RANGE, offsetX, offsetY, offsetZ, speed, amount); - } - - /** - * Displays an icon crack (item break) particle effect which is only visible for the specified players - * - * @param center Center location of the effect - * @param id Id of the icon - * @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 players Receivers of the effect - * @see #sendPacket - * @see #instantiateIconCrackPacket - */ - public static void displayIconCrack(Location center, int id, float offsetX, float offsetY, float offsetZ, float speed, int amount, Player... players) { - sendPacket(Arrays.asList(players), instantiateIconCrackPacket(id, center, offsetX, offsetY, offsetZ, speed, amount)); - } - - /** - * Displays an icon crack (item break) particle effect which is only visible for all players within a certain range in the world of @param center - * - * @param center Center location of the effect - * @param range Range of the visibility - * @param id Id of the icon - * @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 - * @throws @IllegalArgumentException if the range is higher than 20 - * @see #sendPacket - * @see #instantiateIconCrackPacket - */ - public static void displayIconCrack(Location center, double range, int id, float offsetX, float offsetY, float offsetZ, float speed, int amount) { - if (range > MAX_RANGE) - throw new IllegalArgumentException("Range has to be lower/equal the maximum of 16"); - sendPacket(getPlayers(center, range), instantiateIconCrackPacket(id, center, offsetX, offsetY, offsetZ, speed, amount)); - } - - /** - * Displays an icon crack (item break) effect which is visible for all players whitin the maximum range of 20 blocks in the world of @param center - * - * @param center Center location of the effect - * @param id Id of the icon - * @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 - * @see #displayIconCrack(Location, double, int, float, float, float, float, int) - */ - public static void displayIconCrack(Location center, int id, float offsetX, float offsetY, float offsetZ, float speed, int amount) { - displayIconCrack(center, MAX_RANGE, id, offsetX, offsetY, offsetZ, speed, amount); - } - - /** - * Displays a block crack (block break) particle effect which is only visible for the specified players - * - * @param center Center location of the effect - * @param id Id of the block - * @param data Data value - * @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 amount Amount of particles - * @param players Receivers of the effect - * @see #sendPacket - * @see #instantiateBlockCrackPacket - */ - public static void displayBlockCrack(Location center, int id, byte data, float offsetX, float offsetY, float offsetZ, int amount, Player... players) { - sendPacket(Arrays.asList(players), instantiateBlockCrackPacket(id, data, center, offsetX, offsetY, offsetZ, amount)); - } - - /** - * Displays a block crack (block break) particle effect which is only visible for all players within a certain range in the world of @param center - * - * @param center Center location of the effect - * @param range Range of the visibility - * @param id Id of the block - * @param data Data value - * @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 amount Amount of particles - * @throws @IllegalArgumentException if the range is higher than 20 - * @see #sendPacket - * @see #instantiateBlockCrackPacket - */ - public static void displayBlockCrack(Location center, double range, int id, byte data, float offsetX, float offsetY, float offsetZ, int amount) { - if (range > MAX_RANGE) - throw new IllegalArgumentException("Range has to be lower/equal the maximum of 16"); - sendPacket(getPlayers(center, range), instantiateBlockCrackPacket(id, data, center, offsetX, offsetY, offsetZ, amount)); - } - - /** - * Displays a block crack (block break) effect which is visible for all players whitin the maximum range of 20 blocks in the world of @param center - * - * @param center Center location of the effect - * @param id Id of the block - * @param data Data value - * @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 amount Amount of particles - * @see #displayBlockCrack(Location, double, int, byte, float, float, float, int) - */ - public static void displayBlockCrack(Location center, int id, byte data, float offsetX, float offsetY, float offsetZ, int amount) { - displayBlockCrack(center, MAX_RANGE, id, data, offsetX, offsetY, offsetZ, amount); - } - - /** - * Displays a block dust particle effect which is only visible for the specified players - * - * @param center Center location of the effect - * @param id Id of the block - * @param data Data value - * @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 players Receivers of the effect - * @see #sendPacket - * @see #instantiateBlockDustPacket - */ - public static void displayBlockDust(Location center, int id, byte data, float offsetX, float offsetY, float offsetZ, float speed, int amount, Player... players) { - sendPacket(Arrays.asList(players), instantiateBlockDustPacket(id, data, center, offsetX, offsetY, offsetZ, speed, amount)); - } - - /** - * Displays a block dust particle effect which is only visible for all players within a certain range in the world of @param center - * - * @param center Center location of the effect - * @param range Range of the visibility - * @param id Id of the block - * @param data Data value - * @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 - * @throws @IllegalArgumentException if the range is higher than 20 - * @see #sendPacket - * @see #instantiateBlockDustPacket - */ - public static void displayBlockDust(Location center, double range, int id, byte data, float offsetX, float offsetY, float offsetZ, float speed, int amount) { - if (range > MAX_RANGE) - throw new IllegalArgumentException("Range has to be lower/equal the maximum of 16"); - sendPacket(getPlayers(center, range), instantiateBlockDustPacket(id, data, center, offsetX, offsetY, offsetZ, speed, amount)); - } - - /** - * Displays a block dust effect which is visible for all players whitin the maximum range of 20 blocks in the world of @param center - * - * @param center Center location of the effect - * @param id Id of the block - * @param data Data value - * @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 - * @see #displayBlockDust(Location, double, int, byte, float, float, float, float, int) - */ - public static void displayBlockDust(Location center, int id, byte data, float offsetX, float offsetY, float offsetZ, float speed, int amount) { - displayBlockDust(center, MAX_RANGE, id, data, offsetX, offsetY, offsetZ, speed, amount); - } - - /** - * Represents a runtime exception that can be thrown upon packet instantiation - */ - private static final class PacketInstantiationException extends RuntimeException { - private static final long serialVersionUID = 3203085387160737484L; - - /** - * @param message Message that will be logged - */ - public PacketInstantiationException(String message) { - super(message); - } - - /** - * @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 can be thrown upon packet sending - */ - private static final class PacketSendingException extends RuntimeException { - private static final long serialVersionUID = 3203085387160737484L; - - /** - * @param message Message that will be logged - * @param cause Cause of the exception - */ - public PacketSendingException(String message, Throwable cause) { - super(message, cause); - } - } -} +package com.massivecraft.massivecore.particleeffect; + +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; + +import org.bukkit.Bukkit; +import org.bukkit.Location; +import org.bukkit.Material; +import org.bukkit.entity.Player; + +import com.massivecraft.massivecore.particleeffect.ReflectionUtils.PackageType; +import com.massivecraft.massivecore.particleeffect.ReflectionUtils.PacketType; + +/** + * ParticleEffect Library + *

+ * This library was created by @DarkBlade12 based on content related to particles of @microgeek (names and packet parameters), it 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: + *

    + *
  • Don't claim this class as your own + *
  • Don't remove this disclaimer + *
+ *

+ * It would be nice if you provide credit to me if you use this class in a published project + * + * @author DarkBlade12 + * @version 1.5 + */ +public enum ParticleEffect { + /** + * A particle effect which is displayed by exploding tnt and creepers: + *

    + *
  • It looks like a crowd of gray balls which are fading away + *
  • The speed value has no influence on this particle effect + *
+ */ + HUGE_EXPLOSION("hugeexplosion"), + /** + * A particle effect which is displayed by exploding ghast fireballs and wither skulls: + *
    + *
  • It looks like a gray ball which is fading away + *
  • The speed value slightly influences the size of this particle effect + *
+ */ + LARGE_EXPLODE("largeexplode"), + /** + * A particle effect which is displayed by launching fireworks: + *
    + *
  • It looks like a white star which is sparkling + *
  • The speed value influences the velocity at which the particle flies off + *
+ */ + FIREWORKS_SPARK("fireworksSpark"), + /** + * A particle effect which is displayed by swimming entities and arrows in water: + *
    + *
  • It looks like a bubble + *
  • The speed value influences the velocity at which the particle flies off + *
+ */ + BUBBLE("bubble", true), + /** + * A particle effect which is displayed by water: + *
    + *
  • It looks like a tiny blue square + *
  • The speed value has no influence on this particle effect + *
+ */ + SUSPEND("suspend", true), + /** + * A particle effect which is displayed by air when close to bedrock and the in the void: + *
    + *
  • It looks like a tiny gray square + *
  • The speed value has no influence on this particle effect + *
+ */ + DEPTH_SUSPEND("depthSuspend"), + /** + * A particle effect which is displayed by mycelium: + *
    + *
  • It looks like a tiny gray square + *
  • The speed value has no influence on this particle effect + *
+ */ + TOWN_AURA("townaura"), + /** + * A particle effect which is displayed when landing a critical hit and by arrows: + *
    + *
  • It looks like a light brown cross + *
  • The speed value influences the velocity at which the particle flies off + *
+ */ + CRIT("crit"), + /** + * A particle effect which is displayed when landing a hit with an enchanted weapon: + *
    + *
  • It looks like a cyan star + *
  • The speed value influences the velocity at which the particle flies off + *
+ */ + MAGIC_CRIT("magicCrit"), + /** + * A particle effect which is displayed by primed tnt, torches, droppers, dispensers, end portals, brewing stands and monster spawners: + *
    + *
  • It looks like a little gray cloud + *
  • The speed value influences the velocity at which the particle flies off + *
+ */ + SMOKE("smoke"), + /** + * A particle effect which is displayed by entities with active potion effects: + *
    + *
  • It looks like a colored swirl + *
  • The speed value causes the particle to be colored black when set to 0 + *
+ */ + MOB_SPELL("mobSpell"), + /** + * A particle effect which is displayed by entities with active potion effects applied through a beacon: + *
    + *
  • It looks like a transparent colored swirl + *
  • The speed value causes the particle to be always colored black when set to 0 + *
+ */ + MOB_SPELL_AMBIENT("mobSpellAmbient"), + /** + * A particle effect which is displayed when splash potions or bottles o' enchanting hit something: + *
    + *
  • It looks like a white swirl + *
  • The speed value causes the particle to only move upwards when set to 0 + *
+ */ + SPELL("spell"), + /** + * A particle effect which is displayed when instant splash potions hit something: + *
    + *
  • It looks like a white cross + *
  • The speed value causes the particle to only move upwards when set to 0 + *
+ */ + INSTANT_SPELL("instantSpell"), + /** + * A particle effect which is displayed by witches: + *
    + *
  • It looks like a purple cross + *
  • The speed value causes the particle to only move upwards when set to 0 + *
+ */ + WITCH_MAGIC("witchMagic"), + /** + * A particle effect which is displayed by note blocks: + *
    + *
  • It looks like a colored note + *
  • The speed value causes the particle to be colored green when set to 0 + *
+ */ + NOTE("note"), + /** + * A particle effect which is displayed by nether portals, endermen, ender pearls, eyes of ender, ender chests and dragon eggs: + *
    + *
  • It looks like a purple cloud + *
  • The speed value influences the spread of this particle effect + *
+ */ + PORTAL("portal"), + /** + * A particle effect which is displayed by enchantment tables which are nearby bookshelves: + *
    + *
  • It looks like a cryptic white letter + *
  • The speed value influences the spread of this particle effect + *
+ */ + ENCHANTMENT_TABLE("enchantmenttable"), + /** + * A particle effect which is displayed by exploding tnt and creepers: + *
    + *
  • It looks like a white cloud + *
  • The speed value influences the velocity at which the particle flies off + *
+ */ + EXPLODE("explode"), + /** + * A particle effect which is displayed by torches, active furnaces, magma cubes and monster spawners: + *
    + *
  • It looks like a tiny flame + *
  • The speed value influences the velocity at which the particle flies off + *
+ */ + FLAME("flame"), + /** + * A particle effect which is displayed by lava: + *
    + *
  • It looks like a spark + *
  • The speed value has no influence on this particle effect + *
+ */ + LAVA("lava"), + /** + * A particle effect which is currently unused: + *
    + *
  • It looks like a transparent gray square + *
  • The speed value has no influence on this particle effect + *
+ */ + FOOTSTEP("footstep"), + /** + * A particle effect which is displayed by swimming entities, rain dropping on the ground and shaking wolves: + *
    + *
  • It looks like a blue drop + *
  • The speed value has no influence on this particle effect + *
+ */ + SPLASH("splash"), + /** + * A particle effect which is displayed on water when fishing: + *
    + *
  • It looks like a blue droplet + *
  • The speed value influences the velocity at which the particle flies off + *
+ */ + WAKE("wake"), + /** + * A particle effect which is displayed by fire, minecarts with furnace and blazes: + *
    + *
  • It looks like a large gray cloud + *
  • The speed value influences the velocity at which the particle flies off + *
+ */ + LARGE_SMOKE("largesmoke"), + /** + * A particle effect which is displayed when a mob dies: + *
    + *
  • It looks like a large white cloud + *
  • The speed value influences the velocity at which the particle flies off + *
+ */ + CLOUD("cloud"), + /** + * A particle effect which is displayed by redstone ore, powered redstone, redstone torches and redstone repeaters: + *
    + *
  • It looks like a tiny colored cloud + *
  • The speed value causes the particle to be colored red when set to 0 + *
+ */ + RED_DUST("reddust"), + /** + * A particle effect which is displayed when snowballs or eggs hit something: + *
    + *
  • It looks like a tiny part of the snowball icon + *
  • The speed value has no influence on this particle effect + *
+ */ + SNOWBALL_POOF("snowballpoof"), + /** + * A particle effect which is displayed by blocks beneath a water source: + *
    + *
  • It looks like a blue drip + *
  • The speed value has no influence on this particle effect + *
+ */ + DRIP_WATER("dripWater"), + /** + * A particle effect which is displayed by blocks beneath a lava source: + *
    + *
  • It looks like an orange drip + *
  • The speed value has no influence on this particle effect + *
+ */ + DRIP_LAVA("dripLava"), + /** + * A particle effect which is currently unused: + *
    + *
  • It looks like a tiny white cloud + *
  • The speed value influences the velocity at which the particle flies off + *
+ */ + SNOW_SHOVEL("snowshovel"), + /** + * A particle effect which is displayed by slimes: + *
    + *
  • It looks like a tiny part of the slimeball icon + *
  • The speed value has no influence on this particle effect + *
+ */ + SLIME("slime"), + /** + * A particle effect which is displayed when breeding and taming animals: + *
    + *
  • It looks like a red heart + *
  • The speed value has no influence on this particle effect + *
+ */ + HEART("heart"), + /** + * A particle effect which is displayed when attacking a villager in a village: + *
    + *
  • It looks like a cracked gray heart + *
  • The speed value has no influence on this particle effect + *
+ */ + ANGRY_VILLAGER("angryVillager"), + /** + * A particle effect which is displayed when using bone meal and trading with a villager in a village: + *
    + *
  • It looks like a green star + *
  • The speed value has no influence on this particle effect + *
+ */ + HAPPY_VILLAGER("happyVillager"); + + private static final Map NAME_MAP = new HashMap(); + private final String name; + private final boolean requiresWater; + + // Initialize map for quick name lookup + static { + for (ParticleEffect effect : values()) { + NAME_MAP.put(effect.name, effect); + } + } + + /** + * Construct a new particle effect + * + * @param name Name of this particle effect + * @param requiresWater Indicates whether water is required for this particle effect to display properly + */ + private ParticleEffect(String name, boolean requiresWater) { + this.name = name; + this.requiresWater = requiresWater; + } + + /** + * Construct a new particle effect with {@link #requiresWater} set to false + * + * @param name Name of this particle effect + * @see #ParticleEffect(String, boolean) + */ + private ParticleEffect(String name) { + this(name, false); + } + + /** + * Returns the name of this particle effect + * + * @return The name + */ + public String getName() { + return name; + } + + /** + * Determine if water is required for this particle effect to display properly + * + * @return Whether water is required or not + */ + public boolean getRequiresWater() { + return requiresWater; + } + + /** + * Returns the particle effect with the given name + * + * @param name Name of the particle effect + * @return The particle effect + */ + public static ParticleEffect fromName(String name) { + for (Entry entry : NAME_MAP.entrySet()) { + if (!entry.getKey().equalsIgnoreCase(name)) { + continue; + } + return entry.getValue(); + } + return null; + } + + /** + * 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; + } + + /** + * Determine if an id is a block id + * + * @param id Id to check + * @return Whether id is a block or not + */ + @SuppressWarnings("deprecation") + private static boolean isBlock(int id) { + Material material = Material.getMaterial(id); + return material != null && material.isBlock(); + } + + /** + * 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 (Maximum range for particles is usually 16, but it can differ for some types) + * @throws IllegalArgumentException If the particle effect requires water and none is at the center location + * @see ParticleEffectPacket + * @see ParticleEffectPacket#sendTo(Location, double) + */ + public void display(float offsetX, float offsetY, float offsetZ, float speed, int amount, Location center, double range) throws IllegalArgumentException { + if (requiresWater && !isWater(center)) { + throw new IllegalArgumentException("There is no water at the center location"); + } + new ParticleEffectPacket(name, offsetX, offsetY, offsetZ, speed, amount).sendTo(center, range); + } + + /** + * 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 IllegalArgumentException If the particle effect requires water and none is at the center location + * @see ParticleEffectPacket + * @see ParticleEffectPacket#sendTo(Location, List) + */ + public void display(float offsetX, float offsetY, float offsetZ, float speed, int amount, Location center, List players) throws IllegalArgumentException { + if (requiresWater && !isWater(center)) { + throw new IllegalArgumentException("There is no water at the center location"); + } + new ParticleEffectPacket(name, offsetX, offsetY, offsetZ, speed, amount).sendTo(center, players); + } + + /** + * Displays an icon crack (item break) particle effect which is only visible for all players within a certain range in the world of @param center + * + * @param id Id of the icon + * @param data Data value + * @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 (Maximum range for particles is usually 16, but it can differ for some types) + * @see ParticleEffectPacket + * @see ParticleEffectPacket#sendTo(Location, double) + */ + public static void displayIconCrack(int id, byte data, float offsetX, float offsetY, float offsetZ, float speed, int amount, Location center, double range) { + new ParticleEffectPacket("iconcrack_" + id + "_" + data, offsetX, offsetY, offsetZ, speed, amount).sendTo(center, range); + } + + /** + * Displays an icon crack (item break) particle effect which is only visible for the specified players + * + * @param id Id of the icon + * @param data Data value + * @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 + * @see ParticleEffectPacket + * @see ParticleEffectPacket#sendTo(Location, List) + */ + public static void displayIconCrack(int id, byte data, float offsetX, float offsetY, float offsetZ, float speed, int amount, Location center, List players) { + new ParticleEffectPacket("iconcrack_" + id + "_" + data, offsetX, offsetY, offsetZ, speed, amount).sendTo(center, players); + } + + /** + * Displays a block crack (block break) particle effect which is only visible for all players within a certain range in the world of @param center + * + * @param id Id of the block + * @param data Data value + * @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 amount Amount of particles + * @param center Center location of the effect + * @param range Range of the visibility (Maximum range for particles is usually 16, but it can differ for some types) + * @throws IllegalArgumentException If the specified id is not a block id + * @see ParticleEffectPacket + * @see ParticleEffectPacket#sendTo(Location, double) + */ + public static void displayBlockCrack(int id, byte data, float offsetX, float offsetY, float offsetZ, int amount, Location center, double range) throws IllegalArgumentException { + if (!isBlock(id)) { + throw new IllegalArgumentException("Invalid block id"); + } + new ParticleEffectPacket("blockcrack_" + id + "_" + data, offsetX, offsetY, offsetZ, 0, amount).sendTo(center, range); + } + + /** + * Displays a block crack (block break) particle effect which is only visible for the specified players + * + * @param id Id of the block + * @param data Data value + * @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 amount Amount of particles + * @param center Center location of the effect + * @param players Receivers of the effect + * @throws IllegalArgumentException If the specified id is not a block id + * @see ParticleEffectPacket + * @see ParticleEffectPacket#sendTo(Location, List) + */ + public static void displayBlockCrack(int id, byte data, float offsetX, float offsetY, float offsetZ, int amount, Location center, List players) throws IllegalArgumentException { + if (!isBlock(id)) { + throw new IllegalArgumentException("Invalid block id"); + } + new ParticleEffectPacket("blockcrack_" + id + "_" + data, offsetX, offsetY, offsetZ, 0, amount).sendTo(center, players); + } + + /** + * Displays a block dust particle effect which is only visible for all players within a certain range in the world of @param center + * + * @param id Id of the block + * @param data Data value + * @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 (Maximum range for particles is usually 16, but it can differ for some types) + * @throws IllegalArgumentException If the specified id is not a block id + * @see ParticleEffectPacket + * @see ParticleEffectPacket#sendTo(Location, double) + */ + public static void displayBlockDust(int id, byte data, float offsetX, float offsetY, float offsetZ, float speed, int amount, Location center, double range) throws IllegalArgumentException { + if (!isBlock(id)) { + throw new IllegalArgumentException("Invalid block id"); + } + new ParticleEffectPacket("blockdust_" + id + "_" + data, offsetX, offsetY, offsetZ, speed, amount).sendTo(center, range); + } + + /** + * Displays a block dust particle effect which is only visible for the specified players + * + * @param id Id of the block + * @param data Data value + * @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 IllegalArgumentException If the specified id is not a block id + * @see ParticleEffectPacket + * @see ParticleEffectPacket#sendTo(Location, List) + */ + public static void displayBlockDust(int id, byte data, float offsetX, float offsetY, float offsetZ, float speed, int amount, Location center, List players) throws IllegalArgumentException { + if (!isBlock(id)) { + throw new IllegalArgumentException("Invalid block id"); + } + new ParticleEffectPacket("blockdust_" + id + "_" + data, offsetX, offsetY, offsetZ, speed, amount).sendTo(center, players); + } + + /** + * 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 ParticleEffectPacket { + private static Constructor packetConstructor; + private static Method getHandle; + private static Field playerConnection; + private static Method sendPacket; + private static boolean initialized; + private final String name; + private final float offsetX; + private final float offsetY; + private final float offsetZ; + private final float speed; + private final int amount; + private Object packet; + + /** + * Construct a new particle effect packet + * + * @param name Name 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 + * @throws IllegalArgumentException If the speed is lower than 0 or the amount is lower than 1 + * @see #initialize() + */ + public ParticleEffectPacket(String name, float offsetX, float offsetY, float offsetZ, float speed, int amount) throws IllegalArgumentException { + initialize(); + if (speed < 0) { + throw new IllegalArgumentException("The speed is lower than 0"); + } + if (amount < 1) { + throw new IllegalArgumentException("The amount is lower than 1"); + } + this.name = name; + this.offsetX = offsetX; + this.offsetY = offsetY; + this.offsetZ = offsetZ; + this.speed = speed; + this.amount = amount; + } + + /** + * 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 accessed packets, fields or methods differ in your bukkit version + */ + public static void initialize() throws VersionIncompatibleException { + if (initialized) { + return; + } + try { + int version = Integer.parseInt(Character.toString(PackageType.getServerVersion().charAt(3))); + Class packetClass = PackageType.MINECRAFT_SERVER.getClass(version < 7 ? "Packet63WorldParticles" : PacketType.PLAY_OUT_WORLD_PARTICLES.getName()); + 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; + } + + /** + * 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; + } + + /** + * 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 + */ + public void sendTo(Location center, Player player) throws PacketInstantiationException, PacketSendingException { + if (packet == null) { + try { + packet = packetConstructor.newInstance(); + ReflectionUtils.setValue(packet, true, "a", name); + 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); + } + } + 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); + } + } + } + + // Ease of use methods + + public void display(float offsetX, float offsetY, float offsetZ, float speed, int amount, Location center) throws IllegalArgumentException { + display(offsetX, offsetY, offsetZ, speed, amount, center, 32); + } + + public void display(float offsetX, float offsetY, float offsetZ, float speed, int amount, Location center, Player... players) throws IllegalArgumentException { + display(offsetX, offsetY, offsetZ, speed, amount, center, Arrays.asList(players)); + } + + // Backwards compatibility + + public void display(Location center, float offsetX, float offsetY, float offsetZ, float speed, int amount) throws IllegalArgumentException { + display(offsetX, offsetY, offsetZ, speed, amount, center); + } + + public void display(Location center, float offsetX, float offsetY, float offsetZ, float speed, int amount, Player... players) throws IllegalArgumentException { + display(offsetX, offsetY, offsetZ, speed, amount, center, players); + } + +} \ No newline at end of file diff --git a/src/main/java/com/massivecraft/massivecore/particleeffect/ParticleEffectData.java b/src/main/java/com/massivecraft/massivecore/particleeffect/ParticleEffectData.java deleted file mode 100644 index 1e548bb2..00000000 --- a/src/main/java/com/massivecraft/massivecore/particleeffect/ParticleEffectData.java +++ /dev/null @@ -1,48 +0,0 @@ -package com.massivecraft.massivecore.particleeffect; - -import org.bukkit.Location; -import org.bukkit.entity.Player; - -/** - * This class is part of the ParticleEffect library and follows the same usage conditions - * - * @author DarkBlade12 - */ -public abstract class ParticleEffectData { - protected final float offsetX, offsetY, offsetZ; - protected final int amount; - - public ParticleEffectData(float offsetX, float offsetY, float offsetZ, int amount) { - this.offsetX = offsetX; - this.offsetY = offsetY; - this.offsetZ = offsetZ; - this.amount = amount; - } - - public abstract void displayEffect(Location center, Player... players); - - public abstract void displayEffect(Location center); - - public abstract void displayEffect(Location center, double range); - - public float getOffsetX() { - return this.offsetX; - } - - public float getOffsetY() { - return this.offsetY; - } - - public float getOffsetZ() { - return this.offsetZ; - } - - public int getAmount() { - return this.amount; - } - - @Override - public String toString() { - return offsetX + "@" + offsetY + "@" + offsetZ + "@" + amount; - } -} diff --git a/src/main/java/com/massivecraft/massivecore/particleeffect/ReflectionHandler.java b/src/main/java/com/massivecraft/massivecore/particleeffect/ReflectionHandler.java deleted file mode 100644 index 5259b9a3..00000000 --- a/src/main/java/com/massivecraft/massivecore/particleeffect/ReflectionHandler.java +++ /dev/null @@ -1,548 +0,0 @@ -package com.massivecraft.massivecore.particleeffect; - -import java.lang.reflect.Constructor; -import java.lang.reflect.Field; -import java.lang.reflect.Method; -import java.util.HashMap; -import java.util.Map; - -import org.bukkit.Bukkit; - -/** - * ReflectionHandler v1.0 - * - * This class 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: - * 1. Don't claim this class as your own - * 2. Don't remove this text - * - * (Would be nice if you provide credit to me) - * - * @author DarkBlade12 - */ -public final class ReflectionHandler { - private ReflectionHandler() {} - - public static Class getClass(String name, PackageType type) throws Exception { - return Class.forName(type + "." + name); - } - - public static Class getClass(String name, SubPackageType type) throws Exception { - return Class.forName(type + "." + name); - } - - public static Constructor getConstructor(Class clazz, Class... parameterTypes) { - Class[] p = DataType.convertToPrimitive(parameterTypes); - for (Constructor c : clazz.getConstructors()) - if (DataType.equalsArray(DataType.convertToPrimitive(c.getParameterTypes()), p)) - return c; - return null; - } - - public static Constructor getConstructor(String className, PackageType type, Class... parameterTypes) throws Exception { - return getConstructor(getClass(className, type), parameterTypes); - } - - public static Constructor getConstructor(String className, SubPackageType type, Class... parameterTypes) throws Exception { - return getConstructor(getClass(className, type), parameterTypes); - } - - public static Object newInstance(Class clazz, Object... args) throws Exception { - return getConstructor(clazz, DataType.convertToPrimitive(args)).newInstance(args); - } - - public static Object newInstance(String className, PackageType type, Object... args) throws Exception { - return newInstance(getClass(className, type), args); - } - - public static Object newInstance(String className, SubPackageType type, Object... args) throws Exception { - return newInstance(getClass(className, type), args); - } - - public static Method getMethod(Class clazz, String name, Class... parameterTypes) { - Class[] p = DataType.convertToPrimitive(parameterTypes); - for (Method m : clazz.getMethods()) - if (m.getName().equals(name) && DataType.equalsArray(DataType.convertToPrimitive(m.getParameterTypes()), p)) - return m; - return null; - } - - public static Method getMethod(String className, PackageType type, String name, Class... parameterTypes) throws Exception { - return getMethod(getClass(className, type), name, parameterTypes); - } - - public static Method getMethod(String className, SubPackageType type, String name, Class... parameterTypes) throws Exception { - return getMethod(getClass(className, type), name, parameterTypes); - } - - public static Object invokeMethod(String name, Object instance, Object... args) throws Exception { - return getMethod(instance.getClass(), name, DataType.convertToPrimitive(args)).invoke(instance, args); - } - - public static Object invokeMethod(Class clazz, String name, Object instance, Object... args) throws Exception { - return getMethod(clazz, name, DataType.convertToPrimitive(args)).invoke(instance, args); - } - - public static Object invokeMethod(String className, PackageType type, String name, Object instance, Object... args) throws Exception { - return invokeMethod(getClass(className, type), name, instance, args); - } - - public static Object invokeMethod(String className, SubPackageType type, String name, Object instance, Object... args) throws Exception { - return invokeMethod(getClass(className, type), name, instance, args); - } - - public static Field getField(Class clazz, String name) throws Exception { - Field f = clazz.getField(name); - f.setAccessible(true); - return f; - } - - public static Field getField(String className, PackageType type, String name) throws Exception { - return getField(getClass(className, type), name); - } - - public static Field getField(String className, SubPackageType type, String name) throws Exception { - return getField(getClass(className, type), name); - } - - public static Field getDeclaredField(Class clazz, String name) throws Exception { - Field f = clazz.getDeclaredField(name); - f.setAccessible(true); - return f; - } - - public static Field getDeclaredField(String className, PackageType type, String name) throws Exception { - return getDeclaredField(getClass(className, type), name); - } - - public static Field getDeclaredField(String className, SubPackageType type, String name) throws Exception { - return getDeclaredField(getClass(className, type), name); - } - - public static Object getValue(Object instance, String fieldName) throws Exception { - return getField(instance.getClass(), fieldName).get(instance); - } - - public static Object getValue(Class clazz, Object instance, String fieldName) throws Exception { - return getField(clazz, fieldName).get(instance); - } - - public static Object getValue(String className, PackageType type, Object instance, String fieldName) throws Exception { - return getValue(getClass(className, type), instance, fieldName); - } - - public static Object getValue(String className, SubPackageType type, Object instance, String fieldName) throws Exception { - return getValue(getClass(className, type), instance, fieldName); - } - - public static Object getDeclaredValue(Object instance, String fieldName) throws Exception { - return getDeclaredField(instance.getClass(), fieldName).get(instance); - } - - public static Object getDeclaredValue(Class clazz, Object instance, String fieldName) throws Exception { - return getDeclaredField(clazz, fieldName).get(instance); - } - - public static Object getDeclaredValue(String className, PackageType type, Object instance, String fieldName) throws Exception { - return getDeclaredValue(getClass(className, type), instance, fieldName); - } - - public static Object getDeclaredValue(String className, SubPackageType type, Object instance, String fieldName) throws Exception { - return getDeclaredValue(getClass(className, type), instance, fieldName); - } - - public static void setValue(Object instance, String fieldName, Object fieldValue) throws Exception { - Field f = getField(instance.getClass(), fieldName); - f.set(instance, fieldValue); - } - - public static void setValue(Object instance, FieldPair pair) throws Exception { - setValue(instance, pair.getName(), pair.getValue()); - } - - public static void setValue(Class clazz, Object instance, String fieldName, Object fieldValue) throws Exception { - Field f = getField(clazz, fieldName); - f.set(instance, fieldValue); - } - - public static void setValue(Class clazz, Object instance, FieldPair pair) throws Exception { - setValue(clazz, instance, pair.getName(), pair.getValue()); - } - - public static void setValue(String className, PackageType type, Object instance, String fieldName, Object fieldValue) throws Exception { - setValue(getClass(className, type), instance, fieldName, fieldValue); - } - - public static void setValue(String className, PackageType type, Object instance, FieldPair pair) throws Exception { - setValue(className, type, instance, pair.getName(), pair.getValue()); - } - - public static void setValue(String className, SubPackageType type, Object instance, String fieldName, Object fieldValue) throws Exception { - setValue(getClass(className, type), instance, fieldName, fieldValue); - } - - public static void setValue(String className, SubPackageType type, Object instance, FieldPair pair) throws Exception { - setValue(className, type, instance, pair.getName(), pair.getValue()); - } - - public static void setValues(Object instance, FieldPair... pairs) throws Exception { - for (FieldPair pair : pairs) - setValue(instance, pair); - } - - public static void setValues(Class clazz, Object instance, FieldPair... pairs) throws Exception { - for (FieldPair pair : pairs) - setValue(clazz, instance, pair); - } - - public static void setValues(String className, PackageType type, Object instance, FieldPair... pairs) throws Exception { - setValues(getClass(className, type), instance, pairs); - } - - public static void setValues(String className, SubPackageType type, Object instance, FieldPair... pairs) throws Exception { - setValues(getClass(className, type), instance, pairs); - } - - public static void setDeclaredValue(Object instance, String fieldName, Object fieldValue) throws Exception { - Field f = getDeclaredField(instance.getClass(), fieldName); - f.set(instance, fieldValue); - } - - public static void setDeclaredValue(Object instance, FieldPair pair) throws Exception { - setDeclaredValue(instance, pair.getName(), pair.getValue()); - } - - public static void setDeclaredValue(Class clazz, Object instance, String fieldName, Object fieldValue) throws Exception { - Field f = getDeclaredField(clazz, fieldName); - f.set(instance, fieldValue); - } - - public static void setDeclaredValue(Class clazz, Object instance, FieldPair pair) throws Exception { - setDeclaredValue(clazz, instance, pair.getName(), pair.getValue()); - } - - public static void setDeclaredValue(String className, PackageType type, Object instance, String fieldName, Object fieldValue) throws Exception { - setDeclaredValue(getClass(className, type), instance, fieldName, fieldValue); - } - - public static void setDeclaredValue(String className, PackageType type, Object instance, FieldPair pair) throws Exception { - setDeclaredValue(className, type, instance, pair.getName(), pair.getValue()); - } - - public static void setDeclaredValue(String className, SubPackageType type, Object instance, String fieldName, Object fieldValue) throws Exception { - setDeclaredValue(getClass(className, type), instance, fieldName, fieldValue); - } - - public static void setDeclaredValue(String className, SubPackageType type, Object instance, FieldPair pair) throws Exception { - setDeclaredValue(className, type, instance, pair.getName(), pair.getValue()); - } - - public static void setDeclaredValues(Object instance, FieldPair... pairs) throws Exception { - for (FieldPair pair : pairs) - setDeclaredValue(instance, pair); - } - - public static void setDeclaredValues(Class clazz, Object instance, FieldPair... pairs) throws Exception { - for (FieldPair pair : pairs) - setDeclaredValue(clazz, instance, pair); - } - - public static void setDeclaredValues(String className, PackageType type, Object instance, FieldPair... pairs) throws Exception { - setDeclaredValues(getClass(className, type), instance, pairs); - } - - public static void setDeclaredValues(String className, SubPackageType type, Object instance, FieldPair... pairs) throws Exception { - setDeclaredValues(getClass(className, type), instance, pairs); - } - - /** - * This class is part of the ReflectionHandler and follows the same usage conditions - * - * @author DarkBlade12 - */ - 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; - - static { - for (DataType t : values()) { - CLASS_MAP.put(t.primitive, t); - CLASS_MAP.put(t.reference, t); - } - } - - private DataType(Class primitive, Class reference) { - this.primitive = primitive; - this.reference = reference; - } - - public Class getPrimitive() { - return this.primitive; - } - - public Class getReference() { - return this.reference; - } - - public static DataType fromClass(Class c) { - return CLASS_MAP.get(c); - } - - public static Class getPrimitive(Class c) { - DataType t = fromClass(c); - return t == null ? c : t.getPrimitive(); - } - - public static Class getReference(Class c) { - DataType t = fromClass(c); - return t == null ? c : t.getReference(); - } - - public static Class[] convertToPrimitive(Class[] classes) { - int length = classes == null ? 0 : classes.length; - Class[] types = new Class[length]; - for (int i = 0; i < length; i++) - types[i] = getPrimitive(classes[i]); - return types; - } - - public static Class[] convertToPrimitive(Object[] objects) { - int length = objects == null ? 0 : objects.length; - Class[] types = new Class[length]; - for (int i = 0; i < length; i++) - types[i] = getPrimitive(objects[i].getClass()); - return types; - } - - public static boolean equalsArray(Class[] a1, Class[] a2) { - if (a1 == null || a2 == null || a1.length != a2.length) - return false; - for (int i = 0; i < a1.length; i++) - if (!a1[i].equals(a2[i]) && !a1[i].isAssignableFrom(a2[i])) - return false; - return true; - } - } - - /** - * This class is part of the ReflectionHandler and follows the same usage conditions - * - * @author DarkBlade12 - */ - public final class FieldPair { - private final String name; - private final Object value; - - public FieldPair(String name, Object value) { - this.name = name; - this.value = value; - } - - public String getName() { - return this.name; - } - - public Object getValue() { - return this.value; - } - } - - /** - * This class is part of the ReflectionHandler and follows the same usage conditions - * - * @author DarkBlade12 - */ - public enum PackageType { - MINECRAFT_SERVER("net.minecraft.server." + Bukkit.getServer().getClass().getPackage().getName().substring(23)), - CRAFTBUKKIT(Bukkit.getServer().getClass().getPackage().getName()); - - private final String name; - - private PackageType(String name) { - this.name = name; - } - - public String getName() { - return this.name; - } - - @Override - public String toString() { - return name; - } - } - - /** - * This class is part of the ReflectionHandler and follows the same usage conditions - * - * @author DarkBlade12 - */ - public enum SubPackageType { - BLOCK, - CHUNKIO, - COMMAND, - CONVERSATIONS, - ENCHANTMENS, - ENTITY, - EVENT, - GENERATOR, - HELP, - INVENTORY, - MAP, - METADATA, - POTION, - PROJECTILES, - SCHEDULER, - SCOREBOARD, - UPDATER, - UTIL; - - private final String name; - - private SubPackageType() { - name = PackageType.CRAFTBUKKIT + "." + name().toLowerCase(); - } - - public String getName() { - return this.name; - } - - @Override - public String toString() { - return name; - } - } - - /** - * This class is part of the ReflectionHandler and follows the same usage conditions - * - * @author DarkBlade12 - */ - public enum PacketType { - HANDSHAKING_IN_SET_PROTOCOL("PacketHandshakingInSetProtocol"), - LOGIN_IN_ENCRYPTION_BEGIN("PacketLoginInEncryptionBegin"), - LOGIN_IN_START("PacketLoginInStart"), - LOGIN_OUT_DISCONNECT("PacketLoginOutDisconnect"), - LOGIN_OUT_ENCRYPTION_BEGIN("PacketLoginOutEncryptionBegin"), - LOGIN_OUT_SUCCESS("PacketLoginOutSuccess"), - PLAY_IN_ABILITIES("PacketPlayInAbilities"), - PLAY_IN_ARM_ANIMATION("PacketPlayInArmAnimation"), - PLAY_IN_BLOCK_DIG("PacketPlayInBlockDig"), - PLAY_IN_BLOCK_PLACE("PacketPlayInBlockPlace"), - PLAY_IN_CHAT("PacketPlayInChat"), - PLAY_IN_CLIENT_COMMAND("PacketPlayInClientCommand"), - PLAY_IN_CLOSE_WINDOW("PacketPlayInCloseWindow"), - PLAY_IN_CUSTOM_PAYLOAD("PacketPlayInCustomPayload"), - PLAY_IN_ENCHANT_ITEM("PacketPlayInEnchantItem"), - PLAY_IN_ENTITY_ACTION("PacketPlayInEntityAction"), - PLAY_IN_FLYING("PacketPlayInFlying"), - PLAY_IN_HELD_ITEM_SLOT("PacketPlayInHeldItemSlot"), - PLAY_IN_KEEP_ALIVE("PacketPlayInKeepAlive"), - PLAY_IN_LOOK("PacketPlayInLook"), - PLAY_IN_POSITION("PacketPlayInPosition"), - PLAY_IN_POSITION_LOOK("PacketPlayInPositionLook"), - PLAY_IN_SET_CREATIVE_SLOT("PacketPlayInSetCreativeSlot "), - PLAY_IN_SETTINGS("PacketPlayInSettings"), - PLAY_IN_STEER_VEHICLE("PacketPlayInSteerVehicle"), - PLAY_IN_TAB_COMPLETE("PacketPlayInTabComplete"), - PLAY_IN_TRANSACTION("PacketPlayInTransaction"), - PLAY_IN_UPDATE_SIGN("PacketPlayInUpdateSign"), - PLAY_IN_USE_ENTITY("PacketPlayInUseEntity"), - PLAY_IN_WINDOW_CLICK("PacketPlayInWindowClick"), - PLAY_OUT_ABILITIES("PacketPlayOutAbilities"), - PLAY_OUT_ANIMATION("PacketPlayOutAnimation"), - PLAY_OUT_ATTACH_ENTITY("PacketPlayOutAttachEntity"), - PLAY_OUT_BED("PacketPlayOutBed"), - PLAY_OUT_BLOCK_ACTION("PacketPlayOutBlockAction"), - PLAY_OUT_BLOCK_BREAK_ANIMATION("PacketPlayOutBlockBreakAnimation"), - PLAY_OUT_BLOCK_CHANGE("PacketPlayOutBlockChange"), - PLAY_OUT_CHAT("PacketPlayOutChat"), - PLAY_OUT_CLOSE_WINDOW("PacketPlayOutCloseWindow"), - PLAY_OUT_COLLECT("PacketPlayOutCollect"), - PLAY_OUT_CRAFT_PROGRESS_BAR("PacketPlayOutCraftProgressBar"), - PLAY_OUT_CUSTOM_PAYLOAD("PacketPlayOutCustomPayload"), - PLAY_OUT_ENTITY("PacketPlayOutEntity"), - PLAY_OUT_ENTITY_DESTROY("PacketPlayOutEntityDestroy"), - PLAY_OUT_ENTITY_EFFECT("PacketPlayOutEntityEffect"), - PLAY_OUT_ENTITY_EQUIPMENT("PacketPlayOutEntityEquipment"), - PLAY_OUT_ENTITY_HEAD_ROTATION("PacketPlayOutEntityHeadRotation"), - PLAY_OUT_ENTITY_LOOK("PacketPlayOutEntityLook"), - PLAY_OUT_ENTITY_METADATA("PacketPlayOutEntityMetadata"), - PLAY_OUT_ENTITY_STATUS("PacketPlayOutEntityStatus"), - PLAY_OUT_ENTITY_TELEPORT("PacketPlayOutEntityTeleport"), - PLAY_OUT_ENTITY_VELOCITY("PacketPlayOutEntityVelocity"), - PLAY_OUT_EXPERIENCE("PacketPlayOutExperience"), - PLAY_OUT_EXPLOSION("PacketPlayOutExplosion"), - PLAY_OUT_GAME_STATE_CHANGE("PacketPlayOutGameStateChange"), - PLAY_OUT_HELD_ITEM_SLOT("PacketPlayOutHeldItemSlot"), - PLAY_OUT_KEEP_ALIVE("PacketPlayOutKeepAlive"), - PLAY_OUT_KICK_DISCONNECT("PacketPlayOutKickDisconnect"), - PLAY_OUT_LOGIN("PacketPlayOutLogin"), - PLAY_OUT_MAP("PacketPlayOutMap"), - PLAY_OUT_MAP_CHUNK("PacketPlayOutMapChunk"), - PLAY_OUT_MAP_CHUNK_BULK("PacketPlayOutMapChunkBulk"), - PLAY_OUT_MULTI_BLOCK_CHANGE("PacketPlayOutMultiBlockChange"), - PLAY_OUT_NAMED_ENTITY_SPAWN("PacketPlayOutNamedEntitySpawn"), - PLAY_OUT_NAMED_SOUND_EFFECT("PacketPlayOutNamedSoundEffect"), - PLAY_OUT_OPEN_SIGN_EDITOR("PacketPlayOutOpenSignEditor"), - PLAY_OUT_OPEN_WINDOW("PacketPlayOutOpenWindow"), - PLAY_OUT_PLAYER_INFO("PacketPlayOutPlayerInfo"), - PLAY_OUT_POSITION("PacketPlayOutPosition"), - PLAY_OUT_REL_ENTITY_MOVE("PacketPlayOutRelEntityMove"), - PLAY_OUT_REL_ENTITY_MOVE_LOOK("PacketPlayOutRelEntityMoveLook"), - PLAY_OUT_REMOVE_ENTITY_EFFECT("PacketPlayOutRemoveEntityEffect"), - PLAY_OUT_RESPAWN("PacketPlayOutRespawn"), - PLAY_OUT_SCOREBOARD_DISPLAY_OBJECTIVE("PacketPlayOutScoreboardDisplayObjective"), - PLAY_OUT_SCOREBOARD_OBJECTIVE("PacketPlayOutScoreboardObjective"), - PLAY_OUT_SCOREBOARD_SCORE("PacketPlayOutScoreboardScore"), - PLAY_OUT_SCOREBOARD_TEAM("PacketPlayOutScoreboardTeam"), - PLAY_OUT_SET_SLOT("PacketPlayOutSetSlot"), - PLAY_OUT_SPAWN_ENTITY("PacketPlayOutSpawnEntity"), - PLAY_OUT_SPAWN_ENTITY_EXPERIENCE_ORB("PacketPlayOutSpawnEntityExperienceOrb"), - PLAY_OUT_SPAWN_ENTITY_LIVING("PacketPlayOutSpawnEntityLiving"), - PLAY_OUT_SPAWN_ENTITY_PAINTING("PacketPlayOutSpawnEntityPainting"), - PLAY_OUT_SPAWN_ENTITY_WEATHER("PacketPlayOutSpawnEntityWeather"), - PLAY_OUT_SPAWN_POSITION("PacketPlayOutSpawnPosition"), - PLAY_OUT_STATISTIC("PacketPlayOutStatistic"), - PLAY_OUT_TAB_COMPLETE("PacketPlayOutTabComplete"), - PLAY_OUT_TILE_ENTITY_DATA("PacketPlayOutTileEntityData"), - PLAY_OUT_TRANSACTION("PacketPlayOutTransaction"), - PLAY_OUT_UPDATE_ATTRIBUTES("PacketPlayOutUpdateAttributes"), - PLAY_OUT_UPDATE_HEALTH("PacketPlayOutUpdateHealth"), - PLAY_OUT_UPDATE_SIGN("PacketPlayOutUpdateSign"), - PLAY_OUT_UPDATE_TIME("PacketPlayOutUpdateTime"), - PLAY_OUT_WINDOW_ITEMS("PacketPlayOutWindowItems"), - PLAY_OUT_WORLD_EVENT("PacketPlayOutWorldEvent"), - PLAY_OUT_WORLD_PARTICLES("PacketPlayOutWorldParticles"), - STATUS_IN_PING("PacketStatusInPing"), - STATUS_IN_START("PacketStatusInStart"), - STATUS_OUT_PONG("PacketStatusOutPong"), - STATUS_OUT_SERVER_INFO("PacketStatusOutServerInfo"); - - private final String name; - private Class packet; - - private PacketType(String name) { - this.name = name; - } - - public String getName() { - return this.getName(); - } - - public Class getPacket() throws Exception { - return packet == null ? packet = ReflectionHandler.getClass(name, PackageType.MINECRAFT_SERVER) : packet; - } - } -} diff --git a/src/main/java/com/massivecraft/massivecore/particleeffect/ReflectionUtils.java b/src/main/java/com/massivecraft/massivecore/particleeffect/ReflectionUtils.java new file mode 100644 index 00000000..33abc67a --- /dev/null +++ b/src/main/java/com/massivecraft/massivecore/particleeffect/ReflectionUtils.java @@ -0,0 +1,758 @@ +package com.massivecraft.massivecore.particleeffect; + +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; + +import org.bukkit.Bukkit; + +/** + * 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: + *

    + *
  • Don't claim this class as your own + *
  • Don't remove this disclaimer + *
+ *

+ * 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 { + // Prevent accidential 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 #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); + } + + /** + * 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; + } + + /** + * 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 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; + } + + /** + * Returns the version of your server + * + * @return The server version + */ + public static String getServerVersion() { + return Bukkit.getServer().getClass().getPackage().getName().substring(23); + } + } + + /** + * 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); + } + } + + /** + * 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(); + } + + /** + * 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()); + } + 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; + } + } + + /** + * Represents an enumeration of all packet types that are featured in Minecraft 1.7.10 + *

+ * If this enumeration is no longer up-to-date, please let me know in my forum post + *

+ * This class is part of the ReflectionUtils and follows the same usage conditions + * + * @author DarkBlade12 + * @since 1.0 + */ + public enum PacketType { + HANDSHAKING_IN_SET_PROTOCOL("PacketHandshakingInSetProtocol"), + LOGIN_IN_ENCRYPTION_BEGIN("PacketLoginInEncryptionBegin"), + LOGIN_IN_START("PacketLoginInStart"), + LOGIN_OUT_DISCONNECT("PacketLoginOutDisconnect"), + LOGIN_OUT_ENCRYPTION_BEGIN("PacketLoginOutEncryptionBegin"), + LOGIN_OUT_SUCCESS("PacketLoginOutSuccess"), + PLAY_IN_ABILITIES("PacketPlayInAbilities"), + PLAY_IN_ARM_ANIMATION("PacketPlayInArmAnimation"), + PLAY_IN_BLOCK_DIG("PacketPlayInBlockDig"), + PLAY_IN_BLOCK_PLACE("PacketPlayInBlockPlace"), + PLAY_IN_CHAT("PacketPlayInChat"), + PLAY_IN_CLIENT_COMMAND("PacketPlayInClientCommand"), + PLAY_IN_CLOSE_WINDOW("PacketPlayInCloseWindow"), + PLAY_IN_CUSTOM_PAYLOAD("PacketPlayInCustomPayload"), + PLAY_IN_ENCHANT_ITEM("PacketPlayInEnchantItem"), + PLAY_IN_ENTITY_ACTION("PacketPlayInEntityAction"), + PLAY_IN_FLYING("PacketPlayInFlying"), + PLAY_IN_HELD_ITEM_SLOT("PacketPlayInHeldItemSlot"), + PLAY_IN_KEEP_ALIVE("PacketPlayInKeepAlive"), + PLAY_IN_LOOK("PacketPlayInLook"), + PLAY_IN_POSITION("PacketPlayInPosition"), + PLAY_IN_POSITION_LOOK("PacketPlayInPositionLook"), + PLAY_IN_SET_CREATIVE_SLOT("PacketPlayInSetCreativeSlot "), + PLAY_IN_SETTINGS("PacketPlayInSettings"), + PLAY_IN_STEER_VEHICLE("PacketPlayInSteerVehicle"), + PLAY_IN_TAB_COMPLETE("PacketPlayInTabComplete"), + PLAY_IN_TRANSACTION("PacketPlayInTransaction"), + PLAY_IN_UPDATE_SIGN("PacketPlayInUpdateSign"), + PLAY_IN_USE_ENTITY("PacketPlayInUseEntity"), + PLAY_IN_WINDOW_CLICK("PacketPlayInWindowClick"), + PLAY_OUT_ABILITIES("PacketPlayOutAbilities"), + PLAY_OUT_ANIMATION("PacketPlayOutAnimation"), + PLAY_OUT_ATTACH_ENTITY("PacketPlayOutAttachEntity"), + PLAY_OUT_BED("PacketPlayOutBed"), + PLAY_OUT_BLOCK_ACTION("PacketPlayOutBlockAction"), + PLAY_OUT_BLOCK_BREAK_ANIMATION("PacketPlayOutBlockBreakAnimation"), + PLAY_OUT_BLOCK_CHANGE("PacketPlayOutBlockChange"), + PLAY_OUT_CHAT("PacketPlayOutChat"), + PLAY_OUT_CLOSE_WINDOW("PacketPlayOutCloseWindow"), + PLAY_OUT_COLLECT("PacketPlayOutCollect"), + PLAY_OUT_CRAFT_PROGRESS_BAR("PacketPlayOutCraftProgressBar"), + PLAY_OUT_CUSTOM_PAYLOAD("PacketPlayOutCustomPayload"), + PLAY_OUT_ENTITY("PacketPlayOutEntity"), + PLAY_OUT_ENTITY_DESTROY("PacketPlayOutEntityDestroy"), + PLAY_OUT_ENTITY_EFFECT("PacketPlayOutEntityEffect"), + PLAY_OUT_ENTITY_EQUIPMENT("PacketPlayOutEntityEquipment"), + PLAY_OUT_ENTITY_HEAD_ROTATION("PacketPlayOutEntityHeadRotation"), + PLAY_OUT_ENTITY_LOOK("PacketPlayOutEntityLook"), + PLAY_OUT_ENTITY_METADATA("PacketPlayOutEntityMetadata"), + PLAY_OUT_ENTITY_STATUS("PacketPlayOutEntityStatus"), + PLAY_OUT_ENTITY_TELEPORT("PacketPlayOutEntityTeleport"), + PLAY_OUT_ENTITY_VELOCITY("PacketPlayOutEntityVelocity"), + PLAY_OUT_EXPERIENCE("PacketPlayOutExperience"), + PLAY_OUT_EXPLOSION("PacketPlayOutExplosion"), + PLAY_OUT_GAME_STATE_CHANGE("PacketPlayOutGameStateChange"), + PLAY_OUT_HELD_ITEM_SLOT("PacketPlayOutHeldItemSlot"), + PLAY_OUT_KEEP_ALIVE("PacketPlayOutKeepAlive"), + PLAY_OUT_KICK_DISCONNECT("PacketPlayOutKickDisconnect"), + PLAY_OUT_LOGIN("PacketPlayOutLogin"), + PLAY_OUT_MAP("PacketPlayOutMap"), + PLAY_OUT_MAP_CHUNK("PacketPlayOutMapChunk"), + PLAY_OUT_MAP_CHUNK_BULK("PacketPlayOutMapChunkBulk"), + PLAY_OUT_MULTI_BLOCK_CHANGE("PacketPlayOutMultiBlockChange"), + PLAY_OUT_NAMED_ENTITY_SPAWN("PacketPlayOutNamedEntitySpawn"), + PLAY_OUT_NAMED_SOUND_EFFECT("PacketPlayOutNamedSoundEffect"), + PLAY_OUT_OPEN_SIGN_EDITOR("PacketPlayOutOpenSignEditor"), + PLAY_OUT_OPEN_WINDOW("PacketPlayOutOpenWindow"), + PLAY_OUT_PLAYER_INFO("PacketPlayOutPlayerInfo"), + PLAY_OUT_POSITION("PacketPlayOutPosition"), + PLAY_OUT_REL_ENTITY_MOVE("PacketPlayOutRelEntityMove"), + PLAY_OUT_REL_ENTITY_MOVE_LOOK("PacketPlayOutRelEntityMoveLook"), + PLAY_OUT_REMOVE_ENTITY_EFFECT("PacketPlayOutRemoveEntityEffect"), + PLAY_OUT_RESPAWN("PacketPlayOutRespawn"), + PLAY_OUT_SCOREBOARD_DISPLAY_OBJECTIVE("PacketPlayOutScoreboardDisplayObjective"), + PLAY_OUT_SCOREBOARD_OBJECTIVE("PacketPlayOutScoreboardObjective"), + PLAY_OUT_SCOREBOARD_SCORE("PacketPlayOutScoreboardScore"), + PLAY_OUT_SCOREBOARD_TEAM("PacketPlayOutScoreboardTeam"), + PLAY_OUT_SET_SLOT("PacketPlayOutSetSlot"), + PLAY_OUT_SPAWN_ENTITY("PacketPlayOutSpawnEntity"), + PLAY_OUT_SPAWN_ENTITY_EXPERIENCE_ORB("PacketPlayOutSpawnEntityExperienceOrb"), + PLAY_OUT_SPAWN_ENTITY_LIVING("PacketPlayOutSpawnEntityLiving"), + PLAY_OUT_SPAWN_ENTITY_PAINTING("PacketPlayOutSpawnEntityPainting"), + PLAY_OUT_SPAWN_ENTITY_WEATHER("PacketPlayOutSpawnEntityWeather"), + PLAY_OUT_SPAWN_POSITION("PacketPlayOutSpawnPosition"), + PLAY_OUT_STATISTIC("PacketPlayOutStatistic"), + PLAY_OUT_TAB_COMPLETE("PacketPlayOutTabComplete"), + PLAY_OUT_TILE_ENTITY_DATA("PacketPlayOutTileEntityData"), + PLAY_OUT_TRANSACTION("PacketPlayOutTransaction"), + PLAY_OUT_UPDATE_ATTRIBUTES("PacketPlayOutUpdateAttributes"), + PLAY_OUT_UPDATE_HEALTH("PacketPlayOutUpdateHealth"), + PLAY_OUT_UPDATE_SIGN("PacketPlayOutUpdateSign"), + PLAY_OUT_UPDATE_TIME("PacketPlayOutUpdateTime"), + PLAY_OUT_WINDOW_ITEMS("PacketPlayOutWindowItems"), + PLAY_OUT_WORLD_EVENT("PacketPlayOutWorldEvent"), + PLAY_OUT_WORLD_PARTICLES("PacketPlayOutWorldParticles"), + STATUS_IN_PING("PacketStatusInPing"), + STATUS_IN_START("PacketStatusInStart"), + STATUS_OUT_PONG("PacketStatusOutPong"), + STATUS_OUT_SERVER_INFO("PacketStatusOutServerInfo"); + + private static final Map NAME_MAP = new HashMap(); + private final String name; + private Class packet; + + // Initialize map for quick name lookup + static { + for (PacketType type : values()) { + NAME_MAP.put(type.name, type); + } + } + + /** + * Construct a new packet type + * + * @param name Name of this packet + */ + private PacketType(String name) { + this.name = name; + } + + /** + * Returns the name of this packet type + * + * @return The name + */ + public String getName() { + return name; + } + + /** + * Returns the class of this packet + * + * @return The packet class + * @throws ClassNotFoundException If the packet class cannot be found (the name differs in your Bukkit version) + * + */ + public Class getPacket() throws ClassNotFoundException { + return packet == null ? (packet = PackageType.MINECRAFT_SERVER.getClass(name)) : packet; + } + } +} \ No newline at end of file