diff --git a/common/src/main/java/com/dfsek/terra/biome/StandardBiomeProvider.java b/common/src/main/java/com/dfsek/terra/biome/StandardBiomeProvider.java index dbddf6360..b53bb80ed 100644 --- a/common/src/main/java/com/dfsek/terra/biome/StandardBiomeProvider.java +++ b/common/src/main/java/com/dfsek/terra/biome/StandardBiomeProvider.java @@ -1,5 +1,6 @@ package com.dfsek.terra.biome; +import com.dfsek.tectonic.exception.ConfigException; import com.dfsek.terra.api.math.vector.Vector2; import com.dfsek.terra.api.world.biome.TerraBiome; import com.dfsek.terra.biome.pipeline.BiomeHolder; @@ -11,11 +12,10 @@ import net.jafama.FastMath; import org.jetbrains.annotations.NotNull; import java.util.concurrent.ExecutionException; -import java.util.function.Function; public class StandardBiomeProvider implements BiomeProvider { private final BiomePipeline pipeline; - private final LoadingCache cache = CacheBuilder.newBuilder() + private final LoadingCache holderCache = CacheBuilder.newBuilder() .maximumSize(1024) .build( new CacheLoader() { @@ -25,6 +25,22 @@ public class StandardBiomeProvider implements BiomeProvider { } } ); + private final LoadingCache biomeCache = CacheBuilder.newBuilder() + .maximumSize(1024) + .build( + new CacheLoader() { + @Override + public TerraBiome load(@NotNull Vector2 key) throws ExecutionException { + int x = FastMath.floorToInt(key.getX()); + int z = FastMath.floorToInt(key.getZ()); + x /= resolution; + z /= resolution; + int fdX = FastMath.floorDiv(x, pipeline.getSize()); + int fdZ = FastMath.floorDiv(z, pipeline.getSize()); + return holderCache.get(new Vector2(fdX, fdZ)).getBiome(x - fdX * pipeline.getSize(), z - fdZ * pipeline.getSize()); + } + } + ); private int resolution = 4; protected StandardBiomeProvider(BiomePipeline pipeline) { @@ -33,10 +49,8 @@ public class StandardBiomeProvider implements BiomeProvider { @Override public TerraBiome getBiome(int x, int z) { - x /= resolution; - z /= resolution; try { - return cache.get(new Vector2(FastMath.floorDiv(x, pipeline.getSize()), FastMath.floorDiv(z, pipeline.getSize()))).getBiome(FastMath.floorMod(x, pipeline.getSize()), FastMath.floorMod(z, pipeline.getSize())); + return biomeCache.get(new Vector2(x, z)); } catch(ExecutionException e) { throw new RuntimeException(e); } @@ -50,16 +64,24 @@ public class StandardBiomeProvider implements BiomeProvider { this.resolution = resolution; } - public static final class StandardBiomeProviderBuilder implements BiomeProviderBuilder { - private final Function pipelineBuilder; + public interface ExceptionalFunction { + O apply(I in) throws ConfigException; + } - public StandardBiomeProviderBuilder(Function pipelineBuilder) { + public static final class StandardBiomeProviderBuilder implements BiomeProviderBuilder { + private final ExceptionalFunction pipelineBuilder; + + public StandardBiomeProviderBuilder(ExceptionalFunction pipelineBuilder) { this.pipelineBuilder = pipelineBuilder; } @Override public StandardBiomeProvider build(long seed) { - return new StandardBiomeProvider(pipelineBuilder.apply(seed)); + try { + return new StandardBiomeProvider(pipelineBuilder.apply(seed)); + } catch(ConfigException e) { + throw new RuntimeException(e); + } } } } diff --git a/common/src/main/java/com/dfsek/terra/config/base/ConfigPack.java b/common/src/main/java/com/dfsek/terra/config/base/ConfigPack.java index 9118ee389..f263b3fe3 100644 --- a/common/src/main/java/com/dfsek/terra/config/base/ConfigPack.java +++ b/common/src/main/java/com/dfsek/terra/config/base/ConfigPack.java @@ -29,7 +29,7 @@ import com.dfsek.terra.config.files.FolderLoader; import com.dfsek.terra.config.files.Loader; import com.dfsek.terra.config.files.ZIPLoader; import com.dfsek.terra.config.lang.LangUtil; -import com.dfsek.terra.config.loaders.config.BiomeProviderBuilderLoader; +import com.dfsek.terra.config.loaders.config.biome.BiomeProviderBuilderLoader; import com.dfsek.terra.config.templates.AbstractableTemplate; import com.dfsek.terra.config.templates.BiomeTemplate; import com.dfsek.terra.config.templates.CarverTemplate; diff --git a/common/src/main/java/com/dfsek/terra/config/loaders/Types.java b/common/src/main/java/com/dfsek/terra/config/loaders/Types.java index d4f0d17cc..ec20b68c7 100644 --- a/common/src/main/java/com/dfsek/terra/config/loaders/Types.java +++ b/common/src/main/java/com/dfsek/terra/config/loaders/Types.java @@ -3,6 +3,7 @@ package com.dfsek.terra.config.loaders; import com.dfsek.terra.api.math.ProbabilityCollection; import com.dfsek.terra.api.platform.block.BlockData; import com.dfsek.terra.api.platform.block.MaterialData; +import com.dfsek.terra.api.world.biome.TerraBiome; import com.dfsek.terra.api.world.flora.Flora; import com.dfsek.terra.api.world.palette.Palette; import com.dfsek.terra.api.world.tree.Tree; @@ -21,6 +22,7 @@ public final class Types { public static final Type BLOCK_DATA_PROBABILITY_COLLECTION_TYPE; public static final Type FLORA_PROBABILITY_COLLECTION_TYPE; public static final Type TREE_PROBABILITY_COLLECTION_TYPE; + public static final Type TERRA_BIOME_PROBABILITY_COLLECTION_TYPE; static { MATERIAL_SET_TYPE = getType("materialSet"); @@ -29,6 +31,7 @@ public final class Types { BLOCK_DATA_PROBABILITY_COLLECTION_TYPE = getType("blockDataProbabilityCollection"); FLORA_PROBABILITY_COLLECTION_TYPE = getType("floraProbabilityCollection"); TREE_PROBABILITY_COLLECTION_TYPE = getType("treeProbabilityCollection"); + TERRA_BIOME_PROBABILITY_COLLECTION_TYPE = getType("terraBiomeProbabilityCollection"); } private Set materialSet; @@ -37,6 +40,7 @@ public final class Types { private ProbabilityCollection blockDataProbabilityCollection; private ProbabilityCollection floraProbabilityCollection; private ProbabilityCollection treeProbabilityCollection; + private ProbabilityCollection terraBiomeProbabilityCollection; private static Type getType(String dummyFieldName) { try { diff --git a/common/src/main/java/com/dfsek/terra/config/loaders/config/BiomeProviderBuilderLoader.java b/common/src/main/java/com/dfsek/terra/config/loaders/config/BiomeProviderBuilderLoader.java deleted file mode 100644 index 52d421971..000000000 --- a/common/src/main/java/com/dfsek/terra/config/loaders/config/BiomeProviderBuilderLoader.java +++ /dev/null @@ -1,56 +0,0 @@ -package com.dfsek.terra.config.loaders.config; - -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.FastNoiseLite; -import com.dfsek.terra.api.math.noise.samplers.NoiseSampler; -import com.dfsek.terra.api.world.biome.TerraBiome; -import com.dfsek.terra.biome.BiomeProvider; -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.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.config.base.ConfigPack; -import net.jafama.FastMath; - -import java.lang.reflect.Type; - -public class BiomeProviderBuilderLoader implements TypeLoader { - private final ConfigPack pack; - - public BiomeProviderBuilderLoader(ConfigPack pack) { - this.pack = pack; - } - - private static NoiseSampler whiteNoise(int seed) { - FastNoiseLite noiseLite = new FastNoiseLite(seed); - noiseLite.setNoiseType(FastNoiseLite.NoiseType.WhiteNoise); - return noiseLite; - } - - @Override - public BiomeProvider.BiomeProviderBuilder load(Type t, Object c, ConfigLoader loader) { - - - return new StandardBiomeProvider.StandardBiomeProviderBuilder(seed -> { - ProbabilityCollection biomes = new ProbabilityCollection<>(); - - biomes.add(pack.getBiome("PLAINS"), 1) - .add(pack.getBiome("SAVANNA"), 2); - BiomePipeline pipeline = new BiomePipeline.BiomePipelineBuilder(2) - .addStage(new ExpanderStage(new FractalExpander(whiteNoise(FastMath.toInt(seed))))) - .addStage(new ExpanderStage(new FractalExpander(whiteNoise(FastMath.toInt(seed + 1))))) - .addStage(new ExpanderStage(new FractalExpander(whiteNoise(FastMath.toInt(seed + 2))))) - .addStage(new MutatorStage(new SmoothMutator(whiteNoise(FastMath.toInt(seed + 3))))) - .addStage(new ExpanderStage(new FractalExpander(whiteNoise(FastMath.toInt(seed + 4))))) - .addStage(new ExpanderStage(new FractalExpander(whiteNoise(FastMath.toInt(seed + 5))))) - .build(new RandomSource(biomes, whiteNoise(FastMath.toInt(seed) + 4))); - System.out.println(pipeline.getSize()); - return pipeline; - }); - } -} 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 new file mode 100644 index 000000000..55afacc27 --- /dev/null +++ b/common/src/main/java/com/dfsek/terra/config/loaders/config/biome/BiomeProviderBuilderLoader.java @@ -0,0 +1,77 @@ +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.FastNoiseLite; +import com.dfsek.terra.api.math.noise.samplers.NoiseSampler; +import com.dfsek.terra.api.world.biome.TerraBiome; +import com.dfsek.terra.biome.BiomeProvider; +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.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.config.base.ConfigPack; +import com.dfsek.terra.config.loaders.Types; +import com.dfsek.terra.config.loaders.config.NoiseBuilderLoader; +import com.dfsek.terra.generation.config.NoiseBuilder; +import net.jafama.FastMath; + +import java.lang.reflect.Type; +import java.util.List; +import java.util.Map; + +@SuppressWarnings("unchecked") +public class BiomeProviderBuilderLoader implements TypeLoader { + private final ConfigPack pack; + + public BiomeProviderBuilderLoader(ConfigPack pack) { + this.pack = pack; + } + + private static NoiseSampler whiteNoise(int seed) { + FastNoiseLite noiseLite = new FastNoiseLite(seed); + noiseLite.setNoiseType(FastNoiseLite.NoiseType.WhiteNoise); + return noiseLite; + } + + @Override + public BiomeProvider.BiomeProviderBuilder load(Type t, Object c, ConfigLoader loader) { + Map map = (Map) c; + + return new StandardBiomeProvider.StandardBiomeProviderBuilder(seed -> { + Map source = (Map) map.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(FastMath.toInt(seed)); + + List> stages = (List>) map.get("pipeline"); + BiomePipeline.BiomePipelineBuilder pipelineBuilder = new BiomePipeline.BiomePipelineBuilder(2); + 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(FastMath.toInt(seed)); + + 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 = (ProbabilityCollection) loader.loadType(Types.TERRA_BIOME_PROBABILITY_COLLECTION_TYPE, mutator.get("to")); + pipelineBuilder.addStage(new MutatorStage(new ReplaceMutator(fromTag, replaceBiomes, mutatorNoise))); + } else throw new LoadException("No such mutator type \"" + mutator.get("type")); + } else throw new LoadException("No such mutator \"" + entry.getKey() + "\""); + } + } + return pipelineBuilder.build(new RandomSource(sourceBiomes, sourceNoise)); + }); + } +} diff --git a/common/src/test/java/biome/BiomeTest.java b/common/src/test/java/biome/BiomeTest.java index e3fee0794..66a7f6f3d 100644 --- a/common/src/test/java/biome/BiomeTest.java +++ b/common/src/test/java/biome/BiomeTest.java @@ -9,11 +9,14 @@ import com.dfsek.terra.api.world.biome.TerraBiome; import com.dfsek.terra.biome.pipeline.BiomeHolder; import com.dfsek.terra.biome.pipeline.BiomePipeline; import com.dfsek.terra.biome.pipeline.expand.FractalExpander; +import com.dfsek.terra.biome.pipeline.mutator.BorderMutator; +import com.dfsek.terra.biome.pipeline.mutator.ReplaceMutator; import com.dfsek.terra.biome.pipeline.mutator.SmoothMutator; 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.google.common.collect.Sets; import org.junit.jupiter.api.Test; import javax.swing.*; @@ -41,7 +44,7 @@ public class BiomeTest { ProbabilityCollection climate = new ProbabilityCollection<>(); climate.add(ocean, 1); - climate.add(land, 3); + climate.add(land, 2); oceanBiomes.add(new TestBiome(Color.BLUE, "OCEAN"), 10); @@ -61,9 +64,13 @@ public class BiomeTest { BiomePipeline pipeline = new BiomePipeline.BiomePipelineBuilder(20) .addStage(new ExpanderStage(new FractalExpander(whiteNoise(1)))) + .addStage(new MutatorStage(new ReplaceMutator("OCEAN_TEMP", oceanBiomes, whiteNoise(243)))) + .addStage(new MutatorStage(new ReplaceMutator("LAND_TEMP", landBiomes, 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 BorderMutator(Sets.newHashSet("OCEAN"), "LAND", whiteNoise(1234), beachBiomes))) .addStage(new ExpanderStage(new FractalExpander(whiteNoise(5)))) .addStage(new MutatorStage(new SmoothMutator(whiteNoise(6)))) .build(source); @@ -73,25 +80,6 @@ public class BiomeTest { BiomeHolder holder3 = pipeline.getBiomes(0, 1); BiomeHolder holder4 = pipeline.getBiomes(1, 1); - //holder = holder.expand(new FractalExpander(whiteNoise(4))); - - //holder.mutate(new ReplaceMutator("OCEAN_TEMP", oceanBiomes, whiteNoise(234))); - //holder.mutate(new ReplaceMutator("LAND_TEMP", landBiomes, whiteNoise(235))); - - //holder = holder.expand(new FractalExpander(whiteNoise(3))); - //holder = holder.expand(new FractalExpander(whiteNoise(2))); - - //holder.mutate(new SmoothMutator(whiteNoise(34))); - - //holder = holder.expand(new FractalExpander(whiteNoise(5))); - //holder = holder.expand(new FractalExpander(whiteNoise(7))); - - //holder.mutate(new BorderMutator(Sets.newHashSet("OCEAN"), "LAND", whiteNoise(2356), beachBiomes)); - - //holder = holder.expand(new FractalExpander(whiteNoise(6))); - - //holder.mutate(new SmoothMutator(whiteNoise(35))); - long e = System.nanoTime(); int size = pipeline.getSize();