/* * Copyright 2014 MovingBlocks * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.terasology.core.world.generator.facetProviders; import java.util.List; import java.util.Map; import org.terasology.core.world.CoreBiome; import org.terasology.core.world.generator.facets.BiomeFacet; import org.terasology.core.world.generator.facets.FloraFacet; import org.terasology.core.world.generator.rasterizers.FloraType; import org.terasology.entitySystem.Component; import org.terasology.math.geom.Vector3i; import org.terasology.rendering.nui.properties.Range; import org.terasology.utilities.procedural.Noise; import org.terasology.utilities.procedural.WhiteNoise; import org.terasology.world.biomes.Biome; import org.terasology.world.generation.ConfigurableFacetProvider; import org.terasology.world.generation.Facet; import org.terasology.world.generation.GeneratingRegion; import org.terasology.world.generation.Produces; import org.terasology.world.generation.Requires; import org.terasology.world.generation.facets.SeaLevelFacet; import org.terasology.world.generation.facets.SurfaceHeightFacet; import com.google.common.base.Predicate; import com.google.common.collect.ImmutableMap; import com.google.common.collect.Lists; /** * Determines where plants can be placed. Will put plants one block above the surface if it is in the correct biome. */ @Produces(FloraFacet.class) @Requires({ @Facet(SeaLevelFacet.class), @Facet(SurfaceHeightFacet.class), @Facet(BiomeFacet.class) // @Facet(value = DensityFacet.class, border = @FacetBorder(bottom = 1)) }) public class DefaultFloraProvider extends SurfaceObjectProvider<Biome, FloraType> implements ConfigurableFacetProvider { private Noise densityNoiseGen; private Configuration configuration = new Configuration(); private Map<FloraType, Float> typeProbs = ImmutableMap.of( FloraType.GRASS, 0.85f, FloraType.FLOWER, 0.1f, FloraType.MUSHROOM, 0.05f); private Map<CoreBiome, Float> biomeProbs = ImmutableMap.<CoreBiome, Float>builder() .put(CoreBiome.FOREST, 0.3f) .put(CoreBiome.PLAINS, 0.2f) .put(CoreBiome.MOUNTAINS, 0.2f) .put(CoreBiome.SNOW, 0.001f) .put(CoreBiome.BEACH, 0.001f) .put(CoreBiome.OCEAN, 0f) .put(CoreBiome.DESERT, 0.001f).build(); public DefaultFloraProvider() { for (CoreBiome biome : CoreBiome.values()) { float biomeProb = biomeProbs.get(biome); for (FloraType type : typeProbs.keySet()) { float typeProb = typeProbs.get(type); float prob = biomeProb * typeProb; register(biome, type, prob); } } register(CoreBiome.BEACH, FloraType.MUSHROOM, 0); register(CoreBiome.BEACH, FloraType.FLOWER, 0); register(CoreBiome.DESERT, FloraType.MUSHROOM, 0); register(CoreBiome.SNOW, FloraType.MUSHROOM, 0); } /** * @param configuration the default configuration to use */ public DefaultFloraProvider(Configuration configuration) { this(); this.configuration = configuration; } @Override public void setSeed(long seed) { super.setSeed(seed); densityNoiseGen = new WhiteNoise(seed); } @Override public void process(GeneratingRegion region) { SurfaceHeightFacet surface = region.getRegionFacet(SurfaceHeightFacet.class); BiomeFacet biomeFacet = region.getRegionFacet(BiomeFacet.class); FloraFacet facet = new FloraFacet(region.getRegion(), region.getBorderForFacet(FloraFacet.class)); List<Predicate<Vector3i>> filters = getFilters(region); populateFacet(facet, surface, biomeFacet, filters); region.setRegionFacet(FloraFacet.class, facet); } protected List<Predicate<Vector3i>> getFilters(GeneratingRegion region) { List<Predicate<Vector3i>> filters = Lists.newArrayList(); SeaLevelFacet seaLevel = region.getRegionFacet(SeaLevelFacet.class); filters.add(PositionFilters.minHeight(seaLevel.getSeaLevel())); filters.add(PositionFilters.probability(densityNoiseGen, configuration.density)); return filters; } @Override public String getConfigurationName() { return "Flora"; } @Override public Component getConfiguration() { return configuration; } @Override public void setConfiguration(Component configuration) { this.configuration = (Configuration) configuration; } public static class Configuration implements Component { @Range(min = 0, max = 1.0f, increment = 0.05f, precision = 2, description = "Define the overall flora density") public float density = 0.4f; } }