9
0
mirror of https://github.com/Winds-Studio/Leaf.git synced 2025-12-31 04:46:38 +00:00

perf: apply fast bit radix sort [ci skip]

This commit is contained in:
hayanesuru
2025-08-28 17:11:05 +09:00
parent e5e7b690e8
commit 5cc4388005
2 changed files with 42 additions and 45 deletions

View File

@@ -1,11 +1,24 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: hayanesuru <hayanesuru@outlook.jp>
Date: Thu, 28 Aug 2025 15:50:27 +0900
Subject: [PATCH] quick sort
Date: Thu, 28 Aug 2025 17:10:34 +0900
Subject: [PATCH] fast bit radix sort
Co-authored-by: Taiyou06 <kaandindar21@gmail.com>
diff --git a/net/minecraft/server/level/ServerLevel.java b/net/minecraft/server/level/ServerLevel.java
index 5178290d060dd8a72f0e6cb77f77d19683a866d0..c5fea3948be691c42e9a94ddb0acd04fcc0b4415 100644
--- a/net/minecraft/server/level/ServerLevel.java
+++ b/net/minecraft/server/level/ServerLevel.java
@@ -1096,6 +1096,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe
public final org.dreeam.leaf.world.NatureSpawnChunkMap natureSpawnChunkMap = new org.dreeam.leaf.world.NatureSpawnChunkMap(); // Leaf - optimize mob spawning
public final org.dreeam.leaf.world.RandomTickSystem randomTickSystem = new org.dreeam.leaf.world.RandomTickSystem(); // Leaf - optimize random tick
public final org.dreeam.leaf.world.EntityCollisionCache entityCollisionCache = new org.dreeam.leaf.world.EntityCollisionCache(); // Leaf - cache collision list
+ public final org.dreeam.leaf.util.FastBitRadixSort fastBitRadixSort = new org.dreeam.leaf.util.FastBitRadixSort(); // Leaf - fast bit radix sort
public void tickChunk(LevelChunk chunk, int randomTickSpeed) {
final net.minecraft.world.level.levelgen.BitRandomSource simpleRandom = this.simpleRandom; // Paper - optimise random ticking // Leaf - Faster random generator - upcasting
diff --git a/net/minecraft/world/entity/ai/sensing/NearestItemSensor.java b/net/minecraft/world/entity/ai/sensing/NearestItemSensor.java
index 09fd13e2d958da8326276c4dadf25bf488aff5ac..e854127f83b2a60906206f4f5d5f8ddc59a31a66 100644
index 09fd13e2d958da8326276c4dadf25bf488aff5ac..063cab1fbd8dd3a483346242659fe273d3000cc6 100644
--- a/net/minecraft/world/entity/ai/sensing/NearestItemSensor.java
+++ b/net/minecraft/world/entity/ai/sensing/NearestItemSensor.java
@@ -15,6 +15,7 @@ public class NearestItemSensor extends Sensor<Mob> {
@@ -22,7 +35,7 @@ index 09fd13e2d958da8326276c4dadf25bf488aff5ac..e854127f83b2a60906206f4f5d5f8ddc
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));
+ // Leaf start - quick sort
+ // Leaf start - fast bit radix sort
+ net.minecraft.core.Position pos = entity.position();
+ double x = pos.x();
+ double y = pos.y();
@@ -30,16 +43,16 @@ index 09fd13e2d958da8326276c4dadf25bf488aff5ac..e854127f83b2a60906206f4f5d5f8ddc
+ net.minecraft.world.phys.AABB boundingBox = entity.getBoundingBox().inflate(32.0, 16.0, 32.0);
+ it.unimi.dsi.fastutil.objects.ObjectArrayList<ItemEntity> entitiesOfClass = new it.unimi.dsi.fastutil.objects.ObjectArrayList<>();
+ ((ca.spottedleaf.moonrise.patches.chunk_system.level.ChunkSystemLevel) level).moonrise$getEntityLookup().getEntities(ItemEntity.class, null, boundingBox, entitiesOfClass, (ItemEntity itemEntity) -> itemEntity.distanceToSqr(x, y, z) < MAX_DIST_SQ && entity.wantsToPickUp(level, itemEntity.getItem())); // Paper - Perf: Move predicate into getEntities
+ entitiesOfClass.unstableSort(Comparator.comparingDouble((ItemEntity itemEntity) -> itemEntity.distanceToSqr(x, y, z)));
+ // Leaf end - quick sort
+ level.fastBitRadixSort.sort(entitiesOfClass.elements(), entitiesOfClass.size(), pos);
+ // Leaf end - fast bit radix sort
// Paper start - Perf: remove streams from hot code
ItemEntity nearest = null;
for (final ItemEntity itemEntity : entitiesOfClass) {
diff --git a/net/minecraft/world/entity/ai/sensing/NearestLivingEntitySensor.java b/net/minecraft/world/entity/ai/sensing/NearestLivingEntitySensor.java
index b0c5e41fefc7c9adf1a61bd5b52861736657d37e..28607bbf202d780e331f91535335f0e23b7d9f17 100644
index b0c5e41fefc7c9adf1a61bd5b52861736657d37e..51a6302ed5daf512acc6bed915f954ac76559270 100644
--- a/net/minecraft/world/entity/ai/sensing/NearestLivingEntitySensor.java
+++ b/net/minecraft/world/entity/ai/sensing/NearestLivingEntitySensor.java
@@ -17,10 +17,15 @@ public class NearestLivingEntitySensor<T extends LivingEntity> extends Sensor<T>
@@ -17,10 +17,11 @@ public class NearestLivingEntitySensor<T extends LivingEntity> extends Sensor<T>
protected void doTick(ServerLevel level, T entity) {
double attributeValue = entity.getAttributeValue(Attributes.FOLLOW_RANGE);
AABB aabb = entity.getBoundingBox().inflate(attributeValue, attributeValue, attributeValue);
@@ -47,20 +60,16 @@ index b0c5e41fefc7c9adf1a61bd5b52861736657d37e..28607bbf202d780e331f91535335f0e2
- LivingEntity.class, aabb, matchableEntity -> matchableEntity != entity && matchableEntity.isAlive()
- );
- entitiesOfClass.sort(Comparator.comparingDouble(entity::distanceToSqr));
+ // Leaf start - quick sort
+ // Leaf start - fast bit radix sort
+ it.unimi.dsi.fastutil.objects.ObjectArrayList<LivingEntity> entitiesOfClass = new it.unimi.dsi.fastutil.objects.ObjectArrayList<>();
+ ((ca.spottedleaf.moonrise.patches.chunk_system.level.ChunkSystemLevel) level).moonrise$getEntityLookup().getEntities(LivingEntity.class, entity, aabb, entitiesOfClass, LivingEntity::isAlive);
+ net.minecraft.world.phys.Vec3 vec3 = entity.position();
+ double x = vec3.x();
+ double y = vec3.y();
+ double z = vec3.z();
+ entitiesOfClass.unstableSort(Comparator.comparingDouble((LivingEntity e) -> e.distanceToSqr(x, y, z)));
+ // Leaf end - quick sort
+ level.fastBitRadixSort.sort(entitiesOfClass.elements(), entitiesOfClass.size(), entity.position());
+ // Leaf end - fast bit radix sort
Brain<?> brain = entity.getBrain();
brain.setMemory(MemoryModuleType.NEAREST_LIVING_ENTITIES, entitiesOfClass);
brain.setMemory(MemoryModuleType.NEAREST_VISIBLE_LIVING_ENTITIES, new NearestVisibleLivingEntities(level, entity, entitiesOfClass));
diff --git a/net/minecraft/world/entity/ai/sensing/PlayerSensor.java b/net/minecraft/world/entity/ai/sensing/PlayerSensor.java
index fa438315b4ed8e9394383b82b89ecb04bac3399f..896e716975e48637e188c167a4accf79071a0fde 100644
index fa438315b4ed8e9394383b82b89ecb04bac3399f..44942f1fa1f543e81b1553e51c057de437f10e93 100644
--- a/net/minecraft/world/entity/ai/sensing/PlayerSensor.java
+++ b/net/minecraft/world/entity/ai/sensing/PlayerSensor.java
@@ -27,18 +27,26 @@ public class PlayerSensor extends Sensor<LivingEntity> {
@@ -68,7 +77,7 @@ index fa438315b4ed8e9394383b82b89ecb04bac3399f..896e716975e48637e188c167a4accf79
protected void doTick(ServerLevel level, LivingEntity entity) {
// Leaf start - Remove stream in PlayerSensor
- List<Player> list = new java.util.ArrayList<>();
+ // Leaf start - quick sort
+ // Leaf start - fast bit radix sort
+ it.unimi.dsi.fastutil.objects.ObjectArrayList<Player> list = new it.unimi.dsi.fastutil.objects.ObjectArrayList<>();
+ double distance = this.getFollowDistance(entity);
+ double distSq = distance * distance;
@@ -88,8 +97,8 @@ index fa438315b4ed8e9394383b82b89ecb04bac3399f..896e716975e48637e188c167a4accf79
list.add(serverPlayer);
}
- list.sort(Comparator.comparingDouble(entity::distanceToSqr));
+ list.unstableSort(Comparator.comparingDouble(p -> p.distanceToSqr(tx, ty, tz)));
+ // Leaf end - quick sort
+ level.fastBitRadixSort.sort(list.elements(), list.size(), vec3);
+ // Leaf end - fast bit radix sort
// Leaf end - Remove stream in PlayerSensor
Brain<?> brain = entity.getBrain();
brain.setMemory(MemoryModuleType.NEAREST_PLAYERS, list);

View File

@@ -0,0 +1,100 @@
package org.dreeam.leaf.util;
import net.minecraft.world.entity.Entity;
public class FastBitRadixSort {
private static final int SMALL_ARRAY_THRESHOLD = 6;
private static final long[] LONGS = new long[0];
private long[] bitsBuffer = LONGS;
public <T extends Entity> void sort(T[] entities, int size, net.minecraft.core.Position target) {
if (size <= 1) {
return;
}
if (this.bitsBuffer.length < size) {
this.bitsBuffer = new long[size];
}
double tx = target.x();
double ty = target.y();
double tz = target.z();
for (int i = 0; i < size; i++) {
T e = entities[i];
this.bitsBuffer[i] = Double.doubleToRawLongBits(e.distanceToSqr(tx, ty, tz));
}
fastRadixSort(entities, this.bitsBuffer, 0, size - 1, 62);
}
private static void fastRadixSort(
Entity[] 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;
int 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 static void insertionSort(
Entity[] ents,
long[] bits,
int low,
int high
) {
for (int i = low + 1; i <= high; i++) {
int j = i;
Entity currentEntity = ents[j];
long currentBits = bits[j];
while (j > low && bits[j - 1] > currentBits) {
ents[j] = ents[j - 1];
bits[j] = bits[j - 1];
j--;
}
ents[j] = currentEntity;
bits[j] = currentBits;
}
}
private static void swap(Entity[] ents, long[] bits, int a, int b) {
Entity tempEntity = ents[a];
ents[a] = ents[b];
ents[b] = tempEntity;
long tempBits = bits[a];
bits[a] = bits[b];
bits[b] = tempBits;
}
}