diff --git a/Bukkit-Patches/0009-Add-Particle-API.patch b/Bukkit-Patches/0009-Add-Particle-API.patch new file mode 100644 index 000000000..282426e64 --- /dev/null +++ b/Bukkit-Patches/0009-Add-Particle-API.patch @@ -0,0 +1,357 @@ +From abf412d8d3b2888bd6c51df8504fe1df606da9c5 Mon Sep 17 00:00:00 2001 +From: thinkofdeath +Date: Sun, 2 Jun 2013 15:57:09 +1000 +Subject: [PATCH] Add Particle API + + +diff --git a/src/main/java/org/bukkit/Effect.java b/src/main/java/org/bukkit/Effect.java +index 175750f..ae1f4fd 100644 +--- a/src/main/java/org/bukkit/Effect.java ++++ b/src/main/java/org/bukkit/Effect.java +@@ -5,6 +5,7 @@ import java.util.Map; + import com.google.common.collect.Maps; + + import org.bukkit.block.BlockFace; ++import org.bukkit.material.MaterialData; + import org.bukkit.potion.Potion; + + /** +@@ -78,33 +79,193 @@ public enum Effect { + /** + * The flames seen on a mobspawner; a visual effect. + */ +- MOBSPAWNER_FLAMES(2004, Type.VISUAL); ++ MOBSPAWNER_FLAMES(2004, Type.VISUAL), ++ /** ++ * The spark that comes off a fireworks ++ */ ++ FIREWORKS_SPARK("fireworksSpark", Type.PARTICLE), ++ /** ++ * Critical hit particles ++ */ ++ CRIT("crit", Type.PARTICLE), ++ /** ++ * Blue critical hit particles ++ */ ++ MAGIC_CRIT("magicCrit", Type.PARTICLE), ++ /** ++ * Multicolored potion effect particles ++ */ ++ POTION_SWIRL("mobSpell", Type.PARTICLE), ++ /** ++ * Multicolored potion effect particles that are slightly transparent ++ */ ++ POTION_SWIRL_TRANSPARENT("mobSpellAmbient", Type.PARTICLE), ++ /** ++ * A puff of white potion swirls ++ */ ++ SPELL("spell", Type.PARTICLE), ++ /** ++ * A puff of white stars ++ */ ++ INSTANT_SPELL("instantSpell", Type.PARTICLE), ++ /** ++ * A puff of purple particles ++ */ ++ WITCH_MAGIC("witchMagic", Type.PARTICLE), ++ /** ++ * The note that appears above note blocks ++ */ ++ NOTE("note", Type.PARTICLE), ++ /** ++ * The particles shown at nether portals ++ */ ++ PORTAL("portal", Type.PARTICLE), ++ /** ++ * The symbols that fly towards the enchantment table ++ */ ++ FLYING_GLYPH("enchantmenttable", Type.PARTICLE), ++ /** ++ * Fire particles ++ */ ++ FLAME("flame", Type.PARTICLE), ++ /** ++ * The particles that pop out of lava ++ */ ++ LAVA_POP("lava", Type.PARTICLE), ++ /** ++ * A small gray square ++ */ ++ FOOTSTEP("footstep", Type.PARTICLE), ++ /** ++ * Water particles ++ */ ++ SPLASH("splash", Type.PARTICLE), ++ /** ++ * Smoke particles ++ */ ++ PARTICLE_SMOKE("smoke", Type.PARTICLE), ++ /** ++ * The biggest explosion particle effect ++ */ ++ EXPLOSION_HUGE("hugeexplosion", Type.PARTICLE), ++ /** ++ * A larger version of the explode particle ++ */ ++ EXPLOSION_LARGE("largeexplode", Type.PARTICLE), ++ /** ++ * Explosion particles ++ */ ++ EXPLOSION("explode", Type.PARTICLE), ++ /** ++ * Small gray particles ++ */ ++ VOID_FOG("depthsuspend", Type.PARTICLE), ++ /** ++ * Small gray particles ++ */ ++ SMALL_SMOKE("townaura", Type.PARTICLE), ++ /** ++ * A puff of white smoke ++ */ ++ CLOUD("cloud", Type.PARTICLE), ++ /** ++ * Multicolored dust particles ++ */ ++ COLOURED_DUST("reddust", Type.PARTICLE), ++ /** ++ * Snowball breaking ++ */ ++ SNOWBALL_BREAK("snowballpoof", Type.PARTICLE), ++ /** ++ * The water drip particle that appears on blocks under water ++ */ ++ WATERDRIP("dripWater", Type.PARTICLE), ++ /** ++ * The lava drip particle that appears on blocks under lava ++ */ ++ LAVADRIP("dripLava", Type.PARTICLE), ++ /** ++ * White particles ++ */ ++ SNOW_SHOVEL("snowshovel", Type.PARTICLE), ++ /** ++ * The particle shown when a slime jumps ++ */ ++ SLIME("slime", Type.PARTICLE), ++ /** ++ * The particle that appears when breading animals ++ */ ++ HEART("heart", Type.PARTICLE), ++ /** ++ * The particle that appears when hitting a villager ++ */ ++ VILLAGER_THUNDERCLOUD("angryVillager", Type.PARTICLE), ++ /** ++ * The particle that appears when trading with a villager ++ */ ++ HAPPY_VILLAGER("happyVillager", Type.PARTICLE), ++ /** ++ * The particles generated when a tool breaks. ++ * This particle requires a Material so that the client can select the correct texture. ++ */ ++ ITEM_BREAK("iconcrack", Type.PARTICLE, Material.class), ++ /** ++ * The particles generated while breaking a block. ++ * This particle requires a Material and data value so that the client can select the correct texture. ++ */ ++ TILE_BREAK("tilecrack", Type.PARTICLE, MaterialData.class); + + private final int id; + private final Type type; + private final Class data; + private static final Map BY_ID = Maps.newHashMap(); ++ private static final Map BY_NAME = Maps.newHashMap(); ++ private final String particleName; + +- Effect(int id, Type type) { ++ private Effect(int id, Type type) { + this(id,type,null); + } + +- Effect(int id, Type type, Class data) { ++ private Effect(int id, Type type, Class data) { + this.id = id; + this.type = type; + this.data = data; ++ particleName = null; ++ } ++ ++ private Effect(String particleName, Type type, Class data) { ++ this.particleName = particleName; ++ this.type = type; ++ id = 0; ++ this.data = data; ++ } ++ ++ private Effect(String particleName, Type type) { ++ this.particleName = particleName; ++ this.type = type; ++ id = 0; ++ this.data = null; + } + + /** + * Gets the ID for this effect. + * +- * @return ID of this effect ++ * @return if this Effect isn't of type PARTICLE it returns ID of this effect + */ + public int getId() { + return this.id; + } + + /** ++ * Returns the effect's name. This returns null if the effect is not a particle ++ * ++ * @return The effect's name ++ */ ++ public String getName() { ++ return particleName; ++ } ++ ++ /** + * @return The type of the effect. + */ + public Type getType() { +@@ -112,7 +273,7 @@ public enum Effect { + } + + /** +- * @return The class which represents data for this effect, or null if none ++ * @return if this Effect isn't of type PARTICLE it returns the class which represents data for this effect, or null if none + */ + public Class getData() { + return this.data; +@@ -130,12 +291,32 @@ public enum Effect { + + static { + for (Effect effect : values()) { +- BY_ID.put(effect.id, effect); ++ if (effect.type != Type.PARTICLE) { ++ BY_ID.put(effect.id, effect); ++ } ++ } ++ } ++ ++ /** ++ * Gets the Effect associated with the given name. ++ * ++ * @param name name of the Effect to return ++ * @return Effect with the given name ++ */ ++ public static Effect getByName(String name) { ++ return BY_NAME.get(name); ++ } ++ ++ static { ++ for (Effect effect : values()) { ++ if (effect.type == Type.PARTICLE) { ++ BY_NAME.put(effect.particleName, effect); ++ } + } + } + + /** + * Represents the type of an effect. + */ +- public enum Type {SOUND, VISUAL} ++ public enum Type {SOUND, VISUAL, PARTICLE} + } +diff --git a/src/main/java/org/bukkit/World.java b/src/main/java/org/bukkit/World.java +index e14fe40..9ae9b2d 100644 +--- a/src/main/java/org/bukkit/World.java ++++ b/src/main/java/org/bukkit/World.java +@@ -1063,6 +1063,56 @@ public interface World extends PluginMessageRecipient, Metadatable { + */ + public boolean isGameRule(String rule); + ++ // Spigot start ++ public class Spigot ++ { ++ ++ /** ++ * Plays an effect to all players within a default radius around a given ++ * location. ++ * ++ * @param location the {@link Location} around which players must be to ++ * see the effect ++ * @param effect the {@link Effect} ++ * @throws IllegalArgumentException if the location or effect is null. ++ * It also throws when the effect requires a material or a material data ++ */ ++ public void playEffect(Location location, Effect effect) ++ { ++ throw new UnsupportedOperationException( "Not supported yet." ); ++ } ++ ++ /** ++ * Plays an effect to all players within a default radius around a given ++ * location. The effect will use the provided material (and material ++ * data if required). The particle's position on the client will be the ++ * given location, adjusted on each axis by a normal distribution with ++ * mean 0 and standard deviation given in the offset parameters, each ++ * particle has independently calculated offsets. The effect will have ++ * the given speed and particle count if the effect is a particle. Some ++ * effect will create multiple particles. ++ * ++ * @param location the {@link Location} around which players must be to ++ * see the effect ++ * @param effect effect the {@link Effect} ++ * @param id the item/block/data id for the effect ++ * @param data the data value of the block/item for the effect ++ * @param offsetX the amount to be randomly offset by in the X axis ++ * @param offsetY the amount to be randomly offset by in the Y axis ++ * @param offsetZ the amount to be randomly offset by in the Z axis ++ * @param speed the speed of the particles ++ * @param particleCount the number of particles ++ * @param radius the radius around the location ++ */ ++ public void playEffect(Location location, Effect effect, int id, int data, float offsetX, float offsetY, float offsetZ, float speed, int particleCount, int radius) ++ { ++ throw new UnsupportedOperationException( "Not supported yet." ); ++ } ++ } ++ ++ Spigot spigot(); ++ // Spigot end ++ + /** + * Represents various map environment types that a world may be + */ +diff --git a/src/main/java/org/bukkit/entity/Player.java b/src/main/java/org/bukkit/entity/Player.java +index 0c46c84..5b2d0f9 100644 +--- a/src/main/java/org/bukkit/entity/Player.java ++++ b/src/main/java/org/bukkit/entity/Player.java +@@ -661,6 +661,11 @@ public interface Player extends HumanEntity, Conversable, CommandSender, Offline + { + throw new UnsupportedOperationException( "Not supported yet." ); + } ++ ++ public void playEffect(Location location, Effect effect, int id, int data, float offsetX, float offsetY, float offsetZ, float speed, int particleCount, int radius) ++ { ++ throw new UnsupportedOperationException( "Not supported yet." ); ++ } + } + + Spigot spigot(); +diff --git a/src/test/java/org/bukkit/EffectTest.java b/src/test/java/org/bukkit/EffectTest.java +index 08aa71d..5217aec 100644 +--- a/src/test/java/org/bukkit/EffectTest.java ++++ b/src/test/java/org/bukkit/EffectTest.java +@@ -9,7 +9,11 @@ public class EffectTest { + @Test + public void getById() { + for (Effect effect : Effect.values()) { +- assertThat(Effect.getById(effect.getId()), is(effect)); ++ if (effect.getType() != Effect.Type.PARTICLE) { ++ assertThat(Effect.getById(effect.getId()), is(effect)); ++ } else { ++ assertThat(Effect.getByName(effect.getName()), is(effect)); ++ } + } + } + } +-- +1.8.1.2 + diff --git a/CraftBukkit-Patches/0002-mc-dev-imports.patch b/CraftBukkit-Patches/0002-mc-dev-imports.patch index 525a76d13..b1cd24a89 100644 --- a/CraftBukkit-Patches/0002-mc-dev-imports.patch +++ b/CraftBukkit-Patches/0002-mc-dev-imports.patch @@ -1,4 +1,4 @@ -From 6d8f5f571b3642bee78a65ad7cf14e915d1386d3 Mon Sep 17 00:00:00 2001 +From ab1f4060dfec54383427f22f29da6ea2c0ae49c9 Mon Sep 17 00:00:00 2001 From: md_5 Date: Wed, 10 Apr 2013 13:52:52 +1000 Subject: [PATCH] mc-dev imports @@ -385,6 +385,63 @@ index 0000000..53c1cb5 + } + } +} +diff --git a/src/main/java/net/minecraft/server/Packet63WorldParticles.java b/src/main/java/net/minecraft/server/Packet63WorldParticles.java +new file mode 100644 +index 0000000..8c86b03 +--- /dev/null ++++ b/src/main/java/net/minecraft/server/Packet63WorldParticles.java +@@ -0,0 +1,51 @@ ++package net.minecraft.server; ++ ++import java.io.DataInputStream; ++import java.io.DataOutputStream; ++ ++public class Packet63WorldParticles extends Packet { ++ ++ private String a; ++ private float b; ++ private float c; ++ private float d; ++ private float e; ++ private float f; ++ private float g; ++ private float h; ++ private int i; ++ ++ public Packet63WorldParticles() {} ++ ++ public void a(DataInputStream datainputstream) { ++ this.a = a(datainputstream, 64); ++ this.b = datainputstream.readFloat(); ++ this.c = datainputstream.readFloat(); ++ this.d = datainputstream.readFloat(); ++ this.e = datainputstream.readFloat(); ++ this.f = datainputstream.readFloat(); ++ this.g = datainputstream.readFloat(); ++ this.h = datainputstream.readFloat(); ++ this.i = datainputstream.readInt(); ++ } ++ ++ public void a(DataOutputStream dataoutputstream) { ++ a(this.a, dataoutputstream); ++ dataoutputstream.writeFloat(this.b); ++ dataoutputstream.writeFloat(this.c); ++ dataoutputstream.writeFloat(this.d); ++ dataoutputstream.writeFloat(this.e); ++ dataoutputstream.writeFloat(this.f); ++ dataoutputstream.writeFloat(this.g); ++ dataoutputstream.writeFloat(this.h); ++ dataoutputstream.writeInt(this.i); ++ } ++ ++ public void handle(Connection connection) { ++ connection.a(this); ++ } ++ ++ public int a() { ++ return 64; ++ } ++} diff --git a/src/main/java/net/minecraft/server/RegionFileCache.java b/src/main/java/net/minecraft/server/RegionFileCache.java new file mode 100644 index 0000000..900ed68 @@ -459,5 +516,5 @@ index 0000000..900ed68 + } +} -- -1.8.2.1 +1.8.1.2 diff --git a/CraftBukkit-Patches/0003-Skeleton-API-Implementations.patch b/CraftBukkit-Patches/0003-Skeleton-API-Implementations.patch index 6e48b112f..b1ce4e6ce 100644 --- a/CraftBukkit-Patches/0003-Skeleton-API-Implementations.patch +++ b/CraftBukkit-Patches/0003-Skeleton-API-Implementations.patch @@ -1,9 +1,28 @@ -From 422434f8916ce03d16987970843cd154bb4a7676 Mon Sep 17 00:00:00 2001 +From 3660fbe432c9b7116ea02a93e7b43d7b47675fdf Mon Sep 17 00:00:00 2001 From: md_5 Date: Sun, 2 Jun 2013 15:10:56 +1000 Subject: [PATCH] Skeleton API Implementations +diff --git a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java +index 6c7f570..c0fb528 100644 +--- a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java ++++ b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java +@@ -1263,4 +1263,14 @@ public class CraftWorld implements World { + cps.queueUnload(chunk.x, chunk.z); + } + } ++ // Spigot start ++ private final Spigot spigot = new Spigot() ++ { ++ }; ++ ++ public Spigot spigot() ++ { ++ return spigot; ++ } ++ // Spigot end + } diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftArrow.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftArrow.java index b46b9c4..c91b12c 100644 --- a/src/main/java/org/bukkit/craftbukkit/entity/CraftArrow.java diff --git a/CraftBukkit-Patches/0049-Particle-API.patch b/CraftBukkit-Patches/0049-Particle-API.patch new file mode 100644 index 000000000..ecda546ce --- /dev/null +++ b/CraftBukkit-Patches/0049-Particle-API.patch @@ -0,0 +1,251 @@ +From 168d2da67ba73638c687d0b8e00b741e82aaccf3 Mon Sep 17 00:00:00 2001 +From: thinkofdeath +Date: Sun, 2 Jun 2013 16:14:30 +1000 +Subject: [PATCH] Particle API + + +diff --git a/src/main/java/net/minecraft/server/Packet63WorldParticles.java b/src/main/java/net/minecraft/server/Packet63WorldParticles.java +index 8c86b03..fa3af32 100644 +--- a/src/main/java/net/minecraft/server/Packet63WorldParticles.java ++++ b/src/main/java/net/minecraft/server/Packet63WorldParticles.java +@@ -17,7 +17,21 @@ public class Packet63WorldParticles extends Packet { + + public Packet63WorldParticles() {} + +- public void a(DataInputStream datainputstream) { ++ // Spigot start - Added constructor ++ public Packet63WorldParticles(String particleName, float x, float y, float z, float offsetX, float offsetY, float offsetZ, float speed, int count) { ++ a = particleName; ++ b = x; ++ c = y; ++ d = z; ++ e = offsetX; ++ f = offsetY; ++ g = offsetZ; ++ h = speed; ++ i = count; ++ } ++ // Spigot end ++ ++ public void a(DataInputStream datainputstream) throws java.io.IOException { // Spigot - throws IOException + this.a = a(datainputstream, 64); + this.b = datainputstream.readFloat(); + this.c = datainputstream.readFloat(); +@@ -29,7 +43,7 @@ public class Packet63WorldParticles extends Packet { + this.i = datainputstream.readInt(); + } + +- public void a(DataOutputStream dataoutputstream) { ++ public void a(DataOutputStream dataoutputstream) throws java.io.IOException { // Spigot - throws IOException + a(this.a, dataoutputstream); + dataoutputstream.writeFloat(this.b); + dataoutputstream.writeFloat(this.c); +diff --git a/src/main/java/org/bukkit/craftbukkit/CraftEffect.java b/src/main/java/org/bukkit/craftbukkit/CraftEffect.java +index 7de0de5..7eca388 100644 +--- a/src/main/java/org/bukkit/craftbukkit/CraftEffect.java ++++ b/src/main/java/org/bukkit/craftbukkit/CraftEffect.java +@@ -55,6 +55,8 @@ public class CraftEffect { + Validate.isTrue(((Material) data).isBlock(), "Material is not a block!"); + datavalue = ((Material) data).getId(); + break; ++ case ITEM_BREAK: ++ datavalue = ((Material) data).getId(); + default: + datavalue = 0; + } +diff --git a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java +index f07982d..f6646da 100644 +--- a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java ++++ b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java +@@ -887,31 +887,21 @@ public class CraftWorld implements World { + } else { + Validate.isTrue(effect.getData() == null, "Wrong kind of data for this effect!"); + } +- +- int datavalue = data == null ? 0 : CraftEffect.getDataValue(effect, data); +- playEffect(loc, effect, datavalue, radius); ++ if (data.getClass().equals(org.bukkit.material.MaterialData.class)) { ++ org.bukkit.material.MaterialData materialData = (org.bukkit.material.MaterialData) data; ++ Validate.isTrue(!materialData.getItemType().isBlock(), "Material must be block"); ++ spigot().playEffect(loc, effect, materialData.getItemType().getId(), materialData.getData(), 0, 0, 0, 1, 1, radius); ++ } else { ++ int datavalue = data == null ? 0 : CraftEffect.getDataValue(effect, data); ++ playEffect(loc, effect, datavalue, radius); ++ } + } + + public void playEffect(Location location, Effect effect, int data, int radius) { +- Validate.notNull(location, "Location cannot be null"); +- Validate.notNull(effect, "Effect cannot be null"); +- Validate.notNull(location.getWorld(), "World cannot be null"); +- int packetData = effect.getId(); +- Packet61WorldEvent packet = new Packet61WorldEvent(packetData, location.getBlockX(), location.getBlockY(), location.getBlockZ(), data, false); +- int distance; +- radius *= radius; +- +- for (Player player : getPlayers()) { +- if (((CraftPlayer) player).getHandle().playerConnection == null) continue; +- if (!location.getWorld().equals(player.getWorld())) continue; +- +- distance = (int) player.getLocation().distanceSquared(location); +- if (distance <= radius) { +- ((CraftPlayer) player).getHandle().playerConnection.sendPacket(packet); +- } +- } ++ spigot().playEffect(location,effect, data, 0, 0f, 0f, 0f, 1f, 1, radius); + } + ++ + public T spawn(Location location, Class clazz) throws IllegalArgumentException { + return spawn(location, clazz, SpawnReason.CUSTOM); + } +@@ -1390,6 +1380,62 @@ public class CraftWorld implements World { + // Spigot start + private final Spigot spigot = new Spigot() + { ++ @Override ++ public void playEffect(Location location, Effect effect, int id, int data, float offsetX, float offsetY, float offsetZ, float speed, int particleCount, int radius) ++ { ++ Validate.notNull( location, "Location cannot be null" ); ++ Validate.notNull( effect, "Effect cannot be null" ); ++ Validate.notNull( location.getWorld(), "World cannot be null" ); ++ ++ Packet packet; ++ if ( effect.getType() != Effect.Type.PARTICLE ) ++ { ++ int packetData = effect.getId(); ++ packet = new Packet61WorldEvent( packetData, location.getBlockX(), location.getBlockY(), location.getBlockZ(), id, false ); ++ } else ++ { ++ StringBuilder particleFullName = new StringBuilder(); ++ particleFullName.append( effect.getName() ); ++ ++ if ( effect.getData().equals( Material.class ) || effect.getData().equals( org.bukkit.material.MaterialData.class ) ) ++ { ++ particleFullName.append( '_' ).append( id ); ++ } ++ ++ if ( effect.getData().equals( org.bukkit.material.MaterialData.class ) ) ++ { ++ particleFullName.append( '_' ).append( data ); ++ } ++ packet = new Packet63WorldParticles( effect.getName(), (float) location.getX(), (float) location.getY(), (float) location.getZ(), offsetX, offsetY, offsetZ, particleCount, radius ); ++ } ++ ++ int distance; ++ radius *= radius; ++ ++ for ( Player player : getPlayers() ) ++ { ++ if ( ( (CraftPlayer) player ).getHandle().playerConnection == null ) ++ { ++ continue; ++ } ++ if ( !location.getWorld().equals( player.getWorld() ) ) ++ { ++ continue; ++ } ++ ++ distance = (int) player.getLocation().distanceSquared( location ); ++ if ( distance <= radius ) ++ { ++ ( (CraftPlayer) player ).getHandle().playerConnection.sendPacket( packet ); ++ } ++ } ++ } ++ ++ @Override ++ public void playEffect(Location location, Effect effect) ++ { ++ playEffect( location, effect, 0 ); ++ } + }; + + public Spigot spigot() +diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java +index 3d39d07..140b06f 100644 +--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java ++++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java +@@ -266,13 +266,11 @@ public class CraftPlayer extends CraftHumanEntity implements Player { + getHandle().playerConnection.sendPacket(packet); + } + +- public void playEffect(Location loc, Effect effect, int data) { +- if (getHandle().playerConnection == null) return; +- +- int packetData = effect.getId(); +- Packet61WorldEvent packet = new Packet61WorldEvent(packetData, loc.getBlockX(), loc.getBlockY(), loc.getBlockZ(), data, false); +- getHandle().playerConnection.sendPacket(packet); ++ // Spigot start ++ public void playEffect(Location location, Effect effect, int data) { ++ spigot().playEffect(location, effect, data, 0, 0f, 0f, 0f, 1f, 1, 64); + } ++ // Spigot end + + public void playEffect(Location loc, Effect effect, T data) { + if (data != null) { +@@ -280,9 +278,14 @@ public class CraftPlayer extends CraftHumanEntity implements Player { + } else { + Validate.isTrue(effect.getData() == null, "Wrong kind of data for this effect!"); + } +- +- int datavalue = data == null ? 0 : CraftEffect.getDataValue(effect, data); +- playEffect(loc, effect, datavalue); ++ if (data.getClass().equals(org.bukkit.material.MaterialData.class)) { ++ org.bukkit.material.MaterialData materialData = (org.bukkit.material.MaterialData) data; ++ Validate.isTrue(!materialData.getItemType().isBlock(), "Material must be block"); ++ spigot().playEffect(loc, effect, materialData.getItemType().getId(), materialData.getData(), 0, 0, 0, 1, 1, 64); ++ } else { ++ int datavalue = data == null ? 0 : CraftEffect.getDataValue(effect, data); ++ playEffect(loc, effect, datavalue); ++ } + } + + public void sendBlockChange(Location loc, Material material, byte data) { +@@ -1021,6 +1024,43 @@ public class CraftPlayer extends CraftHumanEntity implements Player { + { + return ( getHandle().playerConnection == null ) ? null : (InetSocketAddress) getHandle().playerConnection.networkManager.getSocket().getRemoteSocketAddress(); + } ++ ++ @Override ++ public void playEffect(Location location, Effect effect, int id, int data, float offsetX, float offsetY, float offsetZ, float speed, int particleCount, int radius) ++ { ++ Validate.notNull( location, "Location cannot be null" ); ++ Validate.notNull( effect, "Effect cannot be null" ); ++ Validate.notNull( location.getWorld(), "World cannot be null" ); ++ ++ Packet packet; ++ if ( effect.getType() != Effect.Type.PARTICLE ) ++ { ++ int packetData = effect.getId(); ++ packet = new Packet61WorldEvent( packetData, location.getBlockX(), location.getBlockY(), location.getBlockZ(), id, false ); ++ } else ++ { ++ StringBuilder particleFullName = new StringBuilder(); ++ particleFullName.append( effect.getName() ); ++ ++ if ( effect.getData() != null && ( effect.getData().equals( Material.class ) || effect.getData().equals( org.bukkit.material.MaterialData.class ) ) ) ++ { ++ particleFullName.append( '_' ).append( id ); ++ } ++ ++ if ( effect.getData() != null && effect.getData().equals( org.bukkit.material.MaterialData.class ) ) ++ { ++ particleFullName.append( '_' ).append( data ); ++ } ++ packet = new Packet63WorldParticles( effect.getName(), (float) location.getX(), (float) location.getY(), (float) location.getZ(), offsetX, offsetY, offsetZ, particleCount, radius ); ++ } ++ ++ if ( !location.getWorld().equals( getWorld() ) ) ++ { ++ return; ++ } ++ ++ getHandle().playerConnection.sendPacket( packet ); ++ } + }; + + public Spigot spigot() +-- +1.8.1.2 +