diff --git a/core/src/main/java/com/volmit/iris/core/gui/ProceduralObjectSource.java b/core/src/main/java/com/volmit/iris/core/gui/ProceduralObjectSource.java index a59e467cb..6b55f8627 100644 --- a/core/src/main/java/com/volmit/iris/core/gui/ProceduralObjectSource.java +++ b/core/src/main/java/com/volmit/iris/core/gui/ProceduralObjectSource.java @@ -19,6 +19,7 @@ package com.volmit.iris.core.gui; import com.volmit.iris.core.loader.IrisData; import com.volmit.iris.engine.object.IrisObject; +import com.volmit.iris.engine.object.procedural.ProceduralObjectCatalog; import com.volmit.iris.engine.object.procedural.ResolvedProceduralPlacement; import java.util.LinkedHashMap; @@ -26,16 +27,16 @@ import java.util.List; import java.util.Map; /** - * The objects the pack's procedural settings generate, one entry per definition in a folder per type. + * The objects the pack's procedural settings generate, one entry per definition, in the folders the pack keeps them in. */ final class ProceduralObjectSource implements ObjectSource { - private static final Map FOLDER_BY_KIND = Map.of( - "tree", "Trees", - "formation", "Formations", - "crystal", "Crystals", + private static final Map FOLDER_LABEL_BY_KIND = Map.of( + "trees", "Trees", + "formations", "Formations", + "crystals", "Crystals", "coral", "Coral", - "fungus", "Fungi", - "ruin", "Ruins"); + "fungi", "Fungi", + "ruins", "Ruins"); private Map definitionsByKey = Map.of(); @@ -44,11 +45,14 @@ final class ProceduralObjectSource implements ObjectSource { return "procedural object"; } + // The type folder gets its label; the rest of the path stays as the pack has it. @Override public List keys(IrisData data) { Map byKey = new LinkedHashMap<>(); - for (ResolvedProceduralPlacement definition : data.getProceduralObjects().definitions()) { - byKey.put(FOLDER_BY_KIND.getOrDefault(definition.kind(), definition.kind()) + "/" + definition.name(), definition); + for (ProceduralObjectCatalog.Definition definition : data.getProceduralObjects().definitions()) { + String kind = definition.placement().kind(); + String key = FOLDER_LABEL_BY_KIND.getOrDefault(kind, kind) + definition.path().substring(kind.length()); + byKey.put(key, definition.placement()); } definitionsByKey = byKey; return List.copyOf(byKey.keySet()); diff --git a/core/src/main/java/com/volmit/iris/engine/object/procedural/ProceduralObjectCatalog.java b/core/src/main/java/com/volmit/iris/engine/object/procedural/ProceduralObjectCatalog.java index 36155d9da..1f3258d6b 100644 --- a/core/src/main/java/com/volmit/iris/engine/object/procedural/ProceduralObjectCatalog.java +++ b/core/src/main/java/com/volmit/iris/engine/object/procedural/ProceduralObjectCatalog.java @@ -20,7 +20,8 @@ package com.volmit.iris.engine.object.procedural; import com.google.gson.Gson; import com.volmit.iris.Iris; import com.volmit.iris.core.loader.IrisData; -import com.volmit.iris.engine.object.annotations.Snippet; +import com.volmit.iris.engine.object.IrisBiome; +import com.volmit.iris.engine.object.IrisRegion; import com.volmit.iris.engine.object.procedural.coral.Coral; import com.volmit.iris.engine.object.procedural.coral.ResolvedCoral; import com.volmit.iris.engine.object.procedural.crystal.Crystal; @@ -40,18 +41,29 @@ import java.io.Reader; import java.nio.file.Files; import java.nio.file.Path; import java.util.ArrayList; +import java.util.HashSet; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; +import java.util.Objects; +import java.util.Set; import java.util.stream.Stream; /** - * The procedural objects of one pack: those its regions and biomes declare, and those saved on their own as snippets, - * such as {@code snippet/procedural-tree/oak.json}. A definition several places share is baked once. + * The procedural objects of one pack: those its regions and biomes declare, and those saved on their own as snippets + * in a folder per type under {@code snippet/procedural}, such as {@code snippet/procedural/trees/oak.json}. A definition several places share is baked once. */ public final class ProceduralObjectCatalog { private static final Gson DEFINITION_JSON = new Gson(); - private static final List> DEFINITION_TYPES = List.of(Tree.class, Ruin.class, Formation.class, Coral.class, Fungus.class, Crystal.class); + /** The snippet folder every procedural setting shares, so all of them live under {@code snippet/procedural}. */ + public static final String SNIPPET_FOLDER = "procedural"; + private static final Map> DEFINITION_TYPE_BY_FOLDER = Map.of( + "trees", Tree.class, + "ruins", Ruin.class, + "formations", Formation.class, + "coral", Coral.class, + "fungi", Fungus.class, + "crystals", Crystal.class); private final IrisData data; private final KMap byDefinition = new KMap<>(); @@ -87,47 +99,58 @@ public final class ProceduralObjectCatalog { } /** - * Every procedural object the pack defines, in snippets or in regions and biomes, whether or not its dimensions - * reach them. Where two definitions share a type and name, the first one found stands for both. + * Every procedural object the pack defines, whether or not its dimensions reach them. A snippet is found at its file's + * path under {@code snippet/procedural}, like {@code trees/estranged/oak}; a definition only written in a region or + * biome at its type and name, like {@code trees/oak}. */ - public List definitions() { - Map byTypeAndName = new LinkedHashMap<>(); - for (Class type : DEFINITION_TYPES) { - snippetDefinitions(type).forEach(definition -> addDefinition(byTypeAndName, placementOf(definition))); - } - data.getRegionLoader().streamAll().forEach(region -> addDefinitions(byTypeAndName, region.getProceduralObjects())); - data.getBiomeLoader().streamAll().forEach(biome -> addDefinitions(byTypeAndName, biome.getProceduralObjects())); - return List.copyOf(byTypeAndName.values()); + public List definitions() { + Map pathByPlacement = new LinkedHashMap<>(); + Set takenPaths = new HashSet<>(); + DEFINITION_TYPE_BY_FOLDER.forEach((folder, type) -> snippetDefinitions(folder, type) + .forEach((path, definition) -> addDefinition(pathByPlacement, takenPaths, placementOf(definition), path))); + Stream.concat(data.getRegionLoader().streamAll().map(IrisRegion::getProceduralObjects), + data.getBiomeLoader().streamAll().map(IrisBiome::getProceduralObjects)) + .filter(Objects::nonNull) + .flatMap(settings -> settings.resolved(data).stream()) + .forEach(placement -> addDefinition(pathByPlacement, takenPaths, placement, placement.kind() + "/" + placement.name())); + List definitions = new ArrayList<>(); + pathByPlacement.forEach((placement, path) -> definitions.add(new Definition(path, placement))); + return definitions; } - private void addDefinitions(Map byTypeAndName, ProceduralObjectSettings settings) { - if (settings == null) { + // The same definition found twice keeps its first path; two different ones never share a path. + private static void addDefinition(Map pathByPlacement, Set takenPaths, + ResolvedProceduralPlacement placement, String path) { + if (pathByPlacement.containsKey(placement)) { return; } - settings.resolved(data).forEach(placement -> addDefinition(byTypeAndName, placement)); + String uniquePath = path; + for (int copy = 2; !takenPaths.add(uniquePath); copy++) { + uniquePath = path + " (" + copy + ")"; + } + pathByPlacement.put(placement, uniquePath); } - private static void addDefinition(Map byTypeAndName, ResolvedProceduralPlacement placement) { - byTypeAndName.putIfAbsent(placement.kind() + "/" + placement.name(), placement); - } - - private List snippetDefinitions(Class type) { - Path folder = data.getDataFolder().toPath().resolve("snippet").resolve(type.getAnnotation(Snippet.class).value()); + /** The definitions in the snippet folder of one type, by their path under {@code snippet/procedural} without the extension. */ + private Map snippetDefinitions(String typeFolder, Class type) { + Path proceduralFolder = data.getDataFolder().toPath().resolve("snippet").resolve(SNIPPET_FOLDER); + Path folder = proceduralFolder.resolve(typeFolder); if (!Files.isDirectory(folder)) { - return List.of(); + return Map.of(); } try (Stream files = Files.walk(folder)) { - List definitions = new ArrayList<>(); + Map definitions = new LinkedHashMap<>(); files.filter(file -> file.toString().endsWith(".json")).sorted().forEach(file -> { Object definition = readDefinition(file, type); if (definition != null) { - definitions.add(definition); + String path = proceduralFolder.relativize(file).toString().replace('\\', '/'); + definitions.put(path.substring(0, path.length() - ".json".length()), definition); } }); return definitions; } catch (IOException error) { Iris.warn("Could not list the procedural objects in " + folder + ": " + error.getMessage()); - return List.of(); + return Map.of(); } } @@ -140,4 +163,7 @@ public final class ProceduralObjectCatalog { } } + /** A procedural object and where the pack keeps it, as a path under {@code snippet/procedural}. */ + public record Definition(String path, ResolvedProceduralPlacement placement) { + } } diff --git a/core/src/main/java/com/volmit/iris/engine/object/procedural/ProceduralObjectSettings.java b/core/src/main/java/com/volmit/iris/engine/object/procedural/ProceduralObjectSettings.java index f4ecf0d49..496759ba9 100644 --- a/core/src/main/java/com/volmit/iris/engine/object/procedural/ProceduralObjectSettings.java +++ b/core/src/main/java/com/volmit/iris/engine/object/procedural/ProceduralObjectSettings.java @@ -37,7 +37,7 @@ import java.util.List; * The procedural objects a region or biome declares, written as {@code "proceduralObjects": {"trees": [...], ...}}: things * Iris generates from scratch at world-gen time and places like object placements. */ -@Snippet("procedural-objects") +@Snippet(ProceduralObjectCatalog.SNIPPET_FOLDER) @Desc("Procedurally generated objects placed in a biome or region. Unlike the objects block (which loads iob files), these are generated from scratch at world-gen time.") public final class ProceduralObjectSettings { private final transient AtomicCache> resolved = new AtomicCache<>(); diff --git a/core/src/main/java/com/volmit/iris/engine/object/procedural/ResolvedProceduralPlacement.java b/core/src/main/java/com/volmit/iris/engine/object/procedural/ResolvedProceduralPlacement.java index 8ebf987fe..91a701db0 100644 --- a/core/src/main/java/com/volmit/iris/engine/object/procedural/ResolvedProceduralPlacement.java +++ b/core/src/main/java/com/volmit/iris/engine/object/procedural/ResolvedProceduralPlacement.java @@ -68,7 +68,7 @@ public abstract class ResolvedProceduralPlacement { return shape.name(); } - /** The type of object, as the variant keys name it: tree, ruin, formation, coral, fungus or crystal. */ + /** The type of object, named like its snippet folder: trees, ruins, formations, coral, fungi or crystals. */ public String kind() { return shape.kind(); } @@ -116,7 +116,7 @@ public abstract class ResolvedProceduralPlacement { return keys; } - /** The key variant {@code index} is loaded under, like {@code procedural/tree/oak#0}. */ + /** The key variant {@code index} is loaded under, like {@code procedural/trees/oak#0}. */ public String variantKey(int index) { return "procedural/" + shape.kind() + "/" + shape.name() + "#" + index; } diff --git a/core/src/main/java/com/volmit/iris/engine/object/procedural/coral/Coral.java b/core/src/main/java/com/volmit/iris/engine/object/procedural/coral/Coral.java index 8b7f5577d..cd236b4fd 100644 --- a/core/src/main/java/com/volmit/iris/engine/object/procedural/coral/Coral.java +++ b/core/src/main/java/com/volmit/iris/engine/object/procedural/coral/Coral.java @@ -27,6 +27,7 @@ import com.volmit.iris.engine.object.IrisObjectLimit; import com.volmit.iris.engine.object.IrisMaterialPalette; import com.volmit.iris.engine.object.annotations.Desc; import com.volmit.iris.engine.object.annotations.Snippet; +import com.volmit.iris.engine.object.procedural.ProceduralObjectCatalog; import com.volmit.iris.engine.object.annotations.MaxNumber; import com.volmit.iris.engine.object.annotations.MinNumber; import com.volmit.iris.engine.object.annotations.RegistryListBlockType; @@ -34,7 +35,7 @@ import com.volmit.iris.engine.object.annotations.Required; import java.util.Optional; -@Snippet("coral") +@Snippet(ProceduralObjectCatalog.SNIPPET_FOLDER) @Desc("A single procedurally generated coral reef structure. Iris bakes a pool of deterministic variants from these settings and scatters them across the seafloor at world-gen time, exactly like an object placement but generated from scratch instead of loaded from an iob file. Mirrors the procedural tree system but tuned for underwater reefs: structural blocks are waterlogged so the coral stays alive, and placement defaults to anchoring on the terrain beneath the water surface.") public final class Coral { @Desc("A human readable name used in logs and as the variant load key.") diff --git a/core/src/main/java/com/volmit/iris/engine/object/procedural/crystal/Crystal.java b/core/src/main/java/com/volmit/iris/engine/object/procedural/crystal/Crystal.java index 64fb613cd..61b020409 100644 --- a/core/src/main/java/com/volmit/iris/engine/object/procedural/crystal/Crystal.java +++ b/core/src/main/java/com/volmit/iris/engine/object/procedural/crystal/Crystal.java @@ -27,6 +27,7 @@ import com.volmit.iris.engine.object.IrisObjectLimit; import com.volmit.iris.engine.object.IrisMaterialPalette; import com.volmit.iris.engine.object.annotations.Desc; import com.volmit.iris.engine.object.annotations.Snippet; +import com.volmit.iris.engine.object.procedural.ProceduralObjectCatalog; import com.volmit.iris.engine.object.annotations.MaxNumber; import com.volmit.iris.engine.object.annotations.MinNumber; import com.volmit.iris.engine.object.annotations.RegistryListBlockType; @@ -34,7 +35,7 @@ import com.volmit.iris.engine.object.annotations.Required; import java.util.Optional; -@Snippet("crystal") +@Snippet(ProceduralObjectCatalog.SNIPPET_FOLDER) @Desc("A single procedurally generated crystal cluster: a budding base blob with faceted, tapered shards radiating from it (geode / amethyst-style). Iris bakes a pool of deterministic variants from these settings and scatters them at world-gen time, exactly like an object placement but generated from scratch instead of loaded from an iob file. Built for caves.") public final class Crystal { @Desc("A human readable name used in logs and as the variant load key.") diff --git a/core/src/main/java/com/volmit/iris/engine/object/procedural/crystal/ResolvedCrystal.java b/core/src/main/java/com/volmit/iris/engine/object/procedural/crystal/ResolvedCrystal.java index 613ba5ea4..39a624bcb 100644 --- a/core/src/main/java/com/volmit/iris/engine/object/procedural/crystal/ResolvedCrystal.java +++ b/core/src/main/java/com/volmit/iris/engine/object/procedural/crystal/ResolvedCrystal.java @@ -29,7 +29,7 @@ public final class ResolvedCrystal extends ResolvedProceduralPlacement { private final Crystal settings; public ResolvedCrystal(Crystal settings, IrisData data) { - super(new Shape("crystal", settings.name(), settings.chance(), settings.density(), settings.seed(), settings.variants(), settings.mode(), + super(new Shape("crystals", settings.name(), settings.chance(), settings.density(), settings.seed(), settings.variants(), settings.mode(), settings.rotation(), settings.clamp(), settings.carvingSupport(), settings.underwater(), settings.translate(), settings.stiltSettings().orElse(null)), data); this.settings = settings; diff --git a/core/src/main/java/com/volmit/iris/engine/object/procedural/formation/Formation.java b/core/src/main/java/com/volmit/iris/engine/object/procedural/formation/Formation.java index d8e35dc7e..5d8d8028c 100644 --- a/core/src/main/java/com/volmit/iris/engine/object/procedural/formation/Formation.java +++ b/core/src/main/java/com/volmit/iris/engine/object/procedural/formation/Formation.java @@ -27,6 +27,7 @@ import com.volmit.iris.engine.object.IrisObjectLimit; import com.volmit.iris.engine.object.IrisMaterialPalette; import com.volmit.iris.engine.object.annotations.Desc; import com.volmit.iris.engine.object.annotations.Snippet; +import com.volmit.iris.engine.object.procedural.ProceduralObjectCatalog; import com.volmit.iris.engine.object.annotations.MaxNumber; import com.volmit.iris.engine.object.annotations.MinNumber; import com.volmit.iris.engine.object.annotations.RegistryListBlockType; @@ -34,7 +35,7 @@ import com.volmit.iris.engine.object.annotations.Required; import java.util.Optional; -@Snippet("formation") +@Snippet(ProceduralObjectCatalog.SNIPPET_FOLDER) @Desc("A single procedurally generated natural formation, including rock landmarks and magical glacial silhouettes. Iris bakes a pool of deterministic variants from these settings and scatters them at world-gen time, exactly like an object placement but generated from scratch instead of loaded from an iob file.") public final class Formation { @Desc("A human readable name used in logs and as the variant load key.") diff --git a/core/src/main/java/com/volmit/iris/engine/object/procedural/formation/ResolvedFormation.java b/core/src/main/java/com/volmit/iris/engine/object/procedural/formation/ResolvedFormation.java index d3c2b54f1..c18004990 100644 --- a/core/src/main/java/com/volmit/iris/engine/object/procedural/formation/ResolvedFormation.java +++ b/core/src/main/java/com/volmit/iris/engine/object/procedural/formation/ResolvedFormation.java @@ -29,7 +29,7 @@ public final class ResolvedFormation extends ResolvedProceduralPlacement { private final Formation settings; public ResolvedFormation(Formation settings, IrisData data) { - super(new Shape("formation", settings.name(), settings.chance(), settings.density(), settings.seed(), settings.variants(), settings.mode(), + super(new Shape("formations", settings.name(), settings.chance(), settings.density(), settings.seed(), settings.variants(), settings.mode(), settings.rotation(), settings.clamp(), settings.carvingSupport(), settings.underwater(), settings.translate(), settings.stiltSettings().orElse(null)), data); this.settings = settings; diff --git a/core/src/main/java/com/volmit/iris/engine/object/procedural/fungi/Fungus.java b/core/src/main/java/com/volmit/iris/engine/object/procedural/fungi/Fungus.java index 4d9ff636d..ee182ded8 100644 --- a/core/src/main/java/com/volmit/iris/engine/object/procedural/fungi/Fungus.java +++ b/core/src/main/java/com/volmit/iris/engine/object/procedural/fungi/Fungus.java @@ -27,6 +27,7 @@ import com.volmit.iris.engine.object.IrisObjectLimit; import com.volmit.iris.engine.object.IrisMaterialPalette; import com.volmit.iris.engine.object.annotations.Desc; import com.volmit.iris.engine.object.annotations.Snippet; +import com.volmit.iris.engine.object.procedural.ProceduralObjectCatalog; import com.volmit.iris.engine.object.annotations.MaxNumber; import com.volmit.iris.engine.object.annotations.MinNumber; import com.volmit.iris.engine.object.annotations.RegistryListBlockType; @@ -34,7 +35,7 @@ import com.volmit.iris.engine.object.annotations.Required; import java.util.Optional; -@Snippet("fungus") +@Snippet(ProceduralObjectCatalog.SNIPPET_FOLDER) @Desc("A single procedurally generated fungus (giant mushroom or shelf fungus). Iris bakes a pool of deterministic variants from these settings and scatters them at world-gen time, exactly like an object placement but generated from scratch instead of loaded from an iob file. The fungus is built as a stem column with a cap dome grown on top, mirroring the trunk-and-canopy model used by procedural trees.") public final class Fungus { @Desc("A human readable name used in logs and as the variant load key.") diff --git a/core/src/main/java/com/volmit/iris/engine/object/procedural/fungi/ResolvedFungus.java b/core/src/main/java/com/volmit/iris/engine/object/procedural/fungi/ResolvedFungus.java index f00326028..c8db62107 100644 --- a/core/src/main/java/com/volmit/iris/engine/object/procedural/fungi/ResolvedFungus.java +++ b/core/src/main/java/com/volmit/iris/engine/object/procedural/fungi/ResolvedFungus.java @@ -33,7 +33,7 @@ public final class ResolvedFungus extends ResolvedProceduralPlacement { private final Fungus settings; public ResolvedFungus(Fungus settings, IrisData data) { - super(new Shape("fungus", settings.name(), settings.chance(), settings.density(), settings.seed(), settings.variants(), settings.mode(), + super(new Shape("fungi", settings.name(), settings.chance(), settings.density(), settings.seed(), settings.variants(), settings.mode(), settings.rotation(), settings.clamp(), settings.carvingSupport(), settings.underwater(), settings.translate(), settings.stiltSettings().orElse(null)), data); this.settings = settings; diff --git a/core/src/main/java/com/volmit/iris/engine/object/procedural/ruin/ResolvedRuin.java b/core/src/main/java/com/volmit/iris/engine/object/procedural/ruin/ResolvedRuin.java index f5c219974..a67de51eb 100644 --- a/core/src/main/java/com/volmit/iris/engine/object/procedural/ruin/ResolvedRuin.java +++ b/core/src/main/java/com/volmit/iris/engine/object/procedural/ruin/ResolvedRuin.java @@ -29,7 +29,7 @@ public final class ResolvedRuin extends ResolvedProceduralPlacement { private final Ruin settings; public ResolvedRuin(Ruin settings, IrisData data) { - super(new Shape("ruin", settings.name(), settings.chance(), settings.density(), settings.seed(), settings.variants(), settings.mode(), + super(new Shape("ruins", settings.name(), settings.chance(), settings.density(), settings.seed(), settings.variants(), settings.mode(), settings.rotation(), settings.clamp(), settings.carvingSupport(), settings.underwater(), settings.translate(), settings.stiltSettings().orElse(null)), data); this.settings = settings; diff --git a/core/src/main/java/com/volmit/iris/engine/object/procedural/ruin/Ruin.java b/core/src/main/java/com/volmit/iris/engine/object/procedural/ruin/Ruin.java index 7cfde4dc9..2622f82b7 100644 --- a/core/src/main/java/com/volmit/iris/engine/object/procedural/ruin/Ruin.java +++ b/core/src/main/java/com/volmit/iris/engine/object/procedural/ruin/Ruin.java @@ -27,6 +27,7 @@ import com.volmit.iris.engine.object.IrisObjectLimit; import com.volmit.iris.engine.object.IrisMaterialPalette; import com.volmit.iris.engine.object.annotations.Desc; import com.volmit.iris.engine.object.annotations.Snippet; +import com.volmit.iris.engine.object.procedural.ProceduralObjectCatalog; import com.volmit.iris.engine.object.annotations.MaxNumber; import com.volmit.iris.engine.object.annotations.ArrayType; import com.volmit.iris.engine.object.annotations.MinNumber; @@ -36,7 +37,7 @@ import java.util.Collections; import java.util.List; import java.util.Optional; -@Snippet("ruin") +@Snippet(ProceduralObjectCatalog.SNIPPET_FOLDER) @Desc("A single procedurally generated ruin: a crumbling man-made structure (pillar, wall, arch, foundation slab, or rubble pile). Iris bakes a pool of deterministic variants from these settings and scatters them at world-gen time, exactly like an object placement but generated from scratch instead of loaded from an iob file. Weathering swaps blocks for mossy or cracked variants by noise, erosion deletes blocks so the shape reads as collapsed, and a buried fraction sinks the ruin into the terrain.") public final class Ruin { @Desc("A human readable name used in logs and as the variant load key (procedural/#).") diff --git a/core/src/main/java/com/volmit/iris/engine/object/procedural/ruin/RuinDecorator.java b/core/src/main/java/com/volmit/iris/engine/object/procedural/ruin/RuinDecorator.java index a77dc8ad5..3147e0ed7 100644 --- a/core/src/main/java/com/volmit/iris/engine/object/procedural/ruin/RuinDecorator.java +++ b/core/src/main/java/com/volmit/iris/engine/object/procedural/ruin/RuinDecorator.java @@ -21,6 +21,7 @@ package com.volmit.iris.engine.object.procedural.ruin; import com.volmit.iris.engine.object.IrisMaterialPalette; import com.volmit.iris.engine.object.annotations.Desc; import com.volmit.iris.engine.object.annotations.Snippet; +import com.volmit.iris.engine.object.procedural.ProceduralObjectCatalog; import com.volmit.iris.engine.object.annotations.MaxNumber; import com.volmit.iris.engine.object.annotations.MinNumber; import com.volmit.iris.engine.object.annotations.RegistryListBlockType; @@ -28,7 +29,7 @@ import com.volmit.iris.engine.object.annotations.Required; import java.util.Optional; -@Snippet("ruin-decorator") +@Snippet(ProceduralObjectCatalog.SNIPPET_FOLDER) @Desc("An accent block applied to a generated ruin after it is built and eroded, such as moss carpets on broken tops, vines on the faces, or rubble scattered around the base.") public final class RuinDecorator { @Desc("Where on the ruin this accent is placed. TOP sits on the highest block of each column, SURFACE clings to air-facing vertical faces, BASE_SCATTER rings the ground footprint around the base.") diff --git a/core/src/main/java/com/volmit/iris/engine/object/procedural/tree/ResolvedTree.java b/core/src/main/java/com/volmit/iris/engine/object/procedural/tree/ResolvedTree.java index 90f16ca2a..cae87a7a2 100644 --- a/core/src/main/java/com/volmit/iris/engine/object/procedural/tree/ResolvedTree.java +++ b/core/src/main/java/com/volmit/iris/engine/object/procedural/tree/ResolvedTree.java @@ -37,7 +37,7 @@ public final class ResolvedTree extends ResolvedProceduralPlacement { private final Tree settings; public ResolvedTree(Tree settings, IrisData data) { - super(new Shape("tree", settings.name(), settings.chance(), settings.density(), settings.seed(), settings.variants(), settings.mode(), + super(new Shape("trees", settings.name(), settings.chance(), settings.density(), settings.seed(), settings.variants(), settings.mode(), settings.rotation(), settings.clamp(), settings.carvingSupport(), settings.underwater(), settings.translate(), settings.stiltSettings().orElse(null)), data); this.settings = settings; diff --git a/core/src/main/java/com/volmit/iris/engine/object/procedural/tree/Tree.java b/core/src/main/java/com/volmit/iris/engine/object/procedural/tree/Tree.java index ecb6a1d6f..845b74d39 100644 --- a/core/src/main/java/com/volmit/iris/engine/object/procedural/tree/Tree.java +++ b/core/src/main/java/com/volmit/iris/engine/object/procedural/tree/Tree.java @@ -32,11 +32,12 @@ import com.volmit.iris.engine.object.annotations.MinNumber; import com.volmit.iris.engine.object.annotations.RegistryListBlockType; import com.volmit.iris.engine.object.annotations.Required; import com.volmit.iris.engine.object.annotations.Snippet; +import com.volmit.iris.engine.object.procedural.ProceduralObjectCatalog; import java.util.Collections; import java.util.List; import java.util.Optional; -@Snippet("procedural-tree") +@Snippet(ProceduralObjectCatalog.SNIPPET_FOLDER) @Desc("A single procedurally generated tree. Iris bakes a pool of deterministic variants from these settings and scatters them at world-gen time, exactly like an object placement but generated from scratch instead of loaded from an iob file.") public final class Tree { @Desc("A human readable name used in logs and as the variant load key.") diff --git a/core/src/main/java/com/volmit/iris/engine/object/procedural/tree/TreeBranches.java b/core/src/main/java/com/volmit/iris/engine/object/procedural/tree/TreeBranches.java index 599c4d9ee..25205be18 100644 --- a/core/src/main/java/com/volmit/iris/engine/object/procedural/tree/TreeBranches.java +++ b/core/src/main/java/com/volmit/iris/engine/object/procedural/tree/TreeBranches.java @@ -20,12 +20,13 @@ package com.volmit.iris.engine.object.procedural.tree; import com.volmit.iris.engine.object.annotations.Desc; import com.volmit.iris.engine.object.annotations.Snippet; +import com.volmit.iris.engine.object.procedural.ProceduralObjectCatalog; import com.volmit.iris.engine.object.annotations.MaxNumber; import com.volmit.iris.engine.object.annotations.MinNumber; import java.util.Optional; -@Snippet("tree-branches") +@Snippet(ProceduralObjectCatalog.SNIPPET_FOLDER) @Desc("A branch system that throws limbs out of the trunk and places a leaf ball at each tip. When present, branches drive the canopy and only the topmost crown disc of the profile is still placed.") public final class TreeBranches { @Desc("How branch spawn chance varies over trunk height.") diff --git a/core/src/main/java/com/volmit/iris/engine/object/procedural/tree/TreeCanopy.java b/core/src/main/java/com/volmit/iris/engine/object/procedural/tree/TreeCanopy.java index 4820278c1..2aefdaa71 100644 --- a/core/src/main/java/com/volmit/iris/engine/object/procedural/tree/TreeCanopy.java +++ b/core/src/main/java/com/volmit/iris/engine/object/procedural/tree/TreeCanopy.java @@ -20,6 +20,7 @@ package com.volmit.iris.engine.object.procedural.tree; import com.volmit.iris.engine.object.annotations.Desc; import com.volmit.iris.engine.object.annotations.Snippet; +import com.volmit.iris.engine.object.procedural.ProceduralObjectCatalog; import com.volmit.iris.engine.object.annotations.MaxNumber; import com.volmit.iris.engine.object.annotations.ArrayType; import com.volmit.iris.engine.object.annotations.MinNumber; @@ -27,7 +28,7 @@ import java.util.Collections; import java.util.List; import java.util.Optional; -@Snippet("tree-canopy") +@Snippet(ProceduralObjectCatalog.SNIPPET_FOLDER) @Desc("The leaf crown of a procedural tree. Built from stacked dome-shaped discs (driven by the profile or by explicit layers) and optionally a branch system.") public final class TreeCanopy { @MinNumber(0) diff --git a/core/src/main/java/com/volmit/iris/engine/object/procedural/tree/TreeDecorator.java b/core/src/main/java/com/volmit/iris/engine/object/procedural/tree/TreeDecorator.java index 8c5ac591d..72c228550 100644 --- a/core/src/main/java/com/volmit/iris/engine/object/procedural/tree/TreeDecorator.java +++ b/core/src/main/java/com/volmit/iris/engine/object/procedural/tree/TreeDecorator.java @@ -21,6 +21,7 @@ package com.volmit.iris.engine.object.procedural.tree; import com.volmit.iris.engine.object.IrisMaterialPalette; import com.volmit.iris.engine.object.annotations.Desc; import com.volmit.iris.engine.object.annotations.Snippet; +import com.volmit.iris.engine.object.procedural.ProceduralObjectCatalog; import com.volmit.iris.engine.object.annotations.MaxNumber; import com.volmit.iris.engine.object.annotations.MinNumber; import com.volmit.iris.engine.object.annotations.RegistryListBlockType; @@ -28,7 +29,7 @@ import com.volmit.iris.engine.object.annotations.Required; import java.util.Optional; -@Snippet("tree-decorator") +@Snippet(ProceduralObjectCatalog.SNIPPET_FOLDER) @Desc("An accent block applied to a generated tree such as fruit on branch tips, vines on the trunk, snow on the crown, or a glowing underside.") public final class TreeDecorator { @Desc("Where this decorator is placed on the tree.") diff --git a/core/src/main/java/com/volmit/iris/engine/object/procedural/tree/TreeLayer.java b/core/src/main/java/com/volmit/iris/engine/object/procedural/tree/TreeLayer.java index ef9933d82..aa08b993e 100644 --- a/core/src/main/java/com/volmit/iris/engine/object/procedural/tree/TreeLayer.java +++ b/core/src/main/java/com/volmit/iris/engine/object/procedural/tree/TreeLayer.java @@ -20,9 +20,10 @@ package com.volmit.iris.engine.object.procedural.tree; import com.volmit.iris.engine.object.annotations.Desc; import com.volmit.iris.engine.object.annotations.Snippet; +import com.volmit.iris.engine.object.procedural.ProceduralObjectCatalog; import com.volmit.iris.engine.object.annotations.MinNumber; -@Snippet("tree-layer") +@Snippet(ProceduralObjectCatalog.SNIPPET_FOLDER) @Desc("An explicit canopy disc at a given vertical offset and radius. Define a list of these to bypass the profile and sculpt the crown by hand.") public final class TreeLayer { @Desc("The vertical offset of this disc, measured in blocks above the trunk base.") diff --git a/core/src/main/java/com/volmit/iris/engine/object/procedural/tree/TreeSecondaryLeaf.java b/core/src/main/java/com/volmit/iris/engine/object/procedural/tree/TreeSecondaryLeaf.java index 4f90c545a..cb0fb1b98 100644 --- a/core/src/main/java/com/volmit/iris/engine/object/procedural/tree/TreeSecondaryLeaf.java +++ b/core/src/main/java/com/volmit/iris/engine/object/procedural/tree/TreeSecondaryLeaf.java @@ -20,11 +20,12 @@ package com.volmit.iris.engine.object.procedural.tree; import com.volmit.iris.engine.object.annotations.Desc; import com.volmit.iris.engine.object.annotations.Snippet; +import com.volmit.iris.engine.object.procedural.ProceduralObjectCatalog; import com.volmit.iris.engine.object.annotations.MinNumber; import com.volmit.iris.engine.object.annotations.RegistryListBlockType; import com.volmit.iris.engine.object.annotations.Required; -@Snippet("tree-secondary-leaf") +@Snippet(ProceduralObjectCatalog.SNIPPET_FOLDER) @Desc("A weighted accent leaf or foliage block scattered through the canopy (blossoms, shroomlight, berries).") public final class TreeSecondaryLeaf { @Required diff --git a/core/src/main/java/com/volmit/iris/engine/object/procedural/tree/TreeSubBranches.java b/core/src/main/java/com/volmit/iris/engine/object/procedural/tree/TreeSubBranches.java index b6b8a9695..172a8f0c1 100644 --- a/core/src/main/java/com/volmit/iris/engine/object/procedural/tree/TreeSubBranches.java +++ b/core/src/main/java/com/volmit/iris/engine/object/procedural/tree/TreeSubBranches.java @@ -20,10 +20,11 @@ package com.volmit.iris.engine.object.procedural.tree; import com.volmit.iris.engine.object.annotations.Desc; import com.volmit.iris.engine.object.annotations.Snippet; +import com.volmit.iris.engine.object.procedural.ProceduralObjectCatalog; import com.volmit.iris.engine.object.annotations.MaxNumber; import com.volmit.iris.engine.object.annotations.MinNumber; -@Snippet("tree-sub-branches") +@Snippet(ProceduralObjectCatalog.SNIPPET_FOLDER) @Desc("One recursive level of sub-branches sprouting from each primary branch tip.") public final class TreeSubBranches { @MinNumber(1)