Decompiled source of Dive In v1.0.1

DiveIn.dll

Decompiled an hour ago
using System;
using System.Collections;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Globalization;
using System.IO;
using System.IO.Compression;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
using System.Reflection.Emit;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Serialization;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading;
using BepInEx;
using BepInEx.Bootstrap;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using JetBrains.Annotations;
using Microsoft.CodeAnalysis;
using ServerSync;
using TMPro;
using UnityEngine;
using UnityEngine.Rendering;
using YamlDotNet.Core;
using YamlDotNet.Core.Events;
using YamlDotNet.Core.ObjectPool;
using YamlDotNet.Core.Tokens;
using YamlDotNet.Helpers;
using YamlDotNet.Serialization;
using YamlDotNet.Serialization.BufferedDeserialization;
using YamlDotNet.Serialization.BufferedDeserialization.TypeDiscriminators;
using YamlDotNet.Serialization.Callbacks;
using YamlDotNet.Serialization.Converters;
using YamlDotNet.Serialization.EventEmitters;
using YamlDotNet.Serialization.NamingConventions;
using YamlDotNet.Serialization.NodeDeserializers;
using YamlDotNet.Serialization.NodeTypeResolvers;
using YamlDotNet.Serialization.ObjectFactories;
using YamlDotNet.Serialization.ObjectGraphTraversalStrategies;
using YamlDotNet.Serialization.ObjectGraphVisitors;
using YamlDotNet.Serialization.Schemas;
using YamlDotNet.Serialization.TypeInspectors;
using YamlDotNet.Serialization.TypeResolvers;
using YamlDotNet.Serialization.Utilities;
using YamlDotNet.Serialization.ValueDeserializers;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: AssemblyTitle("DiveIn")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("sighsorry")]
[assembly: AssemblyProduct("DiveIn")]
[assembly: AssemblyCopyright("Copyright ©  2021")]
[assembly: AssemblyTrademark("")]
[assembly: ComVisible(false)]
[assembly: Guid("4358610B-F3F4-4843-B7AF-98B7BC60DCDE")]
[assembly: AssemblyFileVersion("1.0.1")]
[assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.0.1.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableAttribute : Attribute
	{
		public readonly byte[] NullableFlags;

		public NullableAttribute(byte P_0)
		{
			NullableFlags = new byte[1] { P_0 };
		}

		public NullableAttribute(byte[] P_0)
		{
			NullableFlags = P_0;
		}
	}
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableContextAttribute : Attribute
	{
		public readonly byte Flag;

		public NullableContextAttribute(byte P_0)
		{
			Flag = P_0;
		}
	}
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.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;
		}
	}
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Enum | AttributeTargets.Method | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)]
	internal sealed class ExtensionMarkerAttribute : Attribute
	{
		private readonly string <Name>k__BackingField;

		public string Name => <Name>k__BackingField;

		public ExtensionMarkerAttribute(string name)
		{
			<Name>k__BackingField = name;
		}
	}
}
namespace ServerSyncModTemplate
{
	[BepInPlugin("sighsorry.DiveIn", "DiveIn", "1.0.1")]
	public class ServerSyncModTemplatePlugin : BaseUnityPlugin
	{
		private sealed class MonsterDiveYamlRoot
		{
			public MonsterDiveYamlGlobal Global { get; set; } = new MonsterDiveYamlGlobal();


			public Dictionary<string, MonsterDiveYamlGroup> Groups { get; set; } = new Dictionary<string, MonsterDiveYamlGroup>(StringComparer.OrdinalIgnoreCase);

		}

		private sealed class MonsterDiveYamlGlobal
		{
			public float SwimDepthMin { get; set; } = DefaultMonsterDiveGlobalSettings.SwimDepthMin;


			public float SwimDepthMax { get; set; } = DefaultMonsterDiveGlobalSettings.SwimDepthMax;


			public float SwimDepthAdjustSpeed { get; set; } = DefaultMonsterDiveGlobalSettings.SwimDepthAdjustSpeed;

		}

		private sealed class MonsterDiveYamlGroup
		{
			public float PassiveMinDepth { get; set; }

			public float PassiveCenterDepth { get; set; }

			public float PassiveMaxDepth { get; set; }

			public List<string> Prefabs { get; set; } = new List<string>();

		}

		private readonly struct MonsterDiveGlobalSettings
		{
			public float SwimDepthMin { get; }

			public float SwimDepthMax { get; }

			public float SwimDepthAdjustSpeed { get; }

			public MonsterDiveGlobalSettings(float swimDepthMin, float swimDepthMax, float swimDepthAdjustSpeed)
			{
				SwimDepthMin = swimDepthMin;
				SwimDepthMax = swimDepthMax;
				SwimDepthAdjustSpeed = swimDepthAdjustSpeed;
			}
		}

		private readonly struct RouteCacheEntry
		{
			public readonly float Time;

			public readonly Vector3Int PositionBucket;

			public readonly Vector3Int TargetBucket;

			public readonly bool Result;

			public RouteCacheEntry(float time, Vector3Int positionBucket, Vector3Int targetBucket, bool result)
			{
				//IL_0009: Unknown result type (might be due to invalid IL or missing references)
				//IL_000a: Unknown result type (might be due to invalid IL or missing references)
				//IL_0010: Unknown result type (might be due to invalid IL or missing references)
				//IL_0011: Unknown result type (might be due to invalid IL or missing references)
				Time = time;
				PositionBucket = positionBucket;
				TargetBucket = targetBucket;
				Result = result;
			}
		}

		private readonly struct SteerCacheEntry
		{
			public readonly float Time;

			public readonly Vector3Int PositionBucket;

			public readonly Vector3Int TargetBucket;

			public readonly Vector3 Direction;

			public SteerCacheEntry(float time, Vector3Int positionBucket, Vector3Int targetBucket, Vector3 direction)
			{
				//IL_0009: Unknown result type (might be due to invalid IL or missing references)
				//IL_000a: Unknown result type (might be due to invalid IL or missing references)
				//IL_0010: Unknown result type (might be due to invalid IL or missing references)
				//IL_0011: Unknown result type (might be due to invalid IL or missing references)
				//IL_0017: Unknown result type (might be due to invalid IL or missing references)
				//IL_0019: Unknown result type (might be due to invalid IL or missing references)
				Time = time;
				PositionBucket = positionBucket;
				TargetBucket = targetBucket;
				Direction = direction;
			}
		}

		private readonly struct PassiveDepthProfile
		{
			public readonly float CenterDepth;

			public readonly float MinDepth;

			public readonly float MaxDepth;

			public PassiveDepthProfile(float centerDepth, float minDepth, float maxDepth)
			{
				CenterDepth = centerDepth;
				MinDepth = minDepth;
				MaxDepth = maxDepth;
			}
		}

		private readonly struct ConfiguredDiveProfile
		{
			public readonly string GroupName;

			public readonly PassiveDepthProfile PassiveDepthProfile;

			public ConfiguredDiveProfile(string groupName, PassiveDepthProfile passiveDepthProfile)
			{
				GroupName = groupName;
				PassiveDepthProfile = passiveDepthProfile;
			}
		}

		private readonly struct OriginalDiveFlags
		{
			public readonly MonsterAI MonsterAI;

			public readonly bool AvoidWater;

			public readonly bool CanSwim;

			public OriginalDiveFlags(MonsterAI monsterAI, bool avoidWater, bool canSwim)
			{
				MonsterAI = monsterAI;
				AvoidWater = avoidWater;
				CanSwim = canSwim;
			}
		}

		public enum Toggle
		{
			On = 1,
			Off = 0
		}

		private readonly struct SwimDepthGoal
		{
			public readonly float ClampedTargetY;

			public readonly bool RequestedOutsideRange;

			public SwimDepthGoal(float clampedTargetY, bool requestedOutsideRange)
			{
				ClampedTargetY = clampedTargetY;
				RequestedOutsideRange = requestedOutsideRange;
			}
		}

		[HarmonyPatch(typeof(MonsterAI), "Awake")]
		private static class MonsterAIAwakePatch
		{
			private static void Postfix(MonsterAI __instance)
			{
				if (IsConfiguredMonster(__instance))
				{
					EnsureDiveFlags(__instance);
					TryLogOverlapFields(__instance, "MonsterAI.Awake");
				}
			}
		}

		[HarmonyPatch(typeof(MonsterAI), "UpdateAI")]
		private static class MonsterAIUpdateAIPatch
		{
			private static void Prefix(MonsterAI __instance)
			{
				if (IsConfiguredMonster(__instance))
				{
					EnsureDiveFlags(__instance);
					TryLogOverlapFields(__instance, "MonsterAI.UpdateAI");
				}
			}
		}

		[HarmonyPatch(typeof(BaseAI), "HavePath")]
		private static class BaseAIHavePathPatch
		{
			private static bool Prefix(BaseAI __instance, Vector3 target, ref bool __result)
			{
				//IL_003c: Unknown result type (might be due to invalid IL or missing references)
				if (!TryGetConfiguredMonster(__instance, out MonsterAI monsterAI) || !ShouldUseWaterDiveMode(monsterAI))
				{
					return true;
				}
				Character character = ((BaseAI)monsterAI).m_character;
				if ((Object)(object)character == (Object)null)
				{
					return true;
				}
				__result = HasReasonableUnderwaterRoute(__instance, character, target);
				TryLogOverlapFields(monsterAI, "BaseAI.HavePath");
				return false;
			}
		}

		[HarmonyPatch(typeof(BaseAI), "MoveTo")]
		private static class BaseAIMoveToPatch
		{
			private static bool Prefix(BaseAI __instance, float dt, Vector3 point, float dist, bool run, ref bool __result)
			{
				//IL_0045: Unknown result type (might be due to invalid IL or missing references)
				//IL_0070: Unknown result type (might be due to invalid IL or missing references)
				//IL_0077: 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_008f: Unknown result type (might be due to invalid IL or missing references)
				//IL_00ad: Unknown result type (might be due to invalid IL or missing references)
				//IL_0103: Unknown result type (might be due to invalid IL or missing references)
				//IL_010a: Unknown result type (might be due to invalid IL or missing references)
				//IL_010f: Unknown result type (might be due to invalid IL or missing references)
				//IL_0114: Unknown result type (might be due to invalid IL or missing references)
				//IL_0140: Unknown result type (might be due to invalid IL or missing references)
				//IL_0141: Unknown result type (might be due to invalid IL or missing references)
				//IL_0146: Unknown result type (might be due to invalid IL or missing references)
				//IL_0171: Unknown result type (might be due to invalid IL or missing references)
				if (!TryGetConfiguredMonster(__instance, out MonsterAI monsterAI) || !ShouldUseWaterDiveMode(monsterAI))
				{
					return true;
				}
				Character character = ((BaseAI)monsterAI).m_character;
				if ((Object)(object)character == (Object)null)
				{
					return true;
				}
				SwimDepthGoal swimDepthGoal = UpdateSwimDepthTowardsTarget(monsterAI, character, point, dt);
				TryLogOverlapFields(monsterAI, "BaseAI.MoveTo");
				float num = Mathf.Max(dist, run ? 1f : 0.5f);
				float num2 = Utils.DistanceXZ(point, ((Component)__instance).transform.position);
				float num3 = Mathf.Abs(point.y - ((Component)__instance).transform.position.y);
				float num4 = Mathf.Abs(swimDepthGoal.ClampedTargetY - ((Component)__instance).transform.position.y);
				bool flag = num3 < 0.75f || (swimDepthGoal.RequestedOutsideRange && num4 < 0.35f);
				if (num2 < num && flag)
				{
					__instance.StopMoving();
					__result = true;
					return false;
				}
				Vector3 val = point - ((Component)__instance).transform.position;
				if (((Vector3)(ref val)).sqrMagnitude <= 0.0001f)
				{
					__instance.StopMoving();
					__result = true;
					return false;
				}
				Vector3 val2 = BuildSteerDirectionWithAvoidance(__instance, character, point);
				if (((Vector3)(ref val2)).sqrMagnitude <= 0.0001f)
				{
					__instance.StopMoving();
					__result = true;
					return false;
				}
				__instance.MoveTowards(val2, run);
				__result = false;
				return false;
			}
		}

		private class ConfigurationManagerAttributes
		{
			[UsedImplicitly]
			public int? Order = null;

			[UsedImplicitly]
			public bool? Browsable = null;

			[UsedImplicitly]
			public string? Category = null;

			[UsedImplicitly]
			public Action<ConfigEntryBase>? CustomDrawer = null;
		}

		private class AcceptableShortcuts : AcceptableValueBase
		{
			public AcceptableShortcuts()
				: base(typeof(KeyboardShortcut))
			{
			}

