package cx.sfy.TheBridge.packets; 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 org.bukkit.Bukkit; import org.bukkit.Location; import org.bukkit.Particle; import org.bukkit.entity.Entity; import org.bukkit.entity.Player; @SuppressWarnings({ "unchecked", "rawtypes" }) public class ParticleHandler { private static Class packetClass = null; private static Constructor packetConstructor = null; private static Field player_connection = null; private static Method player_sendPacket = null; private static HashMap, Method> handles = new HashMap, Method>(); private static Class enumParticle = null; private ParticleType type; private double speed; private int count; private double radius; public static void load() { String vString = getVersion().replace("v", ""); double v = 0; if (!vString.isEmpty()) { String[] array = vString.split("_"); v = Double.parseDouble(array[0] + "." + array[1]); } try { packetClass = getNmsClass("PacketPlayOutWorldParticles"); if (v == 1.8) { Bukkit.getLogger().info("[ParticleHandler] Hooking into Netty NMS classes"); Bukkit.getLogger().info("[ParticleHandler] Version is " + v + " - using packet constructor"); enumParticle = (Class) getNmsClass("EnumParticle"); packetConstructor = packetClass.getDeclaredConstructor(enumParticle, boolean.class, float.class, float.class, float.class, float.class, float.class, float.class, float.class, int.class, int[].class); } else { Bukkit.getLogger().info("[ParticleHandler] Hooking into the new particle system"); } } catch (Exception ex) { ex.printStackTrace(); Bukkit.getLogger().severe("[ParticleHandler] Failed to initialize NMS components!"); } } public ParticleHandler(ParticleType type, double speed, int count, double radius) { this.type = type; this.speed = speed; this.count = count; this.radius = radius; } public double getSpeed() { return speed; } public int getCount() { return count; } public double getRadius() { return radius; } public void sendToLocation(Location location) { String vString = getVersion().replace("v", ""); double v = 0; if (!vString.isEmpty()) { String[] array = vString.split("_"); v = Double.parseDouble(array[0] + "." + array[1]); } if (v == 1.8) { try { Object packet = createPacket(location); for (Player player : Bukkit.getOnlinePlayers()) { sendPacket(player, packet); } } catch (Exception e) { e.printStackTrace(); } } else { location.getWorld().spawnParticle(Particle.valueOf(type.getName().toUpperCase()), (float) location.getX(), (float) location.getY(), (float) location.getZ(), this.count, (float) this.radius, (float) this.radius, (float) this.radius, (float) this.speed); } } private Object createPacket(Location location) { try { if (this.count <= 0) { this.count = 1; } Object packet; Object particleType = enumParticle.getEnumConstants()[type.getId()]; packet = packetConstructor.newInstance(particleType, true, (float) location.getX(), (float) location.getY(), (float) location.getZ(), (float) this.radius, (float) this.radius, (float) this.radius, (float) this.speed, this.count, new int[0]); return packet; } catch (IllegalAccessException ex) { ex.printStackTrace(); Bukkit.getLogger().severe("{ParticleHandler] Failed to construct particle effect packet!"); } catch (InstantiationException ex) { ex.printStackTrace(); Bukkit.getLogger().severe("{ParticleHandler] Failed to construct particle effect packet!"); } catch (InvocationTargetException ex) { ex.printStackTrace(); Bukkit.getLogger().severe("{ParticleHandler] Failed to construct particle effect packet!"); } return null; } private static void sendPacket(Player p, Object packet) throws IllegalArgumentException { try { if (player_connection == null) { player_connection = getHandle(p).getClass().getField("playerConnection"); for (Method m : player_connection.get(getHandle(p)).getClass().getMethods()) { if (m.getName().equalsIgnoreCase("sendPacket")) { player_sendPacket = m; } } } player_sendPacket.invoke(player_connection.get(getHandle(p)), packet); } catch (IllegalAccessException ex) { ex.printStackTrace(); Bukkit.getLogger().severe("[ParticleHandler] Failed to send packet!"); } catch (InvocationTargetException ex) { ex.printStackTrace(); Bukkit.getLogger().severe("[ParticleHandler] Failed to send packet!"); } catch (NoSuchFieldException ex) { ex.printStackTrace(); Bukkit.getLogger().severe("[ParticleHandler] Failed to send packet!"); } } private static Object getHandle(Entity entity) { try { if (handles.get(entity.getClass()) != null) return handles.get(entity.getClass()).invoke(entity); else { Method entity_getHandle = entity.getClass().getMethod("getHandle"); handles.put(entity.getClass(), entity_getHandle); return entity_getHandle.invoke(entity); } } catch (Exception ex) { ex.printStackTrace(); return null; } } private static Class getNmsClass(String name) { String version = getVersion(); String className = "net.minecraft.server." + version + name; Class clazz = null; try { clazz = Class.forName(className); } catch (ClassNotFoundException ex) { ex.printStackTrace(); Bukkit.getLogger().severe("[ParticleHandler] Failed to load NMS class " + name + "!"); } return clazz; } private static String getVersion() { String[] array = Bukkit.getServer().getClass().getPackage().getName().replace(".", ",").split(","); if (array.length == 4) return array[3] + "."; return ""; } public enum ParticleType { EXPLOSION_NORMAL("explode", 0, 17), EXPLOSION_LARGE("largeexplode", 1, 1), EXPLOSION_HUGE("hugeexplosion", 2, 0), FIREWORKS_SPARK("fireworksSpark", 3, 2), WATER_BUBBLE("bubble", 4, 3), WATER_SPLASH("splash", 5, 21), WATER_WAKE("wake", 6, -1), SUSPENDED("suspended", 7, 4), SUSPENDED_DEPTH("depthsuspend", 8, 5), CRIT("crit", 9, 7), CRIT_MAGIC("magicCrit", 10, 8), SMOKE_NORMAL("smoke", 11, -1), SMOKE_LARGE("largesmoke", 12, 22), SPELL("spell", 13, 11), SPELL_INSTANT("instantSpell", 14, 12), SPELL_MOB("mobSpell", 15, 9), SPELL_MOB_AMBIENT("mobSpellAmbient", 16, 10), SPELL_WITCH("witchMagic", 17, 13), DRIP_WATER("dripWater", 18, 27), DRIP_LAVA("dripLava", 19, 28), VILLAGER_ANGRY("angryVillager", 20, 31), VILLAGER_HAPPY("happyVillager", 21, 32), TOWN_AURA("townaura", 22, 6), NOTE("note", 23, 24), PORTAL("portal", 24, 15), ENCHANTMENT_TABLE("enchantmenttable", 25, 16), FLAME("flame", 26, 18), LAVA("lava", 27, 19), FOOTSTEP("footstep", 28, 20), CLOUD("cloud", 29, 23), REDSTONE("reddust", 30, 24), SNOWBALL("snowballpoof", 31, 25), SNOW_SHOVEL("snowshovel", 32, 28), SLIME("slime", 33, 29), HEART("heart", 34, 30), BARRIER("barrier", 35, -1), ITEM_CRACK("iconcrack_", 36, 33), BLOCK_CRACK("tilecrack_", 37, 34), BLOCK_DUST("blockdust_", 38, -1), WATER_DROP("droplet", 39, -1), ITEM_TAKE("take", 40, -1), MOB_APPEARANCE("mobappearance", 41, -1); private String name; private int id; private int legacyId; ParticleType(String name, int id, int legacyId) { this.name = name; this.id = id; this.legacyId = legacyId; } String getName() { return name; } int getId() { return id; } int getLegacyId() { return legacyId; } } }