From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 From: NONPLAYT <76615486+NONPLAYT@users.noreply.github.com> Date: Sat, 1 Feb 2025 00:09:39 +0300 Subject: [PATCH] World and Noise gen optimizations diff --git a/net/minecraft/world/level/ChunkPos.java b/net/minecraft/world/level/ChunkPos.java index 55ce935a2fab7e32904d9ff599867269035d703f..4fa84743ba7f570f11a4979b7e5381478c844aef 100644 --- a/net/minecraft/world/level/ChunkPos.java +++ b/net/minecraft/world/level/ChunkPos.java @@ -110,7 +110,12 @@ public class ChunkPos { @Override public boolean equals(Object other) { - return this == other || other instanceof ChunkPos chunkPos && this.x == chunkPos.x && this.z == chunkPos.z; + // DivineMC start - Use standard equals + if (other == this) return true; + if (other == null || other.getClass() != this.getClass()) return false; + ChunkPos thatPos = (ChunkPos) other; + return this.x == thatPos.x && this.z == thatPos.z; + // DivineMC end - Use standard equals } public int getMiddleBlockX() { diff --git a/net/minecraft/world/level/biome/TheEndBiomeSource.java b/net/minecraft/world/level/biome/TheEndBiomeSource.java index cf3172be76fa4c7987ed569138439ff42f92fa7f..bfc65a4d8d1e64f42ff13508020e5e0260e83b98 100644 --- a/net/minecraft/world/level/biome/TheEndBiomeSource.java +++ b/net/minecraft/world/level/biome/TheEndBiomeSource.java @@ -27,6 +27,33 @@ public class TheEndBiomeSource extends BiomeSource { private final Holder islands; private final Holder barrens; + // DivineMC start - World gen optimizations + private Holder getBiomeForNoiseGenVanilla(int x, int y, int z, Climate.Sampler noise) { + int i = QuartPos.toBlock(x); + int j = QuartPos.toBlock(y); + int k = QuartPos.toBlock(z); + int l = SectionPos.blockToSectionCoord(i); + int m = SectionPos.blockToSectionCoord(k); + if ((long)l * (long)l + (long)m * (long)m <= 4096L) { + return this.end; + } else { + int n = (SectionPos.blockToSectionCoord(i) * 2 + 1) * 8; + int o = (SectionPos.blockToSectionCoord(k) * 2 + 1) * 8; + double d = noise.erosion().compute(new DensityFunction.SinglePointContext(n, j, o)); + if (d > 0.25D) { + return this.highlands; + } else if (d >= -0.0625D) { + return this.midlands; + } else { + return d < -0.21875D ? this.islands : this.barrens; + } + } + } + + private final ThreadLocal>> cache = ThreadLocal.withInitial(it.unimi.dsi.fastutil.longs.Long2ObjectLinkedOpenHashMap::new); + private final int cacheCapacity = 1024; + // DivineMC end - World gen optimizations + public static TheEndBiomeSource create(HolderGetter biomeGetter) { return new TheEndBiomeSource( biomeGetter.getOrThrow(Biomes.THE_END), @@ -55,26 +82,24 @@ public class TheEndBiomeSource extends BiomeSource { return CODEC; } + // DivineMC start - World gen optimizations @Override - public Holder getNoiseBiome(int x, int y, int z, Climate.Sampler sampler) { - int blockPosX = QuartPos.toBlock(x); - int blockPosY = QuartPos.toBlock(y); - int blockPosZ = QuartPos.toBlock(z); - int sectionPosX = SectionPos.blockToSectionCoord(blockPosX); - int sectionPosZ = SectionPos.blockToSectionCoord(blockPosZ); - if ((long)sectionPosX * sectionPosX + (long)sectionPosZ * sectionPosZ <= 4096L) { - return this.end; + public Holder getNoiseBiome(int biomeX, int biomeY, int biomeZ, Climate.Sampler multiNoiseSampler) { + final long key = net.minecraft.world.level.ChunkPos.asLong(biomeX, biomeZ); + final it.unimi.dsi.fastutil.longs.Long2ObjectLinkedOpenHashMap> cacheThreadLocal = cache.get(); + final Holder biome = cacheThreadLocal.get(key); + if (biome != null) { + return biome; } else { - int i = (SectionPos.blockToSectionCoord(blockPosX) * 2 + 1) * 8; - int i1 = (SectionPos.blockToSectionCoord(blockPosZ) * 2 + 1) * 8; - double d = sampler.erosion().compute(new DensityFunction.SinglePointContext(i, blockPosY, i1)); - if (d > 0.25) { - return this.highlands; - } else if (d >= -0.0625) { - return this.midlands; - } else { - return d < -0.21875 ? this.islands : this.barrens; + final Holder gennedBiome = getBiomeForNoiseGenVanilla(biomeX, biomeY, biomeZ, multiNoiseSampler); + cacheThreadLocal.put(key, gennedBiome); + if (cacheThreadLocal.size() > cacheCapacity) { + for (int i = 0; i < cacheCapacity / 16; i ++) { + cacheThreadLocal.removeFirst(); + } } + return gennedBiome; } } + // DivineMC end - World gen optimizations } diff --git a/net/minecraft/world/level/chunk/LevelChunkSection.java b/net/minecraft/world/level/chunk/LevelChunkSection.java index c83d0667b19830304f22319a46a23422a8766790..5bc74d860923d6485593cacb67d4c18e20db2634 100644 --- a/net/minecraft/world/level/chunk/LevelChunkSection.java +++ b/net/minecraft/world/level/chunk/LevelChunkSection.java @@ -23,6 +23,7 @@ public class LevelChunkSection implements ca.spottedleaf.moonrise.patches.block_ public short tickingFluidCount; public final PalettedContainer states; private PalettedContainer> biomes; // CraftBukkit - read/write + private static final int sliceSize = 4; // DivineMC - World and Noise gen optimizations // Paper start - block counting private static final it.unimi.dsi.fastutil.shorts.ShortArrayList FULL_LIST = new it.unimi.dsi.fastutil.shorts.ShortArrayList(16*16*16); @@ -312,13 +313,15 @@ public class LevelChunkSection implements ca.spottedleaf.moonrise.patches.block_ PalettedContainer> palettedContainer = this.biomes.recreate(); int i = 4; - for (int i1 = 0; i1 < 4; i1++) { - for (int i2 = 0; i2 < 4; i2++) { - for (int i3 = 0; i3 < 4; i3++) { - palettedContainer.getAndSetUnchecked(i1, i2, i3, biomeResolver.getNoiseBiome(x + i1, y + i2, z + i3, climateSampler)); + // DivineMC start - World and Noise gen optimizations + for (int posY = 0; posY < sliceSize; ++posY) { + for (int posZ = 0; posZ < sliceSize; ++posZ) { + for (int posX = 0; posX < sliceSize; ++posX) { + palettedContainer.getAndSetUnchecked(posX, posY, posZ, biomeResolver.getNoiseBiome(x + posX, y + posY, z + posZ, climateSampler)); } } } + // DivineMC end - World and Noise gen optimizations this.biomes = palettedContainer; } diff --git a/net/minecraft/world/level/levelgen/Aquifer.java b/net/minecraft/world/level/levelgen/Aquifer.java index c62a15ea4a1bb22e7bcc2fc544acf8a601892029..43dd5f63fe7834d41874ea30651f3fb738d88ba6 100644 --- a/net/minecraft/world/level/levelgen/Aquifer.java +++ b/net/minecraft/world/level/levelgen/Aquifer.java @@ -85,6 +85,15 @@ public interface Aquifer { private final int minGridZ; private final int gridSizeX; private final int gridSizeZ; + // DivineMC start - World gen optimizations + private int c2me$dist1; + private int c2me$dist2; + private int c2me$dist3; + private long c2me$pos1; + private long c2me$pos2; + private long c2me$pos3; + private double c2me$mutableDoubleThingy; + // DivineMC end - World gen optimizations private static final int[][] SURFACE_SAMPLING_OFFSETS_IN_CHUNKS = new int[][]{ {0, 0}, {-2, -1}, {-1, -1}, {0, -1}, {1, -1}, {-3, 0}, {-2, 0}, {-1, 0}, {1, 0}, {-2, 1}, {-1, 1}, {0, 1}, {1, 1} }; @@ -120,6 +129,36 @@ public interface Aquifer { this.aquiferCache = new Aquifer.FluidStatus[i4]; this.aquiferLocationCache = new long[i4]; Arrays.fill(this.aquiferLocationCache, Long.MAX_VALUE); + // DivineMC start - World gen optimizations + if (this.aquiferLocationCache.length % (this.gridSizeX * this.gridSizeZ) != 0) { + throw new AssertionError("Array length"); + } + + int sizeY = this.aquiferLocationCache.length / (this.gridSizeX * this.gridSizeZ); + + final RandomSource random = org.bxteam.divinemc.util.RandomUtil.getRandom(this.positionalRandomFactory); + // index: y, z, x + for (int y = 0; y < sizeY; y++) { + for (int z = 0; z < this.gridSizeZ; z++) { + for (int x = 0; x < this.gridSizeX; x++) { + final int x1 = x + this.minGridX; + final int y1 = y + this.minGridY; + final int z1 = z + this.minGridZ; + org.bxteam.divinemc.util.RandomUtil.derive(this.positionalRandomFactory, random, x1, y1, z1); + int x2 = x1 * 16 + random.nextInt(10); + int y2 = y1 * 12 + random.nextInt(9); + int z2 = z1 * 16 + random.nextInt(10); + int index = this.getIndex(x1, y1, z1); + this.aquiferLocationCache[index] = BlockPos.asLong(x2, y2, z2); + } + } + } + for (long blockPosition : this.aquiferLocationCache) { + if (blockPosition == Long.MAX_VALUE) { + throw new AssertionError("Array initialization"); + } + } + // DivineMC end - World gen optimizations } private int getIndex(int gridX, int gridY, int gridZ) { @@ -132,140 +171,24 @@ public interface Aquifer { @Nullable @Override public BlockState computeSubstance(DensityFunction.FunctionContext context, double substance) { + // DivineMC start - World gen optimizations int i = context.blockX(); - int i1 = context.blockY(); - int i2 = context.blockZ(); + int j = context.blockY(); + int k = context.blockZ(); if (substance > 0.0) { this.shouldScheduleFluidUpdate = false; return null; } else { - Aquifer.FluidStatus fluidStatus = this.globalFluidPicker.computeFluid(i, i1, i2); - if (fluidStatus.at(i1).is(Blocks.LAVA)) { + Aquifer.FluidStatus fluidLevel = this.globalFluidPicker.computeFluid(i, j, k); + if (fluidLevel.at(j).is(Blocks.LAVA)) { this.shouldScheduleFluidUpdate = false; return Blocks.LAVA.defaultBlockState(); } else { - int i3 = Math.floorDiv(i - 5, 16); - int i4 = Math.floorDiv(i1 + 1, 12); - int i5 = Math.floorDiv(i2 - 5, 16); - int i6 = Integer.MAX_VALUE; - int i7 = Integer.MAX_VALUE; - int i8 = Integer.MAX_VALUE; - int i9 = Integer.MAX_VALUE; - long l = 0L; - long l1 = 0L; - long l2 = 0L; - long l3 = 0L; - - for (int i10 = 0; i10 <= 1; i10++) { - for (int i11 = -1; i11 <= 1; i11++) { - for (int i12 = 0; i12 <= 1; i12++) { - int i13 = i3 + i10; - int i14 = i4 + i11; - int i15 = i5 + i12; - int index = this.getIndex(i13, i14, i15); - long l4 = this.aquiferLocationCache[index]; - long l5; - if (l4 != Long.MAX_VALUE) { - l5 = l4; - } else { - RandomSource randomSource = this.positionalRandomFactory.at(i13, i14, i15); - l5 = BlockPos.asLong( - i13 * 16 + randomSource.nextInt(10), i14 * 12 + randomSource.nextInt(9), i15 * 16 + randomSource.nextInt(10) - ); - this.aquiferLocationCache[index] = l5; - } - - int i16 = BlockPos.getX(l5) - i; - int i17 = BlockPos.getY(l5) - i1; - int i18 = BlockPos.getZ(l5) - i2; - int i19 = i16 * i16 + i17 * i17 + i18 * i18; - if (i6 >= i19) { - l3 = l2; - l2 = l1; - l1 = l; - l = l5; - i9 = i8; - i8 = i7; - i7 = i6; - i6 = i19; - } else if (i7 >= i19) { - l3 = l2; - l2 = l1; - l1 = l5; - i9 = i8; - i8 = i7; - i7 = i19; - } else if (i8 >= i19) { - l3 = l2; - l2 = l5; - i9 = i8; - i8 = i19; - } else if (i9 >= i19) { - l3 = l5; - i9 = i19; - } - } - } - } - - Aquifer.FluidStatus aquiferStatus = this.getAquiferStatus(l); - double d = similarity(i6, i7); - BlockState blockState = aquiferStatus.at(i1); - if (d <= 0.0) { - if (d >= FLOWING_UPDATE_SIMULARITY) { - Aquifer.FluidStatus aquiferStatus1 = this.getAquiferStatus(l1); - this.shouldScheduleFluidUpdate = !aquiferStatus.equals(aquiferStatus1); - } else { - this.shouldScheduleFluidUpdate = false; - } - - return blockState; - } else if (blockState.is(Blocks.WATER) && this.globalFluidPicker.computeFluid(i, i1 - 1, i2).at(i1 - 1).is(Blocks.LAVA)) { - this.shouldScheduleFluidUpdate = true; - return blockState; - } else { - MutableDouble mutableDouble = new MutableDouble(Double.NaN); - Aquifer.FluidStatus aquiferStatus2 = this.getAquiferStatus(l1); - double d1 = d * this.calculatePressure(context, mutableDouble, aquiferStatus, aquiferStatus2); - if (substance + d1 > 0.0) { - this.shouldScheduleFluidUpdate = false; - return null; - } else { - Aquifer.FluidStatus aquiferStatus3 = this.getAquiferStatus(l2); - double d2 = similarity(i6, i8); - if (d2 > 0.0) { - double d3 = d * d2 * this.calculatePressure(context, mutableDouble, aquiferStatus, aquiferStatus3); - if (substance + d3 > 0.0) { - this.shouldScheduleFluidUpdate = false; - return null; - } - } - - double d3 = similarity(i7, i8); - if (d3 > 0.0) { - double d4 = d * d3 * this.calculatePressure(context, mutableDouble, aquiferStatus2, aquiferStatus3); - if (substance + d4 > 0.0) { - this.shouldScheduleFluidUpdate = false; - return null; - } - } - - boolean flag = !aquiferStatus.equals(aquiferStatus2); - boolean flag1 = d3 >= FLOWING_UPDATE_SIMULARITY && !aquiferStatus2.equals(aquiferStatus3); - boolean flag2 = d2 >= FLOWING_UPDATE_SIMULARITY && !aquiferStatus.equals(aquiferStatus3); - if (!flag && !flag1 && !flag2) { - this.shouldScheduleFluidUpdate = d2 >= FLOWING_UPDATE_SIMULARITY - && similarity(i6, i9) >= FLOWING_UPDATE_SIMULARITY - && !aquiferStatus.equals(this.getAquiferStatus(l3)); - } else { - this.shouldScheduleFluidUpdate = true; - } - - return blockState; - } - } + aquiferExtracted$refreshDistPosIdx(i, j, k); + return aquiferExtracted$applyPost(context, substance, j, i, k); } } + // DivineMC end - World gen optimizations } @Override @@ -278,65 +201,28 @@ public interface Aquifer { return 1.0 - Math.abs(secondDistance - firstDistance) / 25.0; } + // DivineMC start - World gen optimizations private double calculatePressure( - DensityFunction.FunctionContext context, MutableDouble substance, Aquifer.FluidStatus firstFluid, Aquifer.FluidStatus secondFluid + DensityFunction.FunctionContext context, MutableDouble substance, Aquifer.FluidStatus fluidLevel, Aquifer.FluidStatus fluidLevel2 // DivineMC - rename args ) { int i = context.blockY(); - BlockState blockState = firstFluid.at(i); - BlockState blockState1 = secondFluid.at(i); - if ((!blockState.is(Blocks.LAVA) || !blockState1.is(Blocks.WATER)) && (!blockState.is(Blocks.WATER) || !blockState1.is(Blocks.LAVA))) { - int abs = Math.abs(firstFluid.fluidLevel - secondFluid.fluidLevel); + BlockState blockState = fluidLevel.at(i); + BlockState blockState2 = fluidLevel2.at(i); + if ((!blockState.is(Blocks.LAVA) || !blockState2.is(Blocks.WATER)) && (!blockState.is(Blocks.WATER) || !blockState2.is(Blocks.LAVA))) { + int abs = Math.abs(fluidLevel.fluidLevel - fluidLevel2.fluidLevel); if (abs == 0) { return 0.0; } else { - double d = 0.5 * (firstFluid.fluidLevel + secondFluid.fluidLevel); - double d1 = i + 0.5 - d; - double d2 = abs / 2.0; - double d3 = 0.0; - double d4 = 2.5; - double d5 = 1.5; - double d6 = 3.0; - double d7 = 10.0; - double d8 = 3.0; - double d9 = d2 - Math.abs(d1); - double d11; - if (d1 > 0.0) { - double d10 = 0.0 + d9; - if (d10 > 0.0) { - d11 = d10 / 1.5; - } else { - d11 = d10 / 2.5; - } - } else { - double d10 = 3.0 + d9; - if (d10 > 0.0) { - d11 = d10 / 3.0; - } else { - d11 = d10 / 10.0; - } - } - - double d10x = 2.0; - double d12; - if (!(d11 < -2.0) && !(d11 > 2.0)) { - double value = substance.getValue(); - if (Double.isNaN(value)) { - double d13 = this.barrierNoise.compute(context); - substance.setValue(d13); - d12 = d13; - } else { - d12 = value; - } - } else { - d12 = 0.0; - } + double d = 0.5 * (double)(fluidLevel.fluidLevel + fluidLevel2.fluidLevel); + final double q = aquiferExtracted$getQ(i, d, abs); - return 2.0 * (d12 + d11); + return aquiferExtracted$postCalculateDensity(context, substance, q); } } else { return 2.0; } } + // DivineMC end - World gen optimizations private int gridX(int x) { return Math.floorDiv(x, 16); @@ -350,23 +236,25 @@ public interface Aquifer { return Math.floorDiv(z, 16); } - private Aquifer.FluidStatus getAquiferStatus(long packedPos) { - int x = BlockPos.getX(packedPos); - int y = BlockPos.getY(packedPos); - int z = BlockPos.getZ(packedPos); - int i = this.gridX(x); - int i1 = this.gridY(y); - int i2 = this.gridZ(z); - int index = this.getIndex(i, i1, i2); - Aquifer.FluidStatus fluidStatus = this.aquiferCache[index]; - if (fluidStatus != null) { - return fluidStatus; + // DivineMC start - World gen optimizations + private Aquifer.FluidStatus getAquiferStatus(long pos) { + int i = BlockPos.getX(pos); + int j = BlockPos.getY(pos); + int k = BlockPos.getZ(pos); + int l = i >> 4; // C2ME - inline: floorDiv(i, 16) + int m = Math.floorDiv(j, 12); // C2ME - inline + int n = k >> 4; // C2ME - inline: floorDiv(k, 16) + int o = this.getIndex(l, m, n); + Aquifer.FluidStatus fluidLevel = this.aquiferCache[o]; + if (fluidLevel != null) { + return fluidLevel; } else { - Aquifer.FluidStatus fluidStatus1 = this.computeFluid(x, y, z); - this.aquiferCache[index] = fluidStatus1; - return fluidStatus1; + Aquifer.FluidStatus fluidLevel2 = this.computeFluid(i, j, k); + this.aquiferCache[o] = fluidLevel2; + return fluidLevel2; } } + // DivineMC end - World gen optimizations private Aquifer.FluidStatus computeFluid(int x, int y, int z) { Aquifer.FluidStatus fluidStatus = this.globalFluidPicker.computeFluid(x, y, z); @@ -406,23 +294,22 @@ public interface Aquifer { return new Aquifer.FluidStatus(i7, this.computeFluidType(x, y, z, fluidStatus, i7)); } + // DivineMC start - World gen optimizations private int computeSurfaceLevel(int x, int y, int z, Aquifer.FluidStatus fluidStatus, int maxSurfaceLevel, boolean fluidPresent) { - DensityFunction.SinglePointContext singlePointContext = new DensityFunction.SinglePointContext(x, y, z); + DensityFunction.SinglePointContext unblendedNoisePos = new DensityFunction.SinglePointContext(x, y, z); double d; double d1; - if (OverworldBiomeBuilder.isDeepDarkRegion(this.erosion, this.depth, singlePointContext)) { + if (OverworldBiomeBuilder.isDeepDarkRegion(this.erosion, this.depth, unblendedNoisePos)) { d = -1.0; d1 = -1.0; } else { int i = maxSurfaceLevel + 8 - y; - int i1 = 64; - double d2 = fluidPresent ? Mth.clampedMap((double)i, 0.0, 64.0, 1.0, 0.0) : 0.0; - double d3 = Mth.clamp(this.fluidLevelFloodednessNoise.compute(singlePointContext), -1.0, 1.0); - double d4 = Mth.map(d2, 1.0, 0.0, -0.3, 0.8); - double d5 = Mth.map(d2, 1.0, 0.0, -0.8, 0.4); - d = d3 - d5; - d1 = d3 - d4; + double f = fluidPresent ? Mth.clampedLerp(1.0, 0.0, ((double) i) / 64.0) : 0.0; // inline + double g = Mth.clamp(this.fluidLevelFloodednessNoise.compute(unblendedNoisePos), -1.0, 1.0); + d = g + 0.8 + (f - 1.0) * 1.2; // inline + d1 = g + 0.3 + (f - 1.0) * 1.1; // inline } + // DivineMC end - World gen optimizations int i; if (d1 > 0.0) { @@ -466,5 +353,183 @@ public interface Aquifer { return blockState; } + + // DivineMC start - World gen optimizations + private @org.jetbrains.annotations.Nullable BlockState aquiferExtracted$applyPost(DensityFunction.FunctionContext pos, double density, int j, int i, int k) { + Aquifer.FluidStatus fluidLevel2 = this.getAquiferStatus(this.c2me$pos1); + double d = similarity(this.c2me$dist1, this.c2me$dist2); + BlockState blockState = fluidLevel2.at(j); + if (d <= 0.0) { + this.shouldScheduleFluidUpdate = d >= FLOWING_UPDATE_SIMULARITY; + return blockState; + } else if (blockState.is(Blocks.WATER) && this.globalFluidPicker.computeFluid(i, j - 1, k).at(j - 1).is(Blocks.LAVA)) { + this.shouldScheduleFluidUpdate = true; + return blockState; + } else { + this.c2me$mutableDoubleThingy = Double.NaN; + Aquifer.FluidStatus fluidLevel3 = this.getAquiferStatus(this.c2me$pos2); + double e = d * this.c2me$calculateDensityModified(pos, fluidLevel2, fluidLevel3); + if (density + e > 0.0) { + this.shouldScheduleFluidUpdate = false; + return null; + } else { + return aquiferExtracted$getFinalBlockState(pos, density, d, fluidLevel2, fluidLevel3, blockState); + } + } + } + + private BlockState aquiferExtracted$getFinalBlockState(DensityFunction.FunctionContext pos, double density, double d, Aquifer.FluidStatus fluidLevel2, Aquifer.FluidStatus fluidLevel3, BlockState blockState) { + Aquifer.FluidStatus fluidLevel4 = this.getAquiferStatus(this.c2me$pos3); + double f = similarity(this.c2me$dist1, this.c2me$dist3); + if (aquiferExtracted$extractedCheckFG(pos, density, d, fluidLevel2, f, fluidLevel4)) return null; + + double g = similarity(this.c2me$dist2, this.c2me$dist3); + if (aquiferExtracted$extractedCheckFG(pos, density, d, fluidLevel3, g, fluidLevel4)) return null; + + this.shouldScheduleFluidUpdate = true; + return blockState; + } + + private boolean aquiferExtracted$extractedCheckFG(DensityFunction.FunctionContext pos, double density, double d, Aquifer.FluidStatus fluidLevel2, double f, Aquifer.FluidStatus fluidLevel4) { + if (f > 0.0) { + double g = d * f * this.c2me$calculateDensityModified(pos, fluidLevel2, fluidLevel4); + if (density + g > 0.0) { + this.shouldScheduleFluidUpdate = false; + return true; + } + } + return false; + } + + private void aquiferExtracted$refreshDistPosIdx(int x, int y, int z) { + int gx = (x - 5) >> 4; + int gy = Math.floorDiv(y + 1, 12); + int gz = (z - 5) >> 4; + int dist1 = Integer.MAX_VALUE; + int dist2 = Integer.MAX_VALUE; + int dist3 = Integer.MAX_VALUE; + long pos1 = 0; + long pos2 = 0; + long pos3 = 0; + + for (int offY = -1; offY <= 1; ++offY) { + for (int offZ = 0; offZ <= 1; ++offZ) { + for (int offX = 0; offX <= 1; ++offX) { + int posIdx = this.getIndex(gx + offX, gy + offY, gz + offZ); + + long position = this.aquiferLocationCache[posIdx]; + + int dx = BlockPos.getX(position) - x; + int dy = BlockPos.getY(position) - y; + int dz = BlockPos.getZ(position) - z; + int dist = dx * dx + dy * dy + dz * dz; + + if (dist3 >= dist) { + pos3 = position; + dist3 = dist; + } + if (dist2 >= dist) { + pos3 = pos2; + dist3 = dist2; + pos2 = position; + dist2 = dist; + } + if (dist1 >= dist) { + pos2 = pos1; + dist2 = dist1; + pos1 = position; + dist1 = dist; + } + } + } + } + + this.c2me$dist1 = dist1; + this.c2me$dist2 = dist2; + this.c2me$dist3 = dist3; + this.c2me$pos1 = pos1; + this.c2me$pos2 = pos2; + this.c2me$pos3 = pos3; + } + + private double c2me$calculateDensityModified( + DensityFunction.FunctionContext pos, Aquifer.FluidStatus fluidLevel, Aquifer.FluidStatus fluidLevel2 + ) { + int i = pos.blockY(); + BlockState blockState = fluidLevel.at(i); + BlockState blockState2 = fluidLevel2.at(i); + if ((!blockState.is(Blocks.LAVA) || !blockState2.is(Blocks.WATER)) && (!blockState.is(Blocks.WATER) || !blockState2.is(Blocks.LAVA))) { + int j = Math.abs(fluidLevel.fluidLevel - fluidLevel2.fluidLevel); + if (j == 0) { + return 0.0; + } else { + double d = 0.5 * (double)(fluidLevel.fluidLevel + fluidLevel2.fluidLevel); + final double q = aquiferExtracted$getQ(i, d, j); + + return aquiferExtracted$postCalculateDensityModified(pos, q); + } + } else { + return 2.0; + } + } + + private double aquiferExtracted$postCalculateDensity(DensityFunction.FunctionContext pos, MutableDouble mutableDouble, double q) { + double r; + if (!(q < -2.0) && !(q > 2.0)) { + double s = mutableDouble.getValue(); + if (Double.isNaN(s)) { + double t = this.barrierNoise.compute(pos); + mutableDouble.setValue(t); + r = t; + } else { + r = s; + } + } else { + r = 0.0; + } + + return 2.0 * (r + q); + } + + private double aquiferExtracted$postCalculateDensityModified(DensityFunction.FunctionContext pos, double q) { + double r; + if (!(q < -2.0) && !(q > 2.0)) { + double s = this.c2me$mutableDoubleThingy; + if (Double.isNaN(s)) { + double t = this.barrierNoise.compute(pos); + this.c2me$mutableDoubleThingy = t; + r = t; + } else { + r = s; + } + } else { + r = 0.0; + } + + return 2.0 * (r + q); + } + + private static double aquiferExtracted$getQ(double i, double d, double j) { + double e = i + 0.5 - d; + double f = j / 2.0; + double o = f - Math.abs(e); + double q; + if (e > 0.0) { + if (o > 0.0) { + q = o / 1.5; + } else { + q = o / 2.5; + } + } else { + double p = 3.0 + o; + if (p > 0.0) { + q = p / 3.0; + } else { + q = p / 10.0; + } + } + return q; + } + // DivineMC end - World gen optimizations } } diff --git a/net/minecraft/world/level/levelgen/Beardifier.java b/net/minecraft/world/level/levelgen/Beardifier.java index 131923282c9ecbcb1d7f45a826da907c02bd2716..36dd3eb0cb29d546531aec91a9c486be09975797 100644 --- a/net/minecraft/world/level/levelgen/Beardifier.java +++ b/net/minecraft/world/level/levelgen/Beardifier.java @@ -29,6 +29,17 @@ public class Beardifier implements DensityFunctions.BeardifierOrMarker { }); private final ObjectListIterator pieceIterator; private final ObjectListIterator junctionIterator; + // DivineMC start - World gen optimizations + private Beardifier.Rigid[] c2me$pieceArray; + private JigsawJunction[] c2me$junctionArray; + + private void c2me$initArrays() { + this.c2me$pieceArray = com.google.common.collect.Iterators.toArray(this.pieceIterator, Beardifier.Rigid.class); + this.pieceIterator.back(Integer.MAX_VALUE); + this.c2me$junctionArray = com.google.common.collect.Iterators.toArray(this.junctionIterator, JigsawJunction.class); + this.junctionIterator.back(Integer.MAX_VALUE); + } + // DivineMC end - World gen optimizations public static Beardifier forStructuresInChunk(StructureManager structureManager, ChunkPos chunkPos) { int minBlockX = chunkPos.getMinBlockX(); @@ -76,50 +87,44 @@ public class Beardifier implements DensityFunctions.BeardifierOrMarker { this.junctionIterator = junctionIterator; } + // DivineMC start - World gen optimizations @Override public double compute(DensityFunction.FunctionContext context) { + if (this.c2me$pieceArray == null || this.c2me$junctionArray == null) { + this.c2me$initArrays(); + } int i = context.blockX(); - int i1 = context.blockY(); - int i2 = context.blockZ(); + int j = context.blockY(); + int k = context.blockZ(); double d = 0.0; - while (this.pieceIterator.hasNext()) { - Beardifier.Rigid rigid = this.pieceIterator.next(); - BoundingBox boundingBox = rigid.box(); - int groundLevelDelta = rigid.groundLevelDelta(); - int max = Math.max(0, Math.max(boundingBox.minX() - i, i - boundingBox.maxX())); - int max1 = Math.max(0, Math.max(boundingBox.minZ() - i2, i2 - boundingBox.maxZ())); - int i3 = boundingBox.minY() + groundLevelDelta; - int i4 = i1 - i3; - - int i5 = switch (rigid.terrainAdjustment()) { - case NONE -> 0; - case BURY, BEARD_THIN -> i4; - case BEARD_BOX -> Math.max(0, Math.max(i3 - i1, i1 - boundingBox.maxY())); - case ENCAPSULATE -> Math.max(0, Math.max(boundingBox.minY() - i1, i1 - boundingBox.maxY())); - }; + for (Beardifier.Rigid piece : this.c2me$pieceArray) { + BoundingBox blockBox = piece.box(); + int l = piece.groundLevelDelta(); + int m = Math.max(0, Math.max(blockBox.minX() - i, i - blockBox.maxX())); + int n = Math.max(0, Math.max(blockBox.minZ() - k, k - blockBox.maxZ())); + int o = blockBox.minY() + l; + int p = j - o; - d += switch (rigid.terrainAdjustment()) { + d += switch (piece.terrainAdjustment()) { // 2 switch statement merged case NONE -> 0.0; - case BURY -> getBuryContribution(max, i5 / 2.0, max1); - case BEARD_THIN, BEARD_BOX -> getBeardContribution(max, i5, max1, i4) * 0.8; - case ENCAPSULATE -> getBuryContribution(max / 2.0, i5 / 2.0, max1 / 2.0) * 0.8; + case BURY -> getBuryContribution(m, (double)p / 2.0, n); + case BEARD_THIN -> getBeardContribution(m, p, n, p) * 0.8; + case BEARD_BOX -> getBeardContribution(m, Math.max(0, Math.max(o - j, j - blockBox.maxY())), n, p) * 0.8; + case ENCAPSULATE -> getBuryContribution((double)m / 2.0, (double)Math.max(0, Math.max(blockBox.minY() - j, j - blockBox.maxY())) / 2.0, (double)n / 2.0) * 0.8; }; } - this.pieceIterator.back(Integer.MAX_VALUE); - - while (this.junctionIterator.hasNext()) { - JigsawJunction jigsawJunction = this.junctionIterator.next(); - int i6 = i - jigsawJunction.getSourceX(); - int groundLevelDelta = i1 - jigsawJunction.getSourceGroundY(); - int max = i2 - jigsawJunction.getSourceZ(); - d += getBeardContribution(i6, groundLevelDelta, max, groundLevelDelta) * 0.4; + for (JigsawJunction jigsawJunction : this.c2me$junctionArray) { + int r = i - jigsawJunction.getSourceX(); + int l = j - jigsawJunction.getSourceGroundY(); + int m = k - jigsawJunction.getSourceZ(); + d += getBeardContribution(r, l, m, l) * 0.4; } - this.junctionIterator.back(Integer.MAX_VALUE); return d; } + // DivineMC end - World gen optimizations @Override public double minValue() { @@ -132,8 +137,14 @@ public class Beardifier implements DensityFunctions.BeardifierOrMarker { } private static double getBuryContribution(double x, double y, double z) { - double len = Mth.length(x, y, z); - return Mth.clampedMap(len, 0.0, 6.0, 1.0, 0.0); + // DivineMC start - World gen optimizations + double d = Math.sqrt(x * x + y * y + z * z); + if (d > 6.0) { + return 0.0; + } else { + return 1.0 - d / 6.0; + } + // DivineMC end - World gen optimizations } private static double getBeardContribution(int x, int y, int z, int height) { diff --git a/net/minecraft/world/level/levelgen/LegacyRandomSource.java b/net/minecraft/world/level/levelgen/LegacyRandomSource.java index c67168517774a0ad9ca43422a79ef14a8ea0c2e8..026dfbbb6c3fd5cd274dcbf721e5cf3af889e3d9 100644 --- a/net/minecraft/world/level/levelgen/LegacyRandomSource.java +++ b/net/minecraft/world/level/levelgen/LegacyRandomSource.java @@ -53,13 +53,7 @@ public class LegacyRandomSource implements BitRandomSource { return this.gaussianSource.nextGaussian(); } - public static class LegacyPositionalRandomFactory implements PositionalRandomFactory { - private final long seed; - - public LegacyPositionalRandomFactory(long seed) { - this.seed = seed; - } - + public record LegacyPositionalRandomFactory(long seed) implements PositionalRandomFactory { // DivineMC - make record @Override public RandomSource at(int x, int y, int z) { long seed = Mth.getSeed(x, y, z); diff --git a/net/minecraft/world/level/levelgen/NoiseBasedChunkGenerator.java b/net/minecraft/world/level/levelgen/NoiseBasedChunkGenerator.java index 65728ef17e63d71833677fdcbd5bb90794b4822b..6ef91bd952d4a0c1ffa6f534e4fcdd5c0a9db40b 100644 --- a/net/minecraft/world/level/levelgen/NoiseBasedChunkGenerator.java +++ b/net/minecraft/world/level/levelgen/NoiseBasedChunkGenerator.java @@ -65,11 +65,13 @@ public final class NoiseBasedChunkGenerator extends ChunkGenerator { } private static Aquifer.FluidPicker createFluidPicker(NoiseGeneratorSettings settings) { - Aquifer.FluidStatus fluidStatus = new Aquifer.FluidStatus(-54, Blocks.LAVA.defaultBlockState()); - int seaLevel = settings.seaLevel(); - Aquifer.FluidStatus fluidStatus1 = new Aquifer.FluidStatus(seaLevel, settings.defaultFluid()); - Aquifer.FluidStatus fluidStatus2 = new Aquifer.FluidStatus(DimensionType.MIN_Y * 2, Blocks.AIR.defaultBlockState()); - return (x, y, z) -> y < Math.min(-54, seaLevel) ? fluidStatus : fluidStatus1; + // DivineMC start - World gen optimizations + Aquifer.FluidStatus fluidLevel = new Aquifer.FluidStatus(-54, Blocks.LAVA.defaultBlockState()); + int i = settings.seaLevel(); + Aquifer.FluidStatus fluidLevel2 = new Aquifer.FluidStatus(i, settings.defaultFluid()); + final int min = Math.min(-54, i); + return (j, k, lx) -> k < min ? fluidLevel : fluidLevel2; + // DivineMC end - World gen optimizations } @Override diff --git a/net/minecraft/world/level/levelgen/NoiseSettings.java b/net/minecraft/world/level/levelgen/NoiseSettings.java index 4cf3a364595ba5f81f741295695cb9a449bdf672..44df2ac0bd972c4d97fc89cd0c2d2d83480ca3e1 100644 --- a/net/minecraft/world/level/levelgen/NoiseSettings.java +++ b/net/minecraft/world/level/levelgen/NoiseSettings.java @@ -8,7 +8,7 @@ import net.minecraft.core.QuartPos; import net.minecraft.world.level.LevelHeightAccessor; import net.minecraft.world.level.dimension.DimensionType; -public record NoiseSettings(int minY, int height, int noiseSizeHorizontal, int noiseSizeVertical) { +public record NoiseSettings(int minY, int height, int noiseSizeHorizontal, int noiseSizeVertical, int horizontalCellBlockCount, int verticalCellBlockCount) { // DivineMC - NoiseSettings optimizations public static final Codec CODEC = RecordCodecBuilder.create( instance -> instance.group( Codec.intRange(DimensionType.MIN_Y, DimensionType.MAX_Y).fieldOf("min_y").forGetter(NoiseSettings::minY), @@ -16,7 +16,10 @@ public record NoiseSettings(int minY, int height, int noiseSizeHorizontal, int n Codec.intRange(1, 4).fieldOf("size_horizontal").forGetter(NoiseSettings::noiseSizeHorizontal), Codec.intRange(1, 4).fieldOf("size_vertical").forGetter(NoiseSettings::noiseSizeVertical) ) - .apply(instance, NoiseSettings::new) + // DivineMC start - NoiseSettings optimizations + .apply(instance, (Integer minY1, Integer height1, Integer noiseSizeHorizontal1, Integer noiseSizeVertical1) -> new NoiseSettings(minY1, height1, noiseSizeHorizontal1, noiseSizeVertical1, + QuartPos.toBlock(noiseSizeHorizontal1), QuartPos.toBlock(noiseSizeVertical1))) + // DivineMC end - NoiseSettings optimizations ) .comapFlatMap(NoiseSettings::guardY, Function.identity()); protected static final NoiseSettings OVERWORLD_NOISE_SETTINGS = create(-64, 384, 1, 2); @@ -36,7 +39,7 @@ public record NoiseSettings(int minY, int height, int noiseSizeHorizontal, int n } public static NoiseSettings create(int minY, int height, int noiseSizeHorizontal, int noiseSizeVertical) { - NoiseSettings noiseSettings = new NoiseSettings(minY, height, noiseSizeHorizontal, noiseSizeVertical); + NoiseSettings noiseSettings = new NoiseSettings(minY, height, noiseSizeHorizontal, noiseSizeVertical, QuartPos.toBlock(noiseSizeHorizontal), QuartPos.toBlock(noiseSizeVertical)); // DivineMC - NoiseSettings optimizations guardY(noiseSettings).error().ifPresent(error -> { throw new IllegalStateException(error.message()); }); @@ -44,16 +47,16 @@ public record NoiseSettings(int minY, int height, int noiseSizeHorizontal, int n } public int getCellHeight() { - return QuartPos.toBlock(this.noiseSizeVertical()); + return verticalCellBlockCount(); // DivineMC - NoiseSettings optimizations } public int getCellWidth() { - return QuartPos.toBlock(this.noiseSizeHorizontal()); + return horizontalCellBlockCount(); // DivineMC - NoiseSettings optimizations } public NoiseSettings clampToHeightAccessor(LevelHeightAccessor heightAccessor) { int max = Math.max(this.minY, heightAccessor.getMinY()); int i = Math.min(this.minY + this.height, heightAccessor.getMaxY() + 1) - max; - return new NoiseSettings(max, i, this.noiseSizeHorizontal, this.noiseSizeVertical); + return new NoiseSettings(max, i, this.noiseSizeHorizontal, this.noiseSizeVertical, QuartPos.toBlock(this.noiseSizeHorizontal), QuartPos.toBlock(this.noiseSizeVertical)); // DivineMC - NoiseSettings optimizations } } diff --git a/net/minecraft/world/level/levelgen/XoroshiroRandomSource.java b/net/minecraft/world/level/levelgen/XoroshiroRandomSource.java index 9d3a9ca1e13cd80f468f1352bbb74345f03903dd..d97b9b43686bda0a95fc02f6ca31b2d07d603a32 100644 --- a/net/minecraft/world/level/levelgen/XoroshiroRandomSource.java +++ b/net/minecraft/world/level/levelgen/XoroshiroRandomSource.java @@ -106,15 +106,7 @@ public class XoroshiroRandomSource implements RandomSource { return this.randomNumberGenerator.nextLong() >>> 64 - bits; } - public static class XoroshiroPositionalRandomFactory implements PositionalRandomFactory { - private final long seedLo; - private final long seedHi; - - public XoroshiroPositionalRandomFactory(long seedLo, long seedHi) { - this.seedLo = seedLo; - this.seedHi = seedHi; - } - + public record XoroshiroPositionalRandomFactory(long seedLo, long seedHi) implements PositionalRandomFactory { // DivineMC - make record @Override public RandomSource at(int x, int y, int z) { long seed = Mth.getSeed(x, y, z); diff --git a/net/minecraft/world/level/levelgen/synth/PerlinNoise.java b/net/minecraft/world/level/levelgen/synth/PerlinNoise.java index ffac5b7b1eb1364ab8442d7145a7b4ebde68ee10..ef28df96ed569113a9d61f6ac4b4d84d578c02da 100644 --- a/net/minecraft/world/level/levelgen/synth/PerlinNoise.java +++ b/net/minecraft/world/level/levelgen/synth/PerlinNoise.java @@ -187,7 +187,7 @@ public class PerlinNoise { } public static double wrap(double value) { - return value - Mth.lfloor(value / 3.3554432E7 + 0.5) * 3.3554432E7; + return value - Math.floor(value / 3.3554432E7 + 0.5) * 3.3554432E7; // DivineMC - avoid casting } protected int firstOctave() {