This commit is contained in:
Brian Neumann-Fopiano committed 2026-07-03 15:10:16 -04:00
1 parent 75e8c22268
commit a8e46e3590
104 files changed
+6002 -2692

No files matched your search

@@ -0,0 +1,70 @@
package art.arcane.iris.core.pregenerator.cache;
import org.junit.Before;
import org.junit.Test;
import java.io.File;
import java.nio.file.Files;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
public class PregenCacheImplPersistenceTest {
private File directory;
@Before
public void setUp() throws Exception {
directory = Files.createTempDirectory("iris-pregen-cache-persist").toFile();
}
@Test
public void partialRegionChunkPersistsAcrossReload() {
PregenCache cache = PregenCache.create(directory);
cache.cacheChunk(5, 7);
cache.write();
PregenCache reloaded = PregenCache.create(directory);
assertTrue(reloaded.isChunkCached(5, 7));
assertFalse(reloaded.isChunkCached(5, 8));
assertFalse(reloaded.isRegionCached(0, 0));
}
@Test
public void partialRegionNegativeCoordinatesPersistAcrossReload() {
PregenCache cache = PregenCache.create(directory);
cache.cacheChunk(-3, -1);
cache.write();
PregenCache reloaded = PregenCache.create(directory);
assertTrue(reloaded.isChunkCached(-3, -1));
assertFalse(reloaded.isChunkCached(-3, -2));
}
@Test
public void fullRegionPersistsAcrossReload() {
PregenCache cache = PregenCache.create(directory);
cache.cacheRegion(2, 3);
cache.write();
PregenCache reloaded = PregenCache.create(directory);
assertTrue(reloaded.isRegionCached(2, 3));
assertTrue(reloaded.isChunkCached((2 << 5) + 11, (3 << 5) + 19));
assertFalse(reloaded.isRegionCached(2, 4));
}
@Test
public void regionCompletedChunkByChunkPersistsAsRegion() {
PregenCache cache = PregenCache.create(directory);
for (int x = 0; x < 32; x++) {
for (int z = 0; z < 32; z++) {
cache.cacheChunk(x, z);
}
}
cache.write();
PregenCache reloaded = PregenCache.create(directory);
assertTrue(reloaded.isRegionCached(0, 0));
assertTrue(reloaded.isChunkCached(31, 31));
assertFalse(reloaded.isChunkCached(32, 0));
}
}
@@ -0,0 +1,213 @@
package art.arcane.iris.core.pregenerator.methods;
import art.arcane.iris.core.pregenerator.PregenListener;
import art.arcane.iris.core.pregenerator.PregenTask;
import art.arcane.iris.core.pregenerator.PregeneratorMethod;
import art.arcane.iris.core.pregenerator.cache.PregenCache;
import art.arcane.volmlib.util.mantle.runtime.Mantle;
import art.arcane.volmlib.util.math.Position2;
import org.junit.Before;
import org.junit.Test;
import java.io.File;
import java.nio.file.Files;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicReference;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
public class CachedPregenMethodCompletionTest {
private File directory;
private PregenCache cache;
private CapturingMethod underlying;
private PregenTask task;
private CachedPregenMethod method;
private RecordingListener listener;
@Before
public void setUp() throws Exception {
directory = Files.createTempDirectory("iris-pregen-cache-test").toFile();
cache = PregenCache.create(directory);
underlying = new CapturingMethod();
task = PregenTask.builder()
.center(new Position2(0, 0))
.radiusX(256)
.radiusZ(256)
.build();
method = new CachedPregenMethod(underlying, cache, task);
listener = new RecordingListener();
}
@Test
public void generateChunkDoesNotCacheOnSubmitOnlyOnCompletion() {
method.generateChunk(3, 4, listener);
assertEquals(1, underlying.generateChunkCalls.get());
assertFalse(cache.isChunkCached(3, 4));
underlying.capturedListener.get().onChunkGenerated(3, 4, false);
assertTrue(cache.isChunkCached(3, 4));
assertEquals(1, listener.generated.get());
}
@Test
public void generateChunkFailureIsNotCached() {
method.generateChunk(6, 9, listener);
underlying.capturedListener.get().onChunkFailed(6, 9);
assertFalse(cache.isChunkCached(6, 9));
assertEquals(0, listener.generated.get());
assertEquals(1, listener.failed.get());
}
@Test
public void generateChunkSkipsUnderlyingMethodWhenCached() {
method.generateChunk(1, 2, listener);
underlying.capturedListener.get().onChunkGenerated(1, 2, false);
assertEquals(1, underlying.generateChunkCalls.get());
method.generateChunk(1, 2, listener);
assertEquals(1, underlying.generateChunkCalls.get());
assertEquals(2, listener.generated.get());
assertEquals(1, listener.generatedCached.get());
}
@Test
public void generateRegionReplayRespectsTaskBounds() {
cache.cacheRegion(0, 0);
List<long[]> expected = new ArrayList<>();
task.iterateChunks(0, 0, (x, z) -> expected.add(new long[]{x, z}));
assertTrue(expected.size() < 1024);
method.generateRegion(0, 0, listener);
assertEquals(0, underlying.generateRegionCalls.get());
assertEquals(expected.size(), listener.generated.get());
assertEquals(expected.size(), listener.generatedCached.get());
}
private static final class CapturingMethod implements PregeneratorMethod {
private final AtomicInteger generateChunkCalls = new AtomicInteger();
private final AtomicInteger generateRegionCalls = new AtomicInteger();
private final AtomicReference<PregenListener> capturedListener = new AtomicReference<>();
@Override
public void init() {
}
@Override
public void close() {
}
@Override
public void save() {
}
@Override
public boolean supportsRegions(int x, int z, PregenListener listener) {
return false;
}
@Override
public String getMethod(int x, int z) {
return "capture";
}
@Override
public void generateRegion(int x, int z, PregenListener listener) {
generateRegionCalls.incrementAndGet();
}
@Override
public void generateChunk(int x, int z, PregenListener listener) {
generateChunkCalls.incrementAndGet();
capturedListener.set(listener);
}
@Override
public Mantle getMantle() {
return null;
}
}
private static final class RecordingListener implements PregenListener {
private final AtomicInteger generated = new AtomicInteger();
private final AtomicInteger generatedCached = new AtomicInteger();
private final AtomicInteger failed = new AtomicInteger();
@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) {
generated.incrementAndGet();
if (cached) {
generatedCached.incrementAndGet();
}
}
@Override
public void onChunkFailed(int x, int z) {
failed.incrementAndGet();
}
@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) {
}
}
}
@@ -0,0 +1,214 @@
package art.arcane.iris.core.runtime;
import art.arcane.iris.core.IrisSettings;
import art.arcane.iris.engine.framework.Engine;
import art.arcane.iris.engine.object.IrisDimension;
import art.arcane.iris.spi.PlatformBiome;
import art.arcane.iris.spi.PlatformBlockState;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import java.io.File;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.security.MessageDigest;
import java.util.ArrayList;
import java.util.HexFormat;
import java.util.List;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
public class GoldenHashEngineTest {
private static final int MIN_Y = 0;
private static final int MAX_Y = 8;
private IrisSettings previousSettings;
private File goldenDir;
private Engine engine;
private PlatformBlockState stone;
private PlatformBlockState dirt;
private PlatformBiome plains;
@Before
public void setUp() throws Exception {
previousSettings = IrisSettings.settings;
IrisSettings.settings = new IrisSettings();
goldenDir = Files.createTempDirectory("iris-goldenhash-test").toFile();
engine = mock(Engine.class);
IrisDimension dimension = mock(IrisDimension.class);
when(dimension.getLoadKey()).thenReturn("testdim");
when(engine.getDimension()).thenReturn(dimension);
stone = mock(PlatformBlockState.class);
when(stone.key()).thenReturn("minecraft:stone");
dirt = mock(PlatformBlockState.class);
when(dirt.key()).thenReturn("minecraft:dirt");
plains = mock(PlatformBiome.class);
when(plains.key()).thenReturn("minecraft:plains");
}
@After
public void tearDown() {
IrisSettings.settings = previousSettings;
}
@Test
public void capturePersistsGoldenFileWithStableFormat() throws Exception {
RecordingFeedback feedback = new RecordingFeedback();
GoldenHashEngine hashEngine = new GoldenHashEngine(engine, request(GoldenHashEngine.Mode.AUTO), goldenDir, source(dirt, 3, 2, 1), feedback, progress());
assertTrue(hashEngine.run());
File goldenFile = new File(goldenDir, "testdim-s1234-c0x0-r0.hashes");
assertTrue(goldenFile.exists());
List<String> lines = Files.readAllLines(goldenFile.toPath(), StandardCharsets.UTF_8);
assertEquals("#iris-goldenhash v1", lines.get(0));
assertEquals("#world=testworld", lines.get(1));
assertEquals("#dim=testdim", lines.get(2));
assertEquals("#seed=1234", lines.get(3));
assertEquals("#mc=test-1.0", lines.get(4));
assertEquals("#minY=0 maxY=8", lines.get(5));
assertEquals("#center=0,0", lines.get(6));
assertEquals("#radius=0", lines.get(7));
String expectedBody = referenceLine(0, 0, 3, 2, 1);
assertEquals(expectedBody, lines.get(8));
assertEquals("#combined=" + referenceCombined(expectedBody), lines.get(9));
}
@Test
public void verifyMatchesGoldenCapture() {
RecordingFeedback captureFeedback = new RecordingFeedback();
GoldenHashEngine capture = new GoldenHashEngine(engine, request(GoldenHashEngine.Mode.AUTO), goldenDir, source(dirt, 3, 2, 1), captureFeedback, progress());
assertTrue(capture.run());
RecordingFeedback verifyFeedback = new RecordingFeedback();
GoldenHashEngine verify = new GoldenHashEngine(engine, request(GoldenHashEngine.Mode.AUTO), goldenDir, source(dirt, 3, 2, 1), verifyFeedback, progress());
assertTrue(verify.run());
assertTrue(verifyFeedback.ok.stream().anyMatch((String line) -> line.startsWith("GOLDEN MATCH: 1/1")));
assertTrue(verifyFeedback.fail.isEmpty());
}
@Test
public void verifyFlagsMismatchAndWritesDiagnostics() {
RecordingFeedback captureFeedback = new RecordingFeedback();
GoldenHashEngine capture = new GoldenHashEngine(engine, request(GoldenHashEngine.Mode.AUTO), goldenDir, source(dirt, 3, 2, 1), captureFeedback, progress());
assertTrue(capture.run());
RecordingFeedback verifyFeedback = new RecordingFeedback();
GoldenHashEngine verify = new GoldenHashEngine(engine, request(GoldenHashEngine.Mode.VERIFY), goldenDir, source(dirt, 7, 4, 9), verifyFeedback, progress());
assertFalse(verify.run());
assertTrue(verifyFeedback.fail.stream().anyMatch((String line) -> line.startsWith("GOLDEN MISMATCH: 1/1")));
File goldenFile = new File(goldenDir, "testdim-s1234-c0x0-r0.hashes");
assertTrue(new File(goldenDir, goldenFile.getName() + ".new").exists());
assertTrue(new File(goldenDir, goldenFile.getName() + ".diag-c0x0.txt").exists());
}
@Test
public void verifyModeWithoutCaptureFails() {
RecordingFeedback feedback = new RecordingFeedback();
GoldenHashEngine verify = new GoldenHashEngine(engine, request(GoldenHashEngine.Mode.VERIFY), goldenDir, source(dirt, 3, 2, 1), feedback, progress());
assertFalse(verify.run());
assertTrue(feedback.fail.stream().anyMatch((String line) -> line.startsWith("No golden capture at ")));
}
@Test
public void abortsWithoutWritingWhenChunkGenerationFails() {
RecordingFeedback feedback = new RecordingFeedback();
GoldenHashEngine.ChunkSource broken = (int chunkX, int chunkZ) -> {
throw new IllegalStateException("boom");
};
GoldenHashEngine hashEngine = new GoldenHashEngine(engine, request(GoldenHashEngine.Mode.AUTO), goldenDir, broken, feedback, progress());
assertFalse(hashEngine.run());
assertFalse(new File(goldenDir, "testdim-s1234-c0x0-r0.hashes").exists());
assertTrue(feedback.fail.stream().anyMatch((String line) -> line.startsWith("GoldenHash aborted: 1 chunk(s)")));
}
private GoldenHashEngine.Request request(GoldenHashEngine.Mode mode) {
return new GoldenHashEngine.Request("testworld", 1234L, "test-1.0", MIN_Y, MAX_Y, 0, 0, 0, 1, mode, false, false, "null");
}
private GoldenHashEngine.Progress progress() {
return new GoldenHashEngine.Progress() {
};
}
private GoldenHashEngine.ChunkSource source(PlatformBlockState special, int sx, int sy, int sz) {
return (int chunkX, int chunkZ) -> new GoldenHashEngine.ChunkSnapshot() {
@Override
public int minY() {
return MIN_Y;
}
@Override
public int maxY() {
return MAX_Y;
}
@Override
public PlatformBlockState block(int x, int y, int z) {
return x == sx && y == sy && z == sz ? special : stone;
}
@Override
public PlatformBiome biome(int x, int y, int z) {
return plains;
}
};
}
private String referenceLine(int chunkX, int chunkZ, int sx, int sy, int sz) throws Exception {
MessageDigest blockDigest = MessageDigest.getInstance("SHA-256");
MessageDigest biomeDigest = MessageDigest.getInstance("SHA-256");
for (int x = 0; x < 16; x++) {
for (int z = 0; z < 16; z++) {
for (int y = MIN_Y; y < MAX_Y; y++) {
String key = x == sx && y == sy && z == sz ? "minecraft:dirt" : "minecraft:stone";
blockDigest.update((key + "\n").getBytes(StandardCharsets.UTF_8));
}
}
}
for (int x = 0; x < 16; x += 4) {
for (int z = 0; z < 16; z += 4) {
for (int y = MIN_Y; y < MAX_Y; y += 4) {
biomeDigest.update("minecraft:plains\n".getBytes(StandardCharsets.UTF_8));
}
}
}
return chunkX + " " + chunkZ + " "
+ HexFormat.of().formatHex(blockDigest.digest()) + " "
+ HexFormat.of().formatHex(biomeDigest.digest());
}
private String referenceCombined(String bodyLine) throws Exception {
MessageDigest digest = MessageDigest.getInstance("SHA-256");
digest.update((bodyLine + "\n").getBytes(StandardCharsets.UTF_8));
return HexFormat.of().formatHex(digest.digest());
}
private static final class RecordingFeedback implements GoldenHashEngine.Feedback {
private final List<String> ok = new ArrayList<>();
private final List<String> warn = new ArrayList<>();
private final List<String> fail = new ArrayList<>();
@Override
public void ok(String message) {
ok.add(message);
}
@Override
public void warn(String message) {
warn.add(message);
}
@Override
public void fail(String message) {
fail.add(message);
}
}
}
@@ -0,0 +1,55 @@
package art.arcane.iris.util.common.math;
import org.junit.Test;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;
public class ChunkSpiralTest {
@Test
public void centerOutMatchesLegacyOrdering() {
int centerX = 5;
int centerZ = -3;
int radius = 3;
List<int[]> expected = legacyOrderedTargets(centerX, centerZ, radius);
List<int[]> actual = ChunkSpiral.centerOut(centerX, centerZ, radius);
assertEquals(expected.size(), actual.size());
for (int i = 0; i < expected.size(); i++) {
assertArrayEquals(expected.get(i), actual.get(i));
}
}
@Test
public void centerOutStartsAtCenterAndCoversSquare() {
List<int[]> targets = ChunkSpiral.centerOut(10, 20, 2);
assertEquals(25, targets.size());
assertArrayEquals(new int[]{10, 20}, targets.get(0));
}
@Test
public void centerOutRadiusZeroIsSingleChunk() {
List<int[]> targets = ChunkSpiral.centerOut(-7, 9, 0);
assertEquals(1, targets.size());
assertArrayEquals(new int[]{-7, 9}, targets.get(0));
}
private static List<int[]> legacyOrderedTargets(int centerChunkX, int centerChunkZ, int radius) {
List<int[]> targets = new ArrayList<>();
for (int dx = -radius; dx <= radius; dx++) {
for (int dz = -radius; dz <= radius; dz++) {
targets.add(new int[]{centerChunkX + dx, centerChunkZ + dz});
}
}
targets.sort(Comparator.comparingInt((int[] t) -> {
int ox = t[0] - centerChunkX;
int oz = t[1] - centerChunkZ;
return ox * ox + oz * oz;
}));
return targets;
}
}
@@ -0,0 +1,120 @@
package art.arcane.iris.util.simd;
import art.arcane.iris.util.project.noise.FastNoiseDouble;
import art.arcane.iris.util.project.noise.FastNoiseDouble.FractalType;
import art.arcane.iris.util.project.noise.FastNoiseDouble.NoiseType;
import art.arcane.volmlib.util.math.RNG;
import org.junit.Test;
import static org.junit.Assert.assertEquals;
public class NoiseKernels2DParityTest {
private static FastNoiseDouble oracle(long seed, int octaves) {
FastNoiseDouble n = new FastNoiseDouble(seed);
n.setNoiseType(NoiseType.SimplexFractal);
n.setFractalType(FractalType.FBM);
n.setFractalOctaves(octaves);
return n;
}
private static void assertKernelMatchesOracle(NoiseKernels2D kernel) {
RNG rng = new RNG(99L);
for (int octaves = 1; octaves <= 8; octaves++) {
FastNoiseDouble n = oracle(1337L + octaves, octaves);
int length = 256;
double[] xs = new double[length];
double[] zs = new double[length];
double[] expected = new double[length];
double[] out = new double[length];
for (int k = 0; k < length; k++) {
double x = (rng.nextDouble() - 0.5D) * 1_000_000D;
double z = (rng.nextDouble() - 0.5D) * 1_000_000D;
xs[k] = x;
zs[k] = z;
expected[k] = n.GetSimplexFractal(x, z);
}
kernel.simplexFractalFBM(1337L + octaves, octaves, n.getFrequency(), 2.0D, 0.5D, n.getFractalBounding(), xs, zs, out, length);
for (int k = 0; k < length; k++) {
assertEquals("octaves=" + octaves + " idx=" + k, expected[k], out[k], 0D);
}
}
}
@Test
public void scalarKernelIsBitExactToOracle() {
assertKernelMatchesOracle(new ScalarNoiseKernels2D());
}
@Test
public void vectorKernelSingleOctaveIsBitExactToOracle() {
org.junit.Assume.assumeTrue(VectorNoiseKernels2D.lanesAligned());
FastNoiseDouble n = oracle(202020L, 1);
RNG rng = new RNG(7L);
int length = 333;
double[] xs = new double[length];
double[] zs = new double[length];
double[] expected = new double[length];
double[] out = new double[length];
for (int k = 0; k < length; k++) {
double x = (rng.nextDouble() - 0.5D) * 800_000D;
double z = (rng.nextDouble() - 0.5D) * 800_000D;
xs[k] = x;
zs[k] = z;
expected[k] = n.GetSimplexFractal(x, z);
}
new VectorNoiseKernels2D().simplexFractalFBM(202020L, 1, n.getFrequency(), 2.0D, 0.5D, n.getFractalBounding(), xs, zs, out, length);
for (int k = 0; k < length; k++) {
assertEquals("idx=" + k, expected[k], out[k], 0D);
}
}
@Test
public void vectorKernelAllOctavesAreBitExactToOracle() {
org.junit.Assume.assumeTrue(VectorNoiseKernels2D.lanesAligned());
assertKernelMatchesOracle(new VectorNoiseKernels2D());
}
@Test
public void simdSupportReturnsBitExactNoiseKernel() {
NoiseKernels2D kernel = SimdSupport.noiseKernels2D();
org.junit.Assert.assertNotNull(kernel);
assertKernelMatchesOracle(kernel);
}
@Test
public void simdSupportNeverSelectsVectorBelowProfitableLanes() {
if (VectorNoiseKernels2D.profitable()) {
org.junit.Assert.assertTrue(SimdSupport.createVectorNoiseKernels2D() instanceof VectorNoiseKernels2D);
} else {
org.junit.Assert.assertTrue(SimdSupport.noiseKernels2D() instanceof ScalarNoiseKernels2D);
}
}
@Test
public void vectorMatchesScalarAcrossEdgeCases() {
org.junit.Assume.assumeTrue(VectorNoiseKernels2D.lanesAligned());
NoiseKernels2D scalar = new ScalarNoiseKernels2D();
NoiseKernels2D vector = new VectorNoiseKernels2D();
RNG rng = new RNG(31337L);
int[] lengths = {1, 3, 7, 8, 9, 255, 256, 257};
double[] edgeCoords = {-4.0D, -3.0D, -1.0D, -0.0D, 0.0D, 1.0D, 4.0D, 1_000_000.0D, -1_000_000.0D};
for (int octaves = 1; octaves <= 8; octaves++) {
for (int length : lengths) {
double[] xs = new double[length];
double[] zs = new double[length];
double[] a = new double[length];
double[] b = new double[length];
for (int k = 0; k < length; k++) {
boolean edge = (k % 3) == 0;
xs[k] = edge ? edgeCoords[k % edgeCoords.length] : (rng.nextDouble() - 0.5D) * 2_000_000D;
zs[k] = edge ? edgeCoords[(k + 1) % edgeCoords.length] : (rng.nextDouble() - 0.5D) * 2_000_000D;
}
scalar.simplexFractalFBM(77L, octaves, 0.01D, 2.0D, 0.5D, 0.6667D, xs, zs, a, length);
vector.simplexFractalFBM(77L, octaves, 0.01D, 2.0D, 0.5D, 0.6667D, xs, zs, b, length);
for (int k = 0; k < length; k++) {
assertEquals("oct=" + octaves + " len=" + length + " idx=" + k, a[k], b[k], 0D);
}
}
}
}
}