package net.mc_pandacraft.java.plugin.pandacraftutils.protocol; import java.lang.reflect.Constructor; import java.lang.reflect.Field; import java.lang.reflect.Method; 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; /** * 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: *
* 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: *
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
* 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
* 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);
}
}
}
}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(ReflectionUtils.PackageType.getServerVersion().charAt(3)));
Class> packetClass = ReflectionUtils.PackageType.MINECRAFT_SERVER.getClass(version < 7 ? "Packet63WorldParticles" : ReflectionUtils.PacketType.PLAY_OUT_WORLD_PARTICLES.getName());
packetConstructor = ReflectionUtils.getConstructor(packetClass);
getHandle = ReflectionUtils.getMethod("CraftPlayer", ReflectionUtils.PackageType.CRAFTBUKKIT_ENTITY, "getHandle");
playerConnection = ReflectionUtils.getField("EntityPlayer", ReflectionUtils.PackageType.MINECRAFT_SERVER, false, "playerConnection");
sendPacket = ReflectionUtils.getMethod(playerConnection.getType(), "sendPacket", ReflectionUtils.PackageType.MINECRAFT_SERVER.getClass("Packet"));
} catch (Exception exception) {
throw new VersionIncompatibleException("Your current bukkit version seems to be incompatible with this library", exception);
}
initialized = true;
}
/**
* 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