Decompiled source of ValheimSeasons v1.3.0

ValheimSeasons.dll

Decompiled 12 hours ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using BepInEx;
using BepInEx.Bootstrap;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using UnityEngine;
using UnityEngine.Rendering;
using UnityEngine.SceneManagement;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: AssemblyVersion("0.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 ValheimSeasons
{
	internal static class Compat
	{
		private static MethodInfo _getCurrentDay;

		private static MethodInfo _getEnv;

		private static MethodInfo _getServerPeerId;

		private static bool _init;

		private static void Init()
		{
			if (!_init)
			{
				_init = true;
				_getCurrentDay = AccessTools.Method(typeof(EnvMan), "GetCurrentDay", Type.EmptyTypes, (Type[])null);
				_getEnv = AccessTools.Method(typeof(EnvMan), "GetEnv", new Type[1] { typeof(string) }, (Type[])null);
				_getServerPeerId = AccessTools.Method(typeof(ZRoutedRpc), "GetServerPeerID", Type.EmptyTypes, (Type[])null);
			}
		}

		internal static int CurrentDay()
		{
			Init();
			EnvMan instance = EnvMan.instance;
			if ((Object)(object)instance == (Object)null || (Object)(object)ZNet.instance == (Object)null)
			{
				return 0;
			}
			try
			{
				if (_getCurrentDay != null)
				{
					return (int)_getCurrentDay.Invoke(instance, null);
				}
			}
			catch
			{
			}
			double num = Math.Max(1.0, instance.m_dayLengthSec);
			return (int)(ZNet.instance.GetTimeSeconds() / num);
		}

		internal static EnvSetup GetEnv(string name)
		{
			Init();
			EnvMan instance = EnvMan.instance;
			if ((Object)(object)instance == (Object)null)
			{
				return null;
			}
			try
			{
				if (_getEnv != null)
				{
					object? obj = _getEnv.Invoke(instance, new object[1] { name });
					return (EnvSetup)((obj is EnvSetup) ? obj : null);
				}
			}
			catch
			{
			}
			if (AccessTools.Field(typeof(EnvMan), "m_environments")?.GetValue(instance) is List<EnvSetup> list)
			{
				foreach (EnvSetup item in list)
				{
					if (item != null && item.m_name == name)
					{
						return item;
					}
				}
			}
			return null;
		}

		internal static void ForceWeatherReroll()
		{
			EnvMan instance = EnvMan.instance;
			if ((Object)(object)instance == (Object)null)
			{
				return;
			}
			try
			{
				FieldInfo fieldInfo = AccessTools.Field(typeof(EnvMan), "m_environmentPeriod");
				if (!(fieldInfo == null))
				{
					fieldInfo.SetValue(instance, Convert.ChangeType(-1, fieldInfo.FieldType));
				}
			}
			catch
			{
			}
		}

		internal static long ServerPeerId()
		{
			Init();
			try
			{
				if (_getServerPeerId != null && ZRoutedRpc.instance != null)
				{
					return (long)_getServerPeerId.Invoke(ZRoutedRpc.instance, null);
				}
			}
			catch
			{
			}
			ZNet instance = ZNet.instance;
			return ((instance != null) ? instance.GetServerPeer() : null)?.m_uid ?? ZDOMan.GetSessionID();
		}
	}
	internal class CreatureRule
	{
		public string Key;

		public float Dmg = 1f;

		public float Spd = 1f;

		public float Hp = 1f;

		public float Spawn = 1f;

		public bool DayOnly;
	}
	internal static class CreatureSeasons
	{
		private class Speeds
		{
			public float[] Values;
		}

		private static string _src;

		private static List<CreatureRule> _rules = new List<CreatureRule>();

		private static readonly Dictionary<string, CreatureRule> _byName = new Dictionary<string, CreatureRule>();

		private static readonly Dictionary<int, string> _prefabOf = new Dictionary<int, string>();

		private static readonly ConditionalWeakTable<Character, Speeds> _orig = new ConditionalWeakTable<Character, Speeds>();

		private static readonly HashSet<Character> _touched = new HashSet<Character>();

		private static FieldInfo[] _speedFields;

		private static float _timer;

		private static FieldInfo[] SpeedFields
		{
			get
			{
				if (_speedFields != null)
				{
					return _speedFields;
				}
				List<FieldInfo> list = new List<FieldInfo>();
				string[] array = new string[7] { "m_speed", "m_walkSpeed", "m_runSpeed", "m_crouchSpeed", "m_swimSpeed", "m_flySlowSpeed", "m_flyFastSpeed" };
				foreach (string text in array)
				{
					FieldInfo fieldInfo = AccessTools.Field(typeof(Character), text);
					if (fieldInfo != null && fieldInfo.FieldType == typeof(float))
					{
						list.Add(fieldInfo);
					}
				}
				return _speedFields = list.ToArray();
			}
		}

		internal static string Source(Season s)
		{
			SeasonMechanics r = Mech.R;
			return s switch
			{
				Season.Spring => r.CreatureSpring, 
				Season.Summer => r.CreatureSummer, 
				Season.Fall => r.CreatureFall, 
				_ => r.CreatureWinter, 
			};
		}

		internal static List<CreatureRule> Rules()
		{
			string text = ((Mech.On && Mech.R.CreatureSeasons) ? (Source(Mech.S) ?? "") : "");
			if (text == _src)
			{
				return _rules;
			}
			_src = text;
			_rules = Parse(text);
			_byName.Clear();
			return _rules;
		}

		internal static List<CreatureRule> Parse(string src)
		{
			List<CreatureRule> list = new List<CreatureRule>();
			string[] array = (src ?? "").Split(',');
			foreach (string text in array)
			{
				int num = text.IndexOf(':');
				if (num <= 0)
				{
					continue;
				}
				CreatureRule creatureRule = new CreatureRule
				{
					Key = text.Substring(0, num).Trim().ToLowerInvariant()
				};
				if (creatureRule.Key.Length == 0)
				{
					continue;
				}
				string[] array2 = text.Substring(num + 1).Split(new char[3] { ' ', ';', '|' }, StringSplitOptions.RemoveEmptyEntries);
				for (int j = 0; j < array2.Length; j++)
				{
					string text2 = array2[j].Trim().ToLowerInvariant();
					float v;
					if (text2 == "dia" || text2 == "day")
					{
						creatureRule.DayOnly = true;
					}
					else if (Tok(text2, "dano", out v) || Tok(text2, "dmg", out v))
					{
						creatureRule.Dmg = Mathf.Clamp(v, 0.1f, 10f);
					}
					else if (Tok(text2, "vel", out v) || Tok(text2, "spd", out v))
					{
						creatureRule.Spd = Mathf.Clamp(v, 0.1f, 5f);
					}
					else if (Tok(text2, "vida", out v) || Tok(text2, "hp", out v))
					{
						creatureRule.Hp = Mathf.Clamp(v, 0.1f, 10f);
					}
					else if (Tok(text2, "spawn", out v))
					{
						creatureRule.Spawn = Mathf.Clamp(v, 0f, 20f);
					}
				}
				list.Add(creatureRule);
			}
			return list;
		}

		private static bool Tok(string t, string prefix, out float v)
		{
			v = 0f;
			if (!t.StartsWith(prefix))
			{
				return false;
			}
			return float.TryParse(t.Substring(prefix.Length).TrimStart('=', 'x', ':'), NumberStyles.Float, CultureInfo.InvariantCulture, out v);
		}

		internal static CreatureRule Find(string prefab)
		{
			List<CreatureRule> list = Rules();
			if (list.Count == 0 || string.IsNullOrEmpty(prefab))
			{
				return null;
			}
			string text = prefab.ToLowerInvariant();
			if (_byName.TryGetValue(text, out var value))
			{
				return value;
			}
			CreatureRule creatureRule = null;
			foreach (CreatureRule item in list)
			{
				if (text.Contains(item.Key) && (creatureRule == null || item.Key.Length > creatureRule.Key.Length))
				{
					creatureRule = item;
				}
			}
			if (_byName.Count > 512)
			{
				_byName.Clear();
			}
			_byName[text] = creatureRule;
			return creatureRule;
		}

		internal static string PrefabName(GameObject go)
		{
			int instanceID = ((Object)go).GetInstanceID();
			if (_prefabOf.TryGetValue(instanceID, out var value))
			{
				return value;
			}
			string name = ((Object)go).name;
			int num = name.IndexOf('(');
			name = ((num > 0) ? name.Substring(0, num) : name).Trim();
			if (_prefabOf.Count > 4096)
			{
				_prefabOf.Clear();
			}
			return _prefabOf[instanceID] = name;
		}

		internal static CreatureRule RuleFor(Character c)
		{
			//IL_0065: Unknown result type (might be due to invalid IL or missing references)
			//IL_006a: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)c == (Object)null || !Mech.On || !Mech.R.CreatureSeasons)
			{
				return null;
			}
			try
			{
				if (c.IsPlayer() || c.IsBoss() || c.IsTamed())
				{
					return null;
				}
				CreatureRule creatureRule = Find(PrefabName(((Component)c).gameObject));
				if (creatureRule == null)
				{
					return null;
				}
				if (WorldGenerator.instance != null && SeasonBiomes.Excluded(WorldGenerator.instance.GetBiome(((Component)c).transform.position)))
				{
					return null;
				}
				if (creatureRule.DayOnly && SeasonPhase.IsNight())
				{
					return null;
				}
				return creatureRule;
			}
			catch
			{
				return null;
			}
		}

		internal static string SpawnString()
		{
			StringBuilder stringBuilder = new StringBuilder();
			foreach (CreatureRule item in Rules())
			{
				if (!Mathf.Approximately(item.Spawn, 1f))
				{
					if (stringBuilder.Length > 0)
					{
						stringBuilder.Append(',');
					}
					stringBuilder.Append(item.Key).Append("*:").Append(item.Spawn.ToString(CultureInfo.InvariantCulture));
				}
			}
			return stringBuilder.ToString();
		}

		internal static void Tick(float dt)
		{
			_timer += dt;
			if (_timer < 2f)
			{
				return;
			}
			_timer = 0f;
			if ((Object)(object)ZNet.instance == (Object)null || (_touched.Count == 0 && !AnySpeedRule()))
			{
				return;
			}
			List<Character> allCharacters = Character.GetAllCharacters();
			for (int i = 0; i < allCharacters.Count; i++)
			{
				Character val = allCharacters[i];
				if ((Object)(object)val == (Object)null)
				{
					continue;
				}
				float num = RuleFor(val)?.Spd ?? 1f;
				Speeds value;
				bool flag = _orig.TryGetValue(val, out value);
				bool flag2 = Mathf.Approximately(num, 1f);
				if (!flag && flag2)
				{
					continue;
				}
				if (!flag)
				{
					value = new Speeds
					{
						Values = new float[SpeedFields.Length]
					};
					for (int j = 0; j < SpeedFields.Length; j++)
					{
						value.Values[j] = (float)SpeedFields[j].GetValue(val);
					}
					_orig.Add(val, value);
					_touched.Add(val);
				}
				for (int k = 0; k < SpeedFields.Length; k++)
				{
					SpeedFields[k].SetValue(val, value.Values[k] * num);
				}
				if (flag2)
				{
					_orig.Remove(val);
					_touched.Remove(val);
				}
			}
			if (_touched.Count > 256)
			{
				_touched.RemoveWhere((Character x) => (Object)(object)x == (Object)null);
			}
		}

		private static bool AnySpeedRule()
		{
			foreach (CreatureRule item in Rules())
			{
				if (!Mathf.Approximately(item.Spd, 1f))
				{
					return true;
				}
			}
			return false;
		}

		internal static void Reset()
		{
			foreach (Character item in _touched)
			{
				if (!((Object)(object)item == (Object)null) && _orig.TryGetValue(item, out var value))
				{
					for (int i = 0; i < SpeedFields.Length; i++)
					{
						SpeedFields[i].SetValue(item, value.Values[i]);
					}
					_orig.Remove(item);
				}
			}
			_touched.Clear();
			_src = null;
			_byName.Clear();
			_prefabOf.Clear();
		}
	}
	[HarmonyPatch]
	internal static class Character_Damage_Season_Patch
	{
		private static MethodBase TargetMethod()
		{
			return AccessTools.Method(typeof(Character), "Damage", new Type[1] { typeof(HitData) }, (Type[])null);
		}

		private static bool Prepare()
		{
			return TargetMethod() != null;
		}

		private static void Prefix(Character __instance, HitData hit)
		{
			if (hit != null && Mech.On && Mech.R.CreatureSeasons)
			{
				float num = 1f;
				CreatureRule creatureRule = CreatureSeasons.RuleFor(hit.GetAttacker());
				if (creatureRule != null)
				{
					num *= creatureRule.Dmg;
				}
				CreatureRule creatureRule2 = CreatureSeasons.RuleFor(__instance);
				if (creatureRule2 != null && creatureRule2.Hp > 0f)
				{
					num /= creatureRule2.Hp;
				}
				if (!Mathf.Approximately(num, 1f))
				{
					((DamageTypes)(ref hit.m_damage)).Modify(num);
				}
			}
		}
	}
	[HarmonyPatch]
	internal static class CharacterDrop_GenerateDropList_Patch
	{
		private static MethodBase TargetMethod()
		{
			return AccessTools.Method(typeof(CharacterDrop), "GenerateDropList", (Type[])null, (Type[])null);
		}

		private static bool TamedFall(Character ch, out float mult)
		{
			//IL_006d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0072: Unknown result type (might be due to invalid IL or missing references)
			mult = 1f;
			try
			{
				if ((Object)(object)ch == (Object)null || !Mech.On || Mech.S != Season.Fall || ch.IsPlayer() || !ch.IsTamed())
				{
					return false;
				}
				mult = Mathf.Clamp(Mech.R.TamedFallDrop, 1f, 10f);
				if (mult <= 1.001f)
				{
					return false;
				}
				return WorldGenerator.instance == null || !SeasonBiomes.Excluded(WorldGenerator.instance.GetBiome(((Component)ch).transform.position));
			}
			catch
			{
				return false;
			}
		}

		private static bool Prepare()
		{
			return TargetMethod() != null;
		}

		private static void Postfix(CharacterDrop __instance, object __result)
		{
			if (!(__result is List<KeyValuePair<GameObject, int>> { Count: not 0 } list) || !TamedFall(((Component)__instance).GetComponent<Character>(), out var mult))
			{
				return;
			}
			for (int i = 0; i < list.Count; i++)
			{
				if ((Object)(object)list[i].Key != (Object)null)
				{
					list[i] = new KeyValuePair<GameObject, int>(list[i].Key, Mathf.Max(1, Mathf.RoundToInt((float)list[i].Value * mult)));
				}
			}
		}
	}
	internal static class CropCalendar
	{
		internal enum State
		{
			NotCrop,
			Good,
			Off,
			Winter
		}

		private static readonly FieldInfo PlantTimeKey = AccessTools.Field(typeof(ZDOVars), "s_plantTime");

		private static readonly Dictionary<Plant, double> _lastCheck = new Dictionary<Plant, double>();

		private static readonly int PauseKey = StringExtensionMethods.GetStableHashCode("ValheimSeasons_pauseAt");

		private static int _pruneCount;

		private static string _calCache;

		private static Dictionary<string, HashSet<Season>> _cal;

		internal static string CropKey(Plant p)
		{
			if ((Object)(object)p == (Object)null)
			{
				return null;
			}
			string text = ((Object)p).name.ToLowerInvariant();
			if (!text.Contains("sapling_"))
			{
				return null;
			}
			foreach (KeyValuePair<string, HashSet<Season>> item in Calendar())
			{
				if (text.Contains(item.Key))
				{
					return item.Key;
				}
			}
			return null;
		}

		internal static Dictionary<string, HashSet<Season>> Calendar()
		{
			string text = Mech.R.CropSeasons ?? "";
			if (_cal != null && _calCache == text)
			{
				return _cal;
			}
			_calCache = text;
			_cal = new Dictionary<string, HashSet<Season>>();
			string[] array = text.Split(',');
			foreach (string text2 in array)
			{
				int num = text2.IndexOf(':');
				if (num <= 0)
				{
					continue;
				}
				HashSet<Season> hashSet = new HashSet<Season>();
				string[] array2 = text2.Substring(num + 1).Split('+');
				for (int j = 0; j < array2.Length; j++)
				{
					switch (array2[j].Trim().ToLowerInvariant())
					{
					case "spring":
					case "primavera":
						hashSet.Add(Season.Spring);
						break;
					case "summer":
					case "verao":
					case "verão":
						hashSet.Add(Season.Summer);
						break;
					case "outono":
					case "fall":
						hashSet.Add(Season.Fall);
						break;
					case "winter":
					case "inverno":
						hashSet.Add(Season.Winter);
						break;
					}
				}
				_cal[text2.Substring(0, num).Trim().ToLowerInvariant()] = hashSet;
			}
			return _cal;
		}

		internal static bool SeasonalAt(Vector3 pos)
		{
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				return WorldGenerator.instance == null || !SeasonBiomes.Excluded(WorldGenerator.instance.GetBiome(pos));
			}
			catch
			{
				return true;
			}
		}

		internal static bool WinterFrozen(Vector3 pos)
		{
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			if (Mech.On && Mech.R.CropCalendar && Mech.S == Season.Winter)
			{
				return SeasonalAt(pos);
			}
			return false;
		}

		internal static State StateOf(Plant p, out string key)
		{
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			key = CropKey(p);
			if ((Object)(object)p == (Object)null || !Mech.On || !Mech.R.CropCalendar)
			{
				return State.NotCrop;
			}
			if (Mech.S == Season.Winter)
			{
				if (!SeasonalAt(((Component)p).transform.position))
				{
					return State.NotCrop;
				}
				return State.Winter;
			}
			if (key == null)
			{
				return State.NotCrop;
			}
			if (!Calendar()[key].Contains(Mech.S))
			{
				return State.Off;
			}
			return State.Good;
		}

		internal static float GrowMultiplier(Plant p)
		{
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)p == (Object)null || !SeasonalAt(((Component)p).transform.position))
			{
				return 1f;
			}
			string key;
			State state = StateOf(p, out key);
			if (state == State.NotCrop)
			{
				return SeasonClient.GrowMultiplier();
			}
			SeasonMechanics r = Mech.R;
			float num = state switch
			{
				State.Good => r.CropGoodSeason, 
				State.Off => r.CropOffSeason, 
				_ => 1f, 
			};
			if (Mech.S == Season.Spring && PlantedEarlySpring(p))
			{
				num *= r.EarlySpringBonus;
			}
			return Mathf.Max(0.05f, num);
		}

		private static bool PlantedEarlySpring(Plant p)
		{
			try
			{
				if (!SeasonClient.HasState || SeasonClient.State.Forced || (Object)(object)EnvMan.instance == (Object)null)
				{
					return false;
				}
				ZNetView component = ((Component)p).GetComponent<ZNetView>();
				ZDO val = ((component != null) ? component.GetZDO() : null);
				if (val == null || PlantTimeKey == null)
				{
					return false;
				}
				long num = val.GetLong((int)PlantTimeKey.GetValue(null), 0L);
				if (num <= 0)
				{
					return false;
				}
				double num2 = Math.Max(1.0, EnvMan.instance.m_dayLengthSec);
				int num3 = (int)(new TimeSpan(num).TotalSeconds / num2);
				int num4 = Math.Max(1, SeasonClient.Rules.DaysPerSeason);
				int num5 = SeasonClient.State.Day - (num4 - 1 - SeasonClient.State.DaysLeft);
				return num3 >= num5 && num3 < num5 + Math.Max(1, Mech.R.EarlySpringDays);
			}
			catch
			{
				return false;
			}
		}

		internal static void PauseTick(Plant p)
		{
			ZNetView component = ((Component)p).GetComponent<ZNetView>();
			if ((Object)(object)component == (Object)null || !component.IsValid() || !component.IsOwner() || (Object)(object)ZNet.instance == (Object)null || PlantTimeKey == null)
			{
				return;
			}
			double timeSeconds = ZNet.instance.GetTimeSeconds();
			ZDO zDO = component.GetZDO();
			if (++_pruneCount > 500)
			{
				_pruneCount = 0;
				Prune();
			}
			if (StateOf(p, out var _) != State.Winter)
			{
				_lastCheck[p] = timeSeconds;
				if (zDO.GetLong(PauseKey, 0L) > 0)
				{
					zDO.Set(PauseKey, -1L);
				}
				return;
			}
			int num = (int)PlantTimeKey.GetValue(null);
			long num2 = zDO.GetLong(num, 0L);
			if (num2 <= 0)
			{
				return;
			}
			double totalSeconds = new TimeSpan(num2).TotalSeconds;
			if (!_lastCheck.TryGetValue(p, out var value))
			{
				long num3 = zDO.GetLong(PauseKey, 0L);
				value = ((num3 > 0) ? new TimeSpan(num3).TotalSeconds : ((num3 >= 0) ? WinterStartSeconds(timeSeconds) : timeSeconds));
				if (value < totalSeconds)
				{
					value = totalSeconds;
				}
			}
			_lastCheck[p] = timeSeconds;
			double num4 = timeSeconds - value;
			if (num4 <= 0.0)
			{
				zDO.Set(PauseKey, TimeSpan.FromSeconds(timeSeconds).Ticks);
				return;
			}
			zDO.Set(num, num2 + TimeSpan.FromSeconds(num4).Ticks);
			zDO.Set(PauseKey, TimeSpan.FromSeconds(timeSeconds).Ticks);
		}

		private static double WinterStartSeconds(double now)
		{
			if (!SeasonClient.HasState || SeasonClient.State.Forced || SeasonClient.State.Season != Season.Winter || (Object)(object)EnvMan.instance == (Object)null)
			{
				return now;
			}
			int num = Math.Max(1, SeasonClient.Rules.DaysPerSeason);
			double num2 = (double)(SeasonClient.State.Day - (num - 1 - SeasonClient.State.DaysLeft)) * Math.Max(1.0, EnvMan.instance.m_dayLengthSec);
			if (!(num2 > 0.0) || !(num2 < now))
			{
				return now;
			}
			return num2;
		}

		private static void Prune()
		{
			List<Plant> list = null;
			foreach (KeyValuePair<Plant, double> item in _lastCheck)
			{
				if ((Object)(object)item.Key == (Object)null)
				{
					List<Plant> obj = list ?? new List<Plant>();
					list = obj;
					obj.Add(item.Key);
				}
			}
			if (list == null)
			{
				return;
			}
			foreach (Plant item2 in list)
			{
				_lastCheck.Remove(item2);
			}
		}

		internal static void Reset()
		{
			_lastCheck.Clear();
			_pruneCount = 0;
		}

		internal static string Hover(Plant p)
		{
			string key;
			return StateOf(p, out key) switch
			{
				State.Good => "<color=#9be564>Estação boa: cresce mais rápido</color>", 
				State.Off => "<color=#e5c364>Fora de época: cresce devagar</color>", 
				State.Winter => "<color=#9fd3ff>Congelada: nada cresce no inverno (volta na primavera)</color>", 
				_ => null, 
			};
		}
	}
	[HarmonyPatch]
	internal static class Plant_SUpdate_Patch
	{
		private static readonly FieldRef<Plant, float> UpdateTime = UpdateTimeRef();

		private static FieldRef<Plant, float> UpdateTimeRef()
		{
			try
			{
				return AccessTools.FieldRefAccess<Plant, float>("m_updateTime");
			}
			catch
			{
				return null;
			}
		}

		private static MethodBase TargetMethod()
		{
			return AccessTools.Method(typeof(Plant), "SUpdate", (Type[])null, (Type[])null);
		}

		private static bool Prepare()
		{
			return TargetMethod() != null;
		}

		private static void Prefix(Plant __instance, float __0)
		{
			if (UpdateTime == null || !(__0 <= UpdateTime.Invoke(__instance)))
			{
				CropCalendar.PauseTick(__instance);
			}
		}
	}
	[HarmonyPatch]
	internal static class Player_TryPlacePiece_Winter_Patch
	{
		private static readonly FieldInfo Ghost = AccessTools.Field(typeof(Player), "m_placementGhost");

		private static MethodBase TargetMethod()
		{
			return AccessTools.Method(typeof(Player), "TryPlacePiece", (Type[])null, (Type[])null);
		}

		private static bool Prepare()
		{
			return TargetMethod() != null;
		}

		private static bool Prefix(Player __instance, Piece __0, ref bool __result)
		{
			//IL_005a: Unknown result type (might be due to invalid IL or missing references)
			//IL_004d: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)__instance != (Object)(object)Player.m_localPlayer || (Object)(object)__0 == (Object)null || (Object)(object)((Component)__0).GetComponent<Plant>() == (Object)null)
			{
				return true;
			}
			object? obj = Ghost?.GetValue(__instance);
			GameObject val = (GameObject)((obj is GameObject) ? obj : null);
			if (!CropCalendar.WinterFrozen(((Object)(object)val != (Object)null) ? val.transform.position : ((Component)__instance).transform.position))
			{
				return true;
			}
			((Character)__instance).Message((MessageType)2, "O chão está congelado: não dá pra plantar no inverno", 0, (Sprite)null, false);
			__result = false;
			return false;
		}
	}
	[HarmonyPatch]
	internal static class Plant_GetHoverText_Patch
	{
		private static MethodBase TargetMethod()
		{
			return AccessTools.Method(typeof(Plant), "GetHoverText", (Type[])null, (Type[])null);
		}

		private static bool Prepare()
		{
			return TargetMethod() != null;
		}

		private static void Postfix(Plant __instance, ref string __result)
		{
			string text = CropCalendar.Hover(__instance);
			if (text != null)
			{
				__result = __result + "\n" + text;
			}
		}
	}
	internal static class FrozenWater
	{
		private class Template
		{
			public GameObject Go;

			public string Name;

			public float Radius;

			public float Offset;

			public float ScaleMin = 1f;

			public float ScaleMax = 1f;
		}

		private struct Rng
		{
			private uint _s;

			public Rng(int seed)
			{
				_s = (uint)(seed ^ -1640531527);
				if (_s == 0)
				{
					_s = 1u;
				}
			}

			public float Next01()
			{
				_s ^= _s << 13;
				_s ^= _s >> 17;
				_s ^= _s << 5;
				return (float)(_s & 0xFFFFFF) / 16777216f;
			}

			public float Range(float a, float b)
			{
				return a + (b - a) * Next01();
			}
		}

		private static readonly Dictionary<WaterVolume, List<GameObject>> _zones = new Dictionary<WaterVolume, List<GameObject>>();

		private static readonly List<Collider> _colliders = new List<Collider>();

		private static bool _frozen;

		private static float _timer;

		private static float _density = -1f;

		private static Material _iceMat;

		private static bool _iceIsFallback;

		private static bool _warnedIce;

		private static float _lastIceScan = -999f;

		private static Texture2D _iceTex;

		private static FieldInfo _surfaceField;

		private static MethodInfo _isAshlands;

		private static Func<float, float, bool> _isAshlandsFast;

		private static bool _reflected;

		private const int BaseFloesPerZone = 7;

		private static readonly Queue<WaterVolume> _queue = new Queue<WaterVolume>();

		private static bool _decided;

		private static string _lastMode = "auto";

		private static List<Template> _templates;

		private static string _templatesKey;

		private static GameObject _templateRoot;

		private static readonly Stopwatch _sw = new Stopwatch();

		private static readonly Queue<GameObject> _trash = new Queue<GameObject>();

		private const float Thickness = 0.8f;

		private const float Freeboard = 0.15f;

		private static readonly List<Ship> _ships = new List<Ship>();

		internal static bool Frozen => _frozen;

		private static float Density => Mathf.Clamp(SeasonClient.Rules.Mech.IceFloes, 0f, 4f);

		internal static bool Wanted
		{
			get
			{
				if (SeasonClient.Active && SeasonClient.Rules.FreezeWater && SeasonClient.Current == Season.Winter && (Object)(object)ZoneSystem.instance != (Object)null && WorldGenerator.instance != null)
				{
					return Density > 0f;
				}
				return false;
			}
		}

		internal static void Tick(float dt)
		{
			PumpTrash();
			Pump();
			_timer += dt;
			if (_timer < 1f)
			{
				return;
			}
			_timer = 0f;
			if (!SeasonClient.Active || (Object)(object)ZoneSystem.instance == (Object)null)
			{
				return;
			}
			bool wanted = Wanted;
			if (wanted && _frozen && (!Mathf.Approximately(_density, Density) || TemplatesKey() != _templatesKey))
			{
				MeltAll();
				FreezeAll();
				return;
			}
			string obj = (SeasonClient.Testing ? ("teste:" + SeasonClient.Current) : (SeasonClient.State.Forced ? ("admin:" + SeasonClient.Current) : "auto"));
			bool flag = obj != _lastMode;
			_lastMode = obj;
			bool flag2 = !_decided || flag || !SeasonClient.Rules.SwapAtNight || SeasonClient.Testing || SeasonPhase.IsNight();
			_decided = true;
			if (wanted && !_frozen && flag2)
			{
				FreezeAll();
			}
			else if (!wanted && _frozen && flag2)
			{
				MeltAll();
			}
			else if (_frozen)
			{
				Cleanup();
			}
		}

		internal static void Shutdown()
		{
			MeltAll();
			while (_trash.Count > 0)
			{
				GameObject val = _trash.Dequeue();
				if ((Object)(object)val != (Object)null)
				{
					Object.Destroy((Object)(object)val);
				}
			}
			_decided = false;
			_lastMode = "auto";
			_ships.Clear();
		}

		private static void Pump()
		{
			if (_queue.Count == 0)
			{
				return;
			}
			if (!_frozen)
			{
				_queue.Clear();
				return;
			}
			float num = Mathf.Max(0.5f, Plugin.FrameBudgetMs.Value * 0.5f);
			_sw.Restart();
			int count = _colliders.Count;
			int num2 = 0;
			while (_queue.Count > 0 && _sw.Elapsed.TotalMilliseconds < (double)num)
			{
				WaterVolume val = _queue.Dequeue();
				if ((Object)(object)val != (Object)null)
				{
					num2 += Add(val);
				}
			}
			if (_colliders.Count > count && _ships.Count > 0)
			{
				List<Collider> range = _colliders.GetRange(count, _colliders.Count - count);
				_ships.RemoveAll((Ship s) => (Object)(object)s == (Object)null);
				foreach (Ship ship in _ships)
				{
					IgnoreShip(ship, range);
				}
			}
			if (_queue.Count == 0 && num2 > 0 && Plugin.DumpMaterials.Value)
			{
				Plugin.Log.LogInfo((object)$"Placas de gelo: {CountAll()} no total.");
			}
		}

		private static int CountAll()
		{
			int num = 0;
			foreach (KeyValuePair<WaterVolume, List<GameObject>> zone in _zones)
			{
				num += zone.Value.Count;
			}
			return num;
		}

		private static void FreezeAll()
		{
			//IL_006f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0074: Unknown result type (might be due to invalid IL or missing references)
			//IL_005e: Unknown result type (might be due to invalid IL or missing references)
			//IL_004d: Unknown result type (might be due to invalid IL or missing references)
			_frozen = true;
			_density = Density;
			Templates();
			_queue.Clear();
			List<WaterVolume> list = new List<WaterVolume>(Object.FindObjectsByType<WaterVolume>((FindObjectsSortMode)0));
			Vector3 c = (((Object)(object)GameCamera.instance != (Object)null) ? ((Component)GameCamera.instance).transform.position : (((Object)(object)Player.m_localPlayer != (Object)null) ? ((Component)Player.m_localPlayer).transform.position : Vector3.zero));
			list.Sort(delegate(WaterVolume a, WaterVolume b)
			{
				//IL_0006: Unknown result type (might be due to invalid IL or missing references)
				//IL_000c: Unknown result type (might be due to invalid IL or missing references)
				//IL_0011: Unknown result type (might be due to invalid IL or missing references)
				//IL_0016: Unknown result type (might be due to invalid IL or missing references)
				//IL_0027: Unknown result type (might be due to invalid IL or missing references)
				//IL_002d: Unknown result type (might be due to invalid IL or missing references)
				//IL_0032: Unknown result type (might be due to invalid IL or missing references)
				//IL_0037: Unknown result type (might be due to invalid IL or missing references)
				Vector3 val = ((Component)a).transform.position - c;
				float sqrMagnitude = ((Vector3)(ref val)).sqrMagnitude;
				val = ((Component)b).transform.position - c;
				return sqrMagnitude.CompareTo(((Vector3)(ref val)).sqrMagnitude);
			});
			foreach (WaterVolume item in list)
			{
				_queue.Enqueue(item);
			}
			Plugin.Log.LogInfo((object)($"Inverno: placas de gelo em {list.Count} zona(s) de água " + ((_templates.Count > 0) ? ("(do jogo: " + string.Join(", ", _templates.ConvertAll((Template t) => t.Name)) + ")") : "(geradas)")));
		}

		internal static void MeltAll()
		{
			_frozen = false;
			_queue.Clear();
			foreach (KeyValuePair<WaterVolume, List<GameObject>> zone in _zones)
			{
				foreach (GameObject item in zone.Value)
				{
					if ((Object)(object)item != (Object)null)
					{
						_trash.Enqueue(item);
					}
				}
			}
			_zones.Clear();
			_colliders.Clear();
		}

		private static void PumpTrash()
		{
			for (int i = 0; i < 40; i++)
			{
				if (_trash.Count <= 0)
				{
					break;
				}
				GameObject val = _trash.Dequeue();
				if ((Object)(object)val != (Object)null)
				{
					Object.Destroy((Object)(object)val);
				}
			}
		}

		private static void Cleanup()
		{
			List<WaterVolume> list = null;
			foreach (KeyValuePair<WaterVolume, List<GameObject>> zone in _zones)
			{
				if ((Object)(object)zone.Key == (Object)null)
				{
					List<WaterVolume> obj = list ?? new List<WaterVolume>();
					list = obj;
					obj.Add(zone.Key);
				}
			}
			if (list == null)
			{
				return;
			}
			foreach (WaterVolume item in list)
			{
				_zones.Remove(item);
			}
			_colliders.RemoveAll((Collider c) => (Object)(object)c == (Object)null);
		}

		internal static void OnWaterVolumeCreated(WaterVolume wv)
		{
			if (_frozen && !((Object)(object)wv == (Object)null) && !_zones.ContainsKey(wv))
			{
				_queue.Enqueue(wv);
			}
		}

		private static int Add(WaterVolume wv)
		{
			//IL_006f: Unknown result type (might be due to invalid IL or missing references)
			//IL_004e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0062: Unknown result type (might be due to invalid IL or missing references)
			//IL_0067: Unknown result type (might be due to invalid IL or missing references)
			//IL_0074: Unknown result type (might be due to invalid IL or missing references)
			//IL_0094: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b3: Unknown result type (might be due to invalid IL or missing references)
			//IL_0111: Unknown result type (might be due to invalid IL or missing references)
			//IL_012f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0168: Unknown result type (might be due to invalid IL or missing references)
			//IL_0183: Unknown result type (might be due to invalid IL or missing references)
			//IL_0299: Unknown result type (might be due to invalid IL or missing references)
			//IL_023f: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)wv == (Object)null || _zones.ContainsKey(wv))
			{
				return 0;
			}
			Reflect();
			object? obj = _surfaceField?.GetValue(wv);
			Renderer val = (Renderer)(((obj is Renderer) ? obj : null) ?? ((Component)wv).GetComponentInChildren<MeshRenderer>());
			Bounds val2 = (Bounds)(((Object)(object)val != (Object)null) ? val.bounds : new Bounds(((Component)wv).transform.position, new Vector3(64f, 1f, 64f)));
			float waterLevel = ZoneSystem.instance.m_waterLevel;
			List<GameObject> list = new List<GameObject>();
			_zones[wv] = list;
			int x = Mathf.FloorToInt((((Bounds)(ref val2)).center.x + 32f) / 64f);
			int z = Mathf.FloorToInt((((Bounds)(ref val2)).center.z + 32f) / 64f);
			Rng rng = new Rng(Hash(x, z));
			float num = 7f * Density;
			int num2 = Mathf.FloorToInt(num) + ((rng.Next01() < num - Mathf.Floor(num)) ? 1 : 0);
			float num3 = Mathf.Max(4f, ((Bounds)(ref val2)).extents.x - 4f);
			float num4 = Mathf.Max(4f, ((Bounds)(ref val2)).extents.z - 4f);
			List<Template> list2 = Templates();
			for (int i = 0; i < num2; i++)
			{
				float num5 = rng.Next01() * rng.Next01();
				float num6 = ((Bounds)(ref val2)).center.x + rng.Range(0f - num3, num3);
				float num7 = ((Bounds)(ref val2)).center.z + rng.Range(0f - num4, num4);
				float num8 = rng.Next01();
				float rot = rng.Next01() * 360f;
				int seed = (int)(rng.Next01() * 2.1474836E+09f);
				if (list2.Count > 0)
				{
					Template template = list2[Mathf.Min(list2.Count - 1, (int)(num8 * (float)list2.Count))];
					float num9 = Mathf.Lerp(template.ScaleMin, template.ScaleMax, num5);
					float r = template.Radius * num9;
					if (GoodSpot(num6, num7, r, waterLevel) && !TooClose(list, num6, num7, r))
					{
						list.Add(SpawnTemplate(wv, template, new Vector3(num6, waterLevel, num7), rot, num9, seed));
					}
				}
				else
				{
					float num10 = Mathf.Lerp(2.2f, 7.5f, num5);
					int sides = 6 + (int)(num8 * 3f);
					if (GoodSpot(num6, num7, num10, waterLevel) && !TooClose(list, num6, num7, num10))
					{
						list.Add(MakeFloe(wv, new Vector3(num6, waterLevel, num7), num10, sides, rot, seed));
					}
				}
			}
			return list.Count;
		}

		private static bool GoodSpot(float x, float z, float r, float level)
		{
			if (IsExcludedSea(x, z))
			{
				return false;
			}
			WorldGenerator instance = WorldGenerator.instance;
			float num = level - 1.5f;
			if (instance.GetHeight(x, z) > num)
			{
				return false;
			}
			for (int i = 0; i < 4; i++)
			{
				float num2 = (float)i * (float)Math.PI * 0.5f;
				if (instance.GetHeight(x + Mathf.Cos(num2) * r, z + Mathf.Sin(num2) * r) > num)
				{
					return false;
				}
			}
			return true;
		}

		private static bool TooClose(List<GameObject> list, float x, float z, float r)
		{
			//IL_0046: Unknown result type (might be due to invalid IL or missing references)
			//IL_004b: Unknown result type (might be due to invalid IL or missing references)
			//IL_004d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0056: Unknown result type (might be due to invalid IL or missing references)
			//IL_0060: Unknown result type (might be due to invalid IL or missing references)
			//IL_0069: Unknown result type (might be due to invalid IL or missing references)
			foreach (GameObject item in list)
			{
				if (!((Object)(object)item == (Object)null))
				{
					Floe component = item.GetComponent<Floe>();
					float num = r + (((Object)(object)component != (Object)null) ? component.Radius : 4f) + 1f;
					Vector3 position = item.transform.position;
					if ((position.x - x) * (position.x - x) + (position.z - z) * (position.z - z) < num * num)
					{
						return true;
					}
				}
			}
			return false;
		}

		private static GameObject MakeFloe(WaterVolume wv, Vector3 pos, float radius, int sides, float rot, int seed)
		{
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: Expected O, but got Unknown
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			//IL_0030: Unknown result type (might be due to invalid IL or missing references)
			GameObject val = new GameObject("ValheimSeasons_IceFloe");
			val.transform.SetParent(((Component)wv).transform, true);
			val.transform.SetPositionAndRotation(pos, Quaternion.Euler(0f, rot, 0f));
			int num = LayerMask.NameToLayer("static_solid");
			val.layer = ((num >= 0) ? num : 0);
			Mesh sharedMesh = BuildMesh(radius, sides, seed);
			Rigidbody val2 = val.AddComponent<Rigidbody>();
			val2.isKinematic = true;
			val2.useGravity = false;
			val2.interpolation = (RigidbodyInterpolation)1;
			MeshCollider val3 = val.AddComponent<MeshCollider>();
			val3.sharedMesh = sharedMesh;
			val3.convex = true;
			_colliders.Add((Collider)(object)val3);
			if (!Plugin.Headless)
			{
				val.AddComponent<MeshFilter>().sharedMesh = sharedMesh;
				MeshRenderer obj = val.AddComponent<MeshRenderer>();
				((Renderer)obj).sharedMaterial = IceMaterial();
				((Renderer)obj).shadowCastingMode = (ShadowCastingMode)1;
				((Renderer)obj).receiveShadows = true;
			}
			val.AddComponent<Floe>().Init(wv, radius, val2, seed, 0f, procedural: true);
			return val;
		}

		private static string TemplatesKey()
		{
			return (SeasonClient.Rules.Mech.IceFloePrefabs ?? "auto").Trim().ToLowerInvariant();
		}

		private static List<Template> Templates()
		{
			string text = TemplatesKey();
			if (_templates != null && text == _templatesKey)
			{
				return _templates;
			}
			ClearTemplates();
			_templatesKey = text;
			_templates = new List<Template>();
			try
			{
				object obj;
				switch (text)
				{
				case "gerado":
				case "none":
					return _templates;
				default:
					if (text.Length != 0)
					{
						obj = SeasonMechanics.ParseList(text);
						break;
					}
					goto case "auto";
				case "auto":
					obj = null;
					break;
				}
				List<string> list = (List<string>)obj;
				if (!(AccessTools.Field(typeof(ZoneSystem), "m_vegetation")?.GetValue(ZoneSystem.instance) is IEnumerable enumerable))
				{
					return _templates;
				}
				HashSet<string> hashSet = new HashSet<string>();
				int num = 64;
				foreach (object item in enumerable)
				{
					if (item == null)
					{
						continue;
					}
					Traverse val = Traverse.Create(item);
					GameObject value = val.Field("m_prefab").GetValue<GameObject>();
					if ((Object)(object)value == (Object)null || !hashSet.Add(((Object)value).name))
					{
						continue;
					}
					string text2 = ((Object)value).name.ToLowerInvariant();
					bool flag;
					if (list != null)
					{
						flag = false;
						foreach (string item2 in list)
						{
							if (text2.Contains(item2))
							{
								flag = true;
								break;
							}
						}
					}
					else
					{
						bool value2 = val.Field("m_enable").GetValue<bool>();
						int num2 = Convert.ToInt32(val.Field("m_biome").GetValue());
						bool value3 = val.Field("m_snapToWater").GetValue<bool>();
						flag = value2 && value3 && (num2 & num) != 0;
					}
					if (flag)
					{
						Template template = BuildTemplate(value);
						if (template != null)
						{
							template.Offset = val.Field("m_groundOffset").GetValue<float>();
							template.ScaleMin = Mathf.Max(0.1f, val.Field("m_scaleMin").GetValue<float>());
							template.ScaleMax = Mathf.Max(template.ScaleMin, val.Field("m_scaleMax").GetValue<float>());
							_templates.Add(template);
						}
					}
				}
			}
			catch (Exception ex)
			{
				Plugin.Log.LogWarning((object)("Não achei as placas de gelo do jogo: " + ex.Message));
			}
			if (_templates.Count == 0)
			{
				Plugin.Log.LogInfo((object)("Placas de gelo do jogo não encontradas (IceFloePrefabs = " + text + "): usando as geradas."));
			}
			return _templates;
		}

		private static void ClearTemplates()
		{
			if (_templates != null)
			{
				foreach (Template template in _templates)
				{
					if ((Object)(object)template.Go != (Object)null)
					{
						Object.Destroy((Object)(object)template.Go);
					}
				}
			}
			_templates = null;
		}

		private static Template BuildTemplate(GameObject prefab)
		{
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			//IL_001c: Expected O, but got Unknown
			//IL_00a3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a9: Expected O, but got Unknown
			//IL_00eb: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fc: Unknown result type (might be due to invalid IL or missing references)
			//IL_012d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0132: Unknown result type (might be due to invalid IL or missing references)
			//IL_013b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0140: Unknown result type (might be due to invalid IL or missing references)
			//IL_0187: Unknown result type (might be due to invalid IL or missing references)
			//IL_018c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0195: Unknown result type (might be due to invalid IL or missing references)
			//IL_019a: Unknown result type (might be due to invalid IL or missing references)
			//IL_01cd: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d4: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d9: Unknown result type (might be due to invalid IL or missing references)
			//IL_01de: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e7: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ec: Unknown result type (might be due to invalid IL or missing references)
			//IL_0218: Unknown result type (might be due to invalid IL or missing references)
			//IL_0227: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)_templateRoot == (Object)null)
			{
				_templateRoot = new GameObject("ValheimSeasons_FloeTemplates");
				_templateRoot.SetActive(false);
				Object.DontDestroyOnLoad((Object)(object)_templateRoot);
			}
			HashSet<Renderer> hashSet = null;
			LODGroup componentInChildren = prefab.GetComponentInChildren<LODGroup>(true);
			if ((Object)(object)componentInChildren != (Object)null)
			{
				LOD[] lODs = componentInChildren.GetLODs();
				if (lODs.Length != 0)
				{
					hashSet = new HashSet<Renderer>();
					Renderer[] renderers = lODs[0].renderers;
					foreach (Renderer val in renderers)
					{
						if ((Object)(object)val != (Object)null)
						{
							hashSet.Add(val);
						}
					}
				}
			}
			GameObject val2 = new GameObject("ValheimSeasons_IceFloe_" + ((Object)prefab).name);
			val2.transform.SetParent(_templateRoot.transform, false);
			val2.layer = prefab.layer;
			if (CopyParts(prefab.transform, val2.transform, hashSet) == 0)
			{
				Object.Destroy((Object)(object)val2);
				return null;
			}
			bool any = false;
			Bounds bb = default(Bounds);
			Matrix4x4 worldToLocalMatrix = val2.transform.worldToLocalMatrix;
			MeshFilter[] componentsInChildren = val2.GetComponentsInChildren<MeshFilter>(true);
			foreach (MeshFilter val3 in componentsInChildren)
			{
				if ((Object)(object)val3.sharedMesh != (Object)null)
				{
					Encap(ref bb, ref any, val3.sharedMesh.bounds, worldToLocalMatrix * ((Component)val3).transform.localToWorldMatrix);
				}
			}
			MeshCollider[] componentsInChildren2 = val2.GetComponentsInChildren<MeshCollider>(true);
			foreach (MeshCollider val4 in componentsInChildren2)
			{
				if ((Object)(object)val4.sharedMesh != (Object)null)
				{
					Encap(ref bb, ref any, val4.sharedMesh.bounds, worldToLocalMatrix * ((Component)val4).transform.localToWorldMatrix);
				}
			}
			BoxCollider[] componentsInChildren3 = val2.GetComponentsInChildren<BoxCollider>(true);
			foreach (BoxCollider val5 in componentsInChildren3)
			{
				Encap(ref bb, ref any, new Bounds(val5.center, val5.size), worldToLocalMatrix * ((Component)val5).transform.localToWorldMatrix);
			}
			float num = (any ? Mathf.Max(new float[3]
			{
				((Bounds)(ref bb)).extents.x,
				((Bounds)(ref bb)).extents.z,
				1f
			}) : 4f);
			return new Template
			{
				Go = val2,
				Name = ((Object)prefab).name,
				Radius = Mathf.Min(num, 30f)
			};
		}

		private static void Encap(ref Bounds bb, ref bool any, Bounds local, Matrix4x4 m)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0016: 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_001c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0038: Unknown result type (might be due to invalid IL or missing references)
			//IL_0030: Unknown result type (might be due to invalid IL or missing references)
			//IL_004c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0044: Unknown result type (might be due to invalid IL or missing references)
			//IL_0053: Unknown result type (might be due to invalid IL or missing references)
			//IL_0058: Unknown result type (might be due to invalid IL or missing references)
			//IL_005d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0062: Unknown result type (might be due to invalid IL or missing references)
			//IL_007e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0068: Unknown result type (might be due to invalid IL or missing references)
			//IL_0069: Unknown result type (might be due to invalid IL or missing references)
			//IL_006e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0073: Unknown result type (might be due to invalid IL or missing references)
			Vector3 center = ((Bounds)(ref local)).center;
			Vector3 extents = ((Bounds)(ref local)).extents;
			for (int i = 0; i < 8; i++)
			{
				Vector3 val = ((Matrix4x4)(ref m)).MultiplyPoint3x4(center + new Vector3(((i & 1) == 0) ? (0f - extents.x) : extents.x, ((i & 2) == 0) ? (0f - extents.y) : extents.y, ((i & 4) == 0) ? (0f - extents.z) : extents.z));
				if (!any)
				{
					bb = new Bounds(val, Vector3.zero);
					any = true;
				}
				else
				{
					((Bounds)(ref bb)).Encapsulate(val);
				}
			}
		}

		private static int CopyParts(Transform src, Transform dst, HashSet<Renderer> allowed)
		{
			//IL_0223: Unknown result type (might be due to invalid IL or missing references)
			//IL_022a: Expected O, but got Unknown
			//IL_0077: Unknown result type (might be due to invalid IL or missing references)
			//IL_0242: Unknown result type (might be due to invalid IL or missing references)
			//IL_0249: Expected O, but got Unknown
			//IL_0273: Unknown result type (might be due to invalid IL or missing references)
			//IL_0286: Unknown result type (might be due to invalid IL or missing references)
			//IL_0299: Unknown result type (might be due to invalid IL or missing references)
			//IL_0159: Unknown result type (might be due to invalid IL or missing references)
			//IL_0166: Unknown result type (might be due to invalid IL or missing references)
			//IL_018b: Unknown result type (might be due to invalid IL or missing references)
			//IL_01bd: Unknown result type (might be due to invalid IL or missing references)
			int num = 0;
			GameObject gameObject = ((Component)dst).gameObject;
			MeshFilter component = ((Component)src).GetComponent<MeshFilter>();
			MeshRenderer component2 = ((Component)src).GetComponent<MeshRenderer>();
			if (!Plugin.Headless && (Object)(object)component != (Object)null && (Object)(object)component.sharedMesh != (Object)null && (Object)(object)component2 != (Object)null && ((Renderer)component2).enabled && (allowed == null || allowed.Contains((Renderer)(object)component2)))
			{
				gameObject.AddComponent<MeshFilter>().sharedMesh = component.sharedMesh;
				MeshRenderer obj = gameObject.AddComponent<MeshRenderer>();
				((Renderer)obj).sharedMaterials = ((Renderer)component2).sharedMaterials;
				((Renderer)obj).shadowCastingMode = ((Renderer)component2).shadowCastingMode;
				((Renderer)obj).receiveShadows = ((Renderer)component2).receiveShadows;
				num++;
			}
			Collider[] components = ((Component)src).GetComponents<Collider>();
			foreach (Collider val in components)
			{
				if ((Object)(object)val == (Object)null || val.isTrigger || !val.enabled)
				{
					continue;
				}
				Collider val2 = val;
				MeshCollider val3 = (MeshCollider)(object)((val2 is MeshCollider) ? val2 : null);
				if (val3 == null)
				{
					BoxCollider val4 = (BoxCollider)(object)((val2 is BoxCollider) ? val2 : null);
					if (val4 == null)
					{
						SphereCollider val5 = (SphereCollider)(object)((val2 is SphereCollider) ? val2 : null);
						if (val5 == null)
						{
							CapsuleCollider val6 = (CapsuleCollider)(object)((val2 is CapsuleCollider) ? val2 : null);
							if (val6 != null)
							{
								CapsuleCollider obj2 = gameObject.AddComponent<CapsuleCollider>();
								obj2.center = val6.center;
								obj2.radius = val6.radius;
								obj2.height = val6.height;
								obj2.direction = val6.direction;
								((Collider)obj2).sharedMaterial = ((Collider)val6).sharedMaterial;
								num++;
							}
						}
						else
						{
							SphereCollider obj3 = gameObject.AddComponent<SphereCollider>();
							obj3.center = val5.center;
							obj3.radius = val5.radius;
							((Collider)obj3).sharedMaterial = ((Collider)val5).sharedMaterial;
							num++;
						}
					}
					else
					{
						BoxCollider obj4 = gameObject.AddComponent<BoxCollider>();
						obj4.center = val4.center;
						obj4.size = val4.size;
						((Collider)obj4).sharedMaterial = ((Collider)val4).sharedMaterial;
						num++;
					}
				}
				else if ((Object)(object)val3.sharedMesh != (Object)null)
				{
					MeshCollider obj5 = gameObject.AddComponent<MeshCollider>();
					obj5.sharedMesh = val3.sharedMesh;
					obj5.convex = true;
					((Collider)obj5).sharedMaterial = ((Collider)val3).sharedMaterial;
					num++;
				}
			}
			foreach (Transform item in src)
			{
				Transform val7 = item;
				if (((Component)val7).gameObject.activeSelf)
				{
					GameObject val8 = new GameObject(((Object)val7).name);
					val8.layer = ((Component)val7).gameObject.layer;
					val8.transform.SetParent(dst, false);
					val8.transform.localPosition = val7.localPosition;
					val8.transform.localRotation = val7.localRotation;
					val8.transform.localScale = val7.localScale;
					int num2 = CopyParts(val7, val8.transform, allowed);
					if (num2 == 0)
					{
						Object.Destroy((Object)(object)val8);
					}
					num += num2;
				}
			}
			return num;
		}

		private static GameObject SpawnTemplate(WaterVolume wv, Template t, Vector3 pos, float rot, float scale, int seed)
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			//IL_0049: Unknown result type (might be due to invalid IL or missing references)
			//IL_004e: Unknown result type (might be due to invalid IL or missing references)
			//IL_005c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0074: Unknown result type (might be due to invalid IL or missing references)
			//IL_008c: Unknown result type (might be due to invalid IL or missing references)
			//IL_009d: Unknown result type (might be due to invalid IL or missing references)
			GameObject val = Object.Instantiate<GameObject>(t.Go, pos + Vector3.up * t.Offset, Quaternion.Euler(0f, rot, 0f), ((Component)wv).transform);
			((Object)val).name = "ValheimSeasons_IceFloe";
			Vector3 lossyScale = ((Component)wv).transform.lossyScale;
			val.transform.localScale = new Vector3(scale / Mathf.Max(0.0001f, Mathf.Abs(lossyScale.x)), scale / Mathf.Max(0.0001f, Mathf.Abs(lossyScale.y)), scale / Mathf.Max(0.0001f, Mathf.Abs(lossyScale.z)));
			Rigidbody val2 = val.AddComponent<Rigidbody>();
			val2.isKinematic = true;
			val2.useGravity = false;
			val2.interpolation = (RigidbodyInterpolation)1;
			Collider[] componentsInChildren = val.GetComponentsInChildren<Collider>(true);
			foreach (Collider item in componentsInChildren)
			{
				_colliders.Add(item);
			}
			val.AddComponent<Floe>().Init(wv, t.Radius * scale, val2, seed, t.Offset, procedural: false);
			val.SetActive(true);
			return val;
		}

		private static Mesh BuildMesh(float radius, int sides, int seed)
		{
			//IL_006b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0070: Unknown result type (might be due to invalid IL or missing references)
			//IL_00df: Unknown result type (might be due to invalid IL or missing references)
			//IL_00eb: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fa: Unknown result type (might be due to invalid IL or missing references)
			//IL_0104: Unknown result type (might be due to invalid IL or missing references)
			//IL_0109: Unknown result type (might be due to invalid IL or missing references)
			//IL_0115: Unknown result type (might be due to invalid IL or missing references)
			//IL_011e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0125: Unknown result type (might be due to invalid IL or missing references)
			//IL_012c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0133: Unknown result type (might be due to invalid IL or missing references)
			//IL_0138: Unknown result type (might be due to invalid IL or missing references)
			//IL_013a: Unknown result type (might be due to invalid IL or missing references)
			//IL_019b: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a5: Unknown result type (might be due to invalid IL or missing references)
			//IL_01aa: Unknown result type (might be due to invalid IL or missing references)
			//IL_01af: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b9: Unknown result type (might be due to invalid IL or missing references)
			//IL_01be: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d7: Unknown result type (might be due to invalid IL or missing references)
			//IL_01dc: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e1: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e6: Unknown result type (might be due to invalid IL or missing references)
			//IL_0208: Unknown result type (might be due to invalid IL or missing references)
			//IL_020a: Unknown result type (might be due to invalid IL or missing references)
			//IL_020c: Unknown result type (might be due to invalid IL or missing references)
			//IL_020e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0212: Unknown result type (might be due to invalid IL or missing references)
			//IL_023a: Unknown result type (might be due to invalid IL or missing references)
			//IL_023f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0244: Unknown result type (might be due to invalid IL or missing references)
			//IL_0249: Unknown result type (might be due to invalid IL or missing references)
			//IL_0268: Unknown result type (might be due to invalid IL or missing references)
			//IL_0272: Unknown result type (might be due to invalid IL or missing references)
			//IL_0277: Unknown result type (might be due to invalid IL or missing references)
			//IL_027c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0286: Unknown result type (might be due to invalid IL or missing references)
			//IL_028b: Unknown result type (might be due to invalid IL or missing references)
			//IL_02a7: Unknown result type (might be due to invalid IL or missing references)
			//IL_02a9: Unknown result type (might be due to invalid IL or missing references)
			//IL_02ab: Unknown result type (might be due to invalid IL or missing references)
			//IL_02ad: Unknown result type (might be due to invalid IL or missing references)
			//IL_02b1: Unknown result type (might be due to invalid IL or missing references)
			//IL_02dc: Unknown result type (might be due to invalid IL or missing references)
			//IL_02e8: Unknown result type (might be due to invalid IL or missing references)
			//IL_02f7: Unknown result type (might be due to invalid IL or missing references)
			//IL_0301: Unknown result type (might be due to invalid IL or missing references)
			//IL_0306: Unknown result type (might be due to invalid IL or missing references)
			//IL_0312: Unknown result type (might be due to invalid IL or missing references)
			//IL_031b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0322: Unknown result type (might be due to invalid IL or missing references)
			//IL_0329: Unknown result type (might be due to invalid IL or missing references)
			//IL_0330: Unknown result type (might be due to invalid IL or missing references)
			//IL_0335: Unknown result type (might be due to invalid IL or missing references)
			//IL_0337: Unknown result type (might be due to invalid IL or missing references)
			//IL_0385: Unknown result type (might be due to invalid IL or missing references)
			//IL_038a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0395: Unknown result type (might be due to invalid IL or missing references)
			//IL_039d: Unknown result type (might be due to invalid IL or missing references)
			//IL_03a6: Unknown result type (might be due to invalid IL or missing references)
			//IL_03af: Unknown result type (might be due to invalid IL or missing references)
			//IL_03b5: Unknown result type (might be due to invalid IL or missing references)
			//IL_03bb: Unknown result type (might be due to invalid IL or missing references)
			//IL_03c2: Expected O, but got Unknown
			Rng rng = new Rng(seed);
			Vector3[] array = (Vector3[])(object)new Vector3[sides];
			for (int i = 0; i < sides; i++)
			{
				float num = ((float)i + rng.Range(-0.25f, 0.25f)) / (float)sides * (float)Math.PI * 2f;
				float num2 = radius * rng.Range(0.78f, 1f);
				array[i] = new Vector3(Mathf.Cos(num) * num2, 0f, Mathf.Sin(num) * num2);
			}
			float num3 = 0.15f;
			float num4 = -0.65f;
			float num5 = 0.125f;
			Vector2 val = default(Vector2);
			((Vector2)(ref val))..ctor(rng.Next01() * 8f, rng.Next01() * 8f);
			List<Vector3> list = new List<Vector3>();
			List<Vector2> list2 = new List<Vector2>();
			List<int> list3 = new List<int>();
			int count = list.Count;
			list.Add(new Vector3(0f, num3, 0f));
			list2.Add(val);
			for (int j = 0; j < sides; j++)
			{
				Vector3 val2 = array[j] * 0.94f;
				val2.y = num3;
				list.Add(val2);
				list2.Add(new Vector2(val2.x, val2.z) * num5 + val);
			}
			for (int k = 0; k < sides; k++)
			{
				list3.Add(count);
				list3.Add(count + 1 + (k + 1) % sides);
				list3.Add(count + 1 + k);
			}
			for (int l = 0; l < sides; l++)
			{
				int num6 = (l + 1) % sides;
				Vector3 a = array[l] * 0.94f;
				Vector3 a2 = array[num6] * 0.94f;
				a.y = (a2.y = num3);
				Vector3 b = array[l];
				Vector3 b2 = array[num6];
				b.y = (b2.y = num3 - 0.12f);
				Quad(list, list2, list3, a, a2, b2, b, num5, val);
			}
			for (int m = 0; m < sides; m++)
			{
				int num7 = (m + 1) % sides;
				Vector3 a3 = array[m];
				Vector3 a4 = array[num7];
				a3.y = (a4.y = num3 - 0.12f);
				Vector3 b3 = array[m] * 0.9f;
				Vector3 b4 = array[num7] * 0.9f;
				b3.y = (b4.y = num4);
				Quad(list, list2, list3, a3, a4, b4, b3, num5, val);
			}
			count = list.Count;
			list.Add(new Vector3(0f, num4, 0f));
			list2.Add(val);
			for (int n = 0; n < sides; n++)
			{
				Vector3 val3 = array[n] * 0.9f;
				val3.y = num4;
				list.Add(val3);
				list2.Add(new Vector2(val3.x, val3.z) * num5 + val);
			}
			for (int num8 = 0; num8 < sides; num8++)
			{
				list3.Add(count);
				list3.Add(count + 1 + num8);
				list3.Add(count + 1 + (num8 + 1) % sides);
			}
			Mesh val4 = new Mesh
			{
				name = "valheimseasons_floe"
			};
			val4.SetVertices(list);
			val4.SetUVs(0, list2);
			val4.SetTriangles(list3, 0);
			val4.RecalculateNormals();
			val4.RecalculateTangents();
			val4.RecalculateBounds();
			return val4;
		}

		private static void Quad(List<Vector3> v, List<Vector2> uv, List<int> tri, Vector3 a0, Vector3 a1, Vector3 b1, Vector3 b0, float s, Vector2 off)
		{
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_0028: Unknown result type (might be due to invalid IL or missing references)
			//IL_0029: Unknown result type (might be due to invalid IL or missing references)
			//IL_002e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0038: Unknown result type (might be due to invalid IL or missing references)
			//IL_003e: Unknown result type (might be due to invalid IL or missing references)
			//IL_004b: Unknown result type (might be due to invalid IL or missing references)
			//IL_004c: Unknown result type (might be due to invalid IL or missing references)
			//IL_004e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0053: Unknown result type (might be due to invalid IL or missing references)
			//IL_0064: Unknown result type (might be due to invalid IL or missing references)
			//IL_0066: Unknown result type (might be due to invalid IL or missing references)
			//IL_006c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0072: Unknown result type (might be due to invalid IL or missing references)
			//IL_0079: Unknown result type (might be due to invalid IL or missing references)
			//IL_007e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0083: Unknown result type (might be due to invalid IL or missing references)
			//IL_0085: Unknown result type (might be due to invalid IL or missing references)
			//IL_008c: 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_009b: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cb: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d0: Unknown result type (might be due to invalid IL or missing references)
			int count = v.Count;
			v.Add(a0);
			v.Add(a1);
			v.Add(b1);
			v.Add(b0);
			Vector3 val = a1 - a0;
			float magnitude = ((Vector3)(ref val)).magnitude;
			float num = Mathf.Abs(a0.y - b0.y);
			val = a0 - b0;
			float num2 = num + ((Vector3)(ref val)).magnitude * 0.5f;
			Vector2 val2 = off + new Vector2(a0.x, a0.z) * s;
			uv.Add(val2);
			uv.Add(val2 + new Vector2(magnitude * s, 0f));
			uv.Add(val2 + new Vector2(magnitude * s, (0f - num2) * s));
			uv.Add(val2 + new Vector2(0f, (0f - num2) * s));
			tri.Add(count);
			tri.Add(count + 1);
			tri.Add(count + 2);
			tri.Add(count);
			tri.Add(count + 2);
			tri.Add(count + 3);
		}

		internal static void OnShip(Ship ship)
		{
			if (!((Object)(object)ship == (Object)null))
			{
				if (!_ships.Contains(ship))
				{
					_ships.Add(ship);
				}
				IgnoreShip(ship, _colliders);
			}
		}

		private static void IgnoreShip(Ship ship, List<Collider> floes)
		{
			if ((Object)(object)ship == (Object)null || floes.Count == 0)
			{
				return;
			}
			Collider[] componentsInChildren = ((Component)ship).GetComponentsInChildren<Collider>(true);
			foreach (Collider flo in floes)
			{
				if ((Object)(object)flo == (Object)null)
				{
					continue;
				}
				Collider[] array = componentsInChildren;
				foreach (Collider val in array)
				{
					if ((Object)(object)val != (Object)null && !val.isTrigger)
					{
						Physics.IgnoreCollision(val, flo, true);
					}
				}
			}
		}

		private static void Reflect()
		{
			if (_reflected)
			{
				return;
			}
			_reflected = true;
			_surfaceField = AccessTools.Field(typeof(WaterVolume), "m_waterSurface");
			_isAshlands = AccessTools.Method(typeof(WorldGenerator), "IsAshlands", new Type[2]
			{
				typeof(float),
				typeof(float)
			}, (Type[])null);
			if (!(_isAshlands != null) || !_isAshlands.IsStatic || !(_isAshlands.ReturnType == typeof(bool)))
			{
				return;
			}
			try
			{
				_isAshlandsFast = (Func<float, float, bool>)Delegate.CreateDelegate(typeof(Func<float, float, bool>), _isAshlands);
			}
			catch
			{
				_isAshlandsFast = null;
			}
		}

		internal static bool IsExcludedSea(float x, float z)
		{
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			//IL_0020: Invalid comparison between Unknown and I4
			//IL_009e: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a5: Invalid comparison between Unknown and I4
			Reflect();
			try
			{
				if (WorldGenerator.instance != null && (int)WorldGenerator.instance.GetBiome(x, z, 0.02f, false) == 64)
				{
					return true;
				}
				if (_isAshlandsFast != null)
				{
					return _isAshlandsFast(x, z);
				}
				if (_isAshlands != null)
				{
					return (bool)_isAshlands.Invoke(_isAshlands.IsStatic ? null : WorldGenerator.instance, new object[2] { x, z });
				}
				if (WorldGenerator.instance != null)
				{
					return (int)WorldGenerator.instance.GetBiome(x, z, 0.02f, false) == 32;
				}
			}
			catch
			{
			}
			return false;
		}

		private static int Hash(int x, int z)
		{
			int num = (x * 73856093) ^ (z * 19349663) ^ 0x2F6B1A3D;
			int num2 = (num ^ (num >> 13)) * 1540483477;
			return num2 ^ (num2 >> 15);
		}

		private static Material IceMaterial()
		{
			//IL_00b2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cd: Expected O, but got Unknown
			//IL_023c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0241: Unknown result type (might be due to invalid IL or missing references)
			//IL_024c: Unknown result type (might be due to invalid IL or missing references)
			//IL_025c: Expected O, but got Unknown
			//IL_0277: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)_iceMat != (Object)null && (!_iceIsFallback || Time.time - _lastIceScan < 30f))
			{
				return _iceMat;
			}
			_lastIceScan = Time.time;
			string text = (Plugin.IceMaterial.Value ?? "").Trim();
			if (text.Length == 0)
			{
				text = "ice";
			}
			if (!text.Equals("gerado", StringComparison.OrdinalIgnoreCase))
			{
				Material[] array = Resources.FindObjectsOfTypeAll<Material>();
				foreach (Material val in array)
				{
					if (!((Object)(object)val == (Object)null) && !(((Object)val).name.Replace("(Instance)", "").Trim() != text))
					{
						_iceMat = new Material(val)
						{
							name = "valheimseasons_ice_" + text
						};
						Object.DontDestroyOnLoad((Object)(object)_iceMat);
						_iceIsFallback = false;
						ManualLogSource log = Plugin.Log;
						string[] obj = new string[5] { "Gelo usando o material do jogo: ", text, " (shader ", null, null };
						Shader shader = val.shader;
						obj[3] = ((shader != null) ? ((Object)shader).name : null);
						obj[4] = ")";
						log.LogInfo((object)string.Concat(obj));
						return _iceMat;
					}
				}
				if (!_warnedIce)
				{
					_warnedIce = true;
					Plugin.Log.LogInfo((object)("Material de gelo '" + text + "' ainda não carregado (o jogo carrega ao passar perto do Deep North). Usando o gelo gerado por enquanto."));
				}
				if ((Object)(object)_iceMat != (Object)null)
				{
					return _iceMat;
				}
			}
			Shader val2 = null;
			string[] array2 = new string[4] { "Custom/Piece", "Standard", "Legacy Shaders/Diffuse", "Sprites/Default" };
			for (int i = 0; i < array2.Length; i++)
			{
				val2 = Shader.Find(array2[i]);
				if ((Object)(object)val2 != (Object)null)
				{
					break;
				}
			}
			if ((Object)(object)val2 == (Object)null)
			{
				Shader[] array3 = Resources.FindObjectsOfTypeAll<Shader>();
				foreach (Shader val3 in array3)
				{
					if ((Object)(object)val3 != (Object)null && ((Object)val3).name == "Custom/Piece")
					{
						val2 = val3;
						break;
					}
				}
			}
			_iceTex = (((Object)(object)_iceTex != (Object)null) ? _iceTex : MakeIceTexture(512));
			_iceIsFallback = !text.Equals("gerado", StringComparison.OrdinalIgnoreCase);
			_iceMat = new Material(val2)
			{
				name = "valheimseasons_ice",
				mainTexture = (Texture)(object)_iceTex
			};
			if (_iceMat.HasProperty("_Color"))
			{
				_iceMat.SetColor("_Color", Color.white);
			}
			if (_iceMat.HasProperty("_Glossiness"))
			{
				_iceMat.SetFloat("_Glossiness", 0.75f);
			}
			Object.DontDestroyOnLoad((Object)(object)_iceMat);
			return _iceMat;
		}

		internal static void ResetMaterial()
		{
			_iceMat = null;
			_iceIsFallback = false;
			_warnedIce = false;
			if (_frozen)
			{
				MeltAll();
				FreezeAll();
			}
		}

		internal static void RefreshMaterial(Renderer r)
		{
			if (!((Object)(object)r == (Object)null) && _iceIsFallback)
			{
				Material val = IceMaterial();
				if ((Object)(object)r.sharedMaterial != (Object)(object)val)
				{
					r.sharedMaterial = val;
				}
			}
		}

		private static Texture2D MakeIceTexture(int size)
		{
			//IL_014d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0152: Unknown result type (might be due to invalid IL or missing references)
			//IL_015d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0164: Unknown result type (might be due to invalid IL or missing references)
			//IL_016b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0172: Unknown result type (might be due to invalid IL or missing references)
			//IL_0179: Unknown result type (might be due to invalid IL or missing references)
			//IL_0180: Unknown result type (might be due to invalid IL or missing references)
			//IL_0186: Expected O, but got Unknown
			//IL_0187: Expected O, but got Unknown
			//IL_00ab: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ac: Unknown result type (might be due to invalid IL or missing references)
			//IL_00be: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ea: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ec: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fd: Unknown result type (might be due to invalid IL or missing references)
			//IL_010a: Unknown result type (might be due to invalid IL or missing references)
			//IL_010f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0124: Unknown result type (might be due to invalid IL or missing references)
			//IL_0126: Unknown result type (might be due to invalid IL or missing references)
			//IL_012b: Unknown result type (might be due to invalid IL or missing references)
			Color32[] array = (Color32[])(object)new Color32[size * size];
			Color val = default(Color);
			((Color)(ref val))..ctor(0.62f, 0.76f, 0.88f);
			Color val2 = default(Color);
			((Color)(ref val2))..ctor(0.9f, 0.95f, 1f);
			for (int i = 0; i < size; i++)
			{
				for (int j = 0; j < size; j++)
				{
					float u = (float)j / (float)size;
					float v = (float)i / (float)size;
					float num = Tile(u, v, 4f, 4);
					float num2 = Mathf.Abs(Tile(u, v, 9f, 2) - 0.5f);
					float num3 = ((num2 < 0.018f) ? (1f - num2 / 0.018f) : 0f);
					float num4 = Tile(u, v, 24f, 2);
					Color val3 = Color.Lerp(val, val2, Mathf.SmoothStep(0.25f, 0.8f, num));
					val3 = Color.Lerp(val3, Color.white, Mathf.Clamp01((num4 - 0.55f) * 2f) * 0.6f);
					val3 = Color.Lerp(val3, new Color(0.97f, 0.99f, 1f), num3 * 0.8f);
					val3.a = 1f;
					array[i * size + j] = Color32.op_Implicit(val3);
				}
			}
			Texture2D val4 = new Texture2D(size, size, (TextureFormat)4, true)
			{
				name = "valheimseasons_ice_tex",
				wrapMode = (TextureWrapMode)0,
				filterMode = (FilterMode)2,
				anisoLevel = 4
			};
			val4.SetPixels32(array);
			val4.Apply(true);
			Object.DontDestroyOnLoad((Object)val4);
			return val4;
		}

		private static float Fbm(float x, float y, int oct)
		{
			float num = 0f;
			float num2 = 0.5f;
			float num3 = 0f;
			for (int i = 0; i < oct; i++)
			{
				num += Noise.Perlin(x, y) * num2;
				num3 += num2;
				x *= 2.03f;
				y *= 2.03f;
				num2 *= 0.5f;
			}
			return num / num3;
		}

		private static float Tile(float u, float v, float f, int oct)
		{
			float num = Fbm(u * f, v * f, oct);
			float num2 = Fbm((u - 1f) * f, v * f, oct);
			float num3 = Fbm(u * f, (v - 1f) * f, oct);
			float num4 = Fbm((u - 1f) * f, (v - 1f) * f, oct);
			return Mathf.Lerp(Mathf.Lerp(num, num2, u), Mathf.Lerp(num3, num4, u), v);
		}
	}
	internal class Floe : MonoBehaviour
	{
		internal float Radius;

		private WaterVolume _wv;

		private Rigidbody _rb;

		private float _phase;

		private int _skip;

		private Renderer _renderer;

		private float _matTimer;

		private float _yaw;

		private float _offset;

		private bool _procedural;

		private static int _camFrame = -1;

		private static Vector3 _cam;

		internal void Init(WaterVolume wv, float radius, Rigidbody rb, int seed, float offset, bool procedural)
		{
			//IL_0060: Unknown result type (might be due to invalid IL or missing references)
			//IL_0065: Unknown result type (might be due to invalid IL or missing references)
			//IL_0068: Unknown result type (might be due to invalid IL or missing references)
			_wv = wv;
			Radius = radius;
			_rb = rb;
			_phase = (float)(seed & 0xFFFF) / 65535f * (float)Math.PI * 2f;
			_offset = offset;
			_procedural = procedural;
			_renderer = (procedural ? ((Component)this).GetComponent<Renderer>() : null);
			Quaternion rotation = ((Component)this).transform.rotation;
			_yaw = ((Quaternion)(ref rotation)).eulerAngles.y;
		}

		private void FixedUpdate()
		{
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			//IL_0039: Unknown result type (might be due to invalid IL or missing references)
			//IL_008c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0091: Unknown result type (might be due to invalid IL or missing references)
			//IL_0098: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bb: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e9: Unknown result type (might be due to invalid IL or missing references)
			//IL_0100: Unknown result type (might be due to invalid IL or missing references)
			//IL_0105: Unknown result type (might be due to invalid IL or missing references)
			//IL_016c: Unknown result type (might be due to invalid IL or missing references)
			//IL_017a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0180: Unknown result type (might be due to invalid IL or missing references)
			//IL_0199: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ae: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b3: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)_wv == (Object)null || (Object)(object)_rb == (Object)null || Plugin.Headless)
			{
				return;
			}
			Vector3 val = CamPos() - ((Component)this).transform.position;
			float sqrMagnitude = ((Vector3)(ref val)).sqrMagnitude;
			if (sqrMagnitude > 22500f)
			{
				if (++_skip % 25 != 0)
				{
					return;
				}
			}
			else if (sqrMagnitude > 3600f && ++_skip % 3 != 0)
			{
				return;
			}
			Vector3 position = ((Component)this).transform.position;
			float waterSurface;
			try
			{
				waterSurface = _wv.GetWaterSurface(position, 1f);
			}
			catch
			{
				return;
			}
			bool num = sqrMagnitude < 3600f;
			float num2 = (num ? SafeSurface(position + new Vector3(Radius * 0.7f, 0f, 0f), waterSurface) : waterSurface);
			float num3 = Mathf.Clamp(Mathf.Atan2((num ? SafeSurface(position + new Vector3(0f, 0f, Radius * 0.7f), waterSurface) : waterSurface) - waterSurface, Radius * 0.7f) * 57.29578f, -6f, 6f);
			float num4 = Mathf.Clamp((0f - Mathf.Atan2(num2 - waterSurface, Radius * 0.7f)) * 57.29578f, -6f, 6f);
			_rb.MovePosition(new Vector3(position.x, waterSurface + _offset, position.z));
			_rb.MoveRotation(Quaternion.Euler(num3, 0f, num4) * Quaternion.Euler(0f, _yaw, 0f));
			if (_procedural)
			{
				_matTimer += Time.fixedDeltaTime;
				if (_matTimer > 5f)
				{
					_matTimer = 0f;
					FrozenWater.RefreshMaterial(_renderer);
				}
			}
		}

		private static Vector3 CamPos()
		{
			//IL_003c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0032: Unknown result type (might be due to invalid IL or missing references)
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			//IL_0037: Unknown result type (might be due to invalid IL or missing references)
			int frameCount = Time.frameCount;
			if (frameCount != _camFrame)
			{
				_camFrame = frameCount;
				_cam = (((Object)(object)GameCamera.instance != (Object)null) ? ((Component)GameCamera.instance).transform.position : Vector3.zero);
			}
			return _cam;
		}

		private float SafeSurface(Vector3 at, float fallback)
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				return _wv.GetWaterSurface(at, 1f);
			}
			catch
			{
				return fallback;
			}
		}
	}
	[HarmonyPatch]
	internal static class WaterVolume_Awake_Patch
	{
		private static MethodBase TargetMethod()
		{
			return AccessTools.Method(typeof(WaterVolume), "Start", (Type[])null, (Type[])null) ?? AccessTools.Method(typeof(WaterVolume), "Awake", (Type[])null, (Type[])null);
		}

		private static bool Prepare()
		{
			return TargetMethod() != null;
		}

		private static void Postfix(WaterVolume __instance)
		{
			FrozenWater.OnWaterVolumeCreated(__instance);
		}
	}
	[HarmonyPatch]
	internal static class Ship_Awake_Patch
	{
		private static MethodBase TargetMethod()
		{
			return AccessTools.Method(typeof(Ship), "Awake", (Type[])null, (Type[])null);
		}

		private static bool Prepare()
		{
			return TargetMethod() != null;
		}

		private static void Postfix(Ship __instance)
		{
			FrozenWater.OnShip(__instance);
		}
	}
	[HarmonyPatch(typeof(Game), "Start")]
	internal static class Game_Start_Patch
	{
		private static void Postfix()
		{
			SeasonClient.Reset();
			SeasonServer.Reset();
			ConfigValidator.Reset();
			ConflictCheck.Found();
			if (ZRoutedRpc.instance != null)
			{
				SeasonServer.RegisterRpcs();
			}
		}
	}
	[HarmonyPatch]
	internal static class Game_OnDestroy_Patch
	{
		private static MethodBase TargetMethod()
		{
			return AccessTools.Method(typeof(Game), "OnDestroy", (Type[])null, (Type[])null);
		}

		private static bool Prepare()
		{
			return TargetMethod() != null;
		}

		private static void Prefix()
		{
			SeasonEffects.RemoveAll(Player.m_localPlayer);
			SeasonVisuals.Shutdown();
			FrozenWater.Shutdown();
			ProtectedMaterials.Reset();
			SeasonSpawns.Restore();
			WolfPacks.Shutdown();
			CreatureSeasons.Reset();
			WinterForage.Reset();
			CropCalendar.Reset();
			SeasonClient.Reset();
			SeasonServer.Reset();
		}
	}
	[HarmonyPatch(typeof(Player), "OnSpawned")]
	internal static class Player_OnSpawned_Patch
	{
		private static void Postfix(Player __instance)
		{
			if (!((Object)(object)__instance != (Object)(object)Player.m_localPlayer))
			{
				SeasonClient.OnLocalSpawn();
				ConflictCheck.ShowOnce();
			}
		}
	}
	[HarmonyPatch]
	internal static class Plant_GetGrowTime_Patch
	{
		private static MethodBase TargetMethod()
		{
			return AccessTools.Method(typeof(Plant), "GetGrowTime", (Type[])null, (Type[])null);
		}

		private static bool Prepare()
		{
			return TargetMethod() != null;
		}

		private static void Postfix(Plant __instance, ref float __result)
		{
			if (SeasonClient.Active)
			{
				__result *= CropCalendar.GrowMultiplier(__instance);
			}
		}
	}
	[HarmonyPatch(typeof(Terminal), "InitTerminal")]
	internal static class Terminal_InitTerminal_Patch
	{
		[Serializable]
		[CompilerGenerated]
		private sealed class <>c
		{
			public static readonly <>c <>9 = new <>c();

			public static ConsoleEvent <>9__1_0;

			internal void <Postfix>b__1_0(ConsoleEventArgs args)
			{
				Run(args);
			}
		}

		private static bool _done;

		private static void Postfix()
		{
			//IL_0041: Unknown result type (might be due to invalid IL or missing references)
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0031: Unknown result type (might be due to invalid IL or missing references)
			//IL_0037: Expected O, but got Unknown
			if (_done)
			{
				return;
			}
			_done = true;
			object obj = <>c.<>9__1_0;
			if (obj == null)
			{
				ConsoleEvent val = delegate(ConsoleEventArgs args)
				{
					Run(args);
				};
				<>c.<>9__1_0 = val;
				obj = (object)val;
			}
			new ConsoleCommand("estacao", "[info | teste <estação|off> | teste transicao <etapa> | lobos | material | set <primavera|verao|outono|inverno|auto>] - estações do ValheimSeasons", (ConsoleEvent)obj, false, false, false, false, false, false, (ConsoleOptionsFetcher)null, false, false, false);
		}

		private static void Run(ConsoleEventArgs args)
		{
			//IL_0144: Unknown result type (might be due to invalid IL or missing references)
			//IL_0149: Unknown result type (might be due to invalid IL or missing references)
			//IL_0153: Unknown result type (might be due to invalid IL or missing references)
			//IL_0158: Unknown result type (might be due to invalid IL or missing references)
			//IL_015d: Unknown result type (might be due to invalid IL or missing references)
			//IL_016e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0173: Unknown result type (might be due to invalid IL or missing references)
			//IL_019f: Unknown result type (might be due to invalid IL or missing references)
			//IL_018e: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a4: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b7: Unknown result type (might be due to invalid IL or missing references)
			//IL_01bc: Unknown result type (might be due to invalid IL or missing references)
			//IL_01be: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c0: Unknown result type (might be due to invalid IL or missing references)
			//IL_0257: Unknown result type (might be due to invalid IL or missing references)
			//IL_0259: Unknown result type (might be due to invalid IL or missing references)
			string[] args2 = args.Args;
			if (args2.Length < 2 || args2[1].ToLowerInvariant() == "info")
			{
				args.Context.AddString(SeasonClient.Describe(SeasonClient.CanTest()));
				return;
			}
			string text = args2[1].ToLowerInvariant();
			string text2 = ((args2.Length > 2) ? args2[2] : "");
			string s = ((args2.Length > 3) ? args2[3] : "");
			switch (text)
			{
			case "teste":
			case "test":
			{
				string text3 = text2.ToLowerInvariant();
				switch (text3)
				{
				case "transicao":
				case "transição":
				case "camada":
				{
					int.TryParse(s, out var result);
					SeasonClient.SetTestLayer(result);
					break;
				}
				case "off":
				case "":
					SeasonClient.SetTest(on: false, Season.Summer);
					break;
				default:
				{
					if (SeasonText.TryParse(text3, out var season))
					{
						SeasonClient.SetTest(on: true, season);
					}
					else
					{
						args.Context.AddString("Uso: estacao teste <primavera|verao|outono|inverno|off> | estacao teste transicao <0-etapas>");
					}
					break;
				}
				}
				break;
			}
			case "material":
			{
				Player localPlayer = Player.m_localPlayer;
				if ((Object)(object)localPlayer == (Object)null)
				{
					args.Context.AddString("Entre num mundo primeiro.");
					break;
				}
				Vector3 val = ((Component)localPlayer).transform.position + Vector3.up * 1.5f;
				HashSet<string> hashSet = new HashSet<string>();
				Vector3[] array = (Vector3[])(object)new Vector3[2]
				{
					Vector3.down,
					((Object)(object)GameCamera.instance != (Object)null) ? ((Component)GameCamera.instance).transform.forward : ((Component)localPlayer).transform.forward
				};
				RaycastHit val3 = default(RaycastHit);
				foreach (Vector3 val2 in array)
				{
					if (!Physics.Raycast(val, val2, ref val3, 30f, -1, (QueryTriggerInteraction)1))
					{
						continue;
					}
					List<Renderer> list = new List<Renderer>(((Component)((RaycastHit)(ref val3)).collider).GetComponentsInParent<Renderer>());
					list.AddRange(((Component)((RaycastHit)(ref val3)).collider).GetComponentsInChildren<Renderer>());
					foreach (Renderer item in list)
					{
						Material[] sharedMaterials = item.sharedMaterials;
						foreach (Material val4 in sharedMaterials)
						{
							if ((Object)(object)val4 != (Object)null && hashSet.Add(((Object)val4).name))
							{
								Terminal context = args.Context;
								string[] obj = new string[8]
								{
									"[Estações] ",
									(val2 == Vector3.down) ? "embaixo" : "na frente",
									": ",
									((Object)((RaycastHit)(ref val3)).collider).name,
									" -> material '",
									((Object)val4).name.Replace(" (Instance)", ""),
									"' | shader ",
									null
								};
								Shader shader = val4.shader;
								obj[7] = ((shader != null) ? ((Object)shader).name : null);
								context.AddString(string.Concat(obj));
							}
						}
					}
				}
				if (hashSet.Count == 0)
				{
					args.Context.AddString("[Estações] nenhum material encontrado (olhe pra algo ou fique em cima)");
				}
				break;
			}
			case "lobos":
			case "wolves":
				if (!SeasonClient.CanTest())
				{
					args.Context.AddString("[Estações] Precisa do devcommands ligado pra chamar lobos.");
				}
				else if ((Object)(object)Player.m_localPlayer == (Object)null)
				{
					args.Context.AddString("Entre num mundo primeiro.");
				}
				else if (!SeasonClient.Active)
				{
					args.Context.AddString("Estações ainda não carregaram.");
				}
				else
				{
					args.Context.AddString("[Estações] " + WolfPacks.Spawn(Player.m_localPlayer, force: true));
				}
				break;
			case "set":
				if (text2.Length == 0)
				{
					args.Context.AddString("Uso: estacao set <primavera|verao|outono|inverno|auto>");
				}
				else
				{
					Send("set", text2);
				}
				break;
			default:
				args.Context.AddString("Uso: estacao [info | teste <estação|off> | teste transicao <etapa> | set <estação|auto>]");
				break;
			}
		}

		private static void Send(string cmd, string arg)
		{
			if (ZRoutedRpc.instance == null || (Object)(object)ZNet.instance == (Object)null)
			{
				Console instance = Console.instance;
				if (instance != null)
				{
					instance.Print("Entre num mundo primeiro.");
				}
			}
			else
			{
				ZRoutedRpc.instance.InvokeRoutedRPC(Compat.ServerPeerId(), "ValheimSeasons_Admin", new object[2] { cmd, arg });
			}
		}
	}
	internal static class ConflictCheck
	{
		private static readonly string[] Known = new string[1] { "seasonality" };

		private static readonly HashSet<string> KnownNames = new HashSet<string> { "seasons", "seasonsmod", "worldseasons", "valheimseasonsmod" };

		private static List<string> _found;

		private static bool _shown;

		internal static List<string> Found()
		{
			if (_found != null)
			{
				return _found;
			}
			_found = new List<string>();
			try
			{
				foreach (KeyValuePair<string, PluginInfo> pluginInfo in Chainloader.PluginInfos)
				{
					PluginInfo value = pluginInfo.Value;
					BepInPlugin val = ((value != null) ? value.Metadata : null);
					if (val == null || val.GUID == "glitnir.valheimseasons")
					{
						continue;
					}
					string text = (val.GUID ?? "").ToLowerInvariant();
					string text2 = (val.Name ?? "").ToLowerInvariant();
					if (text2.Contains("menu") || text.Contains("menu"))
					{
						continue;
					}
					string text3 = text2.Replace(" ", "").Replace("_", "").Replace("-", "");
					bool flag = KnownNames.Contains(text3);
					string[] known = Known;
					foreach (string value2 in known)
					{
						if (text.Contains(value2) || text3.Contains(value2))
						{
							flag = true;
						}
					}
					if (flag)
					{
						_found.Add(val.Name + " (" + val.GUID + ")");
					}
				}
			}
			catch (Exception ex)
			{
				Plugin.Log.LogDebug((object)("Checagem de conflito falhou: " + ex.Message));
			}
			foreach (string item in _found)
			{
				Plugin.Log.LogWarning((object)("Outro mod de estações instalado: " + item + ". Usar os dois juntos pode bagunçar texturas, clima e mecânicas. Recomendado manter só um."));
			}
			return _found;
		}

		internal static void ShowOnce()
		{
			if (_shown || Plugin.Headless || (Object)(object)Player.m_localPlayer == (Object)null)
			{
				return;
			}
			_shown = true;
			List<string> list = Found();
			if (list.Count != 0)
			{
				string text = "ValheimSeasons: outro mod de estações instalado (" + string.Join(", ", list) + "). Recomendado usar só um.";
				((Character)Player.m_localPlayer).Message((MessageType)2, text, 0, (Sprite)null, false);
				Console instance = Console.instance;
				if (instance != null)
				{
					instance.Print("<color=#ffb36b>[Estações]</color> " + text);
				}
			}
		}
	}
	internal static class ConfigWatcher
	{
		private static DateTime _lastWrite;

		private static float _timer;

		private static float _changedAt = -1f;

		internal static void Init()
		{
			try
			{
				_lastWrite = File.GetLastWriteTimeUtc(Plugin.Cfg.ConfigFilePath);
			}
			catch
			{
			}
		}

		internal static void Tick(float dt)
		{
			if (Plugin.Cfg == null)
			{
				return;
			}
			_timer += dt;
			if (_changedAt >= 0f && Time.realtimeSinceStartup - _changedAt > 1f)
			{
				_changedAt = -1f;
				Reload();
			}
			else
			{
				if (_timer < 3f)
				{
					return;
				}
				_timer = 0f;
				try
				{
					DateTime lastWriteTimeUtc = File.GetLastWriteTimeUtc(Plugin.Cfg.ConfigFilePath);
					if (lastWriteTimeUtc != _lastWrite)
					{
						_lastWrite = lastWriteTimeUtc;
						_changedAt = Time.realtimeSinceStartup;
					}
				}
				catch
				{
				}
			}
		}

		private static void Reload()
		{
			try
			{
				Plugin.Cfg.Reload();
				_lastWrite = File.GetLastWriteTimeUtc(Plugin.Cfg.ConfigFilePath);
				ConfigValidator.Reset();
				Plugin.Log.LogInfo((object)"Config recarregada (arquivo salvo). No servidor, as regras novas vão pros jogadores em alguns segundos.");
			}
			catch (Exception ex)
			{
				Plugin.Log.LogWarning((object)("Não consegui recarregar a config: " + ex.Message));
			}
		}
	}
	internal static class OrphanCleanup
	{
		internal static void Run(ConfigFile cfg)
		{
			try
			{
				if (!(AccessTools.Property(typeof(ConfigFile), "OrphanedEntries")?.GetValue(cfg) is IDictionary { Count: not 0 } dictionary))
				{
					return;
				}
				List<string> list = new List<string>();
				foreach (object key in dictionary.Keys)
				{
					list.Add(key.ToString());
				}
				dictionary.Clear();
				cfg.Save();
				Plugin.Log.LogInfo((object)string.Format("Config: removidas {0} opção(ões) antiga(s) que não existem mais: {1}", list.Count, string.Join(", ", list)));
			}
			catch (Exception ex)
			{
				Plugin.Log.LogDebug((object)("Limpeza da config antiga falhou: " + ex.Message));
			}
		}
	}
	internal static class ConfigValidator
	{
		private static string _lastKey;

		private static bool _prefabsChecked;

		private static readonly string[] Tokens = new string[7] { "dano", "dmg", "vel", "spd", "vida", "hp", "spawn" };

		private static readonly HashSet<string> SeasonWords = new HashSet<string> { "spring", "primavera", "summer", "verao", "verão", "fall", "outono", "autumn", "winter", "inverno" };

		internal static void Reset()
		{
			_lastKey = null;
			_prefabsChecked = false;
		}

		internal static void Validate(SeasonMechanics m)
		{
			if (m == null)
			{
				return;
			}
			bool flag = (Object)(object)ZNetScene.instance != (Object)null;
			string text = Signature(m);
			if (text == _lastKey && (_prefabsChecked || !flag))
			{
				return;
			}
			_lastKey = text;
			_prefabsChecked = flag;
			HashSet<string> prefabs = null;
			HashSet<string> creatures = null;
			if (flag)
			{
				prefabs = PrefabNames(out creatures);
			}
			List<string> list = new List<string>();
			KeyValuePair<string, string>[] array = new KeyValuePair<string, string>[4]
			{
				new KeyValuePair<string, string>("CreatureSpring", m.CreatureSpring),
				new KeyValuePair<string, string>("CreatureSummer", m.CreatureSummer),
				new KeyValuePair<string, string>("CreatureFall", m.CreatureFall),
				new KeyValuePair<string, string>("CreatureWinter", m.CreatureWinter)
			};
			for (int i = 0; i < array.Length; i++)
			{
				KeyValuePair<string, string> keyValuePair = array[i];
				CheckCreatures(keyValuePair.Key, keyValuePair.Value, creatures, list);
			}
			array = new KeyValuePair<string, string>[4]
			{
				new KeyValuePair<string, string>("SpawnSpring", m.SpawnSpring),
				new KeyValuePair<string, string>("SpawnSummer", m.SpawnSummer),
				new KeyValuePair<string, string>("SpawnFall", m.SpawnFall),
				new KeyValuePair<string, string>("SpawnWinter", m.SpawnWinter)
			};
			for (int i = 0; i < array.Length; i++)
			{
				KeyValuePair<string, string> keyValuePair2 = array[i];
				CheckPairs(keyValuePair2.Key, keyValuePair2.Value, prefabs, list);
			}
			CheckFour("PickableRegrow", m.PickableRegrow, list);
			CheckFour("BeeTime", m.BeeTime, list);
			CheckFour("MushroomRegrow", m.MushroomRegrow, list);
			string[] array2 = (m.SummerHeatPhases ?? "").Split(',');
			for (int i = 0; i < array2.Length; i++)
			{
				string text2 = array2[i].Trim();
				if (text2.Length > 0)
				{
					switch (text2)
					{
					case "1":
					case "2":
					case "3":
					case "4":
						continue;
					}
					list.Add("SummerHeatPhases: '" + text2 + "' não é fase (use 1 a 4, separadas por vírgula; vazio = verão inteiro).");
				}
			}
			CheckCalendar(m.CropSeasons, list);
			CheckEvents(m.EventSeasons, list);
			string text3 = (m.SeasonTimer ?? "").Trim().ToLowerInvariant();
			if (!text3.StartsWith("h") && !text3.StartsWith("d") && !text3.StartsWith("i"))
			{
				list.Add("SeasonTimer = '" + m.SeasonTimer + "': use horas, dias ou imersivo (usando 'horas').");
			}
			foreach (string item in list)
			{
				Plugin.Log.LogWarning((object)("[Config] " + item));
			}
			if (list.Count > 0)
			{
				Plugin.Log.LogWarning((object)$"[Config] {list.Count} problema(s) na seção \"6 - Mecânicas\". As partes com erro são ignoradas; o resto funciona.");
			}
		}

		private static string Signature(SeasonMechanics m)
		{
			return string.Join("|", m.CreatureSpring, m.CreatureSummer, m.CreatureFall, m.CreatureWinter, m.SpawnSpring, m.SpawnSummer, m.SpawnFall, m.SpawnWinter, m.PickableRegrow, m.BeeTime, m.CropSeasons, m.EventSeasons, m.SeasonTimer, m.MushroomRegrow, m.SummerHeatPhases);
		}

		private static void CheckCreatures(string opt, string src, HashSet<string> creatures, List<string> problems)
		{
			string[] array = (src ?? "").Split(',');
			for (int i = 0; i < array.Length; i++)
			{
				string text = array[i].Trim();
				if (text.Length == 0)
				{
					continue;
				}
				int num = text.IndexOf(':');
				if (num <= 0)
				{
					problems.Add(Hint(opt, text, "falta 'Criatura:' antes dos efeitos"));
					continue;
				}
				string text2 = text.Substring(0, num).Trim();
				string[] array2 = text.Substring(num + 1).Split(new char[3] { ' ', ';', '|' }, StringSplitOptions.RemoveEmptyEntries);
				foreach (string text3 in array2)
				{
					string text4 = text3.Trim().ToLowerInvariant();
					if (text4 == "dia" || text4 == "day")
					{
						continue;
					}
					string text5 = null;
					string[] tokens = Tokens;
					foreach (string text6 in tokens)
					{
						if (text4.StartsWith(text6))
						{
							text5 = text6;
							break;
						}
					}
					float result;
					if (text5 == null)
					{
						problems.Add(opt + ": efeito '" + text3 + "' desconhecido em '" + text + "' (use dano, vel, vida, spawn ou dia).");
					}
					else if (!float.TryParse(text4.Substring(text5.Length).TrimStart('=', 'x', ':'), NumberStyles.Float, CultureInfo.InvariantCulture, out result))
					{
						problems.Add(opt + ": número inválido em '" + text3 + "' ('" + text + "'). Use ponto: " + text5 + "1.2");
					}
				}
				if (creatures != null && !AnyContains(creatures, text2.ToLowerInvariant()))
				{
					problems.Add(opt + ": nenhuma criatura do jogo tem '" + text2 + "' no nome (confira a grafia do prefab).");
				}
			}
		}

		private static void CheckPairs(string opt, string src, HashSet<string> prefabs, List<string> problems)
		{
			string[] array = (src ?? "").Split(',');
			for (int i = 0; i < array.Length; i++)
			{
				string text = array[i].Trim();
				if (text.Length == 0)
				{
					continue;
				}
				int num = text.IndexOf(':');
				if (num <= 0)
				{
					problems.Add(Hint(opt, text, "formato é Prefab:multiplicador"));
					continue;
				}
				string text2 = text.Substring(0, num).Trim();
				if (!float.TryParse(text.Substring(num + 1).Trim(), NumberStyles.Float, CultureInfo.InvariantCulture, out var _))
				{
					problems.Add(opt + ": número inválido em '" + text + "'. Use ponto: " + text2 + ":1.5");
				}
				if (prefabs != null && !AnyGlob(prefabs, text2.ToLowerInvariant()))
				{
					problems.Add(opt + ": nenhum prefab do jogo bate com '" + text2 + "' (aceita *, ex.: Fish*).");
				}
			}
		}

		private static void CheckFour(string opt, string src, List<string> problems)
		{
			string[] array = (src ?? "").Split(',');
			if (array.Length != 4)
			{
				problems.Add(opt + " = '" + src + "': precisa de 4 números (primavera,verão,outono,inverno), com ponto. Ex.: 0.5,1,1,3");
				return;
			}
			string[] array2 = array;
			foreach (string text in array2)
			{
				if (!float.TryParse(text.Trim(), NumberStyles.Float, CultureInfo.InvariantCulture, out var _))
				{
					problems.Add(opt + ": '" + text.Trim() + "' não é número (use ponto: 0.5).");
					break;
				}
			}
		}

		private static void CheckCalendar(string src, List<string> problems)
		{
			string[] array = (src ?? "").Split(',');
			for (int i = 0; i < array.Length; i++)
			{
				string text = array[i].Trim();
				if (text.Length == 0)
				{
					continue;
				}
				int num = text.IndexOf(':');
				if (num <= 0)
				{
					problems.Add(Hin