Decompiled source of FogAndColdControl v1.2.0

plugins/Thanks.Fog&ColdControl.dll

Decompiled 2 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.Runtime.InteropServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using System.Text;
using BepInEx;
using BepInEx.Configuration;
using ExitGames.Client.Photon;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using Photon.Pun;
using Photon.Realtime;
using TMPro;
using UnityEngine;
using UnityEngine.SceneManagement;
using UnityEngine.UI;
using Zorro.Core;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: AssemblyTitle("Thanks.Fog&ColdControl")]
[assembly: AssemblyDescription("Host-only PEAK fog and cold control mode with synced fog movement, compass rewards, HUD, and separate fog-cold and night-cold handling.")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("Thanks")]
[assembly: AssemblyProduct("Fog&ColdControl")]
[assembly: AssemblyCopyright("Copyright (c) Thanks 2026")]
[assembly: AssemblyTrademark("")]
[assembly: ComVisible(false)]
[assembly: Guid("f3d09c64-b194-4a16-9196-85106f2f0d01")]
[assembly: AssemblyFileVersion("1.2.0.0")]
[assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.2.0.0")]
[module: UnverifiableCode]
[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 FogColdControl
{
	[HarmonyPatch(typeof(Fog), "MakePlayerCold")]
	internal static class FogMakePlayerColdPatch
	{
		private static bool Prefix()
		{
			if (Plugin.ShouldSuppressFogColdDamage())
			{
				return false;
			}
			Plugin.BeginLocalFogStatusSource();
			return true;
		}

		private static Exception Finalizer(Exception __exception)
		{
			Plugin.EndLocalFogStatusSource();
			return __exception;
		}
	}
	[HarmonyPatch(typeof(FogSphere), "SetSharderVars")]
	internal static class FogSphereSetShaderVarsPatch
	{
		private static void Prefix()
		{
			Plugin.BeginLocalFogStatusSource();
		}

		private static Exception Finalizer(Exception __exception)
		{
			Plugin.EndLocalFogStatusSource();
			return __exception;
		}
	}
	[HarmonyPatch(typeof(OrbFogHandler), "WaitToMove")]
	internal static class OrbFogHandlerWaitToMovePatch
	{
		private static bool Prefix(OrbFogHandler __instance)
		{
			return !Plugin.ShouldBlockVanillaOrbFogWait(__instance);
		}
	}
	[HarmonyPatch(typeof(OrbFogHandler), "Start")]
	internal static class OrbFogHandlerStartPatch
	{
		private static void Postfix(OrbFogHandler __instance)
		{
			Plugin.NotifyFogHandlerChanged(__instance);
		}
	}
	[HarmonyPatch(typeof(OrbFogHandler), "SetFogOrigin")]
	internal static class OrbFogHandlerSetFogOriginPatch
	{
		private static void Postfix(OrbFogHandler __instance)
		{
			Plugin.NotifyFogHandlerChanged(__instance);
		}
	}
	[HarmonyPatch(typeof(OrbFogHandler), "RPC_InitFog")]
	internal static class OrbFogHandlerRpcInitFogPatch
	{
		private static void Postfix(OrbFogHandler __instance, float s, bool moving, PhotonMessageInfo info)
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			Plugin.NotifyFogHandlerChanged(__instance);
			if (info.Sender != null && info.Sender.IsMasterClient)
			{
				Plugin.NotifyGuestFogSnapshot(__instance, s, moving);
			}
		}
	}
	[HarmonyPatch(typeof(OrbFogHandler), "RPCA_SyncFog")]
	internal static class OrbFogHandlerSyncFogPatch
	{
		private static void Postfix(OrbFogHandler __instance, float s, bool moving)
		{
			Plugin.NotifyGuestFogSnapshot(__instance, s, moving);
		}
	}
	[HarmonyPatch(typeof(Ascents), "get_fogEnabled")]
	internal static class AscentsFogEnabledPatch
	{
		private static void Postfix(ref bool __result)
		{
			if (Plugin.ShouldForceFogCoverageEverywhere())
			{
				__result = true;
			}
		}
	}
	[HarmonyPatch(typeof(Ascents), "get_isNightCold")]
	internal static class AscentsNightColdPatch
	{
		private static void Postfix(ref bool __result)
		{
			if (Plugin.ShouldDisableNightColdFeatureLocally())
			{
				__result = false;
			}
		}
	}
	[HarmonyPatch(typeof(CharacterAfflictions), "AddStatus")]
	internal static class CharacterAfflictionsAddStatusPatch
	{
		private static bool Prefix(CharacterAfflictions __instance, STATUSTYPE statusType, ref bool __result)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			if (!Plugin.ShouldSuppressLocalFogSourceStatus(__instance, statusType))
			{
				return true;
			}
			__result = false;
			return false;
		}
	}
	[HarmonyPatch(typeof(Campfire), "Light_Rpc")]
	internal static class CampfireLightRpcPatch
	{
		private static void Postfix(Campfire __instance)
		{
			Plugin.NotifyCampfireLit(__instance);
		}
	}
	[HarmonyPatch(typeof(WindChillZone), "RPCA_ToggleWind")]
	internal static class WindChillZoneToggleWindPatch
	{
		private static void Postfix(WindChillZone __instance)
		{
			Plugin.NotifyWeatherTransition(__instance);
		}
	}
	internal static class NextBiomeResolver
	{
		private static readonly int KnownSegmentCount = Enum.GetValues(typeof(Segment)).Length;

		internal static bool TryGetNextBiome(MapHandler mapHandler, Segment currentSegment, out BiomeType biome)
		{
			//IL_0024: 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_0033: Invalid comparison between Unknown and I4
			//IL_0035: Unknown result type (might be due to invalid IL or missing references)
			//IL_0037: Invalid comparison between Unknown and I4
			//IL_0039: Unknown result type (might be due to invalid IL or missing references)
			//IL_003b: Invalid comparison between Unknown and I4
			//IL_004c: Unknown result type (might be due to invalid IL or missing references)
			//IL_004e: Expected I4, but got Unknown
			//IL_00a2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a7: 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_00bb: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f6: 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_0106: Invalid comparison between Unknown and I4
			//IL_0114: Unknown result type (might be due to invalid IL or missing references)
			//IL_0117: Expected I4, but got Unknown
			//IL_0108: 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)
			biome = (BiomeType)0;
			try
			{
				if ((Object)(object)mapHandler == (Object)null || !MapHandler.ExistsAndInitialized || RunSettings.isMiniRun || !Enum.IsDefined(typeof(Segment), currentSegment) || (int)currentSegment == 4 || (int)currentSegment == 5 || (int)currentSegment == 6)
				{
					return false;
				}
				MapSegment[] segments = mapHandler.segments;
				int num = (int)currentSegment;
				if (segments == null || segments.Length > KnownSegmentCount || num < 0 || num >= segments.Length - 1 || mapHandler.biomes == null)
				{
					return false;
				}
				MapSegment val = segments[num];
				MapSegment val2 = segments[num + 1];
				if (val == null || val2 == null || !HasReadableVariantChain(mapHandler, val) || !HasReadableVariantChain(mapHandler, val2))
				{
					return false;
				}
				BiomeType biome2 = val.biome;
				BiomeType biome3 = val2.biome;
				if (!Enum.IsDefined(typeof(BiomeType), biome2) || !Enum.IsDefined(typeof(BiomeType), biome3) || !mapHandler.biomes.Contains(biome2) || !mapHandler.biomes.Contains(biome3))
				{
					return false;
				}
				if ((int)currentSegment == 3 && biome2 == biome3)
				{
					return false;
				}
				biome = (BiomeType)(int)biome3;
				return true;
			}
			catch (Exception)
			{
				return false;
			}
		}

		private static bool HasReadableVariantChain(MapHandler mapHandler, MapSegment segment)
		{
			MapSegment[] variantSegments = mapHandler.variantSegments;
			int num = ((variantSegments != null) ? variantSegments.Length : 0) + 1;
			while (segment.hasVariant)
			{
				int variantBiomeIndex = segment.variantBiomeIndex;
				if (num-- <= 0 || mapHandler.biomes == null || variantSegments == null || variantBiomeIndex < 0 || variantBiomeIndex >= variantSegments.Length || variantSegments[variantBiomeIndex] == null)
				{
					return false;
				}
				segment = variantSegments[variantBiomeIndex];
			}
			return true;
		}
	}
	internal enum WeatherHazardKind
	{
		Wind,
		Snow,
		Rain
	}
	internal static class WeatherWarningText
	{
		internal static bool IsKnownKind(WeatherHazardKind kind)
		{
			if (kind != WeatherHazardKind.Wind && kind != WeatherHazardKind.Snow)
			{
				return kind == WeatherHazardKind.Rain;
			}
			return true;
		}

		internal static bool IsValidRemaining(float seconds)
		{
			if (!float.IsNaN(seconds) && !float.IsInfinity(seconds) && seconds > 0.05f)
			{
				return seconds <= 9999.9f;
			}
			return false;
		}

		internal static bool TryFormat(WeatherHazardKind kind, float seconds, bool incoming, bool chinese, out string prefix, out string timer, out string suffix)
		{
			prefix = (timer = (suffix = string.Empty));
			if (!IsKnownKind(kind) || !IsValidRemaining(seconds))
			{
				return false;
			}
			prefix = "<color=#FF7B7B>" + kind switch
			{
				WeatherHazardKind.Wind => chinese ? "强风" : "Strong winds", 
				WeatherHazardKind.Snow => chinese ? "暴风雪" : "Snowstorm", 
				_ => chinese ? "暴雨" : "Heavy rain", 
			} + "</color>" + ((!chinese) ? (incoming ? " arriving in " : " ending in ") : (incoming ? "将在" : "还剩"));
			timer = Math.Ceiling(seconds).ToString(CultureInfo.InvariantCulture);
			suffix = ((!chinese) ? " seconds!" : (incoming ? "秒后到来!" : "秒结束"));
			return true;
		}
	}
	internal static class WeatherWarningLayout
	{
		internal static bool TryFitLine(float prefixWidth, float timerWidth, float suffixWidth, float availableWidth, out float width, out float scale)
		{
			width = (scale = 0f);
			float[] array = new float[4] { prefixWidth, timerWidth, suffixWidth, availableWidth };
			foreach (float num in array)
			{
				if (float.IsNaN(num) || float.IsInfinity(num) || num <= 0f)
				{
					return false;
				}
			}
			float num2 = prefixWidth + timerWidth + suffixWidth + 30f;
			if (float.IsInfinity(num2))
			{
				return false;
			}
			scale = Math.Min(1f, availableWidth / num2);
			if (scale < 0.53846157f)
			{
				return false;
			}
			width = num2 * scale;
			return true;
		}

		internal static bool TryGetCenterY(float safeBottom, float safeTop, float height, float? locatorBottom, out float center)
		{
			center = 0f;
			if (float.IsNaN(safeBottom) || float.IsInfinity(safeBottom) || float.IsNaN(safeTop) || float.IsInfinity(safeTop) || float.IsNaN(height) || float.IsInfinity(height) || height <= 0f || safeTop - safeBottom < height)
			{
				return false;
			}
			float num = height * 0.5f;
			float num2 = safeTop - 40f - num;
			if (locatorBottom.HasValue)
			{
				float value = locatorBottom.Value;
				if (float.IsNaN(value) || float.IsInfinity(value))
				{
					return false;
				}
				num2 = Math.Min(num2, value - 10f - num);
				if (num2 < safeBottom + num)
				{
					return false;
				}
			}
			center = Math.Max(num2, safeBottom + num);
			return true;
		}
	}
	internal static class HudPanelLayout
	{
		internal static bool TryFit(float canvasWidth, float canvasHeight, float width, float height, float requestedScale, float requestedX, float requestedY, out float scale, out float x, out float y)
		{
			scale = 1f;
			x = (y = 0f);
			if (!IsPositiveFinite(canvasWidth) || !IsPositiveFinite(canvasHeight) || !IsPositiveFinite(width) || !IsPositiveFinite(height))
			{
				return false;
			}
			requestedScale = (IsPositiveFinite(requestedScale) ? Math.Max(0.5f, Math.Min(2.5f, requestedScale)) : 0.9f);
			scale = Math.Min(requestedScale, Math.Min(canvasWidth / width, canvasHeight / height));
			x = ClampPosition(requestedX, Math.Max(0f, canvasWidth - width * scale));
			y = ClampPosition(requestedY, Math.Max(0f, canvasHeight - height * scale));
			return IsPositiveFinite(scale);
		}

		private static float ClampPosition(float value, float maximum)
		{
			if (!float.IsNaN(value) && !float.IsInfinity(value))
			{
				return Math.Max(0f, Math.Min(value, maximum));
			}
			return 0f;
		}

		private static bool IsPositiveFinite(float value)
		{
			if (!float.IsNaN(value) && !float.IsInfinity(value))
			{
				return value > 0f;
			}
			return false;
		}
	}
	internal static class HudNumericText
	{
		internal static string Compact(string value)
		{
			if (!string.IsNullOrEmpty(value))
			{
				return "<mspace=0.65em>" + value + "</mspace>";
			}
			return string.Empty;
		}
	}
	internal static class HudModuleLayout
	{
		internal readonly struct Placement
		{
			internal readonly float X;

			internal readonly float Y;

			internal readonly float Width;

			internal Placement(float x, float y, float width)
			{
				X = x;
				Y = y;
				Width = width;
			}
		}

		internal static Placement[] Arrange(IReadOnlyList<float> moduleWidths, bool vertical, float spacing, float moduleHeight, float paddingX, float paddingY, out float width, out float height)
		{
			int count = moduleWidths.Count;
			width = (height = 0f);
			if (count == 0)
			{
				return Array.Empty<Placement>();
			}
			for (int i = 0; i < count; i++)
			{
				width = (vertical ? Math.Max(width, moduleWidths[i]) : (width + moduleWidths[i]));
			}
			width += paddingX * 2f + (vertical ? 0f : (spacing * (float)(count - 1)));
			height = paddingY * 2f + (vertical ? (moduleHeight * (float)count + spacing * (float)(count - 1)) : moduleHeight);
			Placement[] array = new Placement[count];
			float num = paddingX;
			for (int j = 0; j < count; j++)
			{
				array[j] = new Placement(vertical ? paddingX : num, vertical ? (height - paddingY - moduleHeight - (float)j * (moduleHeight + spacing)) : paddingY, moduleWidths[j]);
				num += moduleWidths[j] + spacing;
			}
			return array;
		}
	}
	internal static class FogEtaText
	{
		internal const string UnknownText = "--:--";

		internal const float MinimumRate = 0.02f;

		internal static bool TryEstimate(float remainingUnits, float unitsPerSecond, out float etaSeconds)
		{
			etaSeconds = 0f;
			if (!IsUsable(remainingUnits) || !IsUsable(unitsPerSecond))
			{
				return false;
			}
			if (remainingUnits <= 0.05f)
			{
				return true;
			}
			if (unitsPerSecond < 0.02f)
			{
				return false;
			}
			etaSeconds = remainingUnits / unitsPerSecond;
			return IsUsable(etaSeconds);
		}

		internal static string Format(float etaSeconds)
		{
			int num = Math.Max(0, (int)Math.Ceiling(IsUsable(etaSeconds) ? etaSeconds : 0f));
			return string.Format(CultureInfo.InvariantCulture, "{0:00}:{1:00}", num / 60, num % 60);
		}

		internal static string FormatOrUnknown(bool hasEta, float etaSeconds)
		{
			if (!hasEta)
			{
				return "--:--";
			}
			return Format(etaSeconds);
		}

		private static bool IsUsable(float value)
		{
			if (!float.IsNaN(value))
			{
				return !float.IsInfinity(value);
			}
			return false;
		}
	}
	[HarmonyPatch]
	internal static class ModConfigSettingNamePatch
	{
		private static bool _logged;

		private static bool Prepare()
		{
			List<MethodBase> list = ModConfigPatchTypes.ResolveSettingMethods("GetDisplayName");
			ModConfigPatchTypes.LogResolvedOnce(ref _logged, "display-name", list.Count);
			return list.Count > 0;
		}

		private static IEnumerable<MethodBase> TargetMethods()
		{
			return ModConfigPatchTypes.ResolveSettingMethods("GetDisplayName");
		}

		private static void Postfix(object __instance, ref string __result)
		{
			if (Plugin.TryGetLocalizedModConfigSettingName(__instance, out var localizedName))
			{
				__result = localizedName;
			}
		}
	}
	[HarmonyPatch]
	internal static class ModConfigSettingCategoryPatch
	{
		private static bool _logged;

		private static bool Prepare()
		{
			List<MethodBase> list = ModConfigPatchTypes.ResolveSettingMethods("GetCategory");
			ModConfigPatchTypes.LogResolvedOnce(ref _logged, "category", list.Count);
			return list.Count > 0;
		}

		private static IEnumerable<MethodBase> TargetMethods()
		{
			return ModConfigPatchTypes.ResolveSettingMethods("GetCategory");
		}

		private static void Postfix(object __instance, ref string __result)
		{
			if (Plugin.TryGetLocalizedModConfigCategoryName(__instance, out var localizedName))
			{
				__result = localizedName;
			}
		}
	}
	[HarmonyPatch]
	internal static class ModConfigFloatFormatPatch
	{
		private static bool Prepare()
		{
			return ModConfigPatchTypes.ResolveFloatSettingMethod("GetFormattedString") != null;
		}

		private static MethodBase TargetMethod()
		{
			return ModConfigPatchTypes.ResolveFloatSettingMethod("GetFormattedString");
		}

		private static void Postfix(float value, ref string __result)
		{
			if (!string.IsNullOrEmpty(__result) && __result.IndexOf('%') < 0 && !(Mathf.Abs(value - Mathf.Round(value)) < 0.0005f))
			{
				__result = value.ToString("0.###", CultureInfo.InvariantCulture);
			}
		}
	}
	[HarmonyPatch]
	internal static class ModConfigFloatSliderPatch
	{
		private static bool Prepare()
		{
			return ModConfigPatchTypes.ResolveFloatSettingMethod("Setup") != null;
		}

		private static MethodBase TargetMethod()
		{
			return ModConfigPatchTypes.ResolveFloatSettingMethod("Setup");
		}

		private static void Postfix(object __0, Slider ___slider)
		{
			if (!((Object)(object)___slider == (Object)null) && Plugin.IsModConfigFloatSetting(__0))
			{
				___slider.wholeNumbers = false;
			}
		}
	}
	[HarmonyPatch]
	internal static class ModConfigMenuRelocalizePatch
	{
		private static bool _logged;

		private static bool Prepare()
		{
			List<MethodBase> list = ModConfigPatchTypes.ResolveMenuRefreshMethods();
			ModConfigPatchTypes.LogResolvedOnce(ref _logged, "menu relocalize", list.Count);
			return list.Count > 0;
		}

		private static IEnumerable<MethodBase> TargetMethods()
		{
			return ModConfigPatchTypes.ResolveMenuRefreshMethods();
		}

		private static void Postfix(object __instance)
		{
			Plugin.Instance?.ScheduleModConfigUiLocalization(__instance);
		}
	}
	internal static class ModConfigMenuUiLocalizer
	{
		private const string TabsButtonTypeName = "PEAKLib.ModConfig.Components.ModdedTABSButton";

		internal static object ResolveMenuInstance()
		{
			Type type = AccessTools.TypeByName("PEAKLib.ModConfig.Components.ModSettingsMenu");
			if (type == null)
			{
				return null;
			}
			try
			{
				return type.GetProperty("Instance", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic)?.GetValue(null);
			}
			catch
			{
				return null;
			}
		}

		internal static bool Localize(object menuInstance)
		{
			Object val = (Object)((menuInstance is Object) ? menuInstance : null);
			if (val == null || val == (Object)null)
			{
				return false;
			}
			try
			{
				Dictionary<string, string> map = Plugin.BuildModConfigUiTextMap();
				int num = LocalizeSettingCells(menuInstance, map);
				int num2 = LocalizeTabs(menuInstance, map);
				if (num > 0 || num2 > 0)
				{
					Plugin.LogInfo($"[Fog&ColdControl] ModConfig UI relocalized: {num} rows, {num2} tabs.");
				}
			}
			catch
			{
			}
			return true;
		}

		private static int LocalizeSettingCells(object menuInstance, Dictionary<string, string> map)
		{
			if (!(AccessTools.Field(menuInstance.GetType(), "m_spawnedCells")?.GetValue(menuInstance) is IList list))
			{
				return 0;
			}
			int num = 0;
			foreach (object item in list)
			{
				if (item != null && ApplyLocalizedText((TMP_Text)/*isinst with value type is only supported in some contexts*/, map))
				{
					num++;
				}
			}
			return num;
		}

		private static int LocalizeTabs(object menuInstance, Dictionary<string, string> map)
		{
			if (!IsOwnedMenuContext(menuInstance))
			{
				return 0;
			}
			Component val = (Component)((menuInstance is Component) ? menuInstance : null);
			Type type = AccessTools.TypeByName("PEAKLib.ModConfig.Components.ModdedTABSButton");
			if ((Object)(object)val == (Object)null || type == null)
			{
				return 0;
			}
			int num = 0;
			Component[] componentsInChildren = val.GetComponentsInChildren(type, true);
			for (int i = 0; i < componentsInChildren.Length; i++)
			{
				TMP_Text[] componentsInChildren2 = componentsInChildren[i].GetComponentsInChildren<TMP_Text>(true);
				for (int j = 0; j < componentsInChildren2.Length; j++)
				{
					if (ApplyLocalizedText(componentsInChildren2[j], map))
					{
						num++;
					}
				}
			}
			return num;
		}

		private static bool IsOwnedMenuContext(object menuInstance)
		{
			string text = AccessTools.Field(menuInstance.GetType(), "selectedMod")?.GetValue(menuInstance) as string;
			if (!string.IsNullOrEmpty(text))
			{
				return string.Equals(text, "Fog&ColdControl", StringComparison.OrdinalIgnoreCase);
			}
			return true;
		}

		private static bool ApplyLocalizedText(TMP_Text text, Dictionary<string, string> map)
		{
			if ((Object)(object)text == (Object)null)
			{
				return false;
			}
			string text2 = text.text;
			if (string.IsNullOrEmpty(text2))
			{
				return false;
			}
			if (!map.TryGetValue(text2.Trim(), out var value) || string.IsNullOrEmpty(value) || string.Equals(text2, value, StringComparison.Ordinal))
			{
				return false;
			}
			text.text = value;
			return true;
		}
	}
	internal static class ModConfigPatchTypes
	{
		internal const string ModConfigAssemblyName = "com.github.PEAKModding.PEAKLib.ModConfig";

		internal const string MenuTypeName = "PEAKLib.ModConfig.Components.ModSettingsMenu";

		private const string FloatSettingUiTypeName = "Zorro.Settings.UI.FloatSettingUI";

		private const string SettingInterfaceName = "PEAKLib.ModConfig.IBepInExProperty";

		internal static List<MethodBase> ResolveMenuRefreshMethods()
		{
			List<MethodBase> list = new List<MethodBase>();
			Type type = AccessTools.TypeByName("PEAKLib.ModConfig.Components.ModSettingsMenu");
			if (type == null)
			{
				return list;
			}
			AddResolvedMethod(list, AccessTools.Method(type, "ShowSettings", Type.EmptyTypes, (Type[])null));
			AddResolvedMethod(list, AccessTools.Method(type, "OnEnable", Type.EmptyTypes, (Type[])null));
			AddResolvedMethod(list, AccessTools.Method(type, "UpdateSectionTabs", new Type[1] { typeof(string) }, (Type[])null));
			return list;
		}

		private static void AddResolvedMethod(List<MethodBase> methods, MethodBase method)
		{
			if (method != null && !method.ContainsGenericParameters && !methods.Contains(method))
			{
				methods.Add(method);
			}
		}

		internal static void LogResolvedOnce(ref bool logged, string label, int targetCount)
		{
			if (!logged)
			{
				logged = true;
				Plugin.LogInfo($"[Fog&ColdControl] ModConfig {label} targets: {targetCount}.");
			}
		}

		internal static List<MethodBase> ResolveSettingMethods(string methodName)
		{
			List<MethodBase> list = new List<MethodBase>();
			try
			{
				Type type = AccessTools.TypeByName("PEAKLib.ModConfig.IBepInExProperty");
				if (type?.Assembly == null)
				{
					return list;
				}
				Type[] types = type.Assembly.GetTypes();
				foreach (Type type2 in types)
				{
					if (!type2.ContainsGenericParameters && type.IsAssignableFrom(type2) && !(type2 == type))
					{
						MethodBase methodBase = AccessTools.Method(type2, methodName, Type.EmptyTypes, (Type[])null);
						if (!(methodBase == null) && !methodBase.ContainsGenericParameters && !list.Contains(methodBase))
						{
							list.Add(methodBase);
						}
					}
				}
			}
			catch
			{
			}
			return list;
		}

		internal static MethodBase ResolveFloatSettingMethod(string methodName)
		{
			Type type = AccessTools.TypeByName("Zorro.Settings.UI.FloatSettingUI");
			if (type == null)
			{
				return null;
			}
			if (string.Equals(methodName, "GetFormattedString", StringComparison.Ordinal))
			{
				return AccessTools.Method(type, methodName, new Type[1] { typeof(float) }, (Type[])null);
			}
			return AccessTools.Method(type, methodName, (Type[])null, (Type[])null);
		}
	}
	internal sealed class FogSpeedSamples
	{
		private struct Sample
		{
			internal float Size;

			internal double Time;
		}

		private readonly List<Sample> _samples = new List<Sample>();

		private int _origin = -1;

		private const double WindowSeconds = 5.0;

		private const double TimeoutSeconds = 12.0;

		internal static bool IsValidSpeed(float value)
		{
			if (!float.IsNaN(value) && !float.IsInfinity(value))
			{
				return value >= 0f;
			}
			return false;
		}

		internal void Reset()
		{
			_samples.Clear();
			_origin = -1;
		}

		internal void Observe(int origin, float size, bool moving, double gameTime)
		{
			if (!moving || !IsValidSpeed(size) || double.IsNaN(gameTime) || double.IsInfinity(gameTime))
			{
				Reset();
				return;
			}
			if (_samples.Count > 0)
			{
				Sample sample = _samples[_samples.Count - 1];
				if (_origin != origin || size > sample.Size + 0.01f || gameTime < sample.Time || gameTime - sample.Time > 12.0)
				{
					Reset();
				}
				else if (gameTime == sample.Time)
				{
					return;
				}
			}
			_origin = origin;
			_samples.Add(new Sample
			{
				Size = size,
				Time = gameTime
			});
			while (_samples.Count > 2 && _samples[1].Time <= gameTime - 5.0)
			{
				_samples.RemoveAt(0);
			}
		}

		internal bool TryGetSpeed(int origin, double gameTime, out float speed)
		{
			speed = 0f;
			if (_origin != origin || _samples.Count < 2 || double.IsNaN(gameTime) || double.IsInfinity(gameTime))
			{
				return false;
			}
			Sample sample = _samples[0];
			Sample sample2 = _samples[_samples.Count - 1];
			double num = sample2.Time - sample.Time;
			if (num < 5.0 || gameTime < sample2.Time || gameTime - sample2.Time > 12.0)
			{
				return false;
			}
			speed = (float)((double)(sample.Size - sample2.Size) / num);
			if (IsValidSpeed(speed))
			{
				return speed >= 0.02f;
			}
			return false;
		}
	}
	internal static class GameplayRules
	{
		internal static bool IsFinite(float value)
		{
			if (!float.IsNaN(value))
			{
				return !float.IsInfinity(value);
			}
			return false;
		}

		internal static bool ShouldShowMovingFogSpeed(bool moving, bool paused, bool arrived, float speed)
		{
			if (moving && !paused && !arrived && IsFinite(speed))
			{
				return speed > 0f;
			}
			return false;
		}

		internal static bool TryGetVerticalHazardDistance(float playerHeight, float surfaceHeight, out float distance)
		{
			distance = 0f;
			if (!IsFinite(playerHeight) || !IsFinite(surfaceHeight))
			{
				return false;
			}
			float num = playerHeight - surfaceHeight;
			if (!IsFinite(num))
			{
				return false;
			}
			distance = Math.Max(num, 0f);
			return true;
		}

		internal static bool ShouldBlockFogStatus(bool localCharacter, bool skeleton, int statusIndex, bool fogSource, bool suppressFog)
		{
			if (localCharacter && fogSource && suppressFog)
			{
				return statusIndex == ((!skeleton) ? 2 : 0);
			}
			return false;
		}

		internal static float GetNightColdRate(bool enabled, bool skeleton, int progress, float dayFactor, float baseRate)
		{
			if (!enabled || skeleton || progress >= 3 || !IsFinite(dayFactor) || dayFactor >= 0.5f || !IsFinite(baseRate) || baseRate <= 0f)
			{
				return 0f;
			}
			return baseRate * (1f - Math.Max(0f, dayFactor));
		}

		internal static float GetFogDamageRate(float baseRate, float difficulty)
		{
			float num = ((IsFinite(baseRate) && IsFinite(difficulty)) ? (Math.Max(0f, baseRate) * Math.Max(0f, difficulty)) : 0f);
			if (!IsFinite(num))
			{
				return 0f;
			}
			return num;
		}

		internal static float GetWeatherRemaining(float remaining, double sentAt, double now, float timeScale)
		{
			return (float)Math.Max(0.0, (double)remaining - Math.Max(0.0, now - sentAt) * (double)timeScale);
		}
	}
	internal sealed class StatusCompensationLedger
	{
		private struct Entry
		{
			internal int Status;

			internal float Pending;
		}

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

		internal float Accumulate(int actor, int status, float rate, float gameElapsed, bool send)
		{
			_entries.TryGetValue(actor, out var value);
			if (value.Status != status)
			{
				value.Pending = 0f;
			}
			value.Status = status;
			if (GameplayRules.IsFinite(rate) && rate > 0f && GameplayRules.IsFinite(gameElapsed) && gameElapsed > 0f)
			{
				float num = value.Pending + rate * gameElapsed;
				if (GameplayRules.IsFinite(num))
				{
					value.Pending = num;
				}
			}
			float result = (send ? value.Pending : 0f);
			if (send)
			{
				_entries.Remove(actor);
				return result;
			}
			_entries[actor] = value;
			return result;
		}

		internal void Remove(int actor)
		{
			_entries.Remove(actor);
		}

		internal void Clear()
		{
			_entries.Clear();
		}

		internal void Retain(HashSet<int> actors)
		{
			int[] array = _entries.Keys.Where((int actor) => !actors.Contains(actor)).ToArray();
			foreach (int key in array)
			{
				_entries.Remove(key);
			}
		}
	}
	[BepInPlugin("com.github.Thanks.FogClimb", "Fog&ColdControl", "1.2.0")]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	public sealed class Plugin : BaseUnityPlugin, IOnEventCallback
	{
		private sealed class PendingWeatherSnapshot
		{
			internal object[] Data;

			internal int Sender;

			internal float ReceivedAt;
		}

		private enum ConfigKey
		{
			ModEnabled,
			FogColdSuppression,
			NightColdEnabled,
			FogSpeed,
			FogDelay,
			CompassEnabled,
			CompassHotkey,
			FogPauseHotkey,
			FogUiEnabled,
			CampfireLocatorUiEnabled,
			FogUiX,
			FogUiY,
			FogUiScale,
			FogUiEntrySpacing,
			FogUiLayout,
			FogUiBackgroundOpacity,
			FogStateUiEnabled,
			RunTimerUiEnabled,
			DayNightTimeUiEnabled,
			AltitudeUiEnabled,
			FogSpeedUiEnabled,
			CampfireDistanceUiEnabled,
			WeatherHazardUiEnabled,
			FogTimingUiEnabled,
			DirectStartUiEnabled,
			FogApproachUiEnabled,
			LavaApproachUiEnabled,
			NextBiomeUiEnabled
		}

		internal enum FogUiLayoutKind
		{
			Horizontal,
			Vertical
		}

		private enum VanillaProgressStartUiState
		{
			Hidden,
			Unavailable,
			Tracking
		}

		private enum FogUiIconKind
		{
			StateRunning,
			StateWaiting,
			StatePaused,
			StateArrived,
			StateSyncing,
			StateOff,
			StateLobby,
			StateIdle,
			Speed,
			Delay,
			Timer,
			Campfire,
			Biome,
			Altitude,
			Lava,
			Distance,
			Direct,
			FogHandling,
			Night,
			DayTime,
			NightTime,
			Wind,
			Snowstorm,
			Rain
		}

		private enum FogUiThemeKind
		{
			Day,
			Night,
			Fog
		}

		private sealed class FogUiEntryView
		{
			public RectTransform Root;

			public Image Icon;

			public TextMeshProUGUI Text;

			public string LastText = string.Empty;

			public FogUiIconKind LastIconKind;

			public Color LastIconColor = Color.clear;

			public Color LastTextColor = Color.clear;

			public float LastContentWidth = -1f;
		}

		private sealed class ConfigFileEntryBlock
		{
			public ConfigKey Key;

			public bool HasKnownKey;

			public string SectionName = string.Empty;

			public List<string> Lines = new List<string>();
		}

		private readonly struct FogUiDisplayEntry
		{
			public readonly FogUiIconKind Kind;

			public readonly Color IconColor;

			public readonly string Text;

			public FogUiDisplayEntry(FogUiIconKind kind, Color iconColor, string text)
			{
				//IL_0008: Unknown result type (might be due to invalid IL or missing references)
				//IL_0009: Unknown result type (might be due to invalid IL or missing references)
				Kind = kind;
				IconColor = iconColor;
				Text = text ?? string.Empty;
			}
		}

		private const int StatusProtocolVersion = 2;

		private const string StatusProtocolKey = "FogClimb.StatusProtocol";

		private const string StatusSceneKey = "FogClimb.StatusScene";

		private const string SuppressFogKey = "FogClimb.SuppressFog";

		private const string SuppressNightKey = "FogClimb.SuppressNight";

		private const byte WeatherSnapshotEventCode = 169;

		private const string WeatherSnapshotTag = "FogClimb.Weather.2";

		private readonly HashSet<int> _pendingWeatherActors = new HashSet<int>();

		private readonly List<PendingWeatherSnapshot> _pendingWeatherSnapshots = new List<PendingWeatherSnapshot>();

		private readonly Dictionary<WindChillZone, double> _weatherTransitionTimes = new Dictionary<WindChillZone, double>();

		private static readonly FieldInfo WindDurationField = AccessTools.Field(typeof(WindChillZone), "timeUntilNextWind");

		private static readonly FieldInfo WindRemainingField = AccessTools.Field(typeof(WindChillZone), "untilSwitch");

		private static readonly FieldInfo WindDirectionField = AccessTools.Field(typeof(WindChillZone), "currentWindDirection");

		private static readonly FieldInfo WindActiveTimeField = AccessTools.Field(typeof(WindChillZone), "hasBeenActiveFor");

		private static readonly FieldInfo WindForceField = AccessTools.Field(typeof(WindChillZone), "currentForceMult");

		private readonly Dictionary<OrbFogHandler, float> _originalFogSpeeds = new Dictionary<OrbFogHandler, float>();

		private readonly Dictionary<FogSphereOrigin, bool> _originalFogDisabled = new Dictionary<FogSphereOrigin, bool>();

		private readonly Dictionary<GameObject, bool> _originalFogObjectActive = new Dictionary<GameObject, bool>();

		public const string PluginGuid = "com.github.Thanks.FogClimb";

		public const string PluginName = "Fog&ColdControl";

		public const string PluginVersion = "1.2.0";

		private static readonly string[] LegacyConfigFileNames = new string[2] { "Thanks.FogClimb.cfg", "com.github.Thanks.FogClimb.cfg" };

		private static readonly string[] LegacyPluginFileNames = new string[2] { "Thanks.FogClimb.dll", "com.github.Thanks.FogClimb.dll" };

		private const float DefaultFogUiEntrySpacing = 8f;

		private const float MinFogUiEntrySpacing = 0f;

		private const float MaxFogUiEntrySpacing = 40f;

		private const float DefaultFogUiBackgroundOpacity = 0f;

		private const float MinFogUiBackgroundOpacity = 0f;

		private const float MaxFogUiBackgroundOpacity = 1f;

		private const int FogUiBackgroundSpriteSize = 64;

		private const float FogUiBackgroundCornerRadiusX = 12f;

		private const float FogUiBackgroundCornerRadiusY = 10f;

		private const float FogUiBackgroundSliceBorderX = 12f;

		private const float FogUiBackgroundSliceBorderY = 10f;

		private const float FogUiVerticalContainerWidth = 176f;

		private const float FogUiVerticalMinHeight = 34f;

		private const float FogUiEntryHeight = 34f;

		private const float FogUiHorizontalWidth = 1180f;

		private const float FogUiHorizontalHeight = 34f;

		private const float FogUiBackgroundVerticalPadding = 2f;

		private const float FogUiIconSize = 20f;

		private const float FogUiEntryIconTextSpacing = 4f;

		private const float CampfireLocatorUiWidth = 420f;

		private const float CampfireLocatorUiHeight = 52f;

		private const float CampfireLocatorLineWidth = 400f;

		private const float CampfireLocatorLineHeight = 2f;

		private const float CampfireLocatorDotSize = 22f;

		private const float CampfireLocatorTickHeight = 8f;

		private const float CampfireLocatorTickWidth = 1.5f;

		private const float CampfireLocatorCenterTickHeight = 12f;

		private const float CampfireLocatorCenterTickWidth = 2.5f;

		private const float CampfireLocatorDistanceFontSize = 14f;

		private const float WeatherIncomingWarningSeconds = 5f;

		private const float WeatherNoticeFontSize = 22f;

		private const string FogUiCountdownDangerLabelColor = "#FF6B5F";

		private const string FogUiCountdownDangerValueColor = "#FFD0C8";

		private const string FogUiDelayCountdownStartLabelColor = "#FF9A8A";

		private const string FogUiDelayCountdownStartValueColor = "#FFD6D6";

		private const string FogUiDelayCountdownEndLabelColor = "#FF5A4D";

		private const string FogUiDelayCountdownEndValueColor = "#FFB0A8";

		private const float FogUiEntryMaxWidth = 220f;

		private static readonly ushort CompassItemIdOverride = 0;

		private const string NetworkInstallStateKey = "FogClimb.Enabled";

		private static readonly BindingFlags InstanceBindingFlags = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic;

		private static readonly PropertyInfo ConfigFileEntriesProperty = typeof(ConfigFile).GetProperty("Entries", InstanceBindingFlags);

		private static readonly FieldInfo BasePluginConfigBackingField = typeof(BaseUnityPlugin).GetField("<Config>k__BackingField", InstanceBindingFlags);

		private static readonly FieldInfo OrbFogHandlerOriginsField = typeof(OrbFogHandler).GetField("origins", InstanceBindingFlags);

		private static readonly FieldInfo OrbFogHandlerSphereField = typeof(OrbFogHandler).GetField("sphere", InstanceBindingFlags);

		private static readonly FieldInfo RunManagerRunStartedField = typeof(RunManager).GetField("runStarted", InstanceBindingFlags);

		private static readonly FieldInfo RunManagerTimerActiveField = typeof(RunManager).GetField("timerActive", InstanceBindingFlags);

		private static readonly int StatusTypeCount = Enum.GetNames(typeof(STATUSTYPE)).Length;

		private static readonly string[] DayNightTimeMemberCandidates = new string[6] { "timeOfDayNormalized", "currentTime", "time", "timeOfDay", "timeNormalized", "cycleTime" };

		private static readonly string[] DayNightDayCountMemberCandidates = new string[7] { "dayCount", "dayIndex", "currentDay", "dayNumber", "daysPassed", "totalDays", "day" };

		private static readonly ConfigKey[] BasicConfigFileOrder = new ConfigKey[5]
		{
			ConfigKey.FogColdSuppression,
			ConfigKey.NightColdEnabled,
			ConfigKey.FogSpeed,
			ConfigKey.FogDelay,
			ConfigKey.FogPauseHotkey
		};

		private static readonly ConfigKey[] AdjustmentConfigFileOrder = new ConfigKey[23]
		{
			ConfigKey.ModEnabled,
			ConfigKey.FogUiEnabled,
			ConfigKey.CampfireLocatorUiEnabled,
			ConfigKey.FogStateUiEnabled,
			ConfigKey.RunTimerUiEnabled,
			ConfigKey.DayNightTimeUiEnabled,
			ConfigKey.AltitudeUiEnabled,
			ConfigKey.FogSpeedUiEnabled,
			ConfigKey.CampfireDistanceUiEnabled,
			ConfigKey.WeatherHazardUiEnabled,
			ConfigKey.FogTimingUiEnabled,
			ConfigKey.DirectStartUiEnabled,
			ConfigKey.FogApproachUiEnabled,
			ConfigKey.LavaApproachUiEnabled,
			ConfigKey.NextBiomeUiEnabled,
			ConfigKey.CompassEnabled,
			ConfigKey.CompassHotkey,
			ConfigKey.FogUiX,
			ConfigKey.FogUiY,
			ConfigKey.FogUiScale,
			ConfigKey.FogUiEntrySpacing,
			ConfigKey.FogUiLayout,
			ConfigKey.FogUiBackgroundOpacity
		};

		private static readonly Color CampfireLocatorLineColor = new Color(1f, 1f, 1f, 0.95f);

		private static int _localFogStatusSourceDepth;

		private Harmony _harmony;

		private OrbFogHandler _orbFogHandler;

		private FogSphere _fogSphere;

		private Fog _legacyFog;

		private bool _fogStateInitialized;

		private bool _initialDelayCompleted;

		private int _trackedFogOriginId = -1;

		private float _fogDelayTimer;

		private float _fogHiddenBufferTimer;

		private float _fogHandlerSearchTimer;

		private float _lastFogStateSyncTime = -0.18f;

		private float _lastRemoteStatusSyncTime = -0.25f;

		private float _lastCompassGrantSyncTime = -0.75f;

		private bool _lastHadFogAuthority;

		private bool _lastModEnabledState;

		private bool _lastDetectedChineseLanguage;

		private bool _isRefreshingLanguage;

		private bool _pendingConfigFileLocalizationRefresh;

		private bool _pendingConfigFileLocalizationSave;

		private bool _pendingConfigFileOrderRefresh;

		private FogUiLayoutKind _lastFogUiLayout;

		private bool _hasAdvertisedInstallState;

		private bool _lastAdvertisedInstallState;

		private string _lastObservedRoomKey = string.Empty;

		private float _hiddenNightTestHoldTimer;

		private bool _hiddenNightTestTriggeredThisHold;

		private bool _fogPaused;

		private readonly HashSet<int> _grantedCampfireCompassIds = new HashSet<int>();

		private readonly HashSet<int> _restoredCheckpointCampfireIds = new HashSet<int>();

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

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

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

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

		private Item _compassItem;

		private RectTransform _fogUiRect;

		private bool _fogUiLayoutDirty;

		private int _lastFogUiEntryLayoutCount = -1;

		private float _lastFogUiEntrySpacing = -1f;

		private RectTransform _fogUiEntriesRect;

		private Image _fogUiBackgroundImage;

		private Sprite _fogUiBackgroundSprite;

		private bool _fogUiThemeInitialized;

		private FogUiThemeKind _fogUiThemeKind;

		private readonly List<FogUiEntryView> _fogUiEntryViews = new List<FogUiEntryView>();

		private readonly List<FogUiDisplayEntry> _fogUiDisplayEntries = new List<FogUiDisplayEntry>(9);

		private readonly Dictionary<FogUiIconKind, Sprite> _fogUiIconSprites = new Dictionary<FogUiIconKind, Sprite>();

		private Sprite _campfireLocatorDotSprite;

		private Sprite _campfireLocatorLineSprite;

		private Sprite _nativeCampfireIconSprite;

		private Sprite _nativePoisonIconSprite;

		private Sprite _nativeDrowsyIconSprite;

		private Sprite _nativeAltitudeIconSprite;

		private float _lastNativeIconAttemptTime = -999f;

		private StormVisual[] _cachedStormVisuals;

		private float _lastStormVisualScanTime = -999f;

		private WeatherHazardKind _weatherUiShownKind;

		private float _weatherUiShownRemaining;

		private bool _weatherUiShownIsWarning;

		private RectTransform _weatherHazardNoticeRect;

		private TextMeshProUGUI _weatherHazardNoticeText;

		private TextMeshProUGUI _weatherHazardTimerText;

		private TextMeshProUGUI _weatherHazardSuffixText;

		private readonly List<Material> _weatherNoticeMaterials = new List<Material>();

		private float _weatherNoticeTimerWidth;

		private WeatherHazardKind _weatherNoticeLayoutKind;

		private bool _weatherNoticeLayoutIncoming;

		private static readonly bool EnableDebugDiagnostics = false;

		private static LavaRising _cachedSceneLavaRising;

		private static Segment _cachedSceneLavaSegment = (Segment)0;

		private static bool _cachedSceneLavaValid;

		private static float _cachedSceneLavaScanTime = -999f;

		private float _pendingWeatherStateBroadcastTime = -1f;

		private int _weatherStateBroadcastRetryCount;

		private RectTransform _campfireLocatorUiRect;

		private RectTransform _campfireLocatorDotRect;

		private Image _campfireLocatorDotImage;

		private TextMeshProUGUI _campfireLocatorDistanceText;

		private float _campfireLocatorCurrentDotX;

		private RectTransform _compassLobbyNoticeRect;

		private TextMeshProUGUI _compassLobbyNoticeText;

		private string _lastCompassLobbyNoticeText = string.Empty;

		private float _fogUiStateAnimTime;

		private bool _initialCompassGranted;

		private int _totalCompassGrantCount;

		private bool _hasSyncedFogStateSnapshot;

		private int _lastSyncedFogOriginId = -1;

		private float _lastSyncedFogSize = float.NaN;

		private bool _lastSyncedFogIsMoving;

		private bool _lastSyncedFogHasArrived;

		private int _delayedFogOriginId = -1;

		private int _pendingSyntheticFogSegmentId = -1;

		private int _activeSyntheticFogSegmentId = -1;

		private Vector3 _syntheticFogPoint;

		private float _syntheticFogStartSize;

		private int _fogDistanceTrackedOriginId = -1;

		private float _fogDistanceLastObservedSize = float.NaN;

		private float _fogDistanceLastObservedTime = -1f;

		private float _fogDistanceEstimatedUnitsPerSecond;

		private bool _fogDistanceHasReliableRate;

		private float _fogDistanceLastAppliedHandlerSpeed = -1f;

		private float _lastAdvertisedFogSpeed = -1f;

		private int _lastAdvertisedFogSpeedOrigin = -1;

		private string _lastAdvertisedFogSpeedScene;

		private float _lastFogSpeedAdvertiseTime = -999f;

		private float _syncedHostFogSpeed = -1f;

		private float _guestAppliedFogSpeed = -1f;

		private float _fogDistanceLastRefreshTime = -1f;

		private bool _fogDistanceHasSnapshot;

		private float _fogDistanceRemainingDistance;

		private float _lastGuestFogDiagLogTime = -999f;

		private float _lastHostFogSyncDiagLogTime = -999f;

		private float _lastInstallAdvertiseDiagLogTime = -999f;

		private static FieldInfo _stormVisualZoneField;

		private static FieldInfo _windChillDirectionField;

		private static FieldInfo _windChillUntilSwitchField;

		private static readonly FieldInfo MovingLavaStartedField = AccessTools.Field(typeof(MovingLava), "timeToMove");

		private MovingLava[] _cachedKilnLava;

		private float _lastKilnLavaScan = -999f;

		private readonly StatusCompensationLedger _remoteStatusCompensation = new StatusCompensationLedger();

		private static readonly FieldInfo CharacterInvincibilityField = AccessTools.Field(typeof(CharacterData), "isInvincible");

		private readonly FogSpeedSamples _guestFogSpeedSamples = new FogSpeedSamples();

		private OrbFogHandler _guestFogSampleHandler;

		private int _guestFogSampleHostId = -1;

		internal static ConfigEntry<bool> CompassEnabled { get; private set; }

		internal static ConfigEntry<KeyCode> CompassHotkey { get; private set; }

		internal static ConfigEntry<bool> ModEnabled { get; private set; }

		internal static ConfigEntry<bool> FogColdSuppression { get; private set; }

		internal static ConfigEntry<bool> NightColdEnabled { get; private set; }

		internal static ConfigEntry<float> FogSpeed { get; private set; }

		internal static ConfigEntry<float> FogDelay { get; private set; }

		internal static ConfigEntry<KeyCode> FogPauseHotkey { get; private set; }

		internal static ConfigEntry<bool> FogUiEnabled { get; private set; }

		internal static ConfigEntry<bool> CampfireLocatorUiEnabled { get; private set; }

		internal static ConfigEntry<float> FogUiX { get; private set; }

		internal static ConfigEntry<float> FogUiY { get; private set; }

		internal static ConfigEntry<float> FogUiScale { get; private set; }

		internal static ConfigEntry<float> FogUiEntrySpacing { get; private set; }

		internal static ConfigEntry<FogUiLayoutKind> FogUiLayout { get; private set; }

		internal static ConfigEntry<float> FogUiBackgroundOpacity { get; private set; }

		internal static ConfigEntry<bool> FogStateUiEnabled { get; private set; }

		internal static ConfigEntry<bool> RunTimerUiEnabled { get; private set; }

		internal static ConfigEntry<bool> DayNightTimeUiEnabled { get; private set; }

		internal static ConfigEntry<bool> AltitudeUiEnabled { get; private set; }

		internal static ConfigEntry<bool> FogSpeedUiEnabled { get; private set; }

		internal static ConfigEntry<bool> CampfireDistanceUiEnabled { get; private set; }

		internal static ConfigEntry<bool> WeatherHazardUiEnabled { get; private set; }

		internal static ConfigEntry<bool> FogTimingUiEnabled { get; private set; }

		internal static ConfigEntry<bool> DirectStartUiEnabled { get; private set; }

		internal static ConfigEntry<bool> FogApproachUiEnabled { get; private set; }

		internal static ConfigEntry<bool> LavaApproachUiEnabled { get; private set; }

		internal static ConfigEntry<bool> NextBiomeUiEnabled { get; private set; }

		internal static Plugin Instance { get; private set; }

		private static bool SupportsSourceStatusPolicy(Player player)
		{
			object obj;
			if (player == null)
			{
				obj = null;
			}
			else
			{
				Hashtable customProperties = player.CustomProperties;
				obj = ((customProperties != null) ? customProperties[(object)"FogClimb.StatusProtocol"] : null);
			}
			if (obj is int num)
			{
				return num >= 2;
			}
			return false;
		}

		private static bool UsesSourceStatusPolicy(Player player)
		{
			bool isEnabled = default(bool);
			return SupportsSourceStatusPolicy(player) && TryReadInstallState(player, out isEnabled) && isEnabled;
		}

		private void UpdateStatusPolicyAdvertisement()
		{
			//IL_0022: 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_0085: 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_009b: Expected O, but got Unknown
			//IL_009b: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ac: Expected O, but got Unknown
			//IL_00ac: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b8: Expected O, but got Unknown
			//IL_00bf: Expected O, but got Unknown
			if (PhotonNetwork.InRoom && PhotonNetwork.IsMasterClient && PhotonNetwork.LocalPlayer != null)
			{
				bool flag = ShouldSuppressFogColdDamage();
				bool flag2 = ShouldDisableNightColdFeatureLocally();
				Scene activeScene = SceneManager.GetActiveScene();
				string name = ((Scene)(ref activeScene)).name;
				Hashtable customProperties = PhotonNetwork.LocalPlayer.CustomProperties;
				if (!object.Equals(customProperties[(object)"FogClimb.SuppressFog"], flag) || !object.Equals(customProperties[(object)"FogClimb.SuppressNight"], flag2) || !object.Equals(customProperties[(object)"FogClimb.StatusScene"], name))
				{
					Player localPlayer = PhotonNetwork.LocalPlayer;
					Hashtable val = new Hashtable();
					((Dictionary<object, object>)val).Add((object)"FogClimb.SuppressFog", (object)flag);
					((Dictionary<object, object>)val).Add((object)"FogClimb.SuppressNight", (object)flag2);
					((Dictionary<object, object>)val).Add((object)"FogClimb.StatusScene", (object)name);
					localPlayer.SetCustomProperties(val, (Hashtable)null, (WebFlags)null);
				}
			}
		}

		private static bool TryReadHostStatusPolicy(out bool fog, out bool night)
		{
			//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)
			fog = (night = false);
			Player masterClient = PhotonNetwork.MasterClient;
			if (PhotonNetwork.InRoom && !PhotonNetwork.IsMasterClient && UsesSourceStatusPolicy(masterClient))
			{
				object objA = masterClient.CustomProperties[(object)"FogClimb.StatusScene"];
				Scene activeScene = SceneManager.GetActiveScene();
				if (object.Equals(objA, ((Scene)(ref activeScene)).name))
				{
					if (!(masterClient.CustomProperties[(object)"FogClimb.SuppressFog"] is bool flag) || !(masterClient.CustomProperties[(object)"FogClimb.SuppressNight"] is bool flag2))
					{
						return false;
					}
					fog = flag;
					night = flag2;
					return true;
				}
			}
			return false;
		}

		public void OnEvent(EventData photonEvent)
		{
			if (photonEvent.Code == 169 && IsModFeatureEnabled() && PhotonNetwork.InRoom && !PhotonNetwork.IsMasterClient)
			{
				int sender = photonEvent.Sender;
				Player masterClient = PhotonNetwork.MasterClient;
				if (sender == ((masterClient != null) ? new int?(masterClient.ActorNumber) : ((int?)null)) && UsesSourceStatusPolicy(PhotonNetwork.MasterClient) && photonEvent.CustomData is object[] array && array.Length == 11 && object.Equals(array[0], "FogClimb.Weather.2"))
				{
					_pendingWeatherSnapshots.Add(new PendingWeatherSnapshot
					{
						Data = array,
						Sender = photonEvent.Sender,
						ReceivedAt = Time.unscaledTime
					});
				}
			}
		}

		private void ApplyPendingWeatherSnapshots()
		{
			for (int num = _pendingWeatherSnapshots.Count - 1; num >= 0; num--)
			{
				PendingWeatherSnapshot pendingWeatherSnapshot = _pendingWeatherSnapshots[num];
				if (IsModFeatureEnabled() && PhotonNetwork.InRoom)
				{
					int sender = pendingWeatherSnapshot.Sender;
					Player masterClient = PhotonNetwork.MasterClient;
					if (sender == ((masterClient != null) ? new int?(masterClient.ActorNumber) : ((int?)null)) && !(Time.unscaledTime - pendingWeatherSnapshot.ReceivedAt > 30f) && !TryApplyWeatherSnapshot(pendingWeatherSnapshot.Data))
					{
						continue;
					}
				}
				_pendingWeatherSnapshots.RemoveAt(num);
			}
		}

		internal static void NotifyWeatherTransition(WindChillZone zone)
		{
			if ((Object)(object)Instance != (Object)null && (Object)(object)zone != (Object)null)
			{
				Instance._weatherTransitionTimes[zone] = PhotonNetwork.Time;
			}
		}

		private bool TryApplyWeatherSnapshot(object[] data)
		{
			//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_0066: 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_0254: Unknown result type (might be due to invalid IL or missing references)
			object objA = data[1];
			Scene activeScene = SceneManager.GetActiveScene();
			if (!object.Equals(objA, ((Scene)(ref activeScene)).name) || LoadingScreenHandler.loading)
			{
				return false;
			}
			if (!(data[2] is int num) || !(data[3] is bool flag) || !(data[4] is Vector3 val) || !(data[5] is float num2) || !(data[6] is float num3) || !(data[7] is double num4) || !(data[8] is float num5) || !(data[9] is float num6) || !(data[10] is float num7) || !GameplayRules.IsFinite(num6) || !GameplayRules.IsFinite(num7) || !GameplayRules.IsFinite(num2) || num2 < 0f || !GameplayRules.IsFinite(num3) || num3 <= 0f || !GameplayRules.IsFinite(num5) || num5 < 0f || double.IsNaN(num4) || double.IsInfinity(num4))
			{
				return true;
			}
			PhotonView val2 = PhotonView.Find(num);
			WindChillZone val3 = (((Object)(object)val2 != (Object)null) ? ((Component)val2).GetComponent<WindChillZone>() : null);
			if ((Object)(object)val3 == (Object)null || !((Behaviour)val3).isActiveAndEnabled || WindDurationField == null || WindRemainingField == null || WindDirectionField == null || WindActiveTimeField == null || WindForceField == null)
			{
				return false;
			}
			if (_weatherTransitionTimes.TryGetValue(val3, out var value) && value >= num4)
			{
				return true;
			}
			float num8 = (float)Math.Max(0.0, PhotonNetwork.Time - num4) * num5;
			float weatherRemaining = GameplayRules.GetWeatherRemaining(num2, num4, PhotonNetwork.Time, num5);
			if (weatherRemaining <= 0f)
			{
				return true;
			}
			val3.windActive = flag;
			WindRemainingField.SetValue(val3, weatherRemaining);
			WindDurationField.SetValue(val3, num3);
			WindDirectionField.SetValue(val3, val);
			WindActiveTimeField.SetValue(val3, flag ? Mathf.Max(num6 + num8, 0f) : 0f);
			WindForceField.SetValue(val3, Mathf.MoveTowards(num7, flag ? 1f : 0f, num8));
			val3.StormProgress = (flag ? Mathf.Clamp01(1f - weatherRemaining / num3) : 0f);
			val3.timeUntilStorm = (flag ? 0f : Mathf.Clamp01(1f - weatherRemaining / num3));
			if (val3.windIntensityCurve != null)
			{
				val3.windIntensity = val3.windIntensityCurve.Evaluate(val3.StormProgress);
			}
			return true;
		}

		private void CaptureFogSpeed(OrbFogHandler handler)
		{
			if ((Object)(object)handler != (Object)null && !_originalFogSpeeds.ContainsKey(handler))
			{
				_originalFogSpeeds.Add(handler, handler.speed);
			}
		}

		private void SetFogObjectActive(GameObject target, bool active)
		{
			if (!((Object)(object)target == (Object)null) && target.activeSelf != active)
			{
				if (!_originalFogObjectActive.ContainsKey(target))
				{
					_originalFogObjectActive.Add(target, target.activeSelf);
				}
				target.SetActive(active);
			}
		}

		private void EnableFogOrigin(FogSphereOrigin origin)
		{
			if (!((Object)(object)origin == (Object)null) && origin.disableFog)
			{
				if (!_originalFogDisabled.ContainsKey(origin))
				{
					_originalFogDisabled.Add(origin, origin.disableFog);
				}
				origin.disableFog = false;
			}
		}

		private void RestoreFogOverrides()
		{
			foreach (KeyValuePair<OrbFogHandler, float> originalFogSpeed in _originalFogSpeeds)
			{
				if ((Object)(object)originalFogSpeed.Key != (Object)null)
				{
					originalFogSpeed.Key.speed = originalFogSpeed.Value;
				}
			}
			foreach (KeyValuePair<FogSphereOrigin, bool> item in _originalFogDisabled)
			{
				if ((Object)(object)item.Key != (Object)null)
				{
					item.Key.disableFog = item.Value;
				}
			}
			foreach (KeyValuePair<GameObject, bool> item2 in _originalFogObjectActive)
			{
				if ((Object)(object)item2.Key != (Object)null)
				{
					item2.Key.SetActive(item2.Value);
				}
			}
			_originalFogSpeeds.Clear();
			_originalFogDisabled.Clear();
			_originalFogObjectActive.Clear();
		}

		private void TryGrantInitialCompassIfNeeded()
		{
			if (!_initialCompassGranted && !((Object)(object)_orbFogHandler == (Object)null) && _orbFogHandler.currentID == 0 && _initialDelayCompleted && _orbFogHandler.isMoving && !HasRemotePlayersInJoinGracePeriod())
			{
				_initialCompassGranted = true;
				GrantCompassToAllPlayers("initial-delay-ended");
			}
		}

		private bool TryResolveCompassItem()
		{
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0035: Expected O, but got Unknown
			//IL_007e: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)_compassItem != (Object)null)
			{
				return true;
			}
			if (TryResolveCompassItemOverride(out var item))
			{
				_compassItem = item;
				return true;
			}
			ItemDatabase instance = SingletonAsset<ItemDatabase>.Instance;
			if ((Object)instance == (Object)null || ((DatabaseAsset<ItemDatabase, Item>)(object)instance).Objects == null)
			{
				return false;
			}
			List<string> list = new List<string>();
			foreach (Item @object in ((DatabaseAsset<ItemDatabase, Item>)(object)instance).Objects)
			{
				if ((Object)(object)@object == (Object)null)
				{
					continue;
				}
				CompassPointer componentInChildren = ((Component)@object).GetComponentInChildren<CompassPointer>(true);
				if (!((Object)(object)componentInChildren == (Object)null) && (int)componentInChildren.compassType == 0)
				{
					list.Add(DescribeCompassItem(@object));
					if (LooksLikeStandardCompassItem(@object))
					{
						_compassItem = @object;
						((BaseUnityPlugin)this).Logger.LogInfo((object)("[Fog&ColdControl] Using normal compass item: " + DescribeCompassItem(@object)));
						return true;
					}
				}
			}
			if (list.Count > 0)
			{
				((BaseUnityPlugin)this).Logger.LogWarning((object)("[Fog&ColdControl] Failed to identify the standard compass automatically. Set CompassItemIdOverride manually. Candidates: " + string.Join(", ", list)));
			}
			return false;
		}

		private bool TryResolveCompassItemOverride(out Item item)
		{
			item = null;
			if (CompassItemIdOverride <= 0)
			{
				return false;
			}
			Item val = default(Item);
			if (!ItemDatabase.TryGetItem(CompassItemIdOverride, ref val) || (Object)(object)val == (Object)null)
			{
				((BaseUnityPlugin)this).Logger.LogWarning((object)string.Format("[{0}] CompassItemIdOverride={1} is invalid.", "Fog&ColdControl", CompassItemIdOverride));
				return false;
			}
			item = val;
			((BaseUnityPlugin)this).Logger.LogInfo((object)("[Fog&ColdControl] Using compass item override: " + DescribeCompassItem(item)));
			return true;
		}

		private static bool LooksLikeStandardCompassItem(Item item)
		{
			if ((Object)(object)item == (Object)null)
			{
				return false;
			}
			string obj = ((Object)item).name ?? string.Empty;
			string text = item.UIData?.itemName ?? string.Empty;
			if (obj.IndexOf("Compass", StringComparison.OrdinalIgnoreCase) < 0)
			{
				return text.IndexOf("Compass", StringComparison.OrdinalIgnoreCase) >= 0;
			}
			return true;
		}

		private static string DescribeCompassItem(Item item)
		{
			if ((Object)(object)item == (Object)null)
			{
				return "<null>";
			}
			string arg = item.UIData?.itemName ?? string.Empty;
			return $"{((Object)item).name} (itemID={item.itemID}, uiName={arg})";
		}

		private void GrantCompassToAllPlayers(string reason)
		{
			if (IsModFeatureEnabled() && HasFogAuthority() && IsCompassFeatureEnabled())
			{
				_totalCompassGrantCount++;
				((BaseUnityPlugin)this).Logger.LogDebug((object)string.Format("[{0}] Queued compass grant #{1} ({2}).", "Fog&ColdControl", _totalCompassGrantCount, reason));
				SyncCompassGrantsToPlayers(force: true, reason);
			}
		}

		private void SyncCompassGrantsToPlayersIfNeeded()
		{
			if (IsModFeatureEnabled() && HasFogAuthority() && IsCompassFeatureEnabled() && _totalCompassGrantCount > 0 && !(Time.unscaledTime - _lastCompassGrantSyncTime < 0.75f))
			{
				SyncCompassGrantsToPlayers(force: false, "periodic-sync");
			}
		}

		private void SyncCompassGrantsToPlayers(bool force, string reason)
		{
			if (!IsModFeatureEnabled() || !HasFogAuthority() || !IsCompassFeatureEnabled() || _totalCompassGrantCount <= 0)
			{
				return;
			}
			if (!TryResolveCompassItem())
			{
				((BaseUnityPlugin)this).Logger.LogWarning((object)("[Fog&ColdControl] Failed to resolve compass item while syncing grants (" + reason + ")."));
				return;
			}
			_lastCompassGrantSyncTime = Time.unscaledTime;
			HashSet<int> activePlayerKeys = new HashSet<int>();
			Dictionary<int, Player> dictionary = new Dictionary<int, Player>();
			foreach (Player item in EnumerateTargetPlayers())
			{
				if (!IsPlayerPastJoinGrace(item))
				{
					continue;
				}
				int playerCompassGrantKey = GetPlayerCompassGrantKey(item);
				activePlayerKeys.Add(playerCompassGrantKey);
				PhotonView component = ((Component)item).GetComponent<PhotonView>();
				int? obj;
				if (component == null)
				{
					obj = null;
				}
				else
				{
					Player owner = component.Owner;
					obj = ((owner != null) ? new int?(owner.ActorNumber) : ((int?)null));
				}
				int num = obj ?? (-1);
				if (num > 0 && !dictionary.ContainsKey(num))
				{
					dictionary[num] = item;
				}
				int num2 = GetDeliveredCompassGrantCount(item);
				int num3 = 0;
				while (num2 < _totalCompassGrantCount && GrantCompassToPlayer(item, $"{reason}-{num2 + 1}/{_totalCompassGrantCount}"))
				{
					num2++;
					num3++;
					if (num3 >= 1)
					{
						break;
					}
				}
				_playerCompassGrantCounts[playerCompassGrantKey] = num2;
			}
			TrySyncCompassGrantsToMissingActorPlayers(reason, activePlayerKeys, dictionary);
			int[] array = _playerCompassGrantCounts.Keys.Where((int item) => !activePlayerKeys.Contains(item)).ToArray();
			foreach (int key in array)
			{
				_playerCompassGrantCounts.Remove(key);
			}
		}

		private void TrySyncCompassGrantsToMissingActorPlayers(string reason, HashSet<int> activePlayerKeys, Dictionary<int, Player> playersByActorNumber)
		{
			if (!PhotonNetwork.InRoom || PhotonNetwork.CurrentRoom == null)
			{
				return;
			}
			Player localPlayer = PhotonNetwork.LocalPlayer;
			int num = ((localPlayer != null) ? localPlayer.ActorNumber : (-1));
			foreach (Player item in PhotonNetwork.CurrentRoom.Players.Values.OrderBy((Player player) => (player == null) ? int.MaxValue : player.ActorNumber))
			{
				int num2 = ((item != null) ? item.ActorNumber : (-1));
				if (num2 <= 0 || num2 == num || playersByActorNumber.ContainsKey(num2))
				{
					continue;
				}
				activePlayerKeys.Add(num2);
				if (!IsActorPastJoinGrace(num2))
				{
					continue;
				}
				int num3 = GetDeliveredCompassGrantCountForActor(num2);
				int num4 = 0;
				while (num3 < _totalCompassGrantCount && GrantCompassToActor(num2, $"{reason}-{num3 + 1}/{_totalCompassGrantCount}"))
				{
					num3++;
					num4++;
					if (num4 >= 1)
					{
						break;
					}
				}
				_playerCompassGrantCounts[num2] = num3;
			}
		}

		private static int GetPlayerCompassGrantKey(Player player)
		{
			if ((Object)(object)player == (Object)null)
			{
				return 0;
			}
			PhotonView component = ((Component)player).GetComponent<PhotonView>();
			if (((component != null) ? component.Owner : null) != null)
			{
				return component.Owner.ActorNumber;
			}
			return ((Object)player).GetInstanceID();
		}

		private int GetDeliveredCompassGrantCount(Player player)
		{
			int playerCompassGrantKey = GetPlayerCompassGrantKey(player);
			if (_playerCompassGrantCounts.TryGetValue(playerCompassGrantKey, out var value))
			{
				return value;
			}
			PhotonView val = (((Object)(object)player != (Object)null) ? ((Component)player).GetComponent<PhotonView>() : null);
			if (((val != null) ? val.Owner : null) != null && _remotePlayerCompassBaselineCounts.TryGetValue(val.Owner.ActorNumber, out var value2))
			{
				return value2;
			}
			return 0;
		}

		private int GetDeliveredCompassGrantCountForActor(int actorNumber)
		{
			if (_playerCompassGrantCounts.TryGetValue(actorNumber, out var value))
			{
				return value;
			}
			if (_remotePlayerCompassBaselineCounts.TryGetValue(actorNumber, out var value2))
			{
				return value2;
			}
			return 0;
		}

		private void ProcessPendingCampfireCompassGrants()
		{
			if (IsModFeatureEnabled() && HasFogAuthority() && IsCompassFeatureEnabled() && _pendingCampfireCompassGrantTimes.Count > 0 && !LoadingScreenHandler.loading)
			{
				float now = Time.unscaledTime;
				int[] array = _pendingCampfireCompassGrantTimes.Where(delegate(KeyValuePair<int, float> entry)
				{
					float num3 = now;
					KeyValuePair<int, float> keyValuePair = entry;
					return num3 >= keyValuePair.Value;
				}).Select(delegate(KeyValuePair<int, float> entry)
				{
					KeyValuePair<int, float> keyValuePair = entry;
					return keyValuePair.Key;
				}).ToArray();
				foreach (int num2 in array)
				{
					_pendingCampfireCompassGrantTimes.Remove(num2);
					((BaseUnityPlugin)this).Logger.LogInfo((object)string.Format("[{0}] Delivering delayed campfire compass grant for campfire #{1}.", "Fog&ColdControl", num2));
					GrantCompassToAllPlayers($"campfire-{num2}");
				}
			}
		}

		private bool GrantCompassToPlayer(Player player, string reason)
		{
			if ((Object)(object)player == (Object)null || (Object)(object)_compassItem == (Object)null || !IsPlayerPastJoinGrace(player))
			{
				return false;
			}
			PhotonView component = ((Component)player).GetComponent<PhotonView>();
			int? obj;
			if (component == null)
			{
				obj = null;
			}
			else
			{
				Player owner = component.Owner;
				obj = ((owner != null) ? new int?(owner.ActorNumber) : ((int?)null));
			}
			int actorNumber = obj ?? (-1);
			if (((component != null) ? component.Owner : null) != null && !component.IsMine)
			{
				Character val = player.character;
				if ((Object)(object)val == (Object)null || (Object)(object)val.data == (Object)null || val.data.dead)
				{
					val = ((IEnumerable<Character>)Character.AllCharacters).FirstOrDefault((Func<Character, bool>)((Character character) => (Object)(object)character != (Object)null && (Object)(object)((MonoBehaviourPun)character).photonView != (Object)null && ((MonoBehaviourPun)character).photonView.Owner != null && ((MonoBehaviourPun)character).photonView.Owner.ActorNumber == actorNumber && !character.isBot && !character.isZombie && (Object)(object)character.data != (Object)null && !character.data.dead));
				}
				if ((Object)(object)val != (Object)null)
				{
					return DropCompassInFrontOfCharacter(val, actorNumber, reason);
				}
			}
			return DropCompassInFrontOfPlayer(player, reason, preferLocalViewAnchor: true);
		}

		private bool GrantCompassToActor(int actorNumber, string reason)
		{
			if (actorNumber <= 0 || (Object)(object)_compassItem == (Object)null || !IsActorPastJoinGrace(actorNumber))
			{
				return false;
			}
			Player val = EnumerateTargetPlayers().FirstOrDefault((Func<Player, bool>)delegate(Player player)
			{
				PhotonView val3 = (((Object)(object)player != (Object)null) ? ((Component)player).GetComponent<PhotonView>() : null);
				if (val3 != null)
				{
					Player owner = val3.Owner;
					if (owner == null)
					{
						return false;
					}
					return owner.ActorNumber == actorNumber;
				}
				return false;
			});
			if ((Object)(object)val != (Object)null)
			{
				return GrantCompassToPlayer(val, reason);
			}
			Character val2 = ((IEnumerable<Character>)Character.AllCharacters).FirstOrDefault((Func<Character, bool>)((Character character) => (Object)(object)character != (Object)null && (Object)(object)((MonoBehaviourPun)character).photonView != (Object)null && ((MonoBehaviourPun)character).photonView.Owner != null && ((MonoBehaviourPun)character).photonView.Owner.ActorNumber == actorNumber && !character.isBot && !character.isZombie && (Object)(object)character.data != (Object)null && !character.data.dead));
			if ((Object)(object)val2 == (Object)null)
			{
				return false;
			}
			return DropCompassInFrontOfCharacter(val2, actorNumber, reason);
		}

		private bool DropCompassInFrontOfPlayer(Player player, string reason)
		{
			return DropCompassInFrontOfPlayer(player, reason, preferLocalViewAnchor: false);
		}

		private bool DropCompassInFrontOfPlayer(Player player, string reason, bool preferLocalViewAnchor)
		{
			//IL_004c: 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_0036: 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)
			if ((Object)(object)player == (Object)null || (Object)(object)_compassItem == (Object)null)
			{
				return false;
			}
			ResolveCompassSpawnPose(player, preferLocalViewAnchor, out var spawnPosition, out var spawnRotation);
			try
			{
				if (PhotonNetwork.InRoom)
				{
					PhotonNetwork.InstantiateItemRoom(((Object)_compassItem).name, spawnPosition, spawnRotation, true);
				}
				else
				{
					Object.Instantiate<GameObject>(((Component)_compassItem).gameObject, spawnPosition, spawnRotation);
				}
				((BaseUnityPlugin)this).Logger.LogDebug((object)("[Fog&ColdControl] Spawned compass in front of " + ((Object)player).name + " (" + reason + ")."));
				return true;
			}
			catch (Exception ex)
			{
				((BaseUnityPlugin)this).Logger.LogWarning((object)("[Fog&ColdControl] Failed to spawn compass in front of " + ((Object)player).name + " (" + reason + "): " + ex.Message));
				return false;
			}
		}

		private bool DropCompassInFrontOfCharacter(Character character, int actorNumber, string reason)
		{
			//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_0035: Unknown result type (might be due to invalid IL or missing references)
			//IL_0036: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)character == (Object)null || (Object)(object)_compassItem == (Object)null)
			{
				return false;
			}
			ResolveCompassSpawnPose(character, out var spawnPosition, out var spawnRotation);
			try
			{
				if (PhotonNetwork.InRoom)
				{
					PhotonNetwork.InstantiateItemRoom(((Object)_compassItem).name, spawnPosition, spawnRotation, true);
				}
				else
				{
					Object.Instantiate<GameObject>(((Component)_compassItem).gameObject, spawnPosition, spawnRotation);
				}
				((BaseUnityPlugin)this).Logger.LogDebug((object)string.Format("[{0}] Spawned compass near actor #{1} ({2}).", "Fog&ColdControl", actorNumber, reason));
				return true;
			}
			catch (Exception ex)
			{
				((BaseUnityPlugin)this).Logger.LogWarning((object)string.Format("[{0}] Failed to spawn compass near actor #{1} ({2}): {3}", "Fog&ColdControl", actorNumber, reason, ex.Message));
				return false;
			}
		}

		private static void ResolveCompassSpawnPose(Player player, out Vector3 spawnPosition, out Quaternion spawnRotation)
		{
			ResolveCompassSpawnPose(player, preferLocalViewAnchor: false, out spawnPosition, out spawnRotation);
		}

		private static void ResolveCompassSpawnPose(Player player, bool preferLocalViewAnchor, out Vector3 spawnPosition, out Quaternion spawnRotation)
		{
			//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_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_001d: 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_003a: 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_0040: Unknown result type (might be due to invalid IL or missing references)
			//IL_0045: 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_005a: Unknown result type (might be due to invalid IL or missing references)
			//IL_005f: 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_0080: 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_0087: Unknown result type (might be due to invalid IL or missing references)
			//IL_0088: 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_0098: Unknown result type (might be due to invalid IL or missing references)
			//IL_009e: Unknown result type (might be due to invalid IL or missing references)
			//IL_009f: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a4: 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)
			//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)
			if (!preferLocalViewAnchor || !TryResolveLocalViewCompassSpawnPose(player, out spawnPosition, out spawnRotation))
			{
				Vector3 val = ResolveCompassFaceAnchorPosition(player);
				Vector3 val2 = ResolveCompassFacingForward(player);
				if (((Vector3)(ref val2)).sqrMagnitude < 0.01f)
				{
					val2 = Vector3.forward;
				}
				val2 = ((Vector3)(ref val2)).normalized;
				Vector3 val3 = Vector3.ProjectOnPlane(val2, Vector3.up);
				if (((Vector3)(ref val3)).sqrMagnitude < 0.01f)
				{
					val3 = Vector3.ProjectOnPlane(((Component)player).transform.forward, Vector3.up);
				}
				if (((Vector3)(ref val3)).sqrMagnitude < 0.01f)
				{
					val3 = Vector3.forward;
				}
				val3 = ((Vector3)(ref val3)).normalized;
				spawnPosition = val + val2 * 0.85f;
				spawnRotation = Quaternion.LookRotation(val3, Vector3.up);
			}
		}

		private static void ResolveCompassSpawnPose(Character character, out Vector3 spawnPosition, out Quaternion spawnRotation)
		{
			//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_0010: Unknown result type (might be due to invalid IL or missing references)
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			//IL_001a: 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_0026: 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_0044: 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_0035: Unknown result type (might be due to invalid IL or missing references)
			//IL_003a: 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_006a: 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_006d: 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)
			//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_0083: Unknown result type (might be due to invalid IL or missing references)
			//IL_0084: 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_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)
			Vector3 val = character.Center + Vector3.up * 0.5f;
			Vector3 val2 = ((Component)character).transform.forward;
			if (((Vector3)(ref val2)).sqrMagnitude < 0.01f)
			{
				val2 = Vector3.forward;
			}
			val2 = ((Vector3)(ref val2)).normalized;
			Vector3 val3 = Vector3.ProjectOnPlane(val2, Vector3.up);
			if (((Vector3)(ref val3)).sqrMagnitude < 0.01f)
			{
				val3 = Vector3.forward;
			}
			val3 = ((Vector3)(ref val3)).normalized;
			spawnPosition = val + val2 * 0.85f;
			spawnRotation = Quaternion.LookRotation(val3, Vector3.up);
		}

		private static bool TryResolveLocalViewCompassSpawnPose(Player player, out Vector3 spawnPosition, out Quaternion spawnRotation)
		{
			//IL_0001: 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_000d: Unknown result type (might be due to invalid IL or missing references)
			//IL_009f: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a4: 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_00bc: 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_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_00c8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00de: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ed: Unknown result type (might be due to invalid IL or missing references)
			//IL_0106: Unknown result type (might be due to invalid IL or missing references)
			//IL_010b: 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_0114: Unknown result type (might be due to invalid IL or missing references)
			//IL_011a: Unknown result type (might be due to invalid IL or missing references)
			//IL_011f: 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_012a: 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_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)
			spawnPosition = default(Vector3);
			spawnRotation = Quaternion.identity;
			object obj = Player.localPlayer;
			if (obj == null)
			{
				Character localCharacter = Character.localCharacter;
				obj = ((localCharacter != null) ? localCharacter.player : null);
			}
			Player val = (Player)obj;
			if ((Object)(object)player == (Object)null || (Object)(object)val == (Object)null || (Object)(object)player != (Object)(object)val)
			{
				return false;
			}
			Camera val2 = Camera.main;
			if ((Object)(object)val2 == (Object)null || !((Behaviour)val2).isActiveAndEnabled)
			{
				val2 = ((IEnumerable<Camera>)Object.FindObjectsByType<Camera>((FindObjectsSortMode)0)).FirstOrDefault((Func<Camera, bool>)((Camera candidate) => (Object)(object)candidate != (Object)null && ((Behaviour)candidate).isActiveAndEnabled && ((Component)candidate).gameObject.activeInHierarchy));
			}
			if ((Object)(object)val2 == (Object)null)
			{
				return false;
			}
			Transform transform = ((Component)val2).transform;
			Vector3 val3 = transform.forward;
			if (((Vector3)(ref val3)).sqrMagnitude < 0.01f)
			{
				return false;
			}
			val3 = ((Vector3)(ref val3)).normalized;
			Vector3 val4 = Vector3.ProjectOnPlane(val3, Vector3.up);
			if (((Vector3)(ref val4)).sqrMagnitude < 0.01f)
			{
				val4 = Vector3.ProjectOnPlane(((Component)player).transform.forward, Vector3.up);
			}
			if (((Vector3)(ref val4)).sqrMagnitude < 0.01f)
			{
				val4 = Vector3.forward;
			}
			val4 = ((Vector3)(ref val4)).normalized;
			spawnPosition = transform.position + val3 * 0.9f;
			spawnRotation = Quaternion.LookRotation(val4, Vector3.up);
			return true;
		}

		private static Vector3 ResolveCompassFaceAnchorPosition(Player player)
		{
			//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_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_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_0059: Unknown result type (might be due to invalid IL or missing references)
			//IL_005f: 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_0071: 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_002f: 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_0034: Unknown result type (might be due to invalid IL or missing references)
			//IL_0036: 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_003c: Unknown result type (might be due to invalid IL or missing references)
			if (TryGetCompassFaceAnchor(player, out var anchor))
			{
				Vector3 val = ((((Object)anchor).name.IndexOf("camera", StringComparison.OrdinalIgnoreCase) >= 0) ? (Vector3.down * 0.03f) : Vector3.zero);
				return anchor.position + val;
			}
			Character character = player.character;
			if ((Object)(object)character != (Object)null)
			{
				Vector3 center = character.Center;
				return new Vector3(center.x, center.y + 0.5f, center.z);
			}
			return ((Component)player).transform.position + Vector3.up * 1.45f;
		}

		private static Vector3 ResolveCompassFacingForward(Player player)
		{
			//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)
			//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_0013: Unknown result type (might be due to invalid IL or missing references)
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_007f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0059: 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_00ab: 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_00a5: Unknown result type (might be due to invalid IL or missing references)
			if (TryGetCompassFaceAnchor(player, out var anchor) && ShouldUseCompassAnchorForward(anchor))
			{
				Vector3 forward = anchor.forward;
				if (((Vector3)(ref forward)).sqrMagnitude >= 0.01f)
				{
					return forward;
				}
			}
			Character character = player.character;
			Vector3 forward2;
			if ((Object)(object)character != (Object)null)
			{
				forward2 = ((Component)character).transform.forward;
				if (((Vector3)(ref forward2)).sqrMagnitude >= 0.01f)
				{
					return ((Component)character).transform.forward;
				}
			}
			forward2 = ((Component)player).transform.forward;
			if (((Vector3)(ref forward2)).sqrMagnitude >= 0.01f)
			{
				return ((Component)player).transform.forward;
			}
			if (TryGetCompassFaceAnchor(player, out anchor))
			{
				forward2 = anchor.forward;
				if (((Vector3)(ref forward2)).sqrMagnitude >= 0.01f)
				{
					return anchor.forward;
				}
			}
			return Vector3.forward;
		}

		private static bool TryGetCompassFaceAnchor(Player player, out Transform anchor)
		{
			//IL_00ac: Unknown result type (might be due to invalid IL or missing references)
			anchor = null;
			if ((Object)(object)player == (Object)null)
			{
				return false;
			}
			Transform[] obj = (((Object)(object)player.character != (Object)null && (Object)(object)((Component)player.character).transform != (Object)(object)((Component)player).transform) ? new Transform[2]
			{
				((Component)player.character).transform,
				((Component)player).transform
			} : new Transform[1] { ((Component)player).transform });
			int num = int.MaxValue;
			float num2 = float.MinValue;
			Transform[] array = (Transform[])(object)obj;
			foreach (Transform val in array)
			{
				if ((Object)(object)val == (Object)null)
				{
					continue;
				}
				Transform[] componentsInChildren = ((Component)val).GetComponentsInChildren<Transform>(true);
				foreach (Transform val2 in componentsInChildren)
				{
					int compassFaceAnchorScore = GetCompassFaceAnchorScore(val2);
					if (compassFaceAnchorScore != int.MaxValue)
					{
						float y = val2.position.y;
						if (compassFaceAnchorScore < num || (compassFaceAnchorScore == num && y > num2))
						{
							num = compassFaceAnchorScore;
							num2 = y;
							anchor = val2;
						}
					}
				}
			}
			return (Object)(object)anchor != (Object)null;
		}

		private static int GetCompassFaceAnchorScore(Transform candidate)
		{
			if ((Object)(object)candidate == (Object)null)
			{
				return int.MaxValue;
			}
			string text = ((Object)candidate).name ?? string.Empty;
			if (text.Equals("MainCamera", StringComparison.OrdinalIgnoreCase))
			{
				return 0;
			}
			if (text.IndexOf("maincamera", StringComparison.OrdinalIgnoreCase) >= 0)
			{
				return 1;
			}
			if (text.IndexOf("camera", StringComparison.OrdinalIgnoreCase) >= 0)
			{
				return 2;
			}
			if (text.IndexOf("head", StringComparison.OrdinalIgnoreCase) >= 0)
			{
				return 3;
			}
			if (text.IndexOf("face", StringComparison.OrdinalIgnoreCase) >= 0)
			{
				return 4;
			}
			if (text.IndexOf("look", StringComparison.OrdinalIgnoreCase) >= 0)
			{
				return 5;
			}
			if (text.IndexOf("jaw", StringComparison.OrdinalIgnoreCase) >= 0)
			{
				return 6;
			}
			return int.MaxValue;
		}

		private static bool ShouldUseCompassAnchorForward(Transform anchor)
		{
			if ((Object)(object)anchor == (Object)null)
			{
				return false;
			}
			string text = ((Object)anchor).name ?? string.Empty;
			if (text.IndexOf("camera", StringComparison.OrdinalIgnoreCase) < 0)
			{
				return text.IndexOf("look", StringComparison.OrdinalIgnoreCase) >= 0;
			}
			return true;
		}

		private void HandleManualCompassHotkey()
		{
			//IL_0016: 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_001c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0036: Unknown result type (might be due to invalid IL or missing references)
			if (!IsModFeatureEnabled() || !HasFogAuthority() || !IsCompassFeatureEnabled())
			{
				return;
			}
			KeyCode compassHotkey = GetCompassHotkey();
			if ((int)compassHotkey != 0)
			{
				GUIManager instance = GUIManager.instance;
				if ((!((Object)(object)instance != (Object)null) || !instance.windowBlockingInput) && Input.GetKeyDown(compassHotkey))
				{
					TrySpawnManualCompassForLocalPlayer();
				}
			}
		}

		private void TrySpawnManualCompassForLocalPlayer()
		{
			if (IsCompassFeatureEnabled())
			{
				Player localPlayer;
				if (!TryResolveCompassItem())
				{
					((BaseUnityPlugin)this).Logger.LogWarning((object)"[Fog&ColdControl] Failed to resolve compass item for manual hotkey spawn.");
				}
				else if (TryGetLocalPlayablePlayer(out localPlayer) && !DropCompassInFrontOfPlayer(localPlayer, "manual-hotkey", preferLocalViewAnchor: true))
				{
					((BaseUnityPlugin)this).Logger.LogWarning((object)("[Fog&ColdControl] Manual compass hotkey spawn failed for " + ((Object)localPlayer).name + "."));
				}
			}
		}

		private static KeyCode GetCompassHotkey()
		{
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			return (KeyCode)(((??)CompassHotkey?.Value) ?? 103);
		}

		private unsafe static string GetCompassHotkeyLabel()
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0005: 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)
			KeyCode compassHotkey = GetCompassHotkey();
			string text = ((object)(*(KeyCode*)(&compassHotkey))/*cast due to .constrained prefix*/).ToString();
			if (string.IsNullOrWhiteSpace(text) || (int)compassHotkey == 0)
			{
				return "G";
			}
			return text.ToUpperInvariant();
		}

		private bool ShouldShowCompassLobbyNotice()
		{
			//IL_0015: 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)
			if (IsModFeatureEnabled() && HasFogAuthority() && IsCompassFeatureEnabled() && (int)GetCompassHotkey() != 0)
			{
				return IsAirportScene(SceneManager.GetActiveScene());
			}
			return false;
		}

		private string GetCompassLobbyNoticeTextSafe(bool isChineseLanguage)
		{
			string text = "<color=#FF3B30>" + GetCompassHotkeyLabel() + "</color>";
			if (!isChineseLanguage)
			{
				return "Press " + text + " to spawn compass";
			}
			return "按 " + text + " 生成指南针";
		}

		private void UpdateCompassLobbyNotice()
		{
			if (!ShouldShowCompassLobbyNotice())
			{
				CleanupCompassLobbyNotice();
				return;
			}
			Canvas val = ResolveHudCanvas();
			if (!IsCanvasUsable(val))
			{
				CleanupCompassLobbyNotice();
				return;
			}
			if ((Object)(object)_compassLobbyNoticeRect == (Object)null || (Object)(object)_compassLobbyNoticeText == (Object)null || (Object)(object)((Transform)_compassLobbyNoticeRect).parent != (Object)(object)((Component)val).transform)
			{
				CreateCompassLobbyNotice(val);
				if ((Object)(object)_compassLobbyNoticeRect == (Object)null || (Object)(object)_compassLobbyNoticeText == (Object)null)
				{
					return;
				}
			}
			string compassLobbyNoticeTextSafe = GetCompassLobbyNoticeTextSafe(DetectChineseLanguage());
			if (!string.Equals(_lastCompassLobbyNoticeText, compassLobbyNoticeTextSafe, StringComparison.Ordinal))
			{
				_lastCompassLobbyNoticeText = compassLobbyNoticeTextSafe;
				((TMP_Text)_compassLobbyNoticeText).text = compassLobbyNoticeTextSafe;
			}
			ClampCompassLobbyNoticeToCanvas(val);
			((Component)_compassLobbyNoticeRect).gameObject.SetActive(true);
		}

		private void CreateCompassLobbyNotice(Canvas targetCanvas = null)
		{
			//IL_0035: Unknown result type (might be due to invalid IL or missing references)
			//IL_003b: Expected O, but got Unknown
			//IL_0074: Unknown result type (might be due to invalid IL or missing references)
			CleanupCompassLobbyNotice();
			Canvas val = targetCanvas ?? ResolveHudCanvas();
			if (IsCanvasUsable(val))
			{
				GameObject val2 = new GameObject("FogClimbCompassLobbyNotice", new Type[1] { typeof(RectTransform) });
				_compassLobbyNoticeRect = val2.GetComponent<RectTransform>();
				((Transform)_compassLobbyNoticeRect).SetParent(((Component)val).transform, false);
				((Transform)_compassLobbyNoticeRect).SetAsLastSibling();
				_compassLobbyNoticeRect.sizeDelta = new Vector2(735f, 81f);
				_compassLobbyNoticeText = val2.AddComponent<TextMeshProUGUI>();
				ApplyCompassLobbyNoticeStyle(_compassLobbyNoticeText);
				_lastCompassLobbyNoticeText = GetCompassLobbyNoticeTextSafe(DetectChineseLanguage());
				((TMP_Text)_compassLobbyNoticeText).text = _lastCompassLobbyNoticeText;
				ClampCompassLobbyNoticeToCanvas(val);
			}
		}

		private void ApplyCompassLobbyNoticeStyle(TextMeshProUGUI target)
		{
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)target == (Object)null))
			{
				ApplyGameTextStyle(target, new Color(1f, 0.94f, 0.72f), 1.2f);
				((TMP_Text)target).fontStyle = (FontStyles)0;
				((TMP_Text)target).alignment = (TextAlignmentOptions)4100;
				((TMP_Text)target).textWrappingMode = (TextWrappingModes)0;
				((TMP_Text)target).overflowMode = (TextOverflowModes)0;
				((TMP_Text)target).lineSpacing = 1.125f;
			}
		}

		private void ClampCompassLobbyNoticeToCanvas(Canvas targetCanvas = null)
		{
			if ((Object)(object)_compassLobbyNoticeRect == (Object)null)
			{
				return;
			}
			Canvas val = targetCanvas ?? ResolveHudCanvas() ?? ((Component)_compassLobbyNoticeRect).GetComponentInParent<Canvas>();
			if (IsCanvasUsable(val))
			{
				if ((Object)(object)((Transform)_compassLobbyNoticeRect).parent != (Object)(object)((Component)val).transform)
				{
					((Transform)_compassLobbyNoticeRect).SetParent(((Component)val).transform, false);
				}
				ApplyRightMiddleAnchoredRect(_compassLobbyNoticeRect, 735f, 81f, 28f, 0f);
			}
		}

		private void CleanupCompassLobbyNotice()
		{
			if ((Object)(object)_compassLobbyNoticeRect != (Object)null)
			{
				Object.Destroy((Object)(object)((Component)_compassLobbyNoticeRect).gameObject);
			}
			_compassLobbyNoticeRect = null;
			_compassLobbyNoticeText = null;
			_lastCompassLobbyNoticeText = string.Empty;
		}

		internal static bool IsCompassFeatureEnabled()
		{
			if (CompassEnabled != null)
			{
				return CompassEnabled.Value;
			}
			return true;
		}

		private void InitializeConfig(bool isChineseLanguage)
		{
			FogColdSuppression = ((BaseUnityPlugin)this).Config.Bind<bool>(GetConfigSectionName(ConfigKey.FogColdSuppression), GetConfigKeyName(ConfigKey.FogColdSuppression), false, CreateConfigDescription(ConfigKey.FogColdSuppression, isChineseLanguage));
			NightColdEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>(GetConfigSectionName(ConfigKey.NightColdEnabled), GetConfigKeyName(ConfigKey.NightColdEnabled), true, CreateConfigDescription(ConfigKey.NightColdEnabled, isChineseLanguage));
			FogSpeed = ((BaseUnityPlugin)this).Config.Bind<float>(GetConfigSectionName(ConfigKey.FogSpeed), GetConfigKeyName(ConfigKey.FogSpeed), 0.4f, CreateConfigDescription(ConfigKey.FogSpeed, isChineseLanguage));
			FogDelay = ((BaseUnityPlugin)this).Config.Bind<float>(GetConfigSectionName(ConfigKey.FogDelay), GetConfigKeyName(ConfigKey.FogDelay), 900f, CreateConfigDescription(ConfigKey.FogDelay, isChineseLanguage));
			FogPauseHotkey = ((BaseUnityPlugin)this).Config.Bind<KeyCode>(GetConfigSectionName(ConfigKey.FogPauseHotkey), GetConfigKeyName(ConfigKey.FogPauseHotkey), (KeyCode)121, CreateConfigDescription(ConfigKey.FogPauseHotkey, isChineseLanguage));
			ModEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>(GetConfigSectionName(ConfigKey.ModEnabled), GetConfigKeyName(ConfigKey.ModEnabled), true, CreateConfigDescription(ConfigKey.ModEnabled, isChineseLanguage));
			FogUiEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>(GetConfigSectionName(ConfigKey.FogUiEnabled), GetConfigKeyName(ConfigKey.FogUiEnabled), true, CreateConfigDescription(ConfigKey.FogUiEnabled, isChineseLanguage));
			CampfireLocatorUiEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>(GetConfigSectionName(ConfigKey.CampfireLocatorUiEnabled), GetConfigKeyName(ConfigKey.CampfireLocatorUiEnabled), true, CreateConfigDescription(ConfigKey.CampfireLocatorUiEnabled, isChineseLanguage));
			CompassEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>(GetConfigSectionName(ConfigKey.CompassEnabled), GetConfigKeyName(ConfigKey.CompassEnabled), false, CreateConfigDescription(ConfigKey.CompassEnabled, isChineseLanguage));
			CompassHotkey = ((BaseUnityPlugin)this).Config.Bind<KeyCode>(GetConfigSectionName(ConfigKey.CompassHotkey), GetConfigKeyName(ConfigKey.CompassHotkey), (KeyCode)103, CreateConfigDescription(ConfigKey.CompassHotkey, isChineseLanguage));
			FogUiX = ((BaseUnityPlugin)this).Config.Bind<float>(GetConfigSectionName(ConfigKey.FogUiX), GetConfigKeyName(ConfigKey.FogUiX), 60f, CreateConfigDescription(ConfigKey.FogUiX, isChineseLanguage));
			FogUiY = ((BaseUnityPlugin)this).Config.Bind<float>(GetConfigSectionName(ConfigKey.FogUiY), GetConfigKeyName(ConfigKey.FogUiY), 0f, CreateConfigDescription(ConfigKey.FogUiY, isChineseLanguage));
			FogUiScale = ((BaseUnityPlugin)this).Config.Bind<float>(GetConfigSectionName(ConfigKey.FogUiScale), GetConfigKeyName(ConfigKey.FogUiScale), 0.9f, CreateConfigDescription(ConfigKey.FogUiScale, isChineseLanguage));
			FogUiEntrySpacing = ((BaseUnityPlugin)this).Config.Bind<float>(GetConfigSectionName(ConfigKey.FogUiEntrySpacing), GetConfigKeyName(ConfigKey.FogUiEntrySpacing), 8f, CreateConfigDescription(ConfigKey.FogUiEntrySpacing, isChineseLanguage));
			FogUiLayout = ((BaseUnityPlugin)this).Config.Bind<FogUiLayoutKind>(GetConfigSectionName(ConfigKey.FogUiLayout), GetConfigKeyName(ConfigKey.FogUiLayout), FogUiLayoutKind.Horizontal, CreateConfigDescription(ConfigKey.FogUiLayout, isChineseLanguage));
			FogUiBackgroundOpacity = ((BaseUnityPlugin)this).Config.Bind<float>(GetConfigSectionName(ConfigKey.FogUiBackgroundOpacity), GetConfigKeyName(ConfigKey.FogUiBackgroundOpacity), 0f, CreateConfigDescription(ConfigKey.FogUiBackgroundOpacity, isChineseLanguage));
			FogStateUiEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>(GetConfigSectionName(ConfigKey.FogStateUiEnabled), GetConfigKeyName(ConfigKey.FogStateUiEnabled), true, CreateConfigDescription(ConfigKey.FogStateUiEnabled, isChineseLanguage));
			RunTimerUiEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>(GetConfigSectionName(ConfigKey.RunTimerUiEnabled), GetConfigKeyName(ConfigKey.RunTimerUiEnabled), true, CreateConfigDescription(ConfigKey.RunTimerUiEnabled, isChineseLanguage));
			DayNightTimeUiEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>(GetConfigSectionName(ConfigKey.DayNightTimeUiEnabled), GetConfigKeyName(ConfigKey.DayNightTimeUiEnabled), true, CreateConfigDescription(ConfigKey.DayNightTimeUiEnabled, isChineseLanguage));
			AltitudeUiEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>(GetConfigSectionName(ConfigKey.AltitudeUiEnabled), GetConfigKeyName(ConfigKey.AltitudeUiEnabled), true, CreateConfigDescription(ConfigKey.AltitudeUiEnabled, isChineseLanguage));
			FogSpeedUiEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>(GetConfigSectionName(ConfigKey.FogSpeedUiEnabled), GetConfigKeyName(ConfigKey.FogSpeedUiEnabled), true, CreateConfigDescription(ConfigKey.FogSpeedUiEnabled, isChineseLanguage));
			CampfireDistanceUiEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>(GetConfigSectionName(ConfigKey.CampfireDistanceUiEnabled), GetConfigKeyName(ConfigKey.CampfireDistanceUiEnabled), true, Create