- rewrite BiomeMap

- tweaks to features jsons
- forest surface builder
- fix unsorted material lists for the strata layer generator
This commit is contained in:
dags- 2020-06-07 22:20:04 +01:00
parent adfcc8b382
commit 3043540791
42 changed files with 1040 additions and 871 deletions

2
Engine

@ -1 +1 @@
Subproject commit 97f83a296a351af688a5f35494b943c0b2b141ae
Subproject commit 433db368f37a8f0a538d017610ce5cb11487d7fe

View File

@ -39,13 +39,6 @@ public class SurfaceManager {
private final ReadWriteLock lock = new ReentrantReadWriteLock();
private final Map<ResourceLocation, Surface> surfaces = new HashMap<>();
public SurfaceManager replace(Biome biome, Surface surface) {
lock.writeLock().lock();
surfaces.put(biome.getRegistryName(), surface);
lock.writeLock().unlock();
return this;
}
public Surface getSurface(Biome biome) {
lock.readLock().lock();
Surface surface = surfaces.get(biome.getRegistryName());
@ -62,11 +55,44 @@ public class SurfaceManager {
return surface;
}
public SurfaceManager extend(Biome biome, Surface surface) {
public SurfaceManager replace(Biome biome, Surface surface) {
lock.writeLock().lock();
surfaces.put(biome.getRegistryName(), surface);
lock.writeLock().unlock();
return this;
}
public SurfaceManager replace(Surface surface, Biome... biomes) {
for (Biome biome : biomes) {
replace(biome, surface);
}
return this;
}
public SurfaceManager prepend(Biome biome, Surface surface) {
Surface result = surface.then(getOrCreateSurface(biome));
return replace(biome, result);
}
public SurfaceManager prepend(Surface surface, Biome... biomes) {
for (Biome biome : biomes) {
prepend(biome, surface);
}
return this;
}
public SurfaceManager append(Biome biome, Surface surface) {
Surface result = getOrCreateSurface(biome).then(surface);
return replace(biome, result);
}
public SurfaceManager append(Surface surface, Biome... biomes) {
for (Biome biome : biomes) {
append(biome, surface);
}
return this;
}
public Surface getSurface(SurfaceContext context) {
if (context.biome == context.cached.biome) {
return context.cached.surface;

View File

@ -1,53 +0,0 @@
package com.terraforged.biome;
import com.terraforged.api.biome.BiomeVariant;
import net.minecraft.entity.EntityClassification;
import net.minecraft.entity.EntityType;
import net.minecraft.world.biome.Biome;
import net.minecraft.world.biome.Biomes;
import net.minecraft.world.biome.DefaultBiomeFeatures;
import net.minecraft.world.gen.feature.Feature;
import net.minecraft.world.gen.feature.IFeatureConfig;
import net.minecraft.world.gen.feature.structure.MineshaftConfig;
import net.minecraft.world.gen.feature.structure.MineshaftStructure;
import net.minecraft.world.gen.feature.structure.VillageConfig;
import net.minecraft.world.gen.surfacebuilders.SurfaceBuilder;
public class Dunes extends BiomeVariant {
protected Dunes() {
super((new Biome.Builder()).surfaceBuilder(SurfaceBuilder.DEFAULT, SurfaceBuilder.SAND_SAND_GRAVEL_CONFIG).precipitation(Biome.RainType.NONE).category(Biome.Category.DESERT).depth(0.125F).scale(0.05F).temperature(2.0F).downfall(0.0F).waterColor(4159204).waterFogColor(329011).parent((String)null));
this.addStructure(Feature.VILLAGE.withConfiguration(new VillageConfig("village/desert/town_centers", 6)));
this.addStructure(Feature.PILLAGER_OUTPOST.withConfiguration(IFeatureConfig.NO_FEATURE_CONFIG));
this.addStructure(Feature.DESERT_PYRAMID.withConfiguration(IFeatureConfig.NO_FEATURE_CONFIG));
this.addStructure(Feature.MINESHAFT.withConfiguration(new MineshaftConfig(0.004D, MineshaftStructure.Type.NORMAL)));
this.addStructure(Feature.STRONGHOLD.withConfiguration(IFeatureConfig.NO_FEATURE_CONFIG));
DefaultBiomeFeatures.addCarvers(this);
DefaultBiomeFeatures.addStructures(this);
DefaultBiomeFeatures.addMonsterRooms(this);
DefaultBiomeFeatures.addStoneVariants(this);
DefaultBiomeFeatures.addOres(this);
DefaultBiomeFeatures.addDefaultFlowers(this);
DefaultBiomeFeatures.addSparseGrass(this);
DefaultBiomeFeatures.addDeadBushes(this);
DefaultBiomeFeatures.addMushrooms(this);
DefaultBiomeFeatures.addFreezeTopLayer(this);
this.addSpawn(EntityClassification.CREATURE, new Biome.SpawnListEntry(EntityType.RABBIT, 4, 2, 3));
this.addSpawn(EntityClassification.AMBIENT, new Biome.SpawnListEntry(EntityType.BAT, 10, 8, 8));
this.addSpawn(EntityClassification.MONSTER, new Biome.SpawnListEntry(EntityType.SPIDER, 100, 4, 4));
this.addSpawn(EntityClassification.MONSTER, new Biome.SpawnListEntry(EntityType.SKELETON, 100, 4, 4));
this.addSpawn(EntityClassification.MONSTER, new Biome.SpawnListEntry(EntityType.CREEPER, 100, 4, 4));
this.addSpawn(EntityClassification.MONSTER, new Biome.SpawnListEntry(EntityType.SLIME, 100, 4, 4));
this.addSpawn(EntityClassification.MONSTER, new Biome.SpawnListEntry(EntityType.ENDERMAN, 10, 1, 4));
this.addSpawn(EntityClassification.MONSTER, new Biome.SpawnListEntry(EntityType.WITCH, 5, 1, 1));
this.addSpawn(EntityClassification.MONSTER, new Biome.SpawnListEntry(EntityType.ZOMBIE, 19, 4, 4));
this.addSpawn(EntityClassification.MONSTER, new Biome.SpawnListEntry(EntityType.ZOMBIE_VILLAGER, 1, 1, 1));
this.addSpawn(EntityClassification.MONSTER, new Biome.SpawnListEntry(EntityType.HUSK, 80, 4, 4));
setRegistryName("terraforged", "dunes");
}
@Override
public Biome getBase() {
return Biomes.DESERT;
}
}

View File

@ -41,7 +41,6 @@ public class ModBiomes {
public static final Biome BRICE = register(new Brice());
public static final Biome COLD_STEPPE = register(new ColdSteppe());
public static final Biome DUNES = register(new Dunes());
public static final Biome FIR_FOREST = register(new FirForest());
public static final Biome FLOWER_PLAINS = register(new FlowerPlains());
public static final Biome FROZEN_LAKE = register(new FrozenLake());

View File

@ -1,235 +0,0 @@
/*
*
* MIT License
*
* Copyright (c) 2020 TerraForged
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package com.terraforged.biome.map;
import com.google.common.collect.Sets;
import com.google.gson.JsonArray;
import com.google.gson.JsonObject;
import com.terraforged.biome.ModBiomes;
import com.terraforged.biome.provider.BiomeHelper;
import com.terraforged.world.biome.BiomeType;
import me.dags.noise.util.NoiseUtil;
import net.minecraft.world.biome.Biome;
import net.minecraft.world.biome.Biomes;
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
public abstract class AbstractBiomeMap implements BiomeMap {
private final Biome[][] beach;
private final Biome[][] river;
private final Biome[][] lake;
private final Biome[][] wetland;
private final Biome[][] ocean;
private final Biome[][] deepOcean;
protected final DefaultBiome defaultLand = this::defaultBiome;
protected final DefaultBiome defaultBeach = this::defaultBeach;
protected final DefaultBiome defaultRiver = this::defaultRiver;
protected final DefaultBiome defaultLake = this::defaultLake;
protected final DefaultBiome defaultWetland = this::defaultWetland;
protected final DefaultBiome defaultOcean = this::defaultOcean;
protected final DefaultBiome defaultDeepOcean = this::defaultDeepOcean;
protected AbstractBiomeMap(BiomeMapBuilder builder) {
river = builder.rivers();
lake = builder.lakes();
beach = builder.beaches();
ocean = builder.oceans();
wetland = builder.wetlands();
deepOcean = builder.deepOceans();
}
@Override
public Biome getBeach(float temperature, float moisture, float shape) {
return get(beach, getCategory(temperature), shape, temperature, defaultBeach);
}
@Override
public Biome getRiver(float temperature, float moisture, float shape) {
return get(river, getCategory(temperature), shape, temperature, defaultRiver);
}
@Override
public Biome getLake(float temperature, float moisture, float shape) {
return get(lake, getCategory(temperature), shape, temperature, defaultLake);
}
@Override
public Biome getWetland(float temperature, float moisture, float shape) {
return get(wetland, getCategory(temperature), shape, temperature, defaultWetland);
}
@Override
public Biome getOcean(float temperature, float moisture, float shape) {
return get(ocean, getCategory(temperature), shape, temperature, defaultOcean);
}
@Override
public Biome getDeepOcean(float temperature, float moisture, float shape) {
return get(deepOcean, getCategory(temperature), shape, temperature, defaultDeepOcean);
}
@Override
public Set<Biome> getOceanBiomes(Biome.TempCategory temp) {
return Sets.newHashSet(ocean[temp.ordinal() - 1]);
}
@Override
public Set<Biome> getDeepOceanBiomes(Biome.TempCategory temp) {
return Sets.newHashSet(deepOcean[temp.ordinal() - 1]);
}
@Override
public Set<Biome> getRivers(Biome.TempCategory temp) {
return Sets.newHashSet(river[temp.ordinal() - 1]);
}
@Override
public JsonObject toJson() {
JsonObject root = new JsonObject();
root.add("rivers", collect(river));
root.add("wetland", collect(wetland));
root.add("beaches", collect(beach));
root.add("oceans", collect(ocean));
root.add("deepOceans", collect(deepOcean));
return root;
}
private JsonObject collect(Biome[][] biomes) {
JsonObject root = new JsonObject();
for (Biome.TempCategory temp : Biome.TempCategory.values()) {
if (temp == Biome.TempCategory.OCEAN) {
continue;
}
JsonArray array = new JsonArray();
Biome[] group = biomes[temp.ordinal() - 1];
if (group != null) {
Set<Biome> set = new HashSet<>();
Collections.addAll(set, group);
set.stream().map(BiomeHelper::getId).sorted().forEach(array::add);
}
root.add(temp.name(), array);
}
return root;
}
protected Biome.TempCategory getCategory(float value) {
if (value < 0.25) {
return Biome.TempCategory.COLD;
}
if (value > 0.75) {
return Biome.TempCategory.WARM;
}
return Biome.TempCategory.MEDIUM;
}
protected Biome defaultBeach(float temperature) {
if (temperature < 0.25) {
return Biomes.SNOWY_BEACH;
}
if (temperature > 0.75) {
return ModBiomes.WARM_BEACH;
}
return Biomes.BEACH;
}
protected Biome defaultRiver(float temperature) {
if (temperature < 0.15) {
return Biomes.FROZEN_RIVER;
}
return Biomes.RIVER;
}
protected Biome defaultLake(float temperature) {
if (temperature < 0.15) {
return ModBiomes.FROZEN_LAKE;
}
return ModBiomes.LAKE;
}
protected Biome defaultWetland(float temperature) {
if (temperature < 0.15) {
return ModBiomes.TAIGA_SCRUB;
}
return ModBiomes.MARSHLAND;
}
protected Biome defaultOcean(float temperature) {
if (temperature < 0.3) {
return Biomes.FROZEN_OCEAN;
}
if (temperature > 0.7) {
return Biomes.WARM_OCEAN;
}
return Biomes.OCEAN;
}
protected Biome defaultDeepOcean(float temperature) {
if (temperature < 0.3) {
return Biomes.DEEP_FROZEN_OCEAN;
}
if (temperature > 0.7) {
return Biomes.DEEP_WARM_OCEAN;
}
return Biomes.DEEP_OCEAN;
}
protected Biome defaultBiome(float temperature) {
if (temperature < 0.3) {
return ModBiomes.TAIGA_SCRUB;
}
if (temperature > 0.7) {
return ModBiomes.SAVANNA_SCRUB;
}
return Biomes.PLAINS;
}
protected Biome get(Biome[][] group, Biome.TempCategory category, float shape, float temp, DefaultBiome def) {
return get(group, category.ordinal() - 1, shape, temp, def);
}
protected Biome get(Biome[][] group, BiomeType type, float shape, float temp, DefaultBiome def) {
return get(group, type.ordinal(), shape, temp, def);
}
protected Biome get(Biome[][] group, int ordinal, float shape, float temp, DefaultBiome def) {
if (ordinal >= group.length) {
return def.getDefaultBiome(temp);
}
Biome[] biomes = group[ordinal];
if (biomes == null || biomes.length == 0) {
return def.getDefaultBiome(temp);
}
int index = NoiseUtil.round((biomes.length - 1) * shape);
return biomes[index];
}
}

View File

@ -1,82 +0,0 @@
/*
*
* MIT License
*
* Copyright (c) 2020 TerraForged
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package com.terraforged.biome.map;
import com.google.common.collect.Sets;
import com.google.gson.JsonArray;
import com.google.gson.JsonObject;
import com.terraforged.biome.provider.BiomeHelper;
import com.terraforged.world.biome.BiomeType;
import net.minecraft.world.biome.Biome;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Set;
public class BasicBiomeMap extends AbstractBiomeMap {
private final Biome[][] biomeTypes;
public BasicBiomeMap(BiomeMapBuilder builder) {
super(builder);
biomeTypes = builder.biomeList();
}
@Override
public List<Biome> getAllBiomes(BiomeType type) {
if (type.ordinal() >= biomeTypes.length) {
return Collections.emptyList();
}
return Arrays.asList(biomeTypes[type.ordinal()]);
}
@Override
public Set<Biome> getBiomes(BiomeType type) {
if (type.ordinal() >= biomeTypes.length) {
return Collections.emptySet();
}
return Sets.newHashSet(biomeTypes[type.ordinal()]);
}
@Override
public Biome getBiome(BiomeType type, float temperature, float moisture, float shape) {
return get(biomeTypes, type, shape, temperature, defaultLand);
}
@Override
public JsonObject toJson() {
JsonObject groups = new JsonObject();
for (BiomeType type : BiomeType.values()) {
JsonArray group = new JsonArray();
getBiomes(type).stream().map(BiomeHelper::getId).sorted().forEach(group::add);
groups.add(type.name(), group);
}
JsonObject root = super.toJson();
root.add("biomes", groups);
return root;
}
}

View File

@ -28,60 +28,50 @@ package com.terraforged.biome.map;
import com.google.gson.JsonElement;
import com.terraforged.core.cell.Cell;
import com.terraforged.world.biome.BiomeType;
import com.terraforged.world.heightmap.Levels;
import net.minecraft.world.biome.Biome;
import java.util.List;
import java.util.Set;
public interface BiomeMap {
Biome getBeach(float temperature, float moisture, float shape);
Biome getBeach(Cell cell);
Biome getRiver(float temperature, float moisture, float shape);
Biome getCoast(Cell cell, Biome current);
Biome getLake(float temperature, float moisture, float shape);
Biome getRiver(Cell cell);
Biome getWetland(float temperature, float moisture, float shape);
Biome getLake(Cell cell);
Biome getOcean(float temperature, float moisture, float shape);
Biome getWetland(Cell cell);
Biome getDeepOcean(float temperature, float moisture, float shape);
Biome getShallowOcean(Cell cell);
Biome getBiome(BiomeType type, float temperature, float moisture, float shape);
Biome getDeepOcean(Cell cell);
default Biome getBiome(Cell cell) {
return getBiome(cell.biomeType, cell.temperature, cell.moisture, cell.biome);
}
Biome getLand(Cell cell);
Biome provideBiome(Cell cell, Levels levels);
List<Biome> getAllBiomes(BiomeType type);
Set<Biome> getBiomes(BiomeType type);
Set<Biome> getRivers(Biome.TempCategory temp);
Set<Biome> getOceanBiomes(Biome.TempCategory temp);
Set<Biome> getDeepOceanBiomes(Biome.TempCategory temp);
JsonElement toJson();
static Biome getBiome(Biome biome) {
return biome.delegate.get();
}
interface Builder {
Builder addOcean(Biome biome, int count);
Builder addBeach(Biome biome, int count);
Builder addCoast(Biome biome, int count);
Builder addRiver(Biome biome, int count);
Builder addLake(Biome biome, int count);
Builder addWetland(Biome biome, int count);
Builder addOcean(Biome biome, int count);
Builder addBiome(BiomeType type, Biome biome, int count);
Builder addLand(BiomeType type, Biome biome, int count);
BiomeMap build();
}

View File

@ -26,15 +26,10 @@
package com.terraforged.biome.map;
import com.terraforged.biome.provider.BiomeHelper;
import com.terraforged.core.util.grid.FixedGrid;
import com.terraforged.util.ListUtils;
import com.terraforged.world.biome.BiomeData;
import com.terraforged.world.biome.BiomeType;
import net.minecraft.world.biome.Biome;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.EnumMap;
import java.util.HashMap;
import java.util.List;
@ -43,25 +38,19 @@ import java.util.function.Function;
public class BiomeMapBuilder implements BiomeMap.Builder {
private final Map<Biome.TempCategory, List<Biome>> rivers = new HashMap<>();
private final Map<Biome.TempCategory, List<Biome>> lakes = new HashMap<>();
private final Map<Biome.TempCategory, List<Biome>> wetlands = new HashMap<>();
private final Map<Biome.TempCategory, List<Biome>> beaches = new HashMap<>();
private final Map<Biome.TempCategory, List<Biome>> oceans = new HashMap<>();
private final Map<Biome.TempCategory, List<Biome>> deepOceans = new HashMap<>();
private final Map<BiomeType, List<Biome>> map = new EnumMap<>(BiomeType.class);
private final Map<Biome, BiomeData> dataMap = new HashMap<>();
protected final Map<Biome.TempCategory, List<Biome>> rivers = new HashMap<>();
protected final Map<Biome.TempCategory, List<Biome>> lakes = new HashMap<>();
protected final Map<Biome.TempCategory, List<Biome>> wetlands = new HashMap<>();
protected final Map<Biome.TempCategory, List<Biome>> coasts = new HashMap<>();
protected final Map<Biome.TempCategory, List<Biome>> beaches = new HashMap<>();
protected final Map<Biome.TempCategory, List<Biome>> oceans = new HashMap<>();
protected final Map<Biome.TempCategory, List<Biome>> deepOceans = new HashMap<>();
protected final Map<BiomeType, List<Biome>> map = new EnumMap<>(BiomeType.class);
private final int gridSize;
private final Function<BiomeMapBuilder, BiomeMap> constructor;
BiomeMapBuilder(Function<BiomeMapBuilder, BiomeMap> constructor, int gridSize, List<BiomeData> biomes) {
BiomeMapBuilder(Function<BiomeMapBuilder, BiomeMap> constructor) {
this.constructor = constructor;
this.gridSize = gridSize;
for (BiomeData data : biomes) {
dataMap.put((Biome) data.reference, data);
}
}
@Override
@ -82,6 +71,13 @@ public class BiomeMapBuilder implements BiomeMap.Builder {
return this;
}
@Override
public BiomeMap.Builder addCoast(Biome biome, int count) {
Biome.TempCategory category = BiomeHelper.getTempCategory(biome);
add(coasts.computeIfAbsent(category, c -> new ArrayList<>()), biome, count);
return this;
}
@Override
public BiomeMapBuilder addRiver(Biome biome, int count) {
Biome.TempCategory category = BiomeHelper.getTempCategory(biome);
@ -104,7 +100,7 @@ public class BiomeMapBuilder implements BiomeMap.Builder {
}
@Override
public BiomeMapBuilder addBiome(BiomeType type, Biome biome, int count) {
public BiomeMapBuilder addLand(BiomeType type, Biome biome, int count) {
add(map.computeIfAbsent(type, t -> new ArrayList<>()), biome, count);
return this;
}
@ -114,87 +110,13 @@ public class BiomeMapBuilder implements BiomeMap.Builder {
return constructor.apply(this);
}
Biome[][] rivers() {
return collectTemps(rivers);
}
Biome[][] lakes() {
return collectTemps(lakes);
}
Biome[][] wetlands() {
return collectTemps(wetlands);
}
Biome[][] beaches() {
return collectTemps(beaches);
}
Biome[][] oceans() {
return collectTemps(oceans);
}
Biome[][] deepOceans() {
return collectTemps(deepOceans);
}
Biome[][] biomeList() {
return collectTypes(map);
}
BiomeGroup[] biomeGroups() {
BiomeGroup[] biomes = new BiomeGroup[BiomeType.values().length];
Function<Biome, Float> moisture = b -> dataMap.get(b).rainfall;
Function<Biome, Float> temperature = b -> dataMap.get(b).temperature;
for (BiomeType type : BiomeType.values()) {
List<Biome> list = map.getOrDefault(type, Collections.emptyList());
if (list.isEmpty()) {
continue;
}
FixedGrid<Biome> grid = FixedGrid.generate(gridSize, list, moisture, temperature);
biomes[type.ordinal()] = new BiomeGroup(grid);
}
return biomes;
}
private void add(List<Biome> list, Biome biome, int count) {
for (int i = 0; i < count; i++) {
list.add(biome);
}
}
private Biome[][] collectTemps(Map<Biome.TempCategory, List<Biome>> map) {
Biome[][] biomes = new Biome[3][];
for (Biome.TempCategory category : Biome.TempCategory.values()) {
if (category == Biome.TempCategory.OCEAN) {
continue;
}
List<Biome> list = map.getOrDefault(category, Collections.emptyList());
list = ListUtils.minimize(list);
list.sort(Comparator.comparing(BiomeHelper::getId));
biomes[category.ordinal() - 1] = list.toArray(new Biome[0]);
}
return biomes;
}
private Biome[][] collectTypes(Map<BiomeType, List<Biome>> map) {
Biome[][] biomes = new Biome[BiomeType.values().length][];
for (BiomeType type : BiomeType.values()) {
List<Biome> list = map.getOrDefault(type, Collections.emptyList());
list = ListUtils.minimize(list);
list.sort(Comparator.comparing(BiomeHelper::getId));
biomes[type.ordinal()] = list.toArray(new Biome[0]);
}
return biomes;
}
public static BiomeMap.Builder basic(List<BiomeData> biomes) {
return new BiomeMapBuilder(BasicBiomeMap::new, 0, biomes);
}
public static BiomeMap.Builder grid(int size, List<BiomeData> biomes) {
return new BiomeMapBuilder(GridBiomeMap::new, size, biomes);
public static BiomeMap.Builder create() {
return new BiomeMapBuilder(SimpleBiomeMap::new);
}
}

View File

@ -84,7 +84,8 @@ public interface BiomePredicate {
return false;
}
BiomePredicate COAST = type(Biome.Category.BEACH, Biome.Category.MUSHROOM).or(name("shore")).or(name("beach"));
BiomePredicate BEACH = type(Biome.Category.BEACH).or(name("beach"));
BiomePredicate COAST = type(Biome.Category.MUSHROOM).or(name("coast"));
BiomePredicate COLD_STEPPE = name("steppe").and(temp(-1, 0.3));
BiomePredicate DESERT = type(Biome.Category.DESERT).or(temp(0.9, 2).and(rain(-1, 0.2)));
BiomePredicate GRASSLAND = type(Biome.Category.PLAINS);

View File

@ -1,127 +0,0 @@
/*
*
* MIT License
*
* Copyright (c) 2020 TerraForged
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package com.terraforged.biome.map;
import com.google.gson.JsonArray;
import com.google.gson.JsonObject;
import com.terraforged.core.util.grid.FixedList;
import com.terraforged.core.util.grid.MappedList;
import com.terraforged.world.biome.BiomeType;
import net.minecraft.world.biome.Biome;
import net.minecraft.world.biome.Biomes;
import java.util.Collections;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;
public class GridBiomeMap extends AbstractBiomeMap {
private final BiomeGroup[] biomeTypes;
GridBiomeMap(BiomeMapBuilder builder) {
super(builder);
biomeTypes = builder.biomeGroups();
}
@Override
public Biome getBiome(BiomeType type, float temperature, float moisture, float shape) {
BiomeGroup group = biomeTypes[type.ordinal()];
if (group == null) {
return Biomes.NETHER;
}
return group.biomes.get(moisture, temperature, shape);
}
@Override
public List<Biome> getAllBiomes(BiomeType type) {
BiomeGroup group = biomeTypes[type.ordinal()];
if (group == null) {
return Collections.emptyList();
}
List<Biome> biomes = new LinkedList<>();
for (MappedList<FixedList<Biome>> row : group.biomes) {
for (FixedList<Biome> cell : row) {
for (Biome biome : cell) {
biomes.add(biome);
}
}
}
return biomes;
}
@Override
public Set<Biome> getBiomes(BiomeType type) {
BiomeGroup group = biomeTypes[type.ordinal()];
if (group == null) {
return Collections.emptySet();
}
Set<Biome> biomes = new HashSet<>();
for (MappedList<FixedList<Biome>> row : group.biomes) {
for (FixedList<Biome> cell : row) {
for (Biome biome : cell) {
biomes.add(biome);
}
}
}
return biomes;
}
@Override
public JsonObject toJson() {
JsonObject root = new JsonObject();
for (BiomeType type : BiomeType.values()) {
BiomeGroup group = biomeTypes[type.ordinal()];
JsonObject grid = new JsonObject();
if (group != null) {
int rowCount = 0;
float maxRow = group.biomes.size() - 1;
for (MappedList<FixedList<Biome>> row : group.biomes) {
int colCount = 0;
float maxCol = row.size() - 1;
JsonObject rowJson = new JsonObject();
for (FixedList<Biome> cell : row) {
JsonArray colJson = new JsonArray();
for (Biome biome : cell.uniqueValues()) {
colJson.add(biome.getRegistryName() + "");
}
float colId = colCount / maxCol;
rowJson.add("" + colId, colJson);
colCount++;
}
float rowId = rowCount / maxRow;
grid.add("" + rowId, rowJson);
rowCount++;
}
}
root.add(type.name(), grid);
}
return root;
}
}

View File

@ -0,0 +1,132 @@
package com.terraforged.biome.map;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.terraforged.biome.map.defaults.DefaultBiomes;
import com.terraforged.biome.map.set.BiomeSet;
import com.terraforged.biome.map.set.BiomeTypeSet;
import com.terraforged.biome.map.set.RiverSet;
import com.terraforged.biome.map.set.TemperatureSet;
import com.terraforged.core.cell.Cell;
import com.terraforged.world.biome.BiomeType;
import com.terraforged.world.heightmap.Levels;
import com.terraforged.world.terrain.TerrainType;
import me.dags.noise.util.NoiseUtil;
import net.minecraft.world.biome.Biome;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
public class SimpleBiomeMap implements BiomeMap {
private final BiomeSet deepOcean;
private final BiomeSet shallowOcean;
private final BiomeSet beach;
private final BiomeSet coast;
private final BiomeSet river;
private final BiomeSet lake;
private final BiomeSet wetland;
private final BiomeSet land;
private final BiomeSet[] terrainBiomes;
public SimpleBiomeMap(BiomeMapBuilder builder) {
deepOcean = new TemperatureSet(builder.deepOceans, DefaultBiomes::defaultDeepOcean);
shallowOcean = new TemperatureSet(builder.oceans, DefaultBiomes::defaultOcean);
beach = new TemperatureSet(builder.beaches, DefaultBiomes::defaultBeach);
coast = new TemperatureSet(builder.coasts, DefaultBiomes::defaultBiome);
river = new RiverSet(builder.rivers, DefaultBiomes::defaultRiver, this);
lake = new TemperatureSet(builder.lakes, DefaultBiomes::defaultLake);
wetland = new TemperatureSet(builder.wetlands, DefaultBiomes::defaultWetland);
land = new BiomeTypeSet(builder.map, DefaultBiomes::defaultBiome);
terrainBiomes = new BiomeSet[TerrainType.values().length];
terrainBiomes[TerrainType.SHALLOW_OCEAN.ordinal()] = shallowOcean;
terrainBiomes[TerrainType.DEEP_OCEAN.ordinal()] = deepOcean;
terrainBiomes[TerrainType.WETLAND.ordinal()] = wetland;
terrainBiomes[TerrainType.RIVER.ordinal()] = river;
terrainBiomes[TerrainType.LAKE.ordinal()] = lake;
for (TerrainType type : TerrainType.values()) {
if (terrainBiomes[type.ordinal()] == null) {
terrainBiomes[type.ordinal()] = land;
}
}
}
public Biome provideBiome(Cell cell, Levels levels) {
TerrainType type = cell.terrain.getType();
if (type.isSubmerged() && cell.value > levels.water) {
return land.getBiome(cell);
}
return terrainBiomes[cell.terrain.getType().ordinal()].getBiome(cell);
}
@Override
public Biome getDeepOcean(Cell cell) {
return deepOcean.getBiome(cell);
}
@Override
public Biome getShallowOcean(Cell cell) {
return shallowOcean.getBiome(cell);
}
@Override
public Biome getBeach(Cell cell) {
return beach.getBiome(cell);
}
@Override
public Biome getCoast(Cell cell, Biome current) {
int inland = land.getSize(cell);
Biome[] coastal = coast.getSet(cell);
int total = inland + coastal.length;
int index = NoiseUtil.round((total - 1) * cell.biome);
if (index >= inland) {
return coastal[index - inland];
}
return current;
}
@Override
public Biome getRiver(Cell cell) {
return river.getBiome(cell);
}
@Override
public Biome getLake(Cell cell) {
return lake.getBiome(cell);
}
@Override
public Biome getWetland(Cell cell) {
return wetland.getBiome(cell);
}
@Override
public Biome getLand(Cell cell) {
return land.getBiome(cell);
}
@Override
public List<Biome> getAllBiomes(BiomeType type) {
int size = land.getSize(type.ordinal());
if (size == 0) {
return Collections.emptyList();
}
return Arrays.asList(land.getSet(type.ordinal()));
}
@Override
public JsonElement toJson() {
JsonObject root = new JsonObject();
root.add("DEEP_OCEAN", deepOcean.toJson());
root.add("SHALLOW_OCEAN", shallowOcean.toJson());
root.add("BEACH", beach.toJson());
root.add("COAST", coast.toJson());
root.add("RIVER", river.toJson());
root.add("LAKE", lake.toJson());
root.add("WETLAND", wetland.toJson());
root.add("LAND", land.toJson());
return root;
}
}

View File

@ -1,4 +1,4 @@
package com.terraforged.biome.map;
package com.terraforged.biome.map.defaults;
import net.minecraft.world.biome.Biome;

View File

@ -0,0 +1,73 @@
package com.terraforged.biome.map.defaults;
import com.terraforged.biome.ModBiomes;
import net.minecraft.world.biome.Biome;
import net.minecraft.world.biome.Biomes;
public class DefaultBiomes {
public static Biome defaultBeach(float temperature) {
if (temperature < 0.25) {
return Biomes.SNOWY_BEACH;
}
if (temperature > 0.75) {
return ModBiomes.WARM_BEACH;
}
return Biomes.BEACH;
}
public static Biome defaultRiver(float temperature) {
if (temperature < 0.15) {
return Biomes.FROZEN_RIVER;
}
return Biomes.RIVER;
}
public static Biome defaultLake(float temperature) {
if (temperature < 0.15) {
return ModBiomes.FROZEN_LAKE;
}
return ModBiomes.LAKE;
}
public static Biome defaultWetland(float temperature) {
if (temperature < 0.15) {
return ModBiomes.TAIGA_SCRUB;
}
return ModBiomes.MARSHLAND;
}
public static Biome defaultOcean(float temperature) {
if (temperature < 0.3) {
return Biomes.FROZEN_OCEAN;
}
if (temperature > 0.7) {
return Biomes.WARM_OCEAN;
}
return Biomes.OCEAN;
}
public static Biome defaultDeepOcean(float temperature) {
if (temperature < 0.3) {
return Biomes.DEEP_FROZEN_OCEAN;
}
if (temperature > 0.7) {
return Biomes.DEEP_WARM_OCEAN;
}
return Biomes.DEEP_OCEAN;
}
public static Biome defaultBiome(float temperature) {
if (temperature < 0.3) {
return ModBiomes.TAIGA_SCRUB;
}
if (temperature > 0.7) {
return ModBiomes.SAVANNA_SCRUB;
}
return Biomes.PLAINS;
}
public static boolean overridesRiver(Biome biome) {
return biome.getCategory() == Biome.Category.SWAMP || biome.getCategory() == Biome.Category.JUNGLE;
}
}

View File

@ -0,0 +1,76 @@
package com.terraforged.biome.map.set;
import com.google.gson.JsonElement;
import com.terraforged.biome.map.defaults.DefaultBiome;
import com.terraforged.biome.provider.BiomeHelper;
import com.terraforged.core.cell.Cell;
import com.terraforged.util.ListUtils;
import me.dags.noise.util.NoiseUtil;
import net.minecraft.world.biome.Biome;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
public abstract class BiomeSet {
private static final Biome[] EMPTY = new Biome[0];
private final Biome[][] biomes;
private final DefaultBiome defaultBiome;
public BiomeSet(Biome[][] biomes, DefaultBiome defaultBiome) {
this.biomes = biomes;
this.defaultBiome = defaultBiome;
}
public int getSize(int index) {
return biomes[index].length;
}
public int getSize(Cell cell) {
return biomes[getIndex(cell)].length;
}
public Biome[] getSet(int index) {
return biomes[index];
}
public Biome[] getSet(Cell cell) {
return biomes[getIndex(cell)];
}
public Biome getBiome(Cell cell) {
Biome[] set = biomes[getIndex(cell)];
if (set.length == 0) {
return defaultBiome.getDefaultBiome(cell.temperature);
}
return set[NoiseUtil.round((set.length - 1) * cell.biome)];
}
public abstract int getIndex(Cell cell);
public abstract JsonElement toJson();
protected static Biome[][] collect(Map<? extends Enum<?>, List<Biome>> map, int size, Function<Enum<?>, Integer> indexer) {
Biome[][] biomes = new Biome[size][];
for (Enum<?> type : map.keySet()) {
int index = indexer.apply(type);
if (index < 0 || index >= size) {
continue;
}
List<Biome> list = map.getOrDefault(type, Collections.emptyList());
list = ListUtils.minimize(list);
list.sort(Comparator.comparing(BiomeHelper::getId));
biomes[index] = list.toArray(new Biome[0]);
}
for (int i = 0; i < size; i++) {
if (biomes[i] == null) {
biomes[i] = EMPTY;
}
}
return biomes;
}
}

View File

@ -0,0 +1,37 @@
package com.terraforged.biome.map.set;
import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.terraforged.biome.map.defaults.DefaultBiome;
import com.terraforged.core.cell.Cell;
import com.terraforged.world.biome.BiomeType;
import net.minecraft.world.biome.Biome;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Stream;
public class BiomeTypeSet extends BiomeSet {
public BiomeTypeSet(Map<BiomeType, List<Biome>> map, DefaultBiome defaultBiome) {
super(BiomeSet.collect(map, BiomeType.values().length, Enum::ordinal), defaultBiome);
}
@Override
public int getIndex(Cell cell) {
return cell.biomeType.ordinal();
}
@Override
public JsonElement toJson() {
JsonObject root = new JsonObject();
for (BiomeType type : BiomeType.values()) {
JsonArray array = new JsonArray();
root.add(type.name(), array);
Stream.of(getSet(type.ordinal())).distinct().map(Biome::getRegistryName).map(Objects::toString).forEach(array::add);
}
return root;
}
}

View File

@ -0,0 +1,11 @@
package com.terraforged.biome.map.set;
import java.util.stream.Stream;
public class Check {
public static void main(String[] args) {
String[] s = {null};
Stream.of(null).forEach(System.out::println);
}
}

View File

@ -0,0 +1,29 @@
package com.terraforged.biome.map.set;
import com.terraforged.biome.map.BiomeMap;
import com.terraforged.biome.map.defaults.DefaultBiome;
import com.terraforged.biome.map.defaults.DefaultBiomes;
import com.terraforged.core.cell.Cell;
import net.minecraft.world.biome.Biome;
import java.util.List;
import java.util.Map;
public class RiverSet extends TemperatureSet {
private final BiomeMap biomes;
public RiverSet(Map<Biome.TempCategory, List<Biome>> map, DefaultBiome defaultBiome, BiomeMap biomes) {
super(map, defaultBiome);
this.biomes = biomes;
}
@Override
public Biome getBiome(Cell cell) {
Biome biome = biomes.getLand(cell);
if (DefaultBiomes.overridesRiver(biome)) {
return biome;
}
return super.getBiome(cell);
}
}

View File

@ -0,0 +1,45 @@
package com.terraforged.biome.map.set;
import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.terraforged.biome.map.defaults.DefaultBiome;
import com.terraforged.core.cell.Cell;
import net.minecraft.world.biome.Biome;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Stream;
public class TemperatureSet extends BiomeSet {
public TemperatureSet(Map<Biome.TempCategory, List<Biome>> map, DefaultBiome defaultBiome) {
super(BiomeSet.collect(map, 3, e -> e.ordinal() - 1), defaultBiome);
}
@Override
public int getIndex(Cell cell) {
if (cell.temperature < 0.25) {
return 0;
}
if (cell.temperature > 0.75) {
return 2;
}
return 1;
}
@Override
public JsonElement toJson() {
JsonObject root = new JsonObject();
for (Biome.TempCategory temp : Biome.TempCategory.values()) {
int index = temp.ordinal() - 1;
if (index >= 0 && index < 3) {
JsonArray array = new JsonArray();
root.add(temp.name(), array);
Stream.of(getSet(index)).distinct().map(Biome::getRegistryName).map(Objects::toString).forEach(array::add);
}
}
return root;
}
}

View File

@ -1,53 +1,33 @@
/*
*
* MIT License
*
* Copyright (c) 2020 TerraForged
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package com.terraforged.biome.modifier;
import com.terraforged.api.biome.modifier.BiomeModifier;
import com.terraforged.biome.map.BiomeMap;
import com.terraforged.chunk.TerraContext;
import com.terraforged.core.cell.Cell;
import com.terraforged.world.heightmap.Levels;
import com.terraforged.world.GeneratorContext;
import com.terraforged.world.biome.BiomeType;
import com.terraforged.world.terrain.Terrains;
import me.dags.noise.Module;
import me.dags.noise.Source;
import net.minecraft.world.biome.Biome;
import net.minecraft.world.biome.Biomes;
public class BeachModifier implements BiomeModifier {
private final Levels levels;
private final Terrains terrain;
private final BiomeMap biomeMap;
private final float height;
private final Module noise;
private final BiomeMap biomes;
private final Terrains terrains;
public BeachModifier(BiomeMap biomeMap, TerraContext context) {
this.levels = context.levels;
this.terrain = context.terrain;
this.biomeMap = biomeMap;
public BeachModifier(BiomeMap biomeMap, GeneratorContext context) {
this.biomes = biomeMap;
this.terrains = context.terrain;
this.height = context.levels.water(6);
this.noise = Source.perlin(context.seed.next(), 10, 1).scale(context.levels.scale(5));
}
@Override
public int priority() {
return 0;
return 9;
}
@Override
@ -57,11 +37,13 @@ public class BeachModifier implements BiomeModifier {
@Override
public Biome modify(Biome in, Cell cell, int x, int z) {
if (cell.terrain == terrain.beach) {
return biomeMap.getBeach(cell.temperature, cell.moisture, cell.biome);
if (cell.terrain == terrains.beach && cell.biomeType != BiomeType.DESERT) {
if (cell.value + noise.getValue(x, z) < height) {
if (in == Biomes.MUSHROOM_FIELDS) {
return Biomes.MUSHROOM_FIELD_SHORE;
}
return biomes.getBeach(cell);
}
if (cell.terrain == terrain.coast && cell.value <= levels.water) {
return biomeMap.getOcean(cell.temperature, cell.moisture, cell.biome);
}
return in;
}

View File

@ -47,10 +47,10 @@ public class BiomeModifierManager implements BiomeModifier, ModifierManager {
public BiomeModifierManager(TerraContext context, BiomeMap biomes) {
desertBiomes = new DesertBiomes(context.materials, biomes.getAllBiomes(BiomeType.DESERT));
List<BiomeModifier> modifiers = new ArrayList<>();
modifiers.add(new BeachModifier(biomes, context));
modifiers.add(new CoastModifier(biomes, context));
modifiers.add(new DesertColorModifier(desertBiomes));
modifiers.add(new SandBiomeModifier(context));
modifiers.add(new MushroomModifier());
modifiers.add(new BeachModifier(biomes, context));
Collections.sort(modifiers);
this.biomeModifiers = modifiers;
}

View File

@ -23,16 +23,42 @@
* SOFTWARE.
*/
package com.terraforged.biome.map;
package com.terraforged.biome.modifier;
import com.terraforged.core.util.grid.FixedGrid;
import com.terraforged.api.biome.modifier.BiomeModifier;
import com.terraforged.biome.map.BiomeMap;
import com.terraforged.chunk.TerraContext;
import com.terraforged.core.cell.Cell;
import com.terraforged.world.terrain.Terrains;
import net.minecraft.world.biome.Biome;
public class BiomeGroup {
public class CoastModifier implements BiomeModifier {
public final FixedGrid<Biome> biomes;
private final float height;
private final Terrains terrain;
private final BiomeMap biomeMap;
public BiomeGroup(FixedGrid<Biome> biomes) {
this.biomes = biomes;
public CoastModifier(BiomeMap biomeMap, TerraContext context) {
this.terrain = context.terrain;
this.biomeMap = biomeMap;
this.height = context.levels.water(8);
}
@Override
public int priority() {
return 10;
}
@Override
public boolean test(Biome biome) {
return true;
}
@Override
public Biome modify(Biome in, Cell cell, int x, int z) {
if (cell.terrain.isCoast()) {
return biomeMap.getCoast(cell, in);
}
return in;
}
}

View File

@ -40,7 +40,7 @@ public class DesertColorModifier implements BiomeModifier {
@Override
public int priority() {
return 0;
return 5;
}
@Override

View File

@ -1,24 +0,0 @@
package com.terraforged.biome.modifier;
import com.terraforged.api.biome.modifier.BiomeModifier;
import com.terraforged.core.cell.Cell;
import net.minecraft.world.biome.Biome;
import net.minecraft.world.biome.Biomes;
public class DunesModifier implements BiomeModifier {
@Override
public int priority() {
return 0;
}
@Override
public boolean test(Biome biome) {
return biome.getCategory() == Biome.Category.DESERT;
}
@Override
public Biome modify(Biome in, Cell cell, int x, int z) {
return Biomes.DESERT;
}
}

View File

@ -1,23 +0,0 @@
package com.terraforged.biome.modifier;
import com.terraforged.api.biome.modifier.BiomeModifier;
import com.terraforged.core.cell.Cell;
import net.minecraft.world.biome.Biome;
import net.minecraft.world.biome.Biomes;
public class MushroomModifier implements BiomeModifier {
@Override
public int priority() {
return 0;
}
@Override
public boolean test(Biome biome) {
return biome == Biomes.MUSHROOM_FIELD_SHORE;
}
@Override
public Biome modify(Biome in, Cell cell, int x, int z) {
return Biomes.MUSHROOM_FIELDS;
}
}

View File

@ -48,7 +48,7 @@ public class SandBiomeModifier extends AbstractMaxHeightModifier {
@Override
public int priority() {
return 1;
return 3;
}
@Override

View File

@ -1,57 +0,0 @@
package com.terraforged.biome.provider;
import com.terraforged.core.cell.Cell;
import com.terraforged.world.heightmap.Levels;
import com.terraforged.world.terrain.TerrainType;
import net.minecraft.world.biome.Biome;
public class BiomeAccess {
private static final BiomeAccessor DEEP_OCEAN = (m, c) -> m.getDeepOcean(c.temperature, c.moisture, c.biome);
private static final BiomeAccessor SHALLOW_OCEAN = (m, c) -> m.getOcean(c.temperature, c.moisture, c.biome);
private static final BiomeAccessor LAKE = (m, c) -> m.getLake(c.temperature, c.moisture, c.biome);
private static final BiomeAccessor WETLAND = (m, c) -> m.getWetland(c.temperature, c.moisture, c.biome);
private static final BiomeAccessor NORMAL = (m, c) -> m.getBiome(c.biomeType, c.temperature, c.moisture, c.biome);
private static final BiomeAccessor RIVER = (m, c) -> {
Biome biome = m.getBiome(c.biomeType, c.temperature, c.moisture, c.biome);
if (overridesRiver(biome)) {
return biome;
}
return m.getRiver(c.temperature, c.moisture, c.biome);
};
private static final BiomeAccessor[] accessors = createAccessorArray();
private final Levels levels;
public BiomeAccess(Levels levels) {
this.levels = levels;
}
public BiomeAccessor getAccessor(Cell cell) {
TerrainType type = cell.terrain.getType();
if (type.isSubmerged() && cell.value > levels.water) {
return NORMAL;
}
return accessors[cell.terrain.getType().ordinal()];
}
private static BiomeAccessor[] createAccessorArray() {
BiomeAccessor[] accessors = new BiomeAccessor[TerrainType.values().length];
accessors[TerrainType.SHALLOW_OCEAN.ordinal()] = SHALLOW_OCEAN;
accessors[TerrainType.DEEP_OCEAN.ordinal()] = DEEP_OCEAN;
accessors[TerrainType.WETLAND.ordinal()] = WETLAND;
accessors[TerrainType.RIVER.ordinal()] = RIVER;
accessors[TerrainType.LAKE.ordinal()] = LAKE;
for (TerrainType type : TerrainType.values()) {
if (accessors[type.ordinal()] == null) {
accessors[type.ordinal()] = NORMAL;
}
}
return accessors;
}
private static boolean overridesRiver(Biome biome) {
return biome.getCategory() == Biome.Category.SWAMP || biome.getCategory() == Biome.Category.JUNGLE;
}
}

View File

@ -1,10 +0,0 @@
package com.terraforged.biome.provider;
import com.terraforged.biome.map.BiomeMap;
import com.terraforged.core.cell.Cell;
import net.minecraft.world.biome.Biome;
public interface BiomeAccessor {
Biome getBiome(BiomeMap map, Cell cell);
}

View File

@ -54,26 +54,22 @@ public class BiomeHelper {
private static final Map<BiomeType, BiomePredicate> PREDICATES = new HashMap<BiomeType, BiomePredicate>() {{
put(BiomeType.TROPICAL_RAINFOREST, BiomePredicate.TROPICAL_RAINFOREST);
put(BiomeType.SAVANNA, BiomePredicate.SAVANNA.or(BiomePredicate.MESA).not(BiomePredicate.DESERT).not(BiomePredicate.STEPPE).not(BiomePredicate.COAST).not(BiomePredicate.MOUNTAIN).not(BiomePredicate.WETLAND));
put(BiomeType.DESERT, BiomePredicate.DESERT.or(BiomePredicate.MESA).not(BiomePredicate.COAST).not(BiomePredicate.MOUNTAIN).not(BiomePredicate.WETLAND));
put(BiomeType.TEMPERATE_RAINFOREST, BiomePredicate.TEMPERATE_RAINFOREST.not(BiomePredicate.COAST).not(BiomePredicate.MOUNTAIN));
put(BiomeType.TEMPERATE_FOREST, BiomePredicate.TEMPERATE_FOREST.not(BiomePredicate.COAST).not(BiomePredicate.MOUNTAIN).not(BiomePredicate.WETLAND));
put(BiomeType.GRASSLAND, BiomePredicate.GRASSLAND.not(BiomePredicate.WETLAND).not(BiomePredicate.COAST).not(BiomePredicate.MOUNTAIN));
put(BiomeType.COLD_STEPPE, BiomePredicate.COLD_STEPPE.not(BiomePredicate.COAST).not(BiomePredicate.MOUNTAIN));
put(BiomeType.STEPPE, BiomePredicate.STEPPE.not(BiomePredicate.COAST).not(BiomePredicate.MOUNTAIN));
put(BiomeType.TAIGA, BiomePredicate.TAIGA.not(BiomePredicate.TUNDRA).not(BiomePredicate.COLD_STEPPE).not(BiomePredicate.COAST).not(BiomePredicate.MOUNTAIN));
put(BiomeType.TUNDRA, BiomePredicate.TUNDRA.not(BiomePredicate.TAIGA).not(BiomePredicate.COAST).not(BiomePredicate.MOUNTAIN));
put(BiomeType.SAVANNA, BiomePredicate.SAVANNA.or(BiomePredicate.MESA).not(BiomePredicate.DESERT).not(BiomePredicate.STEPPE).not(BiomePredicate.BEACH).not(BiomePredicate.MOUNTAIN).not(BiomePredicate.WETLAND));
put(BiomeType.DESERT, BiomePredicate.DESERT.or(BiomePredicate.MESA).not(BiomePredicate.BEACH).not(BiomePredicate.MOUNTAIN).not(BiomePredicate.WETLAND));
put(BiomeType.TEMPERATE_RAINFOREST, BiomePredicate.TEMPERATE_RAINFOREST.not(BiomePredicate.BEACH).not(BiomePredicate.MOUNTAIN));
put(BiomeType.TEMPERATE_FOREST, BiomePredicate.TEMPERATE_FOREST.not(BiomePredicate.BEACH).not(BiomePredicate.MOUNTAIN).not(BiomePredicate.WETLAND));
put(BiomeType.GRASSLAND, BiomePredicate.GRASSLAND.not(BiomePredicate.WETLAND).not(BiomePredicate.BEACH).not(BiomePredicate.MOUNTAIN));
put(BiomeType.COLD_STEPPE, BiomePredicate.COLD_STEPPE.not(BiomePredicate.BEACH).not(BiomePredicate.MOUNTAIN));
put(BiomeType.STEPPE, BiomePredicate.STEPPE.not(BiomePredicate.BEACH).not(BiomePredicate.MOUNTAIN));
put(BiomeType.TAIGA, BiomePredicate.TAIGA.not(BiomePredicate.TUNDRA).not(BiomePredicate.COLD_STEPPE).not(BiomePredicate.BEACH).not(BiomePredicate.MOUNTAIN));
put(BiomeType.TUNDRA, BiomePredicate.TUNDRA.not(BiomePredicate.TAIGA).not(BiomePredicate.BEACH).not(BiomePredicate.MOUNTAIN));
put(BiomeType.ALPINE, BiomePredicate.MOUNTAIN);
}};
public static BiomeMap.Builder getBuilder(List<BiomeData> biomes) {
return BiomeMapBuilder.basic(biomes);
}
public static BiomeMap getDefaultBiomeMap() {
public static BiomeMap createBiomeMap() {
List<BiomeData> biomes = getAllBiomeData();
BiomeWeights weights = new BiomeWeights();
BiomeMap.Builder builder = getBuilder(biomes);
BiomeMap.Builder builder = BiomeMapBuilder.create();
for (BiomeData data : biomes) {
Biome biome = (Biome) data.reference;
if (biome.isMutation() && getId(biome).contains("hills")) {
@ -81,8 +77,10 @@ public class BiomeHelper {
}
int weight = weights.getWeight(biome);
if (BiomePredicate.COAST.test(data)) {
if (BiomePredicate.BEACH.test(data)) {
builder.addBeach(biome, weight);
} else if (BiomePredicate.COAST.test(data)) {
builder.addCoast(biome, weight);
} else if (biome.getCategory() == Biome.Category.OCEAN) {
builder.addOcean(biome, weight);
} else if (BiomePredicate.RIVER.test(data)) {
@ -94,16 +92,16 @@ public class BiomeHelper {
} else {
Collection<BiomeType> types = getTypes(data, biome);
for (BiomeType type : types) {
builder.addBiome(type, biome, weight);
builder.addLand(type, biome, weight);
}
}
}
builder.addBiome(BiomeType.TEMPERATE_RAINFOREST, Biomes.PLAINS, 10);
builder.addBiome(BiomeType.TEMPERATE_FOREST, Biomes.FLOWER_FOREST, 2);
builder.addBiome(BiomeType.TEMPERATE_FOREST, Biomes.PLAINS, 10);
builder.addBiome(BiomeType.TUNDRA, ModBiomes.SNOWY_TAIGA_SCRUB, 5);
builder.addBiome(BiomeType.TAIGA, ModBiomes.TAIGA_SCRUB, 5);
builder.addLand(BiomeType.TEMPERATE_RAINFOREST, Biomes.PLAINS, 5);
builder.addLand(BiomeType.TEMPERATE_FOREST, Biomes.FLOWER_FOREST, 2);
builder.addLand(BiomeType.TEMPERATE_FOREST, Biomes.PLAINS, 5);
builder.addLand(BiomeType.TUNDRA, ModBiomes.SNOWY_TAIGA_SCRUB, 2);
builder.addLand(BiomeType.TAIGA, ModBiomes.TAIGA_SCRUB, 2);
return builder.build();
}
@ -185,6 +183,9 @@ public class BiomeHelper {
if (biome.getCategory() == Biome.Category.NETHER) {
return true;
}
if (biome == Biomes.MUSHROOM_FIELD_SHORE) {
return true;
}
return !BiomeDictionary.getTypes(biome).contains(BiomeDictionary.Type.OVERWORLD);
}

View File

@ -47,7 +47,6 @@ import java.util.Set;
public class BiomeProvider extends AbstractBiomeProvider {
private final BiomeMap biomeMap;
private final BiomeAccess biomeAccess;
private final TerraContext context;
private final WorldLookup worldLookup;
private final BiomeModifierManager modifierManager;
@ -55,8 +54,7 @@ public class BiomeProvider extends AbstractBiomeProvider {
public BiomeProvider(TerraContext context) {
this.context = context;
this.biomeMap = BiomeHelper.getDefaultBiomeMap();
this.biomeAccess = new BiomeAccess(context.levels);
this.biomeMap = BiomeHelper.createBiomeMap();
this.worldLookup = new WorldLookup(context.factory, context);
this.modifierManager = SetupHooks.setup(new BiomeModifierManager(context, biomeMap), context.copy());
}
@ -143,8 +141,7 @@ public class BiomeProvider extends AbstractBiomeProvider {
}
public Biome getBiome(Cell cell, int x, int z) {
BiomeAccessor accessor = biomeAccess.getAccessor(cell);
Biome biome = accessor.getBiome(biomeMap, cell);
Biome biome = biomeMap.provideBiome(cell, context.levels);
if (modifierManager.hasModifiers(cell.terrain)) {
return modifierManager.modify(biome, cell, x, z);
}

View File

@ -0,0 +1,36 @@
package com.terraforged.biome.surface;
import com.terraforged.api.chunk.surface.Surface;
import com.terraforged.api.chunk.surface.SurfaceContext;
import com.terraforged.api.material.state.States;
import com.terraforged.world.GeneratorContext;
import me.dags.noise.Module;
import me.dags.noise.Source;
import net.minecraft.block.BlockState;
import net.minecraft.block.Blocks;
public class ForestSurface implements Surface {
private final Module noise;
public ForestSurface(GeneratorContext context) {
noise = Source.simplex(context.seed.next(), 40, 2).warp(Source.RAND, context.seed.next(), 2, 1, 4);
}
@Override
public void buildSurface(int x, int z, int height, SurfaceContext ctx) {
BlockState state = getMaterial(x, z);
ctx.buffer.setBlockState(ctx.pos.setPos(x, height, z), state, false);
}
private BlockState getMaterial(int x, int z) {
float value = noise.getValue(x, z);
if (value > 0.6) {
if (value < 0.75) {
return Blocks.PODZOL.getDefaultState();
}
return States.DIRT.get();
}
return States.GRASS_BLOCK.get();
}
}

View File

@ -5,10 +5,10 @@ import com.terraforged.api.chunk.column.ColumnDecorator;
import com.terraforged.api.chunk.surface.SurfaceManager;
import com.terraforged.biome.ModBiomes;
import com.terraforged.biome.surface.BriceSurface;
import com.terraforged.biome.surface.ForestSurface;
import com.terraforged.biome.surface.IcebergsSurface;
import com.terraforged.biome.surface.SwampSurface;
import com.terraforged.chunk.column.BedrockDecorator;
import com.terraforged.chunk.column.CoastDecorator;
import com.terraforged.chunk.column.ErosionDecorator;
import com.terraforged.chunk.column.GeologyDecorator;
import com.terraforged.chunk.column.post.LayerDecorator;
@ -53,7 +53,6 @@ public class TerraSetupFactory {
Log.info(" - Erosion decorator enabled");
processors.add(new ErosionDecorator(context));
}
processors.add(new CoastDecorator(context));
processors.add(new BedrockDecorator(context));
return processors;
}
@ -112,9 +111,21 @@ public class TerraSetupFactory {
SurfaceManager manager = new SurfaceManager();
manager.replace(Biomes.DEEP_FROZEN_OCEAN.delegate.get(), new IcebergsSurface(context, 30, 30));
manager.replace(Biomes.FROZEN_OCEAN.delegate.get(), new IcebergsSurface(context, 20, 15));
manager.replace(Biomes.SWAMP.delegate.get(), new SwampSurface());
manager.replace(ModBiomes.MARSHLAND, new SwampSurface());
manager.extend(ModBiomes.BRICE, new BriceSurface(context.seed));
manager.append(ModBiomes.BRICE, new BriceSurface(context.seed));
manager.replace(
new SwampSurface(),
Biomes.SWAMP.delegate.get(),
ModBiomes.MARSHLAND
);
manager.append(
new ForestSurface(context),
Biomes.FOREST,
Biomes.BIRCH_FOREST,
Biomes.BIRCH_FOREST_HILLS,
Biomes.TALL_BIRCH_FOREST,
Biomes.DARK_FOREST,
Biomes.DARK_FOREST_HILLS
);
return SetupHooks.setup(manager, context);
}

View File

@ -26,56 +26,28 @@
package com.terraforged.data;
import com.google.gson.GsonBuilder;
import com.google.gson.JsonArray;
import com.google.gson.JsonObject;
import com.terraforged.biome.map.BiomeMap;
import com.terraforged.biome.provider.BiomeHelper;
import com.terraforged.world.biome.BiomeType;
import net.minecraft.util.ResourceLocation;
import net.minecraft.world.biome.Biome;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.Writer;
import java.util.Set;
public class WorldGenBiomes extends DataGen {
public static void genBiomeMap(File dataDir) {
BiomeMap map = BiomeHelper.getDefaultBiomeMap();
for (BiomeType type : BiomeType.values()) {
genBiomes(dataDir, type, map);
}
try (Writer writer = new BufferedWriter(new FileWriter(new File("biome_map.json")))) {
BiomeMap map = BiomeHelper.createBiomeMap();
try (Writer writer = new BufferedWriter(new FileWriter(new File(dataDir, "biome_map.json")))) {
new GsonBuilder().setPrettyPrinting().create().toJson(map.toJson(), writer);
} catch (IOException e) {
e.printStackTrace();
}
}
private static void genBiomes(File dir, BiomeType type, BiomeMap map) {
String path = getJsonPath("tags/biomes", getName(type));
write(new File(dir, path), writer -> {
Set<Biome> biomes = map.getBiomes(type);
JsonObject root = new JsonObject();
JsonArray values = new JsonArray();
root.addProperty("replaceable", false);
root.add("values", values);
biomes.stream()
.map(b -> b.getRegistryName() + "")
.sorted()
.forEach(values::add);
write(root, writer);
});
}
private static ResourceLocation getName(BiomeType type) {
return new ResourceLocation("terraforged", type.name().toLowerCase());
}

View File

@ -41,7 +41,12 @@ import net.minecraft.block.MyceliumBlock;
import net.minecraft.tags.BlockTags;
import net.minecraft.tags.Tag;
import net.minecraft.util.math.BlockPos;
import net.minecraftforge.registries.IForgeRegistryEntry;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Set;
public class Materials {
@ -103,4 +108,16 @@ public class Materials {
return state.getBlockHardness(reader.get(), BlockPos.ZERO);
}
}
public static <T extends IForgeRegistryEntry<T>> List<T> toList(Collection<T> collection) {
List<T> list = new ArrayList<>(collection);
list.sort(Materials::compare);
return Collections.unmodifiableList(list);
}
public static int compare(IForgeRegistryEntry<?> a, IForgeRegistryEntry<?> b) {
String as = a.getRegistryName() + "";
String bs = b.getRegistryName() + "";
return as.compareTo(bs);
}
}

View File

@ -48,10 +48,10 @@ public class GeoGenerator implements StrataGenerator {
public GeoGenerator(Materials materials) {
types.add(Source.PERLIN);
rock = new ArrayList<>(materials.stone);
soil = new ArrayList<>(materials.dirt);
clay = new ArrayList<>(materials.clay);
sediment = new ArrayList<>(materials.sediment);
rock = Materials.toList(materials.stone);
soil = Materials.toList(materials.dirt);
clay = Materials.toList(materials.clay);
sediment = Materials.toList(materials.sediment);
}
@Override

View File

@ -0,0 +1,115 @@
{
"biomes": [
"minecraft:birch*",
"minecraft:tall_birch*"
],
"match": [
[
"minecraft:birch_log",
"minecraft:birch_leaves"
],
[
"terraforged:poisson_surface"
]
],
"after": {
"name": "minecraft:decorated",
"config": {
"feature": {
"name": "minecraft:random_selector",
"config": {
"features": [
{
"name": "minecraft:jungle_ground_bush",
"config": {
"trunk_provider": {
"type": "minecraft:simple_state_provider",
"state": {
"Name": "minecraft:oak_log",
"Properties": {
"axis": "y"
}
}
},
"leaves_provider": {
"type": "minecraft:simple_state_provider",
"state": {
"Name": "minecraft:birch_leaves",
"Properties": {
"distance": "3",
"persistent": "false"
}
}
},
"decorators": [],
"base_height": 3
},
"chance": 0.15
},
{
"name": "minecraft:jungle_ground_bush",
"config": {
"trunk_provider": {
"type": "minecraft:simple_state_provider",
"state": {
"Name": "minecraft:oak_log",
"Properties": {
"axis": "y"
}
}
},
"leaves_provider": {
"type": "minecraft:simple_state_provider",
"state": {
"Name": "minecraft:oak_leaves",
"Properties": {
"distance": "3",
"persistent": "false"
}
}
},
"decorators": [],
"base_height": 4
},
"chance": 0.25
}
],
"default": {
"name": "minecraft:jungle_ground_bush",
"config": {
"trunk_provider": {
"type": "minecraft:simple_state_provider",
"state": {
"Name": "minecraft:oak_log",
"Properties": {
"axis": "y"
}
}
},
"leaves_provider": {
"type": "minecraft:simple_state_provider",
"state": {
"Name": "minecraft:oak_leaves",
"Properties": {
"distance": "3",
"persistent": "false"
}
}
},
"decorators": [],
"base_height": 3
}
}
}
},
"decorator": {
"name": "minecraft:count_extra_heightmap",
"config": {
"count": 0,
"extra_chance": 0.05,
"extra_count": 1
}
}
}
}
}

View File

@ -0,0 +1,117 @@
{
"biomes": [
"minecraft:forest",
"minecraft:forest_hills",
"minecraft:dark_forest",
"minecraft:dark_forest_hills"
],
"match": [
[
"minecraft:oak_log",
"minecraft:oak_leaves"
],
[
"terraforged:poisson_surface"
]
],
"after": {
"name": "minecraft:decorated",
"config": {
"feature": {
"name": "minecraft:random_selector",
"config": {
"features": [
{
"name": "minecraft:jungle_ground_bush",
"config": {
"trunk_provider": {
"type": "minecraft:simple_state_provider",
"state": {
"Name": "minecraft:oak_log",
"Properties": {
"axis": "y"
}
}
},
"leaves_provider": {
"type": "minecraft:simple_state_provider",
"state": {
"Name": "minecraft:birch_leaves",
"Properties": {
"distance": "3",
"persistent": "false"
}
}
},
"decorators": [],
"base_height": 3
},
"chance": 0.15
},
{
"name": "minecraft:jungle_ground_bush",
"config": {
"trunk_provider": {
"type": "minecraft:simple_state_provider",
"state": {
"Name": "minecraft:oak_log",
"Properties": {
"axis": "y"
}
}
},
"leaves_provider": {
"type": "minecraft:simple_state_provider",
"state": {
"Name": "minecraft:oak_leaves",
"Properties": {
"distance": "3",
"persistent": "false"
}
}
},
"decorators": [],
"base_height": 4
},
"chance": 0.25
}
],
"default": {
"name": "minecraft:jungle_ground_bush",
"config": {
"trunk_provider": {
"type": "minecraft:simple_state_provider",
"state": {
"Name": "minecraft:oak_log",
"Properties": {
"axis": "y"
}
}
},
"leaves_provider": {
"type": "minecraft:simple_state_provider",
"state": {
"Name": "minecraft:oak_leaves",
"Properties": {
"distance": "3",
"persistent": "false"
}
}
},
"decorators": [],
"base_height": 3
}
}
}
},
"decorator": {
"name": "minecraft:count_extra_heightmap",
"config": {
"count": 1,
"extra_chance": 0.05,
"extra_count": 1
}
}
}
}
}

View File

@ -0,0 +1,110 @@
{
"biomes": [
"minecraft:birch*",
"minecraft:tall_birch*",
"minecraft:forest",
"minecraft:forest_hills",
"minecraft:dark_forest",
"minecraft:dark_forest_hills"
],
"match": [
[
"minecraft:decorated",
"minecraft:grass"
]
],
"after": {
"name": "minecraft:decorated",
"config": {
"feature": {
"name": "minecraft:random_selector",
"config": {
"features": [
{
"name": "minecraft:random_patch",
"config": {
"state_provider": {
"type": "minecraft:simple_state_provider",
"state": {
"Name": "minecraft:fern"
}
},
"block_placer": {
"type": "minecraft:simple_block_placer"
},
"whitelist": [],
"blacklist": [],
"tries": 20,
"xspread": 7,
"yspread": 3,
"zspread": 7,
"can_replace": false,
"project": true,
"need_water": false
},
"chance": 0.3
},
{
"name": "minecraft:random_patch",
"config": {
"state_provider": {
"type": "minecraft:simple_state_provider",
"state": {
"Name": "minecraft:large_fern",
"Properties": {
"half": "lower"
}
}
},
"block_placer": {
"type": "minecraft:double_plant_placer"
},
"whitelist": [],
"blacklist": [],
"tries": 20,
"xspread": 7,
"yspread": 3,
"zspread": 7,
"can_replace": false,
"project": false,
"need_water": false
},
"chance": 0.2
}
],
"default": {
"name": "minecraft:random_patch",
"config": {
"state_provider": {
"type": "minecraft:simple_state_provider",
"state": {
"Name": "minecraft:fern"
}
},
"block_placer": {
"type": "minecraft:simple_block_placer"
},
"whitelist": [],
"blacklist": [],
"tries": 10,
"xspread": 7,
"yspread": 3,
"zspread": 7,
"can_replace": false,
"project": true,
"need_water": false
}
}
}
},
"decorator": {
"name": "minecraft:count_extra_heightmap",
"config": {
"count": 1,
"extra_chance": 0.1,
"extra_count": 1
}
}
}
}
}

View File

@ -1,7 +1,7 @@
{
"biomes": [
"minecraft:birch_forest",
"minecraft:birch_forest_hills",
"minecraft:birch*",
"minecraft:tall_birch*",
"minecraft:forest",
"minecraft:forest_hills",
"minecraft:dark_forest",

View File

@ -0,0 +1,44 @@
{
"biomes": [
"terraforged:savanna_scrub",
"terraforged:shattered_savanna_scrub"
],
"match": [
[
"minecraft:dead_bush"
]
],
"before": {
"name": "minecraft:decorated",
"config": {
"feature": {
"name": "minecraft:random_selector",
"config": {
"features": [
{
"name": "terraforged:template",
"config": {
"template": "terraforged:acacia_bush"
},
"chance": 0.1
}
],
"default": {
"name": "terraforged:template",
"config": {
"template": "terraforged:acacia_bush"
}
}
}
},
"decorator": {
"name": "minecraft:count_extra_heightmap",
"config": {
"count": 0,
"extra_chance": 0.025,
"extra_count": 1
}
}
}
}
}

View File

@ -42,11 +42,11 @@
"decorator": {
"name": "terraforged:poisson_surface",
"config": {
"radius": 9,
"biome_fade": 0.25,
"radius": 8,
"biome_fade": 0.12,
"density_noise_scale": 300,
"density_noise_min": 0,
"density_noise_max": 2
"density_noise_min": 0.5,
"density_noise_max": 1.5
}
}
}

View File

@ -41,10 +41,10 @@
"decorator": {
"name": "terraforged:poisson_surface",
"config": {
"radius": 9,
"biome_fade": 0.2,
"radius": 8,
"biome_fade": 0.12,
"density_noise_scale": 150,
"density_noise_min": 0.15,
"density_noise_min": 0.5,
"density_noise_max": 1.75
}
}

View File

@ -0,0 +1,11 @@
{
"type": "tree",
"name": "terraforged:acacia_bush",
"paths": [
"terraforged:trees/acacia/bush"
],
"config": {
"extend_base": 2,
"check_bounds": false
}
}