Climate layer works

This commit is contained in:
Adubbz 2019-01-14 20:21:56 +11:00
parent 65305344f7
commit 98cba6e62c
10 changed files with 357 additions and 32 deletions

View file

@ -0,0 +1,153 @@
/*******************************************************************************
* Copyright 2014-2019, the Biomes O' Plenty Team
*
* This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivatives 4.0 International Public License.
*
* To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/4.0/.
******************************************************************************/
package biomesoplenty.api.enums;
import biomesoplenty.common.world.layer.traits.IBOPContextExtended;
import net.minecraft.init.Biomes;
import net.minecraft.world.biome.Biome;
import net.minecraftforge.common.BiomeManager.BiomeType;
import java.util.ArrayList;
import java.util.Iterator;
public enum BOPClimates
{
COLD_DESERT (BiomeType.ICY),
TUNDRA (BiomeType.ICY),
BOREAL (BiomeType.COOL),
COLD_SWAMP (BiomeType.COOL),
WET_TEMPERATE (BiomeType.WARM),
DRY_TEMPERATE (BiomeType.WARM),
COOL_TEMPERATE (BiomeType.COOL),
WARM_TEMPERATE (BiomeType.WARM),
SUBTROPICAL (BiomeType.WARM),
TROPICAL (BiomeType.DESERT),
MEDITERRANEAN (BiomeType.WARM),
SAVANNA (BiomeType.DESERT),
HOT_DESERT (BiomeType.DESERT),
WASTELAND (BiomeType.DESERT),
HELL (null);
public final BiomeType biomeType;
private int totalBiomesWeight;
private ArrayList<WeightedBiomeEntry> landBiomes = new ArrayList<WeightedBiomeEntry>();
BOPClimates(BiomeType biomeType)
{
this.biomeType = biomeType;
}
public BOPClimates addBiome(int weight, Biome biome)
{
return this.addBiome(new WeightedBiomeEntry(weight, biome));
}
public BOPClimates addBiome(WeightedBiomeEntry biomeEntry)
{
this.totalBiomesWeight += biomeEntry.weight;
this.landBiomes.add(biomeEntry);
return this;
}
public Biome getRandomBiome(IBOPContextExtended context)
{
int weight = context.random(this.totalBiomesWeight);
Iterator<WeightedBiomeEntry> iterator = this.landBiomes.iterator();
WeightedBiomeEntry item;
do
{
item = iterator.next();
weight -= item.weight;
}
while (weight >= 0);
return item.biome;
}
public Biome getRandomOceanBiome(IBOPContextExtended context, boolean deep)
{
return (deep ? Biomes.DEEP_OCEAN : Biomes.OCEAN);
}
static
{
// set up vanilla biomes
BOPClimates.COLD_DESERT.addBiome(10, Biomes.SNOWY_TUNDRA);
BOPClimates.TUNDRA.addBiome(10, Biomes.SNOWY_TAIGA).addBiome(5, Biomes.MOUNTAINS);
BOPClimates.BOREAL.addBiome(7, Biomes.DARK_FOREST).addBiome(5, Biomes.MOUNTAINS).addBiome(15, Biomes.TAIGA);
BOPClimates.COLD_SWAMP.addBiome(10, Biomes.SWAMP);
BOPClimates.WET_TEMPERATE.addBiome(3, Biomes.DARK_FOREST).addBiome(7, Biomes.FOREST);
BOPClimates.DRY_TEMPERATE.addBiome(5, Biomes.PLAINS);
BOPClimates.COOL_TEMPERATE.addBiome(7, Biomes.DARK_FOREST).addBiome(7, Biomes.FOREST).addBiome(10, Biomes.BIRCH_FOREST);
BOPClimates.WARM_TEMPERATE.addBiome(7, Biomes.PLAINS);
BOPClimates.SUBTROPICAL.addBiome(5, Biomes.OCEAN);
BOPClimates.TROPICAL.addBiome(15, Biomes.JUNGLE);
BOPClimates.MEDITERRANEAN.addBiome(5, Biomes.PLAINS);
BOPClimates.SAVANNA.addBiome(20, Biomes.SAVANNA);
BOPClimates.HOT_DESERT.addBiome(30, Biomes.DESERT).addBiome(15, Biomes.BADLANDS_PLATEAU);
BOPClimates.WASTELAND.addBiome(1, Biomes.DESERT);
BOPClimates.HELL.addBiome(30, Biomes.NETHER);
}
private static BOPClimates[] values = BOPClimates.values();
public static BOPClimates lookup(int i) {return values[i];}
// map temperature and rainfall to climates
// temperature values from 0 (cold) to 8 (hot) and rainfall values from 0 (wet) to 11 (dry), index is (temperatureValue * 12) + rainfallValue
// we will contrive to make any combination equally likely, so the overall rarity of each climate is in proportion to the number of times it appears in the array
private static final BOPClimates[] climateMapping = new BOPClimates[] {
// 0 1 2 3 4 5 6 7 8 9 10 11
TUNDRA, TUNDRA, TUNDRA, COLD_DESERT, COLD_DESERT, COLD_DESERT, COLD_DESERT, COLD_DESERT, COLD_DESERT, COLD_DESERT, COLD_DESERT, COLD_DESERT, // 0
BOREAL, BOREAL, BOREAL, TUNDRA, TUNDRA, TUNDRA, TUNDRA, TUNDRA, TUNDRA, TUNDRA, TUNDRA, TUNDRA, // 1
COLD_SWAMP, COLD_SWAMP, COLD_SWAMP, BOREAL, BOREAL, BOREAL, BOREAL, BOREAL, BOREAL, BOREAL, BOREAL, BOREAL, // 2
COLD_SWAMP, COLD_SWAMP, COLD_SWAMP, COOL_TEMPERATE, COOL_TEMPERATE, COOL_TEMPERATE, COOL_TEMPERATE, COOL_TEMPERATE, COOL_TEMPERATE, DRY_TEMPERATE, DRY_TEMPERATE, DRY_TEMPERATE, // 3
WET_TEMPERATE, WET_TEMPERATE, WET_TEMPERATE, COOL_TEMPERATE, COOL_TEMPERATE, COOL_TEMPERATE, COOL_TEMPERATE, COOL_TEMPERATE, COOL_TEMPERATE, DRY_TEMPERATE, DRY_TEMPERATE, DRY_TEMPERATE, // 4
SUBTROPICAL, SUBTROPICAL, WET_TEMPERATE, WARM_TEMPERATE, WARM_TEMPERATE, WARM_TEMPERATE, WARM_TEMPERATE, WARM_TEMPERATE, WARM_TEMPERATE, WARM_TEMPERATE, SAVANNA, SAVANNA, // 5
TROPICAL, SUBTROPICAL, SUBTROPICAL, WET_TEMPERATE, WARM_TEMPERATE, WARM_TEMPERATE, WARM_TEMPERATE, WARM_TEMPERATE, MEDITERRANEAN, SAVANNA, SAVANNA, HOT_DESERT, // 6
TROPICAL, TROPICAL, SUBTROPICAL, SUBTROPICAL, WET_TEMPERATE, MEDITERRANEAN, MEDITERRANEAN, MEDITERRANEAN, SAVANNA, HOT_DESERT, HOT_DESERT, HOT_DESERT, // 7
TROPICAL, TROPICAL, TROPICAL, SUBTROPICAL, WET_TEMPERATE, MEDITERRANEAN, MEDITERRANEAN, SAVANNA, HOT_DESERT, HOT_DESERT, WASTELAND, WASTELAND // 8
};
public static int[] getClimateMappingInts()
{
// 9 temperature values, 12 rainfall values, 12 * 9 = 108
int[] out = new int[108];
for (int i = 0; i < 108; i++)
{
out[i] = climateMapping[i].ordinal();
}
return out;
}
public static class WeightedBiomeEntry
{
public final int weight;
public final Biome biome;
public WeightedBiomeEntry(int weight, Biome biome)
{
this.weight = weight;
this.biome = biome;
}
}
// for debugging purposes
public static void printWeights()
{
for (BOPClimates climate : BOPClimates.values())
{
for (WeightedBiomeEntry entry : climate.landBiomes)
{
System.out.println(climate.name()+" "+entry.biome.getDisplayName()+" "+entry.weight);
}
}
}
}

