diff --git a/src/main/java/net/minecraft/server/Block.java b/src/main/java/net/minecraft/server/Block.java
index 0cd743ce90..ede8508752 100644
--- a/src/main/java/net/minecraft/server/Block.java
+++ b/src/main/java/net/minecraft/server/Block.java
@@ -164,6 +164,7 @@ public class Block {
     public final Material material;
     public float frictionFactor;
     private String name;
+    protected ArrayList<ItemStack> dropList; // CraftBukkit
 
     protected Block(int i, Material material) {
         this.bR = true;
@@ -358,6 +359,17 @@ public class Block {
     }
 
     protected void a(World world, int i, int j, int k, ItemStack itemstack) {
+        // CraftBukkit start - the logic of this function is moved into finishDrop
+        if (this.dropList != null) {
+            this.dropList.add(itemstack);
+        } else {
+            this.finishDrop(world, i, j, k, itemstack);
+        }
+    }
+
+    public final void finishDrop(World world, int i, int j, int k, ItemStack itemstack) {
+        this.dropList = null;
+        // CraftBukkit end
         if (!world.isStatic) {
             float f = 0.7F;
             double d0 = (double) (world.random.nextFloat() * f) + (double) (1.0F - f) * 0.5D;
@@ -529,6 +541,23 @@ public class Block {
     public void a(World world, EntityHuman entityhuman, int i, int j, int k, int l) {
         entityhuman.a(StatisticList.C[this.id], 1);
         entityhuman.c(0.025F);
+        // CraftBukkit start - A way to separate statistics from the logic of determining what to drop
+        this.doActualDrop(world, entityhuman, i, j, k, l);
+    }
+
+    public void doActualDrop(World world, EntityHuman entityhuman, int i, int j, int k, int l) {
+        for (ItemStack stack : dropList) {
+            finishDrop(world, i, j, k, stack);
+        }
+    }
+
+    public void setDrops(ArrayList<ItemStack> drops) {
+        this.dropList = drops;
+    }
+
+    public ArrayList<ItemStack> calculateDrops(World world, EntityHuman entityhuman, int i, int j, int k, int l) {
+        this.dropList = new ArrayList<ItemStack>();
+        // CraftBukkit end
         if (this.b() && !this.isTileEntity && EnchantmentManager.hasSilkTouchEnchantment(entityhuman.inventory)) {
             ItemStack itemstack = this.a_(l);
 
@@ -540,6 +569,7 @@ public class Block {
 
             this.b(world, i, j, k, l, i1);
         }
+        return this.dropList; // CraftBukkit
     }
 
     protected ItemStack a_(int i) {
diff --git a/src/main/java/net/minecraft/server/BlockBed.java b/src/main/java/net/minecraft/server/BlockBed.java
index 68232ad830..cc93b4caf8 100644
--- a/src/main/java/net/minecraft/server/BlockBed.java
+++ b/src/main/java/net/minecraft/server/BlockBed.java
@@ -129,14 +129,16 @@ public class BlockBed extends BlockDirectional {
             }
         } else if (world.getTypeId(i + a[j1][0], j, k + a[j1][1]) != this.id) {
             world.setTypeId(i, j, k, 0);
+            /* CraftBukkit - Move this to on break instead of on physics
             if (!world.isStatic) {
                 this.b(world, i, j, k, i1, 0);
             }
+            // */
         }
     }
 
     public int getDropType(int i, Random random, int j) {
-        return d(i) ? 0 : Item.BED.id;
+        return /* d(i) ? 0 CraftBukkit : */ Item.BED.id;
     }
 
     private void s() {
@@ -190,9 +192,9 @@ public class BlockBed extends BlockDirectional {
     }
 
     public void dropNaturally(World world, int i, int j, int k, int l, float f, int i1) {
-        if (!d(l)) {
+        //if (!d(l)) { // CraftBukkit
             super.dropNaturally(world, i, j, k, l, f, 0);
-        }
+        // } // CraftBukkit
     }
 
     public int g() {
diff --git a/src/main/java/net/minecraft/server/BlockCrops.java b/src/main/java/net/minecraft/server/BlockCrops.java
index dfdbc746a3..eafc2d7b4a 100644
--- a/src/main/java/net/minecraft/server/BlockCrops.java
+++ b/src/main/java/net/minecraft/server/BlockCrops.java
@@ -96,6 +96,7 @@ public class BlockCrops extends BlockFlower {
 
             for (int k1 = 0; k1 < j1; ++k1) {
                 if (world.random.nextInt(15) <= l) {
+                    /* CraftBukkit start - Identical logic to superclass method; defer to that method
                     float f1 = 0.7F;
                     float f2 = world.random.nextFloat() * f1 + (1.0F - f1) * 0.5F;
                     float f3 = world.random.nextFloat() * f1 + (1.0F - f1) * 0.5F;
@@ -104,6 +105,8 @@ public class BlockCrops extends BlockFlower {
 
                     entityitem.pickupDelay = 10;
                     world.addEntity(entityitem);
+                    // */
+                    this.a(world, i, j, k, new ItemStack(Item.SEEDS));
                 }
             }
         }
diff --git a/src/main/java/net/minecraft/server/BlockDeadBush.java b/src/main/java/net/minecraft/server/BlockDeadBush.java
index d6e4597a55..9b0c89f8d7 100644
--- a/src/main/java/net/minecraft/server/BlockDeadBush.java
+++ b/src/main/java/net/minecraft/server/BlockDeadBush.java
@@ -1,5 +1,6 @@
 package net.minecraft.server;
 
+import java.util.ArrayList; // CraftBukkit
 import java.util.Random;
 
 public class BlockDeadBush extends BlockFlower {
@@ -26,9 +27,25 @@ public class BlockDeadBush extends BlockFlower {
     public void a(World world, EntityHuman entityhuman, int i, int j, int k, int l) {
         if (!world.isStatic && entityhuman.T() != null && entityhuman.T().id == Item.SHEARS.id) {
             entityhuman.a(StatisticList.C[this.id], 1);
+            /* CraftBukkit start - moved this line into calculateDrops
             this.a(world, i, j, k, new ItemStack(Block.DEAD_BUSH, 1, l));
+            */
+            this.doActualDrop(world, entityhuman, i, j, k, l);
+            // CraftBukkit end
         } else {
             super.a(world, entityhuman, i, j, k, l);
         }
     }
+
+    // CraftBukkit start - Calculate drops
+    public ArrayList<ItemStack> calculateDrops(World world, EntityHuman entityhuman, int i, int j, int k, int l) {
+        if (!world.isStatic && entityhuman.T() != null && entityhuman.T().id == Item.SHEARS.id) {
+            super.dropList = new ArrayList<ItemStack>();
+            this.a(world, i, j, k, new ItemStack(Block.DEAD_BUSH, 1, l));
+            return super.dropList;
+        } else {
+            return super.calculateDrops(world, entityhuman, i, j, k, l);
+        }
+    }
+    // CraftBukkit end
 }
diff --git a/src/main/java/net/minecraft/server/BlockDoor.java b/src/main/java/net/minecraft/server/BlockDoor.java
index 8ce6fc8d4a..1b81e4664a 100644
--- a/src/main/java/net/minecraft/server/BlockDoor.java
+++ b/src/main/java/net/minecraft/server/BlockDoor.java
@@ -169,10 +169,11 @@ public class BlockDoor extends Block {
             }
 
             if (flag) {
+            /* CraftBukkit start - Move the drop to on break instead of on physics
                 if (!world.isStatic) {
                     this.b(world, i, j, k, i1, 0);
                 }
-            // CraftBukkit start
+                // */
             } else if (l > 0 && Block.byId[l].isPowerSource()) {
                 org.bukkit.World bworld = world.getWorld();
                 org.bukkit.block.Block block = bworld.getBlockAt(i, j, k);
@@ -195,7 +196,7 @@ public class BlockDoor extends Block {
     }
 
     public int getDropType(int i, Random random, int j) {
-        return (i & 8) != 0 ? 0 : (this.material == Material.ORE ? Item.IRON_DOOR.id : Item.WOOD_DOOR.id);
+        return /* (i & 8) != 0 ? 0 CraftBukkit : */ (this.material == Material.ORE ? Item.IRON_DOOR.id : Item.WOOD_DOOR.id);
     }
 
     public MovingObjectPosition a(World world, int i, int j, int k, Vec3D vec3d, Vec3D vec3d1) {
diff --git a/src/main/java/net/minecraft/server/BlockLeaves.java b/src/main/java/net/minecraft/server/BlockLeaves.java
index 1f2590b67a..3daf419315 100644
--- a/src/main/java/net/minecraft/server/BlockLeaves.java
+++ b/src/main/java/net/minecraft/server/BlockLeaves.java
@@ -1,5 +1,6 @@
 package net.minecraft.server;
 
+import java.util.ArrayList; // CraftBukkit
 import java.util.Random;
 
 import org.bukkit.event.block.LeavesDecayEvent; // CraftBukkit
@@ -161,12 +162,28 @@ public class BlockLeaves extends BlockTransparant {
     public void a(World world, EntityHuman entityhuman, int i, int j, int k, int l) {
         if (!world.isStatic && entityhuman.T() != null && entityhuman.T().id == Item.SHEARS.id) {
             entityhuman.a(StatisticList.C[this.id], 1);
+            /* CraftBukkit start - moved this line into calculateDrops
             this.a(world, i, j, k, new ItemStack(Block.LEAVES.id, 1, l & 3));
+            */
+            this.doActualDrop(world, entityhuman, i, j, k, l);
+            // CraftBukkit end
         } else {
             super.a(world, entityhuman, i, j, k, l);
         }
     }
 
+    // CraftBukkit start - Calculate drops
+    public ArrayList<ItemStack> calculateDrops(World world, EntityHuman entityhuman, int i, int j, int k, int l) {
+        if (!world.isStatic && entityhuman.T() != null && entityhuman.T().id == Item.SHEARS.id) {
+            super.dropList = new ArrayList<ItemStack>();
+            this.a(world, i, j, k, new ItemStack(Block.LEAVES.id, 1, l & 3));
+            return super.dropList;
+        } else {
+            return super.calculateDrops(world, entityhuman, i, j, k, l);
+        }
+    }
+    // CraftBukkit end
+
     protected int getDropData(int i) {
         return i & 3;
     }
diff --git a/src/main/java/net/minecraft/server/BlockLongGrass.java b/src/main/java/net/minecraft/server/BlockLongGrass.java
index 2f192f54da..b5875e16f8 100644
--- a/src/main/java/net/minecraft/server/BlockLongGrass.java
+++ b/src/main/java/net/minecraft/server/BlockLongGrass.java
@@ -1,5 +1,6 @@
 package net.minecraft.server;
 
+import java.util.ArrayList; // CraftBukkit
 import java.util.Random;
 
 public class BlockLongGrass extends BlockFlower {
@@ -26,9 +27,25 @@ public class BlockLongGrass extends BlockFlower {
     public void a(World world, EntityHuman entityhuman, int i, int j, int k, int l) {
         if (!world.isStatic && entityhuman.T() != null && entityhuman.T().id == Item.SHEARS.id) {
             entityhuman.a(StatisticList.C[this.id], 1);
+            /* CraftBukkit start - moved this line into calculateDrops
             this.a(world, i, j, k, new ItemStack(Block.LONG_GRASS, 1, l));
+            */
+            this.doActualDrop(world, entityhuman, i, j, k, l);
+            // CraftBukkit end
         } else {
             super.a(world, entityhuman, i, j, k, l);
         }
     }
+
+    // CraftBukkit start - Calculate drops
+    public ArrayList<ItemStack> calculateDrops(World world, EntityHuman entityhuman, int i, int j, int k, int l) {
+        if (!world.isStatic && entityhuman.T() != null && entityhuman.T().id == Item.SHEARS.id) {
+            super.dropList = new ArrayList<ItemStack>();
+            this.a(world, i, j, k, new ItemStack(Block.LONG_GRASS, 1, l));
+            return super.dropList;
+        } else {
+            return super.calculateDrops(world, entityhuman, i, j, k, l);
+        }
+    }
+    // CraftBukkit end
 }
diff --git a/src/main/java/net/minecraft/server/BlockPistonExtension.java b/src/main/java/net/minecraft/server/BlockPistonExtension.java
index e6a7b186e0..28adc7f345 100644
--- a/src/main/java/net/minecraft/server/BlockPistonExtension.java
+++ b/src/main/java/net/minecraft/server/BlockPistonExtension.java
@@ -13,9 +13,28 @@ public class BlockPistonExtension extends Block {
         this.c(0.5F);
     }
 
+    // CraftBukkit start - Support getDrops() in BlockBreakEvent
+    public ArrayList<ItemStack> calculateDrops(World world, EntityHuman entityhuman, int i, int j, int k, int d) {
+        super.calculateDrops(world, entityhuman, i, j, k, d);
+        int l = world.getData(i, j, k) & 0x7;
+        if (l > 5 || l < 0) return super.dropList;
+        int i1 = Facing.OPPOSITE_FACING[b(l)];
+
+        i += Facing.b[i1];
+        j += Facing.c[i1];
+        k += Facing.d[i1];
+        int j1 = world.getTypeId(i, j, k);
+
+        if (j1 == Block.PISTON.id || j1 == Block.PISTON_STICKY.id) {
+            super.dropList.add(new ItemStack(Block.byId[j1], 1));
+        }
+        return super.dropList;
+    }
+    // CraftBukkit end
+
     public void remove(World world, int i, int j, int k) {
         super.remove(world, i, j, k);
-        int l = world.getData(i, j, k);
+        int l = world.getData(i, j, k) & 0x7;
         if (l > 5 || l < 0) return; // CraftBukkit - fixed a piston AIOOBE issue.
         int i1 = Facing.OPPOSITE_FACING[b(l)];
 
@@ -27,7 +46,7 @@ public class BlockPistonExtension extends Block {
         if (j1 == Block.PISTON.id || j1 == Block.PISTON_STICKY.id) {
             l = world.getData(i, j, k);
             if (BlockPiston.e(l)) {
-                Block.byId[j1].b(world, i, j, k, l, 0);
+                //Block.byId[j1].b(world, i, j, k, l, 0); // CraftBukkit - drop moved into drop list
                 world.setTypeId(i, j, k, 0);
             }
         }
diff --git a/src/main/java/net/minecraft/server/BlockSnow.java b/src/main/java/net/minecraft/server/BlockSnow.java
index ca871116e7..3c6cfe1597 100644
--- a/src/main/java/net/minecraft/server/BlockSnow.java
+++ b/src/main/java/net/minecraft/server/BlockSnow.java
@@ -1,5 +1,6 @@
 package net.minecraft.server;
 
+import java.util.ArrayList; // CraftBukkit
 import java.util.Random;
 import org.bukkit.craftbukkit.event.CraftEventFactory;
 
@@ -54,19 +55,32 @@ public class BlockSnow extends Block {
     }
 
     public void a(World world, EntityHuman entityhuman, int i, int j, int k, int l) {
+        /* CraftBukkit start - This logic is exactly the same as in the superclass method, so defer it there
         int i1 = Item.SNOW_BALL.id;
         float f = 0.7F;
         double d0 = (double) (world.random.nextFloat() * f) + (double) (1.0F - f) * 0.5D;
         double d1 = (double) (world.random.nextFloat() * f) + (double) (1.0F - f) * 0.5D;
         double d2 = (double) (world.random.nextFloat() * f) + (double) (1.0F - f) * 0.5D;
         EntityItem entityitem = new EntityItem(world, (double) i + d0, (double) j + d1, (double) k + d2, new ItemStack(i1, 1, 0));
+        // This is done so that getDrops() in the BlockBreakEvent works properly.
 
         entityitem.pickupDelay = 10;
         world.addEntity(entityitem);
+        // */
+        super.doActualDrop(world, entityhuman, i, j, k, l);
+        // CraftBukkit end
         world.setTypeId(i, j, k, 0);
         entityhuman.a(StatisticList.C[this.id], 1);
     }
 
+    // CraftBukkit start - Calculate drops
+    public ArrayList<ItemStack> calculateDrops(World world, EntityHuman entityhuman, int i, int j, int k, int l) {
+        super.dropList = new ArrayList<ItemStack>();
+        this.a(world, i, j, k, new ItemStack(Item.SNOW_BALL.id, 1, 1));
+        return super.dropList;
+    }
+    // CraftBukkit end
+
     public int getDropType(int i, Random random, int j) {
         return Item.SNOW_BALL.id;
     }
diff --git a/src/main/java/net/minecraft/server/BlockStem.java b/src/main/java/net/minecraft/server/BlockStem.java
index 4468770313..901b4b4af8 100644
--- a/src/main/java/net/minecraft/server/BlockStem.java
+++ b/src/main/java/net/minecraft/server/BlockStem.java
@@ -158,6 +158,7 @@ public class BlockStem extends BlockFlower {
 
             for (int j1 = 0; j1 < 3; ++j1) {
                 if (world.random.nextInt(15) <= l) {
+                    /* CraftBukkit - Identical logic to superclass method; defer there
                     float f1 = 0.7F;
                     float f2 = world.random.nextFloat() * f1 + (1.0F - f1) * 0.5F;
                     float f3 = world.random.nextFloat() * f1 + (1.0F - f1) * 0.5F;
@@ -166,6 +167,8 @@ public class BlockStem extends BlockFlower {
 
                     entityitem.pickupDelay = 10;
                     world.addEntity(entityitem);
+                    // */
+                    this.a(world, i, j, k, new ItemStack(item));
                 }
             }
         }
diff --git a/src/main/java/net/minecraft/server/BlockTNT.java b/src/main/java/net/minecraft/server/BlockTNT.java
index f1efb1356e..e8261b5521 100644
--- a/src/main/java/net/minecraft/server/BlockTNT.java
+++ b/src/main/java/net/minecraft/server/BlockTNT.java
@@ -1,5 +1,6 @@
 package net.minecraft.server;
 
+import java.util.ArrayList; // CraftBukkit
 import java.util.Random;
 
 public class BlockTNT extends Block {
@@ -41,7 +42,9 @@ public class BlockTNT extends Block {
     public void postBreak(World world, int i, int j, int k, int l) {
         if (!world.isStatic) {
             if ((l & 1) == 0) {
+                /* CraftBukkit - Move this earlier so the block break event can see it
                 this.a(world, i, j, k, new ItemStack(Block.TNT.id, 1, 0));
+                // */
             } else {
                 EntityTNTPrimed entitytntprimed = new EntityTNTPrimed(world, (double) ((float) i + 0.5F), (double) ((float) j + 0.5F), (double) ((float) k + 0.5F));
 
@@ -51,6 +54,14 @@ public class BlockTNT extends Block {
         }
     }
 
+    // CraftBukkit start - Calculate drops
+    public ArrayList<ItemStack> calculateDrops(World world, EntityHuman entityhuman, int i, int j, int k, int l) {
+        super.dropList = new ArrayList<ItemStack>();
+        this.a(world, i, j, k, new ItemStack(Block.TNT.id, 1, 0));
+        return super.dropList;
+    }
+    // CraftBukkit end
+
     public void attack(World world, int i, int j, int k, EntityHuman entityhuman) {
         if (entityhuman.T() != null && entityhuman.T().id == Item.FLINT_AND_STEEL.id) {
             world.setRawData(i, j, k, 1);
diff --git a/src/main/java/net/minecraft/server/BlockVine.java b/src/main/java/net/minecraft/server/BlockVine.java
index d6bda347c4..633c9585b5 100644
--- a/src/main/java/net/minecraft/server/BlockVine.java
+++ b/src/main/java/net/minecraft/server/BlockVine.java
@@ -1,5 +1,6 @@
 package net.minecraft.server;
 
+import java.util.ArrayList; // CraftBukkit
 import java.util.Random;
 
 public class BlockVine extends Block {
@@ -286,9 +287,25 @@ public class BlockVine extends Block {
     public void a(World world, EntityHuman entityhuman, int i, int j, int k, int l) {
         if (!world.isStatic && entityhuman.T() != null && entityhuman.T().id == Item.SHEARS.id) {
             entityhuman.a(StatisticList.C[this.id], 1);
+            /* CraftBukkit start - moved this line into calculateDrops
             this.a(world, i, j, k, new ItemStack(Block.VINE, 1, 0));
+            */
+            this.doActualDrop(world, entityhuman, i, j, k, l);
+            // CraftBukkit end
         } else {
             super.a(world, entityhuman, i, j, k, l);
         }
     }
+
+    // CraftBukkit start - Calculate drops
+    public ArrayList<ItemStack> calculateDrops(World world, EntityHuman entityhuman, int i, int j, int k, int l) {
+        if (!world.isStatic && entityhuman.T() != null && entityhuman.T().id == Item.SHEARS.id) {
+            super.dropList = new ArrayList<ItemStack>();
+            this.a(world, i, j, k, new ItemStack(Block.VINE, 1, 0));
+            return super.dropList;
+        } else {
+            return super.calculateDrops(world, entityhuman, i, j, k, l);
+        }
+    }
+    // CraftBukkit end
 }
diff --git a/src/main/java/net/minecraft/server/Entity.java b/src/main/java/net/minecraft/server/Entity.java
index bc093075a1..f15827a749 100644
--- a/src/main/java/net/minecraft/server/Entity.java
+++ b/src/main/java/net/minecraft/server/Entity.java
@@ -4,6 +4,7 @@ import java.util.List;
 import java.util.Random;
 
 // CraftBukkit start
+import java.util.ArrayList;
 import java.util.UUID;
 import org.bukkit.Bukkit;
 import org.bukkit.block.BlockFace;
@@ -17,6 +18,7 @@ import org.bukkit.event.vehicle.VehicleBlockCollisionEvent;
 import org.bukkit.event.vehicle.VehicleEnterEvent;
 import org.bukkit.event.vehicle.VehicleExitEvent;
 import org.bukkit.craftbukkit.entity.CraftPlayer;
+import org.bukkit.craftbukkit.inventory.CraftItemStack;
 import org.bukkit.event.entity.EntityCombustEvent;
 import org.bukkit.event.entity.EntityDamageByBlockEvent;
 import org.bukkit.event.entity.EntityDamageByEntityEvent;
@@ -1337,12 +1339,18 @@ public abstract class Entity {
         final PluginManager pluginManager = Bukkit.getPluginManager();
 
         if (thisBukkitEntity instanceof Painting) {
-            PaintingBreakByEntityEvent event = new PaintingBreakByEntityEvent((Painting) thisBukkitEntity, stormBukkitEntity);
+            List<org.bukkit.inventory.ItemStack> drops = new ArrayList<org.bukkit.inventory.ItemStack>();
+            PaintingBreakByEntityEvent event = new PaintingBreakByEntityEvent((Painting) thisBukkitEntity, stormBukkitEntity, drops);
             pluginManager.callEvent(event);
 
             if (event.isCancelled()) {
                 return;
             }
+
+            // Something might've been added to the list of drops, so drop them
+            for (org.bukkit.inventory.ItemStack stack : drops) {
+                this.a(CraftItemStack.createNMSItemStack(stack), 0.0f);
+            }
         }
 
         EntityDamageByEntityEvent event = new EntityDamageByEntityEvent(stormBukkitEntity, thisBukkitEntity, EntityDamageEvent.DamageCause.LIGHTNING, 5);
diff --git a/src/main/java/net/minecraft/server/EntityBoat.java b/src/main/java/net/minecraft/server/EntityBoat.java
index e447f4c9f2..744610896d 100644
--- a/src/main/java/net/minecraft/server/EntityBoat.java
+++ b/src/main/java/net/minecraft/server/EntityBoat.java
@@ -1,9 +1,11 @@
 package net.minecraft.server;
 
+import java.util.ArrayList;
 import java.util.List;
 
 // CraftBukkit start
 import org.bukkit.Location;
+import org.bukkit.craftbukkit.inventory.CraftItemStack;
 import org.bukkit.entity.Vehicle;
 import org.bukkit.event.vehicle.VehicleCreateEvent;
 import org.bukkit.event.vehicle.VehicleDamageEvent;
@@ -111,7 +113,19 @@ public class EntityBoat extends Entity {
             this.aV();
             if (this.getDamage() > 40) {
                 // CraftBukkit start
-                VehicleDestroyEvent destroyEvent = new VehicleDestroyEvent(vehicle, attacker);
+                List<org.bukkit.inventory.ItemStack> drops = new ArrayList<org.bukkit.inventory.ItemStack>();
+
+                int j;
+
+                for (j = 0; j < 3; ++j) {
+                    drops.add(new CraftItemStack(Block.WOOD.id, 1));
+                }
+
+                for (j = 0; j < 2; ++j) {
+                    drops.add(new CraftItemStack(Item.STICK.id,1));
+                }
+
+                VehicleDestroyEvent destroyEvent = new VehicleDestroyEvent(vehicle, attacker, drops);
                 this.world.getServer().getPluginManager().callEvent(destroyEvent);
 
                 if (destroyEvent.isCancelled()) {
@@ -124,6 +138,7 @@ public class EntityBoat extends Entity {
                     this.passenger.mount(this);
                 }
 
+                /* CraftBukkit - This logic has been moved up before the event firing
                 int j;
 
                 for (j = 0; j < 3; ++j) {
@@ -133,8 +148,14 @@ public class EntityBoat extends Entity {
                 for (j = 0; j < 2; ++j) {
                     this.a(Item.STICK.id, 1, 0.0F);
                 }
+                // */
 
                 this.die();
+                // CraftBukkit start
+                for (org.bukkit.inventory.ItemStack stack : drops) {
+                    this.a(CraftItemStack.createNMSItemStack(stack), 0.0f);
+                }
+                // CraftBukkit end
             }
 
             return true;
@@ -302,24 +323,39 @@ public class EntityBoat extends Entity {
             if (this.positionChanged && d3 > 0.2D) {
                 if (!this.world.isStatic) {
                     // CraftBukkit start
+                    List<org.bukkit.inventory.ItemStack> drops = new ArrayList<org.bukkit.inventory.ItemStack>();
+                    /* CraftBukkit end
+                    this.die();
+                    // CraftBukkit - deferred to after the event */
+
+                    int k;
+
+                    for (k = 0; k < 3; ++k) {
+                        /* CraftBukkit - add to drop list instead of immediately dropping
+                        this.a(Block.WOOD.id, 1, 0.0F);
+                        // */
+                        drops.add(new CraftItemStack(Block.WOOD.id, 1));
+                    }
+
+                    for (k = 0; k < 2; ++k) {
+                        /* CraftBukkit - add to drop list instead of immediately dropping
+                        this.a(Item.STICK.id, 1, 0.0F);
+                        // */
+                        drops.add(new CraftItemStack(Item.STICK.id,1));
+                    }
+                    // CraftBukkit start
+                    drops.add(new CraftItemStack(Item.MINECART.id,1));
                     Vehicle vehicle = (Vehicle) this.getBukkitEntity();
-                    VehicleDestroyEvent destroyEvent = new VehicleDestroyEvent(vehicle, null);
+                    VehicleDestroyEvent destroyEvent = new VehicleDestroyEvent(vehicle, null, drops);
                     this.world.getServer().getPluginManager().callEvent(destroyEvent);
 
                     if (!destroyEvent.isCancelled()) {
-                    // CraftBukkit end
                         this.die();
-
-                        int k;
-
-                        for (k = 0; k < 3; ++k) {
-                            this.a(Block.WOOD.id, 1, 0.0F);
+                        for (org.bukkit.inventory.ItemStack stack : drops) {
+                            this.a(CraftItemStack.createNMSItemStack(stack), 0.0f);
                         }
-
-                        for (k = 0; k < 2; ++k) {
-                            this.a(Item.STICK.id, 1, 0.0F);
-                        }
-                    } // CraftBukkit
+                    }
+                    // CraftBukkit end
                 }
             } else {
                 this.motX *= 0.9900000095367432D;
diff --git a/src/main/java/net/minecraft/server/EntityMinecart.java b/src/main/java/net/minecraft/server/EntityMinecart.java
index 8e04035170..4945a01a1d 100644
--- a/src/main/java/net/minecraft/server/EntityMinecart.java
+++ b/src/main/java/net/minecraft/server/EntityMinecart.java
@@ -2,6 +2,7 @@ package net.minecraft.server;
 
 // CraftBukkit start
 import java.util.ArrayList;
+import java.util.Iterator;
 import java.util.List;
 
 import org.bukkit.Location;
@@ -17,6 +18,7 @@ import org.bukkit.event.vehicle.VehicleUpdateEvent;
 import org.bukkit.util.Vector;
 import org.bukkit.inventory.InventoryHolder;
 import org.bukkit.craftbukkit.entity.CraftHumanEntity;
+import org.bukkit.craftbukkit.inventory.CraftItemStack;
 // CraftBukkit end
 
 public class EntityMinecart extends Entity implements IInventory {
@@ -146,22 +148,35 @@ public class EntityMinecart extends Entity implements IInventory {
             this.aV();
             this.setDamage(this.getDamage() + i * 10);
             if (this.getDamage() > 40) {
-                if (this.passenger != null) {
-                    this.passenger.mount(this);
-                }
-
                 // CraftBukkit start
-                VehicleDestroyEvent destroyEvent = new VehicleDestroyEvent(vehicle, passenger);
+                List<org.bukkit.inventory.ItemStack> drops = new ArrayList<org.bukkit.inventory.ItemStack>();
+                drops.add(new CraftItemStack(Item.MINECART.id,1));
+                if (this.type == 1) {
+                    drops.add(new CraftItemStack(Block.CHEST.id,1));
+                } else if (this.type == 2) {
+                    drops.add(new org.bukkit.inventory.ItemStack(Block.FURNACE.id,1));
+                }
+                VehicleDestroyEvent destroyEvent = new VehicleDestroyEvent(vehicle, passenger, drops);
                 this.world.getServer().getPluginManager().callEvent(destroyEvent);
 
                 if (destroyEvent.isCancelled()) {
                     this.setDamage(40); // Maximize damage so this doesn't get triggered again right away
                     return true;
                 }
+
                 // CraftBukkit end
 
+                if (this.passenger != null) {
+                    this.passenger.mount(this);
+                }
+
                 this.die();
-                this.a(Item.MINECART.id, 1, 0.0F);
+                // CraftBukkit start - Drop items from the event
+                for(org.bukkit.inventory.ItemStack stack : drops) {
+                    this.a(CraftItemStack.createNMSItemStack(stack), 0.0f);
+                }
+                // CraftBukkit end
+                // this.a(Item.MINECART.id, 1, 0.0F); // CraftBukkit - handled by main drop loop
                 if (this.type == 1) {
                     EntityMinecart entityminecart = this;
 
@@ -193,9 +208,9 @@ public class EntityMinecart extends Entity implements IInventory {
                         }
                     }
 
-                    this.a(Block.CHEST.id, 1, 0.0F);
+                    // this.a(Block.CHEST.id, 1, 0.0F); // CraftBukkit - handled by main drop loop
                 } else if (this.type == 2) {
-                    this.a(Block.FURNACE.id, 1, 0.0F);
+                    // this.a(Block.FURNACE.id, 1, 0.0F); // CraftBukkit - handled by main drop loop
                 }
             }
 
diff --git a/src/main/java/net/minecraft/server/EntityMushroomCow.java b/src/main/java/net/minecraft/server/EntityMushroomCow.java
index b3860ec9c8..295e081107 100644
--- a/src/main/java/net/minecraft/server/EntityMushroomCow.java
+++ b/src/main/java/net/minecraft/server/EntityMushroomCow.java
@@ -1,5 +1,12 @@
 package net.minecraft.server;
 
+// CraftBukkit start
+import java.util.ArrayList;
+import java.util.List;
+
+import org.bukkit.craftbukkit.inventory.CraftItemStack;
+// CraftBukkit end
+
 public class EntityMushroomCow extends EntityCow {
 
     public EntityMushroomCow(World world) {
@@ -16,7 +23,11 @@ public class EntityMushroomCow extends EntityCow {
             return true;
         } else if (itemstack != null && itemstack.id == Item.SHEARS.id && this.getAge() >= 0) {
             // CraftBukkit start
-            org.bukkit.event.player.PlayerShearEntityEvent event = new org.bukkit.event.player.PlayerShearEntityEvent((org.bukkit.entity.Player) entityhuman.getBukkitEntity(), this.getBukkitEntity());
+            List<org.bukkit.inventory.ItemStack> drops = new ArrayList<org.bukkit.inventory.ItemStack>();
+            for (int i = 0; i < 5; ++i) {
+                drops.add(new CraftItemStack(Block.RED_MUSHROOM.id, 1));
+            }
+            org.bukkit.event.player.PlayerShearEntityEvent event = new org.bukkit.event.player.PlayerShearEntityEvent((org.bukkit.entity.Player) entityhuman.getBukkitEntity(), this.getBukkitEntity(), drops);
             this.world.getServer().getPluginManager().callEvent(event);
 
             if (event.isCancelled()) {
@@ -34,9 +45,15 @@ public class EntityMushroomCow extends EntityCow {
                 entitycow.V = this.V;
                 this.world.addEntity(entitycow);
 
+                /* CraftBukkit start - This logic moved up to before the event is fired ...
                 for (int i = 0; i < 5; ++i) {
                     this.world.addEntity(new EntityItem(this.world, this.locX, this.locY + (double) this.length, this.locZ, new ItemStack(Block.RED_MUSHROOM)));
                 }
+                // ... and replaced by this logic */
+                for (org.bukkit.inventory.ItemStack stack : drops) {
+                    this.world.addEntity(new EntityItem(this.world, this.locX, this.locY + this.length, this.locZ, CraftItemStack.createNMSItemStack(stack)));
+                }
+                // CraftBukkit end
             }
 
             return true;
diff --git a/src/main/java/net/minecraft/server/EntityPainting.java b/src/main/java/net/minecraft/server/EntityPainting.java
index 45b00fbb6c..510f7d1040 100644
--- a/src/main/java/net/minecraft/server/EntityPainting.java
+++ b/src/main/java/net/minecraft/server/EntityPainting.java
@@ -4,6 +4,7 @@ import java.util.ArrayList;
 import java.util.List;
 
 // CraftBukkit start
+import org.bukkit.craftbukkit.inventory.CraftItemStack;
 import org.bukkit.entity.Painting;
 import org.bukkit.event.painting.PaintingBreakByEntityEvent;
 import org.bukkit.event.painting.PaintingBreakEvent.RemoveCause;
@@ -125,6 +126,8 @@ public class EntityPainting extends Entity {
             this.f = 0;
             if (!this.survives()) {
                 // CraftBukkit start
+                List<org.bukkit.inventory.ItemStack> drops = new ArrayList<org.bukkit.inventory.ItemStack>();
+                drops.add(new CraftItemStack(Item.PAINTING.id, 1));
                 Material material = this.world.getMaterial((int) this.locX, (int) this.locY, (int) this.locZ);
                 RemoveCause cause;
                 if (material.equals(Material.WATER)) {
@@ -135,7 +138,7 @@ public class EntityPainting extends Entity {
                 } else {
                     cause = RemoveCause.PHYSICS;
                 }
-                PaintingBreakEvent event = new PaintingBreakEvent((Painting) this.getBukkitEntity(), cause);
+                PaintingBreakEvent event = new PaintingBreakEvent((Painting) this.getBukkitEntity(), cause, drops);
                 this.world.getServer().getPluginManager().callEvent(event);
 
                 if (event.isCancelled() || dead) {
@@ -144,7 +147,12 @@ public class EntityPainting extends Entity {
                 // CraftBukkit end
 
                 this.die();
-                this.world.addEntity(new EntityItem(this.world, this.locX, this.locY, this.locZ, new ItemStack(Item.PAINTING)));
+                // CraftBukkit start - replace following line with the loop
+                //this.world.addEntity(new EntityItem(this.world, this.locX, this.locY, this.locZ, new ItemStack(Item.PAINTING)));
+                for (org.bukkit.inventory.ItemStack stack : drops) {
+                    this.world.addEntity(new EntityItem(this.world, this.locX, this.locY, this.locZ, CraftItemStack.createNMSItemStack(stack)));
+                }
+                // CraftBukkit end
             }
         }
     }
@@ -214,12 +222,14 @@ public class EntityPainting extends Entity {
     public boolean damageEntity(DamageSource damagesource, int i) {
         if (!this.dead && !this.world.isStatic) {
             // CraftBukkit start
+            List<org.bukkit.inventory.ItemStack> drops = new ArrayList<org.bukkit.inventory.ItemStack>();
+            drops.add(new CraftItemStack(Item.PAINTING.id, 1));
             PaintingBreakEvent event = null;
             if (damagesource.getEntity() != null) {
-                event = new PaintingBreakByEntityEvent((Painting) this.getBukkitEntity(), damagesource.getEntity() == null ? null : damagesource.getEntity().getBukkitEntity());
+                event = new PaintingBreakByEntityEvent((Painting) this.getBukkitEntity(), damagesource.getEntity().getBukkitEntity(), drops);
             } else {
                 if (damagesource == DamageSource.FIRE) {
-                    event = new PaintingBreakEvent((Painting) this.getBukkitEntity(), RemoveCause.FIRE);
+                    event = new PaintingBreakEvent((Painting) this.getBukkitEntity(), RemoveCause.FIRE, drops);
                 }
                 // TODO: Could put other stuff here?
             }
@@ -236,7 +246,12 @@ public class EntityPainting extends Entity {
 
             this.die();
             this.aV();
-            this.world.addEntity(new EntityItem(this.world, this.locX, this.locY, this.locZ, new ItemStack(Item.PAINTING)));
+            // CraftBukkit start - replace following line with the loop
+            //this.world.addEntity(new EntityItem(this.world, this.locX, this.locY, this.locZ, new ItemStack(Item.PAINTING)));
+            for (org.bukkit.inventory.ItemStack stack : drops) {
+                this.world.addEntity(new EntityItem(this.world, this.locX, this.locY, this.locZ, CraftItemStack.createNMSItemStack(stack)));
+            }
+            // CraftBukkit end
         }
 
         return true;
diff --git a/src/main/java/net/minecraft/server/EntitySheep.java b/src/main/java/net/minecraft/server/EntitySheep.java
index 59f3eb9c10..62e641ba7a 100644
--- a/src/main/java/net/minecraft/server/EntitySheep.java
+++ b/src/main/java/net/minecraft/server/EntitySheep.java
@@ -3,8 +3,12 @@ package net.minecraft.server;
 import java.util.Random;
 
 // CraftBukkit start
+import java.util.ArrayList;
+import java.util.List;
+
 import org.bukkit.Material;
 import org.bukkit.craftbukkit.event.CraftEventFactory;
+import org.bukkit.craftbukkit.inventory.CraftItemStack;
 import org.bukkit.entity.Sheep;
 // CraftBukkit end
 
@@ -80,7 +84,12 @@ public class EntitySheep extends EntityAnimal {
         if (itemstack != null && itemstack.id == Item.SHEARS.id && !this.isSheared() && !this.isBaby()) {
             if (!this.world.isStatic) {
                 // CraftBukkit start
-                org.bukkit.event.player.PlayerShearEntityEvent event = new org.bukkit.event.player.PlayerShearEntityEvent((org.bukkit.entity.Player) entityhuman.getBukkitEntity(), this.getBukkitEntity());
+                int i = 1 + this.random.nextInt(3);
+                List<org.bukkit.inventory.ItemStack> drops = new ArrayList<org.bukkit.inventory.ItemStack>();
+                for (int j = 0; j < i; ++j) {
+                    drops.add(new CraftItemStack(Block.WOOL.id, 1, (short) this.getColor()));
+                }
+                org.bukkit.event.player.PlayerShearEntityEvent event = new org.bukkit.event.player.PlayerShearEntityEvent((org.bukkit.entity.Player) entityhuman.getBukkitEntity(), this.getBukkitEntity(), drops);
                 this.world.getServer().getPluginManager().callEvent(event);
 
                 if (event.isCancelled()) {
@@ -89,11 +98,15 @@ public class EntitySheep extends EntityAnimal {
                 // CraftBukkit end
 
                 this.setSheared(true);
+                /* CraftBukkit start - Moved this line to before the event is fired
                 int i = 1 + this.random.nextInt(3);
-
+                // And this logic is changed to use the drop list from the event
                 for (int j = 0; j < i; ++j) {
                     EntityItem entityitem = this.a(new ItemStack(Block.WOOL.id, 1, this.getColor()), 1.0F);
-
+                    // */
+                for (org.bukkit.inventory.ItemStack stack : drops) {
+                    EntityItem entityitem = this.a(CraftItemStack.createNMSItemStack(stack), 1.0f);
+                    // CraftBukkit end
                     entityitem.motY += (double) (this.random.nextFloat() * 0.05F);
                     entityitem.motX += (double) ((this.random.nextFloat() - this.random.nextFloat()) * 0.1F);
                     entityitem.motZ += (double) ((this.random.nextFloat() - this.random.nextFloat()) * 0.1F);
diff --git a/src/main/java/net/minecraft/server/ItemInWorldManager.java b/src/main/java/net/minecraft/server/ItemInWorldManager.java
index f0a8c89d6c..d9d512faea 100644
--- a/src/main/java/net/minecraft/server/ItemInWorldManager.java
+++ b/src/main/java/net/minecraft/server/ItemInWorldManager.java
@@ -1,7 +1,6 @@
 package net.minecraft.server;
 
 // CraftBukkit start
-import org.bukkit.event.block.BlockBreakEvent;
 import org.bukkit.event.block.BlockDamageEvent;
 import org.bukkit.craftbukkit.event.CraftEventFactory;
 import org.bukkit.event.Event;
@@ -201,37 +200,24 @@ public class ItemInWorldManager {
     }
 
     public boolean breakBlock(int i, int j, int k) {
+        int l = this.world.getTypeId(i, j, k);
+        int i1 = this.world.getData(i, j, k);
+
         // CraftBukkit start
-        if (this.player instanceof EntityPlayer) {
-            org.bukkit.block.Block block = this.world.getWorld().getBlockAt(i, j, k);
-
-            // Tell client the block is gone immediately then process events
-            if (world.getTileEntity(i, j, k) == null) {
-                Packet53BlockChange packet = new Packet53BlockChange(i, j, k, this.world);
-
-                packet.material = 0;
-                packet.data = 0;
-                ((EntityPlayer) this.player).netServerHandler.sendPacket(packet);
-            }
-
-            BlockBreakEvent event = new BlockBreakEvent(block, (org.bukkit.entity.Player) this.player.getBukkitEntity());
-            this.world.getServer().getPluginManager().callEvent(event);
-
-            if (event.isCancelled()) {
-                // Let the client know the block still exists
-                ((EntityPlayer) this.player).netServerHandler.sendPacket(new Packet53BlockChange(i, j, k, this.world));
+        if (player instanceof EntityPlayer) {
+            if(CraftEventFactory.callBlockBreakEvent(this.world, i, j, k, l, i1, this.isCreative(), this.player)) {
                 return false;
             }
         }
         // CraftBukkit end
 
-        int l = this.world.getTypeId(i, j, k);
-        int i1 = this.world.getData(i, j, k);
-
         this.world.a(this.player, 2001, i, j, k, l + (this.world.getData(i, j, k) << 12));
         boolean flag = this.b(i, j, k);
 
         if (this.isCreative()) {
+            // CraftBukkit start - honour additions to drop list
+            Block.byId[l].doActualDrop(this.world, this.player, i, j, k, i1);
+            // CraftBukkit end
             ((EntityPlayer) this.player).netServerHandler.sendPacket(new Packet53BlockChange(i, j, k, this.world));
         } else {
             ItemStack itemstack = this.player.T();
diff --git a/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java b/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java
index cebaa8f034..394e52ab76 100644
--- a/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java
+++ b/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java
@@ -1,6 +1,8 @@
 package org.bukkit.craftbukkit.event;
 
 import java.net.InetAddress;
+import java.util.ArrayList;
+import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
 
@@ -16,10 +18,12 @@ import net.minecraft.server.EntityItem;
 import net.minecraft.server.EntityLiving;
 import net.minecraft.server.EntityPlayer;
 import net.minecraft.server.EntityPotion;
+import net.minecraft.server.IInventory;
 import net.minecraft.server.InventoryCrafting;
 import net.minecraft.server.Item;
 import net.minecraft.server.ItemStack;
 import net.minecraft.server.Packet101CloseWindow;
+import net.minecraft.server.Packet53BlockChange;
 import net.minecraft.server.World;
 import net.minecraft.server.WorldServer;
 
@@ -485,6 +489,7 @@ public class CraftEventFactory {
     public static ItemStack callPreCraftEvent(InventoryCrafting matrix, ItemStack result, InventoryView lastCraftView, boolean isRepair) {
         CraftInventoryCrafting inventory = new CraftInventoryCrafting(matrix, matrix.resultInventory);
         inventory.setResult(new CraftItemStack(result));
+
         PrepareItemCraftEvent event = new PrepareItemCraftEvent(inventory, lastCraftView, isRepair);
         Bukkit.getPluginManager().callEvent(event);
 
@@ -506,4 +511,42 @@ public class CraftEventFactory {
         Bukkit.getPluginManager().callEvent(event);
         return event;
     }
+
+    public static boolean callBlockBreakEvent(World world, int x, int y, int z, int id, int data, boolean creative, EntityHuman player) {
+        net.minecraft.server.Block blockType = net.minecraft.server.Block.byId[id];
+        Block block = world.getWorld().getBlockAt(x, y, z);
+
+        // Tell client the block is gone immediately then process events
+        if (world.getTileEntity(x, y, z) == null) {
+            Packet53BlockChange packet = new Packet53BlockChange(x, y, z, world);
+
+            packet.material = 0;
+            packet.data = 0;
+            ((EntityPlayer) player).netServerHandler.sendPacket(packet);
+        }
+
+        List<org.bukkit.inventory.ItemStack> drops = new ArrayList<org.bukkit.inventory.ItemStack>();
+        if (!creative && player.b(blockType)) {
+            for (ItemStack stack : blockType.calculateDrops(world, player, x, y, z, data)) {
+                drops.add(new CraftItemStack(stack));
+            }
+        }
+
+        BlockBreakEvent event = new BlockBreakEvent(block, (org.bukkit.entity.Player) player.getBukkitEntity(), drops);
+        world.getServer().getPluginManager().callEvent(event);
+
+        if (event.isCancelled()) {
+            // Let the client know the block still exists
+            ((EntityPlayer) player).netServerHandler.sendPacket(new Packet53BlockChange(x, y, z, world));
+            return true;
+        }
+
+        ArrayList<ItemStack> toDrop = new ArrayList<ItemStack>();
+        for (org.bukkit.inventory.ItemStack stack : drops) {
+            toDrop.add(CraftItemStack.createNMSItemStack(stack));
+        }
+        blockType.setDrops(toDrop);
+
+        return false; // Event not cancelled
+    }
 }