From 5cc43880051f13e1a82a5dc196e1f260cc43c812 Mon Sep 17 00:00:00 2001 From: hayanesuru Date: Thu, 28 Aug 2025 17:11:05 +0900 Subject: [PATCH] perf: apply fast bit radix sort [ci skip] --- ...t.patch => 0296-fast-bit-radix-sort.patch} | 47 +++++++++++-------- .../dreeam/leaf/util}/FastBitRadixSort.java | 40 ++++++---------- 2 files changed, 42 insertions(+), 45 deletions(-) rename leaf-server/minecraft-patches/features/{0296-quick-sort.patch => 0296-fast-bit-radix-sort.patch} (69%) rename {leaf-archived-patches/removed/1.21.8/src/dreeam/leaf => leaf-server/src/main/java/org/dreeam/leaf/util}/FastBitRadixSort.java (60%) diff --git a/leaf-server/minecraft-patches/features/0296-quick-sort.patch b/leaf-server/minecraft-patches/features/0296-fast-bit-radix-sort.patch similarity index 69% rename from leaf-server/minecraft-patches/features/0296-quick-sort.patch rename to leaf-server/minecraft-patches/features/0296-fast-bit-radix-sort.patch index 4fc40143..91d22755 100644 --- a/leaf-server/minecraft-patches/features/0296-quick-sort.patch +++ b/leaf-server/minecraft-patches/features/0296-fast-bit-radix-sort.patch @@ -1,11 +1,24 @@ From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 From: hayanesuru -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 +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 { @@ -22,7 +35,7 @@ index 09fd13e2d958da8326276c4dadf25bf488aff5ac..e854127f83b2a60906206f4f5d5f8ddc Brain brain = entity.getBrain(); - List 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 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 extends Sensor +@@ -17,10 +17,11 @@ public class NearestLivingEntitySensor extends Sensor 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 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 { @@ -68,7 +77,7 @@ index fa438315b4ed8e9394383b82b89ecb04bac3399f..896e716975e48637e188c167a4accf79 protected void doTick(ServerLevel level, LivingEntity entity) { // Leaf start - Remove stream in PlayerSensor - List list = new java.util.ArrayList<>(); -+ // Leaf start - quick sort ++ // Leaf start - fast bit radix sort + it.unimi.dsi.fastutil.objects.ObjectArrayList 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); diff --git a/leaf-archived-patches/removed/1.21.8/src/dreeam/leaf/FastBitRadixSort.java b/leaf-server/src/main/java/org/dreeam/leaf/util/FastBitRadixSort.java similarity index 60% rename from leaf-archived-patches/removed/1.21.8/src/dreeam/leaf/FastBitRadixSort.java rename to leaf-server/src/main/java/org/dreeam/leaf/util/FastBitRadixSort.java index aea927e0..3729bb45 100644 --- a/leaf-archived-patches/removed/1.21.8/src/dreeam/leaf/FastBitRadixSort.java +++ b/leaf-server/src/main/java/org/dreeam/leaf/util/FastBitRadixSort.java @@ -2,44 +2,32 @@ package org.dreeam.leaf.util; import net.minecraft.world.entity.Entity; -import java.lang.reflect.Array; // Required for Array.newInstance -import java.util.List; - public class FastBitRadixSort { private static final int SMALL_ARRAY_THRESHOLD = 6; - private Entity[] entityBuffer = new Entity[0]; - private long[] bitsBuffer = new long[0]; + private static final long[] LONGS = new long[0]; + private long[] bitsBuffer = LONGS; - @SuppressWarnings("unchecked") - public T[] sort(List entities, T_REF referenceEntity, Class entityClass) { - int size = entities.size(); + public void sort(T[] entities, int size, net.minecraft.core.Position target) { if (size <= 1) { - T[] resultArray = (T[]) Array.newInstance(entityClass, size); - return entities.toArray(resultArray); + return; } - if (this.entityBuffer.length < size) { - this.entityBuffer = new Entity[size]; + 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++) { - this.entityBuffer[i] = entities.get(i); - this.bitsBuffer[i] = Double.doubleToRawLongBits( - referenceEntity.distanceToSqr(entities.get(i)) - ); + T e = entities[i]; + this.bitsBuffer[i] = Double.doubleToRawLongBits(e.distanceToSqr(tx, ty, tz)); } - fastRadixSort(this.entityBuffer, this.bitsBuffer, 0, size - 1, 62); - - T[] resultArray = (T[]) Array.newInstance(entityClass, size); - for (int i = 0; i < size; i++) { - resultArray[i] = entityClass.cast(this.entityBuffer[i]); - } - return resultArray; + fastRadixSort(entities, this.bitsBuffer, 0, size - 1, 62); } - private void fastRadixSort( + private static void fastRadixSort( Entity[] ents, long[] bits, int low, @@ -79,7 +67,7 @@ public class FastBitRadixSort { } } - private void insertionSort( + private static void insertionSort( Entity[] ents, long[] bits, int low, @@ -100,7 +88,7 @@ public class FastBitRadixSort { } } - private void swap(Entity[] ents, long[] bits, int a, int b) { + private static void swap(Entity[] ents, long[] bits, int a, int b) { Entity tempEntity = ents[a]; ents[a] = ents[b]; ents[b] = tempEntity;