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