Opti pass 1

This commit is contained in:
Brian Neumann-Fopiano
2026-04-15 12:50:12 -04:00
parent 9a231b2bcf
commit dcb3306197
43 changed files with 1832 additions and 410 deletions
@@ -0,0 +1,141 @@
package art.arcane.iris.core.pregenerator;
import art.arcane.iris.core.IrisSettings;
import art.arcane.volmlib.util.mantle.runtime.Mantle;
import art.arcane.volmlib.util.math.Position2;
import org.junit.Test;
import java.lang.reflect.Method;
import java.util.concurrent.atomic.AtomicInteger;
import static org.junit.Assert.assertEquals;
public class IrisPregeneratorInitTest {
@Test
public void initDoesNotSaveBeforeGenerationStarts() throws Exception {
IrisSettings previousSettings = IrisSettings.settings;
IrisSettings.settings = new IrisSettings();
TrackingPregeneratorMethod method = new TrackingPregeneratorMethod();
PregenTask task = PregenTask.builder()
.center(new Position2(0, 0))
.radiusX(16)
.radiusZ(16)
.build();
try {
IrisPregenerator pregenerator = new IrisPregenerator(task, method, new NoOpPregenListener());
Method initMethod = IrisPregenerator.class.getDeclaredMethod("init");
initMethod.setAccessible(true);
initMethod.invoke(pregenerator);
assertEquals(1, method.initCalls.get());
assertEquals(0, method.saveCalls.get());
} finally {
IrisSettings.settings = previousSettings;
}
}
private static final class TrackingPregeneratorMethod implements PregeneratorMethod {
private final AtomicInteger initCalls = new AtomicInteger();
private final AtomicInteger saveCalls = new AtomicInteger();
@Override
public void init() {
initCalls.incrementAndGet();
}
@Override
public void close() {
}
@Override
public void save() {
saveCalls.incrementAndGet();
}
@Override
public boolean supportsRegions(int x, int z, PregenListener listener) {
return false;
}
@Override
public String getMethod(int x, int z) {
return "test";
}
@Override
public void generateRegion(int x, int z, PregenListener listener) {
}
@Override
public void generateChunk(int x, int z, PregenListener listener) {
}
@Override
public Mantle getMantle() {
return null;
}
}
private static final class NoOpPregenListener implements PregenListener {
@Override
public void onTick(double chunksPerSecond, double chunksPerMinute, double regionsPerMinute, double percent, long generated, long totalChunks, long chunksRemaining, long eta, long elapsed, String method, boolean cached) {
}
@Override
public void onChunkGenerating(int x, int z) {
}
@Override
public void onChunkGenerated(int x, int z, boolean cached) {
}
@Override
public void onRegionGenerated(int x, int z) {
}
@Override
public void onRegionGenerating(int x, int z) {
}
@Override
public void onChunkCleaned(int x, int z) {
}
@Override
public void onRegionSkipped(int x, int z) {
}
@Override
public void onNetworkStarted(int x, int z) {
}
@Override
public void onNetworkFailed(int x, int z) {
}
@Override
public void onNetworkReclaim(int revert) {
}
@Override
public void onNetworkGeneratedChunk(int x, int z) {
}
@Override
public void onNetworkDownloaded(int x, int z) {
}
@Override
public void onClose() {
}
@Override
public void onSaving() {
}
@Override
public void onChunkExistsInRegionGen(int x, int z) {
}
}
}
@@ -29,4 +29,16 @@ public class AsyncPregenMethodConcurrencyCapTest {
assertEquals(16, AsyncPregenMethod.applyRuntimeConcurrencyCap(256, false, 8));
assertEquals(20, AsyncPregenMethod.applyRuntimeConcurrencyCap(20, false, 40));
}
@Test
public void paperLikeConcurrencyUsesChunkWorkerPoolWhenAvailable() {
assertEquals(4, AsyncPregenMethod.resolvePaperLikeConcurrencyWorkerThreads(4, 16, 32));
assertEquals(24, AsyncPregenMethod.resolvePaperLikeConcurrencyWorkerThreads(-1, 16, 24));
}
@Test
public void foliaConcurrencyStillUsesBroaderRuntimeCapacity() {
assertEquals(32, AsyncPregenMethod.resolveFoliaConcurrencyWorkerThreads(4, 16, 32));
assertEquals(16, AsyncPregenMethod.resolveFoliaConcurrencyWorkerThreads(-1, 16, 12));
}
}
@@ -0,0 +1,24 @@
package art.arcane.iris.core.service;
import org.junit.Test;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
public class IrisEngineSVCTest {
@Test
public void maintenanceSkipsReductionWhenPregenDoesNotTargetWorld() {
assertTrue(IrisEngineSVC.shouldSkipMantleReductionForMaintenance(true, false));
}
@Test
public void maintenanceDoesNotSkipReductionForActivePregenWorld() {
assertFalse(IrisEngineSVC.shouldSkipMantleReductionForMaintenance(true, true));
}
@Test
public void noMaintenanceNeverSkipsReduction() {
assertFalse(IrisEngineSVC.shouldSkipMantleReductionForMaintenance(false, false));
assertFalse(IrisEngineSVC.shouldSkipMantleReductionForMaintenance(false, true));
}
}
@@ -0,0 +1,67 @@
package art.arcane.iris.engine.object;
import art.arcane.iris.util.project.interpolation.InterpolationMethod3D;
import art.arcane.iris.util.project.interpolation.IrisInterpolation;
import art.arcane.iris.util.project.noise.HexJamesNoise;
import art.arcane.iris.util.project.noise.HexRandomSizeNoise;
import art.arcane.volmlib.util.collection.KList;
import art.arcane.volmlib.util.function.NoiseProvider3;
import art.arcane.volmlib.util.math.RNG;
import org.junit.Test;
import static org.junit.Assert.assertEquals;
public class IrisMathNoiseHotPathParityTest {
@Test
public void hexNoiseSamplesRemainBitExact() {
HexRandomSizeNoise randomSize = new HexRandomSizeNoise(12345L);
HexJamesNoise james = new HexJamesNoise(54321L);
assertEquals(0.4670864519829246D, randomSize.noise(12.5D, -8.25D), 0D);
assertEquals(0.4935590260372404D, randomSize.noise(-31.75D, 44.5D, 9.125D), 0D);
assertEquals(0.5185375921658786D, james.noise(12.5D, -8.25D), 0D);
assertEquals(0.4557738681128938D, james.noise(-31.75D, 44.5D, 9.125D), 0D);
}
@Test
public void generatorNoiseSamplesRemainBitExact() {
IrisNoiseGenerator noiseGenerator = new IrisNoiseGenerator()
.setZoom(7.25D)
.setOffsetX(1.75D)
.setOffsetZ(-3.5D)
.setOpacity(0.82D)
.setStyle(NoiseStyle.PERLIN_IRIS.style())
.setExponent(1.15D);
assertEquals(0.3886291844359823D, noiseGenerator.getNoise(9988L, 31.25D, -17.5D, null), 0D);
IrisGeneratorStyle style = NoiseStyle.IRIS_DOUBLE.style();
assertEquals(0.8640377573263068D, style.createNoCache(new RNG(112233L), null).noiseFast2D(42.5D, -19.75D), 0D);
IrisGenerator generator = new IrisGenerator()
.setZoom(9.5D)
.setOpacity(0.91D)
.setComposite(new KList<IrisNoiseGenerator>().qadd(noiseGenerator));
assertEquals(0.451949817597527D, generator.getHeight(63.0D, -27.0D, 445566L), 0D);
}
@Test
public void interpolationSamplesRemainBitExact() {
NoiseProvider3 provider = (x, y, z) -> {
double angle = (x * 0.017D) + (y * 0.011D) + (z * 0.023D);
return 0.5D + (Math.sin(angle) * 0.25D);
};
assertEquals(
0.5231950552025616D,
IrisInterpolation.getNoise3D(InterpolationMethod3D.TRILINEAR, 5, 7, -3, 2.5D, 3.5D, 4.5D, provider),
0D
);
assertEquals(
0.5259208842929466D,
IrisInterpolation.getNoise3D(InterpolationMethod3D.TRICUBIC, 5, 7, -3, 2.5D, 3.5D, 4.5D, provider),
0D
);
}
}
@@ -27,6 +27,16 @@ public class CNGFastPathParityTest {
}
}
@Test
public void signedFastPathMatchesLegacyAcrossRepresentativeGenerators() {
for (long seed = 31L; seed <= 35L; seed++) {
List<CNG> generators = createSignedGenerators(seed);
for (int index = 0; index < generators.size(); index++) {
assertSignedFastPathParity("signed-seed-" + seed + "-case-" + index, generators.get(index));
}
}
}
private void assertFastPathParity(String label, CNG generator) {
for (int x = -320; x <= 320; x += 19) {
for (int z = -320; z <= 320; z += 23) {
@@ -47,6 +57,26 @@ public class CNGFastPathParityTest {
}
}
private void assertSignedFastPathParity(String label, CNG generator) {
for (int x = -320; x <= 320; x += 19) {
for (int z = -320; z <= 320; z += 23) {
double expected = (generator.noiseFast2D(x, z) * 2D) - 1D;
double actual = generator.noiseFastSigned2D(x, z);
assertEquals(label + " signed-2D x=" + x + " z=" + z, expected, actual, 1.0E-12D);
}
}
for (int x = -128; x <= 128; x += 17) {
for (int y = -96; y <= 96; y += 13) {
for (int z = -128; z <= 128; z += 19) {
double expected = (generator.noiseFast3D(x, y, z) * 2D) - 1D;
double actual = generator.noiseFastSigned3D(x, y, z);
assertEquals(label + " signed-3D x=" + x + " y=" + y + " z=" + z, expected, actual, 1.0E-12D);
}
}
}
}
private CNG createIdentityGenerator(long seed) {
DeterministicNoiseGenerator generator = new DeterministicNoiseGenerator(0.31D + (seed * 0.01D));
return new CNG(new RNG(seed), generator, 1D, 1).bake();
@@ -72,6 +102,24 @@ public class CNGFastPathParityTest {
return generators;
}
private List<CNG> createSignedGenerators(long seed) {
List<CNG> generators = new ArrayList<>();
generators.add(new CNG(new RNG(seed), new SimplexNoise(seed + 100L), 1D, 1).bake());
generators.add(new CNG(new RNG(seed + 1L), new FractalFBMSimplexNoise(seed + 101L), 1D, 1).bake());
generators.add(new CNG(new RNG(seed + 2L), new VascularNoise(seed + 102L), 1D, 1).bake());
generators.add(new CNG(new RNG(seed + 3L), new OffsetNoiseGenerator(new SimplexNoise(seed + 103L), seed + 104L), 1D, 1).bake());
generators.add(new CNG(new RNG(seed + 4L), new OffsetNoiseGenerator(new PerlinNoise(seed + 107L), seed + 108L), 1D, 1).bake());
generators.add(new CNG(new RNG(seed + 5L), new OffsetNoiseGenerator(new VascularNoise(seed + 109L), seed + 110L), 1D, 1).bake());
generators.add(new CNG(new RNG(seed + 6L), new OffsetNoiseGenerator(new FractalFBMSimplexNoise(seed + 111L), seed + 112L), 1D, 1).bake());
CNG fractured = new CNG(new RNG(seed + 7L), new OffsetNoiseGenerator(new FractalFBMSimplexNoise(seed + 105L), seed + 106L), 1D, 1).bake();
fractured.fractureWith(createIdentityGenerator(seed + 500L), 9.5D);
generators.add(fractured);
return generators;
}
private static class DeterministicNoiseGenerator implements NoiseGenerator {
private final double offset;
@@ -0,0 +1,183 @@
package art.arcane.iris.util.project.noise;
import org.junit.Test;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import static org.junit.Assert.assertEquals;
public class FastNoiseDoubleCellularParityTest {
private static final FastNoiseDouble.CellularDistanceFunction[] DISTANCE_FUNCTIONS = new FastNoiseDouble.CellularDistanceFunction[]{
FastNoiseDouble.CellularDistanceFunction.Euclidean,
FastNoiseDouble.CellularDistanceFunction.Manhattan,
FastNoiseDouble.CellularDistanceFunction.Natural
};
private static final FastNoiseDouble.CellularReturnType[] TWO_EDGE_RETURN_TYPES = new FastNoiseDouble.CellularReturnType[]{
FastNoiseDouble.CellularReturnType.Distance2,
FastNoiseDouble.CellularReturnType.Distance2Add,
FastNoiseDouble.CellularReturnType.Distance2Sub,
FastNoiseDouble.CellularReturnType.Distance2Mul,
FastNoiseDouble.CellularReturnType.Distance2Div
};
private static final Method HASH_2D = getDeclaredMethod("hash2D", long.class, long.class, long.class);
private static final Method HASH_3D = getDeclaredMethod("hash3D", long.class, long.class, long.class, long.class);
private static final double[] CELL_2D_X = getDeclaredDoubleArray("CELL_2D_X");
private static final double[] CELL_2D_Y = getDeclaredDoubleArray("CELL_2D_Y");
private static final double[] CELL_3D_X = getDeclaredDoubleArray("CELL_3D_X");
private static final double[] CELL_3D_Y = getDeclaredDoubleArray("CELL_3D_Y");
private static final double[] CELL_3D_Z = getDeclaredDoubleArray("CELL_3D_Z");
@Test
public void cellular2DTwoEdgeModesMatchLegacyUpdateLogic() throws Exception {
for (long seed = 11L; seed <= 17L; seed++) {
double frequency = 0.037D + (seed * 0.001D);
for (FastNoiseDouble.CellularDistanceFunction distanceFunction : DISTANCE_FUNCTIONS) {
for (FastNoiseDouble.CellularReturnType returnType : TWO_EDGE_RETURN_TYPES) {
FastNoiseDouble noise = new FastNoiseDouble(seed);
noise.setFrequency(frequency);
noise.setCellularDistanceFunction(distanceFunction);
noise.setCellularReturnType(returnType);
for (int x = -96; x <= 96; x += 11) {
for (int y = -96; y <= 96; y += 13) {
double sampleX = x + 0.37D;
double sampleY = y - 0.41D;
double expected = legacyGetCellular2D(seed, frequency, distanceFunction, returnType, sampleX, sampleY);
double actual = noise.GetCellular(sampleX, sampleY);
assertEquals("2D seed=" + seed + " distance=" + distanceFunction + " return=" + returnType + " x=" + sampleX + " y=" + sampleY, expected, actual, 0D);
}
}
}
}
}
}
@Test
public void cellular3DTwoEdgeModesMatchLegacyUpdateLogic() throws Exception {
for (long seed = 31L; seed <= 35L; seed++) {
double frequency = 0.029D + (seed * 0.001D);
for (FastNoiseDouble.CellularDistanceFunction distanceFunction : DISTANCE_FUNCTIONS) {
for (FastNoiseDouble.CellularReturnType returnType : TWO_EDGE_RETURN_TYPES) {
FastNoiseDouble noise = new FastNoiseDouble(seed);
noise.setFrequency(frequency);
noise.setCellularDistanceFunction(distanceFunction);
noise.setCellularReturnType(returnType);
for (int x = -48; x <= 48; x += 9) {
for (int y = -32; y <= 32; y += 7) {
for (int z = -48; z <= 48; z += 11) {
double sampleX = x + 0.19D;
double sampleY = y - 0.27D;
double sampleZ = z + 0.43D;
double expected = legacyGetCellular3D(seed, frequency, distanceFunction, returnType, sampleX, sampleY, sampleZ);
double actual = noise.GetCellular(sampleX, sampleY, sampleZ);
assertEquals("3D seed=" + seed + " distance=" + distanceFunction + " return=" + returnType + " x=" + sampleX + " y=" + sampleY + " z=" + sampleZ, expected, actual, 0D);
}
}
}
}
}
}
}
private double legacyGetCellular2D(long seed, double frequency, FastNoiseDouble.CellularDistanceFunction distanceFunction, FastNoiseDouble.CellularReturnType returnType, double x, double y) throws Exception {
double scaledX = x * frequency;
double scaledY = y * frequency;
long xr = fastRound(scaledX);
long yr = fastRound(scaledY);
double distance = 999999D;
double distance2 = 999999D;
for (long xi = xr - 1; xi <= xr + 1; xi++) {
for (long yi = yr - 1; yi <= yr + 1; yi++) {
int cellIndex = (int) hash2D(seed, xi, yi) & 255;
double vecX = xi - scaledX + CELL_2D_X[cellIndex];
double vecY = yi - scaledY + CELL_2D_Y[cellIndex];
double newDistance = switch (distanceFunction) {
case Euclidean -> vecX * vecX + vecY * vecY;
case Manhattan -> Math.abs(vecX) + Math.abs(vecY);
case Natural -> (Math.abs(vecX) + Math.abs(vecY)) + (vecX * vecX + vecY * vecY);
};
distance2 = Math.max(Math.min(distance2, newDistance), distance);
distance = Math.min(distance, newDistance);
}
}
return applyTwoEdgeReturn(distance, distance2, returnType);
}
private double legacyGetCellular3D(long seed, double frequency, FastNoiseDouble.CellularDistanceFunction distanceFunction, FastNoiseDouble.CellularReturnType returnType, double x, double y, double z) throws Exception {
double scaledX = x * frequency;
double scaledY = y * frequency;
double scaledZ = z * frequency;
long xr = fastRound(scaledX);
long yr = fastRound(scaledY);
long zr = fastRound(scaledZ);
double distance = 999999D;
double distance2 = 999999D;
for (long xi = xr - 1; xi <= xr + 1; xi++) {
for (long yi = yr - 1; yi <= yr + 1; yi++) {
for (long zi = zr - 1; zi <= zr + 1; zi++) {
int cellIndex = (int) hash3D(seed, xi, yi, zi) & 255;
double vecX = xi - scaledX + CELL_3D_X[cellIndex];
double vecY = yi - scaledY + CELL_3D_Y[cellIndex];
double vecZ = zi - scaledZ + CELL_3D_Z[cellIndex];
double newDistance = switch (distanceFunction) {
case Euclidean -> vecX * vecX + vecY * vecY + vecZ * vecZ;
case Manhattan -> Math.abs(vecX) + Math.abs(vecY) + Math.abs(vecZ);
case Natural -> (Math.abs(vecX) + Math.abs(vecY) + Math.abs(vecZ)) + (vecX * vecX + vecY * vecY + vecZ * vecZ);
};
distance2 = Math.max(Math.min(distance2, newDistance), distance);
distance = Math.min(distance, newDistance);
}
}
}
return applyTwoEdgeReturn(distance, distance2, returnType);
}
private double applyTwoEdgeReturn(double distance, double distance2, FastNoiseDouble.CellularReturnType returnType) {
return switch (returnType) {
case Distance2 -> distance2 - 1D;
case Distance2Add -> distance2 + distance - 1D;
case Distance2Sub -> distance2 - distance - 1D;
case Distance2Mul -> distance2 * distance - 1D;
case Distance2Div -> distance / distance2 - 1D;
default -> 0D;
};
}
private static long fastRound(double value) {
return value >= 0D ? (long) (value + 0.5D) : (long) (value - 0.5D);
}
private static long hash2D(long seed, long x, long y) throws Exception {
Long value = (Long) HASH_2D.invoke(null, seed, x, y);
return value.longValue();
}
private static long hash3D(long seed, long x, long y, long z) throws Exception {
Long value = (Long) HASH_3D.invoke(null, seed, x, y, z);
return value.longValue();
}
private static Method getDeclaredMethod(String name, Class<?>... parameterTypes) {
try {
Method method = FastNoiseDouble.class.getDeclaredMethod(name, parameterTypes);
method.setAccessible(true);
return method;
} catch (ReflectiveOperationException e) {
throw new IllegalStateException(e);
}
}
private static double[] getDeclaredDoubleArray(String name) {
try {
Field field = FastNoiseDouble.class.getDeclaredField(name);
field.setAccessible(true);
return (double[]) field.get(null);
} catch (ReflectiveOperationException e) {
throw new IllegalStateException(e);
}
}
}