Skip to content

Commit

Permalink
Added support for configuring seasonal biome temp/rain/thunder adjust…
Browse files Browse the repository at this point in the history
…ment
  • Loading branch information
Adubbz committed Jan 20, 2024
1 parent 83bbb3a commit 96524df
Show file tree
Hide file tree
Showing 3 changed files with 126 additions and 161 deletions.
225 changes: 110 additions & 115 deletions common/src/main/java/sereneseasons/config/SeasonsConfig.java
Original file line number Diff line number Diff line change
Expand Up @@ -6,60 +6,50 @@

import com.electronwill.nightconfig.core.Config;
import com.electronwill.nightconfig.core.InMemoryFormat;
import com.google.common.base.Preconditions;
import com.google.common.base.Suppliers;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import glitchcore.util.Environment;
import net.minecraft.resources.ResourceKey;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.util.valueproviders.IntProvider;
import net.minecraft.util.valueproviders.UniformInt;
import net.minecraft.world.level.Level;
import sereneseasons.api.season.Season;
import sereneseasons.core.SereneSeasons;

import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.*;
import java.util.function.Predicate;
import java.util.function.Supplier;
import java.util.stream.Collectors;

import static net.minecraft.server.level.ServerLevel.RAIN_DELAY;

public class SeasonsConfig extends glitchcore.config.Config
{
// Weather settings
public boolean generateSnowAndIce;
public boolean changeWeatherFrequency;

// Time settings
public int dayDuration;
public int subSeasonDuration;
public int startingSubSeason;
public boolean progressSeasonWhileOffline;

// Aesthetic settings
public boolean changeGrassColor;
public boolean changeFoliageColor;
public boolean changeBirchColor;

// Dimension settings
public static List<String> whitelistedDimensions;
private static List<String> defaultWhitelistedDimensions = Lists.newArrayList(Level.OVERWORLD.location().toString());

// Snow melting settings
private static List<Config> meltChanceEntries;
private static List<Config> defaultMeltChances = Lists.newArrayList(
new MeltChanceInfo(Season.SubSeason.EARLY_WINTER, 0.0F, 0),
new MeltChanceInfo(Season.SubSeason.MID_WINTER, 0.0F, 0),
new MeltChanceInfo(Season.SubSeason.LATE_WINTER, 0.0F, 0),
new MeltChanceInfo(Season.SubSeason.EARLY_SPRING, 6.25F, 1),
new MeltChanceInfo(Season.SubSeason.MID_SPRING, 8.33F, 1),
new MeltChanceInfo(Season.SubSeason.LATE_SPRING, 12.5F, 1),
new MeltChanceInfo(Season.SubSeason.EARLY_SUMMER, 25.0F, 1),
new MeltChanceInfo(Season.SubSeason.MID_SUMMER, 25.0F, 1),
new MeltChanceInfo(Season.SubSeason.LATE_SUMMER, 25.0F, 1),
new MeltChanceInfo(Season.SubSeason.EARLY_AUTUMN, 12.5F, 1),
new MeltChanceInfo(Season.SubSeason.MID_AUTUMN, 8.33F, 1),
new MeltChanceInfo(Season.SubSeason.LATE_AUTUMN, 6.25F, 1)
).stream().map(SeasonsConfig::meltChanceInfoToConfig).collect(Collectors.toList());
// From ServerLevel
private static final IntProvider THUNDER_DELAY = UniformInt.of(12000, 180000);

private static final Predicate<List<Config>> SEASON_PROPERTIES_VALIDATOR = (configs) -> configs.stream().allMatch(c -> SeasonProperties.decode(c).isPresent());

private static final Map<Season.SubSeason, SeasonProperties> DEFAULT_SEASON_PROPERTIES = Lists.newArrayList(
new SeasonProperties(Season.SubSeason.EARLY_WINTER, 0.0F, 0, -0.8F, 12000, 36000, -1, -1),
new SeasonProperties(Season.SubSeason.MID_WINTER, 0.0F, 0, -0.8F, 12000, 36000, -1, -1),
new SeasonProperties(Season.SubSeason.LATE_WINTER, 0.0F, 0, -0.8F, 12000, 36000, -1, -1),
new SeasonProperties(Season.SubSeason.EARLY_SPRING, 6.25F, 1, -0.4F, 96000, 12000, THUNDER_DELAY.getMinValue(), THUNDER_DELAY.getMaxValue()),
new SeasonProperties(Season.SubSeason.MID_SPRING, 8.33F, 1, -0.2F, 96000, 12000, THUNDER_DELAY.getMinValue(), THUNDER_DELAY.getMaxValue()),
new SeasonProperties(Season.SubSeason.LATE_SPRING, 12.5F, 1, -0.1F, 96000, 12000, THUNDER_DELAY.getMinValue(), THUNDER_DELAY.getMaxValue()),
new SeasonProperties(Season.SubSeason.EARLY_SUMMER, 25.0F, 1, 0.0F, 12000, 96000, THUNDER_DELAY.getMinValue(), THUNDER_DELAY.getMaxValue()),
new SeasonProperties(Season.SubSeason.MID_SUMMER, 25.0F, 1, 0.0F, 12000, 96000, THUNDER_DELAY.getMinValue(), THUNDER_DELAY.getMaxValue()),
new SeasonProperties(Season.SubSeason.LATE_SUMMER, 25.0F, 1, 0.0F, 12000, 96000, THUNDER_DELAY.getMinValue(), THUNDER_DELAY.getMaxValue()),
new SeasonProperties(Season.SubSeason.EARLY_AUTUMN, 12.5F, 1, -0.1F, RAIN_DELAY.getMinValue(), RAIN_DELAY.getMaxValue(), THUNDER_DELAY.getMinValue(), THUNDER_DELAY.getMaxValue()),
new SeasonProperties(Season.SubSeason.MID_AUTUMN, 8.33F, 1, -0.2F, RAIN_DELAY.getMinValue(), RAIN_DELAY.getMaxValue(), THUNDER_DELAY.getMinValue(), THUNDER_DELAY.getMaxValue()),
new SeasonProperties(Season.SubSeason.LATE_AUTUMN, 6.25F, 1, -0.4F, RAIN_DELAY.getMinValue(), RAIN_DELAY.getMaxValue(), THUNDER_DELAY.getMinValue(), THUNDER_DELAY.getMaxValue())
).stream().collect(Collectors.toMap(SeasonProperties::subSeason, v -> v));

private static final Predicate<List<String>> RESOURCE_LOCATION_VALIDATOR = (list) ->
{
Expand All @@ -78,34 +68,30 @@ public class SeasonsConfig extends glitchcore.config.Config
return true;
};

private static final Predicate<List<Config>> MELT_INFO_VALIDATOR = (configs) ->
{
for (Config config : configs)
{
// Ensure config contains required values
if (!config.contains("season")) return false;
if (!config.contains("melt_percent")) return false;
if (!config.contains("rolls")) return false;
// Weather settings
public boolean generateSnowAndIce;
public boolean changeWeatherFrequency;

try
{
// Validate season.
config.getEnum("season", Season.SubSeason.class);
// Time settings
public int dayDuration;
public int subSeasonDuration;
public int startingSubSeason;
public boolean progressSeasonWhileOffline;

// Validate melt chance is within range.
float meltChance = config.<Number>get("melt_percent").floatValue();
if(meltChance < 0.0F || meltChance > 100.0F) return false;
// Validate rolls is positive.
if(config.getInt("rolls") < 0) return false;
}
catch (Exception e)
{
return false;
}
}
// Aesthetic settings
public boolean changeGrassColor;
public boolean changeFoliageColor;
public boolean changeBirchColor;

// Dimension settings
public List<String> whitelistedDimensions;
private static final List<String> defaultWhitelistedDimensions = Lists.newArrayList(Level.OVERWORLD.location().toString());

// Snow melting settings
private List<Config> seasonProperties;

private Supplier<ImmutableMap<Season.SubSeason, SeasonProperties>> seasonPropertiesMapper;

return true;
};

public SeasonsConfig()
{
Expand All @@ -129,11 +115,23 @@ public void load()

whitelistedDimensions = add("dimension_settings.whitelisted_dimensions", defaultWhitelistedDimensions, "Seasons will only apply to dimensons listed here", RESOURCE_LOCATION_VALIDATOR);

meltChanceEntries = add("melting_settings.season_melt_chances", defaultMeltChances, """
The melting settings for snow and ice in each season. The game must be restarted for these to apply.
final List<Config> defaultProperties = DEFAULT_SEASON_PROPERTIES.values().stream().map(SeasonProperties::encode).toList();
seasonProperties = add("season_properties", defaultProperties, """
melt_percent is the 0-1 percentage chance a snow or ice block will melt when chosen. (e.g. 100.0 = 100%, 50.0 = 50%)
rolls is the number of blocks randomly picked in each chunk, each tick. (High number rolls is not recommended on servers)
rolls should be 0 if blocks should not melt in that season.""", MELT_INFO_VALIDATOR);
melt_rolls is the number of blocks randomly picked in each chunk, each tick. (High number rolls is not recommended on servers)
melt_rolls should be 0 if blocks should not melt in that season.
biome_temp_adjustment is the amount to adjust the biome temperature by from -10.0 to 10.0.
min_rain_time is the minimum time interval between rain events in ticks. Set to -1 to disable rain.
max_rain_time is the maximum time interval between rain events in ticks. Set to -1 to disable rain.
min_thunder_time is the minimum time interval between thunder events in ticks. Set to -1 to disable thunder.
max_thunder_time is the maximum time interval between thunder events in ticks. Set to -1 to disable thunder.""", SEASON_PROPERTIES_VALIDATOR);

seasonPropertiesMapper = Suppliers.memoize(() -> {
var builder = ImmutableMap.<Season.SubSeason, SeasonProperties>builder();
builder.putAll(DEFAULT_SEASON_PROPERTIES);
seasonProperties.stream().map(SeasonProperties::decode).forEach(o -> o.ifPresent(v -> builder.put(v.subSeason(), v)));
return builder.build();
});
}

public boolean isDimensionWhitelisted(ResourceKey<Level> dimension)
Expand All @@ -149,69 +147,66 @@ public boolean isDimensionWhitelisted(ResourceKey<Level> dimension)
return false;
}

