From e38f956d66270023e30b39832dcc47de25381679 Mon Sep 17 00:00:00 2001 From: Brian Neumann-Fopiano Date: Thu, 22 Oct 2026 07:19:57 -0400 Subject: [PATCH] Terminal carving roots - Roots without selectable children resolve to themselves before the per-column child cache - Selection plans build through one shared helper for root checks and child selection --- .../terrain/IrisDimensionCarvingResolver.java | 31 +++++++++++++------ ...risDimensionCarvingResolverParityTest.java | 26 ++++++++++++++++ 2 files changed, 47 insertions(+), 10 deletions(-) diff --git a/core/src/main/java/art/arcane/iris/generation/terrain/IrisDimensionCarvingResolver.java b/core/src/main/java/art/arcane/iris/generation/terrain/IrisDimensionCarvingResolver.java index b977e8614..979f8042e 100644 --- a/core/src/main/java/art/arcane/iris/generation/terrain/IrisDimensionCarvingResolver.java +++ b/core/src/main/java/art/arcane/iris/generation/terrain/IrisDimensionCarvingResolver.java @@ -120,7 +120,7 @@ public final class IrisDimensionCarvingResolver { } int remainingDepth = clampDepth(rootEntry.getChildRecursionDepth()); - if (remainingDepth <= 0) { + if (remainingDepth <= 0 || terminal(engine, data, rootEntry, rootBiome, resolvedState)) { return rootEntry; } @@ -131,13 +131,12 @@ public final class IrisDimensionCarvingResolver { return columns.entries[slot]; } - Map entryIndex = resolveEntryIndex(engine, resolvedState); IrisDimensionCarvingEntry current = rootEntry; int depth = remainingDepth; boolean cacheable = true; while (depth > 0) { cacheable &= fixedChildStyle(current); - IrisDimensionCarvingEntry selected = selectChild(engine, data, current, worldX, worldZ, entryIndex, resolvedState); + IrisDimensionCarvingEntry selected = selectChild(engine, data, current, worldX, worldZ, resolvedState); if (selected == null || selected == current || selected.getWorldYRange() != null && !selected.getWorldYRange().contains(worldY)) { break; @@ -164,6 +163,24 @@ public final class IrisDimensionCarvingResolver { return current; } + private static boolean terminal(Engine engine, IrisData data, IrisDimensionCarvingEntry entry, IrisBiome biome, State state) { + KList children = entry.getChildren(); + if (children == null || children.isEmpty()) { + return true; + } + return selectionPlan(engine, data, entry, biome, state).size() <= 1L; + } + + private static IrisRaritySelection selectionPlan(Engine engine, IrisData data, IrisDimensionCarvingEntry parent, + IrisBiome parentBiome, State state) { + IrisRaritySelection selectionPlan = state.selectionPlans.get(parent); + if (selectionPlan == null) { + selectionPlan = buildSelectionPlan(data, parent, parentBiome, resolveEntryIndex(engine, state), state); + state.selectionPlans.put(parent, selectionPlan); + } + return selectionPlan; + } + private static boolean fixedChildStyle(IrisDimensionCarvingEntry entry) { for (IrisGeneratorStyle style = entry.getChildStyle(); style != null; style = style.getFracture()) { if (style.getExpression() != null) { @@ -202,7 +219,6 @@ public final class IrisDimensionCarvingResolver { IrisDimensionCarvingEntry parent, int worldX, int worldZ, - Map entryIndex, State state ) { KList children = parent.getChildren(); @@ -215,12 +231,7 @@ public final class IrisDimensionCarvingResolver { return parent; } - IrisRaritySelection selectionPlan = state.selectionPlans.get(parent); - if (selectionPlan == null) { - selectionPlan = buildSelectionPlan(data, parent, parentBiome, entryIndex, state); - state.selectionPlans.put(parent, selectionPlan); - } - + IrisRaritySelection selectionPlan = selectionPlan(engine, data, parent, parentBiome, state); if (selectionPlan.size() <= 1L) { return parent; } diff --git a/core/src/test/java/art/arcane/iris/generation/terrain/IrisDimensionCarvingResolverParityTest.java b/core/src/test/java/art/arcane/iris/generation/terrain/IrisDimensionCarvingResolverParityTest.java index 2dbd4a142..28bff4309 100644 --- a/core/src/test/java/art/arcane/iris/generation/terrain/IrisDimensionCarvingResolverParityTest.java +++ b/core/src/test/java/art/arcane/iris/generation/terrain/IrisDimensionCarvingResolverParityTest.java @@ -166,6 +166,32 @@ public class IrisDimensionCarvingResolverParityTest { assertSame(child, IrisDimensionCarvingResolver.resolveFromRoot(fixture.engine, parent, 7, 0, 9, state)); } + @Test + public void rootsWithoutSelectableChildrenResolveToThemselvesWithoutSampling() { + for (List children : List.of(List.of(), List.of("missing-child"))) { + Fixture fixture = createFixture(); + IrisDimensionCarvingEntry parent = spy(fixture.engine.getDimension().getCarvingEntryIndex().get("root-low")); + parent.setChildRecursionDepth(3); + parent.setChildren(new KList<>(children)); + CNG generator = mock(CNG.class); + doReturn(0.5D).when(generator).noiseFast2D(anyDouble(), anyDouble()); + doReturn(generator).when(parent).getChildrenGenerator(anyLong(), any(IrisData.class)); + IrisDimensionCarvingResolver.State state = new IrisDimensionCarvingResolver.State(); + + for (int worldY = -80; worldY < 140; worldY += 13) { + for (int x = -20; x < 20; x += 3) { + for (int z = -20; z < 20; z += 7) { + assertSame(legacyResolveFromRoot(fixture.engine, parent, x, worldY, z), + IrisDimensionCarvingResolver.resolveFromRoot(fixture.engine, parent, x, worldY, z, state)); + assertSame(parent, IrisDimensionCarvingResolver.resolveFromRoot(fixture.engine, parent, x, worldY, z, state)); + } + } + } + + verify(generator, never()).noiseFast2D(anyDouble(), anyDouble()); + } + } + @Test public void repeatedColumnResolutionSamplesChildrenOnceAcrossHeights() { Fixture fixture = createFixture();