diff --git a/leaf-server/minecraft-patches/features/0090-Smart-sort-entities-in-NearestLivingEntitySensor.patch b/leaf-server/minecraft-patches/features/0090-Smart-sort-entities-in-NearestLivingEntitySensor.patch index 0fedddc9..79f5e72e 100644 --- a/leaf-server/minecraft-patches/features/0090-Smart-sort-entities-in-NearestLivingEntitySensor.patch +++ b/leaf-server/minecraft-patches/features/0090-Smart-sort-entities-in-NearestLivingEntitySensor.patch @@ -12,18 +12,10 @@ In non-strict test, this can give ~60-110% improvement (524ms on Paper, 204ms on under 625 villagers situation. diff --git a/net/minecraft/world/entity/ai/sensing/NearestLivingEntitySensor.java b/net/minecraft/world/entity/ai/sensing/NearestLivingEntitySensor.java -index b0c5e41fefc7c9adf1a61bd5b52861736657d37e..5ba8bc485d1c06f16060789dd42a82cc66b5bcc0 100644 +index b0c5e41fefc7c9adf1a61bd5b52861736657d37e..9ef531551bb135d4b6a1ca9c3320e35fa62d7c41 100644 --- a/net/minecraft/world/entity/ai/sensing/NearestLivingEntitySensor.java +++ b/net/minecraft/world/entity/ai/sensing/NearestLivingEntitySensor.java -@@ -1,7 +1,6 @@ - package net.minecraft.world.entity.ai.sensing; - - import com.google.common.collect.ImmutableSet; --import java.util.Comparator; - import java.util.List; - import java.util.Set; - import net.minecraft.server.level.ServerLevel; -@@ -13,18 +12,92 @@ import net.minecraft.world.entity.ai.memory.NearestVisibleLivingEntities; +@@ -13,18 +13,92 @@ import net.minecraft.world.entity.ai.memory.NearestVisibleLivingEntities; import net.minecraft.world.phys.AABB; public class NearestLivingEntitySensor extends Sensor { @@ -63,7 +55,7 @@ index b0c5e41fefc7c9adf1a61bd5b52861736657d37e..5ba8bc485d1c06f16060789dd42a82cc + bits[i] = Double.doubleToRawLongBits(reference.distanceToSqr(entities[i])); + } + -+ fastRadixSort(entities, bits, 0, entities.length-1, 62); ++ fastRadixSort(entities, bits, 0, entities.length - 1, 62); + return entities; + } + @@ -87,19 +79,19 @@ index b0c5e41fefc7c9adf1a61bd5b52861736657d37e..5ba8bc485d1c06f16060789dd42a82cc + } + } + -+ if (low < j) fastRadixSort(ents, bits, low, j, bit-1); -+ if (i < high) fastRadixSort(ents, bits, i, high, bit-1); ++ if (low < j) fastRadixSort(ents, bits, low, j, bit - 1); ++ if (i < high) fastRadixSort(ents, bits, i, high, bit - 1); + } + + private void insertionSort(LivingEntity[] ents, long[] bits, int low, int high) { -+ for (int i = low+1; i <= high; i++) { ++ for (int i = low + 1; i <= high; i++) { + int j = i; + LivingEntity e = ents[j]; + long b = bits[j]; + -+ while (j > low && bits[j-1] > b) { -+ ents[j] = ents[j-1]; -+ bits[j] = bits[j-1]; ++ while (j > low && bits[j - 1] > b) { ++ ents[j] = ents[j - 1]; ++ bits[j] = bits[j - 1]; + j--; + } + diff --git a/leaf-server/minecraft-patches/features/0144-Optimize-SetLookAndInteract-and-NearestVisibleLiving.patch b/leaf-server/minecraft-patches/features/0144-Optimize-SetLookAndInteract-and-NearestVisibleLiving.patch index f860a13e..74e7a213 100644 --- a/leaf-server/minecraft-patches/features/0144-Optimize-SetLookAndInteract-and-NearestVisibleLiving.patch +++ b/leaf-server/minecraft-patches/features/0144-Optimize-SetLookAndInteract-and-NearestVisibleLiving.patch @@ -9,7 +9,7 @@ Paper: 3859ms Leaf : 1363ms (-64% reduction) diff --git a/net/minecraft/world/entity/ai/behavior/SetLookAndInteract.java b/net/minecraft/world/entity/ai/behavior/SetLookAndInteract.java -index 13359e484486a5280f408955fe2a365cd3c34a43..d326bf267123ff26d85e63aeb273baf4b59613d6 100644 +index 13359e484486a5280f408955fe2a365cd3c34a43..48c30c8b686fdc82481bd72d6d10f541e9eb0217 100644 --- a/net/minecraft/world/entity/ai/behavior/SetLookAndInteract.java +++ b/net/minecraft/world/entity/ai/behavior/SetLookAndInteract.java @@ -9,7 +9,7 @@ import net.minecraft.world.entity.ai.memory.NearestVisibleLivingEntities; @@ -17,16 +17,17 @@ index 13359e484486a5280f408955fe2a365cd3c34a43..d326bf267123ff26d85e63aeb273baf4 public class SetLookAndInteract { public static BehaviorControl create(EntityType entityType, int maxDist) { - int i = maxDist * maxDist; -+ final int maxDistSq = maxDist * maxDist; ++ final int maxDistSq = maxDist * maxDist; // Leaf - Optimize SetLookAndInteract and NearestVisibleLivingEntities return BehaviorBuilder.create( instance -> instance.group( instance.registered(MemoryModuleType.LOOK_TARGET), -@@ -19,16 +19,20 @@ public class SetLookAndInteract { +@@ -19,16 +19,22 @@ public class SetLookAndInteract { .apply( instance, (lookTarget, interactionTarget, nearestVisibleLivingEntities) -> (level, entity, gameTime) -> { - Optional optional = instance.get(nearestVisibleLivingEntities) - .findClosest(nearEntity -> nearEntity.distanceToSqr(entity) <= i && entityType.equals(nearEntity.getType())); ++ // Leaf start - Optimize SetLookAndInteract and NearestVisibleLivingEntities + // Check entity type first as it's likely cheaper than distance calculation + NearestVisibleLivingEntities entities = instance.get(nearestVisibleLivingEntities); + Optional optional = entities.findClosest( @@ -46,33 +47,22 @@ index 13359e484486a5280f408955fe2a365cd3c34a43..d326bf267123ff26d85e63aeb273baf4 + interactionTarget.set(livingEntity); + lookTarget.set(new EntityTracker(livingEntity, true)); + return true; ++ // Leaf end - Optimize SetLookAndInteract and NearestVisibleLivingEntities } ) ); diff --git a/net/minecraft/world/entity/ai/memory/NearestVisibleLivingEntities.java b/net/minecraft/world/entity/ai/memory/NearestVisibleLivingEntities.java -index 2b973a3ba7d65330fa4690e71e5321c28457ec61..99a3c44b95ed0a14d272c5eb07b7db90aaa6e6af 100644 +index 2b973a3ba7d65330fa4690e71e5321c28457ec61..82de8e3bc462638bffbb43456076de2670d76540 100644 --- a/net/minecraft/world/entity/ai/memory/NearestVisibleLivingEntities.java +++ b/net/minecraft/world/entity/ai/memory/NearestVisibleLivingEntities.java -@@ -2,10 +2,11 @@ package net.minecraft.world.entity.ai.memory; - - import com.google.common.collect.Iterables; - import it.unimi.dsi.fastutil.objects.Object2BooleanOpenHashMap; -+import it.unimi.dsi.fastutil.objects.ObjectArrayList; -+import it.unimi.dsi.fastutil.objects.ObjectList; - import java.util.List; - import java.util.Optional; - import java.util.function.Predicate; --import java.util.stream.Stream; - import net.minecraft.server.level.ServerLevel; - import net.minecraft.world.entity.LivingEntity; - import net.minecraft.world.entity.ai.sensing.Sensor; -@@ -32,9 +33,26 @@ public class NearestVisibleLivingEntities { +@@ -32,11 +32,30 @@ public class NearestVisibleLivingEntities { } public Optional findClosest(Predicate predicate) { - for (LivingEntity livingEntity : this.nearbyEntities) { - if (predicate.test(livingEntity) && this.lineOfSightTest.test(livingEntity)) { - return Optional.of(livingEntity); ++ // Leaf start - Optimize SetLookAndInteract and NearestVisibleLivingEntities + // Early return if no entities + if (this.nearbyEntities.isEmpty()) { + return Optional.empty(); @@ -95,15 +85,21 @@ index 2b973a3ba7d65330fa4690e71e5321c28457ec61..99a3c44b95ed0a14d272c5eb07b7db90 + } } } ++ // Leaf end - Optimize SetLookAndInteract and NearestVisibleLivingEntities -@@ -45,8 +63,14 @@ public class NearestVisibleLivingEntities { - return Iterables.filter(this.nearbyEntities, target -> predicate.test(target) && this.lineOfSightTest.test(target)); // Leaf - Optimize baby villager sensor - diff on change + return Optional.empty(); + } +@@ -46,8 +65,20 @@ public class NearestVisibleLivingEntities { } -- public Stream find(Predicate predicate) { + public Stream find(Predicate predicate) { - return this.nearbyEntities.stream().filter(target -> predicate.test(target) && this.lineOfSightTest.test(target)); -+ public List find(Predicate predicate) { -+ ObjectList result = new ObjectArrayList<>(); ++ return this.nearbyEntities.stream().filter(target -> predicate.test(target) && this.lineOfSightTest.test(target)); // Leaf - Optimize SetLookAndInteract and NearestVisibleLivingEntities - diff on change ++ } ++ ++ // Leaf start - Optimize SetLookAndInteract and NearestVisibleLivingEntities ++ public List findWithList(Predicate predicate) { ++ it.unimi.dsi.fastutil.objects.ObjectList result = new it.unimi.dsi.fastutil.objects.ObjectArrayList<>(); + for (LivingEntity entity : this.nearbyEntities) { + if (predicate.test(entity) && this.lineOfSightTest.test(entity)) { + result.add(entity); @@ -111,5 +107,7 @@ index 2b973a3ba7d65330fa4690e71e5321c28457ec61..99a3c44b95ed0a14d272c5eb07b7db90 + } + return result; } ++ // Leaf end - Optimize SetLookAndInteract and NearestVisibleLivingEntities public boolean contains(LivingEntity entity) { + return this.nearbyEntities.contains(entity) && this.lineOfSightTest.test(entity); diff --git a/leaf-server/minecraft-patches/features/0145-Remove-streams-on-InsideBrownianWalk.patch b/leaf-server/minecraft-patches/features/0145-Remove-streams-on-InsideBrownianWalk.patch index e056ca71..f8c87c74 100644 --- a/leaf-server/minecraft-patches/features/0145-Remove-streams-on-InsideBrownianWalk.patch +++ b/leaf-server/minecraft-patches/features/0145-Remove-streams-on-InsideBrownianWalk.patch @@ -7,27 +7,20 @@ This method is maninly visible when ton of villagers suddenly wants to sleep Safe optimization, no need to provide any numbers. diff --git a/net/minecraft/world/entity/ai/behavior/InsideBrownianWalk.java b/net/minecraft/world/entity/ai/behavior/InsideBrownianWalk.java -index cbde74f4b6d586a5f80cdd675573441636bf682d..3ac3059ce23d6291aa4e96ed5441159133d3e965 100644 +index cbde74f4b6d586a5f80cdd675573441636bf682d..2324b941c7513692608b5146bc90c8e6124d2ee6 100644 --- a/net/minecraft/world/entity/ai/behavior/InsideBrownianWalk.java +++ b/net/minecraft/world/entity/ai/behavior/InsideBrownianWalk.java -@@ -2,6 +2,7 @@ package net.minecraft.world.entity.ai.behavior; - - import java.util.Collections; - import java.util.List; -+import java.util.ArrayList; - import net.minecraft.Util; - import net.minecraft.core.BlockPos; - import net.minecraft.world.entity.PathfinderMob; -@@ -20,16 +21,29 @@ public class InsideBrownianWalk { +@@ -20,16 +20,31 @@ public class InsideBrownianWalk { return false; } else { BlockPos blockPos = mob.blockPosition(); - List list = BlockPos.betweenClosedStream(blockPos.offset(-1, -1, -1), blockPos.offset(1, 1, 1)) - .map(BlockPos::immutable) - .collect(Util.toMutableList()); ++ // Leaf start - Remove streams on InsideBrownianWalk + BlockPos minPos = blockPos.offset(-1, -1, -1); + BlockPos maxPos = blockPos.offset(1, 1, 1); -+ List list = new ArrayList<>(); ++ List list = new java.util.ArrayList<>(); + + for (int x = minPos.getX(); x <= maxPos.getX(); x++) { + for (int y = minPos.getY(); y <= maxPos.getY(); y++) { @@ -53,6 +46,7 @@ index cbde74f4b6d586a5f80cdd675573441636bf682d..3ac3059ce23d6291aa4e96ed54411591 + break; + } + } ++ // Leaf end - Remove streams on InsideBrownianWalk + return true; }