View file

@ -7,7 +7,7 @@
******************************************************************************/
package biomesoplenty.common.world;
import biomesoplenty.common.world.layer.GenLayerTemperatureNoise;
import biomesoplenty.common.world.layer.*;
import biomesoplenty.common.world.layer.traits.LazyAreaLayerContextBOP;
import com.google.common.collect.ImmutableList;
import net.minecraft.world.WorldType;
@ -47,48 +47,43 @@ public class BOPLayerUtil
{
IAreaFactory<T> temperatureFactory;
temperatureFactory = GenLayerTemperatureNoise.LARGE_ZONES.apply(contextFactory.apply(3L));
/*switch (settings.tempScheme)
switch (settings.tempScheme)
{
case LATITUDE: default:
temperature = new GenLayerTemperatureLatitude(2L, 16, worldSeed);
temperatureFactory = GenLayerTemperatureLatitude.INSTANCE.apply(contextFactory.apply(2L));
break;
case SMALL_ZONES:
temperature = new GenLayerTemperatureNoise(3L, worldSeed, 0.14D);
temperatureFactory = GenLayerTemperatureNoise.SMALL_ZONES.apply(contextFactory.apply(3L));
break;
case MEDIUM_ZONES:
temperature = new GenLayerTemperatureNoise(4L, worldSeed, 0.08D);
temperatureFactory = GenLayerTemperatureNoise.MEDIUM_ZONES.apply(contextFactory.apply(4L));
break;
case LARGE_ZONES:
temperature = new GenLayerTemperatureNoise(5L, worldSeed, 0.04D);
temperatureFactory = GenLayerTemperatureNoise.LARGE_ZONES.apply(contextFactory.apply(5L));
break;
case RANDOM:
temperature = new GenLayerTemperatureRandom(6L);
break;
}*/
/*GenLayer rainfall;
switch(settings.rainScheme)
{
case SMALL_ZONES:
rainfall = new GenLayerRainfallNoise(7L, worldSeed, 0.14D);
break;
case MEDIUM_ZONES: default:
rainfall = new GenLayerRainfallNoise(8L, worldSeed, 0.08D);
break;
case LARGE_ZONES:
rainfall = new GenLayerRainfallNoise(9L, worldSeed, 0.04D);
break;
case RANDOM:
rainfall = new GenLayerRainfallRandom(10L);
temperatureFactory = GenLayerTemperatureRandom.INSTANCE.apply(contextFactory.apply(6L));
break;
}
GenLayerClimate climate = new GenLayerClimate(103L, temperature, rainfall);
// stack = new GenLayerEdge(3L, stack, GenLayerEdge.Mode.SPECIAL);
return climate;*/
IAreaFactory<T> rainfallFactory;
switch(settings.rainScheme)
{
case SMALL_ZONES:
rainfallFactory = GenLayerRainfallNoise.SMALL_ZONES.apply(contextFactory.apply(7L));
break;
case MEDIUM_ZONES: default:
rainfallFactory = GenLayerRainfallNoise.MEDIUM_ZONES.apply(contextFactory.apply(8L));
break;
case LARGE_ZONES:
rainfallFactory = GenLayerRainfallNoise.LARGE_ZONES.apply(contextFactory.apply(9L));
break;
case RANDOM:
rainfallFactory = GenLayerRainfallRandom.INSTANCE.apply(contextFactory.apply(10L));
break;
}
return temperatureFactory;
return GenLayerMixOceans.INSTANCE.apply(contextFactory.apply(103L), temperatureFactory, rainfallFactory);
}
public static <T extends IArea, C extends IContextExtended<T>> ImmutableList<IAreaFactory<T>> createAreaFactories(WorldType worldType, OverworldGenSettings settings, LongFunction<C> contextFactory)

