From e63fd9c448304465148cf2d92b1c8efc4c26a483 Mon Sep 17 00:00:00 2001 From: Brian Neumann-Fopiano Date: Wed, 2 Sep 2026 11:46:29 -0400 Subject: [PATCH] Describe the river placement, routing and grotto pool enums for the schema --- .../engine/object/IrisGrottoPoolLevel.java | 4 ++ .../engine/object/IrisRiverPlacementMode.java | 8 ++++ .../engine/object/IrisRiverRoutingMode.java | 7 ++++ .../core/project/IrisRiverSchemaTest.java | 13 +++++- .../object/HydrologyEnumDescriptionsTest.java | 40 +++++++++++++++++++ 5 files changed, 70 insertions(+), 2 deletions(-) create mode 100644 core/src/test/java/art/arcane/iris/engine/object/HydrologyEnumDescriptionsTest.java diff --git a/core/src/main/java/art/arcane/iris/engine/object/IrisGrottoPoolLevel.java b/core/src/main/java/art/arcane/iris/engine/object/IrisGrottoPoolLevel.java index 047b2f0ca..8ce9b6775 100644 --- a/core/src/main/java/art/arcane/iris/engine/object/IrisGrottoPoolLevel.java +++ b/core/src/main/java/art/arcane/iris/engine/object/IrisGrottoPoolLevel.java @@ -1,5 +1,9 @@ package art.arcane.iris.engine.object; +import art.arcane.iris.engine.object.annotations.Desc; + +@Desc("Where the pool at the bottom of a coastal grotto sits.") public enum IrisGrottoPoolLevel { + @Desc("The pool surface sits at the dimension fluid height, so the grotto meets the sea.") SEA_LEVEL } diff --git a/core/src/main/java/art/arcane/iris/engine/object/IrisRiverPlacementMode.java b/core/src/main/java/art/arcane/iris/engine/object/IrisRiverPlacementMode.java index d0685387c..77b4475d4 100644 --- a/core/src/main/java/art/arcane/iris/engine/object/IrisRiverPlacementMode.java +++ b/core/src/main/java/art/arcane/iris/engine/object/IrisRiverPlacementMode.java @@ -1,9 +1,17 @@ package art.arcane.iris.engine.object; +import art.arcane.iris.engine.object.annotations.Desc; + +@Desc("Controls whether river sources may start inside a dimension, region or biome, and how strongly they are drawn there.") public enum IrisRiverPlacementMode { + @Desc("No river source may start here. Rivers may still pass through when routing allows it.") DISABLED, + @Desc("Rivers may pass through, but no source starts here.") TRANSIT_ONLY, + @Desc("Sources start here on their own merits, ranked like everywhere else.") NATURAL, + @Desc("Eligible source sites here rank ahead of sites elsewhere in the tile.") PREFERRED_HEADWATER, + @Desc("At least one source starts here whenever a site can reach a legal outlet; sources.minimumPerTile can raise that quota.") REQUIRED_HEADWATER } diff --git a/core/src/main/java/art/arcane/iris/engine/object/IrisRiverRoutingMode.java b/core/src/main/java/art/arcane/iris/engine/object/IrisRiverRoutingMode.java index 9315da332..566ecf083 100644 --- a/core/src/main/java/art/arcane/iris/engine/object/IrisRiverRoutingMode.java +++ b/core/src/main/java/art/arcane/iris/engine/object/IrisRiverRoutingMode.java @@ -1,8 +1,15 @@ package art.arcane.iris.engine.object; +import art.arcane.iris.engine.object.annotations.Desc; + +@Desc("Controls whether river routes may pass through a dimension, region or biome, and at what cost.") public enum IrisRiverRoutingMode { + @Desc("Rivers never route through here.") BLOCK, + @Desc("Rivers route through here only when no cheaper path exists; transit carries a strong cost.") AVOID, + @Desc("Rivers route through here at the normal cost.") ALLOW, + @Desc("Rivers route through here at a reduced cost, so routes are drawn toward this area.") PREFER } diff --git a/core/src/test/java/art/arcane/iris/core/project/IrisRiverSchemaTest.java b/core/src/test/java/art/arcane/iris/core/project/IrisRiverSchemaTest.java index 384c840e8..0c3d24228 100644 --- a/core/src/test/java/art/arcane/iris/core/project/IrisRiverSchemaTest.java +++ b/core/src/test/java/art/arcane/iris/core/project/IrisRiverSchemaTest.java @@ -248,8 +248,17 @@ public class IrisRiverSchemaTest { private static List enumValues(JSONObject definitions, JSONObject reference) { String key = reference.getString("$ref").substring("#/definitions/".length()); - JSONArray values = definitions.getJSONObject(key).getJSONArray("enum"); - List names = new ArrayList<>(values.length()); + JSONObject definition = definitions.getJSONObject(key); + List names = new ArrayList<>(); + if (definition.has("oneOf")) { + // A described enum lists one {const, description} entry per value. + JSONArray options = definition.getJSONArray("oneOf"); + for (int index = 0; index < options.length(); index++) { + names.add(options.getJSONObject(index).getString("const")); + } + return names; + } + JSONArray values = definition.getJSONArray("enum"); for (int index = 0; index < values.length(); index++) { names.add(values.getString(index)); } diff --git a/core/src/test/java/art/arcane/iris/engine/object/HydrologyEnumDescriptionsTest.java b/core/src/test/java/art/arcane/iris/engine/object/HydrologyEnumDescriptionsTest.java new file mode 100644 index 000000000..f7340c593 --- /dev/null +++ b/core/src/test/java/art/arcane/iris/engine/object/HydrologyEnumDescriptionsTest.java @@ -0,0 +1,40 @@ +package art.arcane.iris.engine.object; + +import art.arcane.iris.engine.object.annotations.Desc; +import org.junit.Test; + +import java.lang.reflect.Field; +import java.util.List; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; + +public class HydrologyEnumDescriptionsTest { + private static final List>> HYDROLOGY_ENUMS = List.of( + IrisRiverPlacementMode.class, + IrisRiverRoutingMode.class, + IrisGrottoPoolLevel.class + ); + + @Test + public void hydrologyEnumsDescribeThemselvesForTheSchema() { + for (Class> type : HYDROLOGY_ENUMS) { + Desc description = type.getAnnotation(Desc.class); + assertNotNull(type.getSimpleName() + " needs a @Desc", description); + assertFalse(type.getSimpleName() + " has a blank @Desc", description.value().isBlank()); + } + } + + @Test + public void everyHydrologyEnumConstantDescribesItselfForTheSchema() throws NoSuchFieldException { + for (Class> type : HYDROLOGY_ENUMS) { + for (Enum constant : type.getEnumConstants()) { + Field field = type.getField(constant.name()); + Desc description = field.getAnnotation(Desc.class); + String label = type.getSimpleName() + "." + constant.name(); + assertNotNull(label + " needs a @Desc", description); + assertFalse(label + " has a blank @Desc", description.value().isBlank()); + } + } + } +}