Add: Leaf Smart sort entities in NearestLivingEntitySensor

This commit is contained in:
MrHua269
2025-04-18 22:07:58 +08:00
parent 2aaa180a4e
commit 936be4c3fd
11 changed files with 127 additions and 2 deletions

View File

@@ -186,10 +186,10 @@ index 0000000000000000000000000000000000000000..ecde4462b08d701b8bff9f26902f1775
+ RegionStats getRegionStats();
+}
diff --git a/src/main/java/org/bukkit/World.java b/src/main/java/org/bukkit/World.java
index 015d852d5a0c01042a2153a6916d408660356c59..c7b6f3f6c42746297816c0650571990f565d5e68 100644
index bff01411f4b2d3ecd9e6d807c3f450d72c108323..1d74f4814d5c87d6cd1320634e5610cac16d32c5 100644
--- a/src/main/java/org/bukkit/World.java
+++ b/src/main/java/org/bukkit/World.java
@@ -4432,4 +4432,8 @@ public interface World extends RegionAccessor, WorldInfo, PluginMessageRecipient
@@ -4437,4 +4437,8 @@ public interface World extends RegionAccessor, WorldInfo, PluginMessageRecipient
}
}
}

View File

@@ -0,0 +1,125 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: MrHua269 <mrhua269@gmail.com>
Date: Fri, 18 Apr 2025 22:04:20 +0800
Subject: [PATCH] Leaf Smart sort entities in NearestLivingEntitySensor
diff --git a/net/minecraft/world/entity/ai/sensing/NearestLivingEntitySensor.java b/net/minecraft/world/entity/ai/sensing/NearestLivingEntitySensor.java
index b0c5e41fefc7c9adf1a61bd5b52861736657d37e..b91c4aa042f6ac10e402bcf16a03d24d6dafec86 100644
--- a/net/minecraft/world/entity/ai/sensing/NearestLivingEntitySensor.java
+++ b/net/minecraft/world/entity/ai/sensing/NearestLivingEntitySensor.java
@@ -13,18 +13,107 @@ import net.minecraft.world.entity.ai.memory.NearestVisibleLivingEntities;
import net.minecraft.world.phys.AABB;
public class NearestLivingEntitySensor<T extends LivingEntity> extends Sensor<T> {
+
+ // Leaf start - Optimized entity sorting with buffer reuse
+ private static final int SMALL_ARRAY_THRESHOLD = 2;
+ private final ThreadLocal<LivingEntity[]> entityBuffer = ThreadLocal.withInitial(() -> new LivingEntity[0]);
+ private final ThreadLocal<long[]> bitsBuffer = ThreadLocal.withInitial(() -> new long[0]);
+
@Override
protected void doTick(ServerLevel level, T entity) {
- double attributeValue = entity.getAttributeValue(Attributes.FOLLOW_RANGE);
- AABB aabb = entity.getBoundingBox().inflate(attributeValue, attributeValue, attributeValue);
- List<LivingEntity> entitiesOfClass = level.getEntitiesOfClass(
- LivingEntity.class, aabb, matchableEntity -> matchableEntity != entity && matchableEntity.isAlive()
+ double range = entity.getAttributeValue(Attributes.FOLLOW_RANGE);
+ double rangeSqr = range * range;
+ AABB aabb = entity.getBoundingBox().inflate(range, range, range);
+
+ List<LivingEntity> entities = level.getEntitiesOfClass(
+ LivingEntity.class, aabb, e -> e != entity && e.isAlive() && entity.distanceToSqr(e) <= rangeSqr
);
- entitiesOfClass.sort(Comparator.comparingDouble(entity::distanceToSqr));
+
+ LivingEntity[] sorted = smartSort(entities, entity);
+ List<LivingEntity> sortedList = java.util.Arrays.asList(sorted);
+
Brain<?> brain = entity.getBrain();
- brain.setMemory(MemoryModuleType.NEAREST_LIVING_ENTITIES, entitiesOfClass);
- brain.setMemory(MemoryModuleType.NEAREST_VISIBLE_LIVING_ENTITIES, new NearestVisibleLivingEntities(level, entity, entitiesOfClass));
+ brain.setMemory(MemoryModuleType.NEAREST_LIVING_ENTITIES, sortedList);
+ brain.setMemory(MemoryModuleType.NEAREST_VISIBLE_LIVING_ENTITIES,
+ new NearestVisibleLivingEntities(level, entity, sortedList));
+ }
+
+ private LivingEntity[] smartSort(List<LivingEntity> entities, T reference) {
+ int size = entities.size();
+ if (size <= 1) return entities.toArray(new LivingEntity[0]);
+
+ LivingEntity[] entityBufferArray = this.entityBuffer.get();
+ long[] bitsBufferArray = this.bitsBuffer.get();
+ if (entityBufferArray.length < size) {
+ entityBufferArray = new LivingEntity[size];
+ entityBuffer.set(entityBufferArray);
+
+ bitsBufferArray = new long[size];
+ bitsBuffer.set(bitsBufferArray);
+ }
+
+ for (int i = 0; i < size; i++) {
+ LivingEntity e = entities.get(i);
+ entityBufferArray[i] = e;
+ bitsBufferArray[i] = Double.doubleToRawLongBits(reference.distanceToSqr(e));
+ }
+
+ fastRadixSort(entityBufferArray, bitsBufferArray, 0, size - 1, 62);
+
+ return java.util.Arrays.copyOf(entityBufferArray, size);
+ }
+
+ private void fastRadixSort(LivingEntity[] ents, long[] bits, int low, int high, int bit) {
+ if (bit < 0 || low >= high) return;
+
+ if (high - low <= SMALL_ARRAY_THRESHOLD) {
+ insertionSort(ents, bits, low, high);
+ return;
+ }
+
+ int i = low, j = high;
+ final long mask = 1L << bit;
+
+ while (i <= j) {
+ while (i <= j && (bits[i] & mask) == 0) i++;
+ while (i <= j && (bits[j] & mask) != 0) j--;
+
+ if (i < j) {
+ swap(ents, bits, i++, j--);
+ }
+ }
+
+ 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++) {
+ 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];
+ j--;
+ }
+
+ ents[j] = e;
+ bits[j] = b;
+ }
+ }
+
+ private void swap(LivingEntity[] ents, long[] bits, int a, int b) {
+ LivingEntity te = ents[a];
+ ents[a] = ents[b];
+ ents[b] = te;
+
+ long tb = bits[a];
+ bits[a] = bits[b];
+ bits[b] = tb;
}
+ // Leaf end - Optimized entity sorting with buffer reuse
@Override
public Set<MemoryModuleType<?>> requires() {