From f275e9cb9cd28eb560eab3cb444dd3393f0aa583 Mon Sep 17 00:00:00 2001 From: Aikar Date: Fri, 24 Apr 2020 03:01:17 -0400 Subject: [PATCH] Optimize Hoppers - Major Boost - Got2GoFast! * Don't check for Entities with Inventories if the block above us is also occluding (not just Inventoried) * Remove Streams from Item Suck In and restore restore 1.12 AABB checks which is simpler and no voxel allocations (was doing TWO Item Suck ins) * Restore missing application of previous optimization to getEntities for Inventoried Entities from CullanP * Use getChunkIfLoadedImmediately for getting loaded entities (faster/simpler, no risk of sync loads) --- ...opper-searches-if-there-are-no-items.patch | 25 ++++- ...etChunkIfLoadedImmediately-in-places.patch | 19 +++- .../0414-Optimize-Hoppers.patch | 92 +++++++++++++++++-- 3 files changed, 119 insertions(+), 17 deletions(-) diff --git a/Spigot-Server-Patches/0389-Avoid-hopper-searches-if-there-are-no-items.patch b/Spigot-Server-Patches/0389-Avoid-hopper-searches-if-there-are-no-items.patch index e6defa389..76f8a04f0 100644 --- a/Spigot-Server-Patches/0389-Avoid-hopper-searches-if-there-are-no-items.patch +++ b/Spigot-Server-Patches/0389-Avoid-hopper-searches-if-there-are-no-items.patch @@ -1,4 +1,4 @@ -From 1bb7437c18fb1205e811164d1fc7a0bf1a8a7c4d Mon Sep 17 00:00:00 2001 +From 9884366681850e0b0653f26f7dcf2e0105277ed2 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 @@ -14,7 +14,7 @@ And since minecart hoppers are used _very_ rarely near we can avoid alot of sear 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 bdd04305..03c25eae 100644 +index bdd04305f5..29cfef1605 100644 --- a/src/main/java/net/minecraft/server/Chunk.java +++ b/src/main/java/net/minecraft/server/Chunk.java @@ -84,6 +84,10 @@ public class Chunk implements IChunkAccess { @@ -54,7 +54,22 @@ index bdd04305..03c25eae 100644 entityCounts.decrement(entity.getMinecraftKeyString()); this.markDirty(); // Paper // Paper end -@@ -852,9 +868,29 @@ public class Chunk implements IChunkAccess { +@@ -833,6 +849,14 @@ 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.d` ++ * ++ * 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; + while (iterator.hasNext()) { + T entity = (T) iterator.next(); // CraftBukkit - decompile error + if (entity.shouldBeRemoved) continue; // Paper +@@ -852,9 +876,29 @@ public class Chunk implements IChunkAccess { i = MathHelper.clamp(i, 0, this.entitySlices.length - 1); j = MathHelper.clamp(j, 0, this.entitySlices.length - 1); @@ -85,7 +100,7 @@ index bdd04305..03c25eae 100644 T t0 = (T) iterator.next(); // CraftBukkit - decompile error if (t0.shouldBeRemoved) continue; // Paper diff --git a/src/main/java/net/minecraft/server/IEntitySelector.java b/src/main/java/net/minecraft/server/IEntitySelector.java -index 498f3810..a2d1ef36 100644 +index 498f381099..a2d1ef3602 100644 --- a/src/main/java/net/minecraft/server/IEntitySelector.java +++ b/src/main/java/net/minecraft/server/IEntitySelector.java @@ -11,6 +11,7 @@ public final class IEntitySelector { @@ -97,5 +112,5 @@ index 498f3810..a2d1ef36 100644 return entity instanceof IInventory && entity.isAlive(); }; -- -2.25.1.windows.1 +2.25.1 diff --git a/Spigot-Server-Patches/0391-Use-getChunkIfLoadedImmediately-in-places.patch b/Spigot-Server-Patches/0391-Use-getChunkIfLoadedImmediately-in-places.patch index a7c60a733..1f8c19dd0 100644 --- a/Spigot-Server-Patches/0391-Use-getChunkIfLoadedImmediately-in-places.patch +++ b/Spigot-Server-Patches/0391-Use-getChunkIfLoadedImmediately-in-places.patch @@ -1,4 +1,4 @@ -From dda783c45cf1ec51ff0039bb5528281ed983ef67 Mon Sep 17 00:00:00 2001 +From bd020770748fe0dee966f8d73431a8f0da868e35 Mon Sep 17 00:00:00 2001 From: Spottedleaf Date: Mon, 8 Jul 2019 00:13:36 -0700 Subject: [PATCH] Use getChunkIfLoadedImmediately in places @@ -8,7 +8,7 @@ ticket level 33 (yes getChunkIfLoaded will actually perform a chunk load in that case). diff --git a/src/main/java/net/minecraft/server/PlayerConnection.java b/src/main/java/net/minecraft/server/PlayerConnection.java -index 69133121..f88bcb29 100644 +index 691331217b..f88bcb29db 100644 --- a/src/main/java/net/minecraft/server/PlayerConnection.java +++ b/src/main/java/net/minecraft/server/PlayerConnection.java @@ -989,7 +989,7 @@ public class PlayerConnection implements PacketListenerPlayIn { @@ -21,7 +21,7 @@ index 69133121..f88bcb29 100644 return; } diff --git a/src/main/java/net/minecraft/server/World.java b/src/main/java/net/minecraft/server/World.java -index 0bde1717..90f60dfd 100644 +index 0bde171743..311685180f 100644 --- a/src/main/java/net/minecraft/server/World.java +++ b/src/main/java/net/minecraft/server/World.java @@ -116,8 +116,16 @@ public abstract class World implements GeneratorAccess, AutoCloseable { @@ -59,8 +59,17 @@ index 0bde1717..90f60dfd 100644 return ichunkaccess == null ? false : ichunkaccess.getType(blockposition).a((IBlockAccess) this, blockposition, entity); } +@@ -1232,7 +1240,7 @@ public abstract class World implements GeneratorAccess, AutoCloseable { + + for (int i1 = i; i1 < j; ++i1) { + for (int j1 = k; j1 < l; ++j1) { +- Chunk chunk = ichunkprovider.a(i1, j1); ++ Chunk chunk = (Chunk)this.getChunkIfLoadedImmediately(i1, j1); // Paper + + if (chunk != null) { + chunk.a(oclass, axisalignedbb, list, predicate); diff --git a/src/main/java/org/spigotmc/ActivationRange.java b/src/main/java/org/spigotmc/ActivationRange.java -index f86404f8..92601c58 100644 +index f86404f83a..92601c581c 100644 --- a/src/main/java/org/spigotmc/ActivationRange.java +++ b/src/main/java/org/spigotmc/ActivationRange.java @@ -143,9 +143,10 @@ public class ActivationRange @@ -77,5 +86,5 @@ index f86404f8..92601c58 100644 } } -- -2.25.1.windows.1 +2.25.1 diff --git a/Spigot-Server-Patches/0414-Optimize-Hoppers.patch b/Spigot-Server-Patches/0414-Optimize-Hoppers.patch index 21acce06a..2a24622ab 100644 --- a/Spigot-Server-Patches/0414-Optimize-Hoppers.patch +++ b/Spigot-Server-Patches/0414-Optimize-Hoppers.patch @@ -1,4 +1,4 @@ -From cacfeaa2e29f0014ceb10caf0fbcf3eb97c00018 Mon Sep 17 00:00:00 2001 +From 30b5dc4b6adee3603770473e1799d48e597b14c9 Mon Sep 17 00:00:00 2001 From: Aikar Date: Wed, 27 Apr 2016 22:09:52 -0400 Subject: [PATCH] Optimize Hoppers @@ -9,9 +9,11 @@ Subject: [PATCH] Optimize Hoppers However, pushes do not exhibit the same behavior, so this is not something plugins could of been relying on. * Add option (Default on) to cooldown hoppers when they fail to move an item due to full inventory * Skip subsequent InventoryMoveItemEvents if a plugin does not use the item after first event fire for an iteration +* Don't check for Entities with Inventories if the block above us is also occluding (not just Inventoried) +* Remove Streams from Item Suck In and restore restore 1.12 AABB checks which is simpler and no voxel allocations (was doing TWO Item Suck ins) diff --git a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java -index f8d8cb86..3b8488d3 100644 +index f8d8cb8655..3b8488d3ff 100644 --- a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java +++ b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java @@ -638,4 +638,13 @@ public class PaperWorldConfig { @@ -28,8 +30,30 @@ index f8d8cb86..3b8488d3 100644 + log("Hopper Move Item Events: " + (disableHopperMoveEvents ? "disabled" : "enabled")); + } } +diff --git a/src/main/java/net/minecraft/server/IHopper.java b/src/main/java/net/minecraft/server/IHopper.java +index e1aa272e52..4da26365ec 100644 +--- a/src/main/java/net/minecraft/server/IHopper.java ++++ b/src/main/java/net/minecraft/server/IHopper.java +@@ -12,12 +12,13 @@ public interface IHopper extends IInventory { + return IHopper.c; + } + +- @Nullable ++ //@Nullable // Paper - it's annoying + World getWorld(); ++ default BlockPosition getBlockPosition() { return new BlockPosition(getX(), getY(), getZ()); } // Paper + +- double z(); ++ double z();default double getX() { return z(); } // Paper - OBFHELPER + +- double A(); ++ double A();default double getY() { return A(); } // Paper - OBFHELPER + +- double B(); ++ double B();default double getZ() { return B(); } // Paper - OBFHELPER + } diff --git a/src/main/java/net/minecraft/server/ItemStack.java b/src/main/java/net/minecraft/server/ItemStack.java -index d953cdef..d6e43313 100644 +index d953cdef14..d6e43313bf 100644 --- a/src/main/java/net/minecraft/server/ItemStack.java +++ b/src/main/java/net/minecraft/server/ItemStack.java @@ -482,11 +482,12 @@ public final class ItemStack { @@ -49,7 +73,7 @@ index d953cdef..d6e43313 100644 itemstack.d(this.C()); if (this.tag != null) { diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java -index 61fc659e..177d1445 100644 +index 61fc659ed2..177d1445ad 100644 --- a/src/main/java/net/minecraft/server/MinecraftServer.java +++ b/src/main/java/net/minecraft/server/MinecraftServer.java @@ -1217,6 +1217,7 @@ public abstract class MinecraftServer extends IAsyncTaskHandlerReentrant { return worldserver.getWorldData().getName() + " " + IRegistry.DIMENSION_TYPE.getKey(worldserver.worldProvider.getDimensionManager()); diff --git a/src/main/java/net/minecraft/server/TileEntity.java b/src/main/java/net/minecraft/server/TileEntity.java -index 95827924..a8e64dfd 100644 +index 958279249f..a8e64dfdab 100644 --- a/src/main/java/net/minecraft/server/TileEntity.java +++ b/src/main/java/net/minecraft/server/TileEntity.java @@ -62,6 +62,7 @@ public abstract class TileEntity implements KeyedObject { // Paper @@ -81,7 +105,7 @@ index 95827924..a8e64dfd 100644 this.world.b(this.position, this); if (!this.c.isAir()) { diff --git a/src/main/java/net/minecraft/server/TileEntityHopper.java b/src/main/java/net/minecraft/server/TileEntityHopper.java -index 907d088c..4afd33a4 100644 +index 907d088c86..280c4e99e8 100644 --- a/src/main/java/net/minecraft/server/TileEntityHopper.java +++ b/src/main/java/net/minecraft/server/TileEntityHopper.java @@ -168,6 +168,160 @@ public class TileEntityHopper extends TileEntityLootable implements IHopper, ITi @@ -306,6 +330,60 @@ index 907d088c..4afd33a4 100644 itemstack = ItemStack.a; flag = true; } else if (a(itemstack1, itemstack)) { +@@ -419,18 +578,24 @@ public class TileEntityHopper extends TileEntityLootable implements IHopper, ITi + } + + public static List c(IHopper ihopper) { +- return (List) ihopper.P_().d().stream().flatMap((axisalignedbb) -> { +- return ihopper.getWorld().a(EntityItem.class, axisalignedbb.d(ihopper.z() - 0.5D, ihopper.A() - 0.5D, ihopper.B() - 0.5D), IEntitySelector.a).stream(); +- }).collect(Collectors.toList()); ++ // Paper start - Optimize item suck in. remove streams, restore 1.12 checks. Seriously checking the bowl?! ++ World world = ihopper.getWorld(); ++ double d0 = ihopper.getX(); ++ double d1 = ihopper.getY(); ++ double d2 = ihopper.getZ(); ++ AxisAlignedBB bb = new AxisAlignedBB(d0 - 0.5D, d1, d2 - 0.5D, d0 + 0.5D, d1 + 1.5D, d2 + 0.5D); ++ return world.getEntities(EntityItem.class, bb, Entity::isAlive); ++ // Paper end + } + + @Nullable + public static IInventory b(World world, BlockPosition blockposition) { +- return a(world, (double) blockposition.getX() + 0.5D, (double) blockposition.getY() + 0.5D, (double) blockposition.getZ() + 0.5D); ++ return a(world, (double) blockposition.getX() + 0.5D, (double) blockposition.getY() + 0.5D, (double) blockposition.getZ() + 0.5D, true); // Paper + } + + @Nullable +- public static IInventory a(World world, double d0, double d1, double d2) { ++ public static IInventory a(World world, double d0, double d1, double d2) { return a(world, d0, d1, d2, false); } // Paper - overload to default false ++ public static IInventory a(World world, double d0, double d1, double d2, boolean optimizeEntities) { // Paper + Object object = null; + BlockPosition blockposition = new BlockPosition(d0, d1, d2); + if ( !world.isLoaded( blockposition ) ) return null; // Spigot +@@ -450,7 +615,7 @@ public class TileEntityHopper extends TileEntityLootable implements IHopper, ITi + } + } + +- if (object == null) { ++ if (object == null && (!optimizeEntities || !org.bukkit.craftbukkit.util.CraftMagicNumbers.getMaterial(block).isOccluding())) { // Paper + List list = world.getEntities((Entity) null, new AxisAlignedBB(d0 - 0.5D, d1 - 0.5D, d2 - 0.5D, d0 + 0.5D, d1 + 0.5D, d2 + 0.5D), IEntitySelector.d); + + if (!list.isEmpty()) { +diff --git a/src/main/java/net/minecraft/server/World.java b/src/main/java/net/minecraft/server/World.java +index 568e04faa3..9e161746f2 100644 +--- a/src/main/java/net/minecraft/server/World.java ++++ b/src/main/java/net/minecraft/server/World.java +@@ -1205,8 +1205,8 @@ public abstract class World implements GeneratorAccess, AutoCloseable { + return list; + } + +- @Override +- public List a(Class oclass, AxisAlignedBB axisalignedbb, @Nullable Predicate predicate) { ++ public List getEntities(Class oclass, AxisAlignedBB axisalignedbb, @Nullable Predicate predicate) { return a(oclass, axisalignedbb, predicate); } // Paper - OBFHELPER ++ @Override public List a(Class oclass, AxisAlignedBB axisalignedbb, @Nullable Predicate predicate) { + this.getMethodProfiler().c("getEntities"); + int i = MathHelper.floor((axisalignedbb.minX - 2.0D) / 16.0D); + int j = MathHelper.f((axisalignedbb.maxX + 2.0D) / 16.0D); -- -2.25.1.windows.1 +2.25.1