You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

220 lines
7.7 KiB

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<Class<? extends Entity>, Method> handles = new HashMap<Class<? extends Entity>, Method>();
private static Class<Enum> 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<Enum>) 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;
}
}
}