From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 From: NONPLAYT <76615486+NONPLAYT@users.noreply.github.com> Date: Wed, 12 Feb 2025 01:05:50 +0300 Subject: [PATCH] C2ME: Density Function Compiler This functionality compiles density functions from world generation datapacks (including vanilla generation) to JVM bytecode to increase performance by allowing JVM JIT to better optimize the code. All functions provided by vanilla are implemented. About Density function: https://minecraft.wiki/w/Density_function diff --git a/net/minecraft/util/CubicSpline.java b/net/minecraft/util/CubicSpline.java index c04229bbed9d1162ecec99b8042d1707e2fc09bc..45b01de060362d88a5f02a76d6e6dc01748a55f5 100644 --- a/net/minecraft/util/CubicSpline.java +++ b/net/minecraft/util/CubicSpline.java @@ -254,31 +254,47 @@ public interface CubicSpline> extends Bound @Override public float apply(C input) { - float f = this.coordinate.apply(input); - int i = findIntervalStart(this.locations, f); - int i1 = this.locations.length - 1; - if (i < 0) { - return linearExtend(f, this.locations, this.values.get(0).apply(input), this.derivatives, 0); - } else if (i == i1) { - return linearExtend(f, this.locations, this.values.get(i1).apply(input), this.derivatives, i1); + // DivineMC start - Density Function Compiler + float point = this.coordinate.apply(input); + int rangeForLocation = findIntervalStart(this.locations, point); + int last = this.locations.length - 1; + if (rangeForLocation < 0) { + return linearExtend(point, this.locations, this.values.get(0).apply(input), this.derivatives, 0); + } else if (rangeForLocation == last) { + return linearExtend(point, this.locations, this.values.get(last).apply(input), this.derivatives, last); } else { - float f1 = this.locations[i]; - float f2 = this.locations[i + 1]; - float f3 = (f - f1) / (f2 - f1); - BoundedFloatFunction boundedFloatFunction = (BoundedFloatFunction)this.values.get(i); - BoundedFloatFunction boundedFloatFunction1 = (BoundedFloatFunction)this.values.get(i + 1); - float f4 = this.derivatives[i]; - float f5 = this.derivatives[i + 1]; - float f6 = boundedFloatFunction.apply(input); - float f7 = boundedFloatFunction1.apply(input); - float f8 = f4 * (f2 - f1) - (f7 - f6); - float f9 = -f5 * (f2 - f1) + (f7 - f6); - return Mth.lerp(f3, f6, f7) + f3 * (1.0F - f3) * Mth.lerp(f3, f8, f9); + float loc0 = this.locations[rangeForLocation]; + float loc1 = this.locations[rangeForLocation + 1]; + float locDist = loc1 - loc0; + float k = (point - loc0) / locDist; + float n = this.values.get(rangeForLocation).apply(input); + float o = this.values.get(rangeForLocation + 1).apply(input); + float onDist = o - n; + float p = this.derivatives[rangeForLocation] * locDist - onDist; + float q = -this.derivatives[rangeForLocation + 1] * locDist + onDist; + return Mth.lerp(k, n, o) + k * (1.0F - k) * Mth.lerp(k, p, q); } + // DivineMC end - Density Function Compiler } private static int findIntervalStart(float[] locations, float start) { - return Mth.binarySearch(0, locations.length, i -> start < locations[i]) - 1; + // DivineMC start - Density Function Compiler + int min = 0; + int i = locations.length; + + while (i > 0) { + int j = i / 2; + int k = min + j; + if (start < locations[k]) { + i = j; + } else { + min = k + 1; + i -= j + 1; + } + } + + return min - 1; + // DivineMC end - Density Function Compiler } @VisibleForTesting @@ -313,5 +329,27 @@ public interface CubicSpline> extends Bound this.derivatives ); } + + // DivineMC start - Density Function Compiler + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + Multipoint that = (Multipoint) o; + return java.util.Objects.equals(coordinate, that.coordinate()) && java.util.Arrays.equals(locations, that.locations()) && java.util.Objects.equals(values, that.values()) && java.util.Arrays.equals(derivatives, that.derivatives()); + } + + @Override + public int hashCode() { + int result = 1; + + result = 31 * result + java.util.Objects.hashCode(coordinate); + result = 31 * result + java.util.Arrays.hashCode(locations); + result = 31 * result + java.util.Objects.hashCode(values); + result = 31 * result + java.util.Arrays.hashCode(derivatives); + + return result; + } + // DivineMC end - Density Function Compiler } } diff --git a/net/minecraft/world/level/levelgen/DensityFunctions.java b/net/minecraft/world/level/levelgen/DensityFunctions.java index f2fd59359c69a379b9b0a359c7fc917890b3bb74..90531d659d8be9178d8e7ed9fc20a57d204cf07e 100644 --- a/net/minecraft/world/level/levelgen/DensityFunctions.java +++ b/net/minecraft/world/level/levelgen/DensityFunctions.java @@ -281,38 +281,66 @@ public final class DensityFunctions { @Override public void fillArray(double[] array, DensityFunction.ContextProvider contextProvider) { - this.argument1.fillArray(array, contextProvider); - switch (this.type) { - case ADD: - double[] doubles = new double[array.length]; - this.argument2.fillArray(doubles, contextProvider); - - for (int i = 0; i < array.length; i++) { - array[i] += doubles[i]; - } - break; - case MUL: - for (int i1 = 0; i1 < array.length; i1++) { - double d = array[i1]; - array[i1] = d == 0.0 ? 0.0 : d * this.argument2.compute(contextProvider.forIndex(i1)); - } - break; - case MIN: - double d1 = this.argument2.minValue(); + // DivineMC start - Density Function Compiler + Runnable run = () -> { + this.argument1.fillArray(array, contextProvider); + switch (this.type) { + case ADD: + double[] doubles = new double[array.length]; + this.argument2.fillArray(doubles, contextProvider); + + for (int i = 0; i < array.length; i++) { + array[i] += doubles[i]; + } + break; + case MUL: + for (int i1 = 0; i1 < array.length; i1++) { + double d = array[i1]; + array[i1] = d == 0.0 ? 0.0 : d * this.argument2.compute(contextProvider.forIndex(i1)); + } + break; + case MIN: + double d1 = this.argument2.minValue(); + + for (int i2 = 0; i2 < array.length; i2++) { + double d2 = array[i2]; + array[i2] = d2 < d1 ? d2 : Math.min(d2, this.argument2.compute(contextProvider.forIndex(i2))); + } + break; + case MAX: + d1 = this.argument2.maxValue(); + + for (int i2 = 0; i2 < array.length; i2++) { + double d2 = array[i2]; + array[i2] = d2 > d1 ? d2 : Math.max(d2, this.argument2.compute(contextProvider.forIndex(i2))); + } + } + }; + if (org.bxteam.divinemc.config.DivineConfig.PerformanceCategory.enableDensityFunctionCompiler && this.type == DensityFunctions.TwoArgumentSimpleFunction.Type.ADD) { + this.argument1.fillArray(array, contextProvider); + double[] ds; - for (int i2 = 0; i2 < array.length; i2++) { - double d2 = array[i2]; - array[i2] = d2 < d1 ? d2 : Math.min(d2, this.argument2.compute(contextProvider.forIndex(i2))); - } - break; - case MAX: - d1 = this.argument2.maxValue(); + com.ishland.c2me.opts.dfc.common.util.ArrayCache arrayCache = contextProvider instanceof com.ishland.c2me.opts.dfc.common.ducks.IArrayCacheCapable arrayCacheCapable ? arrayCacheCapable.c2me$getArrayCache() : null; - for (int i2 = 0; i2 < array.length; i2++) { - double d2 = array[i2]; - array[i2] = d2 > d1 ? d2 : Math.max(d2, this.argument2.compute(contextProvider.forIndex(i2))); - } + if (arrayCache != null) { + ds = arrayCache.getDoubleArray(array.length, false); + } else { + ds = new double[array.length]; + } + + this.argument2.fillArray(ds, contextProvider); + + for (int i = 0; i < array.length; i++) { + array[i] += ds[i]; + } + + if (arrayCache != null) { + arrayCache.recycle(ds); + } + } else { + run.run(); } + // DivineMC end - Density Function Compiler } @Override @@ -756,7 +784,105 @@ public final class DensityFunctions { } } - protected record Marker(@Override DensityFunctions.Marker.Type type, @Override DensityFunction wrapped) implements DensityFunctions.MarkerOrMarked { + // DivineMC start - Density Function Compiler + public static final class Marker implements com.ishland.c2me.opts.dfc.common.ducks.IFastCacheLike, com.ishland.c2me.opts.dfc.common.ducks.IEqualityOverriding, MarkerOrMarked { + private final Type type; + private final DensityFunction wrapped; + private Object c2me$optionalEquality; + + @Override + public boolean equals(final Object that) { + Function original = (o) -> { + if (o == this) return true; + if (o == null || o.getClass() != this.getClass()) return false; + var a = (Marker) o; + return java.util.Objects.equals(this.type, a.type) && + java.util.Objects.equals(this.wrapped, a.wrapped); + }; + if (true) { + return original.apply(that); + } + Object a = this.c2me$getOverriddenEquality(); + Object b = that instanceof com.ishland.c2me.opts.dfc.common.ducks.IEqualityOverriding equalityOverriding ? equalityOverriding.c2me$getOverriddenEquality() : null; + if (a == null) { + return original.apply(b != null ? b : that); + } else { + return a.equals(b != null ? b : that); + } + } + + @Override + public int hashCode() { + java.util.function.Supplier original = () -> java.util.Objects.hash(type, wrapped); + Object c2me$optionalEquality1 = this.c2me$optionalEquality; + if (c2me$optionalEquality1 != null && false) { + return c2me$optionalEquality1.hashCode(); + } else { + return original.get(); + } + } + + public Marker(Type type, DensityFunction wrapped) { + this.type = type; + this.wrapped = wrapped; + } + + @Override + public double c2me$getCached(int x, int y, int z, com.ishland.c2me.opts.dfc.common.ast.EvalType evalType) { + return Double.longBitsToDouble(CACHE_MISS_NAN_BITS); + } + + @Override + public boolean c2me$getCached(double[] res, int[] x, int[] y, int[] z, com.ishland.c2me.opts.dfc.common.ast.EvalType evalType) { + return false; + } + + @Override + public void c2me$cache(int x, int y, int z, com.ishland.c2me.opts.dfc.common.ast.EvalType evalType, double cached) { + // nop + } + + @Override + public void c2me$cache(double[] res, int[] x, int[] y, int[] z, com.ishland.c2me.opts.dfc.common.ast.EvalType evalType) { + // nop + } + + @Override + public DensityFunction c2me$getDelegate() { + return this.wrapped; + } + + @Override + public DensityFunction c2me$withDelegate(DensityFunction delegate) { + DensityFunctions.Marker wrapping = new DensityFunctions.Marker(this.type(), delegate); + ((com.ishland.c2me.opts.dfc.common.ducks.IEqualityOverriding) (Object) wrapping).c2me$overrideEquality(this); + return wrapping; + } + + @Override + public void c2me$overrideEquality(Object object) { + Object inner = object; + while (true) { + Object inner1 = inner instanceof com.ishland.c2me.opts.dfc.common.ducks.IEqualityOverriding e1 ? e1.c2me$getOverriddenEquality() : null; + if (inner1 == null) { + this.c2me$optionalEquality = inner; + break; + } + inner = inner1; + } + } + + @Override + public Object c2me$getOverriddenEquality() { + return this.c2me$optionalEquality; + } + + @Override + public DensityFunction mapAll(Visitor visitor) { + return visitor.apply(this.c2me$withDelegate(this.wrapped().mapAll(visitor))); + } + // DivineMC end - Density Function Compiler + @Override public double compute(DensityFunction.FunctionContext context) { return this.wrapped.compute(context); @@ -777,7 +903,19 @@ public final class DensityFunctions { return this.wrapped.maxValue(); } - static enum Type implements StringRepresentable { + // DivineMC start - Density Function Compiler + @Override + public Type type() { + return type; + } + + @Override + public DensityFunction wrapped() { + return wrapped; + } + // DivineMC end - Density Function Compiler + + public static enum Type implements StringRepresentable { // DivineMC - Density Function Compiler - make this public Interpolated("interpolated"), FlatCache("flat_cache"), Cache2D("cache_2d"), diff --git a/net/minecraft/world/level/levelgen/NoiseChunk.java b/net/minecraft/world/level/levelgen/NoiseChunk.java index ff0c2aa0cdf7a88f67e6438dbd17d9c2bc39107a..3c3615043ab87da45b7ea47bf2f632a91a60dbc6 100644 --- a/net/minecraft/world/level/levelgen/NoiseChunk.java +++ b/net/minecraft/world/level/levelgen/NoiseChunk.java @@ -8,6 +8,7 @@ import java.util.Arrays; import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.function.Supplier; import javax.annotation.Nullable; import net.minecraft.core.QuartPos; import net.minecraft.core.SectionPos; @@ -21,7 +22,18 @@ import net.minecraft.world.level.chunk.ChunkAccess; import net.minecraft.world.level.levelgen.blending.Blender; import net.minecraft.world.level.levelgen.material.MaterialRuleList; -public class NoiseChunk implements DensityFunction.ContextProvider, DensityFunction.FunctionContext { +// DivineMC start - Density Function Compiler +import com.ishland.c2me.opts.dfc.common.ast.EvalType; +import com.ishland.c2me.opts.dfc.common.ducks.IArrayCacheCapable; +import com.ishland.c2me.opts.dfc.common.ducks.ICoordinatesFilling; +import com.ishland.c2me.opts.dfc.common.ducks.IFastCacheLike; +import com.ishland.c2me.opts.dfc.common.gen.DelegatingBlendingAwareVisitor; +import com.ishland.c2me.opts.dfc.common.util.ArrayCache; +import com.ishland.c2me.opts.dfc.common.vif.EachApplierVanillaInterface; +import com.ishland.c2me.opts.dfc.common.vif.NoisePosVanillaInterface; +// DivineMC end - Density Function Compiler + +public class NoiseChunk implements DensityFunction.ContextProvider, DensityFunction.FunctionContext, IArrayCacheCapable, ICoordinatesFilling { private final NoiseSettings noiseSettings; final int cellCountXZ; final int cellCountY; @@ -57,7 +69,47 @@ public class NoiseChunk implements DensityFunction.ContextProvider, DensityFunct long interpolationCounter; long arrayInterpolationCounter; int arrayIndex; - private final DensityFunction.ContextProvider sliceFillingContextProvider = new DensityFunction.ContextProvider() { + // DivineMC start - Density Function Compiler + private final ArrayCache c2me$arrayCache = new ArrayCache(); + + @Override + public ArrayCache c2me$getArrayCache() { + return this.c2me$arrayCache != null ? this.c2me$arrayCache : new ArrayCache(); + } + + @Override + public void c2me$fillCoordinates(int[] x, int[] y, int[] z) { + int index = 0; + for (int i = this.cellHeight - 1; i >= 0; i--) { + int blockY = this.cellStartBlockY + i; + for (int j = 0; j < this.cellWidth; j++) { + int blockX = this.cellStartBlockX + j; + for (int k = 0; k < this.cellWidth; k++) { + int blockZ = this.cellStartBlockZ + k; + + x[index] = blockX; + y[index] = blockY; + z[index] = blockZ; + + index++; + } + } + } + } + + private @org.jetbrains.annotations.NotNull DelegatingBlendingAwareVisitor c2me$getDelegatingBlendingAwareVisitor(DensityFunction.Visitor visitor) { + return new DelegatingBlendingAwareVisitor(visitor, this.getBlender() != Blender.empty()); + } + + private DensityFunction.Visitor modifyVisitor1(DensityFunction.Visitor visitor) { + return c2me$getDelegatingBlendingAwareVisitor(visitor); + } + + private DensityFunction.Visitor modifyVisitor2(DensityFunction.Visitor visitor) { + return c2me$getDelegatingBlendingAwareVisitor(visitor); + } + + public class NoiseChunkSliceFillingContextProvider implements DensityFunction.ContextProvider, IArrayCacheCapable, ICoordinatesFilling { @Override public DensityFunction.FunctionContext forIndex(int arrayIndex) { NoiseChunk.this.cellStartBlockY = (arrayIndex + NoiseChunk.this.cellNoiseMinY) * NoiseChunk.this.cellHeight; @@ -77,7 +129,23 @@ public class NoiseChunk implements DensityFunction.ContextProvider, DensityFunct values[i] = function.compute(NoiseChunk.this); } } - }; + + @Override + public ArrayCache c2me$getArrayCache() { + return (NoiseChunk.this).c2me$getArrayCache(); + } + + @Override + public void c2me$fillCoordinates(int[] x, int[] y, int[] z) { + for (int i = 0; i < (NoiseChunk.this).cellCountY + 1; i++) { + x[i] = (NoiseChunk.this).cellStartBlockX + (NoiseChunk.this).inCellX; + y[i] = (i + (NoiseChunk.this).cellNoiseMinY) * (NoiseChunk.this).cellHeight; + z[i] = (NoiseChunk.this).cellStartBlockZ + (NoiseChunk.this).inCellZ; + } + } + } + private final DensityFunction.ContextProvider sliceFillingContextProvider = new NoiseChunkSliceFillingContextProvider(); + // DivineMC end - Density Function Compiler public static NoiseChunk forChunk( ChunkAccess chunk, @@ -140,7 +208,7 @@ public class NoiseChunk implements DensityFunction.ContextProvider, DensityFunct } NoiseRouter noiseRouter = random.router(); - NoiseRouter noiseRouter1 = noiseRouter.mapAll(this::wrap); + NoiseRouter noiseRouter1 = noiseRouter.mapAll(org.bxteam.divinemc.config.DivineConfig.PerformanceCategory.enableDensityFunctionCompiler ? modifyVisitor1(this::wrap) : this::wrap); // DivineMC - Density Function Compiler this.preliminarySurfaceLevel = noiseRouter1.preliminarySurfaceLevel(); if (!noiseGeneratorSettings.isAquifersEnabled()) { this.aquifer = Aquifer.createDisabled(fluidPicker); @@ -156,7 +224,7 @@ public class NoiseChunk implements DensityFunction.ContextProvider, DensityFunct DensityFunction densityFunction = DensityFunctions.cacheAllInCell( DensityFunctions.add(noiseRouter1.finalDensity(), DensityFunctions.BeardifierMarker.INSTANCE) ) - .mapAll(this::wrap); + .mapAll(org.bxteam.divinemc.config.DivineConfig.PerformanceCategory.enableDensityFunctionCompiler ? modifyVisitor2(this::wrap) : this::wrap); // DivineMC - Density Function Compiler list.add(context -> this.aquifer.computeSubstance(context, densityFunction.compute(context))); if (noiseGeneratorSettings.oreVeinsEnabled()) { list.add(OreVeinifier.create(noiseRouter1.veinToggle(), noiseRouter1.veinRidged(), noiseRouter1.veinGap(), random.oreRandom())); @@ -167,12 +235,14 @@ public class NoiseChunk implements DensityFunction.ContextProvider, DensityFunct protected Climate.Sampler cachedClimateSampler(NoiseRouter noiseRouter, List points) { return new Climate.Sampler( - noiseRouter.temperature().mapAll(this::wrap), - noiseRouter.vegetation().mapAll(this::wrap), - noiseRouter.continents().mapAll(this::wrap), - noiseRouter.erosion().mapAll(this::wrap), - noiseRouter.depth().mapAll(this::wrap), - noiseRouter.ridges().mapAll(this::wrap), + // DivineMC start - Density Function Compiler + noiseRouter.temperature().mapAll(org.bxteam.divinemc.config.DivineConfig.PerformanceCategory.enableDensityFunctionCompiler ? modifyVisitor2(this::wrap) : this::wrap), + noiseRouter.vegetation().mapAll(org.bxteam.divinemc.config.DivineConfig.PerformanceCategory.enableDensityFunctionCompiler ? modifyVisitor2(this::wrap) : this::wrap), + noiseRouter.continents().mapAll(org.bxteam.divinemc.config.DivineConfig.PerformanceCategory.enableDensityFunctionCompiler ? modifyVisitor2(this::wrap) : this::wrap), + noiseRouter.erosion().mapAll(org.bxteam.divinemc.config.DivineConfig.PerformanceCategory.enableDensityFunctionCompiler ? modifyVisitor2(this::wrap) : this::wrap), + noiseRouter.depth().mapAll(org.bxteam.divinemc.config.DivineConfig.PerformanceCategory.enableDensityFunctionCompiler ? modifyVisitor2(this::wrap) : this::wrap), + noiseRouter.ridges().mapAll(org.bxteam.divinemc.config.DivineConfig.PerformanceCategory.enableDensityFunctionCompiler ? modifyVisitor2(this::wrap) : this::wrap), + // DivineMC end - Density Function Compiler points ); } @@ -378,6 +448,13 @@ public class NoiseChunk implements DensityFunction.ContextProvider, DensityFunct } private DensityFunction wrapNew(DensityFunction densityFunction) { + // DivineMC start - Density Function Compiler + if (org.bxteam.divinemc.config.DivineConfig.PerformanceCategory.enableDensityFunctionCompiler) { + if (this.interpolating && densityFunction instanceof DensityFunctions.Marker) { + throw new IllegalStateException("Cannot create more wrapping during interpolation loop"); + } + } + // DivineMC end - Density Function Compiler if (densityFunction instanceof DensityFunctions.Marker marker) { return (DensityFunction)(switch (marker.type()) { case Interpolated -> new NoiseChunk.NoiseInterpolator(marker.wrapped()); @@ -487,10 +564,48 @@ public class NoiseChunk implements DensityFunction.ContextProvider, DensityFunct BlockState calculate(DensityFunction.FunctionContext context); } - static class Cache2D implements DensityFunctions.MarkerOrMarked, NoiseChunk.NoiseChunkDensityFunction { + static class Cache2D implements DensityFunctions.MarkerOrMarked, NoiseChunk.NoiseChunkDensityFunction, IFastCacheLike { // DivineMC - Density Function Compiler private DensityFunction function; private long lastPos2D = ChunkPos.INVALID_CHUNK_POS; private double lastValue; + // DivineMC start - Density Function Compiler + @Override + public double c2me$getCached(int x, int y, int z, EvalType evalType) { + long l = ChunkPos.asLong(x, z); + if (this.lastPos2D == l) { + return this.lastValue; + } else { + return Double.longBitsToDouble(CACHE_MISS_NAN_BITS); + } + } + + @Override + public boolean c2me$getCached(double[] res, int[] x, int[] y, int[] z, EvalType evalType) { + return false; + } + + @Override + public void c2me$cache(int x, int y, int z, EvalType evalType, double cached) { + this.lastPos2D = ChunkPos.asLong(x, z); + this.lastValue = cached; + } + + @Override + public void c2me$cache(double[] res, int[] x, int[] y, int[] z, EvalType evalType) { + // nop + } + + @Override + public DensityFunction c2me$getDelegate() { + return this.function; + } + + @Override + public DensityFunction c2me$withDelegate(DensityFunction delegate) { + this.function = delegate; + return this; + } + // DivineMC end - Density Function Compiler Cache2D(DensityFunction function) { this.function = function; @@ -527,9 +642,92 @@ public class NoiseChunk implements DensityFunction.ContextProvider, DensityFunct } } - class CacheAllInCell implements DensityFunctions.MarkerOrMarked, NoiseChunk.NoiseChunkDensityFunction { - final DensityFunction noiseFiller; + class CacheAllInCell implements DensityFunctions.MarkerOrMarked, NoiseChunk.NoiseChunkDensityFunction, IFastCacheLike { // DivineMC - Density Function Compiler + DensityFunction noiseFiller; // DivineMC - remove final final double[] values; + // DivineMC start - Density Function Compiler + @Override + public double c2me$getCached(int x, int y, int z, EvalType evalType) { + if (evalType == EvalType.INTERPOLATION) { + boolean isInInterpolationLoop = (NoiseChunk.this).interpolating; + if (isInInterpolationLoop) { + int startBlockX = (NoiseChunk.this).cellStartBlockX; + int startBlockY = (NoiseChunk.this).cellStartBlockY; + int startBlockZ = (NoiseChunk.this).cellStartBlockZ; + int horizontalCellBlockCount = (NoiseChunk.this).cellWidth; + int verticalCellBlockCount = (NoiseChunk.this).cellHeight; + int cellBlockX = x - startBlockX; + int cellBlockY = y - startBlockY; + int cellBlockZ = z - startBlockZ; + if (cellBlockX >= 0 && + cellBlockY >= 0 && + cellBlockZ >= 0 && + cellBlockX < horizontalCellBlockCount && + cellBlockY < verticalCellBlockCount && + cellBlockZ < horizontalCellBlockCount) { + return this.values[((verticalCellBlockCount - 1 - cellBlockY) * horizontalCellBlockCount + cellBlockX) + * horizontalCellBlockCount + + cellBlockZ]; + } + } + } + + return CACHE_MISS_NAN_BITS; + } + + @Override + public boolean c2me$getCached(double[] res, int[] x, int[] y, int[] z, EvalType evalType) { + if (evalType == EvalType.INTERPOLATION) { + boolean isInInterpolationLoop = (NoiseChunk.this).interpolating; + if (isInInterpolationLoop) { + int startBlockX = (NoiseChunk.this).cellStartBlockX; + int startBlockY = (NoiseChunk.this).cellStartBlockY; + int startBlockZ = (NoiseChunk.this).cellStartBlockZ; + int horizontalCellBlockCount = (NoiseChunk.this).cellWidth; + int verticalCellBlockCount = (NoiseChunk.this).cellHeight; + for (int i = 0; i < res.length; i++) { + int cellBlockX = x[i] - startBlockX; + int cellBlockY = y[i] - startBlockY; + int cellBlockZ = z[i] - startBlockZ; + if (cellBlockX >= 0 && + cellBlockY >= 0 && + cellBlockZ >= 0 && + cellBlockX < horizontalCellBlockCount && + cellBlockY < verticalCellBlockCount && + cellBlockZ < horizontalCellBlockCount) { + res[i] = this.values[((verticalCellBlockCount - 1 - cellBlockY) * horizontalCellBlockCount + cellBlockX) * horizontalCellBlockCount + cellBlockZ]; + } else { + System.out.println("partial cell cache hit"); + return false; // partial hit possible + } + } + } + } + + return false; + } + + @Override + public void c2me$cache(int x, int y, int z, EvalType evalType, double cached) { + // nop + } + + @Override + public void c2me$cache(double[] res, int[] x, int[] y, int[] z, EvalType evalType) { + // nop + } + + @Override + public DensityFunction c2me$getDelegate() { + return this.noiseFiller; + } + + @Override + public DensityFunction c2me$withDelegate(DensityFunction delegate) { + this.noiseFiller = delegate; + return this; + } + // DivineMC end - Density Function Compiler CacheAllInCell(final DensityFunction noiseFilter) { this.noiseFiller = noiseFilter; @@ -539,18 +737,51 @@ public class NoiseChunk implements DensityFunction.ContextProvider, DensityFunct @Override public double compute(DensityFunction.FunctionContext context) { - if (context != NoiseChunk.this) { - return this.noiseFiller.compute(context); - } else if (!NoiseChunk.this.interpolating) { - throw new IllegalStateException("Trying to sample interpolator outside the interpolation loop"); - } else { - int i = NoiseChunk.this.inCellX; - int i1 = NoiseChunk.this.inCellY; - int i2 = NoiseChunk.this.inCellZ; - return i >= 0 && i1 >= 0 && i2 >= 0 && i < NoiseChunk.this.cellWidth && i1 < NoiseChunk.this.cellHeight && i2 < NoiseChunk.this.cellWidth - ? this.values[((NoiseChunk.this.cellHeight - 1 - i1) * NoiseChunk.this.cellWidth + i) * NoiseChunk.this.cellWidth + i2] + // DivineMC start - Density Function Compiler + Supplier run = () -> { + if (context != NoiseChunk.this) { + return this.noiseFiller.compute(context); + } else if (!NoiseChunk.this.interpolating) { + throw new IllegalStateException("Trying to sample interpolator outside the interpolation loop"); + } else { + int i = NoiseChunk.this.inCellX; + int i1 = NoiseChunk.this.inCellY; + int i2 = NoiseChunk.this.inCellZ; + return i >= 0 && i1 >= 0 && i2 >= 0 && i < NoiseChunk.this.cellWidth && i1 < NoiseChunk.this.cellHeight && i2 < NoiseChunk.this.cellWidth + ? this.values[((NoiseChunk.this.cellHeight - 1 - i1) * NoiseChunk.this.cellWidth + i) * NoiseChunk.this.cellWidth + i2] + : this.noiseFiller.compute(context); + } + }; + if (!org.bxteam.divinemc.config.DivineConfig.PerformanceCategory.enableDensityFunctionCompiler || context instanceof NoiseChunk) { + return run.get(); + } + if (context instanceof NoisePosVanillaInterface vif && vif.getType() == EvalType.INTERPOLATION) { + boolean isInInterpolationLoop = (NoiseChunk.this).interpolating; + if (!isInInterpolationLoop) { + return run.get(); + } + int startBlockX = (NoiseChunk.this).cellStartBlockX; + int startBlockY = (NoiseChunk.this).cellStartBlockY; + int startBlockZ = (NoiseChunk.this).cellStartBlockZ; + int horizontalCellBlockCount = (NoiseChunk.this).cellWidth; + int verticalCellBlockCount = (NoiseChunk.this).cellHeight; + int cellBlockX = context.blockX() - startBlockX; + int cellBlockY = context.blockY() - startBlockY; + int cellBlockZ = context.blockZ() - startBlockZ; + return cellBlockX >= 0 + && cellBlockY >= 0 + && cellBlockZ >= 0 + && cellBlockX < horizontalCellBlockCount + && cellBlockY < verticalCellBlockCount + && cellBlockZ < horizontalCellBlockCount + ? this.values[((verticalCellBlockCount - 1 - cellBlockY) * horizontalCellBlockCount + cellBlockX) + * horizontalCellBlockCount + + cellBlockZ] : this.noiseFiller.compute(context); } + + return run.get(); + // DivineMC end - Density Function Compiler } @Override @@ -569,13 +800,84 @@ public class NoiseChunk implements DensityFunction.ContextProvider, DensityFunct } } - class CacheOnce implements DensityFunctions.MarkerOrMarked, NoiseChunk.NoiseChunkDensityFunction { + class CacheOnce implements DensityFunctions.MarkerOrMarked, NoiseChunk.NoiseChunkDensityFunction, IFastCacheLike { // DivineMC - Density Function Compiler private DensityFunction function; private long lastCounter; private long lastArrayCounter; private double lastValue; @Nullable private double[] lastArray; + // DivineMC start - Density Function Compiler + private double c2me$lastValue = Double.NaN; + private int c2me$lastX = Integer.MIN_VALUE; + private int c2me$lastY = Integer.MIN_VALUE; + private int c2me$lastZ = Integer.MIN_VALUE; + + private int[] c2me$lastXa; + private int[] c2me$lastYa; + private int[] c2me$lastZa; + private double[] c2me$lastValuea; + + @Override + public double c2me$getCached(int x, int y, int z, EvalType evalType) { + if (c2me$lastValuea != null) { + for (int i = 0; i < this.c2me$lastValuea.length; i ++) { + if (c2me$lastXa[i] == x && c2me$lastYa[i] == y && c2me$lastZa[i] == z) { + return c2me$lastValuea[i]; + } + } + } + if (!Double.isNaN(c2me$lastValue) && c2me$lastX == x && c2me$lastY == y && c2me$lastZ == z) { + return c2me$lastValue; + } + + return Double.longBitsToDouble(CACHE_MISS_NAN_BITS); + } + + @Override + public boolean c2me$getCached(double[] res, int[] x, int[] y, int[] z, EvalType evalType) { + if (c2me$lastValuea != null && Arrays.equals(y, c2me$lastYa) && Arrays.equals(x, c2me$lastXa) && Arrays.equals(z, c2me$lastZa)) { + System.arraycopy(c2me$lastValuea, 0, res, 0, c2me$lastValuea.length); + return true; + } else { + return false; + } + } + + @Override + public void c2me$cache(int x, int y, int z, EvalType evalType, double cached) { + c2me$lastValue = cached; + c2me$lastX = x; + c2me$lastY = y; + c2me$lastZ = z; + } + + @Override + public void c2me$cache(double[] res, int[] x, int[] y, int[] z, EvalType evalType) { + if (c2me$lastValuea != null && this.c2me$lastValuea.length == res.length) { + System.arraycopy(res, 0, this.c2me$lastValuea, 0, this.c2me$lastValuea.length); + System.arraycopy(x, 0, this.c2me$lastXa, 0, this.c2me$lastValuea.length); + System.arraycopy(y, 0, this.c2me$lastYa, 0, this.c2me$lastValuea.length); + System.arraycopy(z, 0, this.c2me$lastZa, 0, this.c2me$lastValuea.length); + } else { + this.c2me$lastValuea = Arrays.copyOf(res, res.length); + this.c2me$lastXa = Arrays.copyOf(x, x.length); + this.c2me$lastYa = Arrays.copyOf(y, y.length); + this.c2me$lastZa = Arrays.copyOf(z, z.length); + } + } + + @Override + public DensityFunction c2me$getDelegate() { + return this.function; + } + + @Override + public DensityFunction c2me$withDelegate(DensityFunction delegate) { + this.function = delegate; + return this; + } + // DivineMC end - Density Function Compiler CacheOnce(final DensityFunction function) { this.function = function; @@ -583,34 +885,82 @@ public class NoiseChunk implements DensityFunction.ContextProvider, DensityFunct @Override public double compute(DensityFunction.FunctionContext context) { - if (context != NoiseChunk.this) { - return this.function.compute(context); - } else if (this.lastArray != null && this.lastArrayCounter == NoiseChunk.this.arrayInterpolationCounter) { - return this.lastArray[NoiseChunk.this.arrayIndex]; - } else if (this.lastCounter == NoiseChunk.this.interpolationCounter) { - return this.lastValue; - } else { - this.lastCounter = NoiseChunk.this.interpolationCounter; - double d = this.function.compute(context); - this.lastValue = d; - return d; + // DivineMC start - Density Function Compiler + Supplier run = () -> { + if (context != NoiseChunk.this) { + return this.function.compute(context); + } else if (this.lastArray != null && this.lastArrayCounter == NoiseChunk.this.arrayInterpolationCounter) { + return this.lastArray[NoiseChunk.this.arrayIndex]; + } else if (this.lastCounter == NoiseChunk.this.interpolationCounter) { + return this.lastValue; + } else { + this.lastCounter = NoiseChunk.this.interpolationCounter; + double d = this.function.compute(context); + this.lastValue = d; + return d; + } + }; + if (!org.bxteam.divinemc.config.DivineConfig.PerformanceCategory.enableDensityFunctionCompiler || context instanceof NoiseChunk) { + return run.get(); } + int blockX = context.blockX(); + int blockY = context.blockY(); + int blockZ = context.blockZ(); + if (c2me$lastValuea != null) { + for (int i = 0; i < this.c2me$lastValuea.length; i ++) { + if (c2me$lastXa[i] == blockX && c2me$lastYa[i] == blockY && c2me$lastZa[i] == blockZ) { + return c2me$lastValuea[i]; + } + } + } + if (!Double.isNaN(c2me$lastValue) && c2me$lastX == blockX && c2me$lastY == blockY && c2me$lastZ == blockZ) { + return c2me$lastValue; + } + double sample = this.function.compute(context); + c2me$lastValue = sample; + c2me$lastX = blockX; + c2me$lastY = blockY; + c2me$lastZ = blockZ; + + return sample; + // DivineMC end - Density Function Compiler } @Override public void fillArray(double[] array, DensityFunction.ContextProvider contextProvider) { - if (this.lastArray != null && this.lastArrayCounter == NoiseChunk.this.arrayInterpolationCounter) { - System.arraycopy(this.lastArray, 0, array, 0, array.length); - } else { - this.wrapped().fillArray(array, contextProvider); - if (this.lastArray != null && this.lastArray.length == array.length) { - System.arraycopy(array, 0, this.lastArray, 0, array.length); + // DivineMC start - Density Function Compiler + Runnable run = () -> { + if (this.lastArray != null && this.lastArrayCounter == NoiseChunk.this.arrayInterpolationCounter) { + System.arraycopy(this.lastArray, 0, array, 0, array.length); } else { - this.lastArray = (double[])array.clone(); - } + this.wrapped().fillArray(array, contextProvider); + if (this.lastArray != null && this.lastArray.length == array.length) { + System.arraycopy(array, 0, this.lastArray, 0, array.length); + } else { + this.lastArray = (double[]) array.clone(); + } - this.lastArrayCounter = NoiseChunk.this.arrayInterpolationCounter; + this.lastArrayCounter = NoiseChunk.this.arrayInterpolationCounter; + } + }; + if (!org.bxteam.divinemc.config.DivineConfig.PerformanceCategory.enableDensityFunctionCompiler || contextProvider instanceof NoiseChunk) { + run.run(); + return; + } + if (contextProvider instanceof EachApplierVanillaInterface ap) { + if (c2me$lastValuea != null && Arrays.equals(ap.getY(), c2me$lastYa) && Arrays.equals(ap.getX(), c2me$lastXa) && Arrays.equals(ap.getZ(), c2me$lastZa)) { + System.arraycopy(c2me$lastValuea, 0, array, 0, c2me$lastValuea.length); + } else { + this.function.fillArray(array, contextProvider); + this.c2me$lastValuea = Arrays.copyOf(array, array.length); + this.c2me$lastXa = ap.getX(); + this.c2me$lastYa = ap.getY(); + this.c2me$lastZa = ap.getZ(); + } + return; } + this.function.fillArray(array, contextProvider); + // DivineMC end - Density Function Compiler } @Override @@ -624,10 +974,64 @@ public class NoiseChunk implements DensityFunction.ContextProvider, DensityFunct } } - class FlatCache implements DensityFunctions.MarkerOrMarked, NoiseChunk.NoiseChunkDensityFunction { + class FlatCache implements DensityFunctions.MarkerOrMarked, NoiseChunk.NoiseChunkDensityFunction, IFastCacheLike { // DivineMC - Density Function Compiler private DensityFunction noiseFiller; final double[] values; final int sizeXZ; + // DivineMC start - Density Function Compiler + @Override + public double c2me$getCached(int x, int y, int z, EvalType evalType) { + int i = QuartPos.fromBlock(x); + int j = QuartPos.fromBlock(z); + int k = i - (NoiseChunk.this).firstNoiseX; + int l = j - (NoiseChunk.this).firstNoiseZ; + int m = this.values.length; + if (k >= 0 && l >= 0 && k < m && l < m) { + return this.values[k + l * this.values.length]; + } else { + return Double.longBitsToDouble(CACHE_MISS_NAN_BITS); + } + } + + @Override + public boolean c2me$getCached(double[] res, int[] x, int[] y, int[] z, EvalType evalType) { + for (int i = 0; i < res.length; i ++) { + int i1 = QuartPos.fromBlock(x[i]); + int j1 = QuartPos.fromBlock(z[i]); + int k = i1 - (NoiseChunk.this).firstNoiseX; + int l = j1 - (NoiseChunk.this).firstNoiseZ; + int m = this.values.length; + if (k >= 0 && l >= 0 && k < m && l < m) { + res[i] = this.values[k + l * this.values.length]; + } else { + System.out.println("partial flat cache hit"); + return false; // partial hit possible + } + } + return true; + } + + @Override + public void c2me$cache(int x, int y, int z, EvalType evalType, double cached) { + // nop + } + + @Override + public void c2me$cache(double[] res, int[] x, int[] y, int[] z, EvalType evalType) { + // nop + } + + @Override + public DensityFunction c2me$getDelegate() { + return this.noiseFiller; + } + + @Override + public DensityFunction c2me$withDelegate(DensityFunction delegate) { + this.noiseFiller = delegate; + return this; + } + // DivineMC end - Density Function Compiler FlatCache(final DensityFunction noiseFiller, final boolean computeValues) { this.noiseFiller = noiseFiller; @@ -686,7 +1090,7 @@ public class NoiseChunk implements DensityFunction.ContextProvider, DensityFunct } } - public class NoiseInterpolator implements DensityFunctions.MarkerOrMarked, NoiseChunk.NoiseChunkDensityFunction { + public class NoiseInterpolator implements DensityFunctions.MarkerOrMarked, NoiseChunk.NoiseChunkDensityFunction, IFastCacheLike { // DivineMC - Density Function Compiler double[][] slice0; double[][] slice1; private DensityFunction noiseFiller; @@ -705,6 +1109,104 @@ public class NoiseChunk implements DensityFunction.ContextProvider, DensityFunct private double valueZ0; private double valueZ1; private double value; + // DivineMC start - Density Function Compiler + @Override + public double c2me$getCached(int x, int y, int z, EvalType evalType) { + if (evalType == EvalType.INTERPOLATION) { + boolean isInInterpolationLoop = (NoiseChunk.this).interpolating; + if (isInInterpolationLoop) { + if ((NoiseChunk.this).fillingCell) { + int startBlockX = (NoiseChunk.this).cellStartBlockX; + int startBlockY = (NoiseChunk.this).cellStartBlockY; + int startBlockZ = (NoiseChunk.this).cellStartBlockZ; + int horizontalCellBlockCount = (NoiseChunk.this).cellWidth; + int verticalCellBlockCount = (NoiseChunk.this).cellHeight; + int cellBlockX = x - startBlockX; + int cellBlockY = y - startBlockY; + int cellBlockZ = z - startBlockZ; + return Mth.lerp3( + (double) cellBlockX / (double) horizontalCellBlockCount, + (double) cellBlockY / (double) verticalCellBlockCount, + (double) cellBlockZ / (double) horizontalCellBlockCount, + this.noise000, + this.noise100, + this.noise010, + this.noise110, + this.noise001, + this.noise101, + this.noise011, + this.noise111 + ); + } else { + return this.value; + } + } + } + + return CACHE_MISS_NAN_BITS; + } + + @Override + public boolean c2me$getCached(double[] res, int[] x, int[] y, int[] z, EvalType evalType) { + if (evalType == EvalType.INTERPOLATION) { + boolean isInInterpolationLoop = (NoiseChunk.this).interpolating; + if (isInInterpolationLoop) { + if ((NoiseChunk.this).fillingCell) { + int startBlockX = (NoiseChunk.this).cellStartBlockX; + int startBlockY = (NoiseChunk.this).cellStartBlockY; + int startBlockZ = (NoiseChunk.this).cellStartBlockZ; + double horizontalCellBlockCount = (NoiseChunk.this).cellWidth; + double verticalCellBlockCount = (NoiseChunk.this).cellHeight; + for (int i = 0; i < res.length; i ++) { + int cellBlockX = x[i] - startBlockX; + int cellBlockY = y[i] - startBlockY; + int cellBlockZ = z[i] - startBlockZ; + res[i] = Mth.lerp3( + (double)cellBlockX / horizontalCellBlockCount, + (double)cellBlockY / verticalCellBlockCount, + (double)cellBlockZ / horizontalCellBlockCount, + this.noise000, + this.noise100, + this.noise010, + this.noise110, + this.noise001, + this.noise101, + this.noise011, + this.noise111 + ); + } + return true; + } else { + Arrays.fill(res, this.value); + return true; + } + } + } + + return false; + } + + @Override + public void c2me$cache(int x, int y, int z, EvalType evalType, double cached) { + // nop + } + + @Override + public void c2me$cache(double[] res, int[] x, int[] y, int[] z, EvalType evalType) { + // nop + } + + @Override + public DensityFunction c2me$getDelegate() { + return this.noiseFiller; + } + + @Override + public DensityFunction c2me$withDelegate(DensityFunction delegate) { + this.noiseFiller = delegate; + return this; + } + // DivineMC end - Density Function Compiler NoiseInterpolator(final DensityFunction noiseFilter) { this.noiseFiller = noiseFilter; @@ -754,16 +1256,18 @@ public class NoiseChunk implements DensityFunction.ContextProvider, DensityFunct @Override public double compute(DensityFunction.FunctionContext context) { - if (context != NoiseChunk.this) { - return this.noiseFiller.compute(context); - } else if (!NoiseChunk.this.interpolating) { - throw new IllegalStateException("Trying to sample interpolator outside the interpolation loop"); - } else { - return NoiseChunk.this.fillingCell - ? Mth.lerp3( - (double)NoiseChunk.this.inCellX / NoiseChunk.this.cellWidth, - (double)NoiseChunk.this.inCellY / NoiseChunk.this.cellHeight, - (double)NoiseChunk.this.inCellZ / NoiseChunk.this.cellWidth, + // DivineMC start - Density Function Compiler + Supplier original = () -> { + if (context != NoiseChunk.this) { + return this.noiseFiller.compute(context); + } else if (!NoiseChunk.this.interpolating) { + throw new IllegalStateException("Trying to sample interpolator outside the interpolation loop"); + } else { + return NoiseChunk.this.fillingCell + ? Mth.lerp3( + (double) NoiseChunk.this.inCellX / NoiseChunk.this.cellWidth, + (double) NoiseChunk.this.inCellY / NoiseChunk.this.cellHeight, + (double) NoiseChunk.this.inCellZ / NoiseChunk.this.cellWidth, this.noise000, this.noise100, this.noise010, @@ -773,8 +1277,45 @@ public class NoiseChunk implements DensityFunction.ContextProvider, DensityFunct this.noise011, this.noise111 ) - : this.value; + : this.value; + } + }; + if (!org.bxteam.divinemc.config.DivineConfig.PerformanceCategory.enableDensityFunctionCompiler || context instanceof NoiseChunk) { + return original.get(); } + if (context instanceof NoisePosVanillaInterface vif && vif.getType() == EvalType.INTERPOLATION) { + NoiseChunk field = NoiseChunk.this; + boolean isInInterpolationLoop = field.interpolating; + boolean isSamplingForCaches = field.fillingCell; + if (!isInInterpolationLoop) { + return original.get(); + } + int startBlockX = field.cellStartBlockX; + int startBlockY = field.cellStartBlockY; + int startBlockZ = field.cellStartBlockZ; + int horizontalCellBlockCount = field.cellWidth(); + int verticalCellBlockCount = field.cellHeight(); + int cellBlockX = context.blockX() - startBlockX; + int cellBlockY = context.blockY() - startBlockY; + int cellBlockZ = context.blockZ() - startBlockZ; + return isSamplingForCaches + ? Mth.lerp3( + (double)cellBlockX / (double)horizontalCellBlockCount, + (double)cellBlockY / (double)verticalCellBlockCount, + (double)cellBlockZ / (double)horizontalCellBlockCount, + this.noise000, + this.noise100, + this.noise010, + this.noise110, + this.noise001, + this.noise101, + this.noise011, + this.noise111 + ) : this.value; + } + + return original.get(); + // DivineMC end - Density Function Compiler } @Override diff --git a/net/minecraft/world/level/levelgen/RandomState.java b/net/minecraft/world/level/levelgen/RandomState.java index f1e089ecfffa40cd794c49db30fcedf138d3fee9..3d8bdd7e40c7457c0ad7729162b43cba2043b8b5 100644 --- a/net/minecraft/world/level/levelgen/RandomState.java +++ b/net/minecraft/world/level/levelgen/RandomState.java @@ -122,6 +122,41 @@ public final class RandomState { this.router.ridges().mapAll(visitor), settings.spawnTarget() ); + + // DivineMC start - Density Function Compiler + if (org.bxteam.divinemc.config.DivineConfig.PerformanceCategory.enableDensityFunctionCompiler) { + com.google.common.base.Stopwatch stopwatch = com.google.common.base.Stopwatch.createStarted(); + it.unimi.dsi.fastutil.objects.Reference2ReferenceMap tempCache = new it.unimi.dsi.fastutil.objects.Reference2ReferenceOpenHashMap<>(); + this.router = new NoiseRouter( + com.ishland.c2me.opts.dfc.common.gen.BytecodeGen.compile(this.router.barrierNoise(), tempCache), + com.ishland.c2me.opts.dfc.common.gen.BytecodeGen.compile(this.router.fluidLevelFloodednessNoise(), tempCache), + com.ishland.c2me.opts.dfc.common.gen.BytecodeGen.compile(this.router.fluidLevelSpreadNoise(), tempCache), + com.ishland.c2me.opts.dfc.common.gen.BytecodeGen.compile(this.router.lavaNoise(), tempCache), + com.ishland.c2me.opts.dfc.common.gen.BytecodeGen.compile(this.router.temperature(), tempCache), + com.ishland.c2me.opts.dfc.common.gen.BytecodeGen.compile(this.router.vegetation(), tempCache), + com.ishland.c2me.opts.dfc.common.gen.BytecodeGen.compile(this.router.continents(), tempCache), + com.ishland.c2me.opts.dfc.common.gen.BytecodeGen.compile(this.router.erosion(), tempCache), + com.ishland.c2me.opts.dfc.common.gen.BytecodeGen.compile(this.router.depth(), tempCache), + com.ishland.c2me.opts.dfc.common.gen.BytecodeGen.compile(this.router.ridges(), tempCache), + com.ishland.c2me.opts.dfc.common.gen.BytecodeGen.compile(this.router.initialDensityWithoutJaggedness(), tempCache), + com.ishland.c2me.opts.dfc.common.gen.BytecodeGen.compile(this.router.finalDensity(), tempCache), + com.ishland.c2me.opts.dfc.common.gen.BytecodeGen.compile(this.router.veinToggle(), tempCache), + com.ishland.c2me.opts.dfc.common.gen.BytecodeGen.compile(this.router.veinRidged(), tempCache), + com.ishland.c2me.opts.dfc.common.gen.BytecodeGen.compile(this.router.veinGap(), tempCache) + ); + this.sampler = new Climate.Sampler( + com.ishland.c2me.opts.dfc.common.gen.BytecodeGen.compile(this.sampler.temperature(), tempCache), + com.ishland.c2me.opts.dfc.common.gen.BytecodeGen.compile(this.sampler.humidity(), tempCache), + com.ishland.c2me.opts.dfc.common.gen.BytecodeGen.compile(this.sampler.continentalness(), tempCache), + com.ishland.c2me.opts.dfc.common.gen.BytecodeGen.compile(this.sampler.erosion(), tempCache), + com.ishland.c2me.opts.dfc.common.gen.BytecodeGen.compile(this.sampler.depth(), tempCache), + com.ishland.c2me.opts.dfc.common.gen.BytecodeGen.compile(this.sampler.weirdness(), tempCache), + this.sampler.spawnTarget() + ); + stopwatch.stop(); + System.out.printf("Density function compilation finished in %s%n", stopwatch); + } + // DivineMC end - Density Function Compiler } public NormalNoise getOrCreateNoise(ResourceKey resourceKey) {