mirror of
https://github.com/VolmitSoftware/Iris.git
synced 2026-10-27 06:20:02 +00:00
Refined terrain assembly
- Ceiling layers use their own thickness generators - Pack validation accepts independent ceiling layer counts - Locked strata repeat across the reference height - Surface and cave palettes share layer emission - Cave passes release retained chunk sections - Nested carving preserves outer blend buffers - Profile blending reuses bounded numeric buffers - Terrain actuators remove unused state and duplicate checks - Regression tests cover layers and carving scratch lifetimes
This commit is contained in:
1 parent
17c927acdd
commit
23bad0e1a2
16 files changed
+446
-223
No files matched your search
@@ -22,24 +22,15 @@ import art.arcane.volmlib.util.json.JSONArray;
|
||||
import art.arcane.volmlib.util.json.JSONObject;
|
||||
|
||||
import java.io.File;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.nio.file.Files;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Validates biome layer stacks. caveCeilingLayers reuses the height generators built from layers,
|
||||
* so a biome with more ceiling entries than surface entries has no generator for the extras; the
|
||||
* engine skips them, and this validator surfaces the mistake to the author at validate time.
|
||||
*/
|
||||
final class PackBiomeLayerValidator {
|
||||
private static final int DEFAULT_LAYER_COUNT = 1;
|
||||
|
||||
private PackBiomeLayerValidator() {
|
||||
}
|
||||
|
||||
static List<String> validateCeilingLayerCounts(File biomesFolder) {
|
||||
static List<String> validateLayers(File biomesFolder) {
|
||||
List<String> blockingErrors = new ArrayList<>();
|
||||
if (biomesFolder == null || !biomesFolder.isDirectory()) {
|
||||
return blockingErrors;
|
||||
@@ -49,24 +40,13 @@ final class PackBiomeLayerValidator {
|
||||
biomeFiles.sort(Comparator.comparing(File::getPath));
|
||||
for (File biomeFile : biomeFiles) {
|
||||
String biomeKey = PackValidationIo.deriveKey(biomesFolder, biomeFile);
|
||||
JSONObject biome;
|
||||
try {
|
||||
biome = new JSONObject(Files.readString(biomeFile.toPath(), StandardCharsets.UTF_8));
|
||||
} catch (Throwable e) {
|
||||
// Invalid JSON is reported by the graph validators; layer counts have nothing to add.
|
||||
JSONObject biome = PackValidationIo.readJson(biomeFile);
|
||||
if (biome == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
Integer layers = arrayLength(biome, "layers", biomeKey, DEFAULT_LAYER_COUNT, blockingErrors);
|
||||
Integer ceiling = arrayLength(biome, "caveCeilingLayers", biomeKey, 0, blockingErrors);
|
||||
if (layers == null || ceiling == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (ceiling > layers) {
|
||||
blockingErrors.add("Biome '" + biomeKey + "' declares " + ceiling + " caveCeilingLayers but only "
|
||||
+ layers + " layers. caveCeilingLayers reuses the layers height generators and must not have more entries.");
|
||||
}
|
||||
validateLayerArray(biome, "layers", biomeKey, blockingErrors);
|
||||
validateLayerArray(biome, "caveCeilingLayers", biomeKey, blockingErrors);
|
||||
}
|
||||
return blockingErrors;
|
||||
}
|
||||
@@ -126,17 +106,15 @@ final class PackBiomeLayerValidator {
|
||||
}
|
||||
}
|
||||
|
||||
private static Integer arrayLength(JSONObject biome, String field, String biomeKey, int defaultCount,
|
||||
private static void validateLayerArray(JSONObject biome, String field, String biomeKey,
|
||||
List<String> blockingErrors) {
|
||||
if (!biome.has(field) || biome.isNull(field)) {
|
||||
return defaultCount;
|
||||
return;
|
||||
}
|
||||
|
||||
JSONArray array = biome.optJSONArray(field);
|
||||
if (array == null) {
|
||||
blockingErrors.add("Biome '" + biomeKey + "' " + field + " must be an array.");
|
||||
return null;
|
||||
}
|
||||
return array.length();
|
||||
}
|
||||
}
|
||||
@@ -150,7 +150,7 @@ public final class PackValidator {
|
||||
new File(packFolder, "spawners"), new File(packFolder, "entities")));
|
||||
blockingErrors.addAll(PackSpawnValidator.validateCustomBiomeSpawns(
|
||||
new File(packFolder, "biomes"), PackSpawnValidator::resolveEntitySpawnCategory));
|
||||
blockingErrors.addAll(PackBiomeLayerValidator.validateCeilingLayerCounts(new File(packFolder, "biomes")));
|
||||
blockingErrors.addAll(PackBiomeLayerValidator.validateLayers(new File(packFolder, "biomes")));
|
||||
blockingErrors.addAll(PackBiomeLayerValidator.validateDecoratorPalettes(
|
||||
new File(packFolder, "biomes"), new File(packFolder, "snippet/decorator")));
|
||||
PackStyledRangeDefaultValidator.Validation styledRanges = PackStyledRangeDefaultValidator.validate(packFolder);
|
||||
|
||||
@@ -41,7 +41,6 @@ import art.arcane.volmlib.util.math.RNG;
|
||||
import art.arcane.volmlib.util.matter.Matter;
|
||||
import art.arcane.volmlib.util.matter.MatterBiomeInject;
|
||||
import art.arcane.volmlib.util.matter.slices.BiomeInjectMatter;
|
||||
import art.arcane.volmlib.util.scheduling.ChronoLatch;
|
||||
import art.arcane.volmlib.util.scheduling.PrecisionStopwatch;
|
||||
|
||||
import java.util.List;
|
||||
@@ -49,7 +48,6 @@ import java.util.Objects;
|
||||
|
||||
public class IrisBiomeActuator extends EngineAssignedActuator<PlatformBiome> {
|
||||
private final RNG rng;
|
||||
private final ChronoLatch cl = new ChronoLatch(5000);
|
||||
private final KMap<String, ResolvedBiome> resolvedBiomes = new KMap<>();
|
||||
private final KMap<String, ResolvedBiome> resolvedPhysicalBiomes = new KMap<>();
|
||||
|
||||
|
||||
@@ -46,11 +46,7 @@ import art.arcane.iris.util.common.data.B;
|
||||
import lombok.Getter;
|
||||
|
||||
public class IrisTerrainNormalActuator extends EngineAssignedActuator<PlatformBlockState> {
|
||||
private static final PlatformBlockState AIR = B.getState("AIR");
|
||||
private static final PlatformBlockState BEDROCK = B.getState("BEDROCK");
|
||||
private static final PlatformBlockState LAVA = B.getState("LAVA");
|
||||
private static final PlatformBlockState GLASS = B.getState("GLASS");
|
||||
private static final PlatformBlockState CAVE_AIR = B.getState("CAVE_AIR");
|
||||
@Getter
|
||||
private final RNG rng;
|
||||
@Getter
|
||||
@@ -83,11 +79,6 @@ public class IrisTerrainNormalActuator extends EngineAssignedActuator<PlatformBl
|
||||
*/
|
||||
@BlockCoordinates
|
||||
public void terrainSliver(int x, int z, int xf, Hunk<PlatformBlockState> h, ChunkContext context) {
|
||||
terrainSliverOptimized(x, z, xf, h, context);
|
||||
}
|
||||
|
||||
@BlockCoordinates
|
||||
private void terrainSliverOptimized(int x, int z, int xf, Hunk<PlatformBlockState> h, ChunkContext context) {
|
||||
int chunkHeight = h.getHeight();
|
||||
int chunkDepth = h.getDepth();
|
||||
IrisDimension dimension = getDimension();
|
||||
|
||||
+1
-3
@@ -42,9 +42,7 @@ public final class IrisTransitionGeometryActuator extends EngineAssignedComponen
|
||||
return;
|
||||
}
|
||||
GeometrySource source = new GeometrySource(blocks, biomes, getEngine().getMinHeight(), context);
|
||||
if (plan != null && plan.hasTransitionAtChunk(x >> 4, z >> 4)) {
|
||||
blendGeometry(x, z, blocks, context, source, plan);
|
||||
}
|
||||
blendGeometry(x, z, blocks, context, source, plan);
|
||||
}
|
||||
|
||||
public static SavedTerrainChunk capture(int x, int z, Hunk<PlatformBlockState> blocks,
|
||||
|
||||
@@ -22,6 +22,8 @@ import art.arcane.volmlib.util.matter.Matter;
|
||||
import art.arcane.volmlib.util.matter.MatterCavern;
|
||||
import art.arcane.volmlib.util.matter.MatterSlice;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
final class CaveCarveScratch {
|
||||
final int[] columnMaxY = new int[256];
|
||||
final int[] fluidMaxY = new int[256];
|
||||
@@ -70,4 +72,9 @@ final class CaveCarveScratch {
|
||||
int adaptiveGeometryStep = -1;
|
||||
int adaptiveGeometryAxisCells = -1;
|
||||
boolean fullWeightsInitialized;
|
||||
|
||||
void releaseSections() {
|
||||
Arrays.fill(sectionMatter, null);
|
||||
Arrays.fill(sectionSlices, null);
|
||||
}
|
||||
}
|
||||
@@ -436,6 +436,7 @@ public class IrisCaveCarver3D {
|
||||
|
||||
return carved;
|
||||
} finally {
|
||||
scratchCache.get().releaseSections();
|
||||
carving.set(nested);
|
||||
if (nested) {
|
||||
scratchCache.set(previousScratch);
|
||||
@@ -2695,10 +2696,6 @@ public class IrisCaveCarver3D {
|
||||
return weight;
|
||||
}
|
||||
|
||||
private double signed(double value) {
|
||||
return (value * 2D) - 1D;
|
||||
}
|
||||
|
||||
private double applySurfaceCeilingFade(
|
||||
CaveCarveScratch scratch,
|
||||
double threshold,
|
||||
|
||||
+60
-33
@@ -19,6 +19,7 @@
|
||||
package art.arcane.iris.engine.mantle.components;
|
||||
|
||||
import art.arcane.iris.engine.IrisComplex;
|
||||
import art.arcane.iris.engine.framework.Engine;
|
||||
import art.arcane.iris.engine.UpperDimensionContext;
|
||||
import art.arcane.iris.engine.mantle.MatterGenerationPhase;
|
||||
import art.arcane.iris.engine.mantle.ComponentFlag;
|
||||
@@ -36,7 +37,6 @@ import art.arcane.iris.util.common.data.B;
|
||||
import art.arcane.iris.util.project.context.ChunkContext;
|
||||
import art.arcane.iris.util.project.stream.ProceduralStream;
|
||||
import art.arcane.iris.util.project.stream.utility.ChunkFillableDoubleStream2D;
|
||||
import art.arcane.iris.util.simd.SimdKernels;
|
||||
import art.arcane.iris.util.simd.SimdSupport;
|
||||
import art.arcane.volmlib.util.documentation.ChunkCoordinates;
|
||||
import art.arcane.volmlib.util.mantle.flag.ReservedFlag;
|
||||
@@ -58,6 +58,7 @@ public class MantleCarvingComponent extends IrisMantleComponent {
|
||||
private static final double MIN_WEIGHT = 0.08D;
|
||||
private static final double THRESHOLD_PENALTY = 0.24D;
|
||||
private static final int MAX_BLENDED_PROFILE_PASSES = 2;
|
||||
private static final int MAX_POOLED_WEIGHT_BUFFERS = 64;
|
||||
private static final int KERNEL_WIDTH = (BLEND_RADIUS * 2) + 1;
|
||||
private static final int KERNEL_SIZE = KERNEL_WIDTH * KERNEL_WIDTH;
|
||||
private static final int[] KERNEL_DX = new int[KERNEL_SIZE];
|
||||
@@ -107,8 +108,25 @@ public class MantleCarvingComponent extends IrisMantleComponent {
|
||||
if (!complex.allowsMantleChunkWrite(x, z)) {
|
||||
return;
|
||||
}
|
||||
BlendScratch previous = BLEND_SCRATCH.get();
|
||||
BlendScratch scratch = previous.inUse ? new BlendScratch() : previous;
|
||||
if (scratch != previous) {
|
||||
BLEND_SCRATCH.set(scratch);
|
||||
}
|
||||
scratch.inUse = true;
|
||||
try {
|
||||
generateLayer(writer, x, z, context, scratch);
|
||||
} finally {
|
||||
scratch.release();
|
||||
if (scratch != previous) {
|
||||
BLEND_SCRATCH.set(previous);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void generateLayer(MantleWriter writer, int x, int z, ChunkContext context, BlendScratch blendScratch) {
|
||||
IrisComplex complex = context.getComplex();
|
||||
IrisDimensionCarvingResolver.State resolverState = new IrisDimensionCarvingResolver.State();
|
||||
BlendScratch blendScratch = BLEND_SCRATCH.get();
|
||||
int[] chunkSurfaceHeights = prepareChunkSurfaceHeights(x, z, context, blendScratch.chunkSurfaceHeights);
|
||||
PrecisionStopwatch resolveStopwatch = PrecisionStopwatch.start();
|
||||
List<WeightedProfile> weightedProfiles = resolveWeightedProfiles(x, z, complex, resolverState);
|
||||
@@ -217,12 +235,12 @@ public class MantleCarvingComponent extends IrisMantleComponent {
|
||||
BlendScratch blendScratch = BLEND_SCRATCH.get();
|
||||
IrisCaveProfile[] profileField = blendScratch.profileField;
|
||||
Map<IrisCaveProfile, double[]> columnProfileWeights = blendScratch.columnProfileWeights;
|
||||
IdentityHashMap<IrisCaveProfile, Boolean> activeProfiles = blendScratch.activeProfiles;
|
||||
List<IrisCaveProfile> profileOrder = blendScratch.profileOrder;
|
||||
IrisCaveProfile[] kernelProfiles = blendScratch.kernelProfiles;
|
||||
double[] kernelProfileWeights = blendScratch.kernelProfileWeights;
|
||||
activeProfiles.clear();
|
||||
columnProfileWeights.clear();
|
||||
profileOrder.clear();
|
||||
blendScratch.nextWeightBuffer = 0;
|
||||
fillProfileField(profileField, chunkX, chunkZ, complex, resolverState, blendScratch);
|
||||
|
||||
for (int localX = 0; localX < CHUNK_SIZE; localX++) {
|
||||
@@ -270,12 +288,8 @@ public class MantleCarvingComponent extends IrisMantleComponent {
|
||||
|
||||
double[] weights = columnProfileWeights.get(profile);
|
||||
if (weights == null) {
|
||||
weights = new double[CHUNK_AREA];
|
||||
weights = blendScratch.acquireWeights();
|
||||
columnProfileWeights.put(profile, weights);
|
||||
} else if (!activeProfiles.containsKey(profile)) {
|
||||
Arrays.fill(weights, 0D);
|
||||
}
|
||||
if (activeProfiles.put(profile, Boolean.TRUE) == null) {
|
||||
profileOrder.add(profile);
|
||||
}
|
||||
weights[columnIndex] = columnWeight;
|
||||
@@ -316,28 +330,27 @@ public class MantleCarvingComponent extends IrisMantleComponent {
|
||||
return weightedProfiles;
|
||||
}
|
||||
|
||||
Map<IrisDimensionCarvingEntry, IrisDimensionCarvingEntry[]> dimensionColumnPlans = blendScratch.dimensionColumnPlans;
|
||||
dimensionColumnPlans.clear();
|
||||
Engine engine = getEngineMantle().getEngine();
|
||||
int baseX = PowerOfTwoCoordinates.chunkToBlock(chunkX);
|
||||
int baseZ = PowerOfTwoCoordinates.chunkToBlock(chunkZ);
|
||||
|
||||
for (IrisDimensionCarvingEntry entry : entries) {
|
||||
if (entry == null || !entry.isEnabled()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
IrisBiome rootBiome = IrisDimensionCarvingResolver.resolveEntryBiome(getEngineMantle().getEngine(), entry, resolverState);
|
||||
IrisBiome rootBiome = IrisDimensionCarvingResolver.resolveEntryBiome(engine, entry, resolverState);
|
||||
if (rootBiome == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
IrisDimensionCarvingEntry[] columnPlan = dimensionColumnPlans.computeIfAbsent(entry, key -> new IrisDimensionCarvingEntry[CHUNK_AREA]);
|
||||
buildDimensionColumnPlan(columnPlan, chunkX, chunkZ, entry, resolverState);
|
||||
|
||||
Map<IrisCaveProfile, double[]> rootProfileColumnWeights = new IdentityHashMap<>();
|
||||
List<IrisCaveProfile> rootProfileOrder = new ArrayList<>();
|
||||
IrisRange worldYRange = entry.getWorldYRange();
|
||||
for (int columnIndex = 0; columnIndex < CHUNK_AREA; columnIndex++) {
|
||||
IrisDimensionCarvingEntry resolvedEntry = columnPlan[columnIndex];
|
||||
IrisBiome resolvedBiome = IrisDimensionCarvingResolver.resolveEntryBiome(getEngineMantle().getEngine(), resolvedEntry, resolverState);
|
||||
IrisDimensionCarvingEntry resolvedEntry = IrisDimensionCarvingResolver.resolveFromRoot(
|
||||
engine, entry, baseX + (columnIndex >> 4), baseZ + (columnIndex & 15), resolverState);
|
||||
IrisBiome resolvedBiome = IrisDimensionCarvingResolver.resolveEntryBiome(engine, resolvedEntry, resolverState);
|
||||
if (resolvedBiome == null) {
|
||||
continue;
|
||||
}
|
||||
@@ -349,7 +362,7 @@ public class MantleCarvingComponent extends IrisMantleComponent {
|
||||
|
||||
double[] columnWeights = rootProfileColumnWeights.get(profile);
|
||||
if (columnWeights == null) {
|
||||
columnWeights = new double[CHUNK_AREA];
|
||||
columnWeights = blendScratch.acquireWeights();
|
||||
rootProfileColumnWeights.put(profile, columnWeights);
|
||||
rootProfileOrder.add(profile);
|
||||
}
|
||||
@@ -364,19 +377,6 @@ public class MantleCarvingComponent extends IrisMantleComponent {
|
||||
return weightedProfiles;
|
||||
}
|
||||
|
||||
private void buildDimensionColumnPlan(IrisDimensionCarvingEntry[] columnPlan, int chunkX, int chunkZ, IrisDimensionCarvingEntry entry, IrisDimensionCarvingResolver.State resolverState) {
|
||||
int baseX = PowerOfTwoCoordinates.chunkToBlock(chunkX);
|
||||
int baseZ = PowerOfTwoCoordinates.chunkToBlock(chunkZ);
|
||||
for (int localX = 0; localX < CHUNK_SIZE; localX++) {
|
||||
int worldX = baseX + localX;
|
||||
for (int localZ = 0; localZ < CHUNK_SIZE; localZ++) {
|
||||
int worldZ = baseZ + localZ;
|
||||
int columnIndex = PowerOfTwoCoordinates.packLocal16(localX, localZ);
|
||||
columnPlan[columnIndex] = IrisDimensionCarvingResolver.resolveFromRoot(getEngineMantle().getEngine(), entry, worldX, worldZ, resolverState);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void fillProfileField(IrisCaveProfile[] profileField, int chunkX, int chunkZ, IrisComplex complex, IrisDimensionCarvingResolver.State resolverState, BlendScratch blendScratch) {
|
||||
int startX = PowerOfTwoCoordinates.chunkToBlock(chunkX) - BLEND_RADIUS;
|
||||
int startZ = PowerOfTwoCoordinates.chunkToBlock(chunkZ) - BLEND_RADIUS;
|
||||
@@ -698,8 +698,7 @@ public class MantleCarvingComponent extends IrisMantleComponent {
|
||||
private final IrisCaveProfile[] kernelProfiles = new IrisCaveProfile[KERNEL_SIZE];
|
||||
private final double[] kernelProfileWeights = new double[KERNEL_SIZE];
|
||||
private final IdentityHashMap<IrisCaveProfile, double[]> columnProfileWeights = new IdentityHashMap<>();
|
||||
private final IdentityHashMap<IrisDimensionCarvingEntry, IrisDimensionCarvingEntry[]> dimensionColumnPlans = new IdentityHashMap<>();
|
||||
private final IdentityHashMap<IrisCaveProfile, Boolean> activeProfiles = new IdentityHashMap<>();
|
||||
private final List<double[]> weightBuffers = new ArrayList<>();
|
||||
private final List<IrisCaveProfile> profileOrder = new ArrayList<>();
|
||||
private final double[] fieldSurfaceHeights = new double[FIELD_SIZE * FIELD_SIZE];
|
||||
private final double[] fieldFluidHeights = new double[FIELD_SIZE * FIELD_SIZE];
|
||||
@@ -710,5 +709,33 @@ public class MantleCarvingComponent extends IrisMantleComponent {
|
||||
private final IrisBiome[] fieldCaveBiomes = new IrisBiome[FIELD_SIZE * FIELD_SIZE];
|
||||
private final int[] chunkSurfaceHeights = new int[CHUNK_AREA];
|
||||
private final double[] chunkSurfaceHeightSamples = new double[CHUNK_AREA];
|
||||
private int nextWeightBuffer;
|
||||
private boolean inUse;
|
||||
|
||||
private double[] acquireWeights() {
|
||||
if (nextWeightBuffer < weightBuffers.size()) {
|
||||
double[] weights = weightBuffers.get(nextWeightBuffer++);
|
||||
Arrays.fill(weights, 0D);
|
||||
return weights;
|
||||
}
|
||||
double[] weights = new double[CHUNK_AREA];
|
||||
if (weightBuffers.size() < MAX_POOLED_WEIGHT_BUFFERS) {
|
||||
weightBuffers.add(weights);
|
||||
nextWeightBuffer++;
|
||||
}
|
||||
return weights;
|
||||
}
|
||||
|
||||
private void release() {
|
||||
Arrays.fill(profileField, null);
|
||||
Arrays.fill(kernelProfiles, null);
|
||||
Arrays.fill(fieldRegions, null);
|
||||
Arrays.fill(fieldSurfaceBiomes, null);
|
||||
Arrays.fill(fieldCaveBiomes, null);
|
||||
columnProfileWeights.clear();
|
||||
profileOrder.clear();
|
||||
nextWeightBuffer = 0;
|
||||
inUse = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -92,6 +92,7 @@ public class IrisBiome extends IrisRegistrant implements IRare {
|
||||
private final transient AtomicCache<IrisBiome> realCarveBiome = new AtomicCache<>();
|
||||
private final transient AtomicCache<KList<IrisBiome>> realChildren = new AtomicCache<>();
|
||||
private final transient AtomicCache<KList<CNG>> layerHeightGenerators = new AtomicCache<>();
|
||||
private final transient AtomicCache<KList<CNG>> layerCeilingHeightGenerators = new AtomicCache<>();
|
||||
private final transient AtomicCache<KList<CNG>> layerSeaHeightGenerators = new AtomicCache<>();
|
||||
private final transient AtomicCache<KList<IrisOreGenerator>> surfaceOreCache = new AtomicCache<>();
|
||||
private final transient AtomicCache<KList<IrisOreGenerator>> undergroundOreCache = new AtomicCache<>();
|
||||
|
||||
@@ -74,7 +74,7 @@ final class IrisBiomeLayerGenerator {
|
||||
IrisBiomePaletteLayer layer = layers.get(i);
|
||||
double zoom = layer.getZoom();
|
||||
CNG hgen = heightGenerators.get(i);
|
||||
double d = hgen.fit(layer.getMinHeight(), layer.getMaxHeight(), wx / zoom, wz / zoom);
|
||||
int d = hgen.fit(layer.getMinHeight(), layer.getMaxHeight(), wx / zoom, wz / zoom);
|
||||
|
||||
IrisSlopeClip sc = layer.getSlopeCondition();
|
||||
|
||||
@@ -88,17 +88,7 @@ final class IrisBiomeLayerGenerator {
|
||||
continue;
|
||||
}
|
||||
|
||||
for (int j = 0; j < d; j++) {
|
||||
if (data.size() >= maxDepth) {
|
||||
break;
|
||||
}
|
||||
|
||||
try {
|
||||
data.add(layer.get(random, i + j, (wx + j) / zoom, j, (wz - j) / zoom, rdata));
|
||||
} catch (Throwable e) {
|
||||
IrisLogging.reportError(e);
|
||||
}
|
||||
}
|
||||
appendLayer(data, layer, i, d, wx, wz, random, maxDepth, rdata);
|
||||
|
||||
if (data.size() >= maxDepth) {
|
||||
break;
|
||||
@@ -132,31 +122,20 @@ final class IrisBiomeLayerGenerator {
|
||||
return data;
|
||||
}
|
||||
|
||||
KList<CNG> heightGenerators = getLayerHeightGenerators(biome, random, rdata);
|
||||
// Ceiling layers reuse the surface-layer height generators, so entries beyond layers.size() have no generator; skip them.
|
||||
int usableLayers = Math.min(layerCount, heightGenerators.size());
|
||||
KList<CNG> heightGenerators = getHeightGenerators(
|
||||
biome.getLayerCeilingHeightGenerators(), ceilingLayers, 7235, random, rdata);
|
||||
|
||||
for (int i = 0; i < usableLayers; i++) {
|
||||
for (int i = 0; i < layerCount; i++) {
|
||||
IrisBiomePaletteLayer layer = ceilingLayers.get(i);
|
||||
double zoom = layer.getZoom();
|
||||
CNG hgen = heightGenerators.get(i);
|
||||
double d = hgen.fit(layer.getMinHeight(), layer.getMaxHeight(), wx / zoom, wz / zoom);
|
||||
int d = hgen.fit(layer.getMinHeight(), layer.getMaxHeight(), wx / zoom, wz / zoom);
|
||||
|
||||
if (d <= 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
for (int j = 0; j < d; j++) {
|
||||
if (data.size() >= maxDepth) {
|
||||
break;
|
||||
}
|
||||
|
||||
try {
|
||||
data.add(layer.get(random, i + j, (wx + j) / zoom, j, (wz - j) / zoom, rdata));
|
||||
} catch (Throwable e) {
|
||||
IrisLogging.reportError(e);
|
||||
}
|
||||
}
|
||||
appendLayer(data, layer, i, d, wx, wz, random, maxDepth, rdata);
|
||||
|
||||
if (data.size() >= maxDepth) {
|
||||
break;
|
||||
@@ -198,7 +177,7 @@ final class IrisBiomeLayerGenerator {
|
||||
IrisBiomePaletteLayer layer = layers.get(i);
|
||||
double zoom = layer.getZoom();
|
||||
CNG hgen = heightGenerators.get(i);
|
||||
double d = hgen.fit(layer.getMinHeight(), layer.getMaxHeight(), wx / zoom, wz / zoom);
|
||||
int d = hgen.fit(layer.getMinHeight(), layer.getMaxHeight(), wx / zoom, wz / zoom);
|
||||
|
||||
IrisSlopeClip sc = layer.getSlopeCondition();
|
||||
|
||||
@@ -212,13 +191,7 @@ final class IrisBiomeLayerGenerator {
|
||||
continue;
|
||||
}
|
||||
|
||||
for (int j = 0; j < d; j++) {
|
||||
try {
|
||||
data.add(layer.get(random, i + j, (wx + j) / zoom, j, (wz - j) / zoom, rdata));
|
||||
} catch (Throwable e) {
|
||||
IrisLogging.reportError(e);
|
||||
}
|
||||
}
|
||||
appendLayer(data, layer, i, d, wx, wz, random, Integer.MAX_VALUE, rdata);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -227,9 +200,8 @@ final class IrisBiomeLayerGenerator {
|
||||
}
|
||||
|
||||
for (int i = 0; i < maxDepth; i++) {
|
||||
int offset = (512 - height) - i;
|
||||
int index = offset % data.size();
|
||||
real.add(data.get(Math.max(index, 0)));
|
||||
long offset = 512L - height - i;
|
||||
real.add(data.get(Math.floorMod(offset, data.size())));
|
||||
}
|
||||
|
||||
return real;
|
||||
@@ -264,17 +236,7 @@ final class IrisBiomeLayerGenerator {
|
||||
continue;
|
||||
}
|
||||
|
||||
for (int j = 0; j < d; j++) {
|
||||
if (data.size() >= maxDepth) {
|
||||
break;
|
||||
}
|
||||
|
||||
try {
|
||||
data.add(layer.get(random, i + j, (wx + j) / zoom, j, (wz - j) / zoom, rdata));
|
||||
} catch (Throwable e) {
|
||||
IrisLogging.reportError(e);
|
||||
}
|
||||
}
|
||||
appendLayer(data, layer, i, d, wx, wz, random, maxDepth, rdata);
|
||||
|
||||
if (data.size() >= maxDepth) {
|
||||
break;
|
||||
@@ -285,7 +247,16 @@ final class IrisBiomeLayerGenerator {
|
||||
}
|
||||
|
||||
static KList<CNG> getLayerHeightGenerators(IrisBiome biome, RNG rng, IrisData rdata) {
|
||||
AtomicCache<KList<CNG>> cache = biome.getLayerHeightGenerators();
|
||||
return getHeightGenerators(biome.getLayerHeightGenerators(), biome.getLayers(), 7235, rng, rdata);
|
||||
}
|
||||
|
||||
static KList<CNG> getLayerSeaHeightGenerators(IrisBiome biome, RNG rng, IrisData data) {
|
||||
return getHeightGenerators(biome.getLayerSeaHeightGenerators(), biome.getSeaLayers(), 7735, rng, data);
|
||||
}
|
||||
|
||||
private static KList<CNG> getHeightGenerators(AtomicCache<KList<CNG>> cache,
|
||||
KList<IrisBiomePaletteLayer> layers,
|
||||
int seedOffset, RNG rng, IrisData data) {
|
||||
KList<CNG> cached = cache.getIfPresent();
|
||||
|
||||
if (cached != null) {
|
||||
@@ -296,36 +267,28 @@ final class IrisBiomeLayerGenerator {
|
||||
{
|
||||
KList<CNG> layerHeightGenerators = new KList<>();
|
||||
|
||||
int m = 7235;
|
||||
int m = seedOffset;
|
||||
|
||||
for (IrisBiomePaletteLayer i : biome.getLayers()) {
|
||||
layerHeightGenerators.add(i.getHeightGenerator(rng.nextParallelRNG((m++) * m * m * m), rdata));
|
||||
for (IrisBiomePaletteLayer layer : layers) {
|
||||
layerHeightGenerators.add(layer.getHeightGenerator(rng.nextParallelRNG((m++) * m * m * m), data));
|
||||
}
|
||||
|
||||
return layerHeightGenerators;
|
||||
});
|
||||
}
|
||||
|
||||
static KList<CNG> getLayerSeaHeightGenerators(IrisBiome biome, RNG rng, IrisData data) {
|
||||
AtomicCache<KList<CNG>> cache = biome.getLayerSeaHeightGenerators();
|
||||
KList<CNG> cached = cache.getIfPresent();
|
||||
|
||||
if (cached != null) {
|
||||
return cached;
|
||||
}
|
||||
|
||||
return cache.aquire(() ->
|
||||
{
|
||||
KList<CNG> layerSeaHeightGenerators = new KList<>();
|
||||
|
||||
int m = 7735;
|
||||
|
||||
for (IrisBiomePaletteLayer i : biome.getSeaLayers()) {
|
||||
layerSeaHeightGenerators.add(i.getHeightGenerator(rng.nextParallelRNG((m++) * m * m * m), data));
|
||||
private static void appendLayer(KList<PlatformBlockState> blocks, IrisBiomePaletteLayer layer,
|
||||
int layerIndex, int thickness, double x, double z,
|
||||
RNG random, int maxDepth, IrisData data) {
|
||||
double zoom = layer.getZoom();
|
||||
for (int offset = 0; offset < thickness && blocks.size() < maxDepth; offset++) {
|
||||
try {
|
||||
blocks.add(layer.get(random, layerIndex + offset,
|
||||
(x + offset) / zoom, offset, (z - offset) / zoom, data));
|
||||
} catch (Throwable error) {
|
||||
IrisLogging.reportError(error);
|
||||
}
|
||||
|
||||
return layerSeaHeightGenerators;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
static PlatformBlockState getSurfaceBlock(IrisBiome biome, int x, int z, RNG rng, IrisData idm) {
|
||||
|
||||
Reference in new issue
Block a user