From b0fe32db5f3514f2ce46d7f5a9b8d8389e7036a8 Mon Sep 17 00:00:00 2001 From: Jake Potrebic Date: Tue, 15 Jun 2021 01:29:12 -0700 Subject: [PATCH] add back optimizing hopper searches (#5839) --- ...opper-searches-if-there-are-no-items.patch | 142 ++++++++++++++++++ 1 file changed, 142 insertions(+) create mode 100644 patches/server/Avoid-hopper-searches-if-there-are-no-items.patch diff --git a/patches/server/Avoid-hopper-searches-if-there-are-no-items.patch b/patches/server/Avoid-hopper-searches-if-there-are-no-items.patch new file mode 100644 index 0000000000..f6733c95da --- /dev/null +++ b/patches/server/Avoid-hopper-searches-if-there-are-no-items.patch @@ -0,0 +1,142 @@ +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/world/level/Level.java b/src/main/java/net/minecraft/world/level/Level.java +index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 +--- a/src/main/java/net/minecraft/world/level/Level.java ++++ b/src/main/java/net/minecraft/world/level/Level.java +@@ -0,0 +0,0 @@ public abstract class Level implements LevelAccessor, AutoCloseable { + } + } + +- }); ++ }, predicate == net.minecraft.world.entity.EntitySelector.CONTAINER_ENTITY_SELECTOR); // Paper + return list; + } + +diff --git a/src/main/java/net/minecraft/world/level/entity/EntitySection.java b/src/main/java/net/minecraft/world/level/entity/EntitySection.java +index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 +--- a/src/main/java/net/minecraft/world/level/entity/EntitySection.java ++++ b/src/main/java/net/minecraft/world/level/entity/EntitySection.java +@@ -0,0 +0,0 @@ public class EntitySection { + protected static final Logger LOGGER = LogManager.getLogger(); + private final ClassInstanceMultiMap storage; + private Visibility chunkStatus; ++ // Paper start - track number of items and minecarts ++ public int itemCount; ++ public int inventoryEntityCount; ++ // Paper end + + public EntitySection(Class entityClass, Visibility status) { + this.chunkStatus = status; +@@ -0,0 +0,0 @@ public class EntitySection { + } + + public void add(T obj) { ++ // Paper start ++ if (obj instanceof net.minecraft.world.entity.item.ItemEntity) { ++ this.itemCount++; ++ } else if (obj instanceof net.minecraft.world.Container) { ++ this.inventoryEntityCount++; ++ } ++ // Paper end + this.storage.add(obj); + } + + public boolean remove(T obj) { ++ // Paper start ++ if (obj instanceof net.minecraft.world.entity.item.ItemEntity) { ++ this.itemCount--; ++ } else if (obj instanceof net.minecraft.world.Container) { ++ this.inventoryEntityCount--; ++ } ++ // Paper end + return this.storage.remove(obj); + } + +@@ -0,0 +0,0 @@ public class EntitySection { + for(T object : this.storage.find(type.getBaseClass())) { + U object2 = (U)type.tryCast(object); + if (object2 != null && filter.test(object2)) { +- action.accept((T)object2); ++ action.accept(object2); // Paper - decompile fix + } + } + +diff --git a/src/main/java/net/minecraft/world/level/entity/EntitySectionStorage.java b/src/main/java/net/minecraft/world/level/entity/EntitySectionStorage.java +index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 +--- a/src/main/java/net/minecraft/world/level/entity/EntitySectionStorage.java ++++ b/src/main/java/net/minecraft/world/level/entity/EntitySectionStorage.java +@@ -0,0 +0,0 @@ public class EntitySectionStorage { + + public LongSet getAllChunksWithExistingSections() { + LongSet longSet = new LongOpenHashSet(); +- this.sections.keySet().forEach((sectionPos) -> { ++ this.sections.keySet().forEach((java.util.function.LongConsumer) (sectionPos) -> { // Paper - decompile fix + longSet.add(getChunkKeyFromSectionKey(sectionPos)); + }); + return longSet; +@@ -0,0 +0,0 @@ public class EntitySectionStorage { + } + + public void getEntities(AABB box, Consumer action) { ++ // Paper start ++ this.getEntities(box, action, false); ++ } ++ public void getEntities(AABB box, Consumer action, boolean isContainerSearch) { ++ // Paper end + this.forEachAccessibleSection(box, (entitySection) -> { ++ if (isContainerSearch && entitySection.inventoryEntityCount <= 0) return; // Paper + entitySection.getEntities(createBoundingBoxCheck(box), action); + }); + } + + public void getEntities(EntityTypeTest filter, AABB box, Consumer action) { + this.forEachAccessibleSection(box, (entitySection) -> { ++ if (filter.getBaseClass() == net.minecraft.world.entity.item.ItemEntity.class && entitySection.itemCount <= 0) return; // Paper + entitySection.getEntities(filter, createBoundingBoxCheck(box), action); + }); + } +diff --git a/src/main/java/net/minecraft/world/level/entity/LevelEntityGetter.java b/src/main/java/net/minecraft/world/level/entity/LevelEntityGetter.java +index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 +--- a/src/main/java/net/minecraft/world/level/entity/LevelEntityGetter.java ++++ b/src/main/java/net/minecraft/world/level/entity/LevelEntityGetter.java +@@ -0,0 +0,0 @@ public interface LevelEntityGetter { + void get(EntityTypeTest filter, Consumer action); + + void get(AABB box, Consumer action); ++ void get(AABB box, Consumer action, boolean isContainerSearch); // Paper + + void get(EntityTypeTest filter, AABB box, Consumer action); + } +diff --git a/src/main/java/net/minecraft/world/level/entity/LevelEntityGetterAdapter.java b/src/main/java/net/minecraft/world/level/entity/LevelEntityGetterAdapter.java +index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 +--- a/src/main/java/net/minecraft/world/level/entity/LevelEntityGetterAdapter.java ++++ b/src/main/java/net/minecraft/world/level/entity/LevelEntityGetterAdapter.java +@@ -0,0 +0,0 @@ public class LevelEntityGetterAdapter implements LevelEn + + @Override + public void get(AABB box, Consumer action) { +- this.sectionStorage.getEntities(box, action); ++ // Paper start ++ this.get(box, action, false); ++ } ++ @Override ++ public void get(AABB box, Consumer action, boolean isContainerSearch) { ++ this.sectionStorage.getEntities(box, action, isContainerSearch); ++ // Paper end + } + + @Override