diff --git a/core/src/main/java/art/arcane/iris/core/pack/PackHydrologyValidator.java b/core/src/main/java/art/arcane/iris/core/pack/PackHydrologyValidator.java index b3c965aa7..91f48d797 100644 --- a/core/src/main/java/art/arcane/iris/core/pack/PackHydrologyValidator.java +++ b/core/src/main/java/art/arcane/iris/core/pack/PackHydrologyValidator.java @@ -186,6 +186,10 @@ final class PackHydrologyValidator { SourceBudget undergroundBudget = underground == null ? SourceBudget.defaults() : validateUnderground(path + ".underground", underground, dimension, errors, warnings); + if (underground != null + && integerValue(underground, "mouthLevelingDistance", 64) > routingValues.maximumRouteLength()) { + errors.add(path + ".underground.mouthLevelingDistance must not exceed routing.maximumRouteLength."); + } if (grottos != null) { validateGrottos(path + ".grottos", grottos, routingValues, errors); } diff --git a/core/src/main/java/art/arcane/iris/engine/object/IrisRiverMouthConfig.java b/core/src/main/java/art/arcane/iris/engine/object/IrisRiverMouthConfig.java index 0a9126550..d7a61ac0b 100644 --- a/core/src/main/java/art/arcane/iris/engine/object/IrisRiverMouthConfig.java +++ b/core/src/main/java/art/arcane/iris/engine/object/IrisRiverMouthConfig.java @@ -18,7 +18,7 @@ public class IrisRiverMouthConfig { private double flareRatio = 1.6D; @MinNumber(0) - @MaxNumber(64) + @MaxNumber(32) @Desc("Maximum number of blocks the recorded mouth footprint may enter the ocean before terminating.") private int maximumOceanApron = 8; } diff --git a/core/src/main/java/art/arcane/iris/engine/object/IrisRiverPolicy.java b/core/src/main/java/art/arcane/iris/engine/object/IrisRiverPolicy.java index 7700931e3..99d34da5a 100644 --- a/core/src/main/java/art/arcane/iris/engine/object/IrisRiverPolicy.java +++ b/core/src/main/java/art/arcane/iris/engine/object/IrisRiverPolicy.java @@ -74,8 +74,8 @@ public class IrisRiverPolicy { @Desc("Multiplier applied to terrain-guided routing cost.") private Double routingMultiplier = null; - @MinNumber(0.0001) - @MaxNumber(16) + @MinNumber(0) + @MaxNumber(4) @Desc("Multiplier applied to the eroded bank width outside the shore band.") private Double bankMultiplier = null; diff --git a/core/src/main/java/art/arcane/iris/engine/object/IrisRiverRoutingConfig.java b/core/src/main/java/art/arcane/iris/engine/object/IrisRiverRoutingConfig.java index 44d71f825..f19adf4c8 100644 --- a/core/src/main/java/art/arcane/iris/engine/object/IrisRiverRoutingConfig.java +++ b/core/src/main/java/art/arcane/iris/engine/object/IrisRiverRoutingConfig.java @@ -20,7 +20,7 @@ public class IrisRiverRoutingConfig { private int tileSize = 2048; @MinNumber(8) - @MaxNumber(512) + @MaxNumber(64) @Desc("Spacing in blocks between terrain samples used to build the drainage graph.") private int sampleSpacing = 64; @@ -52,22 +52,22 @@ public class IrisRiverRoutingConfig { private KList inlandOutlets = new KList<>(); @MinNumber(0) - @MaxNumber(64) + @MaxNumber(8) @Desc("How strongly routes prefer lower ground.") private double valleyPreference = 1.5D; @MinNumber(0) - @MaxNumber(1024) + @MaxNumber(128) @Desc("Cost per block of rise along a route.") private double uphillPenalty = 24D; @MinNumber(0) - @MaxNumber(64) + @MaxNumber(16) @Desc("Cost per unit of terrain slope along a route.") private double slopePenalty = 2D; @MinNumber(0) - @MaxNumber(16) + @MaxNumber(1) @Desc("How strongly routes are drawn toward existing drainage.") private double confluenceAttraction = 0.2D; } diff --git a/core/src/main/java/art/arcane/iris/engine/object/IrisSurfaceRiverBankConfig.java b/core/src/main/java/art/arcane/iris/engine/object/IrisSurfaceRiverBankConfig.java index 5b82c799a..7127627da 100644 --- a/core/src/main/java/art/arcane/iris/engine/object/IrisSurfaceRiverBankConfig.java +++ b/core/src/main/java/art/arcane/iris/engine/object/IrisSurfaceRiverBankConfig.java @@ -12,18 +12,18 @@ import lombok.experimental.Accessors; @Desc("Controls the lip, shore band and eroded valley around a surface river.") @Data public class IrisSurfaceRiverBankConfig { - @MinNumber(1) - @MaxNumber(8) + @MinNumber(0) + @MaxNumber(4) @Desc("Blocks the bank top sits above the water surface at the channel edge.") private int freeboard = 1; - @MinNumber(0) - @MaxNumber(8) + @MinNumber(0.5) + @MaxNumber(6) @Desc("Width in blocks of the shore band that receives shore biome content.") private double shoreWidth = 1.5D; - @MinNumber(1) - @MaxNumber(16) + @MinNumber(0.5) + @MaxNumber(12) @Desc("Horizontal run in blocks of eroded bank per block of cut depth.") private double blendSlope = 3D; @@ -33,7 +33,7 @@ public class IrisSurfaceRiverBankConfig { private int minimumBlendWidth = 4; @MinNumber(1) - @MaxNumber(128) + @MaxNumber(64) @Desc("Widest eroded band outside the shore, in blocks.") private int maximumBlendWidth = 32; diff --git a/core/src/main/java/art/arcane/iris/engine/object/IrisSurfaceRiverChannelConfig.java b/core/src/main/java/art/arcane/iris/engine/object/IrisSurfaceRiverChannelConfig.java index 7536c4e38..060344bac 100644 --- a/core/src/main/java/art/arcane/iris/engine/object/IrisSurfaceRiverChannelConfig.java +++ b/core/src/main/java/art/arcane/iris/engine/object/IrisSurfaceRiverChannelConfig.java @@ -18,13 +18,13 @@ public class IrisSurfaceRiverChannelConfig { @Desc("Wet bed depth in blocks at the channel center.") private IrisStyledRange depth = range(2D, 4D, 768D); - @MinNumber(1) - @MaxNumber(16) + @MinNumber(0) + @MaxNumber(3) @Desc("Blocks the water surface sits below the lowest natural bank beside the channel.") private int inset = 1; - @MinNumber(0) - @MaxNumber(64) + @MinNumber(1) + @MaxNumber(32) @Desc("Maximum cut below natural terrain at the channel center before a course is rejected.") private int maximumIncision = 10; @@ -33,8 +33,8 @@ public class IrisSurfaceRiverChannelConfig { @Desc("Coherent variation of the wet outline and bed as a fraction of the channel size.") private double roughness = 0.25D; - @MinNumber(3) - @MaxNumber(128) + @MinNumber(4) + @MaxNumber(64) @Desc("Wavelength in blocks of the outline and bed variation.") private int roughnessWavelength = 16; diff --git a/core/src/main/java/art/arcane/iris/engine/object/IrisSurfaceRiverFlowConfig.java b/core/src/main/java/art/arcane/iris/engine/object/IrisSurfaceRiverFlowConfig.java index 9afd67a88..1b45bb68c 100644 --- a/core/src/main/java/art/arcane/iris/engine/object/IrisSurfaceRiverFlowConfig.java +++ b/core/src/main/java/art/arcane/iris/engine/object/IrisSurfaceRiverFlowConfig.java @@ -13,12 +13,12 @@ import lombok.experimental.Accessors; @Data public class IrisSurfaceRiverFlowConfig { @MinNumber(1) - @MaxNumber(16) + @MaxNumber(8) @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) + @MaxNumber(32) @Desc("Smallest natural cliff in blocks that becomes a waterfall instead of a cascade.") private int waterfallMinimumDrop = 6; } diff --git a/core/src/main/java/art/arcane/iris/engine/object/IrisUndergroundRiverConfig.java b/core/src/main/java/art/arcane/iris/engine/object/IrisUndergroundRiverConfig.java index 576fa52a3..a2aca6c52 100644 --- a/core/src/main/java/art/arcane/iris/engine/object/IrisUndergroundRiverConfig.java +++ b/core/src/main/java/art/arcane/iris/engine/object/IrisUndergroundRiverConfig.java @@ -33,8 +33,8 @@ public class IrisUndergroundRiverConfig { @Desc("Allow accepted underground courses to connect transactionally to existing caves.") private boolean connectToExistingCaves = true; - @MinNumber(0) - @MaxNumber(2048) + @MinNumber(16) + @MaxNumber(512) @Desc("Distance in blocks over which an ocean-bound underground river levels to sea level before its mouth.") private int mouthLevelingDistance = 64; diff --git a/core/src/test/java/art/arcane/iris/core/pack/PackHydrologyValidatorTest.java b/core/src/test/java/art/arcane/iris/core/pack/PackHydrologyValidatorTest.java index c748f7889..121c06330 100644 --- a/core/src/test/java/art/arcane/iris/core/pack/PackHydrologyValidatorTest.java +++ b/core/src/test/java/art/arcane/iris/core/pack/PackHydrologyValidatorTest.java @@ -113,6 +113,21 @@ public class PackHydrologyValidatorTest { assertTrue(result.errors().toString(), result.errors().isEmpty()); } + @Test + public void rejectsMouthLevelingDistanceBeyondTheRouteLength() throws Exception { + File pack = pack(riversDimension(""" + { + "enabled": true, + "routing": {"tileSize": 1024, "sampleSpacing": 64, "maximumRouteLength": 256, "oceanOutlets": true}, + "underground": {"mouthLevelingDistance": 512} + } + """, "")); + + PackHydrologyValidator.Validation result = validate(pack); + + assertContains(result.errors(), "mouthLevelingDistance must not exceed routing.maximumRouteLength"); + } + @Test public void acceptsEverySchemaBoundAtItsMaximum() throws Exception { File pack = pack(riversDimension("""