private static Config meltChanceInfoToConfig(MeltChanceInfo meltChanceInfo)
{
Config config = Config.of(LinkedHashMap::new, InMemoryFormat.withUniversalSupport());
config.add("season", meltChanceInfo.getSubSeason().toString());
config.add("melt_percent", meltChanceInfo.getMeltChance());
config.add("rolls", meltChanceInfo.getRolls());
return config;
}

private static ImmutableMap<Season.SubSeason, MeltChanceInfo> meltInfoCache;

@Nullable
public MeltChanceInfo getMeltInfo(Season.SubSeason season)
{
return getMeltInfos().get(season);
}

private ImmutableMap<Season.SubSeason, MeltChanceInfo> getMeltInfos()
public SeasonProperties getSeasonProperties(Season.SubSeason season)
{
if (meltInfoCache != null) return meltInfoCache;

Map<Season.SubSeason, MeltChanceInfo> tmp = Maps.newHashMap();

for (Config config : meltChanceEntries)
{
Season.SubSeason subSeason = config.getEnum("season", Season.SubSeason.class);
float meltChance = config.<Number>get("melt_percent").floatValue();
int rolls = config.getInt("rolls");

tmp.put(subSeason, new MeltChanceInfo(subSeason, meltChance, rolls));
}

meltInfoCache = ImmutableMap.copyOf(tmp);
return meltInfoCache;
return seasonPropertiesMapper.get().get(season);
}