			public override object Clamp(object value)
			{
				return value;
			}

			public override bool IsValid(object value)
			{
				return true;
			}

			public override string ToDescriptionString()
			{
				return "# Acceptable values: " + string.Join(", ", UnityInput.Current.SupportedKeyCodes);
			}
		}

		private static readonly string MonsterDiveYamlFileName = "DiveIn.yaml";

		private static readonly string MonsterDiveYamlFileFullPath;

		private static readonly object MonsterDiveYamlLock;

		private static readonly IDeserializer MonsterDiveYamlDeserializer;

		private static readonly MonsterDiveGlobalSettings DefaultMonsterDiveGlobalSettings;

		private FileSystemWatcher _monsterDiveYamlWatcher = null;

		private DateTime _lastMonsterDiveYamlReloadTime;

		private static CustomSyncedValue<string> _monsterDiveYamlSync;

		private static MonsterDiveGlobalSettings _monsterDiveGlobalSettings;

		internal const float DefaultUnderwaterColorDarknessFactor = 0.02f;

		internal const float DefaultUnderwaterVisibilityFalloff = 0f;

		internal const float DefaultMinimumUnderwaterMurkiness = 0.05f;

		internal const float DefaultMaximumUnderwaterMurkiness = 1f;

		internal const float DefaultUnderwaterCameraMinWaterDistance = -5000f;

		internal static ConfigEntry<string> _waterEquipmentBlacklist;

		internal static ConfigEntry<float> _waterStaminaRegenRateMultiplier;

		internal static ConfigEntry<float> _waterDepthStaminaDrainStart;

		internal static ConfigEntry<float> _waterDepthStaminaDrainFull;

		internal static ConfigEntry<float> _waterDepthStaminaDrainMaxMultiplier;

		internal static ConfigEntry<float> _playerSwimRunSpeedMultiplier;

		private static readonly object WaterEquipmentBlacklistLock;

		private static string _lastWaterEquipmentBlacklistRaw;

		private static HashSet<string> _waterEquipmentBlacklistSet;

		internal const string ModName = "DiveIn";

		internal const string ModVersion = "1.0.1";

		internal const string Author = "sighsorry";

		private const string ModGUID = "sighsorry.DiveIn";

		private static readonly string ConfigFileName;

		private static readonly string ConfigFileFullPath;

		internal static string ConnectionError;

		private readonly Harmony _harmony = new Harmony("sighsorry.DiveIn");

		public static readonly ManualLogSource ServerSyncModTemplateLogger;

		private static readonly ConfigSync ConfigSync;

		private static ConfigEntry<float> _diveAiQuality;

		private static readonly object PrefabSetLock;

		private static Dictionary<string, ConfiguredDiveProfile> _configuredDiveProfilesByPrefabName;

		private FileSystemWatcher _watcher = null;

		private readonly object _reloadLock = new object();

		private DateTime _lastConfigReloadTime;

		private const long RELOAD_DELAY = 10000000L;

		private const float PassiveWavePeriodSeconds = 12f;

		private static readonly float[] SteerAngles;

		private static readonly float[] RouteAngles;

		private static readonly Dictionary<int, RouteCacheEntry> RouteCache;

		private static readonly Dictionary<int, SteerCacheEntry> SteerCache;

		private static readonly Dictionary<int, OriginalDiveFlags> OriginalDiveFlagsByInstance;

		private const int MaxCacheEntries = 2048;

		private static ConfigEntry<Toggle> _serverConfigLocked;

		private void InitializeMonsterDiveYaml()
		{
			_monsterDiveYamlSync = new CustomSyncedValue<string>(ConfigSync, "MonsterDiveYaml", string.Empty);
			_monsterDiveYamlSync.ValueChanged += OnMonsterDiveYamlValueChanged;
			ConfigSync.SourceOfTruthChanged += OnMonsterDiveSourceOfTruthChanged;
			if (ConfigSync.IsSourceOfTruth)
			{
				LoadMonsterDiveYamlFromDisk(forceWriteDefaultIfMissing: true, syncToPeers: true, "startup");
			}
			else if (!string.IsNullOrWhiteSpace(_monsterDiveYamlSync.Value))
			{
				ApplyMonsterDiveYaml(_monsterDiveYamlSync.Value, "startup synced value");
			}
		}

		private void SetupMonsterDiveYamlWatcher()
		{
			_monsterDiveYamlWatcher = new FileSystemWatcher(Paths.ConfigPath, MonsterDiveYamlFileName);
			_monsterDiveYamlWatcher.Changed += ReadMonsterDiveYamlValues;
			_monsterDiveYamlWatcher.Created += ReadMonsterDiveYamlValues;
			_monsterDiveYamlWatcher.Renamed += ReadMonsterDiveYamlValues;
			_monsterDiveYamlWatcher.IncludeSubdirectories = true;
			_monsterDiveYamlWatcher.SynchronizingObject = ThreadingHelper.SynchronizingObject;
			_monsterDiveYamlWatcher.EnableRaisingEvents = true;
		}

		private void DisposeMonsterDiveYamlWatcher()
		{
			_monsterDiveYamlWatcher?.Dispose();
		}

		private void ReadMonsterDiveYamlValues(object sender, FileSystemEventArgs e)
		{
			DateTime now = DateTime.Now;
			if (now.Ticks - _lastMonsterDiveYamlReloadTime.Ticks < 10000000)
			{
				return;
			}
			lock (_reloadLock)
			{
				if (!ConfigSync.IsSourceOfTruth)
				{
					ServerSyncModTemplateLogger.LogInfo((object)"Ignoring local monster dive YAML reload because remote synced values are active.");
					return;
				}
				try
				{
					LoadMonsterDiveYamlFromDisk(forceWriteDefaultIfMissing: true, syncToPeers: true, "yaml reload");
					ServerSyncModTemplateLogger.LogInfo((object)"Monster dive YAML reload complete.");
				}
				catch (Exception ex)
				{
					ServerSyncModTemplateLogger.LogError((object)("Error reloading monster dive YAML: " + ex.Message));
				}
			}
			_lastMonsterDiveYamlReloadTime = now;
		}

		private void OnMonsterDiveSourceOfTruthChanged(bool isSourceOfTruth)
		{
			if (isSourceOfTruth)
			{
				LoadMonsterDiveYamlFromDisk(forceWriteDefaultIfMissing: true, syncToPeers: true, "source of truth changed to local");
			}
			else if (!string.IsNullOrWhiteSpace(_monsterDiveYamlSync.Value))
			{
				ApplyMonsterDiveYaml(_monsterDiveYamlSync.Value, "source of truth changed to remote");
			}
		}

		private void OnMonsterDiveYamlValueChanged()
		{
			if (!ConfigSync.IsSourceOfTruth && !string.IsNullOrWhiteSpace(_monsterDiveYamlSync.Value))
			{
				ApplyMonsterDiveYaml(_monsterDiveYamlSync.Value, "synced value changed");
			}
		}

		private static MonsterDiveYamlGroup CreateDefaultGroup(float minDepth, float centerDepth, float maxDepth)
		{
			return new MonsterDiveYamlGroup
			{
				PassiveMinDepth = minDepth,
				PassiveCenterDepth = centerDepth,
				PassiveMaxDepth = maxDepth,
				Prefabs = new List<string>()
			};
		}

		private void LoadMonsterDiveYamlFromDisk(bool forceWriteDefaultIfMissing, bool syncToPeers, string reason)
		{
			lock (MonsterDiveYamlLock)
			{
				if (!File.Exists(MonsterDiveYamlFileFullPath))
				{
					if (!forceWriteDefaultIfMissing)
					{
						return;
					}
					string contents = BuildDefaultMonsterDiveYaml();
					Directory.CreateDirectory(Paths.ConfigPath);
					File.WriteAllText(MonsterDiveYamlFileFullPath, contents);
				}
				string text = File.ReadAllText(MonsterDiveYamlFileFullPath);
				if (ApplyMonsterDiveYaml(text, reason) && syncToPeers && _monsterDiveYamlSync.Value != text)
				{
					_monsterDiveYamlSync.Value = text;
				}
			}
		}

		private static bool ApplyMonsterDiveYaml(string yamlText, string reason)
		{
			if (string.IsNullOrWhiteSpace(yamlText))
			{
				ServerSyncModTemplateLogger.LogWarning((object)("Monster dive YAML is empty during " + reason + ". Keeping previous settings."));
				return false;
			}
			MonsterDiveYamlRoot monsterDiveYamlRoot;
			try
			{
				monsterDiveYamlRoot = MonsterDiveYamlDeserializer.Deserialize<MonsterDiveYamlRoot>(yamlText) ?? new MonsterDiveYamlRoot();
			}
			catch (YamlException ex)
			{
				string text = ((ex.Start.Line > 0) ? $" at line {ex.Start.Line}, column {ex.Start.Column}" : string.Empty);
				ServerSyncModTemplateLogger.LogError((object)("Failed to parse monster dive YAML during " + reason + text + ": " + ex.Message));
				return false;
			}
			catch (Exception ex2)
			{
				ServerSyncModTemplateLogger.LogError((object)("Failed to parse monster dive YAML during " + reason + ": " + ex2.Message));
				return false;
			}
			MonsterDiveGlobalSettings monsterDiveGlobalSettings = NormalizeGlobalSettings(monsterDiveYamlRoot.Global);
			Dictionary<string, MonsterDiveYamlGroup> definedGroups = GetDefinedGroups(monsterDiveYamlRoot);
			Dictionary<string, ConfiguredDiveProfile> dictionary = new Dictionary<string, ConfiguredDiveProfile>(StringComparer.OrdinalIgnoreCase);
			foreach (KeyValuePair<string, MonsterDiveYamlGroup> item in definedGroups)
			{
				string key = item.Key;
				MonsterDiveYamlGroup value = item.Value;
				PassiveDepthProfile passiveProfile = NormalizePassiveDepthProfile(key, value.PassiveMinDepth, value.PassiveCenterDepth, value.PassiveMaxDepth);
				AddYamlGroupEntries(dictionary, value.Prefabs, key, passiveProfile);
			}
			if (dictionary.Count == 0)
			{
				ServerSyncModTemplateLogger.LogWarning((object)("Monster dive YAML loaded during " + reason + ", but no prefabs are assigned to any group."));
			}
			lock (PrefabSetLock)
			{
				_monsterDiveGlobalSettings = monsterDiveGlobalSettings;
				_configuredDiveProfilesByPrefabName = dictionary;
			}
			int num = RestoreRemovedMonsterDiveFlags();
			ClearRuntimeCaches();
			ServerSyncModTemplateLogger.LogInfo((object)$"Loaded monster dive YAML ({reason}). global[min={monsterDiveGlobalSettings.SwimDepthMin:F2}, max={monsterDiveGlobalSettings.SwimDepthMax:F2}, adjust={monsterDiveGlobalSettings.SwimDepthAdjustSpeed:F2}], groups={definedGroups.Count}, prefabs={dictionary.Count}, restoredRemovedInstances={num}.");
			return true;
		}

		private static MonsterDiveGlobalSettings NormalizeGlobalSettings(MonsterDiveYamlGlobal? global)
		{
			if (global == null)
			{
				return DefaultMonsterDiveGlobalSettings;
			}
			float swimDepthMin = global.SwimDepthMin;
			float swimDepthMax = global.SwimDepthMax;
			float swimDepthAdjustSpeed = global.SwimDepthAdjustSpeed;
			float num = Mathf.Max(0.25f, swimDepthMin);
			float num2 = Mathf.Max(num, swimDepthMax);
			float num3 = Mathf.Max(0f, swimDepthAdjustSpeed);
			if (!Mathf.Approximately(num, swimDepthMin) || !Mathf.Approximately(num2, swimDepthMax) || !Mathf.Approximately(num3, swimDepthAdjustSpeed))
			{
				ServerSyncModTemplateLogger.LogWarning((object)("Monster dive YAML normalized global values: swim_depth_min " + swimDepthMin.ToString("0.###", CultureInfo.InvariantCulture) + " -> " + num.ToString("0.###", CultureInfo.InvariantCulture) + ", swim_depth_max " + swimDepthMax.ToString("0.###", CultureInfo.InvariantCulture) + " -> " + num2.ToString("0.###", CultureInfo.InvariantCulture) + ", swim_depth_adjust_speed " + swimDepthAdjustSpeed.ToString("0.###", CultureInfo.InvariantCulture) + " -> " + num3.ToString("0.###", CultureInfo.InvariantCulture) + "."));
			}
			return new MonsterDiveGlobalSettings(num, num2, num3);
		}

