Merged compact biome selection

- Replace expanded rarity lists with cumulative counts
- Preserve ordinary selection mapping and bound extreme rarity storage
This commit is contained in:
Brian Neumann-Fopiano committed 2026-09-06 03:27:31 -04:00
commit 6276bb7327
6 files changed
+273 -140

No files matched your search

@@ -37,6 +37,7 @@ import art.arcane.iris.engine.image.IrisImageMapRuntime;
import art.arcane.iris.engine.mantle.components.MantleHydrologyCaveVoxelView;
import art.arcane.iris.engine.object.InferredType;
import art.arcane.iris.engine.object.IrisBiome;
import art.arcane.iris.engine.object.IrisRaritySelection;
import art.arcane.iris.engine.object.IrisDecorationPart;
import art.arcane.iris.engine.object.IrisDecorator;
import art.arcane.iris.engine.object.IrisGenerator;
@@ -1708,74 +1709,25 @@ public class IrisComplex implements DataProvider {
}
static final class ChildSelectionPlan {
private final IrisBiome[] mappedBiomes;
private final int maxIndex;
private final IrisRaritySelection<IrisBiome> selection;
private ChildSelectionPlan(IrisBiome[] mappedBiomes) {
this.mappedBiomes = mappedBiomes;
this.maxIndex = mappedBiomes.length - 1;
private ChildSelectionPlan(IrisRaritySelection<IrisBiome> selection) {
this.selection = selection;
}
static ChildSelectionPlan create(KList<IrisBiome> options) {
if (options.isEmpty()) {
return new ChildSelectionPlan(new IrisBiome[0]);
}
int maxRarity = 1;
for (IrisBiome biome : options) {
if (biome != null && biome.getRarity() > maxRarity) {
maxRarity = biome.getRarity();
}
}
int rarityMax = maxRarity + 1;
boolean flip = false;
KList<IrisBiome> mapped = new KList<>();
for (IrisBiome biome : options) {
if (biome == null) {
continue;
}
int rarity = Math.max(1, biome.getRarity());
int count = rarityMax - rarity;
for (int index = 0; index < count; index++) {
flip = !flip;
if (flip) {
mapped.add(biome);
} else {
mapped.add(0, biome);
}
}
}
if (mapped.isEmpty()) {
IrisBiome[] fallback = new IrisBiome[]{options.get(0)};
return new ChildSelectionPlan(fallback);
}
IrisBiome[] mappedBiomes = mapped.toArray(new IrisBiome[0]);
return new ChildSelectionPlan(mappedBiomes);
return new ChildSelectionPlan(IrisRaritySelection.create(options));
}
IrisBiome select(CNG childCell, double x, double z) {
if (mappedBiomes.length == 0) {
return null;
long maximumIndex = selection.size() - 1L;
if (maximumIndex <= 0L) {
return selection.get(0L);
}
if (mappedBiomes.length == 1) {
return mappedBiomes[0];
if (maximumIndex <= Integer.MAX_VALUE) {
return selection.get(childCell.fit2D(0, (int) maximumIndex, x, z));
}
int selectedIndex = childCell.fit2D(0, maxIndex, x, z);
if (selectedIndex < 0) {
return mappedBiomes[0];
}
if (selectedIndex > maxIndex) {
return mappedBiomes[maxIndex];
}
return mappedBiomes[selectedIndex];
return selection.select(childCell.noiseFast2D(x, z));
}
}
@@ -2,7 +2,6 @@ package art.arcane.iris.engine.object;
import art.arcane.iris.core.loader.IrisData;
import art.arcane.iris.engine.framework.Engine;
import art.arcane.iris.util.project.interpolation.IrisInterpolation;
import art.arcane.volmlib.util.collection.KList;
import art.arcane.iris.util.project.noise.CNG;
@@ -149,21 +148,20 @@ public final class IrisDimensionCarvingResolver {
return parent;
}
ParentSelectionPlan selectionPlan = state.selectionPlans.get(parent);
IrisRaritySelection<CarvingChoice> selectionPlan = state.selectionPlans.get(parent);
if (selectionPlan == null) {
selectionPlan = buildSelectionPlan(engine, parent, parentBiome, entryIndex, state);
state.selectionPlans.put(parent, selectionPlan);
}
if (selectionPlan.parentOnly) {
if (selectionPlan.size() <= 1L) {
return parent;
}
long seed = resolveChildSeed(engine, state);
CNG childGenerator = parent.getChildrenGenerator(seed, engine.getData());
double sample = childGenerator.noiseFast2D(worldX, worldZ);
int selectedIndex = (int) Math.round(IrisInterpolation.lerp(0, selectionPlan.maxIndex, sample));
CarvingChoice selected = selectionPlan.get(selectedIndex);
CarvingChoice selected = selectionPlan.select(sample);
if (selected == null || selected.entry == null) {
return parent;
}
@@ -171,7 +169,7 @@ public final class IrisDimensionCarvingResolver {
return selected.entry;
}
private static ParentSelectionPlan buildSelectionPlan(
private static IrisRaritySelection<CarvingChoice> buildSelectionPlan(
Engine engine,
IrisDimensionCarvingEntry parent,
IrisBiome parentBiome,
@@ -201,42 +199,7 @@ public final class IrisDimensionCarvingResolver {
}
options.add(new CarvingChoice(parent, rarity(parentBiome)));
if (options.size() <= 1) {
return ParentSelectionPlan.parentOnly();
}
CarvingChoice[] mappedChoices = buildRarityMappedChoices(options);
if (mappedChoices.length == 0) {
return ParentSelectionPlan.parentOnly();
}
return new ParentSelectionPlan(mappedChoices);
}
private static CarvingChoice[] buildRarityMappedChoices(List<CarvingChoice> choices) {
int max = 1;
for (CarvingChoice choice : choices) {
if (choice.rarity > max) {
max = choice.rarity;
}
}
max++;
List<CarvingChoice> mapped = new ArrayList<>();
boolean flip = false;
for (CarvingChoice choice : choices) {
int count = max - choice.rarity;
for (int index = 0; index < count; index++) {
flip = !flip;
if (flip) {
mapped.add(choice);
} else {
mapped.add(0, choice);
}
}
}
return mapped.toArray(new CarvingChoice[0]);
return IrisRaritySelection.create(options);
}
private static int rarity(IrisBiome biome) {
@@ -285,7 +248,7 @@ public final class IrisDimensionCarvingResolver {
public static final class State {
private final Map<Integer, IrisDimensionCarvingEntry> rootEntriesByWorldY = new HashMap<>();
private final Map<IrisDimensionCarvingEntry, ParentSelectionPlan> selectionPlans = new IdentityHashMap<>();
private final Map<IrisDimensionCarvingEntry, IrisRaritySelection<CarvingChoice>> selectionPlans = new IdentityHashMap<>();
private final Map<IrisDimensionCarvingEntry, IrisBiome> biomeCache = new IdentityHashMap<>();
private WeakReference<Engine> engineIdentity;
private WeakReference<IrisDimension> dimensionIdentity;
@@ -316,44 +279,6 @@ public final class IrisDimensionCarvingResolver {
}
}
private static final class ParentSelectionPlan {
private final CarvingChoice[] mappedChoices;
private final int maxIndex;
private final boolean parentOnly;
private ParentSelectionPlan(CarvingChoice[] mappedChoices) {
this.mappedChoices = mappedChoices;
this.maxIndex = mappedChoices.length - 1;
this.parentOnly = false;
}
private ParentSelectionPlan() {
this.mappedChoices = null;
this.maxIndex = -1;
this.parentOnly = true;
}
private static ParentSelectionPlan parentOnly() {
return new ParentSelectionPlan();
}
private CarvingChoice get(int index) {
if (mappedChoices == null || mappedChoices.length == 0) {
return null;
}
if (index < 0) {
return mappedChoices[0];
}
if (index >= mappedChoices.length) {
return mappedChoices[mappedChoices.length - 1];
}
return mappedChoices[index];
}
}
private static final class CarvingChoice implements IRare {
private final IrisDimensionCarvingEntry entry;
private final int rarity;
@@ -0,0 +1,60 @@
package art.arcane.iris.engine.object;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
public final class IrisRaritySelection<T extends IRare> {
private final List<T> choices;
private final long[] cumulativeCounts;
private IrisRaritySelection(List<T> choices, long[] cumulativeCounts) {
this.choices = choices;
this.cumulativeCounts = cumulativeCounts;
}
public static <T extends IRare> IrisRaritySelection<T> create(List<T> options) {
ArrayList<T> choices = new ArrayList<>(options.size());
long maximumRarity = 1L;
for (T option : options) {
if (option != null) {
choices.add(option);
maximumRarity = Math.max(maximumRarity, option.getRarity());
}
}
long[] cumulativeCounts = new long[choices.size()];
long total = 0L;
for (int index = 0; index < choices.size(); index++) {
total += maximumRarity + 1L - Math.max(1, choices.get(index).getRarity());
cumulativeCounts[index] = total;
}
return new IrisRaritySelection<>(List.copyOf(choices), cumulativeCounts);
}
public long size() {
return cumulativeCounts.length == 0 ? 0L : cumulativeCounts[cumulativeCounts.length - 1];
}
public T select(double noiseValue) {
long maximumIndex = size() - 1L;
long selectedIndex = Math.round(noiseValue * maximumIndex);
return get(maximumIndex <= Integer.MAX_VALUE ? (int) selectedIndex : selectedIndex);
}
public T get(long index) {
long size = size();
if (size == 0L) {
return null;
}
if (choices.size() == 1) {
return choices.getFirst();
}
long selectedIndex = Math.max(0L, Math.min(size - 1L, index));
long frontSize = size / 2L;
long insertionIndex = selectedIndex < frontSize
? 2L * (frontSize - selectedIndex) - 1L
: 2L * (selectedIndex - frontSize);
int choiceIndex = Arrays.binarySearch(cumulativeCounts, insertionIndex + 1L);
return choices.get(choiceIndex < 0 ? -choiceIndex - 1 : choiceIndex);
}
}