From d9c5d00be38314a781dff0802d6ff925af0e3b1a Mon Sep 17 00:00:00 2001 From: Brian Neumann-Fopiano Date: Thu, 22 Oct 2026 07:28:44 -0400 Subject: [PATCH] Perfection and ore lookups - Perfection memoizes solid and spike flags per block state identity - Terrain painting resolves the ore chance engine once per chunk --- .../generation/decoration/IrisOreBands.java | 5 +- .../decoration/IrisOreGenerator.java | 11 +- .../stage/IrisPerfectionModifier.java | 167 +++++++++++------- .../stage/IrisTerrainNormalActuator.java | 14 +- .../decoration/IrisOreBandsTest.java | 10 +- 5 files changed, 127 insertions(+), 80 deletions(-) diff --git a/core/src/main/java/art/arcane/iris/generation/decoration/IrisOreBands.java b/core/src/main/java/art/arcane/iris/generation/decoration/IrisOreBands.java index a15ab4ca2..875e60ea2 100644 --- a/core/src/main/java/art/arcane/iris/generation/decoration/IrisOreBands.java +++ b/core/src/main/java/art/arcane/iris/generation/decoration/IrisOreBands.java @@ -1,5 +1,6 @@ package art.arcane.iris.generation.decoration; +import art.arcane.iris.generation.runtime.Engine; import art.arcane.iris.pack.loading.IrisData; import art.arcane.iris.pack.value.IrisRange; import art.arcane.volmlib.nativelib.terrain.NativeBlockState; @@ -94,10 +95,10 @@ public final class IrisOreBands { /** * The ore placed at a Y inside {@link #contains(int)}, or null when no generator places one. */ - public NativeBlockState generate(int x, int y, int z, RNG rng, IrisData data) { + public NativeBlockState generate(int x, int y, int z, RNG rng, IrisData data, Engine engine) { IrisOreGenerator[] candidates = byY == null ? generators : byY[y - minY]; for (IrisOreGenerator candidate : candidates) { - NativeBlockState ore = candidate.generate(x, y, z, rng, data); + NativeBlockState ore = candidate.generate(x, y, z, rng, data, engine); if (ore != null) { return ore; } diff --git a/core/src/main/java/art/arcane/iris/generation/decoration/IrisOreGenerator.java b/core/src/main/java/art/arcane/iris/generation/decoration/IrisOreGenerator.java index b5eeff86f..3c78c4c82 100644 --- a/core/src/main/java/art/arcane/iris/generation/decoration/IrisOreGenerator.java +++ b/core/src/main/java/art/arcane/iris/generation/decoration/IrisOreGenerator.java @@ -65,6 +65,10 @@ public class IrisOreGenerator { } public NativeBlockState generate(int x, int y, int z, RNG rng, IrisData data) { + return generate(x, y, z, rng, data, data == null ? null : data.getEngine()); + } + + public NativeBlockState generate(int x, int y, int z, RNG rng, IrisData data, Engine engine) { if (threshold <= 0 || !range.contains(y)) { return null; } @@ -73,7 +77,7 @@ public class IrisOreGenerator { return null; } - if (chance(rng, data).sample(x, y, z) > threshold) { + if (chance(rng, data, engine).sample(x, y, z) > threshold) { return null; } @@ -81,8 +85,11 @@ public class IrisOreGenerator { } private OreChance chance(RNG rng, IrisData data) { + return chance(rng, data, data == null ? null : data.getEngine()); + } + + private OreChance chance(RNG rng, IrisData data, Engine engine) { long seed = rng.getSeed(); - Engine engine = data == null ? null : data.getEngine(); CachedChance recent = recentChance; if (recent != null && recent.key.seed == seed && recent.key.data == data && recent.key.engine == engine) { return recent.chance; diff --git a/core/src/main/java/art/arcane/iris/generation/stage/IrisPerfectionModifier.java b/core/src/main/java/art/arcane/iris/generation/stage/IrisPerfectionModifier.java index 5fc49d92e..9cf870cc3 100644 --- a/core/src/main/java/art/arcane/iris/generation/stage/IrisPerfectionModifier.java +++ b/core/src/main/java/art/arcane/iris/generation/stage/IrisPerfectionModifier.java @@ -38,6 +38,7 @@ import it.unimi.dsi.fastutil.ints.IntArrayList; public class IrisPerfectionModifier extends EngineAssignedModifier { private static final int SOLID = 1; private static final int SPIKE = 2; + private static final int SLICE_TASKS = 16; private static final BoundBlockState AIR = BoundBlockState.of("AIR"); private static final BoundBlockState WATER = BoundBlockState.of("WATER"); private static final Map ORE_BASES = buildOreBases(); @@ -87,70 +88,94 @@ public class IrisPerfectionModifier extends EngineAssignedModifier perfectSlice(output, columnX)); + for (int task = 0; task < tasks; task++) { + int firstSlice = task * slicesPerTask; + burst.queue(() -> perfectSlices(output, firstSlice, firstSlice + slicesPerTask)); } burst.complete(); getEngine().getMetrics().getPerfection().put(p.getMilliseconds()); } - private void perfectSlice(Hunk output, int x) { + private void perfectSlices(Hunk output, int firstSlice, int lastSlice) { IntArrayList surfaces = new IntArrayList(); - StateClasses classes = new StateClasses(); - for (int z = 0; z < 16; z++) { - boolean changed; - do { - surfaces.clear(); - int top = getHeight(output, x, z, classes); - boolean inside = true; - surfaces.add(top); - for (int y = top; y >= 0; y--) { - NativeBlockState block = output.get(x, y, z); - int flags = classes.of(block); - if ((flags & SPIKE) != 0) { - block = normalizeSpike(block, output, x, z, y, AIR.get(), WATER.get()); - flags = classes.of(block); - } - boolean now = (flags & SOLID) != 0; - if (now != inside) { - inside = now; - if (inside) { - surfaces.add(y); - } - } - } - changed = false; - for (int index = 0; index < surfaces.size(); index++) { - int y = surfaces.getInt(index); - NativeBlockState tip = output.get(x, y, z); - if (!B.isDecorant(tip)) { - continue; - } - NativeBlockState below = output.get(x, y - 1, z); - boolean remove = below == null || !B.canPlaceOnto(tip, below); - boolean removeBelow = false; - if (!remove && IrisProceduralBlocks.hasProperty(below, "half")) { - NativeBlockState support = output.get(x, y - 2, z); - if (support == null || !B.canPlaceOnto(below, support)) { - remove = true; - removeBelow = true; - } - } - if (remove) { - changed = true; - output.set(x, y, z, AIR.get()); - if (removeBelow) { - output.set(x, y - 1, z, AIR.get()); - } - } - } - } while (changed); + StateFlags states = new StateFlags(); + NativeBlockState air = AIR.get(); + NativeBlockState water = WATER.get(); + for (int x = firstSlice; x < lastSlice; x++) { + for (int z = 0; z < 16; z++) { + perfectColumn(output, x, z, surfaces, states, air, water); + } } } + private static void perfectColumn(Hunk output, int x, int z, IntArrayList surfaces, + StateFlags states, NativeBlockState air, NativeBlockState water) { + do { + surfaces.clear(); + int top = getHeight(output, x, z, states); + boolean inside = true; + surfaces.add(top); + NativeBlockState classified = null; + int classifiedFlags = 0; + for (int y = top; y >= 0; y--) { + NativeBlockState block = output.get(x, y, z); + int flags = 0; + if (block != null) { + if (block != classified) { + classified = block; + classifiedFlags = states.of(block); + } + flags = classifiedFlags; + if ((flags & SPIKE) != 0) { + block = normalizeSpike(block, output, x, z, y, air, water); + flags = block == null ? 0 : states.of(block); + } + } + boolean now = (flags & SOLID) != 0; + if (now != inside) { + inside = now; + if (inside) { + surfaces.add(y); + } + } + } + } while (removeUnsupportedDecorants(output, x, z, surfaces, air)); + } + + private static boolean removeUnsupportedDecorants(Hunk output, int x, int z, + IntArrayList surfaces, NativeBlockState air) { + boolean changed = false; + for (int index = 0; index < surfaces.size(); index++) { + int y = surfaces.getInt(index); + NativeBlockState tip = output.get(x, y, z); + if (!B.isDecorant(tip)) { + continue; + } + NativeBlockState below = output.get(x, y - 1, z); + boolean remove = below == null || !B.canPlaceOnto(tip, below); + boolean removeBelow = false; + if (!remove && IrisProceduralBlocks.hasProperty(below, "half")) { + NativeBlockState support = output.get(x, y - 2, z); + if (support == null || !B.canPlaceOnto(below, support)) { + remove = true; + removeBelow = true; + } + } + if (remove) { + changed = true; + output.set(x, y, z, air); + if (removeBelow) { + output.set(x, y - 1, z, air); + } + } + } + return changed; + } + static NativeBlockState normalizeSpike(NativeBlockState state, Hunk output, int x, int z, int y, NativeBlockState air, NativeBlockState water) { if (IrisSpeleothems.isSupported(state, output, x, z, y)) { @@ -208,9 +233,19 @@ public class IrisPerfectionModifier extends EngineAssignedModifier output, int x, int z, StateClasses classes) { + private static int getHeight(Hunk output, int x, int z, StateFlags states) { + NativeBlockState classified = null; + int classifiedFlags = 0; for (int i = Math.min(output.getHeight() - 1, ColumnExtent.highestStoredY(output, x, z)); i >= 0; i--) { - if ((classes.of(output.get(x, i, z)) & SOLID) != 0) { + NativeBlockState state = output.get(x, i, z); + if (state == null) { + continue; + } + if (state != classified) { + classified = state; + classifiedFlags = states.of(state); + } + if ((classifiedFlags & SOLID) != 0) { return i; } } @@ -218,19 +253,21 @@ public class IrisPerfectionModifier extends EngineAssignedModifier riverWaterSurfaceStream; private final boolean bedrockEnabled; @@ -195,6 +196,7 @@ public class IrisTerrainNormalActuator extends EngineAssignedActuator