From fc917d1687acab7313793f5dab44277c7dc4a1d1 Mon Sep 17 00:00:00 2001 From: Aikar Date: Mon, 11 May 2020 03:42:32 -0400 Subject: [PATCH] Optimize Hoppers - Major performance improvement MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Removed streams from hoppers and also fixed a mistake in the logic. When this patch was ported to 1.14/1.15, a line of code was put in the wrong place which disabled a significant portion of the improvement. Replaced usages of streams in isEmpty and itemstack checks Replaced usage of streams in pulling loop Replaced usage of streams in Lootable Inventory isEmpty() check Only check for refilling Lootable Inventory when accessing first slot, not all All of these in general were pretty significant hits, so this single commit is going to cause tacos to magically appear in front of you every day. 🌮🌮🌮🌮🌮🌮🌮🌮🌮🌮🌮🌮🌮🌮🌮🌮🌮🌮🌮🌮🌮🌮🌮🌮🌮🌮🌮🌮🌮🌮🌮🌮🌮 Nom Nom Nom If you hate taco's, you're not allowed to use this improvement. Also ignore the renames, pulled a lot of PR's. --- .../0414-Optimize-Hoppers.patch | 145 ++++++++++++++++-- ...-Fix-PotionEffect-ignores-icon-flag.patch} | 0 ...brigadier-child-sorting-performance.patch} | 0 ...enerate-Carving-Masks-BitSet-unless.patch} | 0 ...ock-unless-actually-showing-the-mes.patch} | 0 ...uid-s-Entity-Collision-optimisation.patch} | 2 +- ...e-Streams-usage-in-Entity-Collision.patch} | 2 +- ...ure-Entity-AABB-s-are-never-invalid.patch} | 0 ...API.patch => 0516-Potential-bed-API.patch} | 0 ...ait-for-Async-Tasks-during-shutdown.patch} | 0 ...orldBorder-collision-checks-and-air.patch} | 0 ...er-respects-game-and-entity-rules-f.patch} | 0 12 files changed, 130 insertions(+), 19 deletions(-) rename Spigot-Server-Patches/{0508-Fix-PotionEffect-ignores-icon-flag.patch => 0509-Fix-PotionEffect-ignores-icon-flag.patch} (100%) rename Spigot-Server-Patches/{0509-Optimize-brigadier-child-sorting-performance.patch => 0510-Optimize-brigadier-child-sorting-performance.patch} (100%) rename Spigot-Server-Patches/{0510-MC-183249-Don-t-generate-Carving-Masks-BitSet-unless.patch => 0511-MC-183249-Don-t-generate-Carving-Masks-BitSet-unless.patch} (100%) rename Spigot-Server-Patches/{0511-Don-t-toString-block-unless-actually-showing-the-mes.patch => 0512-Don-t-toString-block-unless-actually-showing-the-mes.patch} (100%) rename Spigot-Server-Patches/{0512-Implement-JellySquid-s-Entity-Collision-optimisation.patch => 0513-Implement-JellySquid-s-Entity-Collision-optimisation.patch} (98%) rename Spigot-Server-Patches/{0513-Remove-some-Streams-usage-in-Entity-Collision.patch => 0514-Remove-some-Streams-usage-in-Entity-Collision.patch} (99%) rename Spigot-Server-Patches/{0514-Ensure-Entity-AABB-s-are-never-invalid.patch => 0515-Ensure-Entity-AABB-s-are-never-invalid.patch} (100%) rename Spigot-Server-Patches/{0514-Potential-bed-API.patch => 0516-Potential-bed-API.patch} (100%) rename Spigot-Server-Patches/{0515-Wait-for-Async-Tasks-during-shutdown.patch => 0517-Wait-for-Async-Tasks-during-shutdown.patch} (100%) rename Spigot-Server-Patches/{0516-Optimize-WorldBorder-collision-checks-and-air.patch => 0518-Optimize-WorldBorder-collision-checks-and-air.patch} (100%) rename Spigot-Server-Patches/{0520-Ensure-EntityRaider-respects-game-and-entity-rules-f.patch => 0519-Ensure-EntityRaider-respects-game-and-entity-rules-f.patch} (100%) diff --git a/Spigot-Server-Patches/0414-Optimize-Hoppers.patch b/Spigot-Server-Patches/0414-Optimize-Hoppers.patch index 3461c48ca2..a357c25b64 100644 --- a/Spigot-Server-Patches/0414-Optimize-Hoppers.patch +++ b/Spigot-Server-Patches/0414-Optimize-Hoppers.patch @@ -105,7 +105,7 @@ index 958279249fdadfe5c2808d2a046636f06c3bd500..a8e64dfdab1e73894144a65c10c15d22 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 907d088c8691eec5d72836ccda420a7a0703ad22..280c4e99e828114d6b517d5b7bb018ec8f4565e3 100644 +index 907d088c8691eec5d72836ccda420a7a0703ad22..c755faed4f63884cb6a66bf951104a27dbaf887f 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 @@ -121,9 +121,10 @@ index 907d088c8691eec5d72836ccda420a7a0703ad22..280c4e99e828114d6b517d5b7bb018ec + skipPushModeEventFire = skipHopperEvents; + boolean foundItem = false; + for (int i = 0; i < this.getSize(); ++i) { -+ if (!this.getItem(i).isEmpty()) { ++ ItemStack item = this.getItem(i); ++ if (!item.isEmpty()) { + foundItem = true; -+ ItemStack origItemStack = this.getItem(i); ++ ItemStack origItemStack = item; + ItemStack itemstack = origItemStack; + + final int origCount = origItemStack.getCount(); @@ -160,8 +161,7 @@ index 907d088c8691eec5d72836ccda420a7a0703ad22..280c4e99e828114d6b517d5b7bb018ec + return false; + } + -+ private static boolean hopperPull(IHopper ihopper, IInventory iinventory, int i) { -+ ItemStack origItemStack = iinventory.getItem(i); ++ private static boolean hopperPull(IHopper ihopper, IInventory iinventory, ItemStack origItemStack, int i) { + ItemStack itemstack = origItemStack; + final int origCount = origItemStack.getCount(); + final World world = ihopper.getWorld(); @@ -286,23 +286,100 @@ index 907d088c8691eec5d72836ccda420a7a0703ad22..280c4e99e828114d6b517d5b7bb018ec } } } -@@ -246,6 +401,7 @@ public class TileEntityHopper extends TileEntityLootable implements IHopper, ITi +@@ -225,18 +380,54 @@ public class TileEntityHopper extends TileEntityLootable implements IHopper, ITi + return iinventory instanceof IWorldInventory ? IntStream.of(((IWorldInventory) iinventory).getSlotsForFace(enumdirection)) : IntStream.range(0, iinventory.getSize()); + } + +- private boolean b(IInventory iinventory, EnumDirection enumdirection) { +- return a(iinventory, enumdirection).allMatch((i) -> { +- ItemStack itemstack = iinventory.getItem(i); ++ private static boolean allMatch(IInventory iinventory, EnumDirection enumdirection, java.util.function.BiPredicate test) { ++ if (iinventory instanceof IWorldInventory) { ++ for (int i : ((IWorldInventory) iinventory).getSlotsForFace(enumdirection)) { ++ if (!test.test(iinventory.getItem(i), i)) { ++ return false; ++ } ++ } ++ } else { ++ int size = iinventory.getSize(); ++ for (int i = 0; i < size; i++) { ++ if (!test.test(iinventory.getItem(i), i)) { ++ return false; ++ } ++ } ++ } ++ return true; ++ } + +- return itemstack.getCount() >= itemstack.getMaxStackSize(); +- }); ++ private static boolean anyMatch(IInventory iinventory, EnumDirection enumdirection, java.util.function.BiPredicate test) { ++ if (iinventory instanceof IWorldInventory) { ++ for (int i : ((IWorldInventory) iinventory).getSlotsForFace(enumdirection)) { ++ if (test.test(iinventory.getItem(i), i)) { ++ return true; ++ } ++ } ++ } else { ++ int size = iinventory.getSize(); ++ for (int i = 0; i < size; i++) { ++ if (test.test(iinventory.getItem(i), i)) { ++ return true; ++ } ++ } ++ } ++ return true; ++ } ++ private static final java.util.function.BiPredicate STACK_SIZE_TEST = (itemstack, i) -> itemstack.getCount() >= itemstack.getMaxStackSize(); ++ private static final java.util.function.BiPredicate IS_EMPTY_TEST = (itemstack, i) -> itemstack.isEmpty(); ++ ++ // Paper end ++ ++ private boolean b(IInventory iinventory, EnumDirection enumdirection) { ++ // Paper start - no streams ++ return allMatch(iinventory, enumdirection, STACK_SIZE_TEST); ++ // Paper end + } + + private static boolean c(IInventory iinventory, EnumDirection enumdirection) { +- return a(iinventory, enumdirection).allMatch((i) -> { +- return iinventory.getItem(i).isEmpty(); +- }); ++ return allMatch(iinventory, enumdirection, IS_EMPTY_TEST); + } + + public static boolean a(IHopper ihopper) { +@@ -245,9 +436,17 @@ public class TileEntityHopper extends TileEntityLootable implements IHopper, ITi + if (iinventory != null) { EnumDirection enumdirection = EnumDirection.DOWN; - return c(iinventory, enumdirection) ? false : a(iinventory, enumdirection).anyMatch((i) -> { -+ skipPullModeEventFire = skipHopperEvents; // Paper - return a(ihopper, iinventory, i, enumdirection); +- return c(iinventory, enumdirection) ? false : a(iinventory, enumdirection).anyMatch((i) -> { +- return a(ihopper, iinventory, i, enumdirection); ++ // Paper start - optimize hoppers and remove streams ++ skipPullModeEventFire = skipHopperEvents; ++ return !c(iinventory, enumdirection) && anyMatch(iinventory, enumdirection, (item, i) -> { ++ // Logic copied from below to avoid extra getItem calls ++ if (!item.isEmpty() && canTakeItem(iinventory, item, i, enumdirection)) { ++ return hopperPull(ihopper, iinventory, item, i); ++ } else { ++ return false; ++ } }); ++ // Paper end } else { -@@ -269,6 +425,7 @@ public class TileEntityHopper extends TileEntityLootable implements IHopper, ITi + Iterator iterator = c(ihopper).iterator(); + +@@ -268,7 +467,8 @@ public class TileEntityHopper extends TileEntityLootable implements IHopper, ITi + private static boolean a(IHopper ihopper, IInventory iinventory, int i, EnumDirection enumdirection) { ItemStack itemstack = iinventory.getItem(i); - if (!itemstack.isEmpty() && b(iinventory, itemstack, i, enumdirection)) { -+ return hopperPull(ihopper, iinventory, i); /* // Paper - disable rest +- if (!itemstack.isEmpty() && b(iinventory, itemstack, i, enumdirection)) { ++ if (!itemstack.isEmpty() && b(iinventory, itemstack, i, enumdirection)) { // If this logic changes, update above. this is left inused incase reflective plugins ++ return hopperPull(ihopper, iinventory, itemstack, i); /* // Paper - disable rest ItemStack itemstack1 = itemstack.cloneItemStack(); // ItemStack itemstack2 = addItem(iinventory, ihopper, iinventory.splitStack(i, 1), (EnumDirection) null); // CraftBukkit start - Call event on collection of items from inventories into the hopper -@@ -305,7 +462,7 @@ public class TileEntityHopper extends TileEntityLootable implements IHopper, ITi +@@ -305,7 +505,7 @@ public class TileEntityHopper extends TileEntityLootable implements IHopper, ITi } itemstack1.subtract(origCount - itemstack2.getCount()); // Spigot @@ -311,7 +388,7 @@ index 907d088c8691eec5d72836ccda420a7a0703ad22..280c4e99e828114d6b517d5b7bb018ec } return false; -@@ -314,7 +471,7 @@ public class TileEntityHopper extends TileEntityLootable implements IHopper, ITi +@@ -314,7 +514,7 @@ public class TileEntityHopper extends TileEntityLootable implements IHopper, ITi public static boolean a(IInventory iinventory, EntityItem entityitem) { boolean flag = false; // CraftBukkit start @@ -320,7 +397,15 @@ index 907d088c8691eec5d72836ccda420a7a0703ad22..280c4e99e828114d6b517d5b7bb018ec entityitem.world.getServer().getPluginManager().callEvent(event); if (event.isCancelled()) { return false; -@@ -368,7 +525,9 @@ public class TileEntityHopper extends TileEntityLootable implements IHopper, ITi +@@ -356,6 +556,7 @@ public class TileEntityHopper extends TileEntityLootable implements IHopper, ITi + return !iinventory.b(i, itemstack) ? false : !(iinventory instanceof IWorldInventory) || ((IWorldInventory) iinventory).canPlaceItemThroughFace(i, itemstack, enumdirection); + } + ++ private static boolean canTakeItem(IInventory iinventory, ItemStack itemstack, int i, EnumDirection enumdirection) { return b(iinventory, itemstack, i, enumdirection); } // Paper - OBFHELPER + private static boolean b(IInventory iinventory, ItemStack itemstack, int i, EnumDirection enumdirection) { + return !(iinventory instanceof IWorldInventory) || ((IWorldInventory) iinventory).canTakeItemThroughFace(i, itemstack, enumdirection); + } +@@ -368,7 +569,9 @@ public class TileEntityHopper extends TileEntityLootable implements IHopper, ITi boolean flag1 = iinventory1.isEmpty(); if (itemstack1.isEmpty()) { @@ -330,7 +415,7 @@ index 907d088c8691eec5d72836ccda420a7a0703ad22..280c4e99e828114d6b517d5b7bb018ec itemstack = ItemStack.a; flag = true; } else if (a(itemstack1, itemstack)) { -@@ -419,18 +578,24 @@ public class TileEntityHopper extends TileEntityLootable implements IHopper, ITi +@@ -419,18 +622,24 @@ public class TileEntityHopper extends TileEntityLootable implements IHopper, ITi } public static List c(IHopper ihopper) { @@ -360,7 +445,7 @@ index 907d088c8691eec5d72836ccda420a7a0703ad22..280c4e99e828114d6b517d5b7bb018ec 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 +@@ -450,7 +659,7 @@ public class TileEntityHopper extends TileEntityLootable implements IHopper, ITi } } @@ -369,6 +454,32 @@ index 907d088c8691eec5d72836ccda420a7a0703ad22..280c4e99e828114d6b517d5b7bb018ec 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/TileEntityLootable.java b/src/main/java/net/minecraft/server/TileEntityLootable.java +index d4cbce3243fe1f4973c9c0ae0dbdab10e3390897..3b394c2726e0fbe595641a022e59c8967d525f82 100644 +--- a/src/main/java/net/minecraft/server/TileEntityLootable.java ++++ b/src/main/java/net/minecraft/server/TileEntityLootable.java +@@ -72,12 +72,19 @@ public abstract class TileEntityLootable extends TileEntityContainer { + @Override + public boolean isEmpty() { + this.d((EntityHuman) null); +- return this.f().stream().allMatch(ItemStack::isEmpty); ++ // Paper start ++ for (ItemStack itemStack : this.f()) { ++ if (!itemStack.isEmpty()) { ++ return false; ++ } ++ } ++ // Paper end ++ return true; + } + + @Override + public ItemStack getItem(int i) { +- this.d((EntityHuman) null); ++ if (i == 0) this.d((EntityHuman) null); // Paper + return (ItemStack) this.f().get(i); + } + diff --git a/src/main/java/net/minecraft/server/World.java b/src/main/java/net/minecraft/server/World.java index 568e04faa314552e14286efdfcdfb79e682fda95..9e161746f2acbe544140979bddb51ac26ee0d20f 100644 --- a/src/main/java/net/minecraft/server/World.java diff --git a/Spigot-Server-Patches/0508-Fix-PotionEffect-ignores-icon-flag.patch b/Spigot-Server-Patches/0509-Fix-PotionEffect-ignores-icon-flag.patch similarity index 100% rename from Spigot-Server-Patches/0508-Fix-PotionEffect-ignores-icon-flag.patch rename to Spigot-Server-Patches/0509-Fix-PotionEffect-ignores-icon-flag.patch diff --git a/Spigot-Server-Patches/0509-Optimize-brigadier-child-sorting-performance.patch b/Spigot-Server-Patches/0510-Optimize-brigadier-child-sorting-performance.patch similarity index 100% rename from Spigot-Server-Patches/0509-Optimize-brigadier-child-sorting-performance.patch rename to Spigot-Server-Patches/0510-Optimize-brigadier-child-sorting-performance.patch diff --git a/Spigot-Server-Patches/0510-MC-183249-Don-t-generate-Carving-Masks-BitSet-unless.patch b/Spigot-Server-Patches/0511-MC-183249-Don-t-generate-Carving-Masks-BitSet-unless.patch similarity index 100% rename from Spigot-Server-Patches/0510-MC-183249-Don-t-generate-Carving-Masks-BitSet-unless.patch rename to Spigot-Server-Patches/0511-MC-183249-Don-t-generate-Carving-Masks-BitSet-unless.patch diff --git a/Spigot-Server-Patches/0511-Don-t-toString-block-unless-actually-showing-the-mes.patch b/Spigot-Server-Patches/0512-Don-t-toString-block-unless-actually-showing-the-mes.patch similarity index 100% rename from Spigot-Server-Patches/0511-Don-t-toString-block-unless-actually-showing-the-mes.patch rename to Spigot-Server-Patches/0512-Don-t-toString-block-unless-actually-showing-the-mes.patch diff --git a/Spigot-Server-Patches/0512-Implement-JellySquid-s-Entity-Collision-optimisation.patch b/Spigot-Server-Patches/0513-Implement-JellySquid-s-Entity-Collision-optimisation.patch similarity index 98% rename from Spigot-Server-Patches/0512-Implement-JellySquid-s-Entity-Collision-optimisation.patch rename to Spigot-Server-Patches/0513-Implement-JellySquid-s-Entity-Collision-optimisation.patch index 1e30e90f45..50824c0845 100644 --- a/Spigot-Server-Patches/0512-Implement-JellySquid-s-Entity-Collision-optimisation.patch +++ b/Spigot-Server-Patches/0513-Implement-JellySquid-s-Entity-Collision-optimisation.patch @@ -9,7 +9,7 @@ Original code by JellySquid, licensed under GNU Lesser General Public License v3 you can find the original code on https://github.com/jellysquid3/lithium-fabric/tree/1.15.x/fabric (Yarn mappings) diff --git a/src/main/java/net/minecraft/server/ICollisionAccess.java b/src/main/java/net/minecraft/server/ICollisionAccess.java -index e1699528556f5742d907ba4dc4d831e84a5f1287..2974467c2cb4ad9241f005c5a2935251434f7d78 100644 +index 8b0670b8db0bb739fb54fee368a53eadeb72937e..c501dad733b6e6fe89673b35a307e02d474570b6 100644 --- a/src/main/java/net/minecraft/server/ICollisionAccess.java +++ b/src/main/java/net/minecraft/server/ICollisionAccess.java @@ -113,11 +113,24 @@ public interface ICollisionAccess extends IBlockAccess { diff --git a/Spigot-Server-Patches/0513-Remove-some-Streams-usage-in-Entity-Collision.patch b/Spigot-Server-Patches/0514-Remove-some-Streams-usage-in-Entity-Collision.patch similarity index 99% rename from Spigot-Server-Patches/0513-Remove-some-Streams-usage-in-Entity-Collision.patch rename to Spigot-Server-Patches/0514-Remove-some-Streams-usage-in-Entity-Collision.patch index 81f513a8a0..60043775c0 100644 --- a/Spigot-Server-Patches/0513-Remove-some-Streams-usage-in-Entity-Collision.patch +++ b/Spigot-Server-Patches/0514-Remove-some-Streams-usage-in-Entity-Collision.patch @@ -21,7 +21,7 @@ index e865a5694f78fb9273a0625ab2c30b87d0711a90..5648ba73c533f622c35c808decdb305f default Stream b(@Nullable Entity entity, AxisAlignedBB axisalignedbb, Set set) { return IEntityAccess.super.b(entity, axisalignedbb, set); diff --git a/src/main/java/net/minecraft/server/ICollisionAccess.java b/src/main/java/net/minecraft/server/ICollisionAccess.java -index 2974467c2cb4ad9241f005c5a2935251434f7d78..1270f8823817ef8f995bf73db1816de548cb8c21 100644 +index c501dad733b6e6fe89673b35a307e02d474570b6..b98037a1af4cce52fb85867ed778c4e9aadced0b 100644 --- a/src/main/java/net/minecraft/server/ICollisionAccess.java +++ b/src/main/java/net/minecraft/server/ICollisionAccess.java @@ -43,18 +43,39 @@ public interface ICollisionAccess extends IBlockAccess { diff --git a/Spigot-Server-Patches/0514-Ensure-Entity-AABB-s-are-never-invalid.patch b/Spigot-Server-Patches/0515-Ensure-Entity-AABB-s-are-never-invalid.patch similarity index 100% rename from Spigot-Server-Patches/0514-Ensure-Entity-AABB-s-are-never-invalid.patch rename to Spigot-Server-Patches/0515-Ensure-Entity-AABB-s-are-never-invalid.patch diff --git a/Spigot-Server-Patches/0514-Potential-bed-API.patch b/Spigot-Server-Patches/0516-Potential-bed-API.patch similarity index 100% rename from Spigot-Server-Patches/0514-Potential-bed-API.patch rename to Spigot-Server-Patches/0516-Potential-bed-API.patch diff --git a/Spigot-Server-Patches/0515-Wait-for-Async-Tasks-during-shutdown.patch b/Spigot-Server-Patches/0517-Wait-for-Async-Tasks-during-shutdown.patch similarity index 100% rename from Spigot-Server-Patches/0515-Wait-for-Async-Tasks-during-shutdown.patch rename to Spigot-Server-Patches/0517-Wait-for-Async-Tasks-during-shutdown.patch diff --git a/Spigot-Server-Patches/0516-Optimize-WorldBorder-collision-checks-and-air.patch b/Spigot-Server-Patches/0518-Optimize-WorldBorder-collision-checks-and-air.patch similarity index 100% rename from Spigot-Server-Patches/0516-Optimize-WorldBorder-collision-checks-and-air.patch rename to Spigot-Server-Patches/0518-Optimize-WorldBorder-collision-checks-and-air.patch diff --git a/Spigot-Server-Patches/0520-Ensure-EntityRaider-respects-game-and-entity-rules-f.patch b/Spigot-Server-Patches/0519-Ensure-EntityRaider-respects-game-and-entity-rules-f.patch similarity index 100% rename from Spigot-Server-Patches/0520-Ensure-EntityRaider-respects-game-and-entity-rules-f.patch rename to Spigot-Server-Patches/0519-Ensure-EntityRaider-respects-game-and-entity-rules-f.patch