		private static PassiveDepthProfile NormalizePassiveDepthProfile(string groupName, float minDepth, float centerDepth, float maxDepth)
		{
			float num = minDepth;
			float num2 = centerDepth;
			float num3 = maxDepth;
			float num4 = Mathf.Max(0f, num);
			float num5 = Mathf.Max(0f, num3);
			if (num5 < num4)
			{
				float num6 = num5;
				num5 = num4;
				num4 = num6;
			}
			float num7 = Mathf.Clamp(num2, num4, num5);
			if (!Mathf.Approximately(num4, num) || !Mathf.Approximately(num5, num3) || !Mathf.Approximately(num7, num2))
			{
				ServerSyncModTemplateLogger.LogWarning((object)("Monster dive YAML normalized passive profile '" + groupName + "': passive_min_depth " + num.ToString("0.###", CultureInfo.InvariantCulture) + " -> " + num4.ToString("0.###", CultureInfo.InvariantCulture) + ", passive_center_depth " + num2.ToString("0.###", CultureInfo.InvariantCulture) + " -> " + num7.ToString("0.###", CultureInfo.InvariantCulture) + ", passive_max_depth " + num3.ToString("0.###", CultureInfo.InvariantCulture) + " -> " + num5.ToString("0.###", CultureInfo.InvariantCulture) + "."));
			}
			return new PassiveDepthProfile(num7, num4, num5);
		}

		private static Dictionary<string, MonsterDiveYamlGroup> GetDefinedGroups(MonsterDiveYamlRoot root)
		{
			Dictionary<string, MonsterDiveYamlGroup> dictionary = new Dictionary<string, MonsterDiveYamlGroup>(StringComparer.OrdinalIgnoreCase);
			if (root.Groups == null || root.Groups.Count == 0)
			{
				return dictionary;
			}
			foreach (KeyValuePair<string, MonsterDiveYamlGroup> group in root.Groups)
			{
				string text = group.Key?.Trim() ?? string.Empty;
				if (text.Length == 0)
				{
					ServerSyncModTemplateLogger.LogWarning((object)"Monster dive YAML contains an empty group name under groups:. Skipping it.");
				}
				else
				{
					dictionary[text] = group.Value ?? new MonsterDiveYamlGroup();
				}
			}
			return dictionary;
		}

		private static void AddYamlGroupEntries(Dictionary<string, ConfiguredDiveProfile> configuredProfilesByPrefabName, IEnumerable<string>? mobs, string groupName, PassiveDepthProfile passiveProfile)
		{
			if (mobs == null)
			{
				return;
			}
			foreach (string mob in mobs)
			{
				string text = mob?.Trim() ?? string.Empty;
				if (text.Length != 0)
				{
					if (configuredProfilesByPrefabName.ContainsKey(text))
					{
						ServerSyncModTemplateLogger.LogWarning((object)("Monster dive YAML duplicate mob '" + text + "' found in " + groupName + ". Keeping first assignment."));
					}
					else
					{
						configuredProfilesByPrefabName[text] = new ConfiguredDiveProfile(groupName, passiveProfile);
					}
				}
			}
		}

		private static string BuildDefaultMonsterDiveYaml()
		{
			StringBuilder stringBuilder = new StringBuilder();
			stringBuilder.AppendLine("# Monster dive configuration for DiveIn.");
			stringBuilder.AppendLine("# Unknown keys and duplicate keys are treated as errors and keep the previous applied settings.");
			stringBuilder.AppendLine("global:");
			stringBuilder.AppendLine("  swim_depth_min: " + FormatYamlFloat(DefaultMonsterDiveGlobalSettings.SwimDepthMin) + " # Minimum underwater depth allowed while a configured monster actively chases a target.");
			stringBuilder.AppendLine("  swim_depth_max: " + FormatYamlFloat(DefaultMonsterDiveGlobalSettings.SwimDepthMax) + " # Maximum underwater depth allowed while a configured monster actively chases a target.");
			stringBuilder.AppendLine("  swim_depth_adjust_speed: " + FormatYamlFloat(DefaultMonsterDiveGlobalSettings.SwimDepthAdjustSpeed) + " # How quickly a configured monster adjusts its swim depth toward the requested active target depth.");
			stringBuilder.AppendLine();
			stringBuilder.AppendLine("groups:");
			AppendDefaultGroup(stringBuilder, "surface_patrol", 0f, 10f, 20f, includeGroupHeaderComment: true, new string[2] { "Serpent", "Leech" });
			stringBuilder.AppendLine();
			AppendDefaultGroup(stringBuilder, "mid_water", 0f, 15f, 30f);
			stringBuilder.AppendLine();
			AppendDefaultGroup(stringBuilder, "deep_patrol", 10f, 20f, 30f);
			stringBuilder.AppendLine();
			stringBuilder.AppendLine("## RtDOcean sample");
			stringBuilder.AppendLine();
			AppendDefaultGroup(stringBuilder, "rtd_surface", 0f, 10f, 20f, includeGroupHeaderComment: false, new string[11]
			{
				"Neck_RtD", "Animal_Dolphin_RtD", "Animal_Cod_RtD", "Monster_GreatWhiteShark_RtD", "Animal_Turtle_RtD", "Mirmaid_RtD", "BoneFish_RtD", "BoneSquid_RtD", "LuminousLooker_RtD", "MurkPod_RtD",
				"Animal_HumpbackWhale_RtD"
			});
			stringBuilder.AppendLine();
			AppendDefaultGroup(stringBuilder, "rtd_midwater", 0f, 15f, 30f, includeGroupHeaderComment: false, new string[6] { "Belzor_RtD", "Monster_HammerheadShark_RtD", "Animal_Marlin_RtD", "Shark_RtD", "Animal_SpermWhale_RtD", "Monster_Orca_RtD" });
			stringBuilder.AppendLine();
			AppendDefaultGroup(stringBuilder, "rtd_deep", 10f, 20f, 30f, includeGroupHeaderComment: false, new string[2] { "Animal_Tuna_RtD", "Animal_Squid_RtD" });
			stringBuilder.AppendLine();
			AppendDefaultGroup(stringBuilder, "rtd_bottom", 20f, 30f, 40f, includeGroupHeaderComment: false, new string[3] { "CatFish_RtD", "Reptile_RtD", "Animal_Manta_RtD" });
			return stringBuilder.ToString();
		}

		private static void AppendDefaultGroup(StringBuilder builder, string groupName, float minDepth, float centerDepth, float maxDepth, bool includeGroupHeaderComment = false, IEnumerable<string>? examplePrefabs = null)
		{
			string text = (includeGroupHeaderComment ? " # You can use any group name. Add your own groups" : string.Empty);
			builder.AppendLine("  " + groupName + ":" + text);
			builder.AppendLine("    passive_min_depth: " + FormatYamlFloat(minDepth) + " # Shallowest passive dive depth used while the monster has no target and is not alerted.");
			builder.AppendLine("    passive_center_depth: " + FormatYamlFloat(centerDepth) + " # Center depth used by the passive sine-wave swimming pattern.");
			builder.AppendLine("    passive_max_depth: " + FormatYamlFloat(maxDepth) + " # Deepest passive dive depth used while the monster has no target and is not alerted.");
			if (examplePrefabs != null)
			{
				string[] array = examplePrefabs.Where((string prefab) => !string.IsNullOrWhiteSpace(prefab)).ToArray();
				if (array.Length != 0)
				{
					builder.AppendLine("    prefabs: # Monster prefab names assigned to this passive profile group.");
					string[] array2 = array;
					foreach (string text2 in array2)
					{
						builder.AppendLine("      - " + text2);
					}
					return;
				}
			}
			builder.AppendLine("    prefabs: [] # Monster prefab names assigned to this passive profile group.");
		}

		private static string FormatYamlFloat(float value)
		{
			return value.ToString("0.###", CultureInfo.InvariantCulture);
		}

		private void InitializePlayerDiveConfig()
		{
			//IL_0032: Unknown result type (might be due to invalid IL or missing references)
			//IL_003d: Expected O, but got Unknown
			//IL_0081: Unknown result type (might be due to invalid IL or missing references)
			//IL_008c: Expected O, but got Unknown
			//IL_00d0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00db: Expected O, but got Unknown
			//IL_011f: Unknown result type (might be due to invalid IL or missing references)
			//IL_012a: Expected O, but got Unknown
			//IL_016e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0179: Expected O, but got Unknown
			//IL_01bd: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c8: Expected O, but got Unknown
			_waterEquipmentBlacklist = config("2a - Player Diving", "Water Equipment Blacklist", "", new ConfigDescription("Comma-separated item prefab names that remain restricted in water. Everything not listed is allowed in water by default. Example: BowFineWood,ShieldBronzeBuckler.", (AcceptableValueBase)null, new object[1]
			{
				new ConfigurationManagerAttributes
				{
					Order = 100
				}
			}));
			_waterStaminaRegenRateMultiplier = config("2a - Player Diving", "Water Stamina Regen Rate", 0.5f, new ConfigDescription("Multiplier applied to vanilla stamina regeneration while swimming or diving in water. 0 matches vanilla swimming behavior (effective stamina regeneration stays at 0), 1 matches vanilla normal non-swimming stamina regeneration timing and rate.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 2f), new object[1]
			{
				new ConfigurationManagerAttributes
				{
					Order = 99
				}
			}));
			_waterDepthStaminaDrainStart = config("2a - Player Diving", "Water Depth Stamina Drain Start", 2.5f, new ConfigDescription("Depth in meters below the surface where extra swim stamina drain begins.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 50f), new object[1]
			{
				new ConfigurationManagerAttributes
				{
					Order = 98
				}
			}));
			_waterDepthStaminaDrainFull = config("2a - Player Diving", "Water Depth Stamina Drain Full", 30f, new ConfigDescription("Depth in meters below the surface where the maximum extra swim stamina drain multiplier is reached.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.25f, 100f), new object[1]
			{
				new ConfigurationManagerAttributes
				{
					Order = 97
				}
			}));
			_waterDepthStaminaDrainMaxMultiplier = config("2a - Player Diving", "Water Depth Stamina Drain Max Multiplier", 2f, new ConfigDescription("Maximum multiplier applied to vanilla moving swim stamina drain at or below the full depth.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 5f), new object[1]
			{
				new ConfigurationManagerAttributes
				{
					Order = 96
				}
			}));
			_playerSwimRunSpeedMultiplier = config("2a - Player Diving", "Swim Run Speed Multiplier", 1.5f, new ConfigDescription("Multiplier applied to vanilla base swim speed while holding the run key underwater. 1 matches vanilla swim speed, 1.5 matches swim speed 3 with vanilla base swim speed 2.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 3f), new object[1]
			{
				new ConfigurationManagerAttributes
				{
					Order = 95
				}
			}));
		}

		internal static bool IsPlayerDivingEnabled()
		{
			return true;
		}

		internal static bool IsUnderwaterCameraFollowEnabled()
		{
			return IsPlayerDiveEnvAllowed();
		}

		internal static bool IsUnderwaterVisualStylingEnabled()
		{
			return IsPlayerDiveEnvAllowed();
		}

		internal static bool IsUnderwaterVisualDebugLoggingEnabled()
		{
			return false;
		}

		internal static float GetUnderwaterCameraMinWaterDistance()
		{
			return -5000f;
		}

		internal static bool IsPlayerDiveEnvAllowed()
		{
			return true;
		}

		internal static bool IsWaterRestrictedItem(ItemData? item)
		{
			if (item == null || (Object)(object)item.m_dropPrefab == (Object)null)
			{
				return false;
			}
			RefreshWaterEquipmentBlacklistIfNeeded();
			string prefabName = Utils.GetPrefabName(item.m_dropPrefab);
			return !string.IsNullOrEmpty(prefabName) && _waterEquipmentBlacklistSet.Contains(prefabName);
		}

		internal static bool HumanoidHasWaterRestrictedEquipment(Humanoid? humanoid)
		{
			if ((Object)(object)humanoid == (Object)null)
			{
				return false;
			}
			return IsWaterRestrictedItem(humanoid.m_rightItem) || IsWaterRestrictedItem(humanoid.m_hiddenRightItem) || IsWaterRestrictedItem(humanoid.m_leftItem) || IsWaterRestrictedItem(humanoid.m_hiddenLeftItem) || IsWaterRestrictedItem(humanoid.m_chestItem) || IsWaterRestrictedItem(humanoid.m_legItem) || IsWaterRestrictedItem(humanoid.m_helmetItem) || IsWaterRestrictedItem(humanoid.m_shoulderItem) || IsWaterRestrictedItem(humanoid.m_utilityItem) || IsWaterRestrictedItem(humanoid.m_trinketItem);
		}

