diff --git a/core/src/main/java/art/arcane/iris/generation/runtime/IrisComplex.java b/core/src/main/java/art/arcane/iris/generation/runtime/IrisComplex.java index e983da85b..0b8255c20 100644 --- a/core/src/main/java/art/arcane/iris/generation/runtime/IrisComplex.java +++ b/core/src/main/java/art/arcane/iris/generation/runtime/IrisComplex.java @@ -1896,14 +1896,24 @@ public class IrisComplex implements DataProvider { } int grid = biomeBoundsSamplingStep; - if (!ChunkCorners.supports(grid)) { + GridBoundsCache cache = gridBoundsCache.get(); + if (!ChunkCorners.supports(grid) || cache.cornersInUse) { for (int interpolatorIndex = 0; interpolatorIndex < frozenInterpolators.length; interpolatorIndex++) { h += interpolateGenerators(engine, frozenInterpolators[interpolatorIndex], interpolatorIndex, frozenGenerators[interpolatorIndex], x, z, seed); } return h; } - GridBoundsCache cache = gridBoundsCache.get(); + cache.cornersInUse = true; + try { + return cornerBlockHeight(cache, engine, grid, x, z, seed); + } finally { + cache.cornersInUse = false; + } + } + + private double cornerBlockHeight(GridBoundsCache cache, Engine engine, int grid, double x, double z, long seed) { + double h = 0; int xi = (int) Math.floor(x); int zi = (int) Math.floor(z); int gx = xi & ~(grid - 1); @@ -2343,6 +2353,7 @@ public class IrisComplex implements DataProvider { private final BoundsSampler sampler = new BoundsSampler(); private ChunkCorners recentCorners; private ChunkCorners previousCorners; + private boolean cornersInUse; private ChunkCorners chunkCorners(int chunkX, int chunkZ, int groups, int grid) { ChunkCorners recent = recentCorners; diff --git a/core/src/test/java/art/arcane/iris/generation/runtime/IrisComplexChunkCornersTest.java b/core/src/test/java/art/arcane/iris/generation/runtime/IrisComplexChunkCornersTest.java index 6149c12ca..090046995 100644 --- a/core/src/test/java/art/arcane/iris/generation/runtime/IrisComplexChunkCornersTest.java +++ b/core/src/test/java/art/arcane/iris/generation/runtime/IrisComplexChunkCornersTest.java @@ -88,6 +88,24 @@ public class IrisComplexChunkCornersTest { assertEquals(40, counting.calls); } + @Test + public void nestedHeightSamplesLeaveTheOuterChunkBlockIntact() throws Exception { + ReentrantGenerator reentrant = new ReentrantGenerator(); + IrisInterpolator[] interpolators = {new ZeroFreeInterpolator(), new PatchInterpolator(4, -2D)}; + IrisGenerator[][] generators = {{reentrant}, {new WaveGenerator(0.5D)}}; + IrisComplex candidate = createComplex(4, interpolators, generators); + IrisComplex reference = createComplex(4, interpolators, generators); + SplittableRandom random = new SplittableRandom(99L); + for (int sample = 0; sample < 4_000; sample++) { + double x = coordinate(random); + double z = coordinate(random); + reentrant.target = reference; + double expected = expectedHeight(reference, interpolators, generators, x, z); + reentrant.target = candidate; + assertEquals(Double.doubleToRawLongBits(expected), Double.doubleToRawLongBits(interpolatedHeight(candidate, x, z))); + } + } + @Test public void nonFiniteCornersFailTheSameWayAndAreRetried() throws Exception { NaNCornerInterpolator interpolator = new NaNCornerInterpolator(); @@ -191,6 +209,13 @@ public class IrisComplexChunkCornersTest { } } + private static final class ZeroFreeInterpolator extends IrisInterpolator { + @Override + public NoiseBounds interpolateBounds(double x, double z, NoiseBoundsProvider provider) { + return new NoiseBounds(x * 0.01D - 1D, z * 0.01D + 3D); + } + } + private static final class ZeroInterpolator extends IrisInterpolator { private final boolean negative; @@ -227,6 +252,26 @@ public class IrisComplexChunkCornersTest { } } + private static final class ReentrantGenerator extends IrisGenerator { + private IrisComplex target; + private boolean nested; + + @Override + public double getHeight(double x, double z, long seed) { + if (nested) { + return Math.cos(x * 0.13D) * 0.5D; + } + nested = true; + try { + return (interpolatedHeight(target, x + 4099D, z - 2053D) + interpolatedHeight(target, x - 8191D, z + 1031D)) * 0.001D; + } catch (Exception e) { + throw new IllegalStateException(e); + } finally { + nested = false; + } + } + } + private static final class WaveGenerator extends IrisGenerator { private final double amplitude; private int invocations;