From 9d7d7c604f70abfe98b0f08b04305ddcb28b415f Mon Sep 17 00:00:00 2001 From: Shane Freeder Date: Sat, 25 Nov 2017 17:02:33 +0000 Subject: [PATCH] Do not use a snapshot for hoppers In 1.12, Spigot improved their blockstate implementation to take a full copy of the TE, this allows for a much better snapshot in that it will actually retain all of the TE's state, it is a much more expensive implementation. This is also implicated with their backwards compat for inventories meaning that accessing of a snapshots inventory of a placed block will actually access the inventory of the live TE, making creation of a snapshot redundant if the only intent is to interact with the TEs inventory. Hoppers are a horrible hit, every attempt to transfer an ItemStack will result in two TileEntity state snapshots, with two hoppers and a double chest ontop, I managed to log 380 cases per second where a snapshot would have been taken in cases where the snapshot is redundant. diff --git a/src/main/java/net/minecraft/server/TileEntityHopper.java b/src/main/java/net/minecraft/server/TileEntityHopper.java index 8ad081316..ebbe5d326 100644 --- a/src/main/java/net/minecraft/server/TileEntityHopper.java +++ b/src/main/java/net/minecraft/server/TileEntityHopper.java @@ -219,11 +219,15 @@ public class TileEntityHopper extends TileEntityLootable implements IHopper, ITi // Have to special case large chests as they work oddly if (iinventory instanceof InventoryLargeChest) { destinationInventory = new org.bukkit.craftbukkit.inventory.CraftInventoryDoubleChest((InventoryLargeChest) iinventory); + // Paper start - avoid redundant snapshot creation of a TE + } else if (iinventory instanceof TileEntity) { + destinationInventory = ((TileEntity) iinventory).getOwner(false).getInventory(); } else { destinationInventory = iinventory.getOwner().getInventory(); } - InventoryMoveItemEvent event = new InventoryMoveItemEvent(this.getOwner().getInventory(), oitemstack.clone(), destinationInventory, true); + InventoryMoveItemEvent event = new InventoryMoveItemEvent(this.getOwner(false).getInventory(), oitemstack.clone(), destinationInventory, true); + // Paper end - avoid redundant snapshot creation of a TE this.getWorld().getServer().getPluginManager().callEvent(event); if (event.isCancelled()) { this.setItem(i, itemstack); @@ -379,12 +383,22 @@ public class TileEntityHopper extends TileEntityLootable implements IHopper, ITi // Have to special case large chests as they work oddly if (iinventory instanceof InventoryLargeChest) { sourceInventory = new org.bukkit.craftbukkit.inventory.CraftInventoryDoubleChest((InventoryLargeChest) iinventory); + // Paper start - avoid redundant snapshot creation of a TE + } else if (iinventory instanceof TileEntity){ + sourceInventory = ((TileEntity) iinventory).getOwner(false).getInventory(); } else { sourceInventory = iinventory.getOwner().getInventory(); } - InventoryMoveItemEvent event = new InventoryMoveItemEvent(sourceInventory, oitemstack.clone(), ihopper.getOwner().getInventory(), false); + Inventory destination; + if (ihopper instanceof TileEntity) { + destination = ((TileEntity) ihopper).getOwner(false).getInventory(); + } else { + destination = ihopper.getOwner().getInventory(); + } + InventoryMoveItemEvent event = new InventoryMoveItemEvent(sourceInventory, oitemstack.clone(), destination, false); + // Paper end - avoid redundant snapshot creation of a TE ihopper.getWorld().getServer().getPluginManager().callEvent(event); if (event.isCancelled()) { iinventory.setItem(i, itemstack1); -- 2.15.1