diff --git a/core/src/main/java/art/arcane/iris/generation/mantle/CaveTerrainSnapshot.java b/core/src/main/java/art/arcane/iris/generation/mantle/CaveTerrainSnapshot.java index af11616bc..a447c328c 100644 --- a/core/src/main/java/art/arcane/iris/generation/mantle/CaveTerrainSnapshot.java +++ b/core/src/main/java/art/arcane/iris/generation/mantle/CaveTerrainSnapshot.java @@ -17,8 +17,9 @@ import java.util.function.IntFunction; /** * The terrain view of one mantle chunk's cavern and hydrology cells (journaled pre-object values win), * copied once under the chunk monitor. Terrain components finish before any content write reaches a - * chunk and every later write journals the value it replaces, so this view never goes stale while the - * chunk generates. + * chunk and every mantle-writer write journals the value it replaces, so the view holds while the chunk + * generates; the raw writers that run after sCave (dimension stack clearing, continuation restore) drop + * it from the chunk context instead. */ public final class CaveTerrainSnapshot { private static final int SECTION_VOLUME = 4096; diff --git a/core/src/main/java/art/arcane/iris/generation/runtime/EngineMode.java b/core/src/main/java/art/arcane/iris/generation/runtime/EngineMode.java index 5c5c9bda4..768c68dea 100644 --- a/core/src/main/java/art/arcane/iris/generation/runtime/EngineMode.java +++ b/core/src/main/java/art/arcane/iris/generation/runtime/EngineMode.java @@ -218,6 +218,9 @@ public interface EngineMode extends Staged { IrisDimensionStackActuator.clearHostNaturalMetadata(getEngine(), x, z, biomes.getHeight(), ctx); ctx.beginContent(); List continuations = restoreObjectContinuations(x, z); + if (!continuations.isEmpty()) { + ctx.setCaveTerrain(null); + } for (EngineStage i : stages) { i.generate(x, z, blocks, biomes, multicore, ctx); } diff --git a/core/src/main/java/art/arcane/iris/generation/stage/IrisDimensionStackActuator.java b/core/src/main/java/art/arcane/iris/generation/stage/IrisDimensionStackActuator.java index 041a2af5d..a3813bac2 100644 --- a/core/src/main/java/art/arcane/iris/generation/stage/IrisDimensionStackActuator.java +++ b/core/src/main/java/art/arcane/iris/generation/stage/IrisDimensionStackActuator.java @@ -110,6 +110,7 @@ public final class IrisDimensionStackActuator extends EngineAssignedActuator> 4, z >> 4)) { return; } + context.setCaveTerrain(null); MantleChunk chunk = engine.getMantle().getMantle().getChunk(x >> 4, z >> 4).use(); try { synchronized (chunk) { diff --git a/core/src/test/java/art/arcane/iris/generation/stage/IrisNaturalCaveScanTest.java b/core/src/test/java/art/arcane/iris/generation/stage/IrisNaturalCaveScanTest.java index 128eb48ff..59045f346 100644 --- a/core/src/test/java/art/arcane/iris/generation/stage/IrisNaturalCaveScanTest.java +++ b/core/src/test/java/art/arcane/iris/generation/stage/IrisNaturalCaveScanTest.java @@ -5,6 +5,7 @@ import art.arcane.iris.generation.decoration.IrisCeilingDecorator; import art.arcane.iris.generation.decoration.IrisSurfaceDecorator; import art.arcane.iris.generation.runtime.Engine; import art.arcane.iris.generation.runtime.SeedManager; +import art.arcane.iris.generation.context.ChunkContext; import art.arcane.iris.generation.mantle.CaveTerrainSnapshot; import art.arcane.iris.generation.mantle.EngineMantle; import art.arcane.iris.generation.biome.IrisBiome; @@ -33,6 +34,7 @@ import java.util.ArrayList; import java.util.List; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertSame; import static org.junit.Assert.assertThrows; import static org.junit.Assert.assertTrue; @@ -42,10 +44,12 @@ import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.ArgumentMatchers.argThat; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.CALLS_REAL_METHODS; +import static org.mockito.Mockito.clearInvocations; import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.mockStatic; +import static org.mockito.Mockito.never; import static org.mockito.Mockito.verify; public class IrisNaturalCaveScanTest { @@ -72,6 +76,26 @@ public class IrisNaturalCaveScanTest { verifyScan(16, 16); } + @Test + public void decorationReusesOnlyTheCarveSnapshotOfItsOwnChunk() throws Exception { + Fixture fixture = new Fixture(); + ChunkContext context = mock(ChunkContext.class); + doReturn(CaveTerrainSnapshot.capture(fixture.chunk, -2, 3)).when(context).getCaveTerrain(); + clearInvocations(fixture.chunk); + fixture.modifier.decorateNaturalCaves(-32, 48, fixture.output(3, 2), context); + verify(fixture.chunk, never()).use(); + verify(context).setCaveTerrain(null); + assertFalse(fixture.calls.isEmpty()); + + Fixture other = new Fixture(); + ChunkContext stale = mock(ChunkContext.class); + doReturn(CaveTerrainSnapshot.capture(other.chunk, 5, 5)).when(stale).getCaveTerrain(); + clearInvocations(other.chunk); + other.modifier.decorateNaturalCaves(-32, 48, other.output(3, 2), stale); + verify(other.chunk).use(); + assertEquals(fixture.calls, other.calls); + } + @Test public void listenerFailureReleasesMantleChunk() throws Exception { Fixture fixture = new Fixture();