Decompiled source of Clearer Weather v1.0.0

plugins/MoreClearWeather/MoreClearWeather.dll

Decompiled 7 hours ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Reflection;
using System.Reflection.Emit;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: AssemblyTitle("Clearer Weather")]
[assembly: AssemblyCompany("JPValheim")]
[assembly: AssemblyProduct("Clearer Weather")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0")]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: InternalsVisibleTo("MoreClearWeather.Tests")]
[assembly: AssemblyVersion("1.0.0.0")]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace MoreClearWeather
{
	[BepInPlugin("JPValheim.MoreClearWeather", "Clearer Weather", "1.0.0")]
	public sealed class Plugin : BaseUnityPlugin
	{
		public const string Id = "JPValheim.MoreClearWeather";

		internal static WeatherSettings Settings;

		internal static ManualLogSource Log;

		private Harmony harmony;

		private void Awake()
		{
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			//IL_002b: Expected O, but got Unknown
			Log = ((BaseUnityPlugin)this).Logger;
			Settings = new WeatherSettings(((BaseUnityPlugin)this).Config);
			harmony = new Harmony("JPValheim.MoreClearWeather");
			try
			{
				harmony.PatchAll(typeof(WeatherPatch).Assembly);
				((BaseUnityPlugin)this).Logger.LogInfo((object)"Clearer Weather 1.0.0 loaded.");
			}
			catch (Exception ex)
			{
				harmony.UnpatchSelf();
				((BaseUnityPlugin)this).Logger.LogError((object)("Clearer Weather could not patch this game build. Vanilla weather remains active. " + ex));
			}
		}

		private void OnDestroy()
		{
			Harmony obj = harmony;
			if (obj != null)
			{
				obj.UnpatchSelf();
			}
			Settings = null;
			Weather.ClearWarnings();
		}
	}
	internal sealed class SettingsBindings
	{
		internal readonly ConfigFile Config;

		private readonly HashSet<ConfigDefinition> existing;

		internal SettingsBindings(ConfigFile config)
		{
			//IL_00c3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cd: Expected O, but got Unknown
			Config = config;
			existing = new HashSet<ConfigDefinition>(config.Keys);
			if (!File.Exists(config.ConfigFilePath))
			{
				return;
			}
			string text = "";
			string[] array = File.ReadAllLines(config.ConfigFilePath);
			for (int i = 0; i < array.Length; i++)
			{
				string text2 = array[i].Trim();
				if (text2.Length != 0 && !text2.StartsWith("#"))
				{
					if (text2.StartsWith("[") && text2.EndsWith("]"))
					{
						text = text2.Substring(1, text2.Length - 2).Trim();
					}
					else if (text2.IndexOf('=') > 0 && text.Length > 0)
					{
						existing.Add(new ConfigDefinition(text, text2.Substring(0, text2.IndexOf('=')).Trim()));
					}
				}
			}
		}

		internal ConfigEntry<int> Chance(string section, string name, string oldName, int value, string description)
		{
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			//IL_001a: Expected O, but got Unknown
			//IL_003e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0048: Expected O, but got Unknown
			ConfigEntry<int> val = WeatherSettings.Chance(Config, section, name, value, description);
			ConfigDefinition val2 = new ConfigDefinition(section, oldName);
			if (!existing.Contains(val2))
			{
				return val;
			}
			ConfigEntry<int> val3 = Config.Bind<int>(val2, value, new ConfigDescription("", (AcceptableValueBase)null, Array.Empty<object>()));
			if (!existing.Contains(((ConfigEntryBase)val).Definition))
			{
				val.Value = val3.Value;
			}
			Config.Remove(val2);
			return val;
		}

		internal void MigrateAppearance(string section, ConfigEntry<WeatherStyle> style, ConfigEntry<string> custom)
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_000c: Expected O, but got Unknown
			//IL_0032: Unknown result type (might be due to invalid IL or missing references)
			//IL_003c: Expected O, but got Unknown
			ConfigDefinition val = new ConfigDefinition(section, "Clear environment");
			if (existing.Contains(val))
			{
				ConfigEntry<string> val2 = Config.Bind<string>(val, "", new ConfigDescription("", (AcceptableValueBase)null, Array.Empty<object>()));
				WeatherStyle weatherStyle = AppearanceSettings.FromEnvironment(val2.Value);
				if (!existing.Contains(((ConfigEntryBase)style).Definition))
				{
					style.Value = weatherStyle;
				}
				if (weatherStyle == WeatherStyle.Custom && !existing.Contains(((ConfigEntryBase)custom).Definition))
				{
					custom.Value = val2.Value;
				}
				Config.Remove(val);
			}
		}
	}
	internal static class Weather
	{
		private static readonly Dictionary<string, string> Warnings = new Dictionary<string, string>();

		internal static EnvSetup Replace(EnvSetup original, EnvMan manager, long seconds, BiomeSector biome)
		{
			//IL_0076: Unknown result type (might be due to invalid IL or missing references)
			//IL_0080: Expected I4, but got Unknown
			//IL_0084: Unknown result type (might be due to invalid IL or missing references)
			WeatherSettings settings = Plugin.Settings;
			if (settings == null || !settings.Enabled.Value || original == null || manager.m_environmentDuration <= 0 || ((Object)(object)ZNet.instance != (Object)null && ZNet.instance.IsDedicated()))
			{
				return original;
			}
			double sourceShare = SourceShare(manager.GetAvailableEnvironments(biome), original.m_name);
			double roll = WeatherPolicy.Roll(seconds / manager.m_environmentDuration, (int)biome.Biome);
			string name = WeatherPolicy.Choose(settings, biome.Biome, original.m_name, sourceShare, roll, delegate(string message)
			{
				WarnOnce("chance/" + original.m_name, message);
			})?.Trim();
			if (string.IsNullOrEmpty(name) || name == original.m_name)
			{
				return original;
			}
			EnvSetup val = manager.m_environments.Find((EnvSetup env) => env.m_name == name);
			if (val == null)
			{
				WarnOnce("missing/" + ((object)Unsafe.As<Biome, Biome>(ref biome.Biome)/*cast due to .constrained prefix*/).ToString(), "Environment '" + name + "' is unavailable in " + ((object)Unsafe.As<Biome, Biome>(ref biome.Biome)/*cast due to .constrained prefix*/).ToString() + ". Keeping original weather. Check Clear weather style or Custom environment name.");
				return original;
			}
			return CopyAppearance(original, val);
		}

		private static void WarnOnce(string key, string message)
		{
			if (!Warnings.TryGetValue(key, out var value) || !(value == message))
			{
				Warnings[key] = message;
				ManualLogSource log = Plugin.Log;
				if (log != null)
				{
					log.LogWarning((object)message);
				}
			}
		}

		internal static void ClearWarnings()
		{
			Warnings.Clear();
		}

		internal static double SourceShare(List<EnvEntry> environments, string source)
		{
			double num = 0.0;
			double num2 = 0.0;
			if (environments == null)
			{
				return 0.0;
			}
			foreach (EnvEntry environment in environments)
			{
				if (!environment.m_ashlandsOverride && !environment.m_deepnorthOverride && !(environment.m_weight <= 0f) && !float.IsNaN(environment.m_weight) && !float.IsInfinity(environment.m_weight))
				{
					num += (double)environment.m_weight;
					if ((environment.m_env?.m_name ?? environment.m_environment) == source)
					{
						num2 += (double)environment.m_weight;
					}
				}
			}
			if (!(num > 0.0))
			{
				return 0.0;
			}
			return num2 / num;
		}

		internal static EnvSetup CopyAppearance(EnvSetup original, EnvSetup appearance)
		{
			EnvSetup obj = appearance.Clone();
			obj.m_name = "MoreClearWeather:" + original.m_name + ":" + appearance.m_name;
			obj.m_windMin = original.m_windMin;
			obj.m_windMax = original.m_windMax;
			return obj;
		}
	}
	[HarmonyPatch(typeof(EnvMan), "UpdateEnvironment", new Type[]
	{
		typeof(long),
		typeof(BiomeSector)
	})]
	internal static class WeatherPatch
	{
		internal static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instructions)
		{
			//IL_00c6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cd: Expected O, but got Unknown
			//IL_00f3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f9: Expected O, but got Unknown
			//IL_0101: Unknown result type (might be due to invalid IL or missing references)
			//IL_0107: Expected O, but got Unknown
			//IL_010f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0115: Expected O, but got Unknown
			List<CodeInstruction> list = new List<CodeInstruction>(instructions);
			MethodInfo queue = typeof(EnvMan).GetMethod("QueueEnvironment", BindingFlags.Instance | BindingFlags.NonPublic, null, new Type[1] { typeof(EnvSetup) }, null);
			MethodInfo method = typeof(Weather).GetMethod("Replace", BindingFlags.Static | BindingFlags.NonPublic);
			if (queue == null || method == null)
			{
				throw new InvalidOperationException("Required weather methods are unavailable; weather patch was not applied.");
			}
			List<CodeInstruction> list2 = list.FindAll((CodeInstruction instruction) => CodeInstructionExtensions.Calls(instruction, queue));
			if (list2.Count != 1 || list2[0].blocks.Count != 0)
			{
				throw new InvalidOperationException("Expected one ordinary-weather queue call; weather patch was not applied.");
			}
			int index = list.IndexOf(list2[0]);
			CodeInstruction val = new CodeInstruction(OpCodes.Ldarg_0, (object)null);
			CodeInstructionExtensions.MoveLabelsTo(list[index], val);
			list.InsertRange(index, (IEnumerable<CodeInstruction>)(object)new CodeInstruction[4]
			{
				val,
				new CodeInstruction(OpCodes.Ldarg_1, (object)null),
				new CodeInstruction(OpCodes.Ldarg_2, (object)null),
				new CodeInstruction(OpCodes.Call, (object)method)
			});
			return list;
		}
	}
	internal static class WeatherPolicy
	{
		internal static double Roll(long period, int biome)
		{
			long num = period + -7046029254386353131L + (uint)biome * -3335678366873096957L;
			long num2 = (num ^ (num >>> 30)) * -4658895280553007687L;
			long num3 = (num2 ^ (num2 >>> 27)) * -7723592293110705685L;
			return (double)((ulong)(num3 ^ (num3 >>> 31)) >> 11) * 1.1102230246251565E-16;
		}

		internal static int Pick(double roll, double sourceShare, int first, int second = 0)
		{
			if (sourceShare <= 0.0 || first + second == 0)
			{
				return 0;
			}
			double num = Math.Max(sourceShare, (double)(first + second) / 100.0);
			if (roll < (double)first / 100.0 / num)
			{
				return 1;
			}
			if (!(roll < (double)(first + second) / 100.0 / num))
			{
				return 0;
			}
			return 2;
		}

		internal static string Choose(WeatherSettings settings, Biome biome, string original, double sourceShare, double roll, Action<string> warning = null)
		{
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_0090: Unknown result type (might be due to invalid IL or missing references)
			//IL_0095: Unknown result type (might be due to invalid IL or missing references)
			//IL_0096: Unknown result type (might be due to invalid IL or missing references)
			//IL_0098: Invalid comparison between Unknown and I4
			//IL_00a7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00aa: Invalid comparison between Unknown and I4
			//IL_009a: Unknown result type (might be due to invalid IL or missing references)
			//IL_009c: Invalid comparison between Unknown and I4
			//IL_00af: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b2: Invalid comparison between Unknown and I4
			//IL_009e: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a0: Invalid comparison between Unknown and I4
			//IL_00b7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bd: Invalid comparison between Unknown and I4
			if (!settings.IsEnabled(biome, original))
			{
				return null;
			}
			bool sea = original == "Ashlands_SeaStorm";
			if (sea)
			{
				sourceShare = 1.0;
			}
			if (sea)
			{
				return Select(settings.SeaStorm.Value, null, settings.SeaClear.Value, settings.SeaEnvironment, "Ashlands_ashrain");
			}
			Biome val = biome;
			if ((int)val <= 4)
			{
				if ((int)val != 2)
				{
					if ((int)val == 4 && original == "Snow")
					{
						return Select(settings.MountainClear.Value, settings.MountainWeather.Environment);
					}
				}
				else if (original == "SwampRain")
				{
					return Select(settings.SwampClear.Value, settings.SwampWeather.Environment, settings.SwampFog.Value, "Misty");
				}
			}
			else if ((int)val != 16)
			{
				if ((int)val != 32)
				{
					if ((int)val == 512 && original == "Mistlands_clear")
					{
						return Select(settings.MistlandsClear.Value, settings.MistlandsWeather.Environment);
					}
				}
				else if (original == "Ashlands_ashrain")
				{
					return Select(settings.AshlandsClear.Value, settings.AshlandsWeather.Environment);
				}
			}
			else if (original == "Heath clear")
			{
				return Select(settings.PlainsRain.Value, "Rain", settings.PlainsStorm.Value, "ThunderStorm");
			}
			return null;
			unsafe string Select(int first, string firstWeather, int second = 0, string secondWeather = null, string remainder = null)
			{
				//IL_0048: Unknown result type (might be due to invalid IL or missing references)
				//IL_004f: Invalid comparison between Unknown and I4
				//IL_0070: Unknown result type (might be due to invalid IL or missing references)
				//IL_0077: Invalid comparison between Unknown and I4
				if ((double)(first + second) > sourceShare * 100.0 && warning != null)
				{
					double num = sourceShare * 100.0 / (double)(first + second);
					string text = (sea ? "storm" : (((int)biome == 16) ? "added rain" : "clear"));
					string text2 = (sea ? "clear" : (((int)biome == 16) ? "thunderstorm" : "fog"));
					string text3 = ((object)(*(Biome*)(&biome))/*cast due to .constrained prefix*/).ToString() + ": effective " + text + " chance = " + ((double)first * num).ToString("0.##", CultureInfo.InvariantCulture) + "%";
					if (second > 0)
					{
						text3 = text3 + ", " + text2 + " chance = " + ((double)second * num).ToString("0.##", CultureInfo.InvariantCulture) + "%";
					}
					warning(text3 + ". Requested chances exceed the weather available to replace.");
				}
				return Pick(roll, sourceShare, first, second) switch
				{
					2 => secondWeather, 
					1 => firstWeather, 
					_ => remainder, 
				};
			}
		}
	}
	public enum WeatherStyle
	{
		Sunny,
		Forest,
		Golden,
		Northern,
		Custom
	}
	public enum OceanWeatherStyle
	{
		UseAshlands = -1,
		Sunny,
		Forest,
		Golden,
		Northern,
		Custom
	}
	internal sealed class WeatherSettings
	{
		internal readonly ConfigEntry<bool> Enabled;

		internal readonly ConfigEntry<bool> SwampEnabled;

		internal readonly ConfigEntry<bool> MountainEnabled;

		internal readonly ConfigEntry<bool> AshlandsEnabled;

		internal readonly ConfigEntry<bool> SeaEnabled;

		internal readonly ConfigEntry<bool> PlainsEnabled;

		internal readonly ConfigEntry<bool> MistlandsEnabled;

		internal readonly ConfigEntry<int> SwampClear;

		internal readonly ConfigEntry<int> SwampFog;

		internal readonly ConfigEntry<int> MountainClear;

		internal readonly ConfigEntry<int> AshlandsClear;

		internal readonly ConfigEntry<int> SeaStorm;

		internal readonly ConfigEntry<int> SeaClear;

		internal readonly ConfigEntry<int> PlainsRain;

		internal readonly ConfigEntry<int> PlainsStorm;

		internal readonly ConfigEntry<int> MistlandsClear;

		internal readonly AppearanceSettings SwampWeather;

		internal readonly AppearanceSettings MountainWeather;

		internal readonly AppearanceSettings AshlandsWeather;

		internal readonly AppearanceSettings MistlandsWeather;

		internal readonly ConfigEntry<OceanWeatherStyle> SeaStyle;

		internal readonly ConfigEntry<string> SeaCustom;

		internal string SeaEnvironment
		{
			get
			{
				if (SeaStyle.Value != OceanWeatherStyle.UseAshlands)
				{
					return AppearanceSettings.Resolve((WeatherStyle)SeaStyle.Value, SeaCustom.Value);
				}
				return AshlandsWeather.Environment;
			}
		}

		internal WeatherSettings(ConfigFile config)
		{
			SettingsBindings settingsBindings = new SettingsBindings(config);
			bool saveOnConfigSet = config.SaveOnConfigSet;
			config.SaveOnConfigSet = false;
			try
			{
				Enabled = config.Bind<bool>("General", "Enabled", true, "Enable weather changes. Restart after editing this file. Configuration-manager changes apply at the next normal weather selection. The original weather's wind range is kept.");
				SwampEnabled = Enable(config, "Swamp");
				SwampClear = Chance(config, "Swamp", "Clear chance (%)", 30, "Clear weather as a percentage of all normal weather selections. Replaces swamp rain; 0 disables added clear weather.");
				SwampFog = Chance(config, "Swamp", "Fog chance (%)", 5, "Fog as a percentage of normal weather selections. Also replaces swamp rain. If clear and fog exceed the rain available, both scale down; see LogOutput.log.");
				SwampWeather = new AppearanceSettings(settingsBindings, "Swamp", WeatherStyle.Sunny);
				MountainEnabled = Enable(config, "Mountains");
				MountainClear = Chance(config, "Mountains", "Clear chance (%)", 30, "Clear weather as a percentage of all normal weather selections. Replaces ordinary snow; blizzards stay unchanged. A high value uses all available ordinary snow.");
				MountainWeather = new AppearanceSettings(settingsBindings, "Mountains", WeatherStyle.Northern);
				AshlandsEnabled = Enable(config, "Ashlands");
				AshlandsClear = Chance(config, "Ashlands", "Clear chance (%)", 30, "Clear weather as a percentage of all normal weather selections. Replaces ordinary ash rain; other weather stays unchanged.");
				AshlandsWeather = new AppearanceSettings(settingsBindings, "Ashlands", WeatherStyle.Golden);
				SeaEnabled = Enable(config, "Ashlands Ocean");
				SeaStorm = Chance(config, "Ashlands Ocean", "Storm chance (%)", 50, "Sea-storm weather chance. Ash rain fills the chance left after storm and clear weather: 50 storm + 10 clear leaves 40 ash rain.");
				SeaClear = Chance(config, "Ashlands Ocean", "Clear chance (%)", 10, "Clear-weather chance. Storm and clear totals above 100 scale down together; see LogOutput.log. All three options keep the original sea-storm wind range.");
				SeaStyle = config.Bind<OceanWeatherStyle>("Ashlands Ocean", "Clear weather style", OceanWeatherStyle.UseAshlands, "UseAshlands follows the land's style. Sunny = bright; Forest = subdued; Golden = warm and hazy; Northern = freezing. Custom uses Custom environment name.");
				SeaCustom = AppearanceSettings.CustomName(config, "Ashlands Ocean");
				PlainsEnabled = Enable(config, "Plains");
				PlainsRain = settingsBindings.Chance("Plains", "Added rain chance (%)", "Rain chance (%)", 5, "Additional ordinary rain as a percentage of all weather selections. Replaces fair weather; existing light rain and fog stay unchanged.");
				PlainsStorm = Chance(config, "Plains", "Thunderstorm chance (%)", 2, "Additional thunderstorms as a percentage of normal weather selections. Also replaces fair weather. If added rain and thunderstorms exceed available fair weather, both scale down; see LogOutput.log.");
				MistlandsEnabled = Enable(config, "Mistlands");
				MistlandsClear = settingsBindings.Chance("Mistlands", "Alternative weather chance (%)", "Alternative clear chance (%)", 30, "Chance of the selected style across all weather selections. Replaces normal Mistlands fair weather; rain, thunderstorms and local mist stay unchanged.");
				MistlandsWeather = new AppearanceSettings(settingsBindings, "Mistlands", WeatherStyle.Forest);
			}
			finally
			{
				config.SaveOnConfigSet = saveOnConfigSet;
			}
			if (saveOnConfigSet)
			{
				config.Save();
			}
		}

		internal bool IsEnabled(Biome biome, string original)
		{
			//IL_0028: Unknown result type (might be due to invalid IL or missing references)
			//IL_002a: Invalid comparison between Unknown and I4
			//IL_0036: Unknown result type (might be due to invalid IL or missing references)
			//IL_0039: Invalid comparison between Unknown and I4
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			//IL_002e: Invalid comparison between Unknown and I4
			//IL_003b: Unknown result type (might be due to invalid IL or missing references)
			//IL_003e: Invalid comparison between Unknown and I4
			//IL_0030: Unknown result type (might be due to invalid IL or missing references)
			//IL_0032: Invalid comparison between Unknown and I4
			//IL_0040: Unknown result type (might be due to invalid IL or missing references)
			//IL_0046: Invalid comparison between Unknown and I4
			if (!Enabled.Value)
			{
				return false;
			}
			if (original == "Ashlands_SeaStorm")
			{
				return SeaEnabled.Value;
			}
			if ((int)biome <= 4)
			{
				if ((int)biome == 2)
				{
					return SwampEnabled.Value;
				}
				if ((int)biome == 4)
				{
					return MountainEnabled.Value;
				}
			}
			else
			{
				if ((int)biome == 16)
				{
					return PlainsEnabled.Value;
				}
				if ((int)biome == 32)
				{
					return AshlandsEnabled.Value;
				}
				if ((int)biome == 512)
				{
					return MistlandsEnabled.Value;
				}
			}
			return false;
		}

		private static ConfigEntry<bool> Enable(ConfigFile config, string section)
		{
			return config.Bind<bool>(section, "Enabled", true, "Enable this biome's weather changes. False restores its normal weather without changing your other settings.");
		}

		internal static ConfigEntry<int> Chance(ConfigFile config, string section, string name, int value, string description)
		{
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			//IL_001d: Expected O, but got Unknown
			return config.Bind<int>(section, name, value, new ConfigDescription(description, (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 100), Array.Empty<object>()));
		}
	}
	internal sealed class AppearanceSettings
	{
		internal readonly ConfigEntry<WeatherStyle> Style;

		internal readonly ConfigEntry<string> Custom;

		internal string Environment => Resolve(Style.Value, Custom.Value);

		internal AppearanceSettings(SettingsBindings bindings, string section, WeatherStyle defaultStyle)
		{
			Style = bindings.Config.Bind<WeatherStyle>(section, "Clear weather style", defaultStyle, "Sunny = bright sunlight; Forest = subdued woodland light; Golden = warm, hazy sunlight; Northern = clear and freezing. Custom uses Custom environment name. The original wind range is kept.");
			Custom = CustomName(bindings.Config, section);
			bindings.MigrateAppearance(section, Style, Custom);
		}

		internal static ConfigEntry<string> CustomName(ConfigFile config, string section)
		{
			return config.Bind<string>(section, "Custom environment name", "", "Used only when the style is Custom. Enter an exact Valheim or modded environment name. A blank or unknown name keeps the original weather.");
		}

		internal static string Resolve(WeatherStyle style, string custom)
		{
			return style switch
			{
				WeatherStyle.Sunny => "Clear", 
				WeatherStyle.Forest => "DeepForest Mist", 
				WeatherStyle.Golden => "Heath clear", 
				WeatherStyle.Northern => "Twilight_Clear", 
				_ => custom, 
			};
		}

		internal static WeatherStyle FromEnvironment(string name)
		{
			WeatherStyle[] array = new WeatherStyle[4]
			{
				WeatherStyle.Sunny,
				WeatherStyle.Forest,
				WeatherStyle.Golden,
				WeatherStyle.Northern
			};
			foreach (WeatherStyle weatherStyle in array)
			{
				if (Resolve(weatherStyle, "") == name?.Trim())
				{
					return weatherStyle;
				}
			}
			return WeatherStyle.Custom;
		}
	}
}