--- a/net/minecraft/world/level/block/entity/TileEntityHopper.java +++ b/net/minecraft/world/level/block/entity/TileEntityHopper.java @@ -30,6 +30,22 @@ import net.minecraft.world.level.block.state.IBlockData; import net.minecraft.world.phys.AxisAlignedBB; +// CraftBukkit start +import net.minecraft.world.InventoryLargeChest; +import net.minecraft.world.entity.vehicle.EntityMinecartHopper; +import org.bukkit.Bukkit; +import org.bukkit.craftbukkit.block.CraftBlock; +import org.bukkit.craftbukkit.entity.CraftHumanEntity; +import org.bukkit.craftbukkit.inventory.CraftInventory; +import org.bukkit.craftbukkit.inventory.CraftItemStack; +import org.bukkit.entity.HumanEntity; +import org.bukkit.event.entity.EntityRemoveEvent; +import org.bukkit.event.inventory.HopperInventorySearchEvent; +import org.bukkit.event.inventory.InventoryMoveItemEvent; +import org.bukkit.event.inventory.InventoryPickupItemEvent; +import org.bukkit.inventory.Inventory; +// CraftBukkit end + public class TileEntityHopper extends TileEntityLootable implements IHopper { public static final int MOVE_ITEM_SPEED = 8; @@ -40,6 +56,36 @@ private long tickedGameTime; private EnumDirection facing; + // CraftBukkit start - add fields and methods + public List transaction = new java.util.ArrayList(); + private int maxStack = MAX_STACK; + + public List getContents() { + return this.items; + } + + public void onOpen(CraftHumanEntity who) { + transaction.add(who); + } + + public void onClose(CraftHumanEntity who) { + transaction.remove(who); + } + + public List getViewers() { + return transaction; + } + + @Override + public int getMaxStackSize() { + return maxStack; + } + + public void setMaxStackSize(int size) { + maxStack = size; + } + // CraftBukkit end + public TileEntityHopper(BlockPosition blockposition, IBlockData iblockdata) { super(TileEntityTypes.HOPPER, blockposition, iblockdata); this.items = NonNullList.withSize(5, ItemStack.EMPTY); @@ -167,7 +213,29 @@ if (!itemstack.isEmpty()) { int j = itemstack.getCount(); - ItemStack itemstack1 = addItem(tileentityhopper, iinventory, tileentityhopper.removeItem(i, 1), enumdirection); + // CraftBukkit start - Call event when pushing items into other inventories + ItemStack original = itemstack.copy(); + CraftItemStack oitemstack = CraftItemStack.asCraftMirror(tileentityhopper.removeItem(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 if (iinventory.getOwner() != null) { + destinationInventory = iinventory.getOwner().getInventory(); + } else { + destinationInventory = new CraftInventory(iinventory); + } + + InventoryMoveItemEvent event = new InventoryMoveItemEvent(tileentityhopper.getOwner().getInventory(), oitemstack, destinationInventory, true); + world.getCraftServer().getPluginManager().callEvent(event); + if (event.isCancelled()) { + tileentityhopper.setItem(i, original); + tileentityhopper.setCooldown(8); // Delay hopper checks + return false; + } + ItemStack itemstack1 = addItem(tileentityhopper, iinventory, CraftItemStack.asNMSCopy(event.getItem()), enumdirection); + // CraftBukkit end if (itemstack1.isEmpty()) { iinventory.setChanged(); @@ -279,7 +347,34 @@ if (!itemstack.isEmpty() && canTakeItemFromContainer(ihopper, iinventory, itemstack, i, enumdirection)) { int j = itemstack.getCount(); - ItemStack itemstack1 = addItem(iinventory, ihopper, iinventory.removeItem(i, 1), (EnumDirection) null); + // CraftBukkit start - Call event on collection of items from inventories into the hopper + ItemStack original = itemstack.copy(); + CraftItemStack oitemstack = CraftItemStack.asCraftMirror(iinventory.removeItem(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 if (iinventory.getOwner() != null) { + sourceInventory = iinventory.getOwner().getInventory(); + } else { + sourceInventory = new CraftInventory(iinventory); + } + + InventoryMoveItemEvent event = new InventoryMoveItemEvent(sourceInventory, oitemstack, ihopper.getOwner().getInventory(), false); + + Bukkit.getServer().getPluginManager().callEvent(event); + if (event.isCancelled()) { + iinventory.setItem(i, original); + + if (ihopper instanceof TileEntityHopper) { + ((TileEntityHopper) ihopper).setCooldown(8); // Delay hopper checks + } + + return false; + } + ItemStack itemstack1 = addItem(iinventory, ihopper, CraftItemStack.asNMSCopy(event.getItem()), null); + // CraftBukkit end if (itemstack1.isEmpty()) { iinventory.setChanged(); @@ -297,13 +392,20 @@ public static boolean addItem(IInventory iinventory, EntityItem entityitem) { boolean flag = false; + // CraftBukkit start + InventoryPickupItemEvent event = new InventoryPickupItemEvent(iinventory.getOwner().getInventory(), (org.bukkit.entity.Item) entityitem.getBukkitEntity()); + entityitem.level().getCraftServer().getPluginManager().callEvent(event); + if (event.isCancelled()) { + return false; + } + // CraftBukkit end ItemStack itemstack = entityitem.getItem().copy(); ItemStack itemstack1 = addItem((IInventory) null, iinventory, itemstack, (EnumDirection) null); if (itemstack1.isEmpty()) { flag = true; entityitem.setItem(ItemStack.EMPTY); - entityitem.discard(); + entityitem.discard(EntityRemoveEvent.Cause.PICKUP); // CraftBukkit - add Bukkit remove cause } else { entityitem.setItem(itemstack1); } @@ -421,14 +523,38 @@ return itemstack; } + // CraftBukkit start + @Nullable + private static IInventory runHopperInventorySearchEvent(IInventory inventory, CraftBlock hopper, CraftBlock searchLocation, HopperInventorySearchEvent.ContainerType containerType) { + HopperInventorySearchEvent event = new HopperInventorySearchEvent((inventory != null) ? new CraftInventory(inventory) : null, containerType, hopper, searchLocation); + Bukkit.getServer().getPluginManager().callEvent(event); + CraftInventory craftInventory = (CraftInventory) event.getInventory(); + return (craftInventory != null) ? craftInventory.getInventory() : null; + } + // CraftBukkit end + @Nullable private static IInventory getAttachedContainer(World world, BlockPosition blockposition, TileEntityHopper tileentityhopper) { - return getContainerAt(world, blockposition.relative(tileentityhopper.facing)); + // CraftBukkit start + BlockPosition searchPosition = blockposition.relative(tileentityhopper.facing); + IInventory inventory = getContainerAt(world, searchPosition); + + CraftBlock hopper = CraftBlock.at(world, blockposition); + CraftBlock searchBlock = CraftBlock.at(world, searchPosition); + return runHopperInventorySearchEvent(inventory, hopper, searchBlock, HopperInventorySearchEvent.ContainerType.DESTINATION); + // CraftBukkit end } @Nullable private static IInventory getSourceContainer(World world, IHopper ihopper, BlockPosition blockposition, IBlockData iblockdata) { - return getContainerAt(world, blockposition, iblockdata, ihopper.getLevelX(), ihopper.getLevelY() + 1.0D, ihopper.getLevelZ()); + // CraftBukkit start + IInventory inventory = getContainerAt(world, blockposition, iblockdata, ihopper.getLevelX(), ihopper.getLevelY() + 1.0D, ihopper.getLevelZ()); + + BlockPosition blockPosition = BlockPosition.containing(ihopper.getLevelX(), ihopper.getLevelY(), ihopper.getLevelZ()); + CraftBlock hopper = CraftBlock.at(world, blockPosition); + CraftBlock container = CraftBlock.at(world, blockPosition.above()); + return runHopperInventorySearchEvent(inventory, hopper, container, HopperInventorySearchEvent.ContainerType.SOURCE); + // CraftBukkit end } public static List getItemsAtAndAbove(World world, IHopper ihopper) {