diff --git a/src/main/java/org/bukkit/craftbukkit/CraftEffect.java b/src/main/java/org/bukkit/craftbukkit/CraftEffect.java
new file mode 100644
index 0000000000..9a96e53549
--- /dev/null
+++ b/src/main/java/org/bukkit/craftbukkit/CraftEffect.java
@@ -0,0 +1,63 @@
+package org.bukkit.craftbukkit;
+
+import org.apache.commons.lang.Validate;
+import org.bukkit.Effect;
+import org.bukkit.Material;
+import org.bukkit.block.BlockFace;
+import org.bukkit.potion.Potion;
+
+public class CraftEffect {
+    public static <T> int getDataValue(Effect effect, T data) {
+        int datavalue;
+        switch(effect) {
+        case POTION_BREAK:
+            datavalue = ((Potion) data).toDamageValue() & 0x3F;
+            break;
+        case RECORD_PLAY:
+            Validate.isTrue(((Material) data).isRecord(), "Invalid record type!");
+            datavalue = ((Material) data).getId();
+            break;
+        case SMOKE:
+            switch((BlockFace)data) {
+            case SOUTH_EAST:
+                datavalue = 0;
+                break;
+            case SOUTH:
+                datavalue = 1;
+                break;
+            case SOUTH_WEST:
+                datavalue = 2;
+                break;
+            case EAST:
+                datavalue = 3;
+                break;
+            case UP:
+            case SELF:
+                datavalue = 4;
+                break;
+            case WEST:
+                datavalue = 5;
+                break;
+            case NORTH_EAST:
+                datavalue = 6;
+                break;
+            case NORTH:
+                datavalue = 7;
+                break;
+            case NORTH_WEST:
+                datavalue = 8;
+                break;
+            default:
+                throw new IllegalArgumentException("Bad smoke direction!");
+            }
+            break;
+        case STEP_SOUND:
+            Validate.isTrue(((Material) data).isBlock(), "Material is not a block!");
+            datavalue = ((Material) data).getId();
+            break;
+        default:
+            datavalue = 0;
+        }
+        return datavalue;
+    }
+}
diff --git a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java
index f5d565348b..ffc55df2ad 100644
--- a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java
+++ b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java
@@ -39,6 +39,7 @@ import org.bukkit.Bukkit;
 import org.bukkit.generator.ChunkGenerator;
 import org.bukkit.ChunkSnapshot;
 import org.bukkit.Location;
+import org.bukkit.Material;
 import org.bukkit.TreeType;
 import org.bukkit.World;
 import org.bukkit.block.Biome;
@@ -47,6 +48,7 @@ import org.bukkit.Difficulty;
 import org.bukkit.craftbukkit.block.CraftBlock;
 import org.bukkit.craftbukkit.inventory.CraftItemStack;
 import org.bukkit.plugin.messaging.StandardMessenger;
+import org.bukkit.potion.Potion;
 
 public class CraftWorld implements World {
     private final WorldServer world;
@@ -717,6 +719,21 @@ public class CraftWorld implements World {
         playEffect(location, effect, data, 64);
     }
 
+    public <T> void playEffect(Location loc, Effect effect, T data) {
+        playEffect(loc, effect, data, 64);
+    }
+
+    public <T> void playEffect(Location loc, Effect effect, T data, int radius) {
+        if (data != null) {
+            Validate.isTrue(data.getClass().equals(effect.getData()), "Wrong kind of data for this effect!");
+        } 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);
+    }
+
     public void playEffect(Location location, Effect effect, int data, int radius) {
         int packetData = effect.getId();
         Packet61WorldEvent packet = new Packet61WorldEvent(packetData, location.getBlockX(), location.getBlockY(), location.getBlockZ(), data);
diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
index 03c75d64bc..0be3c7e28f 100644
--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
@@ -14,12 +14,16 @@ import java.util.Set;
 import java.util.logging.Level;
 import java.util.logging.Logger;
 import net.minecraft.server.*;
+
+import org.apache.commons.lang.Validate;
 import org.bukkit.*;
 import org.bukkit.Achievement;
 import org.bukkit.Material;
 import org.bukkit.Statistic;
 import org.bukkit.World;
+import org.bukkit.block.BlockFace;
 import org.bukkit.configuration.serialization.DelegateDeserialization;
+import org.bukkit.craftbukkit.CraftEffect;
 import org.bukkit.craftbukkit.CraftOfflinePlayer;
 import org.bukkit.craftbukkit.CraftServer;
 import org.bukkit.craftbukkit.CraftWorld;
@@ -33,6 +37,7 @@ import org.bukkit.map.MapView;
 import org.bukkit.metadata.MetadataValue;
 import org.bukkit.plugin.Plugin;
 import org.bukkit.plugin.messaging.StandardMessenger;
+import org.bukkit.potion.Potion;
 
 @DelegateDeserialization(CraftOfflinePlayer.class)
 public class CraftPlayer extends CraftHumanEntity implements Player {
@@ -227,6 +232,17 @@ public class CraftPlayer extends CraftHumanEntity implements Player {
         getHandle().netServerHandler.sendPacket(packet);
     }
 
+    public <T> void playEffect(Location loc, Effect effect, T data) {
+        if (data != null) {
+            Validate.isTrue(data.getClass().equals(effect.getData()), "Wrong kind of data for this effect!");
+        } 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);
+    }
+
     public void sendBlockChange(Location loc, Material material, byte data) {
         sendBlockChange(loc, material.getId(), data);
     }