mirror of
https://github.com/VolmitSoftware/Iris.git
synced 2026-10-27 06:20:02 +00:00
Surface settings v2
- Replace hydraulics, ridge tunnel, branching and inset ranges with channel, banks, flow and mouth configs - Add routing cost weights, underground mouth leveling, bank biomes and bank multiplier - Map the new schema into planner settings and derive refinement spacing
This commit is contained in:
1 parent
48afa0d93f
commit
915cc1a2f0
37 files changed
+528
-291
No files matched your search
@@ -48,7 +48,7 @@ final class PackHydrologyValidator {
|
||||
"surfaceBiomes",
|
||||
"mouthBiomes",
|
||||
"shoreBiomes",
|
||||
"dryBiomes",
|
||||
"bankBiomes",
|
||||
"floodedCaveBiomes"
|
||||
);
|
||||
private static final List<String> REGION_BIOME_FIELDS = List.of(
|
||||
|
||||
@@ -20,7 +20,7 @@ public record HydrologyColumnLayer(
|
||||
String surfaceBiomeKey,
|
||||
String mouthBiomeKey,
|
||||
String shoreBiomeKey,
|
||||
String dryBiomeKey,
|
||||
String bankBiomeKey,
|
||||
String floodedCaveBiomeKey
|
||||
) {
|
||||
public HydrologyColumnLayer {
|
||||
@@ -29,7 +29,7 @@ public record HydrologyColumnLayer(
|
||||
surfaceBiomeKey = requireKey(surfaceBiomeKey, "surfaceBiomeKey");
|
||||
mouthBiomeKey = requireKey(mouthBiomeKey, "mouthBiomeKey");
|
||||
shoreBiomeKey = requireKey(shoreBiomeKey, "shoreBiomeKey");
|
||||
dryBiomeKey = requireKey(dryBiomeKey, "dryBiomeKey");
|
||||
bankBiomeKey = requireKey(bankBiomeKey, "bankBiomeKey");
|
||||
floodedCaveBiomeKey = requireKey(floodedCaveBiomeKey, "floodedCaveBiomeKey");
|
||||
if (channel && bedY > fluidHeadY) {
|
||||
throw new IllegalArgumentException("A channel bed cannot be above its fluid head.");
|
||||
|
||||
@@ -788,7 +788,7 @@ final class HydrologyFootprintCompiler {
|
||||
layer.surfaceBiomeKey(),
|
||||
layer.mouthBiomeKey(),
|
||||
layer.shoreBiomeKey(),
|
||||
layer.dryBiomeKey(),
|
||||
layer.bankBiomeKey(),
|
||||
layer.floodedCaveBiomeKey()
|
||||
);
|
||||
}
|
||||
@@ -2121,7 +2121,7 @@ final class HydrologyFootprintCompiler {
|
||||
layer.surfaceBiomeKey(),
|
||||
layer.mouthBiomeKey(),
|
||||
layer.shoreBiomeKey(),
|
||||
layer.dryBiomeKey(),
|
||||
layer.bankBiomeKey(),
|
||||
layer.floodedCaveBiomeKey()
|
||||
);
|
||||
}
|
||||
@@ -2232,7 +2232,7 @@ final class HydrologyFootprintCompiler {
|
||||
terrain.surfaceBiomeKey(),
|
||||
terrain.mouthBiomeKey(),
|
||||
terrain.shoreBiomeKey(),
|
||||
terrain.dryBiomeKey(),
|
||||
terrain.bankBiomeKey(),
|
||||
terrain.floodedCaveBiomeKey()
|
||||
);
|
||||
}
|
||||
@@ -2443,7 +2443,7 @@ final class HydrologyFootprintCompiler {
|
||||
terrain.surfaceBiomeKey(),
|
||||
terrain.mouthBiomeKey(),
|
||||
terrain.shoreBiomeKey(),
|
||||
terrain.dryBiomeKey(),
|
||||
terrain.bankBiomeKey(),
|
||||
terrain.floodedCaveBiomeKey()
|
||||
);
|
||||
addLayer(columns, x, z, terrain, layer);
|
||||
@@ -3655,7 +3655,7 @@ final class HydrologyFootprintCompiler {
|
||||
first.surfaceBiomeKey(),
|
||||
first.mouthBiomeKey(),
|
||||
first.shoreBiomeKey(),
|
||||
first.dryBiomeKey(),
|
||||
first.bankBiomeKey(),
|
||||
first.floodedCaveBiomeKey()
|
||||
);
|
||||
}
|
||||
|
||||
@@ -12,7 +12,7 @@ public record HydrologyPlannerSettings(
|
||||
Geometry geometry,
|
||||
List<DeepFluid> deepFluids
|
||||
) {
|
||||
private static final long PLAN_FORMAT_REVISION = 5L;
|
||||
private static final long PLAN_FORMAT_REVISION = 6L;
|
||||
private static final int MAXIMUM_CROSS_TILE_COLOR_PERIOD = 4;
|
||||
|
||||
public HydrologyPlannerSettings {
|
||||
@@ -36,7 +36,7 @@ public record HydrologyPlannerSettings(
|
||||
return new HydrologyPlannerSettings(
|
||||
63,
|
||||
new Routing(2048, 64, 8, 8192, 8192, new Branching(384, 192), 1.5D, 24D, 2D, 0.2D),
|
||||
new Surface(true, surfaceSources, 4, 8, 1, 4, 3, 7, 6, 2, 10, 24, true, 192, 10),
|
||||
new Surface(true, surfaceSources, 4, 8, 2, 4, 1, 1, 10, 1.5D, 4, 32, false, 1, 1, Banks.defaults()),
|
||||
new Hydraulics(80, 180, 1, 7, 24, 8),
|
||||
new Underground(true, undergroundSources, -48, 72, 3, 8, 1, 3, 6, 14, true),
|
||||
new Outlets(
|
||||
@@ -97,8 +97,9 @@ public record HydrologyPlannerSettings(
|
||||
int radius = 0;
|
||||
int routeDisplacement = Math.multiplyExact(routing.sampleSpacing(), 3);
|
||||
if (surface.enabled() && surface.sources().enabled()) {
|
||||
int blendWidth = Math.max(surface.maximumTerrainBlendWidth(), surface.banks().maximumBlendWidth());
|
||||
int surfaceRadius = (int) StrictMath.ceil(
|
||||
surface.maximumWidth() / 2D + surface.shoreWidth() + surface.maximumTerrainBlendWidth()
|
||||
surface.maximumWidth() / 2D + surface.shoreWidth() + blendWidth
|
||||
);
|
||||
surfaceRadius = Math.max(
|
||||
surfaceRadius,
|
||||
@@ -228,11 +229,12 @@ public record HydrologyPlannerSettings(
|
||||
int maximumTerrainBlendWidth,
|
||||
boolean ridgeTunnelsEnabled,
|
||||
int maximumRidgeTunnelLength,
|
||||
int ridgeTunnelHeadroom
|
||||
int ridgeTunnelHeadroom,
|
||||
Banks banks
|
||||
) {
|
||||
public Surface {
|
||||
if (sources == null) {
|
||||
throw new IllegalArgumentException("Surface source settings are required.");
|
||||
if (sources == null || banks == null) {
|
||||
throw new IllegalArgumentException("Surface source and bank settings are required.");
|
||||
}
|
||||
requireRange(minimumWidth, maximumWidth, 1, 256, "surface width");
|
||||
requireRange(minimumDepth, maximumDepth, 1, 64, "surface depth");
|
||||
@@ -247,6 +249,37 @@ public record HydrologyPlannerSettings(
|
||||
}
|
||||
}
|
||||
|
||||
public record Banks(
|
||||
int inset,
|
||||
int freeboard,
|
||||
double blendSlope,
|
||||
int minimumBlendWidth,
|
||||
int maximumBlendWidth,
|
||||
double roughness,
|
||||
int roughnessWavelength,
|
||||
int cascadeRun,
|
||||
int waterfallMinimumDrop,
|
||||
double mouthFlareRatio,
|
||||
boolean exposeCutStrata
|
||||
) {
|
||||
public Banks {
|
||||
if (inset < 1 || inset > 16 || freeboard < 1 || freeboard > 8
|
||||
|| !Double.isFinite(blendSlope) || blendSlope < 1D || blendSlope > 16D
|
||||
|| minimumBlendWidth < 1 || maximumBlendWidth < minimumBlendWidth || maximumBlendWidth > 128
|
||||
|| !Double.isFinite(roughness) || roughness < 0D || roughness > 1D
|
||||
|| roughnessWavelength < 3 || roughnessWavelength > 128
|
||||
|| cascadeRun < 1 || cascadeRun > 16
|
||||
|| waterfallMinimumDrop < 2 || waterfallMinimumDrop > 24
|
||||
|| !Double.isFinite(mouthFlareRatio) || mouthFlareRatio < 1D || mouthFlareRatio > 4D) {
|
||||
throw new IllegalArgumentException("Surface bank settings are invalid.");
|
||||
}
|
||||
}
|
||||
|
||||
public static Banks defaults() {
|
||||
return new Banks(1, 1, 3D, 4, 32, 0.25D, 16, 2, 6, 1.6D, true);
|
||||
}
|
||||
}
|
||||
|
||||
public record Hydraulics(
|
||||
int minimumTargetPoolLength,
|
||||
int maximumTargetPoolLength,
|
||||
|
||||
@@ -22,11 +22,12 @@ public record HydrologyTerrainSample(
|
||||
double depthMultiplier,
|
||||
double incisionMultiplier,
|
||||
double routingMultiplier,
|
||||
double bankMultiplier,
|
||||
String parentBiomeKey,
|
||||
String surfaceBiomeKey,
|
||||
String mouthBiomeKey,
|
||||
String shoreBiomeKey,
|
||||
String dryBiomeKey,
|
||||
String bankBiomeKey,
|
||||
String floodedCaveBiomeKey,
|
||||
List<String> preferredProfileKeys
|
||||
) {
|
||||
@@ -39,6 +40,7 @@ public record HydrologyTerrainSample(
|
||||
requireFinitePositive(depthMultiplier, "depthMultiplier");
|
||||
requireFiniteNonNegative(incisionMultiplier, "incisionMultiplier");
|
||||
requireFiniteNonNegative(routingMultiplier, "routingMultiplier");
|
||||
requireFinitePositive(bankMultiplier, "bankMultiplier");
|
||||
if (caveAvailable && (caveFluidY <= caveFloorY || caveFluidY >= naturalHeight)) {
|
||||
throw new IllegalArgumentException("Available cave fluid must be above its floor and below natural terrain.");
|
||||
}
|
||||
@@ -46,7 +48,7 @@ public record HydrologyTerrainSample(
|
||||
surfaceBiomeKey = normalizeKey(surfaceBiomeKey, parentBiomeKey);
|
||||
mouthBiomeKey = normalizeKey(mouthBiomeKey, surfaceBiomeKey);
|
||||
shoreBiomeKey = normalizeKey(shoreBiomeKey, parentBiomeKey);
|
||||
dryBiomeKey = normalizeKey(dryBiomeKey, parentBiomeKey);
|
||||
bankBiomeKey = normalizeKey(bankBiomeKey, parentBiomeKey);
|
||||
floodedCaveBiomeKey = normalizeKey(floodedCaveBiomeKey, surfaceBiomeKey);
|
||||
preferredProfileKeys = normalizeProfiles(preferredProfileKeys);
|
||||
}
|
||||
@@ -72,6 +74,7 @@ public record HydrologyTerrainSample(
|
||||
1D,
|
||||
1D,
|
||||
1D,
|
||||
1D,
|
||||
parentBiomeKey,
|
||||
parentBiomeKey,
|
||||
parentBiomeKey,
|
||||
@@ -103,6 +106,7 @@ public record HydrologyTerrainSample(
|
||||
1D,
|
||||
1D,
|
||||
1D,
|
||||
1D,
|
||||
parentBiomeKey,
|
||||
parentBiomeKey,
|
||||
parentBiomeKey,
|
||||
@@ -134,11 +138,12 @@ public record HydrologyTerrainSample(
|
||||
depthMultiplier,
|
||||
incisionMultiplier,
|
||||
routingMultiplier,
|
||||
bankMultiplier,
|
||||
parentBiomeKey,
|
||||
surfaceBiomeKey,
|
||||
mouthBiomeKey,
|
||||
shoreBiomeKey,
|
||||
dryBiomeKey,
|
||||
bankBiomeKey,
|
||||
floodedCaveBiomeKey,
|
||||
preferredProfileKeys
|
||||
);
|
||||
|
||||
+4
-3
@@ -14,12 +14,13 @@ public record EffectiveRiverPolicy(
|
||||
List<String> surfaceBiomes,
|
||||
List<String> mouthBiomes,
|
||||
List<String> shoreBiomes,
|
||||
List<String> dryBiomes,
|
||||
List<String> bankBiomes,
|
||||
List<String> floodedCaveBiomes,
|
||||
double widthMultiplier,
|
||||
double depthMultiplier,
|
||||
double incisionMultiplier,
|
||||
double routingMultiplier
|
||||
double routingMultiplier,
|
||||
double bankMultiplier
|
||||
) {
|
||||
public EffectiveRiverPolicy {
|
||||
placement = Objects.requireNonNull(placement);
|
||||
@@ -28,7 +29,7 @@ public record EffectiveRiverPolicy(
|
||||
surfaceBiomes = List.copyOf(surfaceBiomes);
|
||||
mouthBiomes = List.copyOf(mouthBiomes);
|
||||
shoreBiomes = List.copyOf(shoreBiomes);
|
||||
dryBiomes = List.copyOf(dryBiomes);
|
||||
bankBiomes = List.copyOf(bankBiomes);
|
||||
floodedCaveBiomes = List.copyOf(floodedCaveBiomes);
|
||||
}
|
||||
|
||||
|
||||
+10
-5
@@ -41,12 +41,13 @@ public final class RiverPolicyResolver {
|
||||
private List<String> surfaceBiomes = List.of();
|
||||
private List<String> mouthBiomes = List.of();
|
||||
private List<String> shoreBiomes = List.of();
|
||||
private List<String> dryBiomes = List.of();
|
||||
private List<String> bankBiomes = List.of();
|
||||
private List<String> floodedCaveBiomes = List.of();
|
||||
private double widthMultiplier = 1D;
|
||||
private double depthMultiplier = 1D;
|
||||
private double incisionMultiplier = 1D;
|
||||
private double routingMultiplier = 1D;
|
||||
private double bankMultiplier = 1D;
|
||||
|
||||
private void apply(IrisRiverPolicy policy) {
|
||||
if (policy == null) {
|
||||
@@ -73,8 +74,8 @@ public final class RiverPolicyResolver {
|
||||
if (policy.getShoreBiomes() != null) {
|
||||
shoreBiomes = List.copyOf(policy.getShoreBiomes());
|
||||
}
|
||||
if (policy.getDryBiomes() != null) {
|
||||
dryBiomes = List.copyOf(policy.getDryBiomes());
|
||||
if (policy.getBankBiomes() != null) {
|
||||
bankBiomes = List.copyOf(policy.getBankBiomes());
|
||||
}
|
||||
if (policy.getFloodedCaveBiomes() != null) {
|
||||
floodedCaveBiomes = List.copyOf(policy.getFloodedCaveBiomes());
|
||||
@@ -91,6 +92,9 @@ public final class RiverPolicyResolver {
|
||||
if (policy.getRoutingMultiplier() != null) {
|
||||
routingMultiplier = policy.getRoutingMultiplier();
|
||||
}
|
||||
if (policy.getBankMultiplier() != null) {
|
||||
bankMultiplier = policy.getBankMultiplier();
|
||||
}
|
||||
}
|
||||
|
||||
private EffectiveRiverPolicy build() {
|
||||
@@ -102,12 +106,13 @@ public final class RiverPolicyResolver {
|
||||
surfaceBiomes,
|
||||
mouthBiomes,
|
||||
shoreBiomes,
|
||||
dryBiomes,
|
||||
bankBiomes,
|
||||
floodedCaveBiomes,
|
||||
widthMultiplier,
|
||||
depthMultiplier,
|
||||
incisionMultiplier,
|
||||
routingMultiplier
|
||||
routingMultiplier,
|
||||
bankMultiplier
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
+72
-44
@@ -30,7 +30,6 @@ import art.arcane.iris.engine.object.IrisRiverGrottoConfig;
|
||||
import art.arcane.iris.engine.object.IrisRiverChannelShapeConfig;
|
||||
import art.arcane.iris.engine.object.IrisRiverDropShapeConfig;
|
||||
import art.arcane.iris.engine.object.IrisRiverGeometryConfig;
|
||||
import art.arcane.iris.engine.object.IrisRiverHydraulicsConfig;
|
||||
import art.arcane.iris.engine.object.IrisRiverHydrology;
|
||||
import art.arcane.iris.engine.object.IrisRiverInlandOutlet;
|
||||
import art.arcane.iris.engine.object.IrisRiverMeanderConfig;
|
||||
@@ -38,7 +37,9 @@ import art.arcane.iris.engine.object.IrisRiverProfile;
|
||||
import art.arcane.iris.engine.object.IrisRiverRoutingConfig;
|
||||
import art.arcane.iris.engine.object.IrisRiverRoutingMode;
|
||||
import art.arcane.iris.engine.object.IrisStyledRange;
|
||||
import art.arcane.iris.engine.object.IrisSurfaceRiverBankConfig;
|
||||
import art.arcane.iris.engine.object.IrisSurfaceRiverChannelConfig;
|
||||
import art.arcane.iris.engine.object.IrisSurfaceRiverFlowConfig;
|
||||
import art.arcane.iris.engine.object.IrisSurfaceRiverConfig;
|
||||
import art.arcane.iris.engine.object.IrisSurfaceRiverSourceConfig;
|
||||
import art.arcane.iris.engine.object.IrisUndergroundRiverConfig;
|
||||
@@ -463,11 +464,12 @@ public final class IrisHydrologyRuntime implements AutoCloseable {
|
||||
policy.depthMultiplier(),
|
||||
policy.incisionMultiplier(),
|
||||
policy.routingMultiplier() * routingPreference,
|
||||
policy.bankMultiplier(),
|
||||
parentBiomeKey,
|
||||
selectKey(policy.surfaceBiomes(), parentBiomeKey, biomePatchNoise, 1),
|
||||
selectKey(policy.mouthBiomes(), parentBiomeKey, biomePatchNoise, 2),
|
||||
selectKey(policy.shoreBiomes(), parentBiomeKey, biomePatchNoise, 3),
|
||||
selectKey(policy.dryBiomes(), parentBiomeKey, biomePatchNoise, 4),
|
||||
selectKey(policy.bankBiomes(), parentBiomeKey, biomePatchNoise, 4),
|
||||
selectKey(policy.floodedCaveBiomes(), parentBiomeKey, biomePatchNoise, 5),
|
||||
profiles
|
||||
);
|
||||
@@ -556,21 +558,13 @@ public final class IrisHydrologyRuntime implements AutoCloseable {
|
||||
IrisRiverHydrology rivers = hydrology.getRivers();
|
||||
IrisSurfaceRiverConfig surface = rivers.getSurface();
|
||||
IrisSurfaceRiverChannelConfig channel = surface.getChannel();
|
||||
IrisRiverHydraulicsConfig hydraulics = surface.getHydraulics();
|
||||
IrisSurfaceRiverBankConfig banks = surface.getBanks();
|
||||
IrisUndergroundRiverConfig underground = rivers.getUnderground();
|
||||
ProceduralStream<Double> surfaceWidth = styledStream(context, channel.getWidth(), SURFACE_WIDTH_SALT);
|
||||
ProceduralStream<Double> surfaceDepth = styledStream(context, channel.getDepth(), SURFACE_DEPTH_SALT);
|
||||
ProceduralStream<Double> surfaceInset = styledStream(context, channel.getSurfaceInset(), SURFACE_INSET_SALT);
|
||||
ProceduralStream<Double> surfaceBlend = styledStream(
|
||||
context,
|
||||
channel.getTerrainBlendWidth(),
|
||||
SURFACE_BLEND_SALT
|
||||
);
|
||||
ProceduralStream<Double> targetPool = styledStream(
|
||||
context,
|
||||
hydraulics.getTargetPoolLength(),
|
||||
TARGET_POOL_SALT
|
||||
);
|
||||
ProceduralStream<Double> surfaceInset = ProceduralStream.ofDouble((x, z) -> (double) channel.getInset());
|
||||
ProceduralStream<Double> surfaceBlend = ProceduralStream.ofDouble((x, z) -> (double) banks.getMaximumBlendWidth());
|
||||
ProceduralStream<Double> targetPool = ProceduralStream.ofDouble((x, z) -> 128D);
|
||||
ProceduralStream<Double> undergroundLevel = styledStream(
|
||||
context,
|
||||
underground.getFluidLevel(),
|
||||
@@ -646,10 +640,12 @@ public final class IrisHydrologyRuntime implements AutoCloseable {
|
||||
IrisSurfaceRiverConfig surface = rivers.getSurface();
|
||||
IrisSurfaceRiverSourceConfig surfaceSources = surface.getSources();
|
||||
IrisSurfaceRiverChannelConfig channel = surface.getChannel();
|
||||
IrisRiverHydraulicsConfig hydraulics = surface.getHydraulics();
|
||||
IrisSurfaceRiverBankConfig banks = surface.getBanks();
|
||||
IrisSurfaceRiverFlowConfig flow = surface.getFlow();
|
||||
IrisUndergroundRiverConfig underground = rivers.getUnderground();
|
||||
IrisUndergroundRiverSourceConfig undergroundSources = underground.getSources();
|
||||
int routeNodes = maximumRouteNodes(routing);
|
||||
int refinementSpacing = refinementSpacing(routing.getSampleSpacing());
|
||||
int minimumWorldY = dimension.getMinHeight();
|
||||
boolean riversEnabled = rivers.isEnabled();
|
||||
boolean surfaceEnabled = riversEnabled && surface.isEnabled();
|
||||
@@ -657,17 +653,17 @@ public final class IrisHydrologyRuntime implements AutoCloseable {
|
||||
HydrologyPlannerSettings.Routing plannerRouting = new HydrologyPlannerSettings.Routing(
|
||||
routing.getTileSize(),
|
||||
routing.getSampleSpacing(),
|
||||
routing.getRefinementSpacing(),
|
||||
refinementSpacing,
|
||||
routeNodes,
|
||||
routing.getMaximumRouteLength(),
|
||||
new HydrologyPlannerSettings.Branching(
|
||||
routing.getBranching().getMinimumSurfaceCourseLength(),
|
||||
routing.getBranching().getMinimumUndergroundCourseLength()
|
||||
routing.getMinimumSurfaceCourseLength(),
|
||||
routing.getMinimumUndergroundCourseLength()
|
||||
),
|
||||
1.5D,
|
||||
24D,
|
||||
2D,
|
||||
0.2D
|
||||
routing.getValleyPreference(),
|
||||
routing.getUphillPenalty(),
|
||||
routing.getSlopePenalty(),
|
||||
routing.getConfluenceAttraction()
|
||||
);
|
||||
HydrologyPlannerSettings.Source plannerSurfaceSources = new HydrologyPlannerSettings.Source(
|
||||
surfaceEnabled,
|
||||
@@ -684,23 +680,36 @@ public final class IrisHydrologyRuntime implements AutoCloseable {
|
||||
maximumInt(channel.getWidth()),
|
||||
minimumInt(channel.getDepth()),
|
||||
maximumInt(channel.getDepth()),
|
||||
minimumInt(channel.getSurfaceInset()),
|
||||
maximumInt(channel.getSurfaceInset()),
|
||||
channel.getInset(),
|
||||
channel.getInset(),
|
||||
channel.getMaximumIncision(),
|
||||
channel.getShoreWidth(),
|
||||
minimumInt(channel.getTerrainBlendWidth()),
|
||||
maximumInt(channel.getTerrainBlendWidth()),
|
||||
surface.getRidgeTunnels().isEnabled(),
|
||||
surface.getRidgeTunnels().getMaximumLength(),
|
||||
surface.getRidgeTunnels().getHeadroom()
|
||||
banks.getShoreWidth(),
|
||||
banks.getMinimumBlendWidth(),
|
||||
banks.getMaximumBlendWidth(),
|
||||
false,
|
||||
1,
|
||||
1,
|
||||
new HydrologyPlannerSettings.Banks(
|
||||
channel.getInset(),
|
||||
banks.getFreeboard(),
|
||||
banks.getBlendSlope(),
|
||||
banks.getMinimumBlendWidth(),
|
||||
banks.getMaximumBlendWidth(),
|
||||
channel.getRoughness(),
|
||||
channel.getRoughnessWavelength(),
|
||||
flow.getCascadeRun(),
|
||||
flow.getWaterfallMinimumDrop(),
|
||||
surface.getMouths().getFlareRatio(),
|
||||
banks.isExposeCutStrata()
|
||||
)
|
||||
);
|
||||
HydrologyPlannerSettings.Hydraulics plannerHydraulics = new HydrologyPlannerSettings.Hydraulics(
|
||||
minimumInt(hydraulics.getTargetPoolLength()),
|
||||
maximumInt(hydraulics.getTargetPoolLength()),
|
||||
hydraulics.getRiffleDrop(),
|
||||
hydraulics.getMaximumGradualDrop(),
|
||||
hydraulics.getMaximumGradualLength(),
|
||||
hydraulics.getWaterfallMinimumDrop()
|
||||
80,
|
||||
180,
|
||||
1,
|
||||
flow.getWaterfallMinimumDrop() - 1,
|
||||
24,
|
||||
flow.getWaterfallMinimumDrop()
|
||||
);
|
||||
HydrologyPlannerSettings.Source plannerUndergroundSources = new HydrologyPlannerSettings.Source(
|
||||
undergroundEnabled,
|
||||
@@ -736,11 +745,19 @@ public final class IrisHydrologyRuntime implements AutoCloseable {
|
||||
inland.getHeadroom(), inland.getMaximumVolume()),
|
||||
inlandEnabled && inland.isConnectSurfaceRivers(),
|
||||
Math.max(4, coastal.getVerticalRadius()),
|
||||
surface.getMouths().getLevelingDistance(),
|
||||
underground.getMouthLevelingDistance(),
|
||||
surface.getMouths().getMaximumOceanApron(),
|
||||
routing.getMaximumOutletsPerTile()
|
||||
);
|
||||
HydrologyPlannerSettings.Geometry plannerGeometry = geometry(rivers.getGeometry());
|
||||
HydrologyPlannerSettings.Geometry plannerGeometry = geometry(
|
||||
rivers.getGeometry(),
|
||||
new HydrologyPlannerSettings.ChannelShape(
|
||||
2D,
|
||||
channel.getRoughness(),
|
||||
channel.getRoughness(),
|
||||
channel.getRoughnessWavelength()
|
||||
)
|
||||
);
|
||||
return new HydrologyPlannerSettings(
|
||||
dimension.getFluidHeight(),
|
||||
plannerRouting,
|
||||
@@ -749,11 +766,21 @@ public final class IrisHydrologyRuntime implements AutoCloseable {
|
||||
plannerUnderground,
|
||||
plannerOutlets,
|
||||
plannerGeometry,
|
||||
deepFluids(hydrology.getDeepFluids(), minimumWorldY, routing)
|
||||
deepFluids(hydrology.getDeepFluids(), minimumWorldY, routing, refinementSpacing)
|
||||
);
|
||||
}
|
||||
|
||||
private static HydrologyPlannerSettings.Geometry geometry(IrisRiverGeometryConfig geometry) {
|
||||
static int refinementSpacing(int sampleSpacing) {
|
||||
if (sampleSpacing % 4 == 0) {
|
||||
return 4;
|
||||
}
|
||||
return sampleSpacing % 2 == 0 ? 2 : 1;
|
||||
}
|
||||
|
||||
private static HydrologyPlannerSettings.Geometry geometry(
|
||||
IrisRiverGeometryConfig geometry,
|
||||
HydrologyPlannerSettings.ChannelShape surfaceShape
|
||||
) {
|
||||
IrisRiverMeanderConfig meanders = geometry.getMeanders();
|
||||
IrisRiverDropShapeConfig drops = geometry.getDrops();
|
||||
return new HydrologyPlannerSettings.Geometry(
|
||||
@@ -766,7 +793,7 @@ public final class IrisHydrologyRuntime implements AutoCloseable {
|
||||
meanders.getSmoothingPasses(),
|
||||
meanders.getMaximumTurnDegrees()
|
||||
),
|
||||
channelShape(geometry.getSurface()),
|
||||
surfaceShape,
|
||||
channelShape(geometry.getUnderground()),
|
||||
channelShape(geometry.getGrottos()),
|
||||
new HydrologyPlannerSettings.Drops(
|
||||
@@ -809,7 +836,8 @@ public final class IrisHydrologyRuntime implements AutoCloseable {
|
||||
private static List<HydrologyPlannerSettings.DeepFluid> deepFluids(
|
||||
List<IrisDeepFluidConfig> configurations,
|
||||
int minimumWorldY,
|
||||
IrisRiverRoutingConfig routing
|
||||
IrisRiverRoutingConfig routing,
|
||||
int refinementSpacing
|
||||
) {
|
||||
ArrayList<HydrologyPlannerSettings.DeepFluid> deepFluids = new ArrayList<>();
|
||||
for (IrisDeepFluidConfig configuration : configurations) {
|
||||
@@ -820,7 +848,7 @@ public final class IrisHydrologyRuntime implements AutoCloseable {
|
||||
int maximumChannelLength = maximumDeepChannelLength(configuration, routing);
|
||||
int minimumChannelLength = maximumChannelLength == 0
|
||||
? 0
|
||||
: Math.min(maximumChannelLength, Math.max(routing.getRefinementSpacing(), radius));
|
||||
: Math.min(maximumChannelLength, Math.max(refinementSpacing, radius));
|
||||
deepFluids.add(new HydrologyPlannerSettings.DeepFluid(
|
||||
configuration.getId(),
|
||||
configuration.getDensity() > 0D
|
||||
@@ -855,7 +883,7 @@ public final class IrisHydrologyRuntime implements AutoCloseable {
|
||||
return 0;
|
||||
}
|
||||
int configuredLength = Math.max(
|
||||
routing.getRefinementSpacing(), configuration.getSpacing() / 3);
|
||||
refinementSpacing(routing.getSampleSpacing()), configuration.getSpacing() / 3);
|
||||
return Math.min(configuredLength, routing.getTileSize() / 2);
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -326,7 +326,7 @@ public final class MantleHydrologyComponent extends IrisMantleComponent {
|
||||
+ position + ".");
|
||||
}
|
||||
String biomeKey = action == HydrologyCaveAction.DRY_AIR
|
||||
? layer.dryBiomeKey()
|
||||
? layer.bankBiomeKey()
|
||||
: layer.floodedCaveBiomeKey();
|
||||
PlannedCell candidate = new PlannedCell(
|
||||
new HydrologyCaveCell(action, layer.profileKey(), biomeKey),
|
||||
|
||||
@@ -1,25 +0,0 @@
|
||||
package art.arcane.iris.engine.object;
|
||||
|
||||
import art.arcane.iris.engine.object.annotations.Desc;
|
||||
import art.arcane.iris.engine.object.annotations.MaxNumber;
|
||||
import art.arcane.iris.engine.object.annotations.MinNumber;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
@Accessors(chain = true)
|
||||
@NoArgsConstructor
|
||||
@Desc("Controls minimum complete river lengths before a route is published.")
|
||||
@Data
|
||||
public class IrisRiverBranchingConfig {
|
||||
@MinNumber(0)
|
||||
@MaxNumber(32768)
|
||||
@Desc("Minimum complete surface source-to-outlet route length in blocks.")
|
||||
private int minimumSurfaceCourseLength = 384;
|
||||
|
||||
@MinNumber(0)
|
||||
@MaxNumber(32768)
|
||||
@Desc("Minimum complete underground source-to-outlet route length in blocks.")
|
||||
private int minimumUndergroundCourseLength = 192;
|
||||
|
||||
}
|
||||
@@ -7,21 +7,18 @@ import lombok.experimental.Accessors;
|
||||
|
||||
@Accessors(chain = true)
|
||||
@NoArgsConstructor
|
||||
@Desc("Controls organic river routing, beds, carved walls, and descending water geometry.")
|
||||
@Desc("Controls organic river routing and contained cave geometry.")
|
||||
@Data
|
||||
public class IrisRiverGeometryConfig {
|
||||
@Desc("Surface and underground centerline meanders.")
|
||||
private IrisRiverMeanderConfig meanders = new IrisRiverMeanderConfig();
|
||||
|
||||
@Desc("Surface channel bed and bank shape.")
|
||||
private IrisRiverChannelShapeConfig surface = new IrisRiverChannelShapeConfig();
|
||||
|
||||
@Desc("Underground channel bed and wall shape.")
|
||||
private IrisRiverChannelShapeConfig underground = new IrisRiverChannelShapeConfig();
|
||||
|
||||
@Desc("Grotto pool bed and wall shape.")
|
||||
private IrisRiverChannelShapeConfig grottos = new IrisRiverChannelShapeConfig();
|
||||
|
||||
@Desc("Cascade, cataract, waterfall, and sinkhole descent shape.")
|
||||
@Desc("Underground drop, sinkhole and receiving basin shape.")
|
||||
private IrisRiverDropShapeConfig drops = new IrisRiverDropShapeConfig();
|
||||
}
|
||||
@@ -1,41 +0,0 @@
|
||||
package art.arcane.iris.engine.object;
|
||||
|
||||
import art.arcane.iris.engine.object.annotations.Desc;
|
||||
import art.arcane.iris.engine.object.annotations.MaxNumber;
|
||||
import art.arcane.iris.engine.object.annotations.MinNumber;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
@Accessors(chain = true)
|
||||
@NoArgsConstructor
|
||||
@Desc("Controls deterministic river head transitions and hydraulic segment classification.")
|
||||
@Data
|
||||
public class IrisRiverHydraulicsConfig {
|
||||
@Desc("Target longitudinal length of level pools between head transitions.")
|
||||
private IrisStyledRange targetPoolLength = range(80D, 180D, 1024D);
|
||||
|
||||
@MinNumber(0)
|
||||
@MaxNumber(16)
|
||||
@Desc("Normal one-step head loss represented by a riffle.")
|
||||
private int riffleDrop = 1;
|
||||
|
||||
@MinNumber(0)
|
||||
@MaxNumber(64)
|
||||
@Desc("Largest head loss represented as a gradual cascade.")
|
||||
private int maximumGradualDrop = 7;
|
||||
|
||||
@MinNumber(1)
|
||||
@MaxNumber(1024)
|
||||
@Desc("Largest longitudinal distance used for one gradual cascade transition.")
|
||||
private int maximumGradualLength = 24;
|
||||
|
||||
@MinNumber(1)
|
||||
@MaxNumber(128)
|
||||
@Desc("Minimum required head loss represented by a waterfall.")
|
||||
private int waterfallMinimumDrop = 8;
|
||||
|
||||
private static IrisStyledRange range(double min, double max, double zoom) {
|
||||
return new IrisStyledRange(min, max, new IrisGeneratorStyle(NoiseStyle.IRIS).zoomed(zoom));
|
||||
}
|
||||
}
|
||||
@@ -9,16 +9,16 @@ import lombok.experimental.Accessors;
|
||||
|
||||
@Accessors(chain = true)
|
||||
@NoArgsConstructor
|
||||
@Desc("Controls river leveling before a coastal reservoir and the final ocean footprint.")
|
||||
@Desc("Controls how a surface river meets the sea.")
|
||||
@Data
|
||||
public class IrisRiverMouthConfig {
|
||||
@MinNumber(0)
|
||||
@MaxNumber(2048)
|
||||
@Desc("Distance in blocks over which an ocean-bound river reaches sea level before the coastline.")
|
||||
private int levelingDistance = 64;
|
||||
@MinNumber(1)
|
||||
@MaxNumber(4)
|
||||
@Desc("Width multiplier reached at the coastline over the final stretch of the river.")
|
||||
private double flareRatio = 1.6D;
|
||||
|
||||
@MinNumber(0)
|
||||
@MaxNumber(64)
|
||||
@Desc("Maximum number of blocks the river footprint may enter an ocean reservoir before terminating.")
|
||||
@Desc("Maximum number of blocks the recorded mouth footprint may enter the ocean before terminating.")
|
||||
private int maximumOceanApron = 8;
|
||||
}
|
||||
@@ -47,7 +47,7 @@ public class IrisRiverPolicy {
|
||||
@RegistryListResource(IrisBiome.class)
|
||||
@ArrayType(type = String.class)
|
||||
@Desc("Dry river footprint biome selection. An empty list explicitly clears the inherited selection.")
|
||||
private KList<String> dryBiomes = null;
|
||||
private KList<String> bankBiomes = null;
|
||||
|
||||
@RegistryListResource(IrisBiome.class)
|
||||
@ArrayType(type = String.class)
|
||||
@@ -74,12 +74,17 @@ public class IrisRiverPolicy {
|
||||
@Desc("Multiplier applied to terrain-guided routing cost.")
|
||||
private Double routingMultiplier = null;
|
||||
|
||||
@MinNumber(0.0001)
|
||||
@MaxNumber(16)
|
||||
@Desc("Multiplier applied to the eroded bank width outside the shore band.")
|
||||
private Double bankMultiplier = null;
|
||||
|
||||
public KSet<String> getAllBiomeIds() {
|
||||
KSet<String> biomeIds = new KSet<>();
|
||||
addAll(biomeIds, surfaceBiomes);
|
||||
addAll(biomeIds, mouthBiomes);
|
||||
addAll(biomeIds, shoreBiomes);
|
||||
addAll(biomeIds, dryBiomes);
|
||||
addAll(biomeIds, bankBiomes);
|
||||
addAll(biomeIds, floodedCaveBiomes);
|
||||
return biomeIds;
|
||||
}
|
||||
|
||||
@@ -1,27 +0,0 @@
|
||||
package art.arcane.iris.engine.object;
|
||||
|
||||
import art.arcane.iris.engine.object.annotations.Desc;
|
||||
import art.arcane.iris.engine.object.annotations.MaxNumber;
|
||||
import art.arcane.iris.engine.object.annotations.MinNumber;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
@Accessors(chain = true)
|
||||
@NoArgsConstructor
|
||||
@Desc("Controls short contained ridge bores on otherwise viable surface courses.")
|
||||
@Data
|
||||
public class IrisRiverRidgeTunnelConfig {
|
||||
@Desc("Allow short ridge bores when they preserve the accepted drainage course.")
|
||||
private boolean enabled = true;
|
||||
|
||||
@MinNumber(1)
|
||||
@MaxNumber(4096)
|
||||
@Desc("Maximum accepted ridge-bore length in blocks.")
|
||||
private int maximumLength = 192;
|
||||
|
||||
@MinNumber(1)
|
||||
@MaxNumber(128)
|
||||
@Desc("Dry vertical clearance above the river head inside a ridge bore.")
|
||||
private int headroom = 10;
|
||||
}
|
||||
@@ -24,22 +24,24 @@ public class IrisRiverRoutingConfig {
|
||||
@Desc("Spacing in blocks between terrain samples used to build the drainage graph.")
|
||||
private int sampleSpacing = 64;
|
||||
|
||||
@MinNumber(1)
|
||||
@MaxNumber(64)
|
||||
@Desc("Spacing in blocks used to refine accepted terrain-guided centerlines.")
|
||||
private int refinementSpacing = 8;
|
||||
|
||||
@Desc("Minimum route and tributary lengths used to suppress chopped, clustered branches.")
|
||||
private IrisRiverBranchingConfig branching = new IrisRiverBranchingConfig();
|
||||
|
||||
@MinNumber(256)
|
||||
@MaxNumber(32768)
|
||||
@Desc("Maximum bounded length in blocks of one accepted river route.")
|
||||
private int maximumRouteLength = 16384;
|
||||
|
||||
@MinNumber(0)
|
||||
@MaxNumber(32768)
|
||||
@Desc("Minimum exposed source-to-outlet length in blocks of a published surface river.")
|
||||
private int minimumSurfaceCourseLength = 384;
|
||||
|
||||
@MinNumber(0)
|
||||
@MaxNumber(32768)
|
||||
@Desc("Minimum source-to-outlet length in blocks of a published underground river.")
|
||||
private int minimumUndergroundCourseLength = 192;
|
||||
|
||||
@MinNumber(1)
|
||||
@MaxNumber(256)
|
||||
@Desc("Maximum drainage roots selected per planning tile. Fewer roots produce longer, more strongly branching river trees.")
|
||||
@Desc("Maximum drainage roots selected per planning tile.")
|
||||
private int maximumOutletsPerTile = 4;
|
||||
|
||||
@Desc("Allow rivers to terminate at an ocean reservoir.")
|
||||
@@ -48,4 +50,24 @@ public class IrisRiverRoutingConfig {
|
||||
@ArrayType(type = IrisRiverInlandOutlet.class)
|
||||
@Desc("Contained inland outlet kinds available when no legal ocean outlet is selected.")
|
||||
private KList<IrisRiverInlandOutlet> inlandOutlets = new KList<>();
|
||||
|
||||
@MinNumber(0)
|
||||
@MaxNumber(64)
|
||||
@Desc("How strongly routes prefer lower ground.")
|
||||
private double valleyPreference = 1.5D;
|
||||
|
||||
@MinNumber(0)
|
||||
@MaxNumber(1024)
|
||||
@Desc("Cost per block of rise along a route.")
|
||||
private double uphillPenalty = 24D;
|
||||
|
||||
@MinNumber(0)
|
||||
@MaxNumber(64)
|
||||
@Desc("Cost per unit of terrain slope along a route.")
|
||||
private double slopePenalty = 2D;
|
||||
|
||||
@MinNumber(0)
|
||||
@MaxNumber(16)
|
||||
@Desc("How strongly routes are drawn toward existing drainage.")
|
||||
private double confluenceAttraction = 0.2D;
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
package art.arcane.iris.engine.object;
|
||||
|
||||
import art.arcane.iris.engine.object.annotations.Desc;
|
||||
import art.arcane.iris.engine.object.annotations.MaxNumber;
|
||||
import art.arcane.iris.engine.object.annotations.MinNumber;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
@Accessors(chain = true)
|
||||
@NoArgsConstructor
|
||||
@Desc("Controls the lip, shore band and eroded valley around a surface river.")
|
||||
@Data
|
||||
public class IrisSurfaceRiverBankConfig {
|
||||
@MinNumber(1)
|
||||
@MaxNumber(8)
|
||||
@Desc("Blocks the bank top sits above the water surface at the channel edge.")
|
||||
private int freeboard = 1;
|
||||
|
||||
@MinNumber(0)
|
||||
@MaxNumber(8)
|
||||
@Desc("Width in blocks of the shore band that receives shore biome content.")
|
||||
private double shoreWidth = 1.5D;
|
||||
|
||||
@MinNumber(1)
|
||||
@MaxNumber(16)
|
||||
@Desc("Horizontal run in blocks of eroded bank per block of cut depth.")
|
||||
private double blendSlope = 3D;
|
||||
|
||||
@MinNumber(1)
|
||||
@MaxNumber(64)
|
||||
@Desc("Narrowest eroded band outside the shore, in blocks.")
|
||||
private int minimumBlendWidth = 4;
|
||||
|
||||
@MinNumber(1)
|
||||
@MaxNumber(128)
|
||||
@Desc("Widest eroded band outside the shore, in blocks.")
|
||||
private int maximumBlendWidth = 32;
|
||||
|
||||
@Desc("Show the biome's deeper layers on eroded banks instead of the surface layer.")
|
||||
private boolean exposeCutStrata = true;
|
||||
}
|
||||
+18
-20
@@ -9,39 +9,37 @@ import lombok.experimental.Accessors;
|
||||
|
||||
@Accessors(chain = true)
|
||||
@NoArgsConstructor
|
||||
@Desc("Controls the accepted surface-river terrain and biome footprint.")
|
||||
@Desc("Controls the wet channel of a surface river.")
|
||||
@Data
|
||||
public class IrisSurfaceRiverChannelConfig {
|
||||
@Desc("Wet channel width in blocks.")
|
||||
private IrisStyledRange width = range(4D, 8D, 1024D);
|
||||
|
||||
@Desc("Wet bed depth in blocks.")
|
||||
private IrisStyledRange depth = range(1D, 4D, 768D, 2D);
|
||||
@Desc("Wet bed depth in blocks at the channel center.")
|
||||
private IrisStyledRange depth = range(2D, 4D, 768D);
|
||||
|
||||
@Desc("Vertical distance from the natural terrain corridor to the solved water surface.")
|
||||
private IrisStyledRange surfaceInset = range(3D, 7D, 768D, 2D);
|
||||
@MinNumber(1)
|
||||
@MaxNumber(16)
|
||||
@Desc("Blocks the water surface sits below the lowest natural bank beside the channel.")
|
||||
private int inset = 1;
|
||||
|
||||
@MinNumber(0)
|
||||
@MaxNumber(64)
|
||||
@Desc("Maximum permitted channel incision below natural terrain.")
|
||||
private int maximumIncision = 6;
|
||||
@Desc("Maximum cut below natural terrain at the channel center before a course is rejected.")
|
||||
private int maximumIncision = 10;
|
||||
|
||||
@MinNumber(1)
|
||||
@MaxNumber(2)
|
||||
@Desc("Narrow biome-selection band immediately outside the wet channel.")
|
||||
private double shoreWidth = 2D;
|
||||
@MinNumber(0)
|
||||
@MaxNumber(1)
|
||||
@Desc("Coherent variation of the wet outline and bed as a fraction of the channel size.")
|
||||
private double roughness = 0.25D;
|
||||
|
||||
@Desc("Wider terrain-grading distance outside the shore band.")
|
||||
private IrisStyledRange terrainBlendWidth = range(10D, 24D, 1024D);
|
||||
@MinNumber(3)
|
||||
@MaxNumber(128)
|
||||
@Desc("Wavelength in blocks of the outline and bed variation.")
|
||||
private int roughnessWavelength = 16;
|
||||
|
||||
private static IrisStyledRange range(double min, double max, double zoom) {
|
||||
return range(min, max, zoom, 1D);
|
||||
}
|
||||
|
||||
private static IrisStyledRange range(double min, double max, double zoom, double exponent) {
|
||||
IrisGeneratorStyle style = new IrisGeneratorStyle(NoiseStyle.IRIS)
|
||||
.zoomed(zoom)
|
||||
.setExponent(exponent);
|
||||
IrisGeneratorStyle style = new IrisGeneratorStyle(NoiseStyle.IRIS).zoomed(zoom);
|
||||
return new IrisStyledRange(min, max, style);
|
||||
}
|
||||
}
|
||||
@@ -16,15 +16,15 @@ public class IrisSurfaceRiverConfig {
|
||||
@Desc("Surface-river source allocation.")
|
||||
private IrisSurfaceRiverSourceConfig sources = new IrisSurfaceRiverSourceConfig();
|
||||
|
||||
@Desc("Surface channel and surrounding terrain footprint.")
|
||||
@Desc("Wet channel width, depth, inset and roughness.")
|
||||
private IrisSurfaceRiverChannelConfig channel = new IrisSurfaceRiverChannelConfig();
|
||||
|
||||
@Desc("Pool, riffle, cascade, and waterfall classification thresholds.")
|
||||
private IrisRiverHydraulicsConfig hydraulics = new IrisRiverHydraulicsConfig();
|
||||
@Desc("Lip, shore band and eroded valley around the channel.")
|
||||
private IrisSurfaceRiverBankConfig banks = new IrisSurfaceRiverBankConfig();
|
||||
|
||||
@Desc("Short ridge-bore configuration for otherwise viable surface routes.")
|
||||
private IrisRiverRidgeTunnelConfig ridgeTunnels = new IrisRiverRidgeTunnelConfig();
|
||||
@Desc("Cascade and waterfall thresholds.")
|
||||
private IrisSurfaceRiverFlowConfig flow = new IrisSurfaceRiverFlowConfig();
|
||||
|
||||
@Desc("Coastal mouth leveling and ocean-apron limits.")
|
||||
@Desc("Coastal mouth flare and ocean-apron limits.")
|
||||
private IrisRiverMouthConfig mouths = new IrisRiverMouthConfig();
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
package art.arcane.iris.engine.object;
|
||||
|
||||
import art.arcane.iris.engine.object.annotations.Desc;
|
||||
import art.arcane.iris.engine.object.annotations.MaxNumber;
|
||||
import art.arcane.iris.engine.object.annotations.MinNumber;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
@Accessors(chain = true)
|
||||
@NoArgsConstructor
|
||||
@Desc("Controls how a surface river descends.")
|
||||
@Data
|
||||
public class IrisSurfaceRiverFlowConfig {
|
||||
@MinNumber(1)
|
||||
@MaxNumber(16)
|
||||
@Desc("Shortest level run in blocks between one-block steps before consecutive steps are labelled a cascade.")
|
||||
private int cascadeRun = 2;
|
||||
|
||||
@MinNumber(2)
|
||||
@MaxNumber(24)
|
||||
@Desc("Smallest natural cliff in blocks that becomes a waterfall instead of a cascade.")
|
||||
private int waterfallMinimumDrop = 6;
|
||||
}
|
||||
@@ -1,6 +1,8 @@
|
||||
package art.arcane.iris.engine.object;
|
||||
|
||||
import art.arcane.iris.engine.object.annotations.Desc;
|
||||
import art.arcane.iris.engine.object.annotations.MaxNumber;
|
||||
import art.arcane.iris.engine.object.annotations.MinNumber;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.experimental.Accessors;
|
||||
@@ -31,6 +33,11 @@ public class IrisUndergroundRiverConfig {
|
||||
@Desc("Allow accepted underground courses to connect transactionally to existing caves.")
|
||||
private boolean connectToExistingCaves = true;
|
||||
|
||||
@MinNumber(0)
|
||||
@MaxNumber(2048)
|
||||
@Desc("Distance in blocks over which an ocean-bound underground river levels to sea level before its mouth.")
|
||||
private int mouthLevelingDistance = 64;
|
||||
|
||||
private static IrisStyledRange range(double min, double max, double zoom) {
|
||||
return new IrisStyledRange(min, max, new IrisGeneratorStyle(NoiseStyle.IRIS).zoomed(zoom));
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user