9
0
mirror of https://github.com/Winds-Studio/Leaf.git synced 2025-12-19 15:09:25 +00:00

Smart sort items in NearestItemSensor

This commit is contained in:
Taiyou06
2025-05-10 22:53:54 +02:00
parent 55a5cdafd0
commit 06baf83a90
3 changed files with 74 additions and 33 deletions

View File

@@ -12,10 +12,10 @@ In non-strict test, this can give ~60-110% improvement (524ms on Paper, 204ms on
under 625 villagers situation. under 625 villagers situation.
diff --git a/net/minecraft/world/entity/ai/sensing/NearestLivingEntitySensor.java b/net/minecraft/world/entity/ai/sensing/NearestLivingEntitySensor.java diff --git a/net/minecraft/world/entity/ai/sensing/NearestLivingEntitySensor.java b/net/minecraft/world/entity/ai/sensing/NearestLivingEntitySensor.java
index b0c5e41fefc7c9adf1a61bd5b52861736657d37e..3fc212c10d230f027292865a214a8164a84e284a 100644 index b0c5e41fefc7c9adf1a61bd5b52861736657d37e..a887bb8ed2318d6ee39be350a1d0e7223ecf3ff5 100644
--- a/net/minecraft/world/entity/ai/sensing/NearestLivingEntitySensor.java --- a/net/minecraft/world/entity/ai/sensing/NearestLivingEntitySensor.java
+++ b/net/minecraft/world/entity/ai/sensing/NearestLivingEntitySensor.java +++ b/net/minecraft/world/entity/ai/sensing/NearestLivingEntitySensor.java
@@ -13,17 +13,30 @@ import net.minecraft.world.entity.ai.memory.NearestVisibleLivingEntities; @@ -13,17 +13,28 @@ import net.minecraft.world.entity.ai.memory.NearestVisibleLivingEntities;
import net.minecraft.world.phys.AABB; import net.minecraft.world.phys.AABB;
public class NearestLivingEntitySensor<T extends LivingEntity> extends Sensor<T> { public class NearestLivingEntitySensor<T extends LivingEntity> extends Sensor<T> {
@@ -34,13 +34,12 @@ index b0c5e41fefc7c9adf1a61bd5b52861736657d37e..3fc212c10d230f027292865a214a8164
AABB aabb = entity.getBoundingBox().inflate(attributeValue, attributeValue, attributeValue); AABB aabb = entity.getBoundingBox().inflate(attributeValue, attributeValue, attributeValue);
- List<LivingEntity> entitiesOfClass = level.getEntitiesOfClass( - List<LivingEntity> entitiesOfClass = level.getEntitiesOfClass(
- LivingEntity.class, aabb, matchableEntity -> matchableEntity != entity && matchableEntity.isAlive() - LivingEntity.class, aabb, matchableEntity -> matchableEntity != entity && matchableEntity.isAlive()
+ - );
+ List<LivingEntity> entities = level.getEntitiesOfClass(
+ LivingEntity.class, aabb, e -> e != entity && e.isAlive() && entity.distanceToSqr(e) <= rangeSqr
);
- entitiesOfClass.sort(Comparator.comparingDouble(entity::distanceToSqr)); - entitiesOfClass.sort(Comparator.comparingDouble(entity::distanceToSqr));
+ +
+ LivingEntity[] sorted = this.sorter.sort(entities, entity); + List<LivingEntity> entities = level.getEntitiesOfClass(LivingEntity.class, aabb, e -> e != entity && e.isAlive() && entity.distanceToSqr(e) <= rangeSqr);
+
+ LivingEntity[] sorted = this.sorter.sort(entities, entity, LivingEntity.class);
+ List<LivingEntity> sortedList = java.util.Arrays.asList(sorted); + List<LivingEntity> sortedList = java.util.Arrays.asList(sorted);
+ +
Brain<?> brain = entity.getBrain(); Brain<?> brain = entity.getBrain();

View File

@@ -0,0 +1,45 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Taiyou06 <kaandindar21@gmail.com>
Date: Sat, 10 May 2025 22:04:42 +0200
Subject: [PATCH] Smart sort items in NearestItemSensor
diff --git a/net/minecraft/world/entity/ai/sensing/NearestItemSensor.java b/net/minecraft/world/entity/ai/sensing/NearestItemSensor.java
index 09fd13e2d958da8326276c4dadf25bf488aff5ac..70036d073b644ff5f486491486c38db5df643107 100644
--- a/net/minecraft/world/entity/ai/sensing/NearestItemSensor.java
+++ b/net/minecraft/world/entity/ai/sensing/NearestItemSensor.java
@@ -6,6 +6,7 @@ import java.util.List;
import java.util.Optional;
import java.util.Set;
import net.minecraft.server.level.ServerLevel;
+import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.Mob;
import net.minecraft.world.entity.ai.Brain;
import net.minecraft.world.entity.ai.memory.MemoryModuleType;
@@ -16,6 +17,8 @@ public class NearestItemSensor extends Sensor<Mob> {
private static final long Y_RANGE = 16L;
public static final int MAX_DISTANCE_TO_WANTED_ITEM = 32;
+ private final org.dreeam.leaf.util.fastBitRadixSort itemSorter;
+ public NearestItemSensor() {this.itemSorter = new org.dreeam.leaf.util.fastBitRadixSort();}
@Override
public Set<MemoryModuleType<?>> requires() {
return ImmutableSet.of(MemoryModuleType.NEAREST_VISIBLE_WANTED_ITEM);
@@ -24,12 +27,13 @@ public class NearestItemSensor extends Sensor<Mob> {
@Override
protected void doTick(ServerLevel level, Mob entity) {
Brain<?> brain = entity.getBrain();
- List<ItemEntity> entitiesOfClass = level.getEntitiesOfClass(ItemEntity.class, entity.getBoundingBox().inflate(32.0, 16.0, 32.0), itemEntity -> itemEntity.closerThan(entity, MAX_DISTANCE_TO_WANTED_ITEM) && entity.wantsToPickUp(level, itemEntity.getItem())); // Paper - Perf: Move predicate into getEntities
- entitiesOfClass.sort(Comparator.comparingDouble(entity::distanceToSqr));
+ List<ItemEntity> entitiesOfClass = level.getEntitiesOfClass(ItemEntity.class, entity.getBoundingBox().inflate(32.0, 16.0, 32.0), itemEntity -> itemEntity.closerThan(entity, MAX_DISTANCE_TO_WANTED_ITEM) && entity.wantsToPickUp(level, itemEntity.getItem()));
+ ItemEntity[] sortedItems = this.itemSorter.sort(entitiesOfClass, entity, ItemEntity.class);
+
// Paper start - Perf: remove streams from hot code
ItemEntity nearest = null;
- for (final ItemEntity itemEntity : entitiesOfClass) {
- if (entity.hasLineOfSight(itemEntity)) { // Paper - Perf: Move predicate into getEntities
+ for (final ItemEntity itemEntity : sortedItems) {
+ if (entity.hasLineOfSight(itemEntity)) {
nearest = itemEntity;
break;
}

View File

@@ -1,57 +1,55 @@
package org.dreeam.leaf.util; package org.dreeam.leaf.util;
import java.util.List; import java.util.List;
import java.util.Arrays; // For Arrays.copyOf import java.util.Arrays;
import net.minecraft.world.entity.LivingEntity; import net.minecraft.world.entity.Entity;
import java.lang.reflect.Array; // Required for Array.newInstance
public class fastBitRadixSort { public class fastBitRadixSort {
private static final int SMALL_ARRAY_THRESHOLD = 2; private static final int SMALL_ARRAY_THRESHOLD = 2;
private LivingEntity[] entityBuffer = new LivingEntity[0]; private Entity[] entityBuffer = new Entity[0];
private long[] bitsBuffer = new long[0]; private long[] bitsBuffer = new long[0];
/** @SuppressWarnings("unchecked")
* Sorts a list of LivingEntity objects based on their squared distance public <T extends Entity, T_REF extends Entity> T[] sort(List<T> entities, T_REF referenceEntity, Class<T> entityClass) {
* to a reference entity using a fast radix sort algorithm.
**/
public <T_REF extends LivingEntity> LivingEntity[] sort(
List<LivingEntity> entities,
T_REF referenceEntity
) {
int size = entities.size(); int size = entities.size();
if (size <= 1) { if (size <= 1) {
return entities.toArray(new LivingEntity[0]); T[] resultArray = (T[]) Array.newInstance(entityClass, size);
return entities.toArray(resultArray);
} }
if (this.entityBuffer.length < size) { if (this.entityBuffer.length < size) {
this.entityBuffer = new LivingEntity[size]; this.entityBuffer = new Entity[size];
this.bitsBuffer = new long[size]; this.bitsBuffer = new long[size];
} }
for (int i = 0; i < size; i++) { for (int i = 0; i < size; i++) {
LivingEntity e = entities.get(i); this.entityBuffer[i] = entities.get(i);
this.entityBuffer[i] = e;
this.bitsBuffer[i] = Double.doubleToRawLongBits( this.bitsBuffer[i] = Double.doubleToRawLongBits(
referenceEntity.distanceToSqr(e) referenceEntity.distanceToSqr(entities.get(i))
); );
} }
// start from bit 62 (most significant for positive doubles, ignoring sign bit)
fastRadixSort(this.entityBuffer, this.bitsBuffer, 0, size - 1, 62); fastRadixSort(this.entityBuffer, this.bitsBuffer, 0, size - 1, 62);
return Arrays.copyOf(this.entityBuffer, size);
T[] resultArray = (T[]) Array.newInstance(entityClass, size);
for (int i = 0; i < size; i++) {
resultArray[i] = entityClass.cast(this.entityBuffer[i]);
}
return resultArray;
} }
private void fastRadixSort( private void fastRadixSort(
LivingEntity[] ents, Entity[] ents,
long[] bits, long[] bits,
int low, int low,
int high, int high,
int bit int bit
) { ) {
if (bit < 0 || low >= high) { if (bit < 0 || low >= high) {
return; // Base case: no bits left or subarray is trivial return;
} }
// For small subarrays, insertion sort is generally faster
if (high - low <= SMALL_ARRAY_THRESHOLD) { if (high - low <= SMALL_ARRAY_THRESHOLD) {
insertionSort(ents, bits, low, high); insertionSort(ents, bits, low, high);
return; return;
@@ -82,14 +80,14 @@ public class fastBitRadixSort {
} }
private void insertionSort( private void insertionSort(
LivingEntity[] ents, Entity[] ents,
long[] bits, long[] bits,
int low, int low,
int high int high
) { ) {
for (int i = low + 1; i <= high; i++) { for (int i = low + 1; i <= high; i++) {
int j = i; int j = i;
LivingEntity currentEntity = ents[j]; Entity currentEntity = ents[j];
long currentBits = bits[j]; long currentBits = bits[j];
while (j > low && bits[j - 1] > currentBits) { while (j > low && bits[j - 1] > currentBits) {
@@ -97,14 +95,13 @@ public class fastBitRadixSort {
bits[j] = bits[j - 1]; bits[j] = bits[j - 1];
j--; j--;
} }
ents[j] = currentEntity; ents[j] = currentEntity;
bits[j] = currentBits; bits[j] = currentBits;
} }
} }
private void swap(LivingEntity[] ents, long[] bits, int a, int b) { private void swap(Entity[] ents, long[] bits, int a, int b) {
LivingEntity tempEntity = ents[a]; Entity tempEntity = ents[a];
ents[a] = ents[b]; ents[a] = ents[b];
ents[b] = tempEntity; ents[b] = tempEntity;