9
0
mirror of https://github.com/BX-Team/DivineMC.git synced 2025-12-19 14:59:25 +00:00
Files
DivineMC/divinemc-server/minecraft-patches/features/0046-C2ME-Density-Function-Compiler.patch
NONPLAYT d9c4e8a199 Updated Upstream (Purpur)
Upstream has released updates that appear to apply and compile correctly

Purpur Changes:
PurpurMC/Purpur@efc76215 Add missing copper blocks to waxables and weatherables options (#1712)
PurpurMC/Purpur@3ca0d663 Updated Upstream (Paper)
PurpurMC/Purpur@917675d0 Updated Upstream (Paper)
PurpurMC/Purpur@ffe2f809 Add option to disable Warden Sonic Boom (#1713)
2025-10-28 03:51:29 +03:00

1198 lines
58 KiB
Diff

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 e4e1ecdfd28a1c6d0fd518668caed33a8ec45ec3..929820fcab17b1b804759c5e9fa36606e3add72c 100644
--- a/net/minecraft/util/CubicSpline.java
+++ b/net/minecraft/util/CubicSpline.java
@@ -254,31 +254,47 @@ public interface CubicSpline<C, I extends BoundedFloatFunction<C>> extends Bound
@Override
public float apply(C value) {
- float f = this.coordinate.apply(value);
- 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(value), this.derivatives, 0);
- } else if (i == i1) {
- return linearExtend(f, this.locations, this.values.get(i1).apply(value), this.derivatives, i1);
+ // DivineMC start - Density Function Compiler
+ float point = this.coordinate.apply(value);
+ 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(value), this.derivatives, 0);
+ } else if (rangeForLocation == last) {
+ return linearExtend(point, this.locations, this.values.get(last).apply(value), this.derivatives, last);
} else {
- float f1 = this.locations[i];
- float f2 = this.locations[i + 1];
- float f3 = (f - f1) / (f2 - f1);
- BoundedFloatFunction<C> boundedFloatFunction = (BoundedFloatFunction<C>)this.values.get(i);
- BoundedFloatFunction<C> boundedFloatFunction1 = (BoundedFloatFunction<C>)this.values.get(i + 1);
- float f4 = this.derivatives[i];
- float f5 = this.derivatives[i + 1];
- float f6 = boundedFloatFunction.apply(value);
- float f7 = boundedFloatFunction1.apply(value);
- 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(value);
+ float o = this.values.get(rangeForLocation + 1).apply(value);
+ 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<C, I extends BoundedFloatFunction<C>> 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 73412c5b89b38f90a4c941acb3ce6f13e026c303..40d7965d95b78c6046b0da33f290eaeadd99c9b5 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<Object, Boolean> 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<Integer> 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 39efa4329e7517fe0ec47d1e1975fc0d4ec5727c..a743c142b152ad696506dca7b04462d2af3c6893 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<Climate.ParameterPoint> 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 noiseFiller) {
this.noiseFiller = noiseFiller;
@@ -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<Double> 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<Double> 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 noiseFiller) {
this.noiseFiller = noiseFiller;
@@ -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<Double> 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..f0f28f433523e0ee9379af5b70cffe8f8c87da5d 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<DensityFunction, DensityFunction> 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.preliminarySurfaceLevel(), 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<NormalNoise.NoiseParameters> resourceKey) {