public static class MeltChanceInfo
public record SeasonProperties(Season.SubSeason subSeason, float meltChance, int meltRolls, float biomeTempAdjustment, int minRainTime, int maxRainTime, int minThunderTime, int maxThunderTime)
{
private final Season.SubSeason subSeason;
private final float meltChance;
private final int rolls;

private MeltChanceInfo(Season.SubSeason subSeason, float meltChance, int rolls)
public Config encode()
{
this.subSeason = subSeason;
this.meltChance = meltChance;
this.rolls = rolls;
Config config = Config.of(LinkedHashMap::new, InMemoryFormat.withUniversalSupport());
config.add("season", this.subSeason.toString());
config.add("melt_percent", this.meltChance);
config.add("melt_rolls", this.meltRolls);
config.add("biome_temp_adjustment", this.biomeTempAdjustment);
config.add("min_rain_time", this.minRainTime);
config.add("max_rain_time", this.maxRainTime);
config.add("min_thunder_time", this.minThunderTime);
config.add("max_thunder_time", this.maxThunderTime);
return config;
}

public Season.SubSeason getSubSeason()
public static Optional<SeasonProperties> decode(Config config)
{
return subSeason;
try
{
Season.SubSeason subSeason = config.getEnum("season", Season.SubSeason.class);
float meltChance = config.<Number>get("melt_percent").floatValue();
int rolls = config.getInt("melt_rolls");
float biomeTempAdjustment = config.<Number>get("biome_temp_adjustment").floatValue();
int minRainTime = config.getInt("min_rain_time");
int maxRainTime = config.getInt("max_rain_time");
int minThunderTime = config.getInt("min_thunder_time");
int maxThunderTime = config.getInt("max_thunder_time");

Preconditions.checkArgument(meltChance < 0.0F || meltChance > 100.0F);
Preconditions.checkArgument(rolls >= 0);
Preconditions.checkArgument(biomeTempAdjustment >= -10.0 && biomeTempAdjustment <= 10.0);

return Optional.of(new SeasonProperties(subSeason, meltChance, rolls, biomeTempAdjustment, minRainTime, maxRainTime, minThunderTime, maxThunderTime));
}
catch (Exception e)
{
return Optional.empty();
}
}

public float getMeltChance()
public boolean canRain()
{
return meltChance;
return this.minRainTime != -1 && this.maxRainTime != -1;
}

public int getRolls()
public boolean canThunder()
{
return rolls;
return this.minThunderTime != -1 && this.maxThunderTime != -1;
}
}

