diff --git a/core/src/main/java/art/arcane/iris/generation/hydrology/underground/CavePoolFiller.java b/core/src/main/java/art/arcane/iris/generation/hydrology/underground/CavePoolFiller.java index d1bf23062..fb303b98c 100644 --- a/core/src/main/java/art/arcane/iris/generation/hydrology/underground/CavePoolFiller.java +++ b/core/src/main/java/art/arcane/iris/generation/hydrology/underground/CavePoolFiller.java @@ -10,6 +10,7 @@ import it.unimi.dsi.fastutil.longs.LongOpenHashSet; import java.util.Arrays; import java.util.Set; +import java.util.function.Supplier; public final class CavePoolFiller { public static final int REACH = HydrologySettings.MAX_CAVE_POOL_RADIUS + 1; @@ -40,15 +41,19 @@ public final class CavePoolFiller { this.density = settings.density(); } - public void fill(int chunkX, int chunkZ, CarvedTerrain carved, MantleWriter writer, long seed) { + public void fill(int chunkX, int chunkZ, Supplier terrain, MantleWriter writer, long seed) { if (!pools.enabled() || density == 0f) { return; } int attempts = attempts(seed, chunkX, chunkZ); + CarvedTerrain carved = null; for (int attempt = 0; attempt < attempts; attempt++) { if (density < 1f && CellHash.unit(CellHash.mix(seed, SALT_DENSITY + attempt, chunkX, chunkZ)) >= density) { continue; } + if (carved == null) { + carved = terrain.get(); + } long column = CellHash.mix(seed, SALT_COLUMN + attempt, chunkX, chunkZ); int x = (chunkX << 4) + (int) (column & 15); int z = (chunkZ << 4) + (int) ((column >>> 4) & 15); diff --git a/core/src/main/java/art/arcane/iris/generation/mantle/MantleHydrologyComponent.java b/core/src/main/java/art/arcane/iris/generation/mantle/MantleHydrologyComponent.java index 5c3397042..4ac0b4c3d 100644 --- a/core/src/main/java/art/arcane/iris/generation/mantle/MantleHydrologyComponent.java +++ b/core/src/main/java/art/arcane/iris/generation/mantle/MantleHydrologyComponent.java @@ -85,8 +85,9 @@ public final class MantleHydrologyComponent extends IrisMantleComponent { generateFalls(writer, complex, runtime, own, chunkX, chunkZ); if (poolsActive()) { HydrologySettings settings = runtime.settings(); - new CavePoolFiller(settings).fill(chunkX, chunkZ, - new MantleCarvedTerrain(writer, complex, getEngineMantle().getEngine(), chunkX, chunkZ), writer, settings.seed()); + Engine engine = getEngineMantle().getEngine(); + new CavePoolFiller(settings).fill(chunkX, chunkZ, () -> new MantleCarvedTerrain(writer, complex, engine, chunkX, chunkZ), writer, + settings.seed()); } } diff --git a/core/src/test/java/art/arcane/iris/generation/hydrology/underground/CavePoolFillerTest.java b/core/src/test/java/art/arcane/iris/generation/hydrology/underground/CavePoolFillerTest.java index 2d6b4cc30..860215a9a 100644 --- a/core/src/test/java/art/arcane/iris/generation/hydrology/underground/CavePoolFillerTest.java +++ b/core/src/test/java/art/arcane/iris/generation/hydrology/underground/CavePoolFillerTest.java @@ -15,6 +15,7 @@ import java.util.HashMap; import java.util.HashSet; import java.util.Map; import java.util.Set; +import java.util.concurrent.atomic.AtomicInteger; import java.util.function.Consumer; import java.util.function.IntFunction; @@ -50,18 +51,37 @@ public class CavePoolFillerTest { return 0; }); for (int chunkX = 0; chunkX < 1024; chunkX++) { - filler.fill(chunkX, 0, carved, writer, SEED); + filler.fill(chunkX, 0, () -> carved, writer, SEED); } assertTrue("half density samples approximately half the candidate columns", columns.size() > 3600 && columns.size() < 4500); Set repeated = new HashSet<>(columns); columns.clear(); for (int chunkX = 1023; chunkX >= 0; chunkX--) { - filler.fill(chunkX, 0, carved, writer, SEED); + filler.fill(chunkX, 0, () -> carved, writer, SEED); } assertEquals(repeated, columns); verifyNoInteractions(writer); } + @Test + public void chunksWithoutAPoolSiteNeverOpenTheirCaves() { + IrisHydrology config = new IrisHydrology().setDensity(0.5D); + config.getUnderground().getCavePools().setDensity(0.05D); + CavePoolFiller filler = new CavePoolFiller(HydrologySettings.compile(config, SEED, 63, 0, 384)); + CarvedTerrain carved = mock(CarvedTerrain.class); + MantleWriter writer = mock(MantleWriter.class); + AtomicInteger opened = new AtomicInteger(); + int chunks = 1024; + for (int chunkX = 0; chunkX < chunks; chunkX++) { + filler.fill(chunkX, 0, () -> { + opened.incrementAndGet(); + return carved; + }, writer, SEED); + } + assertTrue("only chunks drawing a pool site open their caves, opened " + opened.get(), opened.get() > 0 && opened.get() < chunks / 8); + verifyNoInteractions(writer); + } + @Test public void zeroGlobalDensityDoesNotReadCaves() { IrisHydrology config = new IrisHydrology().setDensity(0D); @@ -69,7 +89,7 @@ public class CavePoolFillerTest { CavePoolFiller filler = new CavePoolFiller(HydrologySettings.compile(config, SEED, 63, 0, 384)); CarvedTerrain carved = mock(CarvedTerrain.class); MantleWriter writer = mock(MantleWriter.class); - filler.fill(0, 0, carved, writer, SEED); + filler.fill(0, 0, () -> carved, writer, SEED); verifyNoInteractions(carved, writer); } @@ -143,10 +163,10 @@ public class CavePoolFillerTest { MantleWriter forwardWriter = writer(forward); MantleWriter reverseWriter = writer(reverse); for (int index = 0; index < 9; index++) { - new CavePoolFiller(settings).fill(index % 3 - 1, index / 3 - 1, world, forwardWriter, SEED); + new CavePoolFiller(settings).fill(index % 3 - 1, index / 3 - 1, () -> world, forwardWriter, SEED); } for (int index = 8; index >= 0; index--) { - new CavePoolFiller(settings).fill(index % 3 - 1, index / 3 - 1, world, reverseWriter, SEED); + new CavePoolFiller(settings).fill(index % 3 - 1, index / 3 - 1, () -> world, reverseWriter, SEED); } assertFalse(forward.isEmpty()); @@ -284,7 +304,7 @@ public class CavePoolFillerTest { private static Map fill(HydrologySettings settings, VoxelWorld world, int chunkX, int chunkZ) { Map written = new HashMap<>(); - new CavePoolFiller(settings).fill(chunkX, chunkZ, world, writer(written), SEED); + new CavePoolFiller(settings).fill(chunkX, chunkZ, () -> world, writer(written), SEED); return written; } diff --git a/core/src/test/java/art/arcane/iris/generation/mantle/MantleCarvedTerrainTest.java b/core/src/test/java/art/arcane/iris/generation/mantle/MantleCarvedTerrainTest.java index 22603f411..de5db777c 100644 --- a/core/src/test/java/art/arcane/iris/generation/mantle/MantleCarvedTerrainTest.java +++ b/core/src/test/java/art/arcane/iris/generation/mantle/MantleCarvedTerrainTest.java @@ -324,7 +324,7 @@ public class MantleCarvedTerrainTest { for (SeaInlet inlet : complex.getHydrologyRuntime().inlets(0, chunkZ)) { rasterizer.write(inlet, 0, chunkZ, writer, HydrologyCaveCell.SEA_FLUID, "", SeaInletRasterizer.SubterrainFluid.NOWHERE); } - new CavePoolFiller(settings).fill(0, chunkZ, new MantleCarvedTerrain(writer, complex, engine, 0, chunkZ), writer, SEED); + new CavePoolFiller(settings).fill(0, chunkZ, () -> new MantleCarvedTerrain(writer, complex, engine, 0, chunkZ), writer, SEED); } return cells; }