Validated terrain samples

- Terrain sampling rejects non-finite active bounds and noise before caching heights
- Validation tests cover invalid samples and unchanged finite arithmetic
- Bukkit packaging uses the existing 8 MB artifact limit
This commit is contained in:
Brian Neumann-Fopiano committed 2026-09-05 12:31:36 -04:00
1 parent 965606bbcc
commit 5a5e8a8dc8
3 files changed
+54 -7

No files matched your search

@@ -1401,15 +1401,25 @@ public class IrisComplex implements DataProvider {
if (generators.length == 0) {
return 0D;
}
if (!Double.isFinite(low) || !Double.isFinite(high)) {
throw new IllegalStateException("Terrain generator bounds were not finite at " + x + "," + z
+ " (generator=" + generators[0].getLoadKey() + ", bounds=" + low + ".." + high + ").");
}
double height = 0D;
if (low == high && Double.isFinite(low)) {
if (low == high) {
for (int i = 0; i < generators.length; i++) {
height += low;
}
return height / generators.length;
}
for (IrisGenerator generator : generators) {
height += M.lerp(low, high, generator.getHeight(x, z, seed));
double noise = generator.getHeight(x, z, seed);
if (!Double.isFinite(noise)) {
throw new IllegalStateException("Terrain generator noise was not finite at " + x + "," + z
+ " (generator=" + generator.getLoadKey() + ", noise=" + noise
+ ", bounds=" + low + ".." + high + ").");
}
height += M.lerp(low, high, noise);
}
return height / generators.length;
}
@@ -7,6 +7,7 @@ import org.junit.Test;
import java.util.Arrays;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertThrows;
import static org.junit.Assert.assertTrue;
public class IrisComplexConstantGeneratorBoundsTest {
@@ -51,11 +52,10 @@ public class IrisComplexConstantGeneratorBoundsTest {
}
@Test
public void nonconstantAndNonfiniteBoundsRetainNoiseEvaluation() {
double[][] bounds = {{0D, 1D}, {-9D, 12D}, {Double.POSITIVE_INFINITY, Double.POSITIVE_INFINITY},
{Double.NEGATIVE_INFINITY, Double.NEGATIVE_INFINITY}, {Double.NaN, Double.NaN}};
public void nonconstantFiniteBoundsRetainNoiseEvaluation() {
double[][] bounds = {{0D, 1D}, {-9D, 12D}};
for (double[] pair : bounds) {
for (double noise : new double[]{0.3D, Double.NaN, Double.POSITIVE_INFINITY}) {
for (double noise : new double[]{0.3D, -2D, 3D}) {
CountingGenerator generator = new CountingGenerator(noise);
double expected = (0D + M.lerp(pair[0], pair[1], noise)) / 1;
assertBits(expected, IrisComplex.averageGeneratorHeights(new IrisGenerator[]{generator},
@@ -65,6 +65,43 @@ public class IrisComplexConstantGeneratorBoundsTest {
}
}
@Test
public void nonfiniteBoundsFailBeforeSamplingWithColumnAndGeneratorDetails() {
for (double invalid : new double[]{Double.NaN, Double.POSITIVE_INFINITY, Double.NEGATIVE_INFINITY}) {
for (double[] bounds : new double[][]{{invalid, 1D}, {0D, invalid}, {invalid, invalid}}) {
CountingGenerator generator = new CountingGenerator(0.3D);
generator.setLoadKey("diagnostic/terrain");
IllegalStateException failure = assertThrows(IllegalStateException.class,
() -> IrisComplex.averageGeneratorHeights(new IrisGenerator[]{generator},
bounds[0], bounds[1], 671D, 2437D, 7331L));
assertTrue(failure.getMessage().contains("671.0,2437.0"));
assertTrue(failure.getMessage().contains("generator=diagnostic/terrain"));
assertTrue(failure.getMessage().contains("bounds=" + bounds[0] + ".." + bounds[1]));
assertEquals(0, generator.calls);
}
}
}
@Test
public void nonfiniteActiveNoiseFailsAtItsFirstSampleWithObservedValue() {
for (double invalid : new double[]{Double.NaN, Double.POSITIVE_INFINITY, Double.NEGATIVE_INFINITY}) {
CountingGenerator valid = new CountingGenerator(0.3D);
CountingGenerator invalidGenerator = new CountingGenerator(invalid);
invalidGenerator.setLoadKey("diagnostic/cliffs");
CountingGenerator unsampled = new CountingGenerator(0.5D);
IllegalStateException failure = assertThrows(IllegalStateException.class,
() -> IrisComplex.averageGeneratorHeights(new IrisGenerator[]{valid, invalidGenerator, unsampled},
0D, 44D, 671D, 2437D, 7331L));
assertTrue(failure.getMessage().contains("671.0,2437.0"));
assertTrue(failure.getMessage().contains("generator=diagnostic/cliffs"));
assertTrue(failure.getMessage().contains("noise=" + invalid));
assertTrue(failure.getMessage().contains("bounds=0.0..44.0"));
assertEquals(1, valid.calls);
assertEquals(1, invalidGenerator.calls);
assertEquals(0, unsampled.calls);
}
}
private static void assertBits(double expected, double actual) {
assertEquals(Double.doubleToLongBits(expected), Double.doubleToLongBits(actual));
}