		private static void RefreshWaterEquipmentBlacklistIfNeeded(bool force = false)
		{
			string text = _waterEquipmentBlacklist?.Value ?? string.Empty;
			if (!force && string.Equals(text, _lastWaterEquipmentBlacklistRaw, StringComparison.Ordinal))
			{
				return;
			}
			lock (WaterEquipmentBlacklistLock)
			{
				if (force || !string.Equals(text, _lastWaterEquipmentBlacklistRaw, StringComparison.Ordinal))
				{
					_waterEquipmentBlacklistSet = (from entry in text.Split(new char[5] { ',', ';', '\n', '\r', '\t' }, StringSplitOptions.RemoveEmptyEntries)
						select entry.Trim() into entry
						where entry.Length > 0
						select entry).ToHashSet<string>(StringComparer.OrdinalIgnoreCase);
					_lastWaterEquipmentBlacklistRaw = text;
				}
			}
		}

		public void Awake()
		{
			//IL_006f: Unknown result type (might be due to invalid IL or missing references)
			//IL_007a: Expected O, but got Unknown
			bool saveOnConfigSet = ((BaseUnityPlugin)this).Config.SaveOnConfigSet;
			((BaseUnityPlugin)this).Config.SaveOnConfigSet = false;
			_serverConfigLocked = config("1 - General", "Lock Configuration", Toggle.On, "If on, the configuration is locked and can be changed by server admins only.");
			ConfigSync.AddLockingConfigEntry<Toggle>(_serverConfigLocked);
			_diveAiQuality = config("3 - Performance", "Dive AI Quality", 50f, new ConfigDescription("Single quality slider for underwater AI behavior. 0 = minimum CPU/minimum smoothness, 100 = maximum CPU/maximum smoothness. Internally adjusts route check cache time, steer cache time, cache cell size, and avoidance sample count.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 100f), Array.Empty<object>()));
			InitializePlayerDiveConfig();
			InitializeMonsterDiveYaml();
			ClearRuntimeCaches();
			_harmony.PatchAll(Assembly.GetExecutingAssembly());
			SetupWatcher();
			SetupMonsterDiveYamlWatcher();
			((BaseUnityPlugin)this).Config.Save();
			if (saveOnConfigSet)
			{
				((BaseUnityPlugin)this).Config.SaveOnConfigSet = saveOnConfigSet;
			}
		}

		private void OnDestroy()
		{
			UnderwaterVisualState.ResetAll("plugin destroy");
			SaveWithRespectToConfigSet();
			_watcher?.Dispose();
			DisposeMonsterDiveYamlWatcher();
		}

		private void SetupWatcher()
		{
			_watcher = new FileSystemWatcher(Paths.ConfigPath, ConfigFileName);
			_watcher.Changed += ReadConfigValues;
			_watcher.Created += ReadConfigValues;
			_watcher.Renamed += ReadConfigValues;
			_watcher.IncludeSubdirectories = true;
			_watcher.SynchronizingObject = ThreadingHelper.SynchronizingObject;
			_watcher.EnableRaisingEvents = true;
		}

		private void ReadConfigValues(object sender, FileSystemEventArgs e)
		{
			DateTime now = DateTime.Now;
			if (now.Ticks - _lastConfigReloadTime.Ticks < 10000000)
			{
				return;
			}
			lock (_reloadLock)
			{
				if (!File.Exists(ConfigFileFullPath))
				{
					ServerSyncModTemplateLogger.LogWarning((object)"Config file does not exist. Skipping reload.");
					return;
				}
				try
				{
					SaveWithRespectToConfigSet(reload: true);
					UnderwaterVisualState.ResetAll("config reload");
					ClearRuntimeCaches();
					ServerSyncModTemplateLogger.LogInfo((object)"Configuration reload complete.");
				}
				catch (Exception ex)
				{
					ServerSyncModTemplateLogger.LogError((object)("Error reloading configuration: " + ex.Message));
				}
			}
			_lastConfigReloadTime = now;
		}

		private void SaveWithRespectToConfigSet(bool reload = false)
		{
			bool saveOnConfigSet = ((BaseUnityPlugin)this).Config.SaveOnConfigSet;
			((BaseUnityPlugin)this).Config.SaveOnConfigSet = false;
			if (reload)
			{
				((BaseUnityPlugin)this).Config.Reload();
			}
			((BaseUnityPlugin)this).Config.Save();
			if (saveOnConfigSet)
			{
				((BaseUnityPlugin)this).Config.SaveOnConfigSet = saveOnConfigSet;
			}
		}

		private static bool TryGetConfiguredDiveProfile(MonsterAI monsterAI, out ConfiguredDiveProfile configuredDiveProfile)
		{
			if ((Object)(object)monsterAI == (Object)null)
			{
				configuredDiveProfile = default(ConfiguredDiveProfile);
				return false;
			}
			string prefabName = Utils.GetPrefabName(((Component)monsterAI).gameObject);
			return _configuredDiveProfilesByPrefabName.TryGetValue(prefabName, out configuredDiveProfile);
		}

		private static bool IsConfiguredMonster(MonsterAI monsterAI)
		{
			ConfiguredDiveProfile configuredDiveProfile;
			return TryGetConfiguredDiveProfile(monsterAI, out configuredDiveProfile);
		}

		private static bool TryGetConfiguredMonster(BaseAI ai, out MonsterAI monsterAI)
		{
			MonsterAI val = (MonsterAI)(object)((ai is MonsterAI) ? ai : null);
			if (val != null && IsConfiguredMonster(val))
			{
				monsterAI = val;
				return true;
			}
			monsterAI = null;
			return false;
		}

		private static bool ShouldUseWaterDiveMode(MonsterAI monsterAI)
		{
			Character character = ((BaseAI)monsterAI).m_character;
			if ((Object)(object)character == (Object)null)
			{
				return false;
			}
			return character.InWater() && character.InLiquidDepth() > 0.05f;
		}

		private static bool IsPassiveDiveState(MonsterAI monsterAI)
		{
			return !((BaseAI)monsterAI).IsAlerted() && (Object)(object)monsterAI.m_targetCreature == (Object)null && (Object)(object)monsterAI.m_targetStatic == (Object)null;
		}

		private static void EnsureDiveFlags(MonsterAI monsterAI)
		{
			TrackOriginalDiveFlags(monsterAI);
			if (((BaseAI)monsterAI).m_avoidWater)
			{
				((BaseAI)monsterAI).m_avoidWater = false;
			}
			Character character = ((BaseAI)monsterAI).m_character;
			if ((Object)(object)character != (Object)null && !character.m_canSwim)
			{
				character.m_canSwim = true;
			}
		}

		private static void TrackOriginalDiveFlags(MonsterAI monsterAI)
		{
			if (!Object.op_Implicit((Object)(object)monsterAI))
			{
				return;
			}
			int instanceID = ((Object)monsterAI).GetInstanceID();
			if (!OriginalDiveFlagsByInstance.ContainsKey(instanceID))
			{
				Character character = ((BaseAI)monsterAI).m_character;
				OriginalDiveFlagsByInstance[instanceID] = new OriginalDiveFlags(monsterAI, ((BaseAI)monsterAI).m_avoidWater, (Object)(object)character != (Object)null && character.m_canSwim);
				if (OriginalDiveFlagsByInstance.Count > 2048)
				{
					PruneTrackedOriginalDiveFlags();
				}
			}
		}

		private static int RestoreRemovedMonsterDiveFlags()
		{
			if (OriginalDiveFlagsByInstance.Count == 0)
			{
				return 0;
			}
			List<int> list = new List<int>();
			int num = 0;
			foreach (KeyValuePair<int, OriginalDiveFlags> item in OriginalDiveFlagsByInstance)
			{
				int key = item.Key;
				OriginalDiveFlags value = item.Value;
				MonsterAI monsterAI = value.MonsterAI;
				if (!Object.op_Implicit((Object)(object)monsterAI))
				{
					list.Add(key);
				}
				else if (!IsConfiguredMonster(monsterAI))
				{
					((BaseAI)monsterAI).m_avoidWater = value.AvoidWater;
					Character character = ((BaseAI)monsterAI).m_character;
					if ((Object)(object)character != (Object)null)
					{
						character.m_canSwim = value.CanSwim;
					}
					list.Add(key);
					num++;
				}
			}
			foreach (int item2 in list)
			{
				OriginalDiveFlagsByInstance.Remove(item2);
			}
			return num;
		}

		private static void PruneTrackedOriginalDiveFlags()
		{
			if (OriginalDiveFlagsByInstance.Count == 0)
			{
				return;
			}
			List<int> list = new List<int>();
			foreach (KeyValuePair<int, OriginalDiveFlags> item in OriginalDiveFlagsByInstance)
			{
				int key = item.Key;
				if (!Object.op_Implicit((Object)(object)item.Value.MonsterAI))
				{
					list.Add(key);
				}
			}
			foreach (int item2 in list)
			{
				OriginalDiveFlagsByInstance.Remove(item2);
			}
		}

		private static Vector3Int ToCacheBucket(Vector3 value)
		{
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			//IL_002e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0033: Unknown result type (might be due to invalid IL or missing references)
			//IL_0036: Unknown result type (might be due to invalid IL or missing references)
			float cacheCellSize = GetCacheCellSize();
			return new Vector3Int(Mathf.RoundToInt(value.x / cacheCellSize), Mathf.RoundToInt(value.y / cacheCellSize), Mathf.RoundToInt(value.z / cacheCellSize));
		}

		private static void ClearRuntimeCaches()
		{
			RouteCache.Clear();
			SteerCache.Clear();
		}

		private static void TrimCachesIfNeeded()
		{
			if (RouteCache.Count > 2048)
			{
				RouteCache.Clear();
			}
			if (SteerCache.Count > 2048)
			{
				SteerCache.Clear();
			}
		}

		private static float GetPassiveDesiredDepth(MonsterAI monsterAI)
		{
			if (!TryGetConfiguredDiveProfile(monsterAI, out var configuredDiveProfile))
			{
				return 0f;
			}
			PassiveDepthProfile passiveDepthProfile = configuredDiveProfile.PassiveDepthProfile;
			int num = Mathf.Abs(((Object)monsterAI).GetInstanceID());
			float num2 = Time.time + (float)(num % 997) * 0.173f;
			float num3 = Mathf.Sin(Mathf.Repeat(num2, 12f) / 12f * (float)Math.PI * 2f);
			float num4 = Mathf.Max(0f, passiveDepthProfile.CenterDepth - passiveDepthProfile.MinDepth);
			float num5 = Mathf.Max(0f, passiveDepthProfile.MaxDepth - passiveDepthProfile.CenterDepth);
			return (num3 >= 0f) ? (passiveDepthProfile.CenterDepth + num3 * num5) : (passiveDepthProfile.CenterDepth + num3 * num4);
		}

		private static void TryLogOverlapFields(MonsterAI monsterAI, string stage)
		{
		}

		private static float GetQuality01()
		{
			return Mathf.Clamp01(_diveAiQuality.Value / 100f);
		}

		private static float GetRouteCacheSeconds()
		{
			return Mathf.Lerp(1f, 0f, GetQuality01());
		}

		private static float GetSteerCacheSeconds()
		{
			return Mathf.Lerp(1f, 0f, GetQuality01());
		}

		private static float GetCacheCellSize()
		{
			return Mathf.Lerp(3f, 0.1f, GetQuality01());
		}

		private static int GetAvoidanceSampleCount()
		{
			return Mathf.Clamp(Mathf.RoundToInt(Mathf.Lerp(3f, 8f, GetQuality01())), 3, 8);
		}

		private static SwimDepthGoal UpdateSwimDepthTowardsTarget(MonsterAI monsterAI, Character character, Vector3 point, float dt)
		{
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			float swimDepthMin = _monsterDiveGlobalSettings.SwimDepthMin;
			float swimDepthMax = _monsterDiveGlobalSettings.SwimDepthMax;
			float liquidLevel = character.GetLiquidLevel();
			float num = liquidLevel - point.y;
			bool flag = IsPassiveDiveState(monsterAI);
			float num2 = (flag ? GetPassiveDesiredDepth(monsterAI) : num);
			bool requestedOutsideRange = flag || num < swimDepthMin || num > swimDepthMax;
			num2 = Mathf.Clamp(num2, swimDepthMin, swimDepthMax);
			float clampedTargetY = liquidLevel - num2;
			float swimDepthAdjustSpeed = _monsterDiveGlobalSettings.SwimDepthAdjustSpeed;
			if (swimDepthAdjustSpeed <= 0f)
			{
				character.m_swimDepth = num2;
				return new SwimDepthGoal(clampedTargetY, requestedOutsideRange);
			}
			float num3 = swimDepthAdjustSpeed * Mathf.Max(dt, 0.01f);
			character.m_swimDepth = Mathf.Clamp(Mathf.MoveTowards(character.m_swimDepth, num2, num3), swimDepthMin, swimDepthMax);
			return new SwimDepthGoal(clampedTargetY, requestedOutsideRange);
		}

		private static Vector3 BuildSteerDirectionWithAvoidance(BaseAI ai, Character character, Vector3 targetPoint)
		{
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			//IL_0085: Unknown result type (might be due to invalid IL or missing references)
			//IL_008c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0091: Unknown result type (might be due to invalid IL or missing references)
			//IL_0096: Unknown result type (might be due to invalid IL or missing references)
			//IL_0079: Unknown result type (might be due to invalid IL or missing references)
			//IL_007e: Unknown result type (might be due to invalid IL or missing references)
			//IL_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_00c6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e6: 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_00b0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b5: Unknown result type (might be due to invalid IL or missing references)
			//IL_029e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0062: Unknown result type (might be due to invalid IL or missing references)
			//IL_0067: Unknown result type (might be due to invalid IL or missing references)
			//IL_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_0147: Unknown result type (might be due to invalid IL or missing references)
			//IL_0149: Unknown result type (might be due to invalid IL or missing references)
			//IL_0298: Unknown result type (might be due to invalid IL or missing references)
			//IL_029a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0288: Unknown result type (might be due to invalid IL or missing references)
			//IL_0289: Unknown result type (might be due to invalid IL or missing references)
			//IL_028a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0171: Unknown result type (might be due to invalid IL or missing references)
			//IL_0176: Unknown result type (might be due to invalid IL or missing references)
			//IL_0178: Unknown result type (might be due to invalid IL or missing references)
			//IL_017d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0180: Unknown result type (might be due to invalid IL or missing references)
			//IL_0203: Unknown result type (might be due to invalid IL or missing references)
			//IL_020a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0211: Unknown result type (might be due to invalid IL or missing references)
			//IL_01aa: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ac: Unknown result type (might be due to invalid IL or missing references)
			//IL_0231: Unknown result type (might be due to invalid IL or missing references)
			//IL_022b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0236: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e6: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e8: Unknown result type (might be due to invalid IL or missing references)
			//IL_0265: Unknown result type (might be due to invalid IL or missing references)
			//IL_0267: Unknown result type (might be due to invalid IL or missing references)
			//IL_0255: Unknown result type (might be due to invalid IL or missing references)
			//IL_0256: Unknown result type (might be due to invalid IL or missing references)
			//IL_0257: Unknown result type (might be due to invalid IL or missing references)
			float steerCacheSeconds = GetSteerCacheSeconds();
			int instanceID = ((Object)ai).GetInstanceID();
			Vector3Int val = ToCacheBucket(((Component)ai).transform.position);
			Vector3Int val2 = ToCacheBucket(targetPoint);
			float time = Time.time;
			if (steerCacheSeconds > 0f && SteerCache.TryGetValue(instanceID, out var value) && time - value.Time <= steerCacheSeconds && value.PositionBucket == val && value.TargetBucket == val2)
			{
				return value.Direction;
			}
			Vector3 val3 = targetPoint - ((Component)ai).transform.position;
			if (((Vector3)(ref val3)).sqrMagnitude <= 0.0001f)
			{
				return Vector3.zero;
			}
			((Vector3)(ref val3)).Normalize();
			Vector3 val4 = default(Vector3);
			((Vector3)(ref val4))..ctor(val3.x, 0f, val3.z);
			float radius = character.GetRadius();
			float num = Mathf.Clamp(Utils.DistanceXZ(targetPoint, ((Component)ai).transform.position), radius + 1f, 6f);
			if (((Vector3)(ref val4)).sqrMagnitude > 0.0001f)
			{
				((Vector3)(ref val4)).Normalize();
				Vector3 centerPoint = character.GetCenterPoint();
				int num2 = Mathf.Clamp(GetAvoidanceSampleCount(), 3, SteerAngles.Length);
				Vector3 val5 = val4;
				float num3 = float.NegativeInfinity;
				for (int i = 0; i < num2; i++)
				{
					float num4 = SteerAngles[i];
					Vector3 val6 = Quaternion.Euler(0f, num4, 0f) * val4;
					float num5;
					if (ai.CanMove(val6, radius, num))
					{
						num5 = 1000f - Mathf.Abs(num4);
					}
					else
					{
						float num6 = ai.Raycast(centerPoint, val6, num * 2f, 0.1f);
						num5 = num6 - Mathf.Abs(num4) * 0.01f;
					}
					if (num5 > num3)
					{
						num3 = num5;
						val5 = val6;
					}
				}
				Vector3 val7 = default(Vector3);
				((Vector3)(ref val7))..ctor(val5.x, val3.y, val5.z);
				Vector3 val8 = ((((Vector3)(ref val7)).sqrMagnitude > 0.0001f) ? ((Vector3)(ref val7)).normalized : val3);
				if (steerCacheSeconds > 0f)
				{
					TrimCachesIfNeeded();
					SteerCache[instanceID] = new SteerCacheEntry(time, val, val2, val8);
				}
				return val8;
			}
			if (steerCacheSeconds > 0f)
			{
				TrimCachesIfNeeded();
				SteerCache[instanceID] = new SteerCacheEntry(time, val, val2, val3);
			}
			return val3;
		}

		private static bool HasReasonableUnderwaterRoute(BaseAI ai, Character character, Vector3 targetPoint)
		{
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			//IL_008d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0094: Unknown result type (might be due to invalid IL or missing references)
			//IL_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_00ea: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f1: 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_00fb: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ff: 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_0062: Unknown result type (might be due to invalid IL or missing references)
			//IL_0067: Unknown result type (might be due to invalid IL or missing references)
			//IL_016c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0171: 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_00d4: Unknown result type (might be due to invalid IL or missing references)
			//IL_014c: Unknown result type (might be due to invalid IL or missing references)
			//IL_014d: Unknown result type (might be due to invalid IL or missing references)
			//IL_01bc: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c1: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c3: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c8: Unknown result type (might be due to invalid IL or missing references)
			//IL_01cb: Unknown result type (might be due to invalid IL or missing references)
			//IL_01cd: Unknown result type (might be due to invalid IL or missing references)
			//IL_0257: Unknown result type (might be due to invalid IL or missing references)
			//IL_0258: Unknown result type (might be due to invalid IL or missing references)
			//IL_0210: Unknown result type (might be due to invalid IL or missing references)
			//IL_0211: Unknown result type (might be due to invalid IL or missing references)
			float routeCacheSeconds = GetRouteCacheSeconds();
			int instanceID = ((Object)ai).GetInstanceID();
			Vector3Int val = ToCacheBucket(((Component)ai).transform.position);
			Vector3Int val2 = ToCacheBucket(targetPoint);
			float time = Time.time;
			if (routeCacheSeconds > 0f && RouteCache.TryGetValue(instanceID, out var value) && time - value.Time <= routeCacheSeconds && value.PositionBucket == val && value.TargetBucket == val2)
			{
				return value.Result;
			}
			float radius = character.GetRadius();
			float num = Utils.DistanceXZ(targetPoint, ((Component)ai).transform.position);
			if (num <= radius + 0.6f)
			{
				if (routeCacheSeconds > 0f)
				{
					TrimCachesIfNeeded();
					RouteCache[instanceID] = new RouteCacheEntry(time, val, val2, result: true);
				}
				return true;
			}
			Vector3 val3 = targetPoint - ((Component)ai).transform.position;
			Vector3 val4 = default(Vector3);
			((Vector3)(ref val4))..ctor(val3.x, 0f, val3.z);
			if (((Vector3)(ref val4)).sqrMagnitude <= 0.0001f)
			{
				if (routeCacheSeconds > 0f)
				{
					TrimCachesIfNeeded();
					RouteCache[instanceID] = new RouteCacheEntry(time, val, val2, result: true);
				}
				return true;
			}
			((Vector3)(ref val4)).Normalize();
			Vector3 centerPoint = character.GetCenterPoint();
			float num2 = Mathf.Clamp(num, radius + 1f, 6f);
			int num3 = Mathf.Clamp(GetAvoidanceSampleCount(), 3, RouteAngles.Length);
			for (int i = 0; i < num3; i++)
			{
				float num4 = RouteAngles[i];
				Vector3 val5 = Quaternion.Euler(0f, num4, 0f) * val4;
				float num5 = ai.Raycast(centerPoint, val5, num2, 0.1f);
				if (num5 >= num2 * 0.9f)
				{
					if (routeCacheSeconds > 0f)
					{
						TrimCachesIfNeeded();
						RouteCache[instanceID] = new RouteCacheEntry(time, val, val2, result: true);
					}
					return true;
				}
			}
			if (routeCacheSeconds > 0f)
			{
				TrimCachesIfNeeded();
				RouteCache[instanceID] = new RouteCacheEntry(time, val, val2, result: false);
			}
			return false;
		}

		private ConfigEntry<T> config<T>(string group, string name, T value, ConfigDescription description, bool synchronizedSetting = true)
		{
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0031: Expected O, but got Unknown
			ConfigDescription val = new ConfigDescription(description.Description + (synchronizedSetting ? " [Synced with Server]" : " [Not Synced with Server]"), description.AcceptableValues, description.Tags);
			ConfigEntry<T> val2 = ((BaseUnityPlugin)this).Config.Bind<T>(group, name, value, val);
			SyncedConfigEntry<T> syncedConfigEntry = ConfigSync.AddConfigEntry<T>(val2);
			syncedConfigEntry.SynchronizedConfig = synchronizedSetting;
			return val2;
		}

		private ConfigEntry<T> config<T>(string group, string name, T value, string description, bool synchronizedSetting = true)
		{
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0019: Expected O, but got Unknown
			return config(group, name, value, new ConfigDescription(description, (AcceptableValueBase)null, Array.Empty<object>()), synchronizedSetting);
		}

		static ServerSyncModTemplatePlugin()
		{
			string configPath = Paths.ConfigPath;
			char directorySeparatorChar = Path.DirectorySeparatorChar;
			MonsterDiveYamlFileFullPath = configPath + directorySeparatorChar + MonsterDiveYamlFileName;
			MonsterDiveYamlLock = new object();
			MonsterDiveYamlDeserializer = new DeserializerBuilder().WithNamingConvention(UnderscoredNamingConvention.Instance).WithDuplicateKeyChecking().Build();
			DefaultMonsterDiveGlobalSettings = new MonsterDiveGlobalSettings(0.25f, 30f, 2f);
			_monsterDiveYamlSync = null;
			_monsterDiveGlobalSettings = DefaultMonsterDiveGlobalSettings;
			_waterEquipmentBlacklist = null;
			_waterStaminaRegenRateMultiplier = null;
			_waterDepthStaminaDrainStart = null;
			_waterDepthStaminaDrainFull = null;
			_waterDepthStaminaDrainMaxMultiplier = null;
			_playerSwimRunSpeedMultiplier = null;
			WaterEquipmentBlacklistLock = new object();
			_lastWaterEquipmentBlacklistRaw = string.Empty;
			_waterEquipmentBlacklistSet = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
			ConfigFileName = "sighsorry.DiveIn.cfg";
			string configPath2 = Paths.ConfigPath;
			directorySeparatorChar = Path.DirectorySeparatorChar;
			ConfigFileFullPath = configPath2 + directorySeparatorChar + ConfigFileName;
			ConnectionError = "";
			ServerSyncModTemplateLogger = Logger.CreateLogSource("DiveIn");
			ConfigSync = new ConfigSync("sighsorry.DiveIn")
			{
				DisplayName = "DiveIn",
				CurrentVersion = "1.0.1",
				MinimumRequiredVersion = "1.0.1"
			};
			_diveAiQuality = null;
			PrefabSetLock = new object();
			_configuredDiveProfilesByPrefabName = new Dictionary<string, ConfiguredDiveProfile>(StringComparer.OrdinalIgnoreCase);
			SteerAngles = new float[8] { 0f, -35f, 35f, -70f, 70f, -120f, 120f, 180f };
			RouteAngles = new float[5] { 0f, -35f, 35f, -70f, 70f };
			RouteCache = new Dictionary<int, RouteCacheEntry>();
			SteerCache = new Dictionary<int, SteerCacheEntry>();
			OriginalDiveFlagsByInstance = new Dictionary<int, OriginalDiveFlags>();
			_serverConfigLocked = null;
		}
	}
	internal static class PlayerDiveUtils
	{
		internal static PlayerDiveController? EnsureLocalDiver()
		{
			Player localPlayer = Player.m_localPlayer;
			if ((Object)(object)localPlayer == (Object)null)
			{
				return null;
			}
			PlayerDiveController playerDiveController = PlayerDiveController.LocalInstance;
			if ((Object)(object)playerDiveController != (Object)null && (Object)(object)playerDiveController.Player == (Object)(object)localPlayer)
			{
				return playerDiveController;
			}
			if (!((Component)localPlayer).TryGetComponent<PlayerDiveController>(ref playerDiveController))
			{
				playerDiveController = ((Component)localPlayer).gameObject.AddComponent<PlayerDiveController>();
			}
			return playerDiveController;
		}

		internal static bool TryGetLocalDiver(Player player, out PlayerDiveController diver)
		{
			if (!IsValidLocalPlayer(player))
			{
				diver = null;
				return false;
			}
			PlayerDiveController playerDiveController = EnsureLocalDiver();
			if ((Object)(object)playerDiveController == (Object)null)
			{
				diver = null;
				return false;
			}
			diver = playerDiveController;
			return true;
		}

		internal static bool IsValidLocalPlayer(Player player)
		{
			return (Object)(object)player != (Object)null && (Object)(object)player == (Object)(object)Player.m_localPlayer;
		}
	}
	internal sealed class PlayerDiveController : MonoBehaviour
	{
		private const float HeadUnderwaterTolerance = 0.01f;

		internal const float DefaultSwimDepth = 1.4f;

		private const float DivingSwimDepth = 2.5f;

		private bool _underwaterMovementActive;

		private float _baseSwimSpeed;

		private int _swimmingUpdateContextDepth;

		private int _swimmingUpdateContextFrame = -1;

		internal static PlayerDiveController? LocalInstance { get; private set; }

		internal Player Player { get; private set; } = null;


		private void Awake()
		{
			Player = ((Component)this).GetComponent<Player>();
			if ((Object)(object)Player == (Object)null)
			{
				Object.Destroy((Object)(object)this);
				return;
			}
			if ((Object)(object)Player != (Object)(object)Player.m_localPlayer)
			{
				Object.Destroy((Object)(object)this);
				return;
			}
			LocalInstance = this;
			((Character)Player).m_swimDepth = 1.4f;
			_baseSwimSpeed = ((Character)Player).m_swimSpeed;
		}

		private void OnDestroy()
		{
			if ((Object)(object)LocalInstance == (Object)(object)this)
			{
				LocalInstance = null;
			}
		}

		internal void DisableUnderwaterMovement()
		{
			_underwaterMovementActive = false;
			ResetSwimDepthToDefault();
			((Character)Player).m_swimSpeed = _baseSwimSpeed;
		}

		internal void ResetSwimDepthIfNotInWater()
		{
			if (!((Character)Player).InWater())
			{
				DisableUnderwaterMovement();
			}
		}

		internal void ResetSwimDepthToDefault()
		{
			((Character)Player).m_swimDepth = 1.4f;
		}

		internal bool CanDive()
		{
			//IL_0058: 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)
			if (ShouldForceDive())
			{
				return true;
			}
			if (!((Character)Player).InWater() || ((Character)Player).IsOnGround() || !((Character)Player).IsSwimming())
			{
				return false;
			}
			float num = default(float);
			Vector3 val = default(Vector3);
			if (((Character)Player).GetGroundHeight(((Component)Player).transform.position, ref num, ref val) && ((Component)Player).transform.position.y - num < 1f)
			{
				return false;
			}
			return true;
		}

		internal bool IsHeadUnderwater()
		{
			//IL_0036: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			float num = (((Object)(object)((Character)Player).m_eye != (Object)null) ? ((Character)Player).m_eye.position.y : ((Component)Player).transform.position.y);
			return ((Character)Player).GetLiquidLevel() - num > 0.01f;
		}

		internal void RefreshUnderwaterMovementState()
		{
			if (!((Character)Player).InWater() || !IsHeadUnderwater())
			{
				_underwaterMovementActive = false;
			}
			else if (IsUnderSurface())
			{
				_underwaterMovementActive = true;
			}
		}

		internal bool ShouldForceSwimming()
		{
			return _underwaterMovementActive && ((Character)Player).InWater() && IsHeadUnderwater();
		}

		internal bool ShouldForceDive()
		{
			return ShouldForceSwimming() && !((Character)Player).IsOnGround();
		}

		internal bool IsUnderSurface()
		{
			return ((Character)Player).m_swimDepth > 1.4f;
		}

		internal bool IsDiving()
		{
			return ((Character)Player).m_swimDepth > 2.5f;
		}

		internal bool IsSurfacing()
		{
			return !IsDiving() && IsUnderSurface();
		}

		internal bool IsIdleInWater()
		{
			//IL_0029: Unknown result type (might be due to invalid IL or missing references)
			//IL_002e: Unknown result type (might be due to invalid IL or missing references)
			int result;
			if (((Character)Player).InWater() && (((Character)Player).IsSwimming() || ShouldForceSwimming()))
			{
				Vector3 velocity = ((Character)Player).GetVelocity();
				result = ((((Vector3)(ref velocity)).magnitude < 1f) ? 1 : 0);
			}
			else
			{
				result = 0;
			}
			return (byte)result != 0;
		}

		internal void BeginSwimmingUpdateContext()
		{
			_swimmingUpdateContextDepth++;
			_swimmingUpdateContextFrame = Time.frameCount;
		}

		internal void EndSwimmingUpdateContext()
		{
			if (_swimmingUpdateContextDepth > 0)
			{
				_swimmingUpdateContextDepth--;
			}
			if (_swimmingUpdateContextDepth == 0)
			{
				_swimmingUpdateContextFrame = -1;
			}
		}

		internal bool IsInSwimmingUpdateContext()
		{
			return _swimmingUpdateContextDepth > 0 && _swimmingUpdateContextFrame == Time.frameCount;
		}

		internal void RegenWaterStamina(float dt)
		{
			float value = ServerSyncModTemplatePlugin._waterStaminaRegenRateMultiplier.Value;
			if (!(value <= 0f))
			{
				float maxStamina = ((Character)Player).GetMaxStamina();
				float num = 1f;
				if (((Character)Player).IsBlocking())
				{
					num *= 0.8f;
				}
				if (((Character)Player).InAttack() || ((Character)Player).InDodge() || ((Character)Player).m_wallRunning || ((Character)Player).IsEncumbered())
				{
					num = 0f;
				}
				float num2 = (Player.m_staminaRegen + (1f - Player.m_stamina / maxStamina) * Player.m_staminaRegen * Player.m_staminaRegenTimeMultiplier) * num;
				float num3 = 1f;
				((Character)Player).m_seman.ModifyStaminaRegen(ref num3);
				num2 *= num3;
				num2 *= value;
				if (Player.m_stamina < maxStamina && Player.m_staminaRegenTimer <= 0f)
				{
					Player.m_stamina = Mathf.Min(maxStamina, Player.m_stamina + num2 * dt * Game.m_staminaRegenRate);
				}
			}
		}

		internal void ApplyDepthScaledSwimDrain(float dt)
		{
			float depthScaledSwimDrainMultiplier = GetDepthScaledSwimDrainMultiplier();
			if (!(depthScaledSwimDrainMultiplier <= 1f))
			{
				float skillFactor = Player.m_skills.GetSkillFactor((SkillType)103);
				float num = Mathf.Lerp(Player.m_swimStaminaDrainMinSkill, Player.m_swimStaminaDrainMaxSkill, skillFactor);
				num += num * ((Character)Player).GetEquipmentSwimStaminaModifier();
				((Character)Player).m_seman.ModifySwimStaminaUsage(num, ref num, true);
				float num2 = depthScaledSwimDrainMultiplier - 1f;
				if (!(num2 <= 0f))
				{
					((Character)Player).UseStamina(dt * num * Game.m_moveStaminaRate * num2);
				}
			}
		}

		internal void UpdateSwimSpeed()
		{
			float num = 1f;
			if (ZInput.GetButton("Run") || ZInput.GetButton("JoyRun"))
			{
				num = Mathf.Max(1f, ServerSyncModTemplatePlugin._playerSwimRunSpeedMultiplier.Value);
			}
			((Character)Player).m_swimSpeed = _baseSwimSpeed * num;
		}

		internal void Dive(float dt, bool ascend, out Vector3? defaultMoveDir)
		{
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			//IL_002f: 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)
			defaultMoveDir = ((Character)Player).m_moveDir;
			((Character)Player).m_moveDir = GetDiveDirection(ascend);
			Vector3 val = CalculateSwimVelocity();
			float num = ((Character)Player).m_swimDepth - val.y * dt;
			((Character)Player).m_swimDepth = Mathf.Max(num, 1.4f);
		}

		private Vector3 GetDiveDirection(bool ascend)
		{
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0004: 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_0017: 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_0053: Unknown result type (might be due to invalid IL or missing references)
			//IL_0054: Unknown result type (might be due to invalid IL or missing references)
			//IL_0055: 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_005d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0062: Unknown result type (might be due to invalid IL or missing references)
			//IL_0066: Unknown result type (might be due to invalid IL or missing references)
			//IL_004c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0051: Unknown result type (might be due to invalid IL or missing references)
			Vector3 val = (ascend ? Vector3.up : Vector3.down);
			Vector3 val2 = ((Character)Player).m_moveDir;
			if (((Vector3)(ref val2)).magnitude < 0.1f)
			{
				float scale = ((ascend && IsSurfacing()) ? 0.6f : 0.05f);
				val2 = GetHorizontalLookDirection(scale);
			}
			Vector3 val3 = val2 + val;
			return ((Vector3)(ref val3)).normalized;
		}

		private Vector3 GetHorizontalLookDirection(float scale)
		{
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			//IL_0028: Unknown result type (might be due to invalid IL or missing references)
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			Vector3 lookDir = ((Character)Player).m_lookDir;
			lookDir.y = 0f;
			((Vector3)(ref lookDir)).Normalize();
			return lookDir * scale;
		}

		private Vector3 CalculateSwimVelocity()
		{
			//IL_0043: Unknown result type (might be due to invalid IL or missing references)
			//IL_0054: Unknown result type (might be due to invalid IL or missing references)
			//IL_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_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_0077: Unknown result type (might be due to invalid IL or missing references)
			//IL_007c: Unknown result type (might be due to invalid IL or missing references)
			//IL_008b: 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_008f: Unknown result type (might be due to invalid IL or missing references)
			float num = ((Character)Player).m_swimSpeed * ((Character)Player).GetAttackSpeedFactorMovement();
			if (((Character)Player).InMinorActionSlowdown())
			{
				num = 0f;
			}
			((Character)Player).m_seman.ApplyStatusEffectSpeedMods(ref num, ((Character)Player).m_moveDir);
			Vector3 val = ((Character)Player).m_moveDir * num;
			val = Vector3.Lerp(((Character)Player).m_currentVel, val, ((Character)Player).m_swimAcceleration);
			((Character)Player).AddPushbackForce(ref val);
			return val;
		}

		private float GetDepthScaledSwimDrainMultiplier()
		{
			float num = Mathf.Max(1f, ServerSyncModTemplatePlugin._waterDepthStaminaDrainMaxMultiplier.Value);
			if (num <= 1f)
			{
				return 1f;
			}
			float num2 = Mathf.Max(0.25f, ServerSyncModTemplatePlugin._waterDepthStaminaDrainFull.Value);
			float num3 = Mathf.Clamp(ServerSyncModTemplatePlugin._waterDepthStaminaDrainStart.Value, 0f, num2);
			if (((Character)Player).m_swimDepth <= num3)
			{
				return 1f;
			}
			float num4 = Mathf.InverseLerp(num3, num2, ((Character)Player).m_swimDepth);
			return Mathf.SmoothStep(1f, num, num4);
		}
	}
	[HarmonyPatch]
	internal static class PlayerDivePatches
	{
		private readonly struct SwimmingUpdateState
		{
			internal PlayerDiveController? Diver { get; }

			internal Vector3? OriginalMoveDir { get; }

			internal SwimmingUpdateState(PlayerDiveController? diver, Vector3? originalMoveDir)
			{
				Diver = diver;
				OriginalMoveDir = originalMoveDir;
			}
		}

		[HarmonyPostfix]
		[HarmonyPatch(typeof(Player), "Awake")]
		private static void PlayerAwakePostfix(Player __instance)
		{
			if ((Object)(object)__instance == (Object)(object)Player.m_localPlayer)
			{
				PlayerDiveUtils.EnsureLocalDiver();
			}
		}

		[HarmonyPrefix]
		[HarmonyPatch(typeof(Character), "UpdateMotion")]
		private static void CharacterUpdateMotionPrefix(Character __instance)
		{
			if ((Object)(object)__instance != (Object)(object)Player.m_localPlayer)
			{
				return;
			}
			PlayerDiveController playerDiveController = PlayerDiveUtils.EnsureLocalDiver();
			if ((Object)(object)playerDiveController == (Object)null)
			{
				return;
			}
			if (!ServerSyncModTemplatePlugin.IsPlayerDiveEnvAllowed())
			{
				playerDiveController.DisableUnderwaterMovement();
				return;
			}
			playerDiveController.ResetSwimDepthIfNotInWater();
			playerDiveController.RefreshUnderwaterMovementState();
			if (playerDiveController.ShouldForceSwimming())
			{
				((Character)playerDiveController.Player).m_lastGroundTouch = 0.3f;
				((Character)playerDiveController.Player).m_swimTimer = 0f;
			}
		}

		[HarmonyPrefix]
		[HarmonyPatch(typeof(Character), "UpdateSwimming")]
		private static void CharacterUpdateSwimmingPrefix(Character __instance, float dt, out SwimmingUpdateState __state)
		{
			if ((Object)(object)__instance != (Object)(object)Player.m_localPlayer)
			{
				__state = new SwimmingUpdateState(null, null);
				return;
			}
			PlayerDiveController playerDiveController = PlayerDiveUtils.EnsureLocalDiver();
			if ((Object)(object)playerDiveController == (Object)null)
			{
				__state = new SwimmingUpdateState(null, null);
				return;
			}
			playerDiveController.BeginSwimmingUpdateContext();
			__state = new SwimmingUpdateState(playerDiveController, null);
			if (!ServerSyncModTemplatePlugin.IsPlayerDiveEnvAllowed())
			{
				playerDiveController.DisableUnderwaterMovement();
				return;
			}
			playerDiveController.UpdateSwimSpeed();
			if ((ZInput.GetButton("Jump") || ZInput.GetButton("JoyJump")) && playerDiveController.IsUnderSurface())
			{
				playerDiveController.Dive(dt, ascend: true, out var defaultMoveDir);
				__state = new SwimmingUpdateState(playerDiveController, defaultMoveDir);
			}
			else if ((ZInput.GetButton("Crouch") || ZInput.GetButton("JoyCrouch")) && playerDiveController.CanDive())
			{
				playerDiveController.Dive(dt, ascend: false, out var defaultMoveDir2);
				__state = new SwimmingUpdateState(playerDiveController, defaultMoveDir2);
			}
			else if ((__instance.IsOnGround() || !playerDiveController.IsDiving()) && !playerDiveController.IsIdleInWater())
			{
				playerDiveController.ResetSwimDepthToDefault();
			}
		}

		[HarmonyPostfix]
		[HarmonyPatch(typeof(Character), "UpdateSwimming")]
		private static void CharacterUpdateSwimmingPostfix(Character __instance, ref SwimmingUpdateState __state)
		{
			//IL_0030: 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)
			__state.Diver?.EndSwimmingUpdateContext();
			if (__state.OriginalMoveDir.HasValue)
			{
				__instance.m_moveDir = __state.OriginalMoveDir.Value;
				__state = default(SwimmingUpdateState);
			}
		}

		[HarmonyPrefix]
		[HarmonyPatch(typeof(Character), "UpdateRotation")]
		private static void CharacterUpdateRotationPrefix(Character __instance, out Quaternion? __state)
		{
			//IL_003e: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)__instance != (Object)(object)Player.m_localPlayer)
			{
				__state = null;
				return;
			}
			PlayerDiveController playerDiveController = PlayerDiveUtils.EnsureLocalDiver();
			if ((Object)(object)playerDiveController != (Object)null && playerDiveController.IsInSwimmingUpdateContext())
			{
				__state = ((Component)__instance).transform.rotation;
			}
			else
			{
				__state = null;
			}
		}

		[HarmonyPostfix]
		[HarmonyPatch(typeof(Character), "UpdateRotation")]
		private static void CharacterUpdateRotationPostfix(Character __instance, float turnSpeed, float dt, ref Quaternion? __state)
		{
			//IL_0032: Unknown result type (might be due to invalid IL or missing references)
			//IL_0038: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b0: 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_0096: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cb: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a8: Unknown result type (might be due to invalid IL or missing references)
			if (__state.HasValue && !((Object)(object)__instance == (Object)null) && !((Object)(object)__instance != (Object)(object)Player.m_localPlayer) && !(((Component)__instance).transform.rotation != __state.Value))
			{
				PlayerDiveController playerDiveController = PlayerDiveUtils.EnsureLocalDiver();
				if (ServerSyncModTemplatePlugin.IsPlayerDiveEnvAllowed() && !((Object)(object)playerDiveController == (Object)null) && playerDiveController.IsInSwimmingUpdateContext() && playerDiveController.IsUnderSurface())
				{
					Player player = playerDiveController.Player;
					Quaternion val = ((((Character)player).AlwaysRotateCamera() || ((Character)player).m_moveDir == Vector3.zero) ? ((Character)player).m_lookYaw : Quaternion.LookRotation(((Character)player).m_moveDir));
					float num = turnSpeed * ((Character)player).GetAttackSpeedFactorRotation();
					((Component)player).transform.rotation = Quaternion.RotateTowards(((Component)player).transform.rotation, val, num * dt);
				}
			}
		}

		[HarmonyPrefix]
		[HarmonyPatch(typeof(Player), "OnSwimming")]
		private static void PlayerOnSwimmingPrefix(Player __instance, Vector3 targetVel, float dt)
		{
			if (!((Object)(object)__instance != (Object)(object)Player.m_localPlayer) && ServerSyncModTemplatePlugin.IsPlayerDiveEnvAllowed())
			{
				PlayerDiveController playerDiveController = PlayerDiveUtils.EnsureLocalDiver();
				if (!((Object)(object)playerDiveController == (Object)null))
				{
					playerDiveController.RegenWaterStamina(dt);
				}
			}
		}

		[HarmonyPostfix]
		[HarmonyPatch(typeof(Player), "OnSwimming")]
		private static void PlayerOnSwimmingPostfix(Player __instance, Vector3 targetVel, float dt)
		{
			if (!((Object)(object)__instance != (Object)(object)Player.m_localPlayer) && !(((Vector3)(ref targetVel)).magnitude < 0.1f) && ServerSyncModTemplatePlugin.IsPlayerDiveEnvAllowed())
			{
				PlayerDiveController playerDiveController = PlayerDiveUtils.EnsureLocalDiver();
				if (!((Object)(object)playerDiveController == (Object)null))
				{
					playerDiveController.ApplyDepthScaledSwimDrain(dt);
				}
			}
		}

		[HarmonyPrefix]
		[HarmonyPatch(typeof(Player), "SetControls")]
		private static void PlayerSetControlsPrefix(Player __instance, ref bool crouch)
		{
			if (!((Object)(object)__instance != (Object)(object)Player.m_localPlayer) && ServerSyncModTemplatePlugin.IsPlayerDiveEnvAllowed() && ((Character)__instance).IsSwimming())
			{
				crouch = false;
			}
		}
	}
	public static class KeyboardExtensions
	{
		[SpecialName]
		public sealed class <G>$8D1D3E80A18AA9715780B6CB7003B2F1
		{
			[SpecialName]
			public static class <M>$895AB635D4D087636CF1C26BA650BA11
			{
			}

			[ExtensionMarker("<M>$895AB635D4D087636CF1C26BA650BA11")]
			public bool IsKeyDown()
			{
				throw new NotSupportedException();
			}

			[ExtensionMarker("<M>$895AB635D4D087636CF1C26BA650BA11")]
			public bool IsKeyHeld()
			{
				throw new NotSupportedException();
			}
		}

		public static bool IsKeyDown(this KeyboardShortcut shortcut)
		{
			//IL_0003: Unknown result type (might be due to invalid IL or missing references)
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			return (int)((KeyboardShortcut)(ref shortcut)).MainKey != 0 && Input.GetKeyDown(((KeyboardShortcut)(ref shortcut)).MainKey) && ((KeyboardShortcut)(ref shortcut)).Modifiers.All((Func<KeyCode, bool>)Input.GetKey);
		}

		public static bool IsKeyHeld(this KeyboardShortcut shortcut)
		{
			//IL_0003: Unknown result type (might be due to invalid IL or missing references)
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			return (int)((KeyboardShortcut)(ref shortcut)).MainKey != 0 && Input.GetKey(((KeyboardShortcut)(ref shortcut)).MainKey) && ((KeyboardShortcut)(ref shortcut)).Modifiers.All((Func<KeyCode, bool>)Input.GetKey);
		}
	}
	public static class ToggleExtentions
	{
		[SpecialName]
		public sealed class <G>$57ABA57BD1CE54EF9BE00DAABFE926BC
		{
			[SpecialName]
			public static class <M>$C02B13F2B6FFC3465B74B38D50860BED
			{
			}

			[ExtensionMarker("<M>$C02B13F2B6FFC3465B74B38D50860BED")]
			public bool IsOn()
			{
				throw new NotSupportedException();
			}

			[ExtensionMarker("<M>$C02B13F2B6FFC3465B74B38D50860BED")]
			public bool IsOff()
			{
				throw new NotSupportedException();
			}
		}

		public static bool IsOn(this ServerSyncModTemplatePlugin.Toggle value)
		{
			return value == ServerSyncModTemplatePlugin.Toggle.On;
		}

		public static bool IsOff(this ServerSyncModTemplatePlugin.Toggle value)
		{
			return value == ServerSyncModTemplatePlugin.Toggle.Off;
		}
	}
	internal static class UnderwaterVisualState
	{
		private sealed class WaterSurfaceState
		{
			public WaterVolume Volume { get; }

			public Transform SurfaceTransform { get; }

			public MeshRenderer? Renderer { get; }

			public Material? Material { get; }

			public Vector3 OriginalPosition { get; }

			public Quaternion OriginalRotation { get; }

			public ShadowCastingMode OriginalShadowCastingMode { get; }

			public float[] OriginalDepth { get; }

			public bool HasOriginalDepth { get; }

			public float OriginalUseGlobalWind { get; }

			public bool HasOriginalUseGlobalWind { get; }

			public bool OverrideApplied { get; set; }

			public WaterSurfaceState(WaterVolume volume)
			{
				//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_0041: Unknown result type (might be due to invalid IL or missing references)
				//IL_0046: Unknown result type (might be due to invalid IL or missing references)
				//IL_0052: Unknown result type (might be due to invalid IL or missing references)
				//IL_0057: Unknown result type (might be due to invalid IL or missing references)
				Volume = volume;
				Transform val = (SurfaceTransform = ((Component)volume.m_waterSurface).transform);
				Renderer = ((Component)volume.m_waterSurface).GetComponent<MeshRenderer>();
				OriginalPosition = val.position;
				OriginalRotation = val.rotation;
				OriginalShadowCastingMode = ((Renderer)volume.m_waterSurface).shadowCastingMode;
				Material = ((Renderer)volume.m_waterSurface).material;
				OriginalDepth = ReadMaterialDepth(Material);
				HasOriginalDepth = (Object)(object)Material != (Object)null && Material.HasProperty(DepthPropertyId);
				OriginalUseGlobalWind = ReadMaterialFloat(Material, UseGlobalWindPropertyId);
				HasOriginalUseGlobalWind = (Object)(object)Material != (Object)null && Material.HasProperty(UseGlobalWindPropertyId);
			}
		}

		private static readonly int DepthPropertyId = Shader.PropertyToID("_depth");

		private static readonly int UseGlobalWindPropertyId = Shader.PropertyToID("_UseGlobalWind");

		private static readonly Dictionary<int, WaterSurfaceState> WaterSurfaceStates = new Dictionary<int, WaterSurfaceState>();

		private static float? _originalMinWaterDistance;

		private static GameCamera? _cameraWithOverride;

		private static bool _cameraOverrideActive;

		private static bool _fogStateCaptured;

		private static bool _fogOverrideActive;

		private static Color _originalFogColor;

		private static float _originalFogDensity;

		internal static void ApplyCameraOverride(GameCamera gameCamera)
		{
			//IL_0079: Unknown result type (might be due to invalid IL or missing references)
			float underwaterCameraMinWaterDistance = ServerSyncModTemplatePlugin.GetUnderwaterCameraMinWaterDistance();
			if (!_originalMinWaterDistance.HasValue)
			{
				_originalMinWaterDistance = gameCamera.m_minWaterDistance;
				_cameraWithOverride = gameCamera;
			}
			if (!_cameraOverrideActive)
			{
				LogVisualState("ApplyCamera", $"camera={DescribeGameObject(((Component)gameCamera).gameObject)}, originalMinWaterDistance={_originalMinWaterDistance:F2}, newMinWaterDistance={underwaterCameraMinWaterDistance:F2}, cameraPos={FormatVector3(((Component)gameCamera).transform.position)}");
				_cameraOverrideActive = true;
			}
			gameCamera.m_minWaterDistance = underwaterCameraMinWaterDistance;
		}

		internal static void ApplyFogOverride(PlayerDiveController diver)
		{
			//IL_000e: 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_006b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0063: Unknown result type (might be due to invalid IL or missing references)
			//IL_0070: Unknown result type (might be due to invalid IL or missing references)
			//IL_007d: Unknown result type (might be due to invalid IL or missing references)
			//IL_008f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0094: Unknown result type (might be due to invalid IL or missing references)
			//IL_0095: 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_0121: Unknown result type (might be due to invalid IL or missing references)
			if (!_fogStateCaptured)
			{
				_originalFogColor = RenderSettings.fogColor;
				_originalFogDensity = RenderSettings.fogDensity;
				_fogStateCaptured = true;
			}
			if ((Object)(object)EnvMan.instance == (Object)null)
			{
				return;
			}
			EnvSetup currentEnvironment = EnvMan.instance.GetCurrentEnvironment();
			if (currentEnvironment != null)
			{
				Color color = ((!EnvMan.IsNight()) ? currentEnvironment.m_fogColorDay : currentEnvironment.m_fogColorNight);
				color.a = 1f;
				color = ChangeColorBrightness(color, ((Character)diver.Player).m_swimDepth * -0.02f);
				RenderSettings.fogColor = color;
				float num = _originalFogDensity + ((Character)diver.Player).m_swimDepth * 0f;
				RenderSettings.fogDensity = Mathf.Clamp(num, 0.05f, 1f);
				if (!_fogOverrideActive)
				{
					LogVisualState("ApplyFog", $"player={DescribeGameObject(((Component)diver.Player).gameObject)}, swimDepth={((Character)diver.Player).m_swimDepth:F2}, originalFogColor={FormatColor(_originalFogColor)}, newFogColor={FormatColor(RenderSettings.fogColor)}, originalFogDensity={_originalFogDensity:F4}, newFogDensity={RenderSettings.fogDensity:F4}, env={DescribeEnvironment()}");
					_fogOverrideActive = true;
				}
			}
		}

		internal static void ApplyWaterSurfaceOverride(WaterVolume volume, float waterLevel)
		{
			//IL_006c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0078: Unknown result type (might be due to invalid IL or missing references)
			//IL_0082: 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_009c: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a1: Unknown result type (might be due to invalid IL or missing references)
			//IL_0111: Unknown result type (might be due to invalid IL or missing references)
			//IL_0129: Unknown result type (might be due to invalid IL or missing references)
			//IL_0137: Unknown result type (might be due to invalid IL or missing references)
			//IL_013c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0140: Unknown result type (might be due to invalid IL or missing references)
			//IL_0158: Unknown result type (might be due to invalid IL or missing references)
			//IL_015d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0161: Unknown result type (might be due to invalid IL or missing references)
			//IL_016f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0182: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)volume.m_waterSurface == (Object)null)
			{
				return;
			}
			int instanceID = ((Object)volume).GetInstanceID();
			if (!WaterSurfaceStates.TryGetValue(instanceID, out WaterSurfaceState value))
			{
				value = new WaterSurfaceState(volume);
				WaterSurfaceStates[instanceID] = value;
			}
			if (!((Object)(object)value.Renderer == (Object)null))
			{
				((Component)volume.m_waterSurface).transform.SetPositionAndRotation(new Vector3(value.OriginalPosition.x, waterLevel, value.OriginalPosition.z), value.OriginalRotation * Quaternion.Euler(180f, 0f, 0f));
				((Renderer)volume.m_waterSurface).shadowCastingMode = (ShadowCastingMode)2;
				ApplyWaterMaterialOverride(value);
				if (!value.OverrideApplied)
				{
					object[] obj = new object[13]
					{
						DescribeGameObject(((Component)volume).gameObject),
						DescribeGameObject(((Component)volume.m_waterSurface).gameObject),
						waterLevel,
						FormatVector3(value.OriginalPosition),
						FormatVector3(((Component)volume.m_waterSurface).transform.position),
						null,
						null,
						null,
						null,
						null,
						null,
						null,
						null
					};
					Quaternion val = value.OriginalRotation;
					obj[5] = FormatEuler(((Quaternion)(ref val)).eulerAngles);
					val = ((Component)volume.m_waterSurface).transform.rotation;
					obj[6] = FormatEuler(((Quaternion)(ref val)).eulerAngles);
					obj[7] = value.OriginalShadowCastingMode;
					obj[8] = ((Renderer)volume.m_waterSurface).shadowCastingMode;
					obj[9] = FormatFloatArray(value.OriginalDepth);
					obj[10] = FormatFloatArray(ReadMaterialDepth(value.Material));
					obj[11] = FormatMaterialFloat(value.HasOriginalUseGlobalWind ? new float?(value.OriginalUseGlobalWind) : null);
					obj[12] = FormatMaterialFloat(ReadMaterialFloatOrNull(value.Material, UseGlobalWindPropertyId));
					LogVisualState("ApplyWaterSurface", string.Format("volume={0}, waterSurface={1}, waterLevel={2:F2}, originalPos={3}, appliedPos={4}, originalEuler={5}, appliedEuler={6}, originalShadow={7}, appliedShadow={8}, originalDepth={9}, appliedDepth={10}, originalUseGlobalWind={11}, appliedUseGlobalWind={12}", obj));
					value.OverrideApplied = true;
				}
			}
		}

		internal static void ResetWaterSurface(WaterVolume? volume, string reason = "")
		{
			if (!((Object)(object)volume == (Object)null) && WaterSurfaceStates.TryGetValue(((Object)volume).GetInstanceID(), out WaterSurfaceState value))
			{
				RestoreWaterSurfaceState(value, reason);
				WaterSurfaceStates.Remove(((Object)volume).GetInstanceID());
			}
		}

		internal static void ResetAll(string reason = "")
		{
			ResetCameraAndFog(reason);
			ResetTrackedWaterSurfacesExcept(null, reason);
		}

		internal static void ResetCameraAndFog(string reason = "")
		{
			ResetCamera(reason);
			ResetFog(reason);
		}

		internal static void ResetCamera(string reason = "")
		{
			GameCamera val = (GameCamera)(((Object)(object)_cameraWithOverride != (Object)null) ? ((object)_cameraWithOverride) : ((object)GameCamera.instance));
			float num = (((Object)(object)val != (Object)null) ? val.m_minWaterDistance : float.NaN);
			if ((Object)(object)val != (Object)null && _originalMinWaterDistance.HasValue)
			{
				val.m_minWaterDistance = _originalMinWaterDistance.Value;
			}
			if (_cameraOverrideActive)
			{
				LogVisualState("ResetCamera", $"reason={reason}, camera={DescribeGameObject(((Object)(object)val != (Object)null) ? ((Component)val).gameObject : null)}, currentMinWaterDistance={num:F2}, restoredMinWaterDistance={_originalMinWaterDistance.GetValueOrDefault(float.NaN):F2}");
			}
			_originalMinWaterDistance = null;
			_cameraWithOverride = null;
			_cameraOverrideActive = false;
		}

		internal static void ResetFog(string reason = "")
		{
			//IL_007a: 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_0041: Unknown result type (might be due to invalid IL or missing references)
			bool fogStateCaptured = _fogStateCaptured;
			if (_fogStateCaptured)
			{
				if (_fogOverrideActive)
				{
					LogVisualState("ResetFog", $"reason={reason}, currentFogColor={FormatColor(RenderSettings.fogColor)}, restoredFogColor={FormatColor(_originalFogColor)}, currentFogDensity={RenderSettings.fogDensity:F4}, restoredFogDensity={_originalFogDensity:F4}, env={DescribeEnvironment()}");
				}
				RenderSettings.fogColor = _originalFogColor;
				RenderSettings.fogDensity = _originalFogDensity;
				_fogStateCaptured = false;
			}
			_fogOverrideActive = false;
			if (fogStateCaptured)
			{
				RefreshEnvironment();
			}
		}

		private static void ResetTrackedWaterSurfacesExcept(int? activeVolumeId, string reason = "")
		{
			if (WaterSurfaceStates.Count == 0)
			{
				return;
			}
			List<int> list = WaterSurfaceStates.Keys.ToList();
			foreach (int item in list)
			{
				if (!activeVolumeId.HasValue || item != activeVolumeId.Value)
				{
					RestoreWaterSurfaceState(WaterSurfaceStates[item], reason);
					WaterSurfaceStates.Remove(item);
				}
			}
		}

		private static void RestoreWaterSurfaceState(WaterSurfaceState state, string reason)
		{
			//IL_0177: Unknown result type (might be due to invalid IL or missing references)
			//IL_017d: 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_009f: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ba: 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_00cd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e8: 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_01a7: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)state.Volume == (Object)null) && !((Object)(object)state.Volume.m_waterSurface == (Object)null) && !((Object)(object)state.SurfaceTransform == (Object)null))
			{
				if (state.OverrideApplied)
				{
					object[] obj = new object[13]
					{
						reason,
						DescribeGameObject(((Component)state.Volume).gameObject),
						DescribeGameObject(((Component)state.Volume.m_waterSurface).gameObject),
						FormatVector3(state.SurfaceTransform.position),
						FormatVector3(state.OriginalPosition),
						null,
						null,
						null,
						null,
						null,
						null,
						null,
						null
					};
					Quaternion val = state.SurfaceTransform.rotation;
					obj[5] = FormatEuler(((Quaternion)(ref val)).eulerAngles);
					val = state.OriginalRotation;
					obj[6] = FormatEuler(((Quaternion)(ref val)).eulerAngles);
					obj[7] = ((Renderer)state.Volume.m_waterSurface).shadowCastingMode;
					obj[8] = state.OriginalShadowCastingMode;
					obj[9] = FormatFloatArray(ReadMaterialDepth(state.Material));
					obj[10] = FormatFloatArray(state.OriginalDepth);
					obj[11] = FormatMaterialFloat(ReadMaterialFloatOrNull(state.Material, UseGlobalWindPropertyId));
					obj[12] = FormatMaterialFloat(state.HasOriginalUseGlobalWind ? new float?(state.OriginalUseGlobalWind) : null);
					LogVisualState("ResetWaterSurface", string.Format("reason={0}, volume={1}, waterSurface={2}, currentPos={3}, restoredPos={4}, currentEuler={5}, restoredEuler={6}, currentShadow={7}, restoredShadow={8}, currentDepth={9}, restoredDepth={10}, currentUseGlobalWind={11}, restoredUseGlobalWind={12}", obj));
				}
				state.SurfaceTransform.SetPositionAndRotation(state.OriginalPosition, state.OriginalRotation);
				if ((Object)(object)state.Renderer != (Object)null)
				{
					((Renderer)state.Volume.m_waterSurface).shadowCastingMode = state.OriginalShadowCastingMode;
				}
				RestoreWaterMaterialState(state);
				state.OverrideApplied = false;
			}
		}

		private static void ApplyWaterMaterialOverride(WaterSurfaceState state)
		{
			Material material = state.Material;
			if ((Object)(object)material == (Object)null)
			{
				return;
			}
			if (material.HasProperty(DepthPropertyId))
			{
				if (state.Volume.m_forceDepth >= 0f)
				{
					material.SetFloatArray(DepthPropertyId, new float[4]
					{
						state.Volume.m_forceDepth,
						state.Volume.m_forceDepth,
						state.Volume.m_forceDepth,
						state.Volume.m_forceDepth
					});
				}
				else
				{
					material.SetFloatArray(DepthPropertyId, state.Volume.m_normalizedDepth);
				}
			}
			if (material.HasProperty(UseGlobalWindPropertyId))
			{
				material.SetFloat(UseGlobalWindPropertyId, state.Volume.m_useGlobalWind ? 1f : 0f);
			}
		}

		private static void RestoreWaterMaterialState(WaterSurfaceState state)
		{
			Material material = state.Material;
			if (!((Object)(object)material == (Object)null))
			{
				if (state.HasOriginalDepth)
				{
					material.SetFloatArray(DepthPropertyId, state.OriginalDepth);
				}
				if (state.HasOriginalUseG