static
{
Preconditions.checkState(DEFAULT_SEASON_PROPERTIES.keySet().containsAll(List.of(Season.SubSeason.values())));
}
}
40 changes: 15 additions & 25 deletions common/src/main/java/sereneseasons/season/RandomUpdateHandler.java
Original file line number Diff line number Diff line change
Expand Up @@ -32,41 +32,31 @@

public class RandomUpdateHandler
{
private static void adjustWeatherFrequency(Level world, Season season)
private static void adjustWeatherFrequency(Level world, Season.SubSeason subSeason)
{
if (!ModConfig.seasons.changeWeatherFrequency)
return;

ServerLevelData serverLevelData = (ServerLevelData)world.getLevelData();
SeasonsConfig.SeasonProperties seasonProperties = ModConfig.seasons.getSeasonProperties(subSeason);

if (season == Season.WINTER)
if (seasonProperties.canRain())
{
if (serverLevelData.isThundering())
if (!world.getLevelData().isRaining() && serverLevelData.getRainTime() > seasonProperties.maxRainTime())
{
serverLevelData.setThundering(false);
}
if (!world.getLevelData().isRaining() && serverLevelData.getRainTime() > 36000)
{
serverLevelData.setRainTime(world.random.nextInt(24000) + 12000);
serverLevelData.setRainTime(world.random.nextInt(seasonProperties.maxRainTime() - seasonProperties.minRainTime()) + seasonProperties.minRainTime());
}
}
else
else if (serverLevelData.isRaining()) serverLevelData.setRaining(false);

if (seasonProperties.canThunder())
{
if (season == Season.SPRING)
if (!world.getLevelData().isThundering() && serverLevelData.getThunderTime() > seasonProperties.maxThunderTime())
{
if (!world.getLevelData().isRaining() && serverLevelData.getRainTime() > 96000)
{
serverLevelData.setRainTime(world.random.nextInt(84000) + 12000);
}
}
else if (season == Season.SUMMER)
{
if (!world.getLevelData().isThundering() && serverLevelData.getThunderTime() > 36000)
{
serverLevelData.setThunderTime(world.random.nextInt(24000) + 12000);
}
serverLevelData.setThunderTime(world.random.nextInt(seasonProperties.maxThunderTime() - seasonProperties.minThunderTime()) + seasonProperties.minThunderTime());
}
}
else if (serverLevelData.isThundering()) serverLevelData.setThundering(false);
}

private static void meltInChunk(ChunkMap chunkMap, LevelChunk chunkIn, float meltChance)
Expand Down Expand Up @@ -106,11 +96,11 @@ public static void onWorldTick(TickEvent.Level event)
Season.SubSeason subSeason = SeasonHelper.getSeasonState(level).getSubSeason();
Season season = subSeason.getSeason();

SeasonsConfig.MeltChanceInfo meltInfo = ModConfig.seasons.getMeltInfo(subSeason);
float meltRand = meltInfo.getMeltChance() / 100.0F;
int rolls = meltInfo.getRolls();
SeasonsConfig.SeasonProperties seasonProperties = ModConfig.seasons.getSeasonProperties(subSeason);
float meltRand = seasonProperties.meltChance() / 100.0F;
int rolls = seasonProperties.meltRolls();

adjustWeatherFrequency(level, season);
adjustWeatherFrequency(level, subSeason);

if(rolls > 0 && meltRand > 0.0F)
{
Expand Down
22 changes: 1 addition & 21 deletions common/src/main/java/sereneseasons/season/SeasonHooks.java
Original file line number Diff line number Diff line change
Expand Up @@ -137,27 +137,7 @@ public static float getBiomeTemperatureInSeason(Season.SubSeason subSeason, Hold
float biomeTemp = biome.value().getTemperature(pos);
if (!tropicalBiome && biome.value().getBaseTemperature() <= 0.8F && !biome.is(ModTags.Biomes.BLACKLISTED_BIOMES))
{
switch (subSeason)
{
default:
break;

case LATE_SPRING: case EARLY_AUTUMN:
biomeTemp = Mth.clamp(biomeTemp - 0.1F, -0.5F, 2.0F);
break;

case MID_SPRING: case MID_AUTUMN:
biomeTemp = Mth.clamp(biomeTemp - 0.2F, -0.5F, 2.0F);
break;

case EARLY_SPRING: case LATE_AUTUMN:
biomeTemp = Mth.clamp(biomeTemp - 0.4F, -0.5F, 2.0F);
break;

case EARLY_WINTER: case MID_WINTER: case LATE_WINTER:
biomeTemp = Mth.clamp(biomeTemp - 0.8F, -0.5F, 2.0F);
break;
}
biomeTemp = Mth.clamp(biomeTemp + ModConfig.seasons.getSeasonProperties(subSeason).biomeTempAdjustment(), -0.5F, 2.0F);
}

return biomeTemp;
Expand Down

0 comments on commit 96524df

Please sign in to comment.