From 3318161c444930dbbbce66fe2de8c9538961390e Mon Sep 17 00:00:00 2001 From: dfsek Date: Thu, 21 Jan 2021 22:20:40 -0700 Subject: [PATCH] cleanup biome config loading --- .../terra/biome/pipeline/BiomePipeline.java | 17 +++- .../biome/pipeline/stages/SeededBuilder.java | 15 +++ .../terra/biome/pipeline/stages/Stage.java | 1 + .../biome/BiomeProviderBuilderLoader.java | 94 +++++-------------- .../config/biome/SourceBuilderLoader.java | 33 +++++++ .../config/biome/StageBuilderLoader.java | 89 ++++++++++++++++++ common/src/test/java/biome/BiomeTest.java | 31 +++--- 7 files changed, 187 insertions(+), 93 deletions(-) create mode 100644 common/src/main/java/com/dfsek/terra/biome/pipeline/stages/SeededBuilder.java create mode 100644 common/src/main/java/com/dfsek/terra/config/loaders/config/biome/SourceBuilderLoader.java create mode 100644 common/src/main/java/com/dfsek/terra/config/loaders/config/biome/StageBuilderLoader.java diff --git a/common/src/main/java/com/dfsek/terra/biome/pipeline/BiomePipeline.java b/common/src/main/java/com/dfsek/terra/biome/pipeline/BiomePipeline.java index d3838e030..b3693381f 100644 --- a/common/src/main/java/com/dfsek/terra/biome/pipeline/BiomePipeline.java +++ b/common/src/main/java/com/dfsek/terra/biome/pipeline/BiomePipeline.java @@ -3,9 +3,11 @@ package com.dfsek.terra.biome.pipeline; import com.dfsek.terra.api.math.vector.Vector2; import com.dfsek.terra.api.util.GlueList; import com.dfsek.terra.biome.pipeline.source.BiomeSource; +import com.dfsek.terra.biome.pipeline.stages.SeededBuilder; import com.dfsek.terra.biome.pipeline.stages.Stage; import java.util.List; +import java.util.stream.Collectors; public class BiomePipeline { private final BiomeSource source; @@ -40,7 +42,7 @@ public class BiomePipeline { public static final class BiomePipelineBuilder { private final int init; - List stages = new GlueList<>(); + List> stages = new GlueList<>(); private int expand; public BiomePipelineBuilder(int init) { @@ -48,13 +50,18 @@ public class BiomePipeline { expand = init; } - public BiomePipeline build(BiomeSource source) { - return new BiomePipeline(source, stages, expand, init); + public BiomePipeline build(BiomeSource source, long seed) { + List stagesBuilt = stages.stream().map(stageBuilder -> stageBuilder.build(seed)).collect(Collectors.toList()); + + for(Stage stage : stagesBuilt) { + if(stage.isExpansion()) expand = expand * 2 - 1; + } + + return new BiomePipeline(source, stagesBuilt, expand, init); } - public BiomePipelineBuilder addStage(Stage stage) { + public BiomePipelineBuilder addStage(SeededBuilder stage) { stages.add(stage); - if(stage.isExpansion()) expand = expand * 2 - 1; return this; } } diff --git a/common/src/main/java/com/dfsek/terra/biome/pipeline/stages/SeededBuilder.java b/common/src/main/java/com/dfsek/terra/biome/pipeline/stages/SeededBuilder.java new file mode 100644 index 000000000..c7ca1b120 --- /dev/null +++ b/common/src/main/java/com/dfsek/terra/biome/pipeline/stages/SeededBuilder.java @@ -0,0 +1,15 @@ +package com.dfsek.terra.biome.pipeline.stages; + +import java.util.function.Function; + +public class SeededBuilder { + private final Function builder; + + public SeededBuilder(Function builder) { + this.builder = builder; + } + + public T build(long seed) { + return builder.apply(seed); + } +} diff --git a/common/src/main/java/com/dfsek/terra/biome/pipeline/stages/Stage.java b/common/src/main/java/com/dfsek/terra/biome/pipeline/stages/Stage.java index 6830c7da5..531313363 100644 --- a/common/src/main/java/com/dfsek/terra/biome/pipeline/stages/Stage.java +++ b/common/src/main/java/com/dfsek/terra/biome/pipeline/stages/Stage.java @@ -6,4 +6,5 @@ public interface Stage { boolean isExpansion(); BiomeHolder apply(BiomeHolder in); + } diff --git a/common/src/main/java/com/dfsek/terra/config/loaders/config/biome/BiomeProviderBuilderLoader.java b/common/src/main/java/com/dfsek/terra/config/loaders/config/biome/BiomeProviderBuilderLoader.java index 9f2a0d428..294ed15f6 100644 --- a/common/src/main/java/com/dfsek/terra/config/loaders/config/biome/BiomeProviderBuilderLoader.java +++ b/common/src/main/java/com/dfsek/terra/config/loaders/config/biome/BiomeProviderBuilderLoader.java @@ -3,26 +3,15 @@ package com.dfsek.terra.config.loaders.config.biome; import com.dfsek.tectonic.exception.LoadException; import com.dfsek.tectonic.loading.ConfigLoader; import com.dfsek.tectonic.loading.TypeLoader; -import com.dfsek.terra.api.math.ProbabilityCollection; -import com.dfsek.terra.api.math.noise.samplers.NoiseSampler; import com.dfsek.terra.api.platform.TerraPlugin; import com.dfsek.terra.api.world.biome.TerraBiome; import com.dfsek.terra.biome.BiomeProvider; import com.dfsek.terra.biome.ImageBiomeProvider; import com.dfsek.terra.biome.StandardBiomeProvider; import com.dfsek.terra.biome.pipeline.BiomePipeline; -import com.dfsek.terra.biome.pipeline.expand.FractalExpander; -import com.dfsek.terra.biome.pipeline.mutator.BorderListMutator; -import com.dfsek.terra.biome.pipeline.mutator.BorderMutator; -import com.dfsek.terra.biome.pipeline.mutator.ReplaceListMutator; -import com.dfsek.terra.biome.pipeline.mutator.ReplaceMutator; -import com.dfsek.terra.biome.pipeline.mutator.SmoothMutator; -import com.dfsek.terra.biome.pipeline.source.RandomSource; -import com.dfsek.terra.biome.pipeline.stages.ExpanderStage; -import com.dfsek.terra.biome.pipeline.stages.MutatorStage; +import com.dfsek.terra.biome.pipeline.source.BiomeSource; +import com.dfsek.terra.biome.pipeline.stages.SeededBuilder; import com.dfsek.terra.config.files.Loader; -import com.dfsek.terra.config.loaders.SelfProbabilityCollectionLoader; -import com.dfsek.terra.config.loaders.Types; import com.dfsek.terra.config.loaders.config.NoiseBuilderLoader; import com.dfsek.terra.debug.Debug; import com.dfsek.terra.generation.config.NoiseBuilder; @@ -32,7 +21,6 @@ import javax.imageio.ImageIO; import java.awt.image.BufferedImage; import java.io.IOException; import java.lang.reflect.Type; -import java.util.HashMap; import java.util.List; import java.util.Map; @@ -51,79 +39,37 @@ public class BiomeProviderBuilderLoader implements TypeLoader map = (Map) c; - int resolution = 1; if(map.containsKey("resolution")) resolution = Integer.parseInt(map.get("resolution").toString()); - if(map.get("type").equals("PIPELINE")) { Map pipeline = (Map) map.get("pipeline"); + + List> stages = (List>) pipeline.get("stages"); + + if(stages == null) throw new LoadException("No pipeline stages defined!"); + + int init; + if(pipeline.containsKey("initial-size")) init = Integer.parseInt(pipeline.get("initial-size").toString()); + else init = 3; + StandardBiomeProvider.StandardBiomeProviderBuilder builder = new StandardBiomeProvider.StandardBiomeProviderBuilder(seed -> { - - Map source = (Map) pipeline.get("source"); - ProbabilityCollection sourceBiomes = (ProbabilityCollection) loader.loadType(Types.TERRA_BIOME_PROBABILITY_COLLECTION_TYPE, source.get("biomes")); - NoiseSampler sourceNoise = new NoiseBuilderLoader().load(NoiseBuilder.class, source.get("noise"), loader).build((int) seed.longValue()); - - List> stages = (List>) pipeline.get("stages"); - - int init; - if(pipeline.containsKey("initial-size")) init = Integer.parseInt(pipeline.get("initial-size").toString()); - else init = 3; - BiomePipeline.BiomePipelineBuilder pipelineBuilder = new BiomePipeline.BiomePipelineBuilder(init); for(Map stage : stages) { for(Map.Entry entry : stage.entrySet()) { - Map mutator = (Map) entry.getValue(); - NoiseSampler mutatorNoise = new NoiseBuilderLoader().load(NoiseBuilder.class, mutator.get("noise"), loader).build((int) seed.longValue()); - - if(entry.getKey().equals("expand")) { - if(mutator.get("type").equals("FRACTAL")) - pipelineBuilder.addStage(new ExpanderStage(new FractalExpander(mutatorNoise))); - else throw new LoadException("No such expander \"" + mutator.get("type")); - } else if(entry.getKey().equals("mutate")) { - if(mutator.get("type").equals("SMOOTH")) { - pipelineBuilder.addStage(new MutatorStage(new SmoothMutator(mutatorNoise))); - } else if(mutator.get("type").equals("REPLACE")) { - String fromTag = mutator.get("from").toString(); - ProbabilityCollection replaceBiomes = new SelfProbabilityCollectionLoader().load(Types.TERRA_BIOME_PROBABILITY_COLLECTION_TYPE, mutator.get("to"), loader); - - pipelineBuilder.addStage(new MutatorStage(new ReplaceMutator(fromTag, replaceBiomes, mutatorNoise))); - } else if(mutator.get("type").equals("REPLACE_LIST")) { - String fromTag = mutator.get("default-from").toString(); - ProbabilityCollection replaceBiomes = new SelfProbabilityCollectionLoader().load(Types.TERRA_BIOME_PROBABILITY_COLLECTION_TYPE, mutator.get("default-to"), loader); - - Map> replace = new HashMap<>(); - for(Map.Entry e : ((Map) mutator.get("to")).entrySet()) { - replace.put((TerraBiome) loader.loadType(TerraBiome.class, e.getKey()), new SelfProbabilityCollectionLoader().load(Types.TERRA_BIOME_PROBABILITY_COLLECTION_TYPE, e.getValue(), loader)); - } - - pipelineBuilder.addStage(new MutatorStage(new ReplaceListMutator(replace, fromTag, replaceBiomes, mutatorNoise))); - } else if(mutator.get("type").equals("BORDER")) { - String fromTag = mutator.get("from").toString(); - String replaceTag = mutator.get("replace").toString(); - ProbabilityCollection replaceBiomes = new SelfProbabilityCollectionLoader().load(Types.TERRA_BIOME_PROBABILITY_COLLECTION_TYPE, mutator.get("to"), loader); - - pipelineBuilder.addStage(new MutatorStage(new BorderMutator(fromTag, replaceTag, mutatorNoise, replaceBiomes))); - } else if(mutator.get("type").equals("BORDER_LIST")) { - String fromTag = mutator.get("from").toString(); - String replaceTag = mutator.get("default-replace").toString(); - ProbabilityCollection replaceBiomes = new SelfProbabilityCollectionLoader().load(Types.TERRA_BIOME_PROBABILITY_COLLECTION_TYPE, mutator.get("default-to"), loader); - - Map> replace = new HashMap<>(); - for(Map.Entry e : ((Map) mutator.get("replace")).entrySet()) { - replace.put((TerraBiome) loader.loadType(TerraBiome.class, e.getKey()), new SelfProbabilityCollectionLoader().load(Types.TERRA_BIOME_PROBABILITY_COLLECTION_TYPE, e.getValue(), loader)); - } - - pipelineBuilder.addStage(new MutatorStage(new BorderListMutator(replace, fromTag, replaceTag, mutatorNoise, replaceBiomes))); - } else throw new LoadException("No such mutator type \"" + mutator.get("type")); - } else throw new LoadException("No such mutator \"" + entry.getKey() + "\""); + pipelineBuilder.addStage(new StageBuilderLoader().load(SeededBuilder.class, entry, loader)); } } - BiomePipeline biomePipeline = pipelineBuilder.build(new RandomSource(sourceBiomes, sourceNoise)); + + if(!pipeline.containsKey("source")) throw new LoadException("Biome Source not defined!"); + SeededBuilder source = new SourceBuilderLoader().load(BiomeSource.class, pipeline.get("source"), loader); + + BiomePipeline biomePipeline = pipelineBuilder.build(source.build(seed), seed); Debug.info("Biome Pipeline scale factor: " + biomePipeline.getSize()); return biomePipeline; }, main); + builder.setResolution(resolution); if(map.containsKey("blend")) { Map blend = (Map) map.get("blend"); @@ -141,6 +87,8 @@ public class BiomeProviderBuilderLoader implements TypeLoader> { + @Override + public SeededBuilder load(Type t, Object c, ConfigLoader loader) throws LoadException { + Map source = (Map) c; + + String type = source.get("type").toString(); + + if("NOISE".equals(type)) { + ProbabilityCollection sourceBiomes = (ProbabilityCollection) loader.loadType(Types.TERRA_BIOME_PROBABILITY_COLLECTION_TYPE, source.get("biomes")); + NoiseBuilder sourceNoise = new NoiseBuilderLoader().load(NoiseBuilder.class, source.get("noise"), loader); + return new SeededBuilder<>(seed -> new RandomSource(sourceBiomes, sourceNoise.build((int) seed.longValue()))); + } + throw new LoadException("No such loader type: " + type); + } +} diff --git a/common/src/main/java/com/dfsek/terra/config/loaders/config/biome/StageBuilderLoader.java b/common/src/main/java/com/dfsek/terra/config/loaders/config/biome/StageBuilderLoader.java new file mode 100644 index 000000000..5e041eb0c --- /dev/null +++ b/common/src/main/java/com/dfsek/terra/config/loaders/config/biome/StageBuilderLoader.java @@ -0,0 +1,89 @@ +package com.dfsek.terra.config.loaders.config.biome; + +import com.dfsek.tectonic.exception.LoadException; +import com.dfsek.tectonic.loading.ConfigLoader; +import com.dfsek.tectonic.loading.TypeLoader; +import com.dfsek.terra.api.math.ProbabilityCollection; +import com.dfsek.terra.api.world.biome.TerraBiome; +import com.dfsek.terra.biome.pipeline.expand.FractalExpander; +import com.dfsek.terra.biome.pipeline.mutator.BorderListMutator; +import com.dfsek.terra.biome.pipeline.mutator.BorderMutator; +import com.dfsek.terra.biome.pipeline.mutator.ReplaceListMutator; +import com.dfsek.terra.biome.pipeline.mutator.ReplaceMutator; +import com.dfsek.terra.biome.pipeline.mutator.SmoothMutator; +import com.dfsek.terra.biome.pipeline.stages.ExpanderStage; +import com.dfsek.terra.biome.pipeline.stages.MutatorStage; +import com.dfsek.terra.biome.pipeline.stages.SeededBuilder; +import com.dfsek.terra.biome.pipeline.stages.Stage; +import com.dfsek.terra.config.loaders.SelfProbabilityCollectionLoader; +import com.dfsek.terra.config.loaders.Types; +import com.dfsek.terra.config.loaders.config.NoiseBuilderLoader; +import com.dfsek.terra.generation.config.NoiseBuilder; + +import java.lang.reflect.Type; +import java.util.HashMap; +import java.util.Map; + +@SuppressWarnings("unchecked") +public class StageBuilderLoader implements TypeLoader> { + @Override + public SeededBuilder load(Type t, Object c, ConfigLoader loader) throws LoadException { + Map.Entry entry = (Map.Entry) c; + + Map mutator = (Map) entry.getValue(); + NoiseBuilder mutatorNoise = new NoiseBuilderLoader().load(NoiseBuilder.class, mutator.get("noise"), loader); + + if(entry.getKey().equals("expand")) { + if(mutator.get("type").equals("FRACTAL")) + return new SeededBuilder<>(seed -> new ExpanderStage(new FractalExpander(mutatorNoise.build((int) seed.longValue())))); + else throw new LoadException("No such expander \"" + mutator.get("type")); + } else if(entry.getKey().equals("mutate")) { + + switch(mutator.get("type").toString()) { + case "SMOOTH": { + return new SeededBuilder<>(seed -> new MutatorStage(new SmoothMutator(mutatorNoise.build((int) seed.longValue())))); + } + case "REPLACE": { + String fromTag = mutator.get("from").toString(); + ProbabilityCollection replaceBiomes = new SelfProbabilityCollectionLoader().load(Types.TERRA_BIOME_PROBABILITY_COLLECTION_TYPE, mutator.get("to"), loader); + + return new SeededBuilder<>(seed -> new MutatorStage(new ReplaceMutator(fromTag, replaceBiomes, mutatorNoise.build((int) seed.longValue())))); + } + case "REPLACE_LIST": { + String fromTag = mutator.get("default-from").toString(); + ProbabilityCollection replaceBiomes = new SelfProbabilityCollectionLoader().load(Types.TERRA_BIOME_PROBABILITY_COLLECTION_TYPE, mutator.get("default-to"), loader); + + Map> replace = new HashMap<>(); + for(Map.Entry e : ((Map) mutator.get("to")).entrySet()) { + replace.put((TerraBiome) loader.loadType(TerraBiome.class, e.getKey()), new SelfProbabilityCollectionLoader().load(Types.TERRA_BIOME_PROBABILITY_COLLECTION_TYPE, e.getValue(), loader)); + } + + return new SeededBuilder<>(seed -> new MutatorStage(new ReplaceListMutator(replace, fromTag, replaceBiomes, mutatorNoise.build((int) seed.longValue())))); + } + case "BORDER": { + String fromTag = mutator.get("from").toString(); + String replaceTag = mutator.get("replace").toString(); + ProbabilityCollection replaceBiomes = new SelfProbabilityCollectionLoader().load(Types.TERRA_BIOME_PROBABILITY_COLLECTION_TYPE, mutator.get("to"), loader); + + return new SeededBuilder<>(seed -> new MutatorStage(new BorderMutator(fromTag, replaceTag, mutatorNoise.build((int) seed.longValue()), replaceBiomes))); + } + case "BORDER_LIST": { + String fromTag = mutator.get("from").toString(); + String replaceTag = mutator.get("default-replace").toString(); + ProbabilityCollection replaceBiomes = new SelfProbabilityCollectionLoader().load(Types.TERRA_BIOME_PROBABILITY_COLLECTION_TYPE, mutator.get("default-to"), loader); + + Map> replace = new HashMap<>(); + for(Map.Entry e : ((Map) mutator.get("replace")).entrySet()) { + replace.put((TerraBiome) loader.loadType(TerraBiome.class, e.getKey()), new SelfProbabilityCollectionLoader().load(Types.TERRA_BIOME_PROBABILITY_COLLECTION_TYPE, e.getValue(), loader)); + } + + return new SeededBuilder<>(seed -> new MutatorStage(new BorderListMutator(replace, fromTag, replaceTag, mutatorNoise.build((int) seed.longValue()), replaceBiomes))); + } + default: + throw new LoadException("No such mutator type \"" + mutator.get("type")); + + } + } + throw new LoadException("No such mutator \"" + entry.getKey() + "\""); + } +} diff --git a/common/src/test/java/biome/BiomeTest.java b/common/src/test/java/biome/BiomeTest.java index f905f9a99..ec48dd1ad 100644 --- a/common/src/test/java/biome/BiomeTest.java +++ b/common/src/test/java/biome/BiomeTest.java @@ -18,6 +18,7 @@ import com.dfsek.terra.biome.pipeline.source.BiomeSource; import com.dfsek.terra.biome.pipeline.source.RandomSource; import com.dfsek.terra.biome.pipeline.stages.ExpanderStage; import com.dfsek.terra.biome.pipeline.stages.MutatorStage; +import com.dfsek.terra.biome.pipeline.stages.SeededBuilder; import org.junit.jupiter.api.Test; import javax.swing.*; @@ -63,21 +64,21 @@ public class BiomeTest { BiomeProvider provider = new StandardBiomeProvider.StandardBiomeProviderBuilder((seed) -> new BiomePipeline.BiomePipelineBuilder(2) - .addStage(new MutatorStage(new ReplaceMutator("LAND_TEMP", landBiomes, whiteNoise(243)))) - .addStage(new ExpanderStage(new FractalExpander(whiteNoise(2)))) - .addStage(new MutatorStage(new ReplaceMutator("OCEAN_TEMP", oceanBiomes, whiteNoise(243)))) - .addStage(new ExpanderStage(new FractalExpander(whiteNoise(2)))) - .addStage(new ExpanderStage(new FractalExpander(whiteNoise(2)))) - .addStage(new MutatorStage(new SmoothMutator(whiteNoise(3)))) - .addStage(new ExpanderStage(new FractalExpander(whiteNoise(4)))) - .addStage(new MutatorStage(new SmoothMutator(whiteNoise(6)))) - .addStage(new ExpanderStage(new FractalExpander(whiteNoise(4)))) - .addStage(new ExpanderStage(new FractalExpander(whiteNoise(4)))) - .addStage(new MutatorStage(new BorderMutator("OCEAN", "LAND", whiteNoise(1234), beachBiomes))) - .addStage(new ExpanderStage(new FractalExpander(whiteNoise(4)))) - .addStage(new MutatorStage(new SmoothMutator(whiteNoise(6)))) - .addStage(new MutatorStage(new SmoothMutator(whiteNoise(6)))) - .build(source), null).build(0); + .addStage(new SeededBuilder<>(s -> new MutatorStage(new ReplaceMutator("LAND_TEMP", landBiomes, whiteNoise(243))))) + .addStage(new SeededBuilder<>(s -> new ExpanderStage(new FractalExpander(whiteNoise(2))))) + .addStage(new SeededBuilder<>(s -> new MutatorStage(new ReplaceMutator("OCEAN_TEMP", oceanBiomes, whiteNoise(243))))) + .addStage(new SeededBuilder<>(s -> new ExpanderStage(new FractalExpander(whiteNoise(2))))) + .addStage(new SeededBuilder<>(s -> new ExpanderStage(new FractalExpander(whiteNoise(2))))) + .addStage(new SeededBuilder<>(s -> new MutatorStage(new SmoothMutator(whiteNoise(3))))) + .addStage(new SeededBuilder<>(s -> new ExpanderStage(new FractalExpander(whiteNoise(4))))) + .addStage(new SeededBuilder<>(s -> new MutatorStage(new SmoothMutator(whiteNoise(6))))) + .addStage(new SeededBuilder<>(s -> new ExpanderStage(new FractalExpander(whiteNoise(4))))) + .addStage(new SeededBuilder<>(s -> new ExpanderStage(new FractalExpander(whiteNoise(4))))) + .addStage(new SeededBuilder<>(s -> new MutatorStage(new BorderMutator("OCEAN", "LAND", whiteNoise(1234), beachBiomes)))) + .addStage(new SeededBuilder<>(s -> new ExpanderStage(new FractalExpander(whiteNoise(4))))) + .addStage(new SeededBuilder<>(s -> new MutatorStage(new SmoothMutator(whiteNoise(6))))) + .addStage(new SeededBuilder<>(s -> new MutatorStage(new SmoothMutator(whiteNoise(6))))) + .build(source, seed), null).build(0); int size = 1000;