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 9607089eb..0ef34aff0 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 @@ -14,7 +14,7 @@ import art.arcane.volmlib.util.noise.CNG; import java.lang.ref.WeakReference; import java.util.ArrayList; -import java.util.HashMap; +import java.util.Arrays; import java.util.IdentityHashMap; import java.util.List; import java.util.Map; @@ -81,8 +81,9 @@ public final class IrisDimensionCarvingResolver { } private static IrisDimensionCarvingEntry resolveBoundRootEntry(Engine engine, int worldY, IrisData data, State resolvedState) { - if (resolvedState.rootEntriesByWorldY.containsKey(worldY)) { - return resolvedState.rootEntriesByWorldY.get(worldY); + int slot = resolvedState.rootSlot(worldY); + if (slot >= 0) { + return resolvedState.roots[slot]; } return selectBoundRootEntry(engine.getDimension(), worldY, data, resolvedState); @@ -91,7 +92,7 @@ public final class IrisDimensionCarvingResolver { private static IrisDimensionCarvingEntry selectBoundRootEntry(IrisDimension dimension, int worldY, IrisData data, State resolvedState) { List entries = dimension.getCarving(); if (entries == null || entries.isEmpty()) { - resolvedState.rootEntriesByWorldY.put(worldY, null); + resolvedState.rememberRoot(worldY, null); return null; } @@ -104,7 +105,7 @@ public final class IrisDimensionCarvingResolver { resolved = entry; } - resolvedState.rootEntriesByWorldY.put(worldY, resolved); + resolvedState.rememberRoot(worldY, resolved); return resolved; } @@ -324,8 +325,9 @@ public final class IrisDimensionCarvingResolver { } public IrisBiome resolveBiome(int worldX, int worldY, int worldZ) { - IrisDimensionCarvingEntry root = state.rootEntriesByWorldY.containsKey(worldY) - ? state.rootEntriesByWorldY.get(worldY) + int slot = state.rootSlot(worldY); + IrisDimensionCarvingEntry root = slot >= 0 + ? state.roots[slot] : selectBoundRootEntry(dimension, worldY, data, state); if (root == null) { return null; @@ -336,7 +338,11 @@ public final class IrisDimensionCarvingResolver { } public static final class State { - private final Map rootEntriesByWorldY = new HashMap<>(); + private static final int ROOT_SLOTS = 512; + + private int[] rootWorldYs; + private IrisDimensionCarvingEntry[] roots; + private boolean[] rootsKnown; private final Map> selectionPlans = new IdentityHashMap<>(); private final Map biomeCache = new IdentityHashMap<>(); private WeakReference engineIdentity; @@ -357,7 +363,10 @@ public final class IrisDimensionCarvingResolver { engineIdentity = new WeakReference<>(engine); dimensionIdentity = new WeakReference<>(dimension); dataIdentity = new WeakReference<>(data); - rootEntriesByWorldY.clear(); + if (rootsKnown != null) { + Arrays.fill(rootsKnown, false); + Arrays.fill(roots, null); + } selectionPlans.clear(); biomeCache.clear(); entryIndex = null; @@ -366,6 +375,23 @@ public final class IrisDimensionCarvingResolver { return data; } + private int rootSlot(int worldY) { + int slot = worldY & (ROOT_SLOTS - 1); + return rootsKnown != null && rootsKnown[slot] && rootWorldYs[slot] == worldY ? slot : -1; + } + + private void rememberRoot(int worldY, IrisDimensionCarvingEntry root) { + if (rootsKnown == null) { + rootWorldYs = new int[ROOT_SLOTS]; + roots = new IrisDimensionCarvingEntry[ROOT_SLOTS]; + rootsKnown = new boolean[ROOT_SLOTS]; + } + int slot = worldY & (ROOT_SLOTS - 1); + rootWorldYs[slot] = worldY; + roots[slot] = root; + rootsKnown[slot] = true; + } + private static boolean references(WeakReference identity, Object value) { return identity != null && identity.get() == value; } diff --git a/core/src/main/java/art/arcane/iris/world/history/GenerationSemanticCapture.java b/core/src/main/java/art/arcane/iris/world/history/GenerationSemanticCapture.java index edd4de352..8e8c8cb9a 100644 --- a/core/src/main/java/art/arcane/iris/world/history/GenerationSemanticCapture.java +++ b/core/src/main/java/art/arcane/iris/world/history/GenerationSemanticCapture.java @@ -227,12 +227,12 @@ public final class GenerationSemanticCapture { } resolvedCaves.set(position); if (explicitBiomeKey != null && !explicitBiomeKey.isBlank()) { - semantics.addCaveBiome(explicitBiomeKey); + caveBiomes.add(semantics, explicitBiomeKey); return; } IrisBiome caveBiome = caveBiomes.resolve(blockX, y, blockZ); if (caveBiome != null && caveBiome.getLoadKey() != null) { - semantics.addCaveBiome(caveBiome.getLoadKey()); + caveBiomes.add(semantics, caveBiome.getLoadKey()); } } @@ -280,6 +280,7 @@ public final class GenerationSemanticCapture { private final IrisDimensionCarvingResolver.State fallbackState = new IrisDimensionCarvingResolver.State(); private IrisDimensionCarvingResolver.Snapshot snapshot; private int minimumY; + private String lastKey; private CaveBiomes(Engine engine, boolean scoped) { this.engine = engine; @@ -290,6 +291,13 @@ public final class GenerationSemanticCapture { : null; } + private void add(ChunkGenerationSemantics.Builder semantics, String key) { + if (key != lastKey) { + semantics.addCaveBiome(key); + lastKey = key; + } + } + private IrisBiome resolve(int x, int y, int z) { if (!scoped) { return engine.getCaveBiome(x, y, z); 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 3ee98ec8b..504be0ec7 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 @@ -494,12 +494,11 @@ public class IrisDimensionCarvingResolverParityTest { assertSame(fixture.entry(), IrisDimensionCarvingResolver.resolveRootEntry( fixture.engine(), 80, state)); - Field rootEntriesField = IrisDimensionCarvingResolver.State.class - .getDeclaredField("rootEntriesByWorldY"); - rootEntriesField.setAccessible(true); + Field rootsField = IrisDimensionCarvingResolver.State.class.getDeclaredField("roots"); + rootsField.setAccessible(true); System.gc(); - assertSame(fixture.entry(), ((Map) rootEntriesField.get(state)).get(80)); + assertSame(fixture.entry(), ((IrisDimensionCarvingEntry[]) rootsField.get(state))[80]); } private RetainedFixture createRetainedFixture() {