View file

@ -0,0 +1,41 @@
/*******************************************************************************
* Copyright 2014-2019, the Biomes O' Plenty Team
*
* This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivatives 4.0 International Public License.
*
* To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/4.0/.
******************************************************************************/
package biomesoplenty.common.world.layer;
import biomesoplenty.api.enums.BOPClimates;
import net.minecraft.util.math.MathHelper;
import net.minecraft.world.gen.IContext;
import net.minecraft.world.gen.area.AreaDimension;
import net.minecraft.world.gen.area.IArea;
import net.minecraft.world.gen.layer.traits.IAreaTransformer2;
import net.minecraft.world.gen.layer.traits.IDimOffset0Transformer;
public enum GenLayerClimate implements IAreaTransformer2, IDimOffset0Transformer
{
INSTANCE;
private final int[] climateMapping;
GenLayerClimate()
{
this.climateMapping = BOPClimates.getClimateMappingInts();
}
@Override
public int apply(IContext context, AreaDimension dimension, IArea area1, IArea area2, int x, int z)
{
int temperature = area1.getValue(x, z);
int rainfall = area2.getValue(x, z);
// temperature values from 0 (cold) to 8 (hot) and rainfall values from 0 (wet) to 11 (dry), index is (temperatureValue * 12) + rainfallValue
// clamp as a precaution against potential rounding errors due to use of doubles/floats in noise calculations
// this guarantees index is between 0 and 108 (= 9 * 12), the range of indexes in BOPClimates.getClimateMappingInts()
int index = ( MathHelper.clamp(temperature, 0, 8) * 12 ) + MathHelper.clamp(rainfall, 0, 11);
return this.climateMapping[index];
}
}

