package net.glowstone.constants; import org.bukkit.Effect; import org.bukkit.Particle; import org.bukkit.inventory.ItemStack; import org.bukkit.material.MaterialData; import java.util.HashMap; import java.util.Map; import static com.google.common.base.Preconditions.checkNotNull; /** * Id mappings for particles. */ public final class GlowParticle { private static final int[] EMPTY = new int[0]; private static final int[] ONE_EMPTY = new int[]{0}; private static final int[] TWO_EMPTY = new int[]{0, 0}; private static final Map<Object, Integer> ids = new HashMap<>(); static { // http://wiki.vg/Protocol#Particle IDs, but keyed by API enum set(Particle.EXPLOSION_NORMAL, Effect.EXPLOSION, 0); // explode set(Particle.EXPLOSION_LARGE, Effect.EXPLOSION_LARGE, 1); // largeexplode set(Particle.EXPLOSION_HUGE, Effect.EXPLOSION_HUGE, 2); // hugeexplosion set(Particle.FIREWORKS_SPARK, Effect.FIREWORKS_SPARK, 3); // fireworksSpark set(Particle.WATER_BUBBLE, Effect.BUBBLE, 4); // bubble set(Particle.WATER_SPLASH, Effect.SPLASH, 5); // splash set(Particle.WATER_WAKE, Effect.WAKE, 6); // wake set(Particle.SUSPENDED, Effect.UNDERWATER, 7); // suspended set(Particle.SUSPENDED_DEPTH, Effect.VOID_FOG, 8); // depthsuspend set(Particle.CRIT, Effect.CRIT, 9); // crit set(Particle.CRIT_MAGIC, Effect.MAGIC_CRIT, 10); // magicCrit set(Particle.SMOKE_NORMAL, Effect.PARTICLE_SMOKE, 11); // smoke set(Particle.SMOKE_LARGE, Effect.LARGE_SMOKE, 12); // largesmoke set(Particle.SPELL, Effect.POTION_SWIRL, 13); // spell set(Particle.SPELL_INSTANT, Effect.INSTANT_SPELL, 14); // instantSpell set(Particle.SPELL, Effect.SPELL, 15); // spell set(Particle.SPELL_MOB_AMBIENT, Effect.POTION_SWIRL_TRANSPARENT, 16); // mobSpellAmbient set(Particle.SPELL_WITCH, Effect.WITCH_MAGIC, 17); // witchMagic set(Particle.DRIP_WATER, Effect.WATERDRIP, 18); // dripWater set(Particle.DRIP_LAVA, Effect.LAVADRIP, 19); // dripLava set(Particle.VILLAGER_ANGRY, Effect.VILLAGER_THUNDERCLOUD, 20); // angryVillager set(Particle.VILLAGER_HAPPY, Effect.HAPPY_VILLAGER, 21); // happyVillager set(Particle.TOWN_AURA, Effect.SMALL_SMOKE, 22); // townaura set(Particle.NOTE, Effect.NOTE, 23); // note set(Particle.PORTAL, Effect.PORTAL, 24); // portal set(Particle.ENCHANTMENT_TABLE, Effect.FLYING_GLYPH, 25); // enchantmenttable set(Particle.FLAME, Effect.FLAME, 26); // flame set(Particle.LAVA, Effect.LAVA_POP, 27); // lava set(Particle.FOOTSTEP, Effect.FOOTSTEP, 28); // footstep set(Particle.CLOUD, Effect.CLOUD, 29); // cloud set(Particle.REDSTONE, Effect.COLOURED_DUST, 30); // reddust set(Particle.SNOWBALL, Effect.SNOWBALL_BREAK, 31); // snowballpoof set(Particle.SNOW_SHOVEL, Effect.SNOW_SHOVEL, 32); // snowshovel set(Particle.SLIME, Effect.SLIME, 33); // slime set(Particle.HEART, Effect.HEART, 34); // heart set(Particle.BARRIER, Effect.BARRIER, 35); // barrier set(Particle.ITEM_CRACK, Effect.ITEM_BREAK, 36); // iconcrack_(id)_(data) set(Particle.BLOCK_CRACK, Effect.TILE_BREAK, 37); // blockcrack_(id+(data<<12)) set(Particle.BLOCK_DUST, Effect.TILE_DUST, 38); // blockdust_(id) set(Particle.WATER_DROP, Effect.RAIN, 39); // droplet set(Particle.ITEM_TAKE, Effect.ITEM_TAKE, 40); // take set(Particle.MOB_APPEARANCE, Effect.MOB_APPEARANCE, 41); // mobappearance } private GlowParticle() { } /** * Get the particle id for a specified Particle. * * @param particle the Particle. * @return the particle id. */ public static int getId(Particle particle) { checkNotNull(particle, "particle cannot be null"); return ids.get(particle); } /** * Get the particle id for a specified Particle. * * @param particle the Particle. * @return the particle id. */ public static int getId(Effect particle) { checkNotNull(particle, "particle cannot be null"); return ids.get(particle); } /** * Convert a MaterialData to an extData array if possible for a particle. * * @param particle the Particle to validate. * @param material the MaterialData to convert. * @return The extData array for the particle effect. */ public static int[] getExtData(Effect particle, MaterialData material) { switch (particle) { case ITEM_BREAK: if (material == null) { return TWO_EMPTY; } // http://wiki.vg/Protocol#Particle // data "Length depends on particle. "iconcrack" [Effect.ITEM_BREAK] has length of 2, "blockcrack", // and "blockdust" have lengths of 1, the rest have 0" // iconcrack_(id)_(data) 36 return new int[]{material.getItemTypeId(), material.getData()}; case TILE_BREAK: if (material == null) { return ONE_EMPTY; } return new int[]{material.getItemTypeId() + (material.getData() << 12)}; case TILE_DUST: if (material == null) { return ONE_EMPTY; } return new int[]{material.getItemTypeId()}; default: return EMPTY; } } /** * Convert an object to an extData array if possible for a particle. * * @param particle the Particle to validate. * @param object the Object to convert. * @return The extData array for the particle effect. */ public static int[] getExtData(Particle particle, Object object) { if (particle.getDataType() == Void.class) { return new int[0]; } if (particle.getDataType() == MaterialData.class) { if (object == null) { return new int[]{0}; } MaterialData material = (MaterialData) object; return new int[]{material.getItemTypeId() + (material.getData() << 12)}; } if (particle.getDataType() == ItemStack.class) { if (object == null) { return TWO_EMPTY; } ItemStack item = (ItemStack) object; // http://wiki.vg/Protocol#Particle // data "Length depends on particle. "iconcrack" [Effect.ITEM_BREAK] has length of 2, "blockcrack", // and "blockdust" have lengths of 1, the rest have 0" // iconcrack_(id)_(data) 36 return new int[]{item.getTypeId(), item.getDurability()}; } // doesn't make sense, there are only 3 particle data types return null; } /** * Determine whether a particle type is considered long distance, meaning * it has a higher visible range than normal. * * @param particle the Particle. * @return True if the particle is long distance. */ public static boolean isLongDistance(Effect particle) { switch (particle) { case EXPLOSION: case EXPLOSION_LARGE: case EXPLOSION_HUGE: case MOB_APPEARANCE: return true; } return false; } /** * Determine whether a particle type is considered long distance, meaning * it has a higher visible range than normal. * * @param particle the Particle. * @return True if the particle is long distance. */ public static boolean isLongDistance(Particle particle) { switch (particle) { case EXPLOSION_NORMAL: case EXPLOSION_LARGE: case EXPLOSION_HUGE: case MOB_APPEARANCE: return true; } return false; } private static void set(Particle particle, Effect effect, int id) { ids.put(particle, id); ids.put(effect, id); } }