From f4e9f4737fd331e32fec5debd109bcb636f04ba9 Mon Sep 17 00:00:00 2001 From: Shane Freeder Date: Sat, 25 Nov 2017 17:35:32 +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 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. --- ...55-Do-not-use-a-snapshot-for-hoppers.patch | 67 +++++++++++++++++++ 1 file changed, 67 insertions(+) create mode 100644 Spigot-Server-Patches/0255-Do-not-use-a-snapshot-for-hoppers.patch diff --git a/Spigot-Server-Patches/0255-Do-not-use-a-snapshot-for-hoppers.patch b/Spigot-Server-Patches/0255-Do-not-use-a-snapshot-for-hoppers.patch new file mode 100644 index 0000000000..fefd4fbff1 --- /dev/null +++ b/Spigot-Server-Patches/0255-Do-not-use-a-snapshot-for-hoppers.patch @@ -0,0 +1,67 @@ +From b0456f32941d38b616e2e3f3f37583cb7a5713ef 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.0 +