View file

@ -0,0 +1,49 @@
/*******************************************************************************
* Copyright 2014-2019, the Biomes O' Plenty Team
*
* This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivatives 4.0 International Public License.
*
* To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/4.0/.
******************************************************************************/
package biomesoplenty.common.world.layer;
import biomesoplenty.common.world.SimplexNoise;
import biomesoplenty.common.world.layer.traits.IBOPAreaTransformer0;
import biomesoplenty.common.world.layer.traits.IBOPContextExtended;
import net.minecraft.world.gen.area.AreaDimension;
public enum GenLayerRainfallNoise implements IBOPAreaTransformer0
{
SMALL_ZONES(0.14D),
MEDIUM_ZONES(0.08D),
LARGE_ZONES(0.04D);
private final double scale;
GenLayerRainfallNoise(double scale)
{
this.scale = scale;
}
@Override
public int apply(IBOPContextExtended context, AreaDimension areaDimension, int x, int z)
{
double xOffset = (double)(context.getWorldSeed() & 0xFFFFFF) * 0.000003D;
double zOffset = (double)(context.getWorldSeed() & 0xFFFFFF) * 0.000004D;
double noiseVal = SimplexNoise.noise((x + xOffset) * this.scale, (z + zOffset) * this.scale);
// boundaries were determined empirically by analyzing statistically output from the SimplexNoise function, and splitting into 12 equally likely groups
if (noiseVal < -0.637D) return 0;
else if (noiseVal < -0.575D) return 1;
else if (noiseVal < -0.465D) return 2;
else if (noiseVal < -0.295D) return 3;
else if (noiseVal < -0.148D) return 4;
else if (noiseVal < -0.034D) return 5;
else if (noiseVal < 0.132D) return 6;
else if (noiseVal < 0.246D) return 7;
else if (noiseVal < 0.400D) return 8;
else if (noiseVal < 0.551D) return 9;
else if (noiseVal < 0.634D) return 10;
else return 11;
}
}

View file

@ -0,0 +1,24 @@
/*******************************************************************************
* Copyright 2014-2019, the Biomes O' Plenty Team
*
* This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivatives 4.0 International Public License.
*
* To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/4.0/.
******************************************************************************/
package biomesoplenty.common.world.layer;
import biomesoplenty.common.world.layer.traits.IBOPAreaTransformer0;
import biomesoplenty.common.world.layer.traits.IBOPContextExtended;
import net.minecraft.world.gen.area.AreaDimension;
public enum GenLayerRainfallRandom implements IBOPAreaTransformer0
{
INSTANCE;
@Override
public int apply(IBOPContextExtended context, AreaDimension areaDimension, int x, int z)
{
// Choose a random heat value
return context.random(12);
}
}

