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:
@@ -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);
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user