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

optimize natural spawner

This commit is contained in:
hayanesuru
2025-06-03 16:17:08 +09:00
parent 347ef03d5f
commit 4249e11cc3
4 changed files with 334 additions and 0 deletions

View File

@@ -0,0 +1,56 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: hayanesuru <hayanesuru@outlook.jp>
Date: Tue, 3 Jun 2025 15:16:32 +0900
Subject: [PATCH] optimise ChunkGenerator#getMobsAt
inline fillStartsForStructure
diff --git a/net/minecraft/world/level/StructureManager.java b/net/minecraft/world/level/StructureManager.java
index 8bc6a6c86cd8db53feefba7508b6031ba67e242e..0785bb41560aae7edd4a727fe2403a064c9b5d9f 100644
--- a/net/minecraft/world/level/StructureManager.java
+++ b/net/minecraft/world/level/StructureManager.java
@@ -78,7 +78,7 @@ public class StructureManager {
public void fillStartsForStructure(Structure structure, LongSet structureRefs, Consumer<StructureStart> startConsumer) {
for (long l : structureRefs) {
- SectionPos sectionPos = SectionPos.of(new ChunkPos(l), this.level.getMinSectionY());
+ SectionPos sectionPos = SectionPos.of(ChunkPos.getX(l), this.level.getMinSectionY(), ChunkPos.getZ(l)); // Leaf
StructureStart startForStructure = this.getStartForStructure(
sectionPos, structure, this.level.getChunk(sectionPos.x(), sectionPos.z(), ChunkStatus.STRUCTURE_STARTS)
);
diff --git a/net/minecraft/world/level/chunk/ChunkGenerator.java b/net/minecraft/world/level/chunk/ChunkGenerator.java
index 176adfcaa0fc458043d4bc05ead1861864b63606..9cc9ba1f008635ab713a4547ca3cdbfafcee9ffc 100644
--- a/net/minecraft/world/level/chunk/ChunkGenerator.java
+++ b/net/minecraft/world/level/chunk/ChunkGenerator.java
@@ -501,18 +501,21 @@ public abstract class ChunkGenerator {
Structure structure = entry.getKey();
StructureSpawnOverride structureSpawnOverride = structure.spawnOverrides().get(category);
if (structureSpawnOverride != null) {
- MutableBoolean mutableBoolean = new MutableBoolean(false);
- Predicate<StructureStart> predicate = structureSpawnOverride.boundingBox() == StructureSpawnOverride.BoundingBoxType.PIECE
- ? structureStart -> structureManager.structureHasPieceAt(pos, structureStart)
- : structureStart -> structureStart.getBoundingBox().isInside(pos);
- structureManager.fillStartsForStructure(structure, entry.getValue(), structureStart -> {
- if (mutableBoolean.isFalse() && predicate.test(structureStart)) {
- mutableBoolean.setTrue();
+ // Leaf start
+ for (long l : entry.getValue()) {
+ SectionPos sectionPos = SectionPos.of(ChunkPos.getX(l), structureManager.level.getMinSectionY(), ChunkPos.getZ(l)); // Leaf
+ StructureStart startForStructure = structureManager.getStartForStructure(
+ sectionPos, structure, structureManager.level.getChunk(sectionPos.x(), sectionPos.z(), ChunkStatus.STRUCTURE_STARTS)
+ );
+ if (startForStructure != null && startForStructure.isValid()) {
+ if (structureSpawnOverride.boundingBox() == StructureSpawnOverride.BoundingBoxType.PIECE
+ ? structureManager.structureHasPieceAt(pos, startForStructure)
+ : startForStructure.getBoundingBox().isInside(pos)) {
+ return structureSpawnOverride.spawns();
+ }
}
- });
- if (mutableBoolean.isTrue()) {
- return structureSpawnOverride.spawns();
}
+ // Leaf end
}
}

View File

@@ -0,0 +1,102 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: hayanesuru <hayanesuru@outlook.jp>
Date: Tue, 3 Jun 2025 15:20:40 +0900
Subject: [PATCH] optimise getBiome
diff --git a/net/minecraft/server/level/ServerLevel.java b/net/minecraft/server/level/ServerLevel.java
index eb849c57992658005e0f514c6f7923f8ca43bebf..c706f0dacd9c322d9b09d6ee073872c4229818b0 100644
--- a/net/minecraft/server/level/ServerLevel.java
+++ b/net/minecraft/server/level/ServerLevel.java
@@ -899,6 +899,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe
this.advanceWeatherCycle();
}
+ if (runsNormally && (getGameTime() & 7L) == 7L) this.getBiomeManager().recomputeCache(); // Leaf - cache getBiome
// Leaf start - SparklyPaper - parallel world ticking
if (!org.dreeam.leaf.config.modules.async.SparklyPaperParallelWorldTicking.enabled) {
this.moonrise$midTickTasks();
diff --git a/net/minecraft/world/level/biome/BiomeManager.java b/net/minecraft/world/level/biome/BiomeManager.java
index a48175a7ebb1788ace46395621ed78d910178a53..2ce1754e0cf854468791688752a7d16c76917d3b 100644
--- a/net/minecraft/world/level/biome/BiomeManager.java
+++ b/net/minecraft/world/level/biome/BiomeManager.java
@@ -15,6 +15,10 @@ public class BiomeManager {
private final BiomeManager.NoiseBiomeSource noiseBiomeSource;
private final long biomeZoomSeed;
private static final double maxOffset = 0.4500000001D; // Leaf - Carpet-Fixes - Optimized getBiome method
+ // Leaf start - cache getBiome
+ private final Holder<Biome>[] biomeCache = new Holder[65536];
+ private final long[] biomeCachePos = new long[65536];
+ // Leaf end - cache getBiome
public BiomeManager(BiomeManager.NoiseBiomeSource noiseBiomeSource, long biomeZoomSeed) {
this.noiseBiomeSource = noiseBiomeSource;
@@ -29,7 +33,28 @@ public class BiomeManager {
return new BiomeManager(newSource, this.biomeZoomSeed);
}
+ // Leaf start - cache getBiome
+ public synchronized void recomputeCache() {
+ java.util.Arrays.fill(this.biomeCache, null);
+ }
+ // Leaf end - cache getBiome
+
public Holder<Biome> getBiome(BlockPos pos) {
+ // Leaf start - cache getBiome
+ long packedPos = pos.asLong();
+ long hash = packedPos;
+ hash = (hash ^ (hash >>> 32)) * 0xff51afd7ed558ccdL;
+ hash = (hash ^ (hash >>> 32)) * 0xc4ceb9fe1a85ec53L;
+ hash = (hash ^ (hash >>> 32)) & 65535L;
+ synchronized (this) {
+ if (biomeCachePos[(int) hash] == packedPos) {
+ Holder<Biome> biome = biomeCache[(int) hash];
+ if (biome != null) {
+ return biome;
+ }
+ }
+ }
+ // Leaf end - cache getBiome
// Leaf start - Carpet-Fixes - Optimized getBiome method
int xMinus2 = pos.getX() - 2;
int yMinus2 = pos.getY() - 2;
@@ -85,11 +110,18 @@ public class BiomeManager {
smallestDist = biomeDist;
}
}
- return this.noiseBiomeSource.getNoiseBiome(
+ // Leaf start - cache getBiome
+ Holder<Biome> biome = this.noiseBiomeSource.getNoiseBiome(
(smallestX & 4) == 0 ? x : x + 1,
(smallestX & 2) == 0 ? y : y + 1,
(smallestX & 1) == 0 ? z : z + 1
);
+ synchronized (this) {
+ biomeCache[(int) hash] = biome;
+ biomeCachePos[(int) hash] = packedPos;
+ }
+ return biome;
+ // Leaf end - cache getBiome
// Leaf end - Carpet-Fixes - Optimized getBiome method
}
@@ -126,9 +158,18 @@ public class BiomeManager {
return Mth.square(zNoise + fiddle2) + Mth.square(yNoise + fiddle1) + Mth.square(xNoise + fiddle);
}
+ // Leaf start
+ private static final double[] FIDDLE_TABLE = new double[1024];
+ static {
+ for (int i = 0; i < 1024; i++) {
+ FIDDLE_TABLE[i] = (i - 512) * (0.9 / 1024.0);
+ }
+ }
private static double getFiddle(long seed) {
- return (double)(((seed >> 24) & (1024 - 1)) - (1024/2)) * (0.9 / 1024.0); // Paper - avoid floorMod, fp division, and fp subtraction
+ return FIDDLE_TABLE[(int)(seed >>> 24) & 1023];
+ // return (double)(((seed >> 24) & (1024 - 1)) - (1024/2)) * (0.9 / 1024.0); // Paper - avoid floorMod, fp division, and fp subtraction
}
+ // Leaf end
public interface NoiseBiomeSource {
Holder<Biome> getNoiseBiome(int x, int y, int z);

View File

@@ -0,0 +1,130 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: hayanesuru <hayanesuru@outlook.jp>
Date: Tue, 3 Jun 2025 15:20:59 +0900
Subject: [PATCH] optimise NaturalSpawner#spawnForChunk
diff --git a/net/minecraft/world/level/NaturalSpawner.java b/net/minecraft/world/level/NaturalSpawner.java
index ce2621a87dec1befb016b3437ceb2d02ed6d0b75..a6831e701a0ffbc91ea947c09c39ac7d919d1870 100644
--- a/net/minecraft/world/level/NaturalSpawner.java
+++ b/net/minecraft/world/level/NaturalSpawner.java
@@ -156,8 +156,15 @@ public final class NaturalSpawner {
}
public static void spawnForChunk(ServerLevel level, LevelChunk chunk, NaturalSpawner.SpawnState spawnState, List<MobCategory> categories) {
+ BlockPos.MutableBlockPos pos = new BlockPos.MutableBlockPos(); // Leaf
for (MobCategory mobCategory : categories) {
// Paper start - Optional per player mob spawns
+ // Leaf start - reduce 3/4 while failed 16 canSpawn attempts
+ if (chunk.failedSpawnAttempts[mobCategory.ordinal()] >= 16 && (level.random.nextInt(4)) != 0) {
+ continue;
+ }
+ // Leaf end - reduce 3/4 while failed 16 canSpawn attempts
+ // Paper start - Optional per player mob attempts
final boolean canSpawn;
int maxSpawns = Integer.MAX_VALUE;
if (level.paperConfig().entities.spawning.perPlayerMobSpawns) {
@@ -197,9 +204,16 @@ public final class NaturalSpawner {
canSpawn = spawnState.canSpawnForCategoryLocal(mobCategory, chunk.getPos());
}
if (canSpawn) {
+ // Leaf start
// Paper start - throttle failed spawn attempts
- int spawnCount = spawnCategoryForChunk(mobCategory, level, chunk, spawnState::canSpawn, spawnState::afterSpawn,
- maxSpawns, level.paperConfig().entities.spawning.perPlayerMobSpawns ? level.getChunkSource().chunkMap::updatePlayerMobTypeMap : null, false);
+ int spawnCount = 0;
+ final Consumer<Entity> trackEntity = level.paperConfig().entities.spawning.perPlayerMobSpawns ? level.getChunkSource().chunkMap::updatePlayerMobTypeMap : null;
+ // Paper end - Optional per player mob spawns
+ mutableRandomPosWithin(pos, level, chunk);
+ if (pos.getY() >= level.getMinY() + 1) {
+ spawnCount = spawnCategoryForPosition(mobCategory, level, chunk, pos, spawnState::canSpawn, spawnState::afterSpawn, maxSpawns, trackEntity, false);// Paper - Optional per player mob spawns // Paper - throttle failed spawn attempts
+ } // Paper - throttle failed spawn attempts
+ // Leaf end
if (spawnCount == 0) {
chunk.failedSpawnAttempts[mobCategory.ordinal()]++;
} else {
@@ -275,24 +289,48 @@ public final class NaturalSpawner {
StructureManager structureManager = level.structureManager();
ChunkGenerator generator = level.getChunkSource().getGenerator();
int y = pos.getY();
+ int posX = pos.getX(); // Leaf
+ int posZ = pos.getZ(); // Leaf
int i = 0; // Paper - throttle failed spawn attempts
BlockState blockState = level.getBlockStateIfLoadedAndInBounds(pos); // Paper - don't load chunks for mob spawn
if (blockState != null && !blockState.isRedstoneConductor(chunk, pos)) { // Paper - don't load chunks for mob spawn
- BlockPos.MutableBlockPos mutableBlockPos = new BlockPos.MutableBlockPos();
+ BlockPos.MutableBlockPos mutableBlockPos = pos instanceof BlockPos.MutableBlockPos pos2 ? pos2 : new BlockPos.MutableBlockPos(); // Leaf
//int i = 0; // Paper - throttle failed spawn attempts - move up
+ // Leaf start
+ long rand = level.random.nextLong();
+ int bits = 0;
for (int i1 = 0; i1 < 3; i1++) {
- int x = pos.getX();
- int z = pos.getZ();
- int i2 = 6;
+ int x = posX;
+ int z = posZ;
MobSpawnSettings.SpawnerData spawnerData = null;
SpawnGroupData spawnGroupData = null;
- int ceil = Mth.ceil(level.random.nextFloat() * 4.0F);
+ int ceil = (int) ((rand & 0x3L) + 1L);
+ bits += 2;
int i3 = 0;
for (int i4 = 0; i4 < ceil; i4++) {
- x += level.random.nextInt(6) - level.random.nextInt(6);
- z += level.random.nextInt(6) - level.random.nextInt(6);
+ int rand1=0,rand2=0,rand3=0,rand4=0,valuesNeeded=4;
+ while (valuesNeeded > 0) {
+ if (bits > 61) {
+ rand = level.random.nextLong();
+ bits = 0;
+ }
+ int threeBits = (int) ((rand >>> bits) & 0x7L);
+ bits += 3;
+ if (threeBits != 7 && threeBits != 6) {
+ switch (valuesNeeded) {
+ case 1 -> rand4 = threeBits;
+ case 2 -> rand3 = threeBits;
+ case 3 -> rand2 = threeBits;
+ case 4 -> rand1 = threeBits;
+ }
+ valuesNeeded--;
+ }
+ }
+ x += rand1 - rand2;
+ z += rand3 - rand4;
+ // Leaf end
mutableBlockPos.set(x, y, z);
double d = x + 0.5;
double d1 = z + 0.5;
@@ -368,8 +406,8 @@ public final class NaturalSpawner {
private static boolean isRightDistanceToPlayerAndSpawnPoint(ServerLevel level, ChunkAccess chunk, BlockPos.MutableBlockPos pos, double distance) {
return !(distance <= 576.0)
- && !level.getSharedSpawnPos().closerToCenterThan(new Vec3(pos.getX() + 0.5, pos.getY(), pos.getZ() + 0.5), 24.0)
- && (Objects.equals(new ChunkPos(pos), chunk.getPos()) || level.isNaturalSpawningAllowed(pos));
+ && !(level.getSharedSpawnPos().distToCenterSqr(pos.getX() + 0.5, pos.getY(), pos.getZ() + 0.5) < 576.0) // Leaf
+ && (ChunkPos.asLong(pos) == chunk.getPos().longKey || level.isNaturalSpawningAllowed(pos)); // Leaf
}
// Paper start - PreCreatureSpawnEvent
@@ -474,6 +512,17 @@ public final class NaturalSpawner {
}
}
+ // Leaf start
+ private static void mutableRandomPosWithin(BlockPos.MutableBlockPos pos1, Level level, LevelChunk chunk) {
+ ChunkPos pos = chunk.getPos();
+ int i = pos.getMinBlockX() + level.random.nextInt(16);
+ int i1 = pos.getMinBlockZ() + level.random.nextInt(16);
+ int i2 = chunk.getHeight(Heightmap.Types.WORLD_SURFACE, i, i1) + 1;
+ int i3 = Mth.randomBetweenInclusive(level.random, level.getMinY(), i2);
+ pos1.set(i, i3, i1);
+ }
+ // Leaf end
+
private static BlockPos getRandomPosWithin(Level level, LevelChunk chunk) {
ChunkPos pos = chunk.getPos();
int i = pos.getMinBlockX() + level.random.nextInt(16);

View File

@@ -0,0 +1,46 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: hayanesuru <hayanesuru@outlook.jp>
Date: Tue, 3 Jun 2025 15:41:12 +0900
Subject: [PATCH] optimize structure map
diff --git a/net/minecraft/world/level/chunk/ChunkAccess.java b/net/minecraft/world/level/chunk/ChunkAccess.java
index 50a9903367f49ece2a267d10944b1515c7b93859..db6828ec94682c16b5b7ec6fc6262df256781f01 100644
--- a/net/minecraft/world/level/chunk/ChunkAccess.java
+++ b/net/minecraft/world/level/chunk/ChunkAccess.java
@@ -76,8 +76,8 @@ public abstract class ChunkAccess implements BiomeManager.NoiseBiomeSource, Ligh
protected BlendingData blendingData;
public final Map<Heightmap.Types, Heightmap> heightmaps = Maps.newEnumMap(Heightmap.Types.class);
// Paper - rewrite chunk system
- private final Map<Structure, StructureStart> structureStarts = Maps.newHashMap();
- private final Map<Structure, LongSet> structuresRefences = Maps.newHashMap();
+ private final Map<Structure, StructureStart> structureStarts = new it.unimi.dsi.fastutil.objects.Object2ObjectArrayMap<>(); // Leaf
+ private final Map<Structure, LongSet> structuresRefences = new it.unimi.dsi.fastutil.objects.Object2ObjectArrayMap<>(); // Leaf
protected final Map<BlockPos, CompoundTag> pendingBlockEntities = Maps.newHashMap();
public final Map<BlockPos, BlockEntity> blockEntities = new Object2ObjectOpenHashMap<>();
protected final LevelHeightAccessor levelHeightAccessor;
@@ -297,7 +297,7 @@ public abstract class ChunkAccess implements BiomeManager.NoiseBiomeSource, Ligh
}
public Map<Structure, StructureStart> getAllStarts() {
- return Collections.unmodifiableMap(this.structureStarts);
+ return it.unimi.dsi.fastutil.objects.Object2ObjectMaps.unmodifiable((it.unimi.dsi.fastutil.objects.Object2ObjectArrayMap<Structure, StructureStart>) this.structureStarts); // Leaf
}
public void setAllStarts(Map<Structure, StructureStart> structureStarts) {
@@ -313,13 +313,13 @@ public abstract class ChunkAccess implements BiomeManager.NoiseBiomeSource, Ligh
@Override
public void addReferenceForStructure(Structure structure, long reference) {
- this.structuresRefences.computeIfAbsent(structure, key -> new LongOpenHashSet()).add(reference);
+ this.structuresRefences.computeIfAbsent(structure, key -> new it.unimi.dsi.fastutil.longs.LongArraySet()).add(reference); // Leaf
this.markUnsaved();
}
@Override
public Map<Structure, LongSet> getAllReferences() {
- return Collections.unmodifiableMap(this.structuresRefences);
+ return it.unimi.dsi.fastutil.objects.Object2ObjectMaps.unmodifiable((it.unimi.dsi.fastutil.objects.Object2ObjectArrayMap<Structure, LongSet>) this.structuresRefences); // Leaf
}
@Override