--- ../work/decompile-8eb82bde//net/minecraft/server/TileEntityHopper.java	2014-11-28 17:43:43.401707428 +0000
+++ src/main/java/net/minecraft/server/TileEntityHopper.java	2014-11-28 17:38:19.000000000 +0000
@@ -2,11 +2,45 @@
 
 import java.util.List;
 
+// CraftBukkit start
+import org.bukkit.craftbukkit.entity.CraftHumanEntity;
+import org.bukkit.craftbukkit.inventory.CraftItemStack;
+import org.bukkit.entity.HumanEntity;
+import org.bukkit.event.inventory.InventoryMoveItemEvent;
+import org.bukkit.event.inventory.InventoryPickupItemEvent;
+import org.bukkit.inventory.Inventory;
+// CraftBukkit end
+
 public class TileEntityHopper extends TileEntityContainer implements IHopper, IUpdatePlayerListBox {
 
     private ItemStack[] items = new ItemStack[5];
     private String f;
     private int g = -1;
+    
+    // CraftBukkit start - add fields and methods
+    public List<HumanEntity> transaction = new java.util.ArrayList<HumanEntity>();
+    private int maxStack = MAX_STACK;
+
+    public ItemStack[] getContents() {
+        return this.items;
+    }
+
+    public void onOpen(CraftHumanEntity who) {
+        transaction.add(who);
+    }
+
+    public void onClose(CraftHumanEntity who) {
+        transaction.remove(who);
+    }
+
+    public List<HumanEntity> getViewers() {
+        return transaction;
+    }
+
+    public void setMaxStackSize(int size) {
+        maxStack = size;
+    }
+    // CraftBukkit end    
 
     public TileEntityHopper() {}
 
@@ -119,7 +153,7 @@
     }
 
     public int getMaxStackSize() {
-        return 64;
+        return maxStack; // CraftBukkit
     }
 
     public boolean a(EntityHuman entityhuman) {
@@ -215,10 +249,35 @@
                 for (int i = 0; i < this.getSize(); ++i) {
                     if (this.getItem(i) != null) {
                         ItemStack itemstack = this.getItem(i).cloneItemStack();
-                        ItemStack itemstack1 = addItem(iinventory, this.splitStack(i, 1), enumdirection);
+                        // ItemStack itemstack1 = addItem(iinventory, this.splitStack(i, 1), enumdirection);
+                        
+                        // CraftBukkit start - Call event when pushing items into other inventories
+                        CraftItemStack oitemstack = CraftItemStack.asCraftMirror(this.splitStack(i, 1));
+
+                        Inventory destinationInventory;
+                        // Have to special case large chests as they work oddly
+                        if (iinventory instanceof InventoryLargeChest) {
+                            destinationInventory = new org.bukkit.craftbukkit.inventory.CraftInventoryDoubleChest((InventoryLargeChest) iinventory);
+                        } else {
+                            destinationInventory = iinventory.getOwner().getInventory();
+                        }
+
+                        InventoryMoveItemEvent event = new InventoryMoveItemEvent(this.getOwner().getInventory(), oitemstack.clone(), destinationInventory, true);
+                        this.getWorld().getServer().getPluginManager().callEvent(event);
+                        if (event.isCancelled()) {
+                            this.setItem(i, itemstack);
+                            this.d(8); // Delay hopper checks
+                            return false;
+                        }
+                        ItemStack itemstack1 = addItem(iinventory, CraftItemStack.asNMSCopy(event.getItem()), enumdirection);
 
                         if (itemstack1 == null || itemstack1.count == 0) {
-                            iinventory.update();
+                            if (event.getItem().equals(oitemstack)) {
+                                iinventory.update();
+                            } else {
+                                this.setItem(i, itemstack);
+                            }
+                            // CraftBukkit end
                             return true;
                         }
 
@@ -325,10 +384,41 @@
 
         if (itemstack != null && b(iinventory, itemstack, i, enumdirection)) {
             ItemStack itemstack1 = itemstack.cloneItemStack();
-            ItemStack itemstack2 = addItem(ihopper, iinventory.splitStack(i, 1), (EnumDirection) null);
+            // ItemStack itemstack2 = addItem(ihopper, iinventory.splitStack(i, 1), (EnumDirection) null);
+            // CraftBukkit start - Call event on collection of items from inventories into the hopper
+            CraftItemStack oitemstack = CraftItemStack.asCraftMirror(iinventory.splitStack(i, 1));
+
+            Inventory sourceInventory;
+            // Have to special case large chests as they work oddly
+            if (iinventory instanceof InventoryLargeChest) {
+                sourceInventory = new org.bukkit.craftbukkit.inventory.CraftInventoryDoubleChest((InventoryLargeChest) iinventory);
+            } else {
+                sourceInventory = iinventory.getOwner().getInventory();
+            }
+
+            InventoryMoveItemEvent event = new InventoryMoveItemEvent(sourceInventory, oitemstack.clone(), ihopper.getOwner().getInventory(), false);
+
+            ihopper.getWorld().getServer().getPluginManager().callEvent(event);
+            if (event.isCancelled()) {
+                iinventory.setItem(i, itemstack1);
+
+                if (ihopper instanceof TileEntityHopper) {
+                    ((TileEntityHopper) ihopper).d(8); // Delay hopper checks
+                } else if (ihopper instanceof EntityMinecartHopper) {
+                    ((EntityMinecartHopper) ihopper).l(4); // Delay hopper minecart checks
+                }
+
+                return false;
+            }
+            ItemStack itemstack2 = addItem(ihopper, CraftItemStack.asNMSCopy(event.getItem()), null);
 
             if (itemstack2 == null || itemstack2.count == 0) {
-                iinventory.update();
+                if (event.getItem().equals(oitemstack)) {
+                    iinventory.update();
+                } else {
+                    iinventory.setItem(i, itemstack1);
+                }
+                // CraftBukkit end
                 return true;
             }
 
@@ -344,6 +434,14 @@
         if (entityitem == null) {
             return false;
         } else {
+            // CraftBukkit start
+            InventoryPickupItemEvent event = new InventoryPickupItemEvent(iinventory.getOwner().getInventory(), (org.bukkit.entity.Item) entityitem.getBukkitEntity());
+            entityitem.world.getServer().getPluginManager().callEvent(event);
+            if (event.isCancelled()) {
+                return false;
+            }
+            // CraftBukkit end
+        
             ItemStack itemstack = entityitem.getItemStack().cloneItemStack();
             ItemStack itemstack1 = addItem(iinventory, itemstack, (EnumDirection) null);