add back optimizing hopper searches (#5839)
This commit is contained in:
parent
a0056c36f1
commit
3846367c2d
333 changed files with 147 additions and 132 deletions
|
@ -1,127 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: CullanP <cullanpage@gmail.com>
|
||||
Date: Thu, 3 Mar 2016 02:13:38 -0600
|
||||
Subject: [PATCH] Avoid hopper searches if there are no items
|
||||
1.17: figure this out after methods got moved
|
||||
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/entity/EntitySelector.java b/src/main/java/net/minecraft/world/entity/EntitySelector.java
|
||||
index d3640975c5a33b4911428760691215905b987385..e7facd849e3511c64b4ae44b34382f4a4985f2a4 100644
|
||||
--- a/src/main/java/net/minecraft/world/entity/EntitySelector.java
|
||||
+++ b/src/main/java/net/minecraft/world/entity/EntitySelector.java
|
||||
@@ -16,6 +16,7 @@ public final class EntitySelector {
|
||||
public static final Predicate<Entity> ENTITY_NOT_BEING_RIDDEN = (entity) -> {
|
||||
return entity.isAlive() && !entity.isVehicle() && !entity.isPassenger();
|
||||
};
|
||||
+ public static final Predicate<Entity> isInventory() { return CONTAINER_ENTITY_SELECTOR; } // Paper - OBFHELPER
|
||||
public static final Predicate<Entity> CONTAINER_ENTITY_SELECTOR = (entity) -> {
|
||||
return entity instanceof Container && entity.isAlive();
|
||||
};
|
||||
diff --git a/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java b/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java
|
||||
index 85861545ec4620a6cfd06876dad091637bd29b0b..4fef3abe4b416cbebe1b456468b5c3e162de18f1 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java
|
||||
@@ -31,10 +31,13 @@ import net.minecraft.server.level.ChunkHolder;
|
||||
import net.minecraft.server.level.ServerChunkCache;
|
||||
import net.minecraft.server.level.ServerLevel;
|
||||
import net.minecraft.util.Mth;
|
||||
+import net.minecraft.world.Container;
|
||||
import net.minecraft.world.entity.Entity;
|
||||
+import net.minecraft.world.entity.EntitySelector;
|
||||
import net.minecraft.world.entity.EntityType;
|
||||
import net.minecraft.world.entity.boss.EnderDragonPart;
|
||||
import net.minecraft.world.entity.boss.enderdragon.EnderDragon;
|
||||
+import net.minecraft.world.entity.item.ItemEntity;
|
||||
import net.minecraft.world.level.ChunkPos;
|
||||
import net.minecraft.world.level.ChunkTickList;
|
||||
import net.minecraft.world.level.EmptyTickList;
|
||||
@@ -122,6 +125,10 @@ public class LevelChunk implements ChunkAccess {
|
||||
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 LevelChunk(Level world, ChunkPos pos, ChunkBiomeContainer biomes, UpgradeData upgradeData, TickList<Block> blockTickScheduler, TickList<Fluid> fluidTickScheduler, long inhabitedTime, @Nullable LevelChunkSection[] sections, @Nullable Consumer<LevelChunk> loadToWorldConsumer) {
|
||||
@@ -581,6 +588,13 @@ public class LevelChunk implements ChunkAccess {
|
||||
entity.zChunk = this.chunkPos.z;
|
||||
this.entities.add(entity); // Paper - per chunk entity list
|
||||
this.entitySlices[k].add(entity);
|
||||
+ // Paper start
|
||||
+ if (entity instanceof ItemEntity) {
|
||||
+ itemCounts[k]++;
|
||||
+ } else if (entity instanceof Container) {
|
||||
+ inventoryEntityCounts[k]++;
|
||||
+ }
|
||||
+ // Paper end
|
||||
entity.entitySlice = this.entitySlices[k]; // Paper
|
||||
this.markUnsaved(); // Paper
|
||||
}
|
||||
@@ -614,6 +628,11 @@ public class LevelChunk implements ChunkAccess {
|
||||
if (!this.entitySlices[section].remove(entity)) {
|
||||
return;
|
||||
}
|
||||
+ if (entity instanceof ItemEntity) {
|
||||
+ itemCounts[section]--;
|
||||
+ } else if (entity instanceof Container) {
|
||||
+ inventoryEntityCounts[section]--;
|
||||
+ }
|
||||
entityCounts.decrement(entity.getMinecraftKeyString());
|
||||
this.markUnsaved(); // Paper
|
||||
// Paper end
|
||||
@@ -899,6 +918,14 @@ public class LevelChunk implements ChunkAccess {
|
||||
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 == EntitySelector.isInventory() && inventoryEntityCounts[k] <= 0) continue;
|
||||
while (iterator.hasNext()) {
|
||||
T entity = (T) iterator.next(); // CraftBukkit - decompile error
|
||||
if (entity.shouldBeRemoved) continue; // Paper
|
||||
@@ -919,9 +946,29 @@ public class LevelChunk implements ChunkAccess {
|
||||
i = Mth.clamp(i, 0, this.entitySlices.length - 1);
|
||||
j = Mth.clamp(j, 0, this.entitySlices.length - 1);
|
||||
|
||||
+ // Paper start
|
||||
+ int[] counts;
|
||||
+ if (ItemEntity.class.isAssignableFrom(entityClass)) {
|
||||
+ counts = itemCounts;
|
||||
+ } else if (Container.class.isAssignableFrom(entityClass)) {
|
||||
+ 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
|
||||
|
||||
+ // 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 == EntitySelector.isInventory() && inventoryEntityCounts[k] <= 0) continue;
|
||||
+ // Paper end
|
||||
while (iterator.hasNext()) {
|
||||
T t0 = (T) iterator.next(); // CraftBukkit - decompile error
|
||||
if (t0.shouldBeRemoved) continue; // Paper
|
|
@ -0,0 +1,142 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: CullanP <cullanpage@gmail.com>
|
||||
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 507a70521a97c463d6fd22b788c39e9f458971c3..1dc1f7a5319e067b5f56c2fdadf04547ae1bc9ea 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/Level.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/Level.java
|
||||
@@ -984,7 +984,7 @@ 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 9a7b2602c2549dd03ad097c4a922a10a5e869645..5342eafe25614d262eeb39fa517a242e27d998f6 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/entity/EntitySection.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/entity/EntitySection.java
|
||||
@@ -12,6 +12,10 @@ public class EntitySection<T> {
|
||||
protected static final Logger LOGGER = LogManager.getLogger();
|
||||
private final ClassInstanceMultiMap<T> storage;
|
||||
private Visibility chunkStatus;
|
||||
+ // Paper start - track number of items and minecarts
|
||||
+ public int itemCount;
|
||||
+ public int inventoryEntityCount;
|
||||
+ // Paper end
|
||||
|
||||
public EntitySection(Class<T> entityClass, Visibility status) {
|
||||
this.chunkStatus = status;
|
||||
@@ -19,10 +23,24 @@ public class EntitySection<T> {
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
@@ -39,7 +57,7 @@ public class EntitySection<T> {
|
||||
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 067138e3983959347d19754e668bb7a1f702bad0..24552500307c42f9f3dc5c4d9ba73a84a787423a 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/entity/EntitySectionStorage.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/entity/EntitySectionStorage.java
|
||||
@@ -105,7 +105,7 @@ public class EntitySectionStorage<T extends EntityAccess> {
|
||||
|
||||
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;
|
||||
@@ -118,13 +118,20 @@ public class EntitySectionStorage<T extends EntityAccess> {
|
||||
}
|
||||
|
||||
public void getEntities(AABB box, Consumer<T> action) {
|
||||
+ // Paper start
|
||||
+ this.getEntities(box, action, false);
|
||||
+ }
|
||||
+ public void getEntities(AABB box, Consumer<T> action, boolean isContainerSearch) {
|
||||
+ // Paper end
|
||||
this.forEachAccessibleSection(box, (entitySection) -> {
|
||||
+ if (isContainerSearch && entitySection.inventoryEntityCount <= 0) return; // Paper
|
||||
entitySection.getEntities(createBoundingBoxCheck(box), action);
|
||||
});
|
||||
}
|
||||
|
||||
public <U extends T> void getEntities(EntityTypeTest<T, U> filter, AABB box, Consumer<U> 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 9723a0ad61548c8c6c4c5ef20a150d5b17d80afd..da1ad0b2679e392ed81b50c15f012c63cb5c939e 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/entity/LevelEntityGetter.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/entity/LevelEntityGetter.java
|
||||
@@ -17,6 +17,7 @@ public interface LevelEntityGetter<T extends EntityAccess> {
|
||||
<U extends T> void get(EntityTypeTest<T, U> filter, Consumer<U> action);
|
||||
|
||||
void get(AABB box, Consumer<T> action);
|
||||
+ void get(AABB box, Consumer<T> action, boolean isContainerSearch); // Paper
|
||||
|
||||
<U extends T> void get(EntityTypeTest<T, U> filter, AABB box, Consumer<U> 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 d5129c12c79eb6fe6b7e5f8eed4d24226423f5fd..3b13f6ea36a3bfecabe09221eb5c48dddab119db 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/entity/LevelEntityGetterAdapter.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/entity/LevelEntityGetterAdapter.java
|
||||
@@ -38,7 +38,13 @@ public class LevelEntityGetterAdapter<T extends EntityAccess> implements LevelEn
|
||||
|
||||
@Override
|
||||
public void get(AABB box, Consumer<T> action) {
|
||||
- this.sectionStorage.getEntities(box, action);
|
||||
+ // Paper start
|
||||
+ this.get(box, action, false);
|
||||
+ }
|
||||
+ @Override
|
||||
+ public void get(AABB box, Consumer<T> action, boolean isContainerSearch) {
|
||||
+ this.sectionStorage.getEntities(box, action, isContainerSearch);
|
||||
+ // Paper end
|
||||
}
|
||||
|
||||
@Override
|
|
@ -266,7 +266,7 @@ index e638d982b4bd1d261a7282cad6dab98ad0b55213..e305173fd1652a8b88ae8a9b94d0fae0
|
|||
|
||||
public BlockPos getHomePos() { // Paper - public
|
||||
diff --git a/src/main/java/net/minecraft/world/level/Level.java b/src/main/java/net/minecraft/world/level/Level.java
|
||||
index 507a70521a97c463d6fd22b788c39e9f458971c3..ea455e8aa7db5e9c397875e1fc8716cd52044c05 100644
|
||||
index 1dc1f7a5319e067b5f56c2fdadf04547ae1bc9ea..9d5dcaabe43ee36259b24063b4c74daddc7df773 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/Level.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/Level.java
|
||||
@@ -1300,10 +1300,18 @@ public abstract class Level implements LevelAccessor, AutoCloseable {
|
|
@ -299,7 +299,7 @@ index 0ef3c4982df88a7991a56d983ac733daa8adc507..cdd797c6fc7507a0e6376f7d9c521be8
|
|||
}
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/world/level/Level.java b/src/main/java/net/minecraft/world/level/Level.java
|
||||
index ea455e8aa7db5e9c397875e1fc8716cd52044c05..6aeb3ff79f08ade7ddd0d328d1a01514a91f671a 100644
|
||||
index 9d5dcaabe43ee36259b24063b4c74daddc7df773..06f2f76636804cd5f997bbe1558a104bc24aa84a 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/Level.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/Level.java
|
||||
@@ -837,6 +837,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable {
|
|
@ -56,7 +56,7 @@ index cdf214fca3b0055efa56702470d9d2f890a8aead..a12af10e28f2d023ba6f916b5e7a5353
|
|||
|
||||
this.level.getProfiler().push("explosion_blocks");
|
||||
diff --git a/src/main/java/net/minecraft/world/level/Level.java b/src/main/java/net/minecraft/world/level/Level.java
|
||||
index 6aeb3ff79f08ade7ddd0d328d1a01514a91f671a..b969e7f2087aed5b1f97ce8593a25ada737daec9 100644
|
||||
index 06f2f76636804cd5f997bbe1558a104bc24aa84a..b92d930448757968cd6a178f4bcafae72c93044c 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/Level.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/Level.java
|
||||
@@ -420,6 +420,10 @@ public abstract class Level implements LevelAccessor, AutoCloseable {
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue