diff --git a/common/src/main/java/com/dfsek/terra/api/GenericLoaders.java b/common/src/main/java/com/dfsek/terra/api/GenericLoaders.java index 21f34a35a..8ad9c2fd7 100644 --- a/common/src/main/java/com/dfsek/terra/api/GenericLoaders.java +++ b/common/src/main/java/com/dfsek/terra/api/GenericLoaders.java @@ -6,7 +6,6 @@ import com.dfsek.terra.api.math.ProbabilityCollection; import com.dfsek.terra.api.math.Range; import com.dfsek.terra.api.math.noise.samplers.Normalizer; import com.dfsek.terra.api.platform.TerraPlugin; -import com.dfsek.terra.biome.BiomeProvider; import com.dfsek.terra.biome.palette.PaletteHolder; import com.dfsek.terra.biome.palette.PaletteLayer; import com.dfsek.terra.carving.CarverPalette; @@ -19,7 +18,6 @@ import com.dfsek.terra.config.loaders.config.NoiseBuilderLoader; import com.dfsek.terra.config.loaders.config.OreConfigLoader; import com.dfsek.terra.config.loaders.config.OreHolderLoader; import com.dfsek.terra.config.loaders.config.TreeLayerLoader; -import com.dfsek.terra.config.loaders.config.biome.BiomeProviderBuilderLoader; import com.dfsek.terra.config.loaders.palette.CarverPaletteLoader; import com.dfsek.terra.config.loaders.palette.PaletteHolderLoader; import com.dfsek.terra.config.loaders.palette.PaletteLayerLoader; @@ -55,7 +53,6 @@ public class GenericLoaders implements LoaderRegistrar { .registerLoader(MaterialSet.class, new MaterialSetLoader()) .registerLoader(OreHolder.class, new OreHolderLoader()) .registerLoader(TerraFlora.Search.class, (t, o, l) -> TerraFlora.Search.valueOf(o.toString())) - .registerLoader(Normalizer.NormalType.class, (t, o, l) -> Normalizer.NormalType.valueOf(o.toString().toUpperCase())) - .registerLoader(BiomeProvider.BiomeProviderBuilder.class, new BiomeProviderBuilderLoader(main)); + .registerLoader(Normalizer.NormalType.class, (t, o, l) -> Normalizer.NormalType.valueOf(o.toString().toUpperCase())); } } diff --git a/common/src/main/java/com/dfsek/terra/api/world/biome/TerraBiome.java b/common/src/main/java/com/dfsek/terra/api/world/biome/TerraBiome.java index 82cb27815..605672887 100644 --- a/common/src/main/java/com/dfsek/terra/api/world/biome/TerraBiome.java +++ b/common/src/main/java/com/dfsek/terra/api/world/biome/TerraBiome.java @@ -30,4 +30,6 @@ public interface TerraBiome { int getColor(); Set getTags(); + + String getID(); } diff --git a/common/src/main/java/com/dfsek/terra/biome/ImageBiomeProvider.java b/common/src/main/java/com/dfsek/terra/biome/ImageBiomeProvider.java new file mode 100644 index 000000000..f0924f1e8 --- /dev/null +++ b/common/src/main/java/com/dfsek/terra/biome/ImageBiomeProvider.java @@ -0,0 +1,54 @@ +package com.dfsek.terra.biome; + +import com.dfsek.terra.api.world.biome.TerraBiome; +import com.dfsek.terra.registry.TerraRegistry; +import net.jafama.FastMath; + +import java.awt.*; +import java.awt.image.BufferedImage; +import java.util.HashMap; +import java.util.Map; + +public class ImageBiomeProvider implements BiomeProvider { + private final Map colorBiomeMap = new HashMap<>(); + private final BufferedImage image; + private final int resolution; + + public ImageBiomeProvider(TerraRegistry registry, BufferedImage image, int resolution) { + this.image = image; + this.resolution = resolution; + registry.forEach(biome -> colorBiomeMap.put(new Color(biome.getColor()), biome)); + } + + private static int distance(Color a, Color b) { + return FastMath.abs(a.getRed() - b.getRed()) + FastMath.abs(a.getGreen() - b.getGreen()) + FastMath.abs(a.getBlue() - b.getBlue()); + } + + @Override + public TerraBiome getBiome(int x, int z) { + Color color = new Color(image.getRGB(FastMath.floorMod(x / resolution, image.getWidth()), FastMath.floorMod(z / resolution, image.getHeight()))); + + return colorBiomeMap.get(colorBiomeMap.keySet().stream().reduce(colorBiomeMap.keySet().stream().findAny().orElseThrow(IllegalStateException::new), (running, element) -> { + int d1 = distance(color, running); + int d2 = distance(color, element); + return d1 < d2 ? running : element; + })); + } + + public static class ImageBiomeProviderBuilder implements BiomeProviderBuilder { + private final BufferedImage image; + private final int resolution; + private final TerraRegistry registry; + + public ImageBiomeProviderBuilder(BufferedImage image, int resolution, TerraRegistry registry) { + this.image = image; + this.resolution = resolution; + this.registry = registry; + } + + @Override + public BiomeProvider build(long seed) { + return new ImageBiomeProvider(registry, image, resolution); + } + } +} diff --git a/common/src/main/java/com/dfsek/terra/biome/UserDefinedBiome.java b/common/src/main/java/com/dfsek/terra/biome/UserDefinedBiome.java index c0f57197b..153878883 100644 --- a/common/src/main/java/com/dfsek/terra/biome/UserDefinedBiome.java +++ b/common/src/main/java/com/dfsek/terra/biome/UserDefinedBiome.java @@ -5,7 +5,6 @@ import com.dfsek.terra.api.platform.world.Biome; import com.dfsek.terra.api.platform.world.World; import com.dfsek.terra.api.world.biome.Generator; import com.dfsek.terra.api.world.biome.TerraBiome; -import com.dfsek.terra.config.base.ConfigPack; import com.dfsek.terra.config.builder.GeneratorBuilder; import com.dfsek.terra.config.templates.BiomeTemplate; @@ -20,18 +19,15 @@ public class UserDefinedBiome implements TerraBiome { private final ProbabilityCollection vanilla; private final String id; private final BiomeTemplate config; - private final ConfigPack pack; - private UserDefinedBiome erode; private final int color; private final Set tags; - public UserDefinedBiome(ProbabilityCollection vanilla, GeneratorBuilder gen, BiomeTemplate config, ConfigPack pack) { + public UserDefinedBiome(ProbabilityCollection vanilla, GeneratorBuilder gen, BiomeTemplate config) { this.vanilla = vanilla; this.gen = gen; this.id = config.getID(); this.config = config; - this.pack = pack; this.color = config.getColor(); this.tags = config.getTags() == null ? new HashSet<>() : config.getTags(); tags.add("BIOME:" + id); @@ -47,19 +43,11 @@ public class UserDefinedBiome implements TerraBiome { return vanilla; } - + @Override public String getID() { return id; } - public UserDefinedBiome getErode() { - if(erode == null) { - erode = (config.getErode() == null) ? this : pack.getBiome(config.getErode()); - } - return erode; - } - - public BiomeTemplate getConfig() { return config; } 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 fa16ddced..d3838e030 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 @@ -20,6 +20,13 @@ public class BiomePipeline { this.init = init; } + /** + * Get biomes in a chunk + * + * @param x Chunk X coord + * @param z Chunk Z coord + * @return BiomeHolder containing biomes. + */ public BiomeHolder getBiomes(int x, int z) { BiomeHolder holder = new TerraBiomeHolder(init, new Vector2(x * (init - 1), z * (init - 1))); holder.fill(source); 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 4e656f1a4..14b393f4d 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 @@ -13,7 +13,7 @@ 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; -import com.dfsek.terra.biome.UserDefinedBiome; +import com.dfsek.terra.biome.BiomeProvider; import com.dfsek.terra.carving.UserDefinedCarver; import com.dfsek.terra.config.exception.FileMissingException; import com.dfsek.terra.config.factories.BiomeFactory; @@ -28,6 +28,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.biome.BiomeProviderBuilderLoader; import com.dfsek.terra.config.templates.AbstractableTemplate; import com.dfsek.terra.config.templates.BiomeTemplate; import com.dfsek.terra.config.templates.CarverTemplate; @@ -59,14 +60,13 @@ import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; import java.nio.charset.StandardCharsets; -import java.util.ArrayList; import java.util.Collection; import java.util.Enumeration; import java.util.List; import java.util.Map; -import java.util.Objects; import java.util.Set; import java.util.logging.Level; +import java.util.stream.Collectors; import java.util.zip.ZipEntry; import java.util.zip.ZipFile; @@ -92,8 +92,13 @@ public class ConfigPack implements LoaderRegistrar { private final SamplerCache samplerCache; + private final TerraPlugin main; + private final Loader loader; + public ConfigPack(File folder, TerraPlugin main) throws ConfigException { + this.loader = new FolderLoader(folder.toPath()); + this.main = main; long l = System.nanoTime(); this.samplerCache = new SamplerCache(main); floraRegistry = new FloraRegistry(main); @@ -112,11 +117,12 @@ public class ConfigPack implements LoaderRegistrar { } catch(FileNotFoundException e) { throw new FileMissingException("No pack.yml file found in " + folder.getAbsolutePath(), e); } - - load(new FolderLoader(folder.toPath()), l, main); + load(l, main); } public ConfigPack(ZipFile file, TerraPlugin main) throws ConfigException { + this.loader = new ZIPLoader(file); + this.main = main; long l = System.nanoTime(); this.samplerCache = new SamplerCache(main); floraRegistry = new FloraRegistry(main); @@ -143,12 +149,13 @@ public class ConfigPack implements LoaderRegistrar { selfLoader.load(template, stream); - load(new ZIPLoader(file), l, main); + + load(l, main); template.getProviderBuilder().build(0); // Build dummy provider to catch errors at load time. } - private void load(Loader loader, long start, TerraPlugin main) throws ConfigException { + private void load(long start, TerraPlugin main) throws ConfigException { for(Map.Entry var : template.getVariables().entrySet()) { varScope.create(var.getKey()).setValue(var.getValue()); } @@ -185,14 +192,6 @@ public class ConfigPack implements LoaderRegistrar { .open("biomes", ".yml").then(streams -> buildAll(new BiomeFactory(this), biomeRegistry, abstractConfigLoader.load(streams, () -> new BiomeTemplate(this, main)), main)).close(); - for(UserDefinedBiome b : biomeRegistry.entries()) { - try { - Objects.requireNonNull(b.getErode()); // Throws NPE if it cannot load erosion biomes. - } catch(NullPointerException e) { - throw new LoadException("Invalid erosion biome defined in biome \"" + b.getID() + "\"", e); - } - } - LangUtil.log("config-pack.loaded", Level.INFO, template.getID(), String.valueOf((System.nanoTime() - start) / 1000000D), template.getAuthor(), template.getVersion()); } @@ -200,14 +199,12 @@ public class ConfigPack implements LoaderRegistrar { for(C template : configTemplates) registry.add(template.getID(), factory.build(template, main)); } - public UserDefinedBiome getBiome(String id) { + public TerraBiome getBiome(String id) { return biomeRegistry.get(id); } public List getBiomeIDs() { - List biomeIDs = new ArrayList<>(); - biomeRegistry.forEach(biome -> biomeIDs.add(biome.getID())); - return biomeIDs; + return biomeRegistry.entries().stream().map(TerraBiome::getID).collect(Collectors.toList()); } public TerraStructure getStructure(String id) { @@ -227,9 +224,7 @@ public class ConfigPack implements LoaderRegistrar { } public List getStructureIDs() { - List ids = new ArrayList<>(); - structureRegistry.forEach(structure -> ids.add(structure.getTemplate().getID())); - return ids; + return structureRegistry.entries().stream().map(terraStructure -> terraStructure.getTemplate().getID()).collect(Collectors.toList()); } public TreeRegistry getTreeRegistry() { @@ -256,7 +251,8 @@ public class ConfigPack implements LoaderRegistrar { .registerLoader(Tree.class, treeRegistry) .registerLoader(StructureScript.class, scriptRegistry) .registerLoader(TerraStructure.class, structureRegistry) - .registerLoader(LootTable.class, lootRegistry); + .registerLoader(LootTable.class, lootRegistry) + .registerLoader(BiomeProvider.BiomeProviderBuilder.class, new BiomeProviderBuilderLoader(main, biomeRegistry, loader)); } public ScriptRegistry getScriptRegistry() { diff --git a/common/src/main/java/com/dfsek/terra/config/base/ConfigPackTemplate.java b/common/src/main/java/com/dfsek/terra/config/base/ConfigPackTemplate.java index 16095467f..f71c79d56 100644 --- a/common/src/main/java/com/dfsek/terra/config/base/ConfigPackTemplate.java +++ b/common/src/main/java/com/dfsek/terra/config/base/ConfigPackTemplate.java @@ -92,7 +92,7 @@ public class ConfigPackTemplate implements ValidatedConfigTemplate { @Default private String version = "0.1.0"; - @Value("biome-pipeline") + @Value("biomes") private BiomeProvider.BiomeProviderBuilder providerBuilder; public BiomeProvider.BiomeProviderBuilder getProviderBuilder() { diff --git a/common/src/main/java/com/dfsek/terra/config/factories/BiomeFactory.java b/common/src/main/java/com/dfsek/terra/config/factories/BiomeFactory.java index a0bd7aa2d..82ba62bb9 100644 --- a/common/src/main/java/com/dfsek/terra/config/factories/BiomeFactory.java +++ b/common/src/main/java/com/dfsek/terra/config/factories/BiomeFactory.java @@ -1,12 +1,13 @@ package com.dfsek.terra.config.factories; import com.dfsek.terra.api.platform.TerraPlugin; +import com.dfsek.terra.api.world.biome.TerraBiome; import com.dfsek.terra.biome.UserDefinedBiome; import com.dfsek.terra.config.base.ConfigPack; import com.dfsek.terra.config.builder.GeneratorBuilder; import com.dfsek.terra.config.templates.BiomeTemplate; -public class BiomeFactory implements TerraFactory { +public class BiomeFactory implements TerraFactory { private final ConfigPack pack; public BiomeFactory(ConfigPack pack) { @@ -29,6 +30,6 @@ public class BiomeFactory implements TerraFactory { private final TerraPlugin main; + private final TerraRegistry biomeRegistry; + private final Loader fileLoader; - public BiomeProviderBuilderLoader(TerraPlugin main) { + public BiomeProviderBuilderLoader(TerraPlugin main, TerraRegistry biomeRegistry, Loader fileLoader) { this.main = main; + this.biomeRegistry = biomeRegistry; + this.fileLoader = fileLoader; } @Override public BiomeProvider.BiomeProviderBuilder load(Type t, Object c, ConfigLoader loader) throws LoadException { Map map = (Map) c; - StandardBiomeProvider.StandardBiomeProviderBuilder builder = 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((int) seed.longValue()); + int resolution = 1; + if(map.containsKey("resolution")) resolution = Integer.parseInt(map.get("resolution").toString()); - List> stages = (List>) map.get("pipeline"); - int init; - if(map.containsKey("initial-size")) init = Integer.parseInt(map.get("initial-size").toString()); - else init = 3; + if(map.get("type").equals("PIPELINE")) { + Map pipeline = (Map) map.get("pipeline"); + StandardBiomeProvider.StandardBiomeProviderBuilder builder = new StandardBiomeProvider.StandardBiomeProviderBuilder(seed -> { - BiomePipeline.BiomePipelineBuilder pipelineBuilder = new BiomePipeline.BiomePipelineBuilder(init); + 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()); - 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()); + List> stages = (List>) pipeline.get("stages"); - 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("BORDER")) { - String fromTag = mutator.get("from").toString(); - String replaceTag = mutator.get("replace").toString(); - ProbabilityCollection replaceBiomes = (ProbabilityCollection) loader.loadType(Types.TERRA_BIOME_PROBABILITY_COLLECTION_TYPE, mutator.get("to")); - pipelineBuilder.addStage(new MutatorStage(new BorderMutator(fromTag, replaceTag, mutatorNoise, replaceBiomes))); - } else throw new LoadException("No such mutator type \"" + mutator.get("type")); - } else throw new LoadException("No such mutator \"" + entry.getKey() + "\""); + 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("BORDER")) { + String fromTag = mutator.get("from").toString(); + String replaceTag = mutator.get("replace").toString(); + ProbabilityCollection replaceBiomes = (ProbabilityCollection) loader.loadType(Types.TERRA_BIOME_PROBABILITY_COLLECTION_TYPE, mutator.get("to")); + pipelineBuilder.addStage(new MutatorStage(new BorderMutator(fromTag, replaceTag, mutatorNoise, replaceBiomes))); + } else throw new LoadException("No such mutator type \"" + mutator.get("type")); + } else throw new LoadException("No such mutator \"" + entry.getKey() + "\""); + } } + BiomePipeline biomePipeline = pipelineBuilder.build(new RandomSource(sourceBiomes, sourceNoise)); + Debug.info("Biome Pipeline scale factor: " + biomePipeline.getSize()); + return biomePipeline; + }, main); + builder.setResolution(resolution); + if(map.containsKey("blend")) { + Map blend = (Map) map.get("blend"); + if(blend.containsKey("amplitude")) builder.setNoiseAmp(Integer.parseInt(blend.get("amplitude").toString())); + if(blend.containsKey("noise")) + builder.setBuilder(new NoiseBuilderLoader().load(NoiseBuilder.class, blend.get("noise"), loader)); } - BiomePipeline pipeline = pipelineBuilder.build(new RandomSource(sourceBiomes, sourceNoise)); - Debug.info("Biome Pipeline scale factor: " + pipeline.getSize()); - return pipeline; - }, main); - if(map.containsKey("resolution")) builder.setResolution(Integer.parseInt(map.get("resolution").toString())); - if(map.containsKey("blend")) { - Map blend = (Map) map.get("blend"); - if(blend.containsKey("amplitude")) builder.setNoiseAmp(Integer.parseInt(blend.get("amplitude").toString())); - if(blend.containsKey("noise")) - builder.setBuilder(new NoiseBuilderLoader().load(NoiseBuilder.class, blend.get("noise"), loader)); - } - return builder; + return builder; + } else if(map.get("type").equals("IMAGE")) { + Map imageMap = (Map) map.get("image"); + try { + main.getLogger().info("Using image " + imageMap.get("name") + " for biome distribution."); + BufferedImage image = ImageIO.read(fileLoader.get(imageMap.get("name").toString())); + return new ImageBiomeProvider.ImageBiomeProviderBuilder(image, resolution, biomeRegistry); + } catch(IOException e) { + throw new LoadException("Failed to load image", e); + } + } else throw new LoadException("No such biome provider type: " + map.get("type")); } } diff --git a/common/src/main/java/com/dfsek/terra/registry/BiomeRegistry.java b/common/src/main/java/com/dfsek/terra/registry/BiomeRegistry.java index 66c59dc3c..2781b59f1 100644 --- a/common/src/main/java/com/dfsek/terra/registry/BiomeRegistry.java +++ b/common/src/main/java/com/dfsek/terra/registry/BiomeRegistry.java @@ -1,6 +1,6 @@ package com.dfsek.terra.registry; -import com.dfsek.terra.biome.UserDefinedBiome; +import com.dfsek.terra.api.world.biome.TerraBiome; -public class BiomeRegistry extends TerraRegistry { +public class BiomeRegistry extends TerraRegistry { } diff --git a/common/src/test/java/biome/DistributionTest.java b/common/src/test/java/biome/DistributionTest.java index 8239c7ebc..4305b5cd0 100644 --- a/common/src/test/java/biome/DistributionTest.java +++ b/common/src/test/java/biome/DistributionTest.java @@ -21,7 +21,7 @@ import com.dfsek.terra.config.loaders.ProbabilityCollectionLoader; import com.dfsek.terra.config.loaders.config.biome.BiomeProviderBuilderLoader; import com.dfsek.terra.config.templates.AbstractableTemplate; import com.dfsek.terra.debug.Debug; -import com.dfsek.terra.registry.TerraRegistry; +import com.dfsek.terra.registry.BiomeRegistry; import org.junit.jupiter.api.Test; import javax.swing.*; @@ -48,13 +48,12 @@ public class DistributionTest { AbstractConfigLoader loader = new AbstractConfigLoader(); - TerraRegistry biomeRegistry = new TerraRegistry() { - }; + BiomeRegistry biomeRegistry = new BiomeRegistry(); folderLoader.open("biomes", ".yml").then(inputStreams -> ConfigPack.buildAll((template, main) -> template, biomeRegistry, loader.load(inputStreams, TestBiome::new), null)); BiomeProviderTemplate template = new BiomeProviderTemplate(); ConfigLoader pipeLoader = new ConfigLoader() - .registerLoader(BiomeProvider.BiomeProviderBuilder.class, new BiomeProviderBuilderLoader(null)) + .registerLoader(BiomeProvider.BiomeProviderBuilder.class, new BiomeProviderBuilderLoader(null, biomeRegistry, folderLoader)) .registerLoader(ProbabilityCollection.class, new ProbabilityCollectionLoader()) .registerLoader(TerraBiome.class, biomeRegistry); new GenericLoaders(null).register(pipeLoader); diff --git a/common/src/test/java/biome/ImageTest.java b/common/src/test/java/biome/ImageTest.java new file mode 100644 index 000000000..82b69c7d0 --- /dev/null +++ b/common/src/test/java/biome/ImageTest.java @@ -0,0 +1,222 @@ +package biome; + +import com.dfsek.tectonic.abstraction.AbstractConfigLoader; +import com.dfsek.tectonic.annotations.Abstractable; +import com.dfsek.tectonic.annotations.Default; +import com.dfsek.tectonic.annotations.Value; +import com.dfsek.tectonic.config.ConfigTemplate; +import com.dfsek.tectonic.config.ValidatedConfigTemplate; +import com.dfsek.tectonic.exception.ConfigException; +import com.dfsek.terra.api.math.ProbabilityCollection; +import com.dfsek.terra.api.platform.world.Biome; +import com.dfsek.terra.api.platform.world.World; +import com.dfsek.terra.api.world.biome.Generator; +import com.dfsek.terra.api.world.biome.TerraBiome; +import com.dfsek.terra.biome.BiomeProvider; +import com.dfsek.terra.biome.ImageBiomeProvider; +import com.dfsek.terra.config.base.ConfigPack; +import com.dfsek.terra.config.files.FolderLoader; +import com.dfsek.terra.config.templates.AbstractableTemplate; +import com.dfsek.terra.debug.Debug; +import com.dfsek.terra.registry.TerraRegistry; +import org.junit.jupiter.api.Test; + +import javax.imageio.ImageIO; +import javax.swing.*; +import java.awt.*; +import java.awt.event.KeyEvent; +import java.awt.event.KeyListener; +import java.awt.event.MouseEvent; +import java.awt.event.MouseListener; +import java.awt.image.BufferedImage; +import java.awt.image.ColorModel; +import java.awt.image.WritableRaster; +import java.io.File; +import java.io.IOException; +import java.util.HashSet; +import java.util.Set; +import java.util.concurrent.ThreadLocalRandom; +import java.util.logging.Logger; + +public class ImageTest { + private static ImageBiomeProvider getProvider(long seed) throws ConfigException, IOException { + System.out.println(seed); + File pack = new File("/home/dfsek/Documents/Terra/platforms/bukkit/target/server/plugins/Terra/packs/default/"); + FolderLoader folderLoader = new FolderLoader(pack.toPath()); + + AbstractConfigLoader loader = new AbstractConfigLoader(); + + TerraRegistry biomeRegistry = new TerraRegistry() { + }; + folderLoader.open("biomes", ".yml").then(inputStreams -> ConfigPack.buildAll((template, main) -> template, biomeRegistry, loader.load(inputStreams, TestBiome::new), null)); + + return new ImageBiomeProvider(biomeRegistry, ImageIO.read(ImageTest.class.getResourceAsStream("/map.jpg")), 1); + } + + @Test + public static void main(String... args) throws ConfigException, IOException { + Debug.setLogger(Logger.getLogger("Terra")); + Debug.setDebug(true); + JFrame testFrame = new JFrame("Biome Viewer"); + + + final BiomeProvider[] provider = {getProvider(2403)}; + + + int size = 1024; + final BufferedImage[] image = {new BufferedImage(size, size, BufferedImage.TYPE_INT_ARGB)}; + for(int x = 0; x < size; x++) { + for(int z = 0; z < size; z++) { + image[0].setRGB(x, z, provider[0].getBiome(x, z).getColor()); + } + } + + JLabel img = new JLabel(new ImageIcon(image[0])); + + testFrame.add(img); + testFrame.pack(); + img.addMouseListener(new MouseListener() { + @Override + public void mouseClicked(MouseEvent e) { + BufferedImage newImage = deepCopy(image[0]); + Graphics graphics = newImage.getGraphics(); + graphics.setColor(Color.WHITE); + graphics.fillRect(0, 0, 512, 24); + graphics.setColor(Color.BLACK); + graphics.setFont(new Font("Monospace", Font.BOLD, 20)); + graphics.drawString(provider[0].getBiome(e.getX(), e.getY()).toString(), 0, 20); + + graphics.setColor(Color.WHITE); + graphics.fillOval(e.getX() - 2, e.getY() - 2, 12, 12); + graphics.setColor(Color.BLACK); + graphics.fillOval(e.getX(), e.getY(), 8, 8); + + img.setIcon(new ImageIcon(newImage)); + } + + @Override + public void mousePressed(MouseEvent e) { + + } + + @Override + public void mouseReleased(MouseEvent e) { + + } + + @Override + public void mouseEntered(MouseEvent e) { + + } + + @Override + public void mouseExited(MouseEvent e) { + + } + }); + + testFrame.addKeyListener(new KeyListener() { + @Override + public void keyTyped(KeyEvent e) { + if(e.getKeyChar() == 's') { + try { + provider[0] = getProvider(ThreadLocalRandom.current().nextLong()); + } catch(ConfigException | IOException configException) { + configException.printStackTrace(); + } + image[0] = new BufferedImage(size, size, BufferedImage.TYPE_INT_ARGB); + for(int x = 0; x < size; x++) { + for(int z = 0; z < size; z++) { + image[0].setRGB(x, z, provider[0].getBiome(x, z).getColor()); + } + } + img.setIcon(new ImageIcon(image[0])); + } + } + + @Override + public void keyPressed(KeyEvent e) { + + } + + @Override + public void keyReleased(KeyEvent e) { + + } + }); + + testFrame.setResizable(false); + testFrame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE); + testFrame.setVisible(true); + + } + + private static BufferedImage deepCopy(BufferedImage bi) { + ColorModel cm = bi.getColorModel(); + boolean isAlphaPremultiplied = cm.isAlphaPremultiplied(); + WritableRaster raster = bi.copyData(null); + return new BufferedImage(cm, raster, isAlphaPremultiplied, null); + } + + private static final class BiomeProviderTemplate implements ConfigTemplate { + @Value("biome-pipeline") + BiomeProvider.BiomeProviderBuilder biomeProviderBuilder; + + public BiomeProvider.BiomeProviderBuilder getBiomeProviderBuilder() { + return biomeProviderBuilder; + } + } + + private static final class TestBiome extends AbstractableTemplate implements TerraBiome, ValidatedConfigTemplate { + + @Value("color") + @Default + @Abstractable + private int color; + + @Value("tags") + @Abstractable + @Default + private Set tags = new HashSet<>(); + + @Value("id") + private String id; + + @Override + public ProbabilityCollection getVanillaBiomes() { + return null; + } + + @Override + public Generator getGenerator(World w) { + return null; + } + + @Override + public int getColor() { + return color; + } + + @Override + public Set getTags() { + return tags; + } + + @Override + public boolean validate() { + color += (255 << 24); // Alpha adjustment + tags.add("BIOME:" + id); + return true; + } + + @Override + public String getID() { + return id; + } + + @Override + public String toString() { + return id; + } + } +} diff --git a/common/src/test/resources/map.jpg b/common/src/test/resources/map.jpg new file mode 100644 index 000000000..8179d9d70 Binary files /dev/null and b/common/src/test/resources/map.jpg differ diff --git a/platforms/bukkit/src/main/java/com/dfsek/terra/bukkit/command/command/biome/BiomeInfoCommand.java b/platforms/bukkit/src/main/java/com/dfsek/terra/bukkit/command/command/biome/BiomeInfoCommand.java index 7ac34d132..ea5a0aab9 100644 --- a/platforms/bukkit/src/main/java/com/dfsek/terra/bukkit/command/command/biome/BiomeInfoCommand.java +++ b/platforms/bukkit/src/main/java/com/dfsek/terra/bukkit/command/command/biome/BiomeInfoCommand.java @@ -32,15 +32,13 @@ public class BiomeInfoCommand extends WorldCommand { ConfigPack cfg = getMain().getWorld(BukkitAdapter.adapt(world)).getConfig(); UserDefinedBiome b; try { - b = cfg.getBiome(id); + b = (UserDefinedBiome) cfg.getBiome(id); } catch(IllegalArgumentException | NullPointerException e) { LangUtil.send("command.biome.invalid", new BukkitCommandSender(sender), id); return true; } sender.sendMessage("TerraBiome info for \"" + b.getID() + "\"."); sender.sendMessage("Vanilla biome: " + b.getVanillaBiomes()); - sender.sendMessage("Eroded by: " + b.getErode().getConfig().getID()); - BiomeTemplate bio = b.getConfig(); diff --git a/platforms/bukkit/src/main/java/com/dfsek/terra/bukkit/command/command/biome/BiomeLocateCommand.java b/platforms/bukkit/src/main/java/com/dfsek/terra/bukkit/command/command/biome/BiomeLocateCommand.java index 2f1ebf43f..55333edcd 100644 --- a/platforms/bukkit/src/main/java/com/dfsek/terra/bukkit/command/command/biome/BiomeLocateCommand.java +++ b/platforms/bukkit/src/main/java/com/dfsek/terra/bukkit/command/command/biome/BiomeLocateCommand.java @@ -2,8 +2,8 @@ package com.dfsek.terra.bukkit.command.command.biome; import com.dfsek.terra.TerraWorld; import com.dfsek.terra.api.math.vector.Vector3; +import com.dfsek.terra.api.world.biome.TerraBiome; import com.dfsek.terra.async.AsyncBiomeFinder; -import com.dfsek.terra.biome.UserDefinedBiome; import com.dfsek.terra.bukkit.TerraBukkitPlugin; import com.dfsek.terra.bukkit.command.WorldCommand; import com.dfsek.terra.bukkit.world.BukkitAdapter; @@ -41,7 +41,7 @@ public class BiomeLocateCommand extends WorldCommand { LangUtil.send("command.biome.invalid-radius", BukkitAdapter.adapt(sender), args[1]); return true; } - UserDefinedBiome b; + TerraBiome b; try { b = getMain().getWorld(BukkitAdapter.adapt(world)).getConfig().getBiome(id); } catch(IllegalArgumentException | NullPointerException e) { diff --git a/platforms/bukkit/src/main/java/com/dfsek/terra/bukkit/generator/BukkitChunkGeneratorWrapper.java b/platforms/bukkit/src/main/java/com/dfsek/terra/bukkit/generator/BukkitChunkGeneratorWrapper.java index 909466ac4..673ad3ed2 100644 --- a/platforms/bukkit/src/main/java/com/dfsek/terra/bukkit/generator/BukkitChunkGeneratorWrapper.java +++ b/platforms/bukkit/src/main/java/com/dfsek/terra/bukkit/generator/BukkitChunkGeneratorWrapper.java @@ -10,6 +10,7 @@ import com.dfsek.terra.bukkit.world.BukkitAdapter; import com.dfsek.terra.bukkit.world.BukkitBiomeGrid; import com.dfsek.terra.config.lang.LangUtil; import com.dfsek.terra.debug.Debug; +import com.dfsek.terra.population.CavePopulator; import com.dfsek.terra.population.FloraPopulator; import com.dfsek.terra.population.OrePopulator; import com.dfsek.terra.population.StructurePopulator; @@ -89,7 +90,7 @@ public class BukkitChunkGeneratorWrapper extends ChunkGenerator implements Gener @Override public @NotNull List getDefaultPopulators(@NotNull World world) { - return Stream.of(new StructurePopulator(main), popMan).map(BukkitPopulatorWrapper::new).collect(Collectors.toList()); + return Stream.of(new CavePopulator(main), new StructurePopulator(main), popMan).map(BukkitPopulatorWrapper::new).collect(Collectors.toList()); } @Override