View file

@ -0,0 +1,32 @@
/*******************************************************************************
* Copyright 2014-2019, the Biomes O' Plenty Team
*
* This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivatives 4.0 International Public License.
*
* To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/4.0/.
******************************************************************************/
package biomesoplenty.common.world.layer;
import biomesoplenty.common.world.layer.traits.IBOPAreaTransformer0;
import biomesoplenty.common.world.layer.traits.IBOPContextExtended;
import net.minecraft.util.math.MathHelper;
import net.minecraft.world.gen.area.AreaDimension;
public enum GenLayerTemperatureLatitude implements IBOPAreaTransformer0
{
INSTANCE;
private static final double HALF_PERIOD = 16.0D;
private static final double PERIOD = HALF_PERIOD * 2.0D;
private static final double OFFSET_VARIATION = HALF_PERIOD / 10.0D;
private static final double AMPLITUDE = 8.9999D / HALF_PERIOD;
@Override
public int apply(IBOPContextExtended context, AreaDimension areaDimension, int x, int z)
{
int offset = (int) (context.getWorldSeed() % ((int) (PERIOD * 2)));
double yOffset = z + offset + ((context.random(1001) - 500) * OFFSET_VARIATION / 500.0D);
return MathHelper.floor(AMPLITUDE * Math.abs((Math.abs(yOffset % PERIOD) - HALF_PERIOD)));
}
}

View file

@ -8,11 +8,11 @@
package biomesoplenty.common.world.layer;
import biomesoplenty.common.world.SimplexNoise;
import biomesoplenty.common.world.layer.traits.IBOPAreaTransformer;
import biomesoplenty.common.world.layer.traits.IBOPAreaTransformer0;
import biomesoplenty.common.world.layer.traits.IBOPContextExtended;
import net.minecraft.world.gen.area.AreaDimension;
public enum GenLayerTemperatureNoise implements IBOPAreaTransformer
public enum GenLayerTemperatureNoise implements IBOPAreaTransformer0
{
SMALL_ZONES(0.14D),
MEDIUM_ZONES(0.08D),

View file

@ -0,0 +1,24 @@
/*******************************************************************************
* Copyright 2014-2019, the Biomes O' Plenty Team
*
* This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivatives 4.0 International Public License.
*
* To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/4.0/.
******************************************************************************/
package biomesoplenty.common.world.layer;
import biomesoplenty.common.world.layer.traits.IBOPAreaTransformer0;
import biomesoplenty.common.world.layer.traits.IBOPContextExtended;
import net.minecraft.util.math.MathHelper;
import net.minecraft.world.gen.area.AreaDimension;
public enum GenLayerTemperatureRandom implements IBOPAreaTransformer0
{
INSTANCE;
@Override
public int apply(IBOPContextExtended context, AreaDimension areaDimension, int x, int z)
{
return context.random(9);
}
}

View file

@ -12,7 +12,11 @@ import net.minecraft.world.gen.area.AreaDimension;
import net.minecraft.world.gen.area.IArea;
import net.minecraft.world.gen.area.IAreaFactory;
public interface IBOPAreaTransformer
/***
* An area transformer that takes 0 existing AreaDimensions. Classes implementing
* this interface are not required to implement any further Transformer interfaces.
*/
public interface IBOPAreaTransformer0
{
default <R extends IArea> IAreaFactory<R> apply(IContextExtended<R> context)
{

View file

@ -10,6 +10,9 @@ package biomesoplenty.common.world.layer.traits;
import net.minecraft.world.gen.IContextExtended;
import net.minecraft.world.gen.area.IArea;
/***
* Provides extra information beyond that used by Mojang.
*/
public interface IBOPContextExtended<R extends IArea> extends IContextExtended<R>
{
long getWorldSeed();