Decompiled source of Fimbulvetr v1.1.0

Fimbulvetr.dll

Decompiled 11 hours ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Configuration;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETFramework,Version=v4.6.2", FrameworkDisplayName = "")]
[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 Fimbulvetr
{
	[BepInPlugin("com.chase.fimbulvetr", "Fimbulvetr", "1.1.0")]
	public class Plugin : BaseUnityPlugin
	{
		private class Fragment
		{
			public Vector3 center;

			public Vector3 halfSize;

			public Quaternion rotation;

			public float radius;
		}

		private class SheetState
		{
			public Fragment[] fragments;

			public float fullHealth;

			public double lastTick;

			public float lastStamp;

			public float progress;

			public float awayCarry;
		}

		private struct Heat
		{
			public Vector3 pos;

			public bool pyre;
		}

		[HarmonyPatch(typeof(MineRock5), "Awake")]
		private static class RegisterSheet
		{
			private static void Postfix(MineRock5 __instance)
			{
				if (!s_replaying && (Object)(object)Instance != (Object)null && Instance.IsIceSheet(__instance))
				{
					s_sheets.Add(__instance);
				}
			}
		}

		[HarmonyPatch(typeof(Destructible), "Awake")]
		private static class RegisterWholeSheet
		{
			private static void Postfix(Destructible __instance)
			{
				MineRock5 val = (((Object)(object)__instance.m_spawnWhenDestroyed != (Object)null) ? __instance.m_spawnWhenDestroyed.GetComponent<MineRock5>() : null);
				if (!s_replaying && (Object)(object)val != (Object)null && (Object)(object)Instance != (Object)null && Instance.IsIceSheet(val))
				{
					s_wholeSheets.RemoveWhere((Destructible d) => (Object)(object)d == (Object)null);
					s_wholeSheets.Add(__instance);
				}
			}
		}

		[HarmonyPatch(typeof(Fireplace), "Awake")]
		private static class RegisterFire
		{
			private static void Postfix(Fireplace __instance)
			{
				s_fires.RemoveWhere((Fireplace f) => (Object)(object)f == (Object)null);
				s_fires.Add(__instance);
			}
		}

		[HarmonyPatch(typeof(Piece), "Awake")]
		private static class RegisterPyre
		{
			private static void Postfix(Piece __instance)
			{
				if (__instance.m_name != "$piece_faderember")
				{
					return;
				}
				s_pyres.Add(__instance);
				if (!s_loggedPyre && (Object)(object)Instance != (Object)null)
				{
					s_loggedPyre = true;
					List<string> list = new List<string>();
					Component[] components = ((Component)__instance).GetComponents<Component>();
					foreach (Component val in components)
					{
						list.Add(((object)val).GetType().Name);
					}
					((BaseUnityPlugin)Instance).Logger.LogInfo((object)("Eternal Pyre found: " + ((Object)((Component)__instance).gameObject).name + " (" + string.Join(", ", list) + ")"));
				}
			}
		}

		[HarmonyPatch(typeof(MineRock5), "DamageArea")]
		private static class KeepBrokenSheet
		{
			private static void Prefix(MineRock5 __instance)
			{
				s_breaking = (((Object)(object)Instance != (Object)null && Instance.m_enabled.Value && Instance.m_iceRefreeze.Value && s_sheets.Contains(__instance)) ? __instance : null);
			}

			private static void Postfix(MineRock5 __instance)
			{
				if ((Object)(object)s_breaking == (Object)(object)__instance)
				{
					f_mrAllDestroyed.SetValue(__instance, false);
				}
				s_breaking = null;
			}
		}

		[HarmonyPatch(typeof(ZNetView), "Destroy")]
		private static class SkipSheetDestroy
		{
			private static bool Prefix(ZNetView __instance)
			{
				if (!((Object)(object)s_breaking == (Object)null))
				{
					return (Object)(object)((Component)__instance).gameObject != (Object)(object)((Component)s_breaking).gameObject;
				}
				return true;
			}
		}

		private class ZoneState
		{
			public bool[] deepNorth;

			public byte[] shelter;

			public float shelterCheckedAt;

			public double lastTick;

			public float lastSave;

			public bool dirty;

			public float pending;
		}

		[HarmonyPatch(typeof(TerrainComp), "Save")]
		private static class StampSaveTime
		{
			private static void Postfix(TerrainComp __instance)
			{
				//IL_000b: Unknown result type (might be due to invalid IL or missing references)
				//IL_0011: Expected O, but got Unknown
				//IL_003d: Unknown result type (might be due to invalid IL or missing references)
				try
				{
					ZNetView val = (ZNetView)f_nview.GetValue(__instance);
					if ((Object)(object)val != (Object)null && val.IsValid() && val.IsOwner() && (Object)(object)ZNet.instance != (Object)null && TouchesDeepNorth(((Component)__instance).transform.position))
					{
						ZDO zDO = val.GetZDO();
						zDO.Set(s_lastSnowTime, (long)ZNet.instance.GetTimeSeconds());
						f_lastDataRevision.SetValue(__instance, zDO.DataRevision);
					}
				}
				catch
				{
				}
			}
		}

		[HarmonyPatch(typeof(ZNet), "Shutdown")]
		private static class SaveOnShutdown
		{
			private static void Prefix()
			{
				try
				{
					Instance?.SaveAll();
				}
				catch
				{
				}
			}
		}

		[HarmonyPatch(typeof(Terminal), "InitTerminal")]
		private static class Commands
		{
			[Serializable]
			[CompilerGenerated]
			private sealed class <>c
			{
				public static readonly <>c <>9 = new <>c();

				public static ConsoleEvent <>9__0_0;

				internal void <Postfix>b__0_0(ConsoleEventArgs args)
				{
					if ((Object)(object)Instance == (Object)null)
					{
						return;
					}
					if (args.Length > 1)
					{
						string text = args[1].ToLowerInvariant();
						if (text == "disable" || text == "enable")
						{
							Instance.m_enabled.Value = text == "enable";
							Instance.m_zones.Clear();
							Instance.m_sheetStates.Clear();
							Instance.m_zonesChecked.Clear();
							Instance.m_resumeTime = (((Object)(object)ZNet.instance != (Object)null) ? ZNet.instance.GetTimeSeconds() : 0.0);
						}
						else
						{
							Instance.m_force = ((text == "off") ? "" : text);
						}
					}
					args.Context.AddString(Instance.Status());
				}
			}

			private static void Postfix()
			{
				//IL_0033: Unknown result type (might be due to invalid IL or missing references)
				//IL_001e: Unknown result type (might be due to invalid IL or missing references)
				//IL_0023: Unknown result type (might be due to invalid IL or missing references)
				//IL_0029: Expected O, but got Unknown
				object obj = <>c.<>9__0_0;
				if (obj == null)
				{
					ConsoleEvent val = delegate(ConsoleEventArgs args)
					{
						if (!((Object)(object)Instance == (Object)null))
						{
							if (args.Length > 1)
							{
								string text = args[1].ToLowerInvariant();
								if (text == "disable" || text == "enable")
								{
									Instance.m_enabled.Value = text == "enable";
									Instance.m_zones.Clear();
									Instance.m_sheetStates.Clear();
									Instance.m_zonesChecked.Clear();
									Instance.m_resumeTime = (((Object)(object)ZNet.instance != (Object)null) ? ZNet.instance.GetTimeSeconds() : 0.0);
								}
								else
								{
									Instance.m_force = ((text == "off") ? "" : text);
								}
							}
							args.Context.AddString(Instance.Status());
						}
					};
					<>c.<>9__0_0 = val;
					obj = (object)val;
				}
				new ConsoleCommand("fimbul", "[calm|snow|storm|off|enable|disable] Deep North snow regrowth and ice refreezing: show status and cost, force a weather rate, or switch it off", (ConsoleEvent)obj, false, false, false, false, false, false, (ConsoleOptionsFetcher)null, false, false, false);
			}
		}

		private struct Original
		{
			public string prefab;

			public string frac;

			public Vector3 pos;

			public Quaternion rot;

			public Vector3 scale;
		}

		[HarmonyPatch(typeof(ZoneSystem), "IsBlocked")]
		private static class ReplayBlockCheck
		{
			private static readonly RaycastHit[] s_hits = (RaycastHit[])(object)new RaycastHit[32];

			private static bool Prefix(Vector3 p, ref bool __result)
			{
				//IL_0048: 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)
				if (!s_replaying)
				{
					return true;
				}
				if (s_blockMaskNoPieces == 0)
				{
					s_blockMaskNoPieces = LayerMask.GetMask(new string[3] { "Default", "static_solid", "Default_small" });
				}
				p.y += 2000f;
				int num = Physics.RaycastNonAlloc(p, Vector3.down, s_hits, 10000f, s_blockMaskNoPieces);
				__result = false;
				for (int i = 0; i < num; i++)
				{
					ZNetView componentInParent = ((Component)((RaycastHit)(ref s_hits[i])).collider).GetComponentInParent<ZNetView>();
					if (!((Object)(object)componentInParent != (Object)null) || componentInParent.GetZDO() == null || !s_iceNames.Contains(ZdoPrefabName(componentInParent)))
					{
						__result = true;
						break;
					}
				}
				return false;
			}
		}

		private const string PyrePieceName = "$piece_faderember";

		private static readonly int s_iceLastTime = StringExtensionMethods.GetStableHashCode("fimbul_iceLast");

		private static readonly Type t_hitArea = AccessTools.Inner(typeof(MineRock5), "HitArea");

		private static readonly FieldInfo f_hitAreas = AccessTools.Field(typeof(MineRock5), "m_hitAreas");

		private static readonly FieldInfo f_haHealth = AccessTools.Field(t_hitArea, "m_health");

		private static readonly FieldInfo f_haMesh = AccessTools.Field(t_hitArea, "m_meshFilter");

		private static readonly FieldInfo f_mrNview = AccessTools.Field(typeof(MineRock5), "m_nview");

		private static readonly FieldInfo f_mrAllDestroyed = AccessTools.Field(typeof(MineRock5), "m_allDestroyed");

		private static readonly FieldInfo f_mrLastRevision = AccessTools.Field(typeof(MineRock5), "m_lastDataRevision");

		private static readonly MethodInfo m_loadHealth = AccessTools.Method(typeof(MineRock5), "LoadHealth", (Type[])null, (Type[])null);

		private static readonly MethodInfo m_saveHealth = AccessTools.Method(typeof(MineRock5), "SaveHealth", (Type[])null, (Type[])null);

		private static readonly HashSet<MineRock5> s_sheets = new HashSet<MineRock5>();

		private static readonly HashSet<Piece> s_pyres = new HashSet<Piece>();

		private static readonly HashSet<Fireplace> s_fires = new HashSet<Fireplace>();

		private static readonly HashSet<Destructible> s_wholeSheets = new HashSet<Destructible>();

		private static bool s_loggedPyre;

		private static MineRock5 s_breaking;

		private ConfigEntry<bool> m_iceRefreeze;

		private ConfigEntry<string> m_icePrefabs;

		private ConfigEntry<float> m_iceMinutes;

		private ConfigEntry<float> m_icePlayerDistance;

		private ConfigEntry<bool> m_iceHeat;

		private ConfigEntry<float> m_iceHeatMargin;

		private ConfigEntry<bool> m_icePyre;

		private ConfigEntry<float> m_icePyreRadius;

		private readonly Dictionary<MineRock5, SheetState> m_sheetStates = new Dictionary<MineRock5, SheetState>();

		private readonly List<MineRock5> m_sheetScratch = new List<MineRock5>();

		private readonly List<int> m_eligible = new List<int>();

		private readonly Collider[] m_overlap = (Collider[])(object)new Collider[8];

		private int m_blockMask;

		private int m_refrozen;

		private int m_thawed;

		private readonly Dictionary<string, bool> m_iceKinds = new Dictionary<string, bool>();

		private float m_newSheetCheck;

		private readonly List<MineRock5> m_gone2 = new List<MineRock5>();

		private readonly List<Heat> m_heat = new List<Heat>();

		private readonly List<ZDO> m_heatZdos = new List<ZDO>();

		private readonly Dictionary<int, int> m_heatKinds = new Dictionary<int, int>();

		private static readonly MethodInfo m_handleDestroyed = AccessTools.Method(typeof(ZDOMan), "HandleDestroyedZDO", (Type[])null, (Type[])null);

		public const string Guid = "com.chase.fimbulvetr";

		public const string Version = "1.1.0";

		private const float MetresAtFullMask = 2f;

		private static readonly int s_lastSnowTime = StringExtensionMethods.GetStableHashCode("fimbul_lastSnow");

		private static readonly FieldInfo f_instances = AccessTools.Field(typeof(TerrainComp), "s_instances");

		private static readonly FieldInfo f_paintMask = AccessTools.Field(typeof(TerrainComp), "m_paintMask");

		private static readonly FieldInfo f_modifiedPaint = AccessTools.Field(typeof(TerrainComp), "m_modifiedPaint");

		private static readonly FieldInfo f_hmap = AccessTools.Field(typeof(TerrainComp), "m_hmap");

		private static readonly FieldInfo f_nview = AccessTools.Field(typeof(TerrainComp), "m_nview");

		private static readonly FieldInfo f_initialized = AccessTools.Field(typeof(TerrainComp), "m_initialized");

		private static readonly FieldInfo f_lastDataRevision = AccessTools.Field(typeof(TerrainComp), "m_lastDataRevision");

		private static readonly FieldInfo f_buildData = AccessTools.Field(typeof(Heightmap), "m_buildData");

		private static readonly MethodInfo m_save = AccessTools.Method(typeof(TerrainComp), "Save", (Type[])null, (Type[])null);

		internal static Plugin Instance;

		private ConfigEntry<bool> m_enabled;

		private ConfigEntry<float> m_calmRate;

		private ConfigEntry<float> m_snowfallRate;

		private ConfigEntry<float> m_stormRate;

		private ConfigEntry<bool> m_catchUp;

		private ConfigEntry<bool> m_protectRoofs;

		private ConfigEntry<bool> m_protectShields;

		private ConfigEntry<bool> m_fireMelts;

		private ConfigEntry<float> m_range;

		private ConfigEntry<float> m_tickInterval;

		private ConfigEntry<float> m_saveInterval;

		private ConfigEntry<float> m_minStep;

		private ConfigEntry<int> m_maxRedrawsPerTick;

		private readonly Dictionary<TerrainComp, ZoneState> m_zones = new Dictionary<TerrainComp, ZoneState>();

		private readonly List<TerrainComp> m_scratch = new List<TerrainComp>();

		private readonly List<TerrainComp> m_gone = new List<TerrainComp>();

		private readonly HashSet<TerrainComp> m_toSync = new HashSet<TerrainComp>();

		private float m_timer;

		private readonly Stopwatch m_watch = new Stopwatch();

		private double m_tickMs;

		private int m_ticks;

		private int m_redraws;

		private float m_statsSince;

		private int m_shelterMask;

		private int m_pieceMask;

		private float m_minSnowBuildup = -1f;

		private float m_maxSnowBuildup = -1f;

		private double m_resumeTime;

		internal string m_force = "";

		private static readonly MethodInfo m_placeVegetation = AccessTools.Method(typeof(ZoneSystem), "PlaceVegetation", (Type[])null, (Type[])null);

		private static readonly MethodInfo m_updateMesh = AccessTools.Method(typeof(MineRock5), "UpdateMesh", (Type[])null, (Type[])null);

		private static readonly Type t_clearArea = AccessTools.Inner(typeof(ZoneSystem), "ClearArea");

		private static readonly FieldInfo f_spawnSystems = AccessTools.Field(typeof(SpawnSystem), "m_instances");

		private static readonly FieldInfo f_spawnNview = AccessTools.Field(typeof(SpawnSystem), "m_nview");

		private static bool s_replaying;

		private static int s_blockMaskNoPieces;

		private ConfigEntry<bool> m_iceRestore;

		private List<ZoneVegetation> m_iceVegetation;

		private readonly Dictionary<string, string> m_iceFrac = new Dictionary<string, string>();

		private static readonly HashSet<string> s_iceNames = new HashSet<string>();

		private readonly HashSet<Vector2s> m_zonesChecked = new HashSet<Vector2s>();

		private readonly Dictionary<Vector2s, float> m_zoneSeen = new Dictionary<Vector2s, float>();

		private readonly List<GameObject> m_ghosts = new List<GameObject>();

		private int m_restored;

		private int m_removedDuplicates;

		private static readonly int s_restoredFlag = StringExtensionMethods.GetStableHashCode("fimbul_restored");

		private readonly List<ZDO> m_zoneZdos = new List<ZDO>();

		private readonly List<ZDO> m_iceZdos = new List<ZDO>();

		private void BindIce()
		{
			m_iceRefreeze = ((BaseUnityPlugin)this).Config.Bind<bool>("Ice", "RefreezeIce", true, "Broken Deep North Ice Sheets slowly freeze back over, faster in snowstorms. A sheet broken completely is kept so it can refreeze.");
			m_icePrefabs = ((BaseUnityPlugin)this).Config.Bind<string>("Ice", "IcePrefabs", "IceShore", "Comma-separated prefab name prefixes of the ice sheets that refreeze. Any mineable rock that drops Ice also counts.");
			m_iceMinutes = ((BaseUnityPlugin)this).Config.Bind<float>("Ice", "MinutesPerPiece", 6f, "Real minutes for one broken piece of a sheet to refreeze in light snowfall. Scales with the snow rates: about 5x slower with no snow falling, 5x faster in the heaviest blizzard (default rates).");
			m_icePlayerDistance = ((BaseUnityPlugin)this).Config.Bind<float>("Ice", "PlayerDistance", 30f, "Ice never refreezes within this many metres of a player, so nobody gets frozen in or sees it pop back.");
			m_iceHeat = ((BaseUnityPlugin)this).Config.Bind<bool>("Ice", "HeatKeepsWaterOpen", true, "Ice doesn't refreeze where the heat of a campfire, hearth, brazier or other heat source reaches it.");
			m_iceHeatMargin = ((BaseUnityPlugin)this).Config.Bind<float>("Ice", "FireReach", 8f, "Ice doesn't refreeze within this many metres of a lit fire: torches, campfires, braziers, hearths and the like.");
			m_icePyre = ((BaseUnityPlugin)this).Config.Bind<bool>("Ice", "EternalPyreThaws", true, "A lit Eternal Pyre thaws all ice within PyreRadius, a piece at a time, and keeps it from refreezing. Thawed ice drops nothing.");
			m_icePyreRadius = ((BaseUnityPlugin)this).Config.Bind<float>("Ice", "PyreRadius", 40f, "Metres around a lit Eternal Pyre that are kept ice-free.");
			BindRestore();
		}

		internal static string PrefabNameOf(MineRock5 rock)
		{
			ZNetView component = ((Component)rock).GetComponent<ZNetView>();
			ZDO val = ((component != null) ? component.GetZDO() : null);
			if (val != null && (Object)(object)ZNetScene.instance != (Object)null)
			{
				GameObject prefab = ZNetScene.instance.GetPrefab(val.GetPrefab());
				if ((Object)(object)prefab != (Object)null)
				{
					return ((Object)prefab).name;
				}
			}
			return Utils.GetPrefabName(((Component)rock).gameObject);
		}

		private bool IsIceSheet(MineRock5 rock)
		{
			//IL_0047: 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_0060: Unknown result type (might be due to invalid IL or missing references)
			string text = PrefabNameOf(rock);
			if (m_iceKinds.TryGetValue(text, out var value))
			{
				return value;
			}
			bool flag = IsIcePrefab(text);
			if (!flag && rock.m_dropItems != null)
			{
				foreach (DropData drop in rock.m_dropItems.m_drops)
				{
					ItemDrop val = (((Object)(object)drop.m_item != (Object)null) ? drop.m_item.GetComponent<ItemDrop>() : null);
					if ((Object)(object)val != (Object)null && val.m_itemData?.m_shared?.m_name == "$item_ice")
					{
						flag = true;
						break;
					}
				}
			}
			m_iceKinds[text] = flag;
			((BaseUnityPlugin)this).Logger.LogInfo((object)("Mineable rock kind " + text + " (" + rock.m_name + "): " + (flag ? "ice sheet, will refreeze" : "not ice")));
			return flag;
		}

		private float IceRate(float snowRate)
		{
			float num = Mathf.Max(0.01f, m_snowfallRate.Value);
			return snowRate / num / (Mathf.Max(0.1f, m_iceMinutes.Value) * 60f);
		}

		private bool HasNewSheet()
		{
			//IL_006d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0073: Expected O, but got Unknown
			//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_0098: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a3: 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_00c6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d8: Unknown result type (might be due to invalid IL or missing references)
			if (!m_iceRefreeze.Value || Time.time - m_newSheetCheck < 0.5f)
			{
				return false;
			}
			m_newSheetCheck = Time.time;
			foreach (MineRock5 s_sheet in s_sheets)
			{
				if ((Object)(object)s_sheet != (Object)null && !m_sheetStates.ContainsKey(s_sheet))
				{
					ZNetView val = (ZNetView)f_mrNview.GetValue(s_sheet);
					Vector3 position = ((Component)s_sheet).transform.position;
					if ((Object)(object)val != (Object)null && val.IsValid() && val.IsOwner() && Vector3.Distance(position, ((Component)Player.m_localPlayer).transform.position) <= m_range.Value + 30f && WorldGenerator.IsDeepnorth(position.x, position.z) && ZNetScene.instance.IsAreaReady(position))
					{
						return true;
					}
				}
			}
			return false;
		}

		private void IceTick(double now)
		{
			//IL_0086: Unknown result type (might be due to invalid IL or missing references)
			//IL_008b: 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_0103: Expected O, but got Unknown
			//IL_0139: Unknown result type (might be due to invalid IL or missing references)
			//IL_013e: 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_0142: Unknown result type (might be due to invalid IL or missing references)
			//IL_014e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0155: 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_01c8: Unknown result type (might be due to invalid IL or missing references)
			//IL_020f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0219: Expected O, but got Unknown
			//IL_0445: Unknown result type (might be due to invalid IL or missing references)
			//IL_0447: Unknown result type (might be due to invalid IL or missing references)
			if (!m_iceRefreeze.Value)
			{
				return;
			}
			CollectHeat();
			CrackWholeSheetsNearPyres();
			if (m_blockMask == 0)
			{
				m_blockMask = LayerMask.GetMask(new string[5] { "vehicle", "character", "character_net", "character_ghost", "item" });
			}
			string label;
			float num = IceRate(CurrentRate(out label));
			float num2 = IceRate(m_calmRate.Value);
			Vector3 position = ((Component)Player.m_localPlayer).transform.position;
			float num3 = m_range.Value + 30f;
			m_sheetScratch.Clear();
			m_sheetScratch.AddRange(s_sheets);
			foreach (MineRock5 item in m_sheetScratch)
			{
				if ((Object)(object)item == (Object)null)
				{
					s_sheets.Remove(item);
					continue;
				}
				ZNetView val = (ZNetView)f_mrNview.GetValue(item);
				if ((Object)(object)val == (Object)null || !val.IsValid() || !val.IsOwner())
				{
					m_sheetStates.Remove(item);
					continue;
				}
				Vector3 position2 = ((Component)item).transform.position;
				if (Vector3.Distance(position2, position) > num3 || !WorldGenerator.IsDeepnorth(position2.x, position2.z) || !SurroundingsLoaded(position2))
				{
					continue;
				}
				ZDO zDO = val.GetZDO();
				m_loadHealth.Invoke(item, null);
				IList list = (IList)f_hitAreas.GetValue(item);
				if (list == null || list.Count == 0)
				{
					continue;
				}
				if (!m_sheetStates.TryGetValue(item, out var value))
				{
					if (!ZNetScene.instance.IsAreaReady(position2))
					{
						continue;
					}
					value = new SheetState();
					value.fragments = new Fragment[list.Count];
					for (int i = 0; i < list.Count; i++)
					{
						value.fragments[i] = MeasureFragment((MeshFilter)f_haMesh.GetValue(list[i]));
					}
					value.fullHealth = item.m_health + (float)Game.m_worldLevel * item.m_health * Game.instance.m_worldLevelMineHPMultiplier;
					long num4 = zDO.GetLong(s_iceLastTime, 0L);
					value.lastTick = ((m_catchUp.Value && num4 > 0) ? Math.Max(num4, m_resumeTime) : now);
					value.lastStamp = Time.time;
					m_sheetStates[item] = value;
				}
				double num5 = now - value.lastTick;
				value.lastTick = now;
				bool flag = false;
				if (m_icePyre.Value)
				{
					for (int j = 0; j < list.Count; j++)
					{
						if ((float)f_haHealth.GetValue(list[j]) > 0f && NearLitPyre(value.fragments[j]))
						{
							SetFragment(item, val, list[j], j, 0f);
							m_thawed++;
							flag = true;
						}
					}
				}
				bool anyIntact = false;
				int num6 = 0;
				for (int k = 0; k < list.Count; k++)
				{
					if ((float)f_haHealth.GetValue(list[k]) > 0f)
					{
						anyIntact = true;
					}
					else
					{
						num6++;
					}
				}
				if (num5 > 0.0 && num6 > 0)
				{
					double num7 = Math.Min(num5, m_tickInterval.Value * 2f);
					double num8 = num5 - num7;
					if (num8 > 0.0)
					{
						float num9 = (float)(num8 * (double)num2) + value.awayCarry;
						int num10 = Freeze(item, val, value, list, Mathf.FloorToInt(num9), ignorePlayers: true, ref anyIntact);
						value.awayCarry = Mathf.Min(num9 - (float)Mathf.FloorToInt(num9), 1f);
						if (num10 > 0)
						{
							flag = true;
							num6 -= num10;
							((BaseUnityPlugin)this).Logger.LogInfo((object)$"Ice caught up {num10} pieces for {num8 / 60.0:0} min away, {Vector3.Distance(position2, position):0} m from you");
						}
					}
					value.progress = Mathf.Min(value.progress + (float)(num7 * (double)num), (float)num6);
					int num11 = Mathf.FloorToInt(value.progress);
					if (num11 > 0)
					{
						int num12 = Freeze(item, val, value, list, num11, ignorePlayers: false, ref anyIntact);
						value.progress -= num12;
						flag = flag || num12 > 0;
					}
				}
				bool flag2 = false;
				for (int l = 0; l < list.Count; l++)
				{
					if (flag2)
					{
						break;
					}
					flag2 = (float)f_haHealth.GetValue(list[l]) <= 0f;
				}
				if (flag2 && (flag || Time.time - value.lastStamp >= 60f))
				{
					zDO.Set(s_iceLastTime, (long)now);
					value.lastStamp = Time.time;
					flag = true;
				}
				if (flag)
				{
					m_saveHealth.Invoke(item, null);
				}
			}
			m_gone2.Clear();
			foreach (KeyValuePair<MineRock5, SheetState> sheetState in m_sheetStates)
			{
				if ((Object)(object)sheetState.Key == (Object)null)
				{
					m_gone2.Add(sheetState.Key);
				}
			}
			foreach (MineRock5 item2 in m_gone2)
			{
				m_sheetStates.Remove(item2);
			}
		}

		private static void SetFragment(MineRock5 rock, ZNetView nview, object area, int index, float health)
		{
			f_haHealth.SetValue(area, health);
			nview.InvokeRPC(ZNetView.Everybody, "RPC_SetAreaHealth", new object[2] { index, health });
		}

		private static Fragment MeasureFragment(MeshFilter filter)
		{
			//IL_0034: 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_0067: 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_0078: Unknown result type (might be due to invalid IL or missing references)
			//IL_007d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0082: Unknown result type (might be due to invalid IL or missing references)
			//IL_008a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0090: Unknown result type (might be due to invalid IL or missing references)
			//IL_0095: Unknown result type (might be due to invalid IL or missing references)
			//IL_009a: 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)
			//IL_00d5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00dc: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e1: 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_0102: 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_003f: 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_004a: Unknown result type (might be due to invalid IL or missing references)
			//IL_004f: Unknown result type (might be due to invalid IL or missing references)
			Fragment fragment = new Fragment();
			if ((Object)(object)filter == (Object)null || (Object)(object)filter.sharedMesh == (Object)null)
			{
				fragment.center = (((Object)(object)filter != (Object)null) ? ((Component)filter).transform.position : Vector3.zero);
				fragment.halfSize = Vector3.one;
				fragment.rotation = Quaternion.identity;
				fragment.radius = 2f;
				return fragment;
			}
			Bounds bounds = filter.sharedMesh.bounds;
			Transform transform = ((Component)filter).transform;
			fragment.center = transform.TransformPoint(((Bounds)(ref bounds)).center);
			fragment.halfSize = Vector3.Scale(((Bounds)(ref bounds)).extents, transform.lossyScale);
			fragment.halfSize = new Vector3(Mathf.Abs(fragment.halfSize.x), Mathf.Abs(fragment.halfSize.y), Mathf.Abs(fragment.halfSize.z));
			fragment.rotation = transform.rotation;
			Vector2 val = new Vector2(fragment.halfSize.x, fragment.halfSize.z);
			fragment.radius = ((Vector2)(ref val)).magnitude;
			return fragment;
		}

		private int Freeze(MineRock5 rock, ZNetView nview, SheetState state, IList areas, int count, bool ignorePlayers, ref bool anyIntact)
		{
			if (count <= 0)
			{
				return 0;
			}
			m_eligible.Clear();
			for (int i = 0; i < areas.Count; i++)
			{
				if ((float)f_haHealth.GetValue(areas[i]) <= 0f && CanRefreeze(state.fragments[i], ignorePlayers))
				{
					m_eligible.Add(i);
				}
			}
			int num = 0;
			while (num < count && m_eligible.Count > 0)
			{
				int index = (anyIntact ? ClosestToIntact(state, areas, m_eligible) : 0);
				int index2 = m_eligible[index];
				m_eligible.RemoveAt(index);
				SetFragment(rock, nview, areas[index2], index2, state.fullHealth);
				anyIntact = true;
				num++;
				m_refrozen++;
			}
			return num;
		}

		private bool CanRefreeze(Fragment f, bool ignorePlayers = false)
		{
			//IL_0004: Unknown result type (might be due to invalid IL or missing references)
			//IL_0075: Unknown result type (might be due to invalid IL or missing references)
			//IL_0089: Unknown result type (might be due to invalid IL or missing references)
			//IL_008e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0093: Unknown result type (might be due to invalid IL or missing references)
			//IL_0095: Unknown result type (might be due to invalid IL or missing references)
			//IL_009a: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a2: 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)
			if (!ignorePlayers && Player.IsPlayerInRange(f.center, m_icePlayerDistance.Value + f.radius))
			{
				return false;
			}
			if (m_icePyre.Value && NearLitPyre(f))
			{
				return false;
			}
			if (m_iceHeat.Value && (NearLitFire(f) || (Object)(object)EffectArea.IsPointInsideArea(f.center, (Type)1, f.radius + 2f) != (Object)null))
			{
				return false;
			}
			Vector3 val = f.halfSize + new Vector3(0.5f, 1.5f, 0.5f);
			return Physics.OverlapBoxNonAlloc(f.center, val, m_overlap, f.rotation, m_blockMask) == 0;
		}

		private void CollectHeat()
		{
			//IL_0045: Unknown result type (might be due to invalid IL or missing references)
			//IL_004a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0052: Unknown result type (might be due to invalid IL or missing references)
			//IL_0177: Unknown result type (might be due to invalid IL or missing references)
			//IL_017c: Unknown result type (might be due to invalid IL or missing references)
			m_heat.Clear();
			if ((s_sheets.Count == 0 && s_wholeSheets.Count == 0) || ZDOMan.instance == null)
			{
				return;
			}
			m_heatZdos.Clear();
			ZDOMan.instance.FindSectorObjects(ZoneSystem.GetZone(((Component)Player.m_localPlayer).transform.position), new SimulationDistance(3, 0, true), m_heatZdos, (List<ZDO>)null);
			foreach (ZDO heatZdo in m_heatZdos)
			{
				int prefab = heatZdo.GetPrefab();
				if (!m_heatKinds.TryGetValue(prefab, out var value))
				{
					value = 0;
					GameObject prefab2 = ZNetScene.instance.GetPrefab(prefab);
					if ((Object)(object)prefab2 != (Object)null)
					{
						Fireplace component = prefab2.GetComponent<Fireplace>();
						Piece component2 = prefab2.GetComponent<Piece>();
						if ((Object)(object)component2 != (Object)null && component2.m_name == "$piece_faderember")
						{
							value = 2 | (((Object)(object)component == (Object)null || component.m_infiniteFuel) ? 4 : 0);
						}
						else if ((Object)(object)component != (Object)null)
						{
							value = 1 | (component.m_infiniteFuel ? 4 : 0);
						}
					}
					m_heatKinds[prefab] = value;
				}
				if (value != 0)
				{
					bool pyre = (value & 2) != 0;
					bool flag = (value & 4) != 0;
					if (heatZdo.GetInt(ZDOVars.s_state, 1) == 1 && (flag || heatZdo.GetFloat(ZDOVars.s_fuel, 0f) > 0f))
					{
						m_heat.Add(new Heat
						{
							pos = heatZdo.GetPosition(),
							pyre = pyre
						});
					}
				}
			}
		}

		private static bool SurroundingsLoaded(Vector3 pos)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			//IL_001c: 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)
			Vector2s zone = ZoneSystem.GetZone(pos);
			for (int i = -1; i <= 1; i++)
			{
				for (int j = -1; j <= 1; j++)
				{
					if (!ZoneSystem.instance.IsZoneLoaded(new Vector2s(zone.x + i, zone.y + j)))
					{
						return false;
					}
				}
			}
			return true;
		}

		private bool NearLitFire(Fragment f)
		{
			//IL_0028: 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_0033: 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_0039: Unknown result type (might be due to invalid IL or missing references)
			//IL_003f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0046: 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)
			float num = m_iceHeatMargin.Value + f.radius;
			foreach (Heat item in m_heat)
			{
				Vector3 val = item.pos - f.center;
				if (val.x * val.x + val.z * val.z <= num * num)
				{
					return true;
				}
			}
			return false;
		}

		private bool NearLitPyre(Fragment f)
		{
			//IL_0032: 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_003d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0042: Unknown result type (might be due to invalid IL or missing references)
			//IL_0043: 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_0050: 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)
			float num = m_icePyreRadius.Value + f.radius;
			foreach (Heat item in m_heat)
			{
				if (item.pyre)
				{
					Vector3 val = item.pos - f.center;
					if (val.x * val.x + val.z * val.z <= num * num)
					{
						return true;
					}
				}
			}
			return false;
		}

		private static int ClosestToIntact(SheetState state, IList areas, List<int> eligible)
		{
			//IL_001a: 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_004c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0051: Unknown result type (might be due to invalid IL or missing references)
			//IL_0052: Unknown result type (might be due to invalid IL or missing references)
			//IL_0057: Unknown result type (might be due to invalid IL or missing references)
			int result = 0;
			float num = float.MaxValue;
			for (int i = 0; i < eligible.Count; i++)
			{
				Vector3 center = state.fragments[eligible[i]].center;
				for (int j = 0; j < areas.Count; j++)
				{
					if (!((float)f_haHealth.GetValue(areas[j]) <= 0f))
					{
						Vector3 val = state.fragments[j].center - center;
						float sqrMagnitude = ((Vector3)(ref val)).sqrMagnitude;
						if (sqrMagnitude < num)
						{
							num = sqrMagnitude;
							result = i;
						}
					}
				}
			}
			return result;
		}

		internal string IceStatus()
		{
			int num = 0;
			int num2 = 0;
			foreach (KeyValuePair<MineRock5, SheetState> sheetState in m_sheetStates)
			{
				if ((Object)(object)sheetState.Key == (Object)null)
				{
					continue;
				}
				num++;
				IList list = (IList)f_hitAreas.GetValue(sheetState.Key);
				int num3 = 0;
				while (list != null && num3 < list.Count)
				{
					if ((float)f_haHealth.GetValue(list[num3]) <= 0f)
					{
						num2++;
					}
					num3++;
				}
			}
			int num4 = 0;
			int num5 = 0;
			foreach (Heat item in m_heat)
			{
				if (item.pyre)
				{
					num4++;
				}
				else
				{
					num5++;
				}
			}
			string result = (m_iceRefreeze.Value ? $"Ice: {num} sheets tracked, {num2} pieces open, {m_refrozen} refrozen and {m_thawed} thawed by a pyre, {m_restored} missing sheets restored, {m_removedDuplicates} duplicates removed (since last check), {num4} lit Eternal Pyres and {num5} lit fires nearby" : "Ice: refreezing off");
			m_refrozen = 0;
			m_restored = 0;
			m_removedDuplicates = 0;
			m_thawed = 0;
			return result;
		}

		private void CrackWholeSheetsNearPyres()
		{
			//IL_0067: 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_0090: Unknown result type (might be due to invalid IL or missing references)
			//IL_0095: Unknown result type (might be due to invalid IL or missing references)
			//IL_009d: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c4: Unknown result type (might be due to invalid IL or missing references)
			//IL_0101: Unknown result type (might be due to invalid IL or missing references)
			if (!m_icePyre.Value)
			{
				return;
			}
			foreach (Destructible s_wholeSheet in s_wholeSheets)
			{
				if ((Object)(object)s_wholeSheet == (Object)null)
				{
					continue;
				}
				ZNetView component = ((Component)s_wholeSheet).GetComponent<ZNetView>();
				if ((Object)(object)component == (Object)null || !component.IsValid() || !component.IsOwner())
				{
					continue;
				}
				Fragment f = new Fragment
				{
					center = ((Component)s_wholeSheet).transform.position,
					radius = SheetRadius(s_wholeSheet)
				};
				if (NearLitPyre(f))
				{
					Vector3 position = ((Component)s_wholeSheet).transform.position;
					GameObject val = Object.Instantiate<GameObject>(s_wholeSheet.m_spawnWhenDestroyed, position, ((Component)s_wholeSheet).transform.rotation);
					ZNetView component2 = val.GetComponent<ZNetView>();
					if (component2 != null)
					{
						component2.SetLocalScale(((Component)s_wholeSheet).transform.localScale);
					}
					ZDO zDO = component.GetZDO();
					ZNetScene.instance.Destroy(((Component)s_wholeSheet).gameObject);
					ForgetZdo(zDO);
					OpenUnderHeat(val.GetComponent<MineRock5>());
					((BaseUnityPlugin)this).Logger.LogInfo((object)$"Eternal Pyre cracked a whole ice sheet at {position:F0}");
				}
			}
		}

		internal static void ForgetZdo(ZDO zdo)
		{
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			if (zdo != null && zdo.IsValid() && ZDOMan.instance != null)
			{
				m_handleDestroyed.Invoke(ZDOMan.instance, new object[1] { zdo.m_uid });
			}
		}

		private void OpenUnderHeat(MineRock5 rock)
		{
			//IL_0017: 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_0078: Expected O, but got Unknown
			ZNetView val = ((!((Object)(object)rock != (Object)null)) ? ((ZNetView)null) : ((ZNetView)f_mrNview.GetValue(rock)));
			IList list = (((Object)(object)rock != (Object)null) ? ((IList)f_hitAreas.GetValue(rock)) : null);
			if ((Object)(object)val == (Object)null || !val.IsValid() || list == null)
			{
				return;
			}
			bool flag = false;
			foreach (object item in list)
			{
				Fragment f = MeasureFragment((MeshFilter)f_haMesh.GetValue(item));
				if (NearLitPyre(f) || (m_iceHeat.Value && NearLitFire(f)))
				{
					f_haHealth.SetValue(item, 0f);
					m_thawed++;
					flag = true;
				}
			}
			if (flag)
			{
				val.GetZDO().Set(s_iceLastTime, (long)ZNet.instance.GetTimeSeconds());
				m_saveHealth.Invoke(rock, null);
				m_updateMesh.Invoke(rock, null);
			}
		}

		private static float SheetRadius(Destructible whole)
		{
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			//IL_0019: 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_0027: 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_0034: Unknown result type (might be due to invalid IL or missing references)
			//IL_003b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0042: Unknown result type (might be due to invalid IL or missing references)
			//IL_0047: Unknown result type (might be due to invalid IL or missing references)
			//IL_0052: 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_0068: Unknown result type (might be due to invalid IL or missing references)
			//IL_006d: Unknown result type (might be due to invalid IL or missing references)
			float num = 0f;
			Collider[] componentsInChildren = ((Component)whole).GetComponentsInChildren<Collider>();
			for (int i = 0; i < componentsInChildren.Length; i++)
			{
				Bounds bounds = componentsInChildren[i].bounds;
				Vector3 val = ((Bounds)(ref bounds)).center - ((Component)whole).transform.position;
				float num2 = num;
				Vector2 val2 = new Vector2(val.x, val.z);
				float magnitude = ((Vector2)(ref val2)).magnitude;
				val2 = new Vector2(((Bounds)(ref bounds)).extents.x, ((Bounds)(ref bounds)).extents.z);
				num = Mathf.Max(num2, magnitude + ((Vector2)(ref val2)).magnitude * 0.7f);
			}
			if (!(num > 0f))
			{
				return 10f;
			}
			return num;
		}

		private void Awake()
		{
			//IL_01da: Unknown result type (might be due to invalid IL or missing references)
			Instance = this;
			m_enabled = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "Enabled", true, "Let Deep North ground snow build back up.");
			m_calmRate = ((BaseUnityPlugin)this).Config.Bind<float>("Rates", "CalmRate", 1f, "Centimetres of snow per real minute when no snow is falling (drift).");
			m_snowfallRate = ((BaseUnityPlugin)this).Config.Bind<float>("Rates", "SnowfallRate", 5f, "Centimetres per real minute in the lightest snowfall.");
			m_stormRate = ((BaseUnityPlugin)this).Config.Bind<float>("Rates", "StormRate", 25f, "Centimetres per real minute in the heaviest blizzard. Weather in between is interpolated.");
			m_catchUp = ((BaseUnityPlugin)this).Config.Bind<bool>("Rates", "CatchUpWhileAway", true, "When you come back to an area (or after sleeping), add the snow that fell meanwhile at the calm rate.");
			m_protectRoofs = ((BaseUnityPlugin)this).Config.Bind<bool>("Shelter", "KeepRoofedGroundClear", true, "No snow builds up on ground with a building piece above it (floors, roofs).");
			m_protectShields = ((BaseUnityPlugin)this).Config.Bind<bool>("Shelter", "KeepShieldedGroundClear", true, "No snow builds up inside a Shield Generator's dome.");
			m_fireMelts = ((BaseUnityPlugin)this).Config.Bind<bool>("Shelter", "KeepHeatedGroundClear", true, "No snow builds up inside the heat area of fires and other heat sources.");
			m_range = ((BaseUnityPlugin)this).Config.Bind<float>("Performance", "Range", 150f, "Only zones within this many metres of you are updated.");
			m_tickInterval = ((BaseUnityPlugin)this).Config.Bind<float>("Performance", "TickSeconds", 2f, "How often the snow grows locally.");
			m_saveInterval = ((BaseUnityPlugin)this).Config.Bind<float>("Performance", "SaveSeconds", 20f, "How often grown snow is saved to the world and sent to other players.");
			m_minStep = ((BaseUnityPlugin)this).Config.Bind<float>("Performance", "MinStepCm", 2f, "Snow is applied (and the terrain redrawn) only once this many centimetres have built up in an area.");
			m_maxRedrawsPerTick = ((BaseUnityPlugin)this).Config.Bind<int>("Performance", "MaxRedrawsPerTick", 2, "At most this many terrain areas are redrawn per tick; the rest wait for the next one.");
			BindIce();
			new Harmony("com.chase.fimbulvetr").PatchAll(typeof(Plugin).Assembly);
			((BaseUnityPlugin)this).Logger.LogInfo((object)"Fimbulvetr 1.1.0 loaded");
		}

		private void Update()
		{
			if (!m_enabled.Value || (Object)(object)Player.m_localPlayer == (Object)null || (Object)(object)ZNet.instance == (Object)null || (Object)(object)EnvMan.instance == (Object)null || WorldGenerator.instance == null)
			{
				return;
			}
			m_timer += Time.deltaTime;
			if (m_timer < m_tickInterval.Value && !HasNewSheet())
			{
				return;
			}
			m_timer = 0f;
			try
			{
				m_watch.Restart();
				Tick();
				IceTick(ZNet.instance.GetTimeSeconds());
				RestoreTick();
				m_watch.Stop();
				m_tickMs += m_watch.Elapsed.TotalMilliseconds;
				m_ticks++;
			}
			catch (Exception ex)
			{
				((BaseUnityPlugin)this).Logger.LogError((object)ex);
			}
		}

		private void Tick()
		{
			//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_0152: Unknown result type (might be due to invalid IL or missing references)
			//IL_0157: 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_0160: Unknown result type (might be due to invalid IL or missing references)
			//IL_0167: 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_0175: 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_018a: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a2: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a9: Expected O, but got Unknown
			//IL_01ce: Unknown result type (might be due to invalid IL or missing references)
			if (m_shelterMask == 0)
			{
				m_shelterMask = LayerMask.GetMask(new string[2] { "piece", "static_solid" });
				m_pieceMask = LayerMask.GetMask(new string[1] { "piece" });
			}
			InitWeatherScale();
			double timeSeconds = ZNet.instance.GetTimeSeconds();
			string label;
			float num = CurrentRate(out label) / 100f / 2f / 60f;
			float num2 = m_calmRate.Value / 100f / 2f / 60f;
			Vector3 position = ((Component)Player.m_localPlayer).transform.position;
			float num3 = m_range.Value + 45f;
			float num4 = m_minStep.Value / 100f / 2f;
			int num5 = 0;
			m_scratch.Clear();
			m_scratch.AddRange((List<TerrainComp>)f_instances.GetValue(null));
			foreach (TerrainComp item in m_scratch)
			{
				if ((Object)(object)item == (Object)null || !(bool)f_initialized.GetValue(item))
				{
					continue;
				}
				if (!item.IsOwner())
				{
					m_zones.Remove(item);
					continue;
				}
				Vector3 position2 = ((Component)item).transform.position;
				Vector2 val = new Vector2(position2.x - position.x, position2.z - position.z);
				if (((Vector2)(ref val)).magnitude > num3 || !TouchesDeepNorth(position2))
				{
					continue;
				}
				Heightmap val2 = (Heightmap)f_hmap.GetValue(item);
				if ((Object)(object)val2 == (Object)null || val2.IsDistantLod)
				{
					continue;
				}
				ZDO zDO = ((ZNetView)f_nview.GetValue(item)).GetZDO();
				if (!m_zones.TryGetValue(item, out var value))
				{
					value = new ZoneState();
					long num6 = zDO.GetLong(s_lastSnowTime, 0L);
					value.lastTick = ((m_catchUp.Value && num6 > 0) ? Math.Max(num6, m_resumeTime) : timeSeconds);
					value.lastSave = Time.time;
					m_zones[item] = value;
					m_toSync.Add(item);
				}
				double num7 = timeSeconds - value.lastTick;
				value.lastTick = timeSeconds;
				if (num7 <= 0.0)
				{
					continue;
				}
				double num8 = Math.Min(num7, m_tickInterval.Value * 2f);
				value.pending += (float)(num8 * (double)num + (num7 - num8) * (double)num2);
				if (value.pending >= num4 && num5 < m_maxRedrawsPerTick.Value)
				{
					float pending = value.pending;
					value.pending = 0f;
					if (Grow(item, val2, value, pending))
					{
						m_toSync.Add(item);
						val2.Poke(1, true);
						value.dirty = true;
						num5++;
						m_redraws++;
					}
				}
				if (value.dirty && Time.time - value.lastSave >= m_saveInterval.Value)
				{
					SaveZone(item);
					value.dirty = false;
					value.lastSave = Time.time;
				}
			}
			foreach (TerrainComp item2 in m_toSync)
			{
				if ((Object)(object)item2 != (Object)null)
				{
					SyncEdges(item2);
				}
			}
			m_toSync.Clear();
			m_gone.Clear();
			foreach (KeyValuePair<TerrainComp, ZoneState> zone in m_zones)
			{
				if ((Object)(object)zone.Key == (Object)null)
				{
					m_gone.Add(zone.Key);
				}
			}
			foreach (TerrainComp item3 in m_gone)
			{
				m_zones.Remove(item3);
			}
		}

		private void SyncEdges(TerrainComp a)
		{
			//IL_001c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0022: Expected O, but got Unknown
			//IL_00d9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e4: 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_00ee: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f0: 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_0132: Unknown result type (might be due to invalid IL or missing references)
			//IL_0167: Unknown result type (might be due to invalid IL or missing references)
			//IL_016e: Expected O, but got Unknown
			//IL_0145: Unknown result type (might be due to invalid IL or missing references)
			//IL_026a: Unknown result type (might be due to invalid IL or missing references)
			//IL_026f: 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_02ae: Unknown result type (might be due to invalid IL or missing references)
			//IL_032e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0324: Unknown result type (might be due to invalid IL or missing references)
			//IL_0333: Unknown result type (might be due to invalid IL or missing references)
			//IL_034b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0340: Unknown result type (might be due to invalid IL or missing references)
			//IL_0350: Unknown result type (might be due to invalid IL or missing references)
			//IL_0352: Unknown result type (might be due to invalid IL or missing references)
			//IL_0359: Unknown result type (might be due to invalid IL or missing references)
			//IL_036d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0374: Unknown result type (might be due to invalid IL or missing references)
			//IL_0388: Unknown result type (might be due to invalid IL or missing references)
			//IL_038f: Unknown result type (might be due to invalid IL or missing references)
			//IL_03cc: Unknown result type (might be due to invalid IL or missing references)
			//IL_03ce: Unknown result type (might be due to invalid IL or missing references)
			//IL_03eb: Unknown result type (might be due to invalid IL or missing references)
			//IL_03f2: Unknown result type (might be due to invalid IL or missing references)
			//IL_03d6: Unknown result type (might be due to invalid IL or missing references)
			//IL_03dd: Unknown result type (might be due to invalid IL or missing references)
			//IL_041e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0425: Unknown result type (might be due to invalid IL or missing references)
			//IL_0409: Unknown result type (might be due to invalid IL or missing references)
			//IL_0410: Unknown result type (might be due to invalid IL or missing references)
			//IL_0451: Unknown result type (might be due to invalid IL or missing references)
			//IL_0458: Unknown result type (might be due to invalid IL or missing references)
			//IL_043c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0443: Unknown result type (might be due to invalid IL or missing references)
			//IL_046c: Unknown result type (might be due to invalid IL or missing references)
			//IL_046e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0483: Unknown result type (might be due to invalid IL or missing references)
			//IL_0485: Unknown result type (might be due to invalid IL or missing references)
			if (!m_zones.TryGetValue(a, out var value))
			{
				return;
			}
			Heightmap val = (Heightmap)f_hmap.GetValue(a);
			Color[] array = (Color[])f_paintMask.GetValue(a);
			bool[] array2 = (bool[])f_modifiedPaint.GetValue(a);
			object? value2 = f_buildData.GetValue(val);
			Color[] array3 = ((HMBuildData)(((value2 is HMBuildData) ? value2 : null)?)).m_baseMask;
			if ((Object)(object)val == (Object)null || array == null || array2 == null || array3 == null)
			{
				return;
			}
			int width = val.m_width;
			int num = width + 1;
			bool flag = false;
			foreach (TerrainComp item in m_scratch)
			{
				if ((Object)(object)item == (Object)null || (Object)(object)item == (Object)(object)a || !(bool)f_initialized.GetValue(item))
				{
					continue;
				}
				Vector3 val2 = ((Component)item).transform.position - ((Component)a).transform.position;
				if (Mathf.Abs(val2.x) > (float)width * val.m_scale + 1f || Mathf.Abs(val2.z) > (float)width * val.m_scale + 1f || (Mathf.Abs(val2.x) < 1f && Mathf.Abs(val2.z) < 1f))
				{
					continue;
				}
				Heightmap val3 = (Heightmap)f_hmap.GetValue(item);
				Color[] array4 = (Color[])f_paintMask.GetValue(item);
				bool[] array5 = (bool[])f_modifiedPaint.GetValue(item);
				Color[] array6 = ((!((Object)(object)val3 != (Object)null)) ? null : ((HMBuildData)(/*isinst with value type is only supported in some contexts*/?)).m_baseMask);
				if ((Object)(object)val3 == (Object)null || array4 == null || array5 == null || array6 == null || val3.m_width != width)
				{
					continue;
				}
				ZoneState value3;
				bool flag2 = item.IsOwner() && m_zones.TryGetValue(item, out value3);
				bool flag3 = false;
				for (int i = 0; i < 4 * width; i++)
				{
					int num2;
					int num3;
					if (i < width)
					{
						num2 = i;
						num3 = 0;
					}
					else if (i < 2 * width)
					{
						num2 = width;
						num3 = i - width;
					}
					else if (i < 3 * width)
					{
						num2 = width - (i - 2 * width);
						num3 = width;
					}
					else
					{
						num2 = 0;
						num3 = width - (i - 3 * width);
					}
					Vector3 val4 = val.VertexMaskToWorld(num2, num3);
					int num4 = Mathf.RoundToInt((val4.x - ((Component)val3).transform.position.x) / val3.m_scale + (float)(width / 2) + 0.5f);
					int num5 = Mathf.RoundToInt((val4.z - ((Component)val3).transform.position.z) / val3.m_scale + (float)(width / 2) + 0.5f);
					if (num4 < 0 || num5 < 0 || num4 > width || num5 > width)
					{
						continue;
					}
					int num6 = num3 * num + num2;
					int num7 = num5 * num + num4;
					if (!array2[num6] && !array5[num7])
					{
						continue;
					}
					Color val5 = (array2[num6] ? array[num6] : array3[num6]);
					Color val6 = (array5[num7] ? array4[num7] : array6[num7]);
					if (!(Mathf.Abs(val5.g - val6.g) < 0.002f) || !(Mathf.Abs(val5.r - val6.r) < 0.002f) || !(Mathf.Abs(val5.b - val6.b) < 0.002f))
					{
						bool flag4 = value.shelter != null && value.shelter.Length == array.Length && value.shelter[num6] == 2;
						Color val7 = val5;
						val7.g = (flag4 ? Mathf.Min(val5.g, val6.g) : Mathf.Max(val5.g, val6.g));
						val7.r = (flag4 ? Mathf.Max(val5.r, val6.r) : Mathf.Min(val5.r, val6.r));
						val7.b = (flag4 ? Mathf.Max(val5.b, val6.b) : Mathf.Min(val5.b, val6.b));
						array[num6] = val7;
						array2[num6] = true;
						flag = true;
						if (flag2)
						{
							array4[num7] = val7;
							array5[num7] = true;
							flag3 = true;
						}
					}
				}
				if (flag3)
				{
					val3.Poke(1, true);
					m_zones[item].dirty = true;
				}
			}
			if (flag)
			{
				val.Poke(1, true);
				value.dirty = true;
			}
		}

		private static bool TouchesDeepNorth(Vector3 c)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_0013: 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_0032: 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_0051: 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_0070: Unknown result type (might be due to invalid IL or missing references)
			//IL_007c: Unknown result type (might be due to invalid IL or missing references)
			if (!WorldGenerator.IsDeepnorth(c.x, c.z) && !WorldGenerator.IsDeepnorth(c.x - 32f, c.z - 32f) && !WorldGenerator.IsDeepnorth(c.x + 32f, c.z - 32f) && !WorldGenerator.IsDeepnorth(c.x - 32f, c.z + 32f))
			{
				return WorldGenerator.IsDeepnorth(c.x + 32f, c.z + 32f);
			}
			return true;
		}

		private bool Grow(TerrainComp comp, Heightmap hmap, ZoneState zone, float add)
		{
			//IL_00a5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00aa: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b4: 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_012c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0131: Unknown result type (might be due to invalid IL or missing references)
			//IL_0136: 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_013d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0144: Unknown result type (might be due to invalid IL or missing references)
			//IL_0155: Unknown result type (might be due to invalid IL or missing references)
			//IL_0163: Unknown result type (might be due to invalid IL or missing references)
			//IL_016a: 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_019f: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ee: Unknown result type (might be due to invalid IL or missing references)
			//IL_0236: 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_0253: Unknown result type (might be due to invalid IL or missing references)
			//IL_0269: Unknown result type (might be due to invalid IL or missing references)
			//IL_0270: 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_028d: Unknown result type (might be due to invalid IL or missing references)
			//IL_02a4: Unknown result type (might be due to invalid IL or missing references)
			//IL_02a6: Unknown result type (might be due to invalid IL or missing references)
			//IL_0206: Unknown result type (might be due to invalid IL or missing references)
			//IL_021d: Unknown result type (might be due to invalid IL or missing references)
			//IL_021f: Unknown result type (might be due to invalid IL or missing references)
			if (add <= 0f)
			{
				return false;
			}
			Color[] array = (Color[])f_paintMask.GetValue(comp);
			bool[] array2 = (bool[])f_modifiedPaint.GetValue(comp);
			object? value = f_buildData.GetValue(hmap);
			Color[] array3 = ((HMBuildData)(((value is HMBuildData) ? value : null)?)).m_baseMask;
			if (array == null || array2 == null || array3 == null || array3.Length != array.Length)
			{
				return false;
			}
			int num = hmap.m_width + 1;
			if (zone.deepNorth == null || zone.deepNorth.Length != array.Length)
			{
				zone.deepNorth = new bool[array.Length];
				zone.shelter = new byte[array.Length];
				for (int i = 0; i < array.Length; i++)
				{
					Vector3 val = hmap.VertexMaskToWorld(i % num, i / num);
					zone.deepNorth[i] = WorldGenerator.IsDeepnorth(val.x, val.z);
				}
			}
			if (Time.time - zone.shelterCheckedAt > 60f)
			{
				Array.Clear(zone.shelter, 0, zone.shelter.Length);
				zone.shelterCheckedAt = Time.time;
			}
			bool result = false;
			for (int j = 0; j < array.Length; j++)
			{
				if (!array2[j] || !zone.deepNorth[j])
				{
					continue;
				}
				Color val2 = array3[j];
				Color val3 = array[j];
				bool flag = val3.g < val2.g - 0.0001f;
				bool flag2 = val2.g > 0.05f && (val3.r > val2.r + 0.0001f || val3.b > val2.b + 0.0001f);
				if (!flag && !flag2 && val3.g <= 0.0001f)
				{
					continue;
				}
				if (zone.shelter[j] == 0)
				{
					zone.shelter[j] = Shelter(hmap, j % num, j / num);
				}
				if (zone.shelter[j] == 3)
				{
					continue;
				}
				if (zone.shelter[j] == 2)
				{
					if (val3.g > 0.0001f)
					{
						val3.g = Mathf.Max(0f, val3.g - add);
						array[j] = val3;
						result = true;
					}
				}
				else if (flag || flag2)
				{
					float num2 = add / Mathf.Max(val2.g, 0.15f);
					val3.g = Mathf.Min(val2.g, val3.g + add);
					val3.r = Mathf.Max(val2.r, val3.r - num2);
					val3.b = Mathf.Max(val2.b, val3.b - num2);
					array[j] = val3;
					result = true;
				}
			}
			return result;
		}

		private byte Shelter(Heightmap hmap, int x, int y)
		{
			//IL_0003: Unknown result type (might be due to invalid IL or missing references)
			//IL_0008: 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_0029: Unknown result type (might be due to invalid IL or missing references)
			//IL_002a: 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_003e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0092: Unknown result type (might be due to invalid IL or missing references)
			//IL_0057: 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_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_006c: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a9: Unknown result type (might be due to invalid IL or missing references)
			Vector3 val = hmap.VertexMaskToWorld(x, y);
			float y2 = default(float);
			if (hmap.GetWorldHeight(val, ref y2))
			{
				val.y = y2;
			}
			if (m_protectRoofs.Value)
			{
				if (Physics.Raycast(val - Vector3.up * 1f, Vector3.up, 61f, m_pieceMask))
				{
					return 2;
				}
				if (Physics.Raycast(val + Vector3.up * 0.05f, Vector3.up, 60f, m_shelterMask))
				{
					return 3;
				}
			}
			if (m_protectShields.Value && ShieldGenerator.IsInsideShield(val))
			{
				return 3;
			}
			if (m_fireMelts.Value && (Object)(object)EffectArea.IsPointInsideArea(val, (Type)1, 0f) != (Object)null)
			{
				return 3;
			}
			return 1;
		}

		private static void SaveZone(TerrainComp comp)
		{
			m_save.Invoke(comp, new object[1] { true });
		}

		private void InitWeatherScale()
		{
			if (m_maxSnowBuildup >= 0f)
			{
				return;
			}
			float num = float.MaxValue;
			float num2 = 0f;
			foreach (EnvSetup environment in EnvMan.instance.m_environments)
			{
				if (environment.m_snowBuildup > 0f)
				{
					num = Mathf.Min(num, environment.m_snowBuildup);
					num2 = Mathf.Max(num2, environment.m_snowBuildup);
					((BaseUnityPlugin)this).Logger.LogInfo((object)$"Snowing weather: {environment.m_name} buildup {environment.m_snowBuildup}");
				}
			}
			m_maxSnowBuildup = num2;
			m_minSnowBuildup = ((num2 > 0f) ? num : 0f);
		}

		internal float CurrentRate(out string label)
		{
			switch (m_force)
			{
			case "calm":
				label = "forced calm";
				return m_calmRate.Value;
			case "snow":
				label = "forced snowfall";
				return m_snowfallRate.Value;
			case "storm":
				label = "forced storm";
				return m_stormRate.Value;
			default:
			{
				EnvSetup currentEnvironment = EnvMan.instance.GetCurrentEnvironment();
				float num = currentEnvironment?.m_snowBuildup ?? 0f;
				label = currentEnvironment?.m_name ?? "?";
				if (num <= 0f || m_maxSnowBuildup <= 0f)
				{
					return m_calmRate.Value;
				}
				float num2 = ((m_maxSnowBuildup > m_minSnowBuildup) ? Mathf.InverseLerp(m_minSnowBuildup, m_maxSnowBuildup, num) : 1f);
				return Mathf.Lerp(m_snowfallRate.Value, m_stormRate.Value, num2);
			}
			}
		}

		internal string Status()
		{
			InitWeatherScale();
			string label;
			float num = CurrentRate(out label);
			int num2 = 0;
			int num3 = 0;
			foreach (KeyValuePair<TerrainComp, ZoneState> zone in m_zones)
			{
				if ((Object)(object)zone.Key != (Object)null && zone.Key.IsOwner())
				{
					num2++;
					if (zone.Value.dirty)
					{
						num3++;
					}
				}
			}
			float num4 = Mathf.Max(1f / 60f, (Time.time - m_statsSince) / 60f);
			string text = ((m_ticks > 0) ? $"{m_tickMs / (double)m_ticks:0.00} ms per tick, {(float)m_redraws / num4:0.#} terrain redraws per minute" : "no ticks yet");
			m_tickMs = 0.0;
			m_ticks = 0;
			m_redraws = 0;
			m_statsSince = Time.time;
			return string.Format("Fimbulvetr {0}: weather '{1}', {2:0.#} cm/min, {3} Deep North zones tracked, {4} with unsaved growth; {5} (since last check)\n{6}", m_enabled.Value ? "ON" : "OFF", label, num, num2, num3, text, IceStatus());
		}

		internal void SaveAll()
		{
			foreach (KeyValuePair<TerrainComp, ZoneState> zone in m_zones)
			{
				if ((Object)(object)zone.Key != (Object)null && zone.Key.IsOwner() && zone.Value.dirty)
				{
					SaveZone(zone.Key);
					zone.Value.dirty = false;
					zone.Value.lastSave = Time.time;
				}
			}
		}

		private void BindRestore()
		{
			m_iceRestore = ((BaseUnityPlugin)this).Config.Bind<bool>("Ice", "RestoreMissingSheets", true, "Put back Ice Sheets the game deleted after they were broken completely (including before this mod was installed), empty, so they refreeze to the world's original ice.");
		}

		private void RestoreTick()
		{
			//IL_02ce: Unknown result type (might be due to invalid IL or missing references)
			//IL_02d3: 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_0319: Expected O, but got Unknown
			//IL_0345: Unknown result type (might be due to invalid IL or missing references)
			//IL_034a: Unknown result type (might be due to invalid IL or missing references)
			//IL_034f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0357: Unknown result type (might be due to invalid IL or missing references)
			//IL_0363: Unknown result type (might be due to invalid IL or missing references)
			//IL_0365: Unknown result type (might be due to invalid IL or missing references)
			//IL_036a: Unknown result type (might be due to invalid IL or missing references)
			//IL_036c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0373: Unknown result type (might be due to invalid IL or missing references)
			//IL_037a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0381: Unknown result type (might be due to invalid IL or missing references)
			//IL_0388: Unknown result type (might be due to invalid IL or missing references)
			//IL_038d: Unknown result type (might be due to invalid IL or missing references)
			//IL_03a3: Unknown result type (might be due to invalid IL or missing references)
			//IL_03b4: Unknown result type (might be due to invalid IL or missing references)
			//IL_03d7: Unknown result type (might be due to invalid IL or missing references)
			//IL_03df: Unknown result type (might be due to invalid IL or missing references)
			//IL_0246: Unknown result type (might be due to invalid IL or missing references)
			//IL_024d: Invalid comparison between Unknown and I4
			//IL_03fe: Unknown result type (might be due to invalid IL or missing references)
			//IL_0400: Unknown result type (might be due to invalid IL or missing references)
			if (!m_iceRefreeze.Value || !m_iceRestore.Value || (Object)(object)ZoneSystem.instance == (Object)null || (Object)(object)ZNetScene.instance == (Object)null)
			{
				return;
			}
			if (m_iceVegetation == null)
			{
				m_iceVegetation = new List<ZoneVegetation>();
				foreach (ZoneVegetation item in ZoneSystem.instance.m_vegetation)
				{
					if (item.m_enable && !((Object)(object)item.m_prefab == (Object)null))
					{
						MineRock5 val = item.m_prefab.GetComponent<MineRock5>();
						if ((Object)(object)val == (Object)null)
						{
							GameObject val2 = item.m_prefab.GetComponent<Destructible>()?.m_spawnWhenDestroyed;
							val = (((Object)(object)val2 != (Object)null) ? val2.GetComponent<MineRock5>() : null);
						}
						if ((Object)(object)val != (Object)null && IsIceSheet(val))
						{
							m_iceVegetation.Add(item);
							m_iceFrac[((Object)item.m_prefab).name] = ((Object)((Component)val).gameObject).name;
							s_iceNames.Add(((Object)item.m_prefab).name);
							s_iceNames.Add(((Object)((Component)val).gameObject).name);
							((BaseUnityPlugin)this).Logger.LogInfo((object)("Ice sheet world generation entry: " + item.m_name + " (" + ((Object)item.m_prefab).name + ", breaks into " + ((Object)((Component)val).gameObject).name + ")"));
						}
					}
				}
				if (m_iceVegetation.Count == 0)
				{
					List<string> list = new List<string>();
					foreach (ZoneVegetation item2 in ZoneSystem.instance.m_vegetation)
					{
						if ((Object)(object)item2.m_prefab != (Object)null && ((Object)(object)item2.m_prefab.GetComponent<MineRock5>() != (Object)null || ((Object)item2.m_prefab).name.IndexOf("ice", StringComparison.OrdinalIgnoreCase) >= 0))
						{
							list.Add(((Object)item2.m_prefab).name + (item2.m_enable ? "" : " (off)") + (((int)item2.m_biome == 64) ? " [DN]" : ""));
						}
					}
					((BaseUnityPlugin)this).Logger.LogWarning((object)string.Format("No ice sheet world generation entries found among {0}; missing sheets can't be restored. Mineable/ice entries: {1}", ZoneSystem.instance.m_vegetation.Count, string.Join(", ", list)));
				}
			}
			if (m_iceVegetation.Count == 0)
			{
				return;
			}
			Vector3 position = ((Component)Player.m_localPlayer).transform.position;
			foreach (SpawnSystem item3 in (List<SpawnSystem>)f_spawnSystems.GetValue(null))
			{
				if ((Object)(object)item3 == (Object)null)
				{
					continue;
				}
				ZNetView val3 = (ZNetView)f_spawnNview.GetValue(item3);
				if ((Object)(object)val3 == (Object)null || !val3.IsValid() || !val3.IsOwner())
				{
					continue;
				}
				Vector2s zone = ZoneSystem.GetZone(((Component)item3).transform.position);
				if (m_zonesChecked.Contains(zone))
				{
					continue;
				}
				Vector3 zonePos = ZoneSystem.GetZonePos(zone);
				Vector2 val4 = new Vector2(zonePos.x - position.x, zonePos.z - position.z);
				if (((Vector2)(ref val4)).magnitude > 96f)
				{
					continue;
				}
				if (!m_zoneSeen.TryGetValue(zone, out var value))
				{
					m_zoneSeen[zone] = Time.time;
				}
				else if (!(Time.time - value < 10f))
				{
					m_zonesChecked.Add(zone);
					Heightmap val5 = Heightmap.FindHeightmap(zonePos);
					if (!((Object)(object)val5 == (Object)null) && val5.HaveBiome((Biome)64))
					{
						RestoreZone(zone, zonePos, val5);
						break;
					}
				}
			}
		}

		private void RestoreZone(Vector2s zone, Vector3 center, Heightmap hmap)
		{
			//IL_0041: 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_0054: 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_0064: 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_006b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0093: 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)
			//IL_011b: 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_0283: Unknown result type (might be due to invalid IL or missing references)
			//IL_0290: Unknown result type (might be due to invalid IL or missing references)
			//IL_01cf: 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_01e2: 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_01f5: Unknown result type (might be due to invalid IL or missing references)
			//IL_01fa: Unknown result type (might be due to invalid IL or missing references)
			//IL_02dd: Unknown result type (might be due to invalid IL or missing references)
			//IL_02e4: Unknown result type (might be due to invalid IL or missing references)
			//IL_0327: Unknown result type (might be due to invalid IL or missing references)
			//IL_03f9: Unknown result type (might be due to invalid IL or missing references)
			List<Original> list = new List<Original>();
			ZoneSystem instance = ZoneSystem.instance;
			List<ZoneVegetation> vegetation = instance.m_vegetation;
			IList list2 = (IList)Activator.CreateInstance(typeof(List<>).MakeGenericType(t_clearArea));
			if (instance.m_locationInstances.TryGetValue(zone, out var value) && value.m_location != null && value.m_location.m_clearArea)
			{
				Vector3 position = value.m_position;
				if (value.m_location.m_snapToWater)
				{
					position.y = 30f;
				}
				list2.Add(Activator.CreateInstance(t_clearArea, position, value.m_location.m_exteriorRadius));
			}
			List<ZoneVegetation> list3 = new List<ZoneVegetation>(1);
			List<GameObject> list4 = new List<GameObject>();
			foreach (ZoneVegetation item in m_iceVegetation)
			{
				list3.Clear();
				list3.Add(item);
				m_ghosts.Clear();
				try
				{
					s_replaying = true;
					instance.m_vegetation = list3;
					m_placeVegetation.Invoke(instance, new object[7]
					{
						zone,
						center,
						((Component)hmap).transform,
						hmap,
						list2,
						(object)(SpawnMode)2,
						m_ghosts
					});
				}
				finally
				{
					instance.m_vegetation = vegetation;
					s_replaying = false;
				}
				foreach (GameObject ghost in m_ghosts)
				{
					if (!((Object)(object)ghost == (Object)null))
					{
						list.Add(new Original
						{
							prefab = ((Object)item.m_prefab).name,
							frac = m_iceFrac[((Object)item.m_prefab).name],
							pos = ghost.transform.position,
							rot = ghost.transform.rotation,
							scale = ghost.transform.localScale
						});
						list4.Add(ghost);
					}
				}
			}
			foreach (GameObject item2 in list4)
			{
				Object.Destroy((Object)(object)item2);
			}
			m_ghosts.Clear();
			CollectIceZdos(zone);
			RemoveDuplicates();
			CollectIceZdos(zone);
			foreach (Original item3 in list)
			{
				if (SheetExistsNear(item3))
				{
					continue;
				}
				GameObject prefab = ZNetScene.instance.GetPrefab(item3.frac);
				if ((Object)(object)prefab == (Object)null)
				{
					continue;
				}
				GameObject obj = Object.Instantiate<GameObject>(prefab, item3.pos, item3.rot);
				ZNetView component = obj.GetComponent<ZNetView>();
				MineRock5 component2 = obj.GetComponent<MineRock5>();
				if (!((Object)(object)component == (Object)null) && component.IsValid() && !((Object)(object)component2 == (Object)null))
				{
					component.SetLocalScale(item3.scale);
					IList list5 = (IList)f_hitAreas.GetValue(component2);
					int num = 0;
					while (list5 != null && num < list5.Count)
					{
						f_haHealth.SetValue(list5[num], 0f);
						num++;
					}
					component.GetZDO().Set(s_iceLastTime, (long)ZNet.instance.GetTimeSeconds());
					component.GetZDO().Set(s_restoredFlag, true);
					m_iceZdos.Add(component.GetZDO());
					m_saveHealth.Invoke(component2, null);
					m_updateMesh.Invoke(component2, null);
					m_restored++;
					((BaseUnityPlugin)this).Logger.LogInfo((object)$"Restored missing ice sheet {item3.prefab} at {item3.pos:F0} (empty; it will refreeze)");
				}
			}
		}

		private void CollectIceZdos(Vector2s zone)
		{
			//IL_001b: 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)
			m_zoneZdos.Clear();
			m_iceZdos.Clear();
			ZDOMan.instance.FindSectorObjects(zone, new SimulationDistance(1, 0, true), m_zoneZdos, (List<ZDO>)null);
			foreach (ZDO zoneZdo in m_zoneZdos)
			{
				GameObject prefab = ZNetScene.instance.GetPrefab(zoneZdo.GetPrefab());
				if ((Object)(object)prefab != (Object)null && s_iceNames.Contains(((Object)prefab).name))
				{
					m_iceZdos.Add(zoneZdo);
				}
			}
		}

		private bool SheetExistsNear(Original o)
		{
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			//IL_0025: 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_002c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0033: 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)
			foreach (ZDO iceZdo in m_iceZdos)
			{
				Vector3 val = iceZdo.GetPosition() - o.pos;
				if (val.x * val.x + val.z * val.z < 4f)
				{
					return true;
				}
			}
			return false;
		}

		private void RemoveDuplicates()
		{
			//IL_00a4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00aa: Unknown result type (might be due to invalid IL or missing references)
			//IL_00af: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bd: 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_00cc: Unknown result type (might be due to invalid IL or missing references)
			//IL_0177: Unknown result type (might be due to invalid IL or missing references)
			//IL_017c: 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)
			HashSet<ZDO> hashSet = new HashSet<ZDO>();
			foreach (ZDO iceZdo in m_iceZdos)
			{
				GameObject prefab = ZNetScene.instance.GetPrefab(iceZdo.GetPrefab());
				if ((Object)(object)prefab == (Object)null || (Object)(object)prefab.GetComponent<MineRock5>() == (Object)null || !iceZdo.IsOwner())
				{
					continue;
				}
				bool flag = iceZdo.GetBool(s_restoredFlag, false);
				foreach (ZDO iceZdo2 in m_iceZdos)
				{
					if (iceZdo2 == iceZdo || hashSet.Contains(iceZdo2) || !iceZdo2.IsValid())
					{
						continue;
					}
					Vector3 val = iceZdo2.GetPosition() - iceZdo.GetPosition();
					if (val.x * val.x + val.z * val.z >= (flag ? 4f : 0.25f))
					{
						continue;
					}
					GameObject prefab2 = ZNetScene.instance.GetPrefab(iceZdo2.GetPrefab());
					bool num = (Object)(object)prefab2 != (Object)null && (Object)(object)prefab2.GetComponent<MineRock5>() == (Object)null;
					bool flag2 = iceZdo2.GetBool(s_restoredFlag, false);
					if (num || (flag && !flag2) || (flag == flag2 && string.CompareOrdinal(((object)Unsafe.As<ZDOID, ZDOID>(ref iceZdo.m_uid)/*cast due to .constrained prefix*/).ToString(), ((object)Unsafe.As<ZDOID, ZDOID>(ref iceZdo2.m_uid)/*cast due to .constrained prefix*/).ToString()) > 0))
					{
						ZNetView val2 = ZNetScene.instance.FindInstance(iceZdo);
						Vector3 position = iceZdo.GetPosition();
						if ((Object)(object)val2 != (Object)null)
						{
							ZNetScene.instance.Destroy(((Component)val2).gameObject);
						}
						else
						{
							ZDOMan.instance.DestroyZDO(iceZdo);
						}
						hashSet.Add(iceZdo);
						ForgetZdo(iceZdo);
						m_removedDuplicates++;
						((BaseUnityPlugin)this).Logger.LogInfo((object)$"Removed a duplicate ice sheet at {position:F0}");
						break;
					}
				}
			}
		}

		private static string ZdoPrefabName(ZNetView nview)
		{
			ZDO zDO = nview.GetZDO();
			GameObject val = ((zDO != null && (Object)(object)ZNetScene.instance != (Object)null) ? ZNetScene.instance.GetPrefab(zDO.GetPrefab()) : null);
			if (!((Object)(object)val != (Object)null))
			{
				return "";
			}
			return ((Object)val).name;
		}

		private bool IsIcePrefab(string name)
		{
			string[] array = m_icePrefabs.Value.Split(',');
			for (int i = 0; i < array.Length; i++)
			{
				string text = array[i].Trim();
				if (text.Length > 0 && name.StartsWith(text, StringComparison.OrdinalIgnoreCase))
				{
					return true;
				}
			}
			return false;
		}
	}
}