From 9fee8541d0c435ae91647fe32c4e9e88bcd2725e Mon Sep 17 00:00:00 2001 From: Omer Uddin Date: Wed, 7 Aug 2019 23:08:22 +0500 Subject: [PATCH] Reimplement hopper optimization patch (#2388) Co-authored-by: Shane Freeder --- ...opper-searches-if-there-are-no-items.patch | 105 ++++++++++++++++++ 1 file changed, 105 insertions(+) create mode 100644 Spigot-Server-Patches/Avoid-hopper-searches-if-there-are-no-items.patch diff --git a/Spigot-Server-Patches/Avoid-hopper-searches-if-there-are-no-items.patch b/Spigot-Server-Patches/Avoid-hopper-searches-if-there-are-no-items.patch new file mode 100644 index 0000000000..e0e85d6521 --- /dev/null +++ b/Spigot-Server-Patches/Avoid-hopper-searches-if-there-are-no-items.patch @@ -0,0 +1,105 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: CullanP +Date: Thu, 3 Mar 2016 02:13:38 -0600 +Subject: [PATCH] Avoid hopper searches if there are no items + +Hoppers searching for items and minecarts is the most expensive part of hopper ticking. +We keep track of the number of minecarts and items in a chunk. +If there are no items in the chunk, we skip searching for items. +If there are no minecarts in the chunk, we skip searching for them. + +Usually hoppers aren't near items, so we can skip most item searches. +And since minecart hoppers are used _very_ rarely near we can avoid alot of searching there. + +Combined, this adds up a lot. + + +diff --git a/src/main/java/net/minecraft/server/Chunk.java b/src/main/java/net/minecraft/server/Chunk.java +index d604f96c1..67dc837f4 100644 +--- a/src/main/java/net/minecraft/server/Chunk.java ++++ b/src/main/java/net/minecraft/server/Chunk.java +@@ -0,0 +0,0 @@ public class Chunk implements IChunkAccess { + return removed; + } + } ++ // Track the number of minecarts and items ++ // Keep this synced with entitySlices.add() and entitySlices.remove() ++ private final int[] itemCounts = new int[16]; ++ private final int[] inventoryEntityCounts = new int[16]; + // Paper end + + public Chunk(World world, ChunkCoordIntPair chunkcoordintpair, BiomeBase[] abiomebase, ChunkConverter chunkconverter, TickList ticklist, TickList ticklist1, long i, @Nullable ChunkSection[] achunksection, @Nullable Consumer consumer) { +@@ -0,0 +0,0 @@ public class Chunk implements IChunkAccess { + entity.chunkY = k; + entity.chunkZ = this.loc.z; + this.entitySlices[k].add(entity); ++ // Paper start ++ if (entity instanceof EntityItem) { ++ itemCounts[k]++; ++ } else if (entity instanceof IInventory) { ++ inventoryEntityCounts[k]++; ++ } ++ // Paper end + entity.entitySlice = this.entitySlices[k]; // Paper + this.markDirty(); // Paper + } +@@ -0,0 +0,0 @@ public class Chunk implements IChunkAccess { + if (!this.entitySlices[i].remove(entity)) { + return; + } ++ if (entity instanceof EntityItem) { ++ itemCounts[i]--; ++ } else if (entity instanceof IInventory) { ++ inventoryEntityCounts[i]--; ++ } + entityCounts.decrement(entity.getMinecraftKeyString()); + this.markDirty(); // Paper + // Paper end +@@ -0,0 +0,0 @@ public class Chunk implements IChunkAccess { + for (int k = i; k <= j; ++k) { + Iterator iterator = this.entitySlices[k].iterator(); // Spigot + ++ // Paper start - Don't search for inventories if we have none, and that is all we want ++ /* ++ * We check if they want inventories by seeing if it is the static `IEntitySelector.c` ++ * ++ * Make sure the inventory selector stays in sync. ++ * It should be the one that checks `var1 instanceof IInventory && var1.isAlive()` ++ */ ++ if (predicate == IEntitySelector.isInventory() && inventoryEntityCounts[k] <= 0) continue; ++ // Paper end + while (iterator.hasNext()) { + Entity entity = (Entity) iterator.next(); + if (entity.shouldBeRemoved) continue; // Paper +@@ -0,0 +0,0 @@ public class Chunk implements IChunkAccess { + i = MathHelper.clamp(i, 0, this.entitySlices.length - 1); + j = MathHelper.clamp(j, 0, this.entitySlices.length - 1); + ++ // Paper start ++ int[] counts; ++ if (EntityItem.class.isAssignableFrom(oclass)) { ++ counts = itemCounts; ++ } else if (IInventory.class.isAssignableFrom(oclass)) { ++ counts = inventoryEntityCounts; ++ } else { ++ counts = null; ++ } ++ // Paper end + for (int k = i; k <= j; ++k) { ++ if (counts != null && counts[k] <= 0) continue; // Paper - Don't check a chunk if it doesn't have the type we are looking for + Iterator iterator = this.entitySlices[k].iterator(); // Spigot + + while (iterator.hasNext()) { +diff --git a/src/main/java/net/minecraft/server/IEntitySelector.java b/src/main/java/net/minecraft/server/IEntitySelector.java +index 56488b78d..56739e6ed 100644 +--- a/src/main/java/net/minecraft/server/IEntitySelector.java ++++ b/src/main/java/net/minecraft/server/IEntitySelector.java +@@ -0,0 +0,0 @@ public final class IEntitySelector { + public static final Predicate c = (entity) -> { + return entity.isAlive() && !entity.isVehicle() && !entity.isPassenger(); + }; ++ public static final Predicate isInventory() { return d; } // Paper - OBFHELPER + public static final Predicate d = (entity) -> { + return entity instanceof IInventory && entity.isAlive(); + }; +-- \ No newline at end of file