Decompiled source of SwimmingReworked v1.0.5

SwimmingReworked.dll

Decompiled a week ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using System.Security.Permissions;
using BepInEx;
using BepInEx.Configuration;
using HarmonyLib;
using Jotunn.Entities;
using Jotunn.Extensions;
using Jotunn.Managers;
using Jotunn.Utils;
using SwimmingReworked.Effects;
using UnityEngine;
using UnityEngine.Rendering;
using UnityEngine.UI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: AssemblyTitle("SwimmingReworked")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("SwimmingReworked")]
[assembly: AssemblyCopyright("Copyright ©  2021")]
[assembly: AssemblyTrademark("")]
[assembly: ComVisible(false)]
[assembly: Guid("e3243d22-4307-4008-ba36-9f326008cde5")]
[assembly: AssemblyFileVersion("1.0.5")]
[assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.0.5.0")]
namespace SwimmingReworked
{
	internal class BreathHud : MonoBehaviour
	{
		private GameObject _root;

		private RectTransform _container;

		private readonly List<Image> _bubbles = new List<Image>();

		private Sprite _bubbleSprite;

		private Text _breathText;

		private const int BubbleCount = 10;

		private float _cachedOffsetX;

		private float _cachedOffsetY;

		private float _cachedScale;

		private bool _cachedShowLabels;

		private void Awake()
		{
			CreateHud();
		}

		private void Update()
		{
			Player localPlayer = Player.m_localPlayer;
			if ((Object)(object)localPlayer == (Object)null || (Object)(object)Camera.main == (Object)null)
			{
				SetVisible(visible: false);
				return;
			}
			CheckConfigChanges();
			float currentBreath = SwimAPI.GetCurrentBreath(localPlayer);
			float maxBreath = SwimAPI.GetMaxBreath(localPlayer);
			float percent = Mathf.Clamp01(SwimAPI.GetBreathPercent(localPlayer));
			bool flag = WaterHelper.IsBodyInWater(localPlayer) || currentBreath < maxBreath - 0.01f;
			SetVisible(flag);
			if (flag)
			{
				UpdateBubbles(percent);
				if ((Object)(object)_breathText != (Object)null && ((Component)_breathText).gameObject.activeSelf)
				{
					_breathText.text = $"{currentBreath:F0}/{maxBreath:F0}";
				}
			}
		}

		private void CheckConfigChanges()
		{
			//IL_009e: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a4: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)SwimmingReworked.Instance == (Object)null)
			{
				return;
			}
			float value = SwimmingReworked.BreathHudOffsetX.Value;
			float value2 = SwimmingReworked.BreathHudOffsetY.Value;
			float value3 = SwimmingReworked.BreathHudScale.Value;
			bool value4 = SwimmingReworked.BreathHudShowLabels.Value;
			if (!Mathf.Approximately(_cachedOffsetX, value) || !Mathf.Approximately(_cachedOffsetY, value2))
			{
				UpdateContainerPosition(value, value2);
				_cachedOffsetX = value;
				_cachedOffsetY = value2;
			}
			if (!Mathf.Approximately(_cachedScale, value3))
			{
				((Transform)_container).localScale = Vector3.one * value3;
				_cachedScale = value3;
			}
			if (_cachedShowLabels != value4)
			{
				if ((Object)(object)_breathText != (Object)null)
				{
					((Component)_breathText).gameObject.SetActive(value4);
				}
				_cachedShowLabels = value4;
			}
		}

		private void UpdateContainerPosition(float offsetX, float offsetY)
		{
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0047: 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)
			_container.anchorMin = new Vector2(1f, 0.5f);
			_container.anchorMax = new Vector2(1f, 0.5f);
			_container.pivot = new Vector2(1f, 0.5f);
			_container.anchoredPosition = new Vector2(offsetX, offsetY);
		}

		private void UpdateBubbles(float percent)
		{
			//IL_009d: 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)
			int num = Mathf.CeilToInt(percent * 10f);
			for (int i = 0; i < _bubbles.Count; i++)
			{
				Image val = _bubbles[i];
				if (((Behaviour)val).enabled = i < num)
				{
					float num2 = (float)i / 9f;
					float num3 = -60f + num2 * 120f + Mathf.PingPong(Time.time * 8f + (float)i * 0.5f, 15f);
					float num4 = Mathf.Sin(Time.time * 2f + (float)i) * 5f;
					RectTransform rectTransform = ((Graphic)val).rectTransform;
					rectTransform.anchoredPosition = new Vector2(num4, num3);
					float num5 = 0.45f + 0.45f * Mathf.PingPong(Time.time * 1.2f + (float)i * 0.3f, 1f);
					((Graphic)val).color = new Color(0.8f, 0.92f, 1f, num5);
				}
			}
		}

		private void SetVisible(bool visible)
		{
			if ((Object)(object)_root != (Object)null && _root.activeSelf != visible)
			{
				_root.SetActive(visible);
			}
		}

		private void CreateHud()
		{
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_0011: Expected O, but got Unknown
			//IL_005c: 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_007e: Expected O, but got Unknown
			//IL_00b2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f7: 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_0148: Expected O, but got Unknown
			//IL_0171: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b2: 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_01ed: Expected O, but got Unknown
			//IL_0259: Unknown result type (might be due to invalid IL or missing references)
			//IL_027d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0294: Unknown result type (might be due to invalid IL or missing references)
			_root = new GameObject("BreathHud");
			Object.DontDestroyOnLoad((Object)(object)_root);
			Canvas val = _root.AddComponent<Canvas>();
			val.renderMode = (RenderMode)0;
			val.sortingOrder = 5000;
			CanvasScaler val2 = _root.AddComponent<CanvasScaler>();
			val2.uiScaleMode = (ScaleMode)1;
			val2.referenceResolution = new Vector2(1920f, 1080f);
			_root.AddComponent<GraphicRaycaster>();
			GameObject val3 = new GameObject("Container");
			val3.transform.SetParent(_root.transform, false);
			_container = val3.AddComponent<RectTransform>();
			_container.sizeDelta = new Vector2(80f, 200f);
			float value = SwimmingReworked.BreathHudOffsetX.Value;
			float value2 = SwimmingReworked.BreathHudOffsetY.Value;
			float value3 = SwimmingReworked.BreathHudScale.Value;
			UpdateContainerPosition(value, value2);
			((Transform)_container).localScale = Vector3.one * value3;
			_cachedOffsetX = value;
			_cachedOffsetY = value2;
			_cachedScale = value3;
			_bubbleSprite = CreateBubbleSprite(64);
			for (int i = 0; i < 10; i++)
			{
				GameObject val4 = new GameObject($"Bubble_{i}");
				val4.transform.SetParent((Transform)(object)_container, false);
				RectTransform val5 = val4.AddComponent<RectTransform>();
				val5.sizeDelta = new Vector2(12f, 12f);
				Image val6 = val4.AddComponent<Image>();
				val6.sprite = _bubbleSprite;
				val6.preserveAspect = true;
				((Graphic)val6).color = new Color(0.8f, 0.92f, 1f, 0.8f);
				_bubbles.Add(val6);
			}
			GameObject val7 = new GameObject("BreathText");
			val7.transform.SetParent((Transform)(object)_container, false);
			_breathText = val7.AddComponent<Text>();
			_breathText.font = Resources.GetBuiltinResource<Font>("Arial.ttf");
			_breathText.fontSize = 12;
			_breathText.alignment = (TextAnchor)5;
			((Graphic)_breathText).color = new Color(0.8f, 0.92f, 1f, 0.8f);
			RectTransform rectTransform = ((Graphic)_breathText).rectTransform;
			rectTransform.sizeDelta = new Vector2(70f, 20f);
			rectTransform.anchoredPosition = new Vector2(-35f, -110f);
			((Component)_breathText).gameObject.SetActive(SwimmingReworked.BreathHudShowLabels.Value);
			_cachedShowLabels = SwimmingReworked.BreathHudShowLabels.Value;
			SetVisible(visible: false);
		}

		private Sprite CreateBubbleSprite(int size)
		{
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: Expected O, but got Unknown
			//IL_0049: 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_0190: Unknown result type (might be due to invalid IL or missing references)
			//IL_019f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0095: Unknown result type (might be due to invalid IL or missing references)
			//IL_0097: 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_00f8: 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_0148: Unknown result type (might be due to invalid IL or missing references)
			//IL_011b: Unknown result type (might be due to invalid IL or missing references)
			//IL_012e: Unknown result type (might be due to invalid IL or missing references)
			//IL_013b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0140: Unknown result type (might be due to invalid IL or missing references)
			Texture2D val = new Texture2D(size, size, (TextureFormat)4, false);
			((Texture)val).filterMode = (FilterMode)1;
			((Texture)val).wrapMode = (TextureWrapMode)1;
			Vector2 val2 = default(Vector2);
			((Vector2)(ref val2))..ctor((float)(size - 1) * 0.5f, (float)(size - 1) * 0.5f);
			float num = (float)size * 0.42f;
			float num2 = num * 0.72f;
			Vector2 val3 = default(Vector2);
			((Vector2)(ref val3))..ctor(val2.x - (float)size * 0.12f, val2.y + (float)size * 0.12f);
			float num3 = (float)size * 0.12f;
			Vector2 val4 = default(Vector2);
			Color val5 = default(Color);
			for (int i = 0; i < size; i++)
			{
				for (int j = 0; j < size; j++)
				{
					((Vector2)(ref val4))..ctor((float)j, (float)i);
					float num4 = Vector2.Distance(val4, val2);
					if (num4 > num)
					{
						val.SetPixel(j, i, Color.clear);
						continue;
					}
					float num5 = Mathf.InverseLerp(num, num2, num4);
					float num6 = Mathf.Lerp(0.15f, 0.95f, num5);
					((Color)(ref val5))..ctor(0.82f, 0.93f, 1f, num6);
					float num7 = Vector2.Distance(val4, val3);
					if (num7 < num3)
					{
						float num8 = 1f - num7 / num3;
						val5 = Color.Lerp(val5, new Color(1f, 1f, 1f, num6), num8 * 0.65f);
					}
					val.SetPixel(j, i, val5);
				}
			}
			val.Apply();
			return Sprite.Create(val, new Rect(0f, 0f, (float)size, (float)size), new Vector2(0.5f, 0.5f), 100f);
		}
	}
	internal static class InputHelper
	{
		public static bool GetRun()
		{
			return ZInput.GetButton("Run");
		}

		public static bool GetJump()
		{
			return ZInput.GetButton("Jump");
		}

		public static bool GetCrouch()
		{
			return ZInput.GetButton("Crouch");
		}

		public static float GetHorizontal()
		{
			return Input.GetAxisRaw("Horizontal");
		}

		public static float GetVertical()
		{
			return Input.GetAxisRaw("Vertical");
		}

		public static float GetDiveVertical()
		{
			float num = 0f;
			if (GetJump())
			{
				num += 1f;
			}
			if (GetCrouch())
			{
				num -= 1f;
			}
			return num;
		}
	}
	internal static class RuntimeFlags
	{
		public static bool AllowStaminaUseFromSwimSprint;
	}
	public static class SwimAPI
	{
		public static event Action<Player> OnEnterWater;

		public static event Action<Player> OnExitWater;

		public static event Action<Player> OnHeadUnderwater;

		public static event Action<Player> OnHeadAboveWater;

		public static event Action<Player> OnOutOfBreath;

		public static float GetBreathPercent(Player player)
		{
			if ((Object)(object)player == (Object)null)
			{
				return 1f;
			}
			SwimState swimState = SwimStateManager.Get(player);
			float maxBreath = GetMaxBreath(player);
			if (maxBreath <= 0f)
			{
				return 0f;
			}
			return Mathf.Clamp01(swimState.Breath / maxBreath);
		}

		public static bool IsUnderwater(Player player)
		{
			if ((Object)(object)player == (Object)null)
			{
				return false;
			}
			return WaterHelper.IsHeadUnderwater(player);
		}

		public static bool IsSwimming(Player player)
		{
			if ((Object)(object)player == (Object)null)
			{
				return false;
			}
			return WaterHelper.IsBodyInWater(player);
		}

		public static float GetCurrentBreath(Player player)
		{
			if ((Object)(object)player == (Object)null)
			{
				return 0f;
			}
			return SwimStateManager.Get(player).Breath;
		}

		public static float GetBaseMaxBreath(Player player)
		{
			if ((Object)(object)player == (Object)null)
			{
				return SwimmingReworked.MaxBreathSeconds.Value;
			}
			float skillFactor = ((Character)player).GetSkillFactor((SkillType)103);
			return SwimmingReworked.MaxBreathSeconds.Value + SwimmingReworked.MaxBreathBonusAtSkill100.Value * skillFactor;
		}

		public static float GetMaxBreath(Player player)
		{
			if ((Object)(object)player == (Object)null)
			{
				return SwimmingReworked.MaxBreathSeconds.Value;
			}
			SwimState swimState = SwimStateManager.Get(player);
			return GetBaseMaxBreath(player) + swimState.ExtraBreathBonus;
		}

		public static bool IsOutOfBreath(Player player)
		{
			return GetCurrentBreath(player) <= 0f;
		}

		public static float GetSwimSkillFactor(Player player)
		{
			if ((Object)(object)player == (Object)null)
			{
				return 0f;
			}
			return ((Character)player).GetSkillFactor((SkillType)103);
		}

		public static bool HasInfiniteBreath(Player player)
		{
			if ((Object)(object)player == (Object)null)
			{
				return false;
			}
			SwimState swimState = SwimStateManager.Get(player);
			return Time.time < swimState.InfiniteBreathUntil;
		}

		public static float GetExternalSwimSpeedMultiplier(Player player)
		{
			if ((Object)(object)player == (Object)null)
			{
				return 1f;
			}
			SwimState swimState = SwimStateManager.Get(player);
			if (Time.time >= swimState.SwimSpeedMultiplierUntil)
			{
				swimState.SwimSpeedMultiplier = 1f;
				return 1f;
			}
			return swimState.SwimSpeedMultiplier;
		}

		public static void RestoreBreath(Player player, float amount)
		{
			if (!((Object)(object)player == (Object)null) && !(amount <= 0f))
			{
				SwimState swimState = SwimStateManager.Get(player);
				swimState.Breath = Mathf.Min(GetMaxBreath(player), swimState.Breath + amount);
			}
		}

		public static void DrainBreath(Player player, float amount)
		{
			if (!((Object)(object)player == (Object)null) && !(amount <= 0f))
			{
				SwimState swimState = SwimStateManager.Get(player);
				swimState.Breath = Mathf.Max(0f, swimState.Breath - amount);
			}
		}

		public static void SetInfiniteBreath(Player player, float duration)
		{
			if (!((Object)(object)player == (Object)null) && !(duration <= 0f))
			{
				SwimState swimState = SwimStateManager.Get(player);
				swimState.InfiniteBreathUntil = Mathf.Max(swimState.InfiniteBreathUntil, Time.time + duration);
				swimState.Breath = GetMaxBreath(player);
			}
		}

		public static void AddBreathBonus(Player player, float bonusSeconds)
		{
			if (!((Object)(object)player == (Object)null))
			{
				SwimState swimState = SwimStateManager.Get(player);
				swimState.ExtraBreathBonus = Mathf.Max(0f, swimState.ExtraBreathBonus + bonusSeconds);
				swimState.Breath = Mathf.Min(swimState.Breath, GetMaxBreath(player));
			}
		}

		public static void SetBreathBonus(Player player, float bonusSeconds)
		{
			if (!((Object)(object)player == (Object)null))
			{
				SwimState swimState = SwimStateManager.Get(player);
				swimState.ExtraBreathBonus = Mathf.Max(0f, bonusSeconds);
				swimState.Breath = Mathf.Min(swimState.Breath, GetMaxBreath(player));
			}
		}

		public static void AddSwimSpeedBonus(Player player, float multiplier, float duration)
		{
			if (!((Object)(object)player == (Object)null) && !(multiplier <= 0f) && !(duration <= 0f))
			{
				SwimState swimState = SwimStateManager.Get(player);
				swimState.SwimSpeedMultiplier = Mathf.Max(swimState.SwimSpeedMultiplier, multiplier);
				swimState.SwimSpeedMultiplierUntil = Mathf.Max(swimState.SwimSpeedMultiplierUntil, Time.time + duration);
			}
		}

		internal static void UpdateEvents(Player player)
		{
			if (!((Object)(object)player == (Object)null))
			{
				SwimState swimState = SwimStateManager.Get(player);
				bool flag = IsSwimming(player);
				bool flag2 = IsUnderwater(player);
				bool flag3 = IsOutOfBreath(player);
				if (flag && !swimState.WasSwimming)
				{
					SwimAPI.OnEnterWater?.Invoke(player);
				}
				else if (!flag && swimState.WasSwimming)
				{
					SwimAPI.OnExitWater?.Invoke(player);
				}
				if (flag2 && !swimState.WasHeadUnderwater)
				{
					SwimAPI.OnHeadUnderwater?.Invoke(player);
				}
				else if (!flag2 && swimState.WasHeadUnderwater)
				{
					SwimAPI.OnHeadAboveWater?.Invoke(player);
				}
				if (flag3 && !swimState.WasOutOfBreath)
				{
					SwimAPI.OnOutOfBreath?.Invoke(player);
				}
				swimState.WasSwimming = flag;
				swimState.WasHeadUnderwater = flag2;
				swimState.WasOutOfBreath = flag3;
			}
		}
	}
	[BepInPlugin("dzk.SwimmingReworked", "SwimmingReworked", "1.0.3")]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[SynchronizationMode(/*Could not decode attribute arguments.*/)]
	internal class SwimmingReworked : BaseUnityPlugin
	{
		public const string PluginGUID = "dzk.SwimmingReworked";

		public const string PluginName = "SwimmingReworked";

		public const string PluginVersion = "1.0.5";

		internal static SwimmingReworked Instance;

		internal static Harmony Harmony;

		public static CustomLocalization Localization = LocalizationManager.Instance.GetLocalization();

		internal static ConfigEntry<bool> EnableMod;

		internal static ConfigEntry<float> MaxBreathSeconds;

		internal static ConfigEntry<float> MaxBreathBonusAtSkill100;

		internal static ConfigEntry<float> BreathRecoveryPerSecond;

		internal static ConfigEntry<float> SuffocationDamagePercentPerTick;

		internal static ConfigEntry<float> SuffocationTickInterval;

		internal static ConfigEntry<float> SprintSwimMultiplier;

		internal static ConfigEntry<float> SprintStaminaPerSecond;

		internal static ConfigEntry<float> VerticalSwimSpeed;

		internal static ConfigEntry<float> MinSwimSpeed;

		internal static ConfigEntry<float> MaxSwimSpeedAtSkill100;

		internal static ConfigEntry<bool> AllowUnderwaterSprint;

		internal static ConfigEntry<bool> DisableVanillaSwimStaminaDrain;

		internal static ConfigEntry<bool> DisableVanillaDrowningFromStamina;

		internal static ConfigEntry<float> BaseUnderwaterStaminaRegenPerSecond;

		internal static ConfigEntry<float> MaxSwimSkillBonusStaminaRegenPerSecond;

		internal static ConfigEntry<bool> DebugLogging;

		private ConfigFileWatcher _configWatcher;

		internal static ConfigEntry<float> BreathHudOffsetX;

		internal static ConfigEntry<float> BreathHudOffsetY;

		internal static ConfigEntry<float> BreathHudScale;

		internal static ConfigEntry<bool> BreathHudShowLabels;

		private void Awake()
		{
			//IL_0056: Unknown result type (might be due to invalid IL or missing references)
			//IL_0060: Expected O, but got Unknown
			Instance = this;
			CreateConfig();
			CreateConfigWatcher();
			SynchronizationManager.OnConfigurationSynchronized += OnConfigurationSynchronized;
			SynchronizationManager.OnAdminStatusChanged += OnAdminStatusChanged;
			((Component)this).gameObject.AddComponent<BreathHud>();
			((Component)this).gameObject.AddComponent<DiveImmersionEffect>();
			Harmony = new Harmony("dzk.SwimmingReworked");
			Harmony.PatchAll();
			((BaseUnityPlugin)this).Logger.LogInfo((object)"SwimmingReworked 1.0.5 loaded");
		}

		private void OnDestroy()
		{
			SynchronizationManager.OnConfigurationSynchronized -= OnConfigurationSynchronized;
			SynchronizationManager.OnAdminStatusChanged -= OnAdminStatusChanged;
			if (_configWatcher != null)
			{
				_configWatcher = null;
			}
		}

		private void CreateConfig()
		{
			//IL_00aa: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b4: Expected O, but got Unknown
			((BaseUnityPlugin)this).Config.SaveOnConfigSet = false;
			BreathHudOffsetX = ((BaseUnityPlugin)this).Config.Bind<float>("Breath HUD", "OffsetX", -40f, "Horizontal offset from right edge of screen (negative = left).");
			BreathHudOffsetY = ((BaseUnityPlugin)this).Config.Bind<float>("Breath HUD", "OffsetY", 0f, "Vertical offset from center of screen.");
			BreathHudScale = ((BaseUnityPlugin)this).Config.Bind<float>("Breath HUD", "Scale", 1f, "Scale multiplier for the breath indicator.");
			AcceptableValueBase val = (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.3f, 3f);
			BreathHudScale = ((BaseUnityPlugin)this).Config.Bind<float>("Breath HUD", "Scale", 1f, new ConfigDescription("Scale multiplier for the breath indicator.", val, Array.Empty<object>()));
			BreathHudShowLabels = ((BaseUnityPlugin)this).Config.Bind<bool>("Breath HUD", "ShowLabels", false, "Show numeric breath value next to bubbles.");
			EnableMod = ConfigFileExtensions.BindConfig<bool>(((BaseUnityPlugin)this).Config, "General", "EnableMod", true, "Enable or disable the mod.", true, (int?)null, (AcceptableValueBase)null, (Action<ConfigEntryBase>)null, (ConfigurationManagerAttributes)null);
			ConfigFile config = ((BaseUnityPlugin)this).Config;
			AcceptableValueBase val2 = (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 600f);
			MaxBreathSeconds = ConfigFileExtensions.BindConfig<float>(config, "Breath", "MaxBreathSeconds", 30f, "Maximum underwater breath at Swim skill 0.", true, (int?)null, val2, (Action<ConfigEntryBase>)null, (ConfigurationManagerAttributes)null);
			ConfigFile config2 = ((BaseUnityPlugin)this).Config;
			val2 = (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 600f);
			MaxBreathBonusAtSkill100 = ConfigFileExtensions.BindConfig<float>(config2, "Breath", "MaxBreathBonusAtSkill100", 150f, "Additional breath time gained at Swim skill 100.", true, (int?)null, val2, (Action<ConfigEntryBase>)null, (ConfigurationManagerAttributes)null);
			ConfigFile config3 = ((BaseUnityPlugin)this).Config;
			val2 = (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 300f);
			BreathRecoveryPerSecond = ConfigFileExtensions.BindConfig<float>(config3, "Breath", "BreathRecoveryPerSecond", 30f, "Breath recovered per second when not underwater.", true, (int?)null, val2, (Action<ConfigEntryBase>)null, (ConfigurationManagerAttributes)null);
			ConfigFile config4 = ((BaseUnityPlugin)this).Config;
			val2 = (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 100f);
			SuffocationDamagePercentPerTick = ConfigFileExtensions.BindConfig<float>(config4, "Breath", "SuffocationDamagePercentPerTick", 10f, "Percent of max health lost each suffocation tick when breath reaches 0.", true, (int?)null, val2, (Action<ConfigEntryBase>)null, (ConfigurationManagerAttributes)null);
			ConfigFile config5 = ((BaseUnityPlugin)this).Config;
			val2 = (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.1f, 30f);
			SuffocationTickInterval = ConfigFileExtensions.BindConfig<float>(config5, "Breath", "SuffocationTickInterval", 2f, "Seconds between suffocation damage ticks when breath reaches 0.", true, (int?)null, val2, (Action<ConfigEntryBase>)null, (ConfigurationManagerAttributes)null);
			ConfigFile config6 = ((BaseUnityPlugin)this).Config;
			val2 = (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 5f);
			SprintSwimMultiplier = ConfigFileExtensions.BindConfig<float>(config6, "Movement", "SprintSwimMultiplier", 1.75f, "Sprint speed multiplier while swimming.", true, (int?)null, val2, (Action<ConfigEntryBase>)null, (ConfigurationManagerAttributes)null);
			ConfigFile config7 = ((BaseUnityPlugin)this).Config;
			val2 = (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 100f);
			SprintStaminaPerSecond = ConfigFileExtensions.BindConfig<float>(config7, "Movement", "SprintStaminaPerSecond", 8f, "Stamina drained per second while sprint swimming.", true, (int?)null, val2, (Action<ConfigEntryBase>)null, (ConfigurationManagerAttributes)null);
			ConfigFile config8 = ((BaseUnityPlugin)this).Config;
			val2 = (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.1f, 20f);
			VerticalSwimSpeed = ConfigFileExtensions.BindConfig<float>(config8, "Movement", "VerticalSwimSpeed", 3f, "Vertical swimming speed while diving.", true, (int?)null, val2, (Action<ConfigEntryBase>)null, (ConfigurationManagerAttributes)null);
			AllowUnderwaterSprint = ConfigFileExtensions.BindConfig<bool>(((BaseUnityPlugin)this).Config, "Movement", "AllowUnderwaterSprint", true, "Allow sprinting underwater.", true, (int?)null, (AcceptableValueBase)null, (Action<ConfigEntryBase>)null, (ConfigurationManagerAttributes)null);
			DisableVanillaSwimStaminaDrain = ConfigFileExtensions.BindConfig<bool>(((BaseUnityPlugin)this).Config, "Vanilla Overrides", "DisableVanillaSwimStaminaDrain", true, "Disables vanilla stamina drain for normal swimming.", true, (int?)null, (AcceptableValueBase)null, (Action<ConfigEntryBase>)null, (ConfigurationManagerAttributes)null);
			DisableVanillaDrowningFromStamina = ConfigFileExtensions.BindConfig<bool>(((BaseUnityPlugin)this).Config, "Vanilla Overrides", "DisableVanillaDrowningFromStamina", true, "Disables vanilla drowning behavior caused by stamina depletion.", true, (int?)null, (AcceptableValueBase)null, (Action<ConfigEntryBase>)null, (ConfigurationManagerAttributes)null);
			ConfigFile config9 = ((BaseUnityPlugin)this).Config;
			val2 = (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 50f);
			BaseUnderwaterStaminaRegenPerSecond = ConfigFileExtensions.BindConfig<float>(config9, "Movement", "BaseUnderwaterStaminaRegenPerSecond", 2f, "Base stamina regenerated per second while swimming and not sprinting.", true, (int?)null, val2, (Action<ConfigEntryBase>)null, (ConfigurationManagerAttributes)null);
			ConfigFile config10 = ((BaseUnityPlugin)this).Config;
			val2 = (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 50f);
			MaxSwimSkillBonusStaminaRegenPerSecond = ConfigFileExtensions.BindConfig<float>(config10, "Movement", "MaxSwimSkillBonusStaminaRegenPerSecond", 4f, "Additional stamina regenerated per second at Swim skill 100.", true, (int?)null, val2, (Action<ConfigEntryBase>)null, (ConfigurationManagerAttributes)null);
			ConfigFile config11 = ((BaseUnityPlugin)this).Config;
			val2 = (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.1f, 10f);
			MinSwimSpeed = ConfigFileExtensions.BindConfig<float>(config11, "Movement", "MinSwimSpeed", 1f, "Swim speed multiplier at Swim skill 0.", true, (int?)null, val2, (Action<ConfigEntryBase>)null, (ConfigurationManagerAttributes)null);
			ConfigFile config12 = ((BaseUnityPlugin)this).Config;
			val2 = (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.1f, 10f);
			MaxSwimSpeedAtSkill100 = ConfigFileExtensions.BindConfig<float>(config12, "Movement", "MaxSwimSpeedAtSkill100", 2f, "Swim speed multiplier at Swim skill 100.", true, (int?)null, val2, (Action<ConfigEntryBase>)null, (ConfigurationManagerAttributes)null);
			DebugLogging = ((BaseUnityPlugin)this).Config.Bind<bool>("Debug", "DebugLogging", false, "Enable debug logs.");
			((BaseUnityPlugin)this).Config.SaveOnConfigSet = true;
			((BaseUnityPlugin)this).Config.Save();
		}

		private void CreateConfigWatcher()
		{
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0018: Expected O, but got Unknown
			_configWatcher = new ConfigFileWatcher(((BaseUnityPlugin)this).Config, 1000L);
			_configWatcher.OnConfigFileReloaded += delegate
			{
				((BaseUnityPlugin)this).Logger.LogInfo((object)"Config file reloaded from disk.");
			};
		}

		private void OnConfigurationSynchronized(object sender, ConfigurationSynchronizationEventArgs e)
		{
			if (e.InitialSynchronization)
			{
				((BaseUnityPlugin)this).Logger.LogInfo((object)"Initial config sync received.");
			}
			else
			{
				((BaseUnityPlugin)this).Logger.LogInfo((object)"Config sync update received.");
			}
		}

		private void OnAdminStatusChanged()
		{
			((BaseUnityPlugin)this).Logger.LogInfo((object)("Admin status changed: " + (SynchronizationManager.Instance.PlayerIsAdmin ? "admin" : "not admin")));
		}

		internal static bool IsEnabled()
		{
			return (Object)(object)Instance != (Object)null && EnableMod.Value;
		}

		internal static void LogDebug(string msg)
		{
			if ((Object)(object)Instance != (Object)null && DebugLogging.Value)
			{
				((BaseUnityPlugin)Instance).Logger.LogInfo((object)msg);
			}
		}
	}
	internal class SwimState
	{
		public float Breath;

		public bool WasHeadUnderwater;

		public bool WasSwimming;

		public float LastSurfaceTime;

		public float SuffocationTickTimer;

		public float ExtraBreathBonus;

		public float InfiniteBreathUntil;

		public float SwimSpeedMultiplier = 1f;

		public float SwimSpeedMultiplierUntil;

		public bool WasOutOfBreath;
	}
	internal static class SwimStateManager
	{
		private static readonly Dictionary<long, SwimState> States = new Dictionary<long, SwimState>();

		public static SwimState Get(Player player)
		{
			long playerID = player.GetPlayerID();
			if (!States.TryGetValue(playerID, out var value))
			{
				value = new SwimState
				{
					Breath = SwimAPI.GetBaseMaxBreath(player),
					WasHeadUnderwater = false,
					WasSwimming = false,
					LastSurfaceTime = 0f,
					SuffocationTickTimer = 0f,
					ExtraBreathBonus = 0f,
					InfiniteBreathUntil = 0f,
					SwimSpeedMultiplier = 1f,
					SwimSpeedMultiplierUntil = 0f,
					WasOutOfBreath = false
				};
				States[playerID] = value;
			}
			return value;
		}

		public static void Remove(Player player)
		{
			if (!((Object)(object)player == (Object)null))
			{
				States.Remove(player.GetPlayerID());
			}
		}
	}
	internal static class WaterHelper
	{
		public static bool TryGetWaterLevel(Vector3 position, out float waterLevel)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			waterLevel = Floating.GetLiquidLevel(position, 1f, (LiquidType)0);
			return waterLevel > -10000f;
		}

		public static Vector3 GetHeadPosition(Player player)
		{
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_000f: 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_0022: 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)
			if ((Object)(object)player == (Object)null)
			{
				return Vector3.zero;
			}
			return ((Character)player).GetHeadPoint();
		}

		public static Vector3 GetChestPosition(Player player)
		{
			//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_002e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0033: Unknown result type (might be due to invalid IL or missing references)
			//IL_0038: Unknown result type (might be due to invalid IL or missing references)
			//IL_000f: 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_003a: Unknown result type (might be due to invalid IL or missing references)
			//IL_003b: Unknown result type (might be due to invalid IL or missing references)
			//IL_003e: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)player == (Object)null)
			{
				return Vector3.zero;
			}
			return ((Component)player).transform.position + Vector3.up * 1f;
		}

		public static bool IsBodyInWater(Player player)
		{
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			//IL_001c: Unknown result type (might be due to invalid IL or missing references)
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)player == (Object)null)
			{
				return false;
			}
			Vector3 chestPosition = GetChestPosition(player);
			float waterLevel;
			return TryGetWaterLevel(chestPosition, out waterLevel) && chestPosition.y < waterLevel;
		}

		public static bool IsHeadUnderwater(Player player)
		{
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			//IL_001c: Unknown result type (might be due to invalid IL or missing references)
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)player == (Object)null)
			{
				return false;
			}
			Vector3 headPosition = GetHeadPosition(player);
			float waterLevel;
			return TryGetWaterLevel(headPosition, out waterLevel) && headPosition.y < waterLevel - 0.02f;
		}

		public static bool IsNearSurface(Player player, float tolerance = 0.35f)
		{
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			//IL_001c: Unknown result type (might be due to invalid IL or missing references)
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)player == (Object)null)
			{
				return false;
			}
			Vector3 headPosition = GetHeadPosition(player);
			float waterLevel;
			return TryGetWaterLevel(headPosition, out waterLevel) && Mathf.Abs(headPosition.y - waterLevel) <= tolerance;
		}
	}
}
namespace SwimmingReworked.Patches
{
	[HarmonyPatch(typeof(CameraEffects), "SetSunShafts")]
	internal static class CameraEffectsPatch
	{
		private static void Prefix(ref bool enabled)
		{
			if (DiveImmersionEffect.IsUnderwaterImmersionActive)
			{
				enabled = false;
			}
		}
	}
	[HarmonyPatch(typeof(Character), "Damage")]
	internal static class CharacterDamageDebugPatch
	{
		private static void Prefix(Character __instance, HitData hit)
		{
			//IL_0081: 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)
			if (SwimmingReworked.IsEnabled() && SwimmingReworked.DebugLogging.Value)
			{
				Player val = (Player)(object)((__instance is Player) ? __instance : null);
				if (val != null && !((Object)(object)val != (Object)(object)Player.m_localPlayer) && WaterHelper.IsBodyInWater(val))
				{
					float totalDamage = hit.GetTotalDamage();
					SwimmingReworked.LogDebug($"Damage underwater -> total:{totalDamage}, attacker:{hit.GetAttacker()}, point:{hit.m_point}, dir:{hit.m_dir}");
				}
			}
		}
	}
	[HarmonyPatch(typeof(Character), "Damage")]
	internal static class CharacterDamagePatch
	{
		private static bool Prefix(Character __instance, HitData hit)
		{
			if (!SwimmingReworked.IsEnabled())
			{
				return true;
			}
			Player val = (Player)(object)((__instance is Player) ? __instance : null);
			if (val == null || (Object)(object)val != (Object)(object)Player.m_localPlayer)
			{
				return true;
			}
			if (hit == null)
			{
				return true;
			}
			SwimState swimState = SwimStateManager.Get(val);
			if (swimState.Breath > 0f && IsVanillaDrowningHit(val, hit))
			{
				if (SwimmingReworked.DebugLogging.Value)
				{
					SwimmingReworked.LogDebug($"Blocked vanilla drowning hit: total={hit.GetTotalDamage():F1}");
				}
				return false;
			}
			return true;
		}

		private static bool IsVanillaDrowningHit(Player player, HitData hit)
		{
			//IL_004d: 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_0053: Unknown result type (might be due to invalid IL or missing references)
			if (!WaterHelper.IsHeadUnderwater(player))
			{
				return false;
			}
			if ((Object)(object)hit.GetAttacker() != (Object)null)
			{
				return false;
			}
			float totalDamage = hit.GetTotalDamage();
			if (totalDamage <= 0f)
			{
				return false;
			}
			Vector3 dir = hit.m_dir;
			bool flag = dir.y < -0.9f;
			bool flag2 = Mathf.Abs(totalDamage - 2f) < 0.01f;
			return flag && flag2;
		}
	}
	[HarmonyPatch]
	internal static class CharacterSwimmingPatch
	{
		[HarmonyPatch(typeof(Character), "CustomFixedUpdate")]
		[HarmonyPrefix]
		private static void CharacterCustomFixedUpdatePrefix(Character __instance, ref Vector3 ___m_lookDir)
		{
			if (!SwimmingReworked.IsEnabled())
			{
				return;
			}
			Player val = (Player)(object)((__instance is Player) ? __instance : null);
			if (val == null || (Object)(object)val != (Object)(object)Player.m_localPlayer)
			{
				return;
			}
			if (!WaterHelper.IsBodyInWater(val))
			{
				((Character)val).m_swimDepth = 1.5f;
				return;
			}
			float diveVertical = InputHelper.GetDiveVertical();
			if (diveVertical < -0.01f)
			{
				((Character)val).m_swimDepth = ((Character)val).m_swimDepth + SwimmingReworked.VerticalSwimSpeed.Value * 0.02f;
			}
			else if (diveVertical > 0.01f)
			{
				((Character)val).m_swimDepth = ((Character)val).m_swimDepth - SwimmingReworked.VerticalSwimSpeed.Value * 0.02f;
			}
			((Character)val).m_swimDepth = Mathf.Clamp(((Character)val).m_swimDepth, 1.5f, 100f);
		}

		[HarmonyPatch(typeof(Character), "UpdateMotion")]
		[HarmonyPrefix]
		private static void CharacterUpdateMotionPrefix(Character __instance, ref float ___m_lastGroundTouch, ref float ___m_swimTimer)
		{
			if (SwimmingReworked.IsEnabled())
			{
				Player val = (Player)(object)((__instance is Player) ? __instance : null);
				if (val != null && !((Object)(object)val != (Object)(object)Player.m_localPlayer) && WaterHelper.IsBodyInWater(val))
				{
					___m_lastGroundTouch = 0.3f;
					___m_swimTimer = 0f;
				}
			}
		}

		[HarmonyPatch(typeof(Character), "UpdateSwimming")]
		[HarmonyPrefix]
		private static bool CharacterUpdateSwimmingPrefix(float dt, ref Character __instance)
		{
			//IL_004d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0052: Unknown result type (might be due to invalid IL or missing references)
			//IL_005e: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a9: Unknown result type (might be due to invalid IL or missing references)
			//IL_008a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0096: 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_0198: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a4: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ab: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b0: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f7: Unknown result type (might be due to invalid IL or missing references)
			//IL_01fc: Unknown result type (might be due to invalid IL or missing references)
			//IL_0204: Unknown result type (might be due to invalid IL or missing references)
			//IL_0209: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d0: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d3: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d8: Unknown result type (might be due to invalid IL or missing references)
			//IL_01dd: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e1: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ed: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f2: Unknown result type (might be due to invalid IL or missing references)
			//IL_023e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0249: Unknown result type (might be due to invalid IL or missing references)
			//IL_024e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0253: Unknown result type (might be due to invalid IL or missing references)
			//IL_0278: Unknown result type (might be due to invalid IL or missing references)
			//IL_0282: Unknown result type (might be due to invalid IL or missing references)
			//IL_0287: Unknown result type (might be due to invalid IL or missing references)
			//IL_02f1: Unknown result type (might be due to invalid IL or missing references)
			//IL_030f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0398: Unknown result type (might be due to invalid IL or missing references)
			//IL_03cb: Unknown result type (might be due to invalid IL or missing references)
			//IL_03d0: Unknown result type (might be due to invalid IL or missing references)
			//IL_03d4: Unknown result type (might be due to invalid IL or missing references)
			//IL_03f5: Unknown result type (might be due to invalid IL or missing references)
			//IL_032c: Unknown result type (might be due to invalid IL or missing references)
			//IL_035d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0362: Unknown result type (might be due to invalid IL or missing references)
			//IL_0366: Unknown result type (might be due to invalid IL or missing references)
			//IL_0386: Unknown result type (might be due to invalid IL or missing references)
			//IL_0456: Unknown result type (might be due to invalid IL or missing references)
			//IL_047b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0480: Unknown result type (might be due to invalid IL or missing references)
			//IL_0483: Unknown result type (might be due to invalid IL or missing references)
			//IL_0488: Unknown result type (might be due to invalid IL or missing references)
			//IL_0492: Unknown result type (might be due to invalid IL or missing references)
			//IL_049d: Unknown result type (might be due to invalid IL or missing references)
			//IL_04af: Unknown result type (might be due to invalid IL or missing references)
			//IL_04b4: Unknown result type (might be due to invalid IL or missing references)
			//IL_0438: Unknown result type (might be due to invalid IL or missing references)
			if (!SwimmingReworked.IsEnabled())
			{
				return true;
			}
			Character obj = __instance;
			Player val = (Player)(object)((obj is Player) ? obj : null);
			if (val == null || (Object)(object)val != (Object)(object)Player.m_localPlayer)
			{
				return true;
			}
			bool flag = ((Character)val).IsOnGround();
			Vector3 position = ((Component)val).transform.position;
			if (Mathf.Max(0f, ((Character)val).m_maxAirAltitude - position.y) > 0.5f && ((Character)val).m_onLand != null)
			{
				((Character)val).m_onLand(new Vector3(position.x, ((Character)val).m_waterLevel, position.z));
			}
			((Character)val).m_maxAirAltitude = position.y;
			float skillFactor = val.m_skills.GetSkillFactor((SkillType)103);
			float num = Mathf.Lerp(SwimmingReworked.MinSwimSpeed.Value, SwimmingReworked.MaxSwimSpeedAtSkill100.Value, skillFactor);
			num *= SwimAPI.GetExternalSwimSpeedMultiplier(val);
			num *= ((Character)val).GetAttackSpeedFactorMovement();
			bool flag2 = false;
			float num2 = SwimmingReworked.SprintStaminaPerSecond.Value * dt;
			if (((Character)val).IsEncumbered())
			{
				num *= 0.3f;
			}
			if (((Character)val).InMinorAction())
			{
				num = 0f;
			}
			else if (InputHelper.GetRun() && !((Character)val).IsEncumbered() && val.GetStamina() > num2 + 0.01f)
			{
				num *= SwimmingReworked.SprintSwimMultiplier.Value;
				try
				{
					RuntimeFlags.AllowStaminaUseFromSwimSprint = true;
					((Character)val).UseStamina(num2);
				}
				finally
				{
					RuntimeFlags.AllowStaminaUseFromSwimSprint = false;
				}
			}
			((Character)val).m_seman.ApplyStatusEffectSpeedMods(ref num, ((Character)val).m_moveDir);
			Vector3 val2 = ((Character)val).m_moveDir * num;
			if (((Vector3)(ref val2)).magnitude > 0f && ((Character)val).IsOnGround())
			{
				Vector3 val3 = Vector3.ProjectOnPlane(val2, ((Character)val).m_lastGroundNormal);
				val2 = ((Vector3)(ref val3)).normalized * ((Vector3)(ref val2)).magnitude;
			}
			((Character)val).m_currentVel = Vector3.Lerp(((Character)val).m_currentVel, val2, ((Character)val).m_swimAcceleration);
			if (((Vector3)(ref val2)).magnitude > 0.1f)
			{
				((Character)val).AddNoise(15f);
			}
			((Character)val).AddPushbackForce(ref ((Character)val).m_currentVel);
			Vector3 val4 = ((Character)val).m_currentVel - ((Character)val).m_body.linearVelocity;
			val4.y = 0f;
			if (((Vector3)(ref val4)).magnitude > 20f)
			{
				val4 = ((Vector3)(ref val4)).normalized * 20f;
			}
			if (((Vector3)(ref val2)).magnitude > 0.1f)
			{
				val.m_swimSkillImproveTimer += dt;
				if (val.m_swimSkillImproveTimer > 1f)
				{
					val.m_swimSkillImproveTimer = 0f;
					((Character)val).RaiseSkill((SkillType)103, 1f);
				}
			}
			else
			{
				val.m_swimSkillImproveTimer = 0f;
			}
			((Character)val).m_body.AddForce(val4, (ForceMode)2);
			float num3 = ((Character)val).m_waterLevel - ((Character)val).m_swimDepth;
			if (((Component)val).transform.position.y < num3)
			{
				float num4 = Mathf.Clamp01((num3 - ((Component)val).transform.position.y) / 2f);
				float num5 = Mathf.Lerp(0f, 10f, num4);
				Vector3 linearVelocity = ((Character)val).m_body.linearVelocity;
				linearVelocity.y = Mathf.MoveTowards(linearVelocity.y, num5, 50f * dt);
				((Character)val).m_body.linearVelocity = linearVelocity;
			}
			else
			{
				float num6 = Mathf.Clamp01((((Component)val).transform.position.y - num3) / 1f);
				float num7 = Mathf.Lerp(0f, 10f, num6);
				Vector3 linearVelocity2 = ((Character)val).m_body.linearVelocity;
				linearVelocity2.y = Mathf.MoveTowards(linearVelocity2.y, 0f - num7, 30f * dt);
				((Character)val).m_body.linearVelocity = linearVelocity2;
			}
			float num8 = 0f;
			if (((Vector3)(ref ((Character)val).m_moveDir)).magnitude > 0.1f || ((Character)val).AlwaysRotateCamera())
			{
				float swimTurnSpeed = ((Character)val).m_swimTurnSpeed;
				((Character)val).m_seman.ApplyStatusEffectSpeedMods(ref swimTurnSpeed, ((Character)val).m_moveDir);
				num8 = ((Character)val).UpdateRotation(swimTurnSpeed, dt, true);
			}
			((Character)val).m_body.angularVelocity = Vector3.zero;
			((Character)val).UpdateEyeRotation();
			((Character)val).m_body.useGravity = true;
			Vector3 forward = ((Component)val).transform.forward;
			float num9 = Vector3.Dot(((Character)val).m_currentVel, forward);
			float num10 = Vector3.Dot(((Character)val).m_currentVel, ((Component)val).transform.right);
			float num11 = Vector3.Dot(((Character)val).m_body.linearVelocity, forward);
			((Character)val).m_currentTurnVel = Mathf.SmoothDamp(((Character)val).m_currentTurnVel, num8, ref ((Character)val).m_currentTurnVelChange, 0.5f, 99f);
			int hash = ZSyncAnimation.GetHash("forward_speed");
			int hash2 = ZSyncAnimation.GetHash("sideway_speed");
			int hash3 = ZSyncAnimation.GetHash("turn_speed");
			int hash4 = ZSyncAnimation.GetHash("inWater");
			int hash5 = ZSyncAnimation.GetHash("onGround");
			int hash6 = ZSyncAnimation.GetHash("encumbered");
			int hash7 = ZSyncAnimation.GetHash("flying");
			((Character)val).m_zanim.SetFloat(hash, ((Character)val).IsPlayer() ? num9 : num11);
			((Character)val).m_zanim.SetFloat(hash2, num10);
			((Character)val).m_zanim.SetFloat(hash3, ((Character)val).m_currentTurnVel);
			((Character)val).m_zanim.SetBool(hash4, !flag);
			((Character)val).m_zanim.SetBool(hash5, false);
			((Character)val).m_zanim.SetBool(hash6, false);
			((Character)val).m_zanim.SetBool(hash7, false);
			return false;
		}
	}
	[HarmonyPatch]
	internal static class CharacterWaterStatePatch
	{
		[HarmonyPrefix]
		[HarmonyPatch(typeof(Character), "IsSwimming")]
		private static bool CharacterIsSwimmingPrefix(Character __instance, ref bool __result)
		{
			if (!SwimmingReworked.IsEnabled())
			{
				return true;
			}
			Player val = (Player)(object)((__instance is Player) ? __instance : null);
			if (val == null || (Object)(object)val != (Object)(object)Player.m_localPlayer)
			{
				return true;
			}
			StackTrace stackTrace = new StackTrace();
			for (int i = 2; i < stackTrace.FrameCount && i < 14; i++)
			{
				MethodBase methodBase = stackTrace.GetFrame(i)?.GetMethod();
				if (!(methodBase == null))
				{
					string text = methodBase.DeclaringType?.FullName + "." + methodBase.Name;
					if (text.Contains("EquipItem") || text.Contains("UpdateEquipment") || text.Contains("HideHandItems") || text.Contains("UnequipItem"))
					{
						__result = false;
						return false;
					}
				}
			}
			if (WaterHelper.IsBodyInWater(val))
			{
				__result = true;
				return false;
			}
			return true;
		}

		[HarmonyPostfix]
		[HarmonyPatch(typeof(Character), "IsOnGround")]
		private static void CharacterIsOnGroundPostfix(Character __instance, ref bool __result)
		{
			if (SwimmingReworked.IsEnabled())
			{
				Player val = (Player)(object)((__instance is Player) ? __instance : null);
				if (val != null && !((Object)(object)val != (Object)(object)Player.m_localPlayer) && WaterHelper.IsBodyInWater(val))
				{
					__result = false;
				}
			}
		}

		[HarmonyPostfix]
		[HarmonyPatch(typeof(Character), "InWater")]
		private static void CharacterInWaterPostfix(Character __instance, ref bool __result)
		{
			if (SwimmingReworked.IsEnabled())
			{
				Player val = (Player)(object)((__instance is Player) ? __instance : null);
				if (val != null && !((Object)(object)val != (Object)(object)Player.m_localPlayer) && WaterHelper.IsBodyInWater(val))
				{
					__result = true;
				}
			}
		}
	}
	[HarmonyPatch(typeof(GameCamera), "UpdateCamera")]
	internal static class GameCameraPatch
	{
		private static float _originalMaxDistance;

		private static float _originalMinWaterDistance;

		private static bool _cachedOriginalValues;

		private static void Prefix(GameCamera __instance, Camera ___m_camera)
		{
			if (!SwimmingReworked.IsEnabled())
			{
				return;
			}
			Player localPlayer = Player.m_localPlayer;
			if (!((Object)(object)localPlayer == (Object)null) && !((Object)(object)___m_camera == (Object)null))
			{
				bool flag = WaterHelper.IsBodyInWater(localPlayer);
				if (!_cachedOriginalValues)
				{
					_originalMaxDistance = __instance.m_maxDistance;
					_originalMinWaterDistance = __instance.m_minWaterDistance;
					_cachedOriginalValues = true;
				}
				if (flag)
				{
					__instance.m_minWaterDistance = -5000f;
					__instance.m_maxDistance = _originalMaxDistance;
				}
				else
				{
					__instance.m_minWaterDistance = _originalMinWaterDistance;
					__instance.m_maxDistance = _originalMaxDistance;
				}
			}
		}
	}
	[HarmonyPatch]
	internal static class PlayerEquipInWater
	{
		internal static bool _allowCombat;

		[HarmonyPrefix]
		[HarmonyPatch(typeof(Player), "Update")]
		private static void PlayerUpdate_Prefix(Player __instance)
		{
			if (SwimmingReworked.IsEnabled() && !((Object)(object)__instance != (Object)(object)Player.m_localPlayer) && WaterHelper.IsBodyInWater(__instance))
			{
				bool button = ZInput.GetButton("Attack");
				bool button2 = ZInput.GetButton("Block");
				if (button || button2)
				{
					_allowCombat = true;
				}
			}
		}

		[HarmonyPostfix]
		[HarmonyPatch(typeof(Player), "Update")]
		private static void PlayerUpdate_Postfix()
		{
			_allowCombat = false;
		}

		[HarmonyFinalizer]
		[HarmonyPatch(typeof(Player), "Update")]
		private static void PlayerUpdate_Finalizer()
		{
			_allowCombat = false;
		}

		[HarmonyPostfix]
		[HarmonyPatch(typeof(Character), "InAttack")]
		private static void InAttack_Postfix(Character __instance, ref bool __result)
		{
			if (SwimmingReworked.IsEnabled() && !((Object)(object)__instance != (Object)(object)Player.m_localPlayer) && _allowCombat && WaterHelper.IsBodyInWater(Player.m_localPlayer))
			{
				__result = false;
			}
		}
	}
	[HarmonyPatch(typeof(Player), "FixedUpdate")]
	internal static class PlayerFixedUpdatePatch
	{
		private static void Postfix(Player __instance)
		{
			if (!SwimmingReworked.IsEnabled() || (Object)(object)__instance == (Object)null || (Object)(object)__instance != (Object)(object)Player.m_localPlayer)
			{
				return;
			}
			bool flag = WaterHelper.IsBodyInWater(__instance);
			bool headUnderwater = WaterHelper.IsHeadUnderwater(__instance);
			if (!flag)
			{
				Rigidbody component = ((Component)__instance).GetComponent<Rigidbody>();
				if ((Object)(object)component != (Object)null)
				{
					component.useGravity = true;
				}
				HandleBreath(__instance, headUnderwater: false);
				return;
			}
			Rigidbody component2 = ((Component)__instance).GetComponent<Rigidbody>();
			if (!((Object)(object)component2 == (Object)null))
			{
				component2.useGravity = true;
				HandleBreath(__instance, headUnderwater);
				HandleUnderwaterStaminaRegen(__instance);
			}
		}

		private static void HandleBreath(Player player, bool headUnderwater)
		{
			//IL_00e2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e9: Expected O, but got Unknown
			//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_00fd: Unknown result type (might be due to invalid IL or missing references)
			//IL_0102: Unknown result type (might be due to invalid IL or missing references)
			SwimState swimState = SwimStateManager.Get(player);
			float fixedDeltaTime = Time.fixedDeltaTime;
			float maxBreath = SwimAPI.GetMaxBreath(player);
			bool flag = SwimAPI.HasInfiniteBreath(player);
			if (headUnderwater)
			{
				if (flag)
				{
					swimState.Breath = maxBreath;
					swimState.SuffocationTickTimer = 0f;
				}
				else
				{
					swimState.Breath -= fixedDeltaTime;
					if (swimState.Breath < 0f)
					{
						swimState.Breath = 0f;
					}
					if (swimState.Breath <= 0f)
					{
						swimState.SuffocationTickTimer += fixedDeltaTime;
						if (swimState.SuffocationTickTimer >= SwimmingReworked.SuffocationTickInterval.Value)
						{
							swimState.SuffocationTickTimer = 0f;
							float maxHealth = ((Character)player).GetMaxHealth();
							float damage = maxHealth * (SwimmingReworked.SuffocationDamagePercentPerTick.Value / 100f);
							HitData val = new HitData();
							val.m_point = ((Component)player).transform.position;
							val.m_dir = Vector3.zero;
							val.m_damage.m_damage = damage;
							((Character)player).Damage(val);
						}
					}
					else
					{
						swimState.SuffocationTickTimer = 0f;
					}
				}
			}
			else
			{
				swimState.Breath += SwimmingReworked.BreathRecoveryPerSecond.Value * fixedDeltaTime;
				if (swimState.Breath > maxBreath)
				{
					swimState.Breath = maxBreath;
				}
				swimState.SuffocationTickTimer = 0f;
			}
			SwimAPI.UpdateEvents(player);
			if (SwimmingReworked.DebugLogging.Value && Time.frameCount % 60 == 0)
			{
				SwimmingReworked.LogDebug($"Breath={swimState.Breath:F1}/{maxBreath:F1}, underwater={headUnderwater}, infinite={flag}");
			}
			swimState.WasHeadUnderwater = headUnderwater;
		}

		private static void HandleUnderwaterStaminaRegen(Player player)
		{
			if (!InputHelper.GetRun() || !(player.GetStamina() > 0f))
			{
				float skillFactor = ((Character)player).GetSkillFactor((SkillType)103);
				float num = SwimmingReworked.BaseUnderwaterStaminaRegenPerSecond.Value + SwimmingReworked.MaxSwimSkillBonusStaminaRegenPerSecond.Value * skillFactor;
				float value = Traverse.Create((object)player).Field("m_stamina").GetValue<float>();
				float maxStamina = ((Character)player).GetMaxStamina();
				float num2 = num * Time.fixedDeltaTime;
				value += num2;
				if (value > maxStamina)
				{
					value = maxStamina;
				}
				Traverse.Create((object)player).Field("m_stamina").SetValue((object)value);
			}
		}
	}
	[HarmonyPatch(typeof(Player), "Update")]
	internal static class PlayerUpdatePatch
	{
		private static void Postfix(Player __instance)
		{
		}
	}
	[HarmonyPatch(typeof(Player), "UpdateStats", new Type[] { typeof(float) })]
	internal static class PlayerUpdateStatsPatch
	{
		private static void Postfix(Player __instance, float dt)
		{
			if (SwimmingReworked.IsEnabled() && !((Object)(object)__instance == (Object)null) && !((Object)(object)__instance != (Object)(object)Player.m_localPlayer) && WaterHelper.IsBodyInWater(__instance) && (!InputHelper.GetRun() || !(__instance.GetStamina() > 0f)))
			{
				Traverse.Create((object)__instance).Field("m_staminaRegenTimer").SetValue((object)0f);
			}
		}
	}
	[HarmonyPatch(typeof(WaterVolume), "UpdateMaterials")]
	internal static class SurfacePatch
	{
		private static readonly Dictionary<MeshRenderer, GameObject> UnderwaterCopies = new Dictionary<MeshRenderer, GameObject>();

		private const float SurfaceOffset = -0.05f;

		private const float OverlapScale = 1.04f;

		private static void Postfix(WaterVolume __instance)
		{
			if (!SwimmingReworked.IsEnabled() || (Object)(object)__instance == (Object)null || (Object)(object)__instance.m_waterSurface == (Object)null)
			{
				return;
			}
			MeshRenderer component = ((Component)__instance.m_waterSurface).GetComponent<MeshRenderer>();
			MeshFilter component2 = ((Component)__instance.m_waterSurface).GetComponent<MeshFilter>();
			if ((Object)(object)component == (Object)null || (Object)(object)component2 == (Object)null)
			{
				return;
			}
			if (!UnderwaterCopies.TryGetValue(component, out var value) || (Object)(object)value == (Object)null)
			{
				value = CreateUnderwaterSurfaceCopy(((Component)component).gameObject, component, component2);
				if ((Object)(object)value != (Object)null)
				{
					UnderwaterCopies[component] = value;
				}
			}
			if (!((Object)(object)value == (Object)null))
			{
				value.SetActive(IsCameraUnderwater());
			}
		}

		private static GameObject CreateUnderwaterSurfaceCopy(GameObject original, MeshRenderer originalRenderer, MeshFilter originalFilter)
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_000c: Expected O, but got Unknown
			//IL_0034: 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_0074: Unknown result type (might be due to invalid IL or missing references)
			GameObject val = new GameObject("SwimmingReworked_UnderwaterSurface");
			val.transform.SetParent(original.transform, false);
			val.transform.localPosition = new Vector3(0f, -0.025f, 0f);
			val.transform.localRotation = Quaternion.Euler(180f, 180f, 0f);
			val.transform.localScale = new Vector3(1.02f, 1f, 1.02f);
			MeshFilter val2 = val.AddComponent<MeshFilter>();
			val2.sharedMesh = originalFilter.sharedMesh;
			MeshRenderer val3 = val.AddComponent<MeshRenderer>();
			((Renderer)val3).sharedMaterial = ((Renderer)originalRenderer).sharedMaterial;
			((Renderer)val3).shadowCastingMode = (ShadowCastingMode)0;
			((Renderer)val3).receiveShadows = false;
			((Renderer)val3).lightProbeUsage = (LightProbeUsage)0;
			((Renderer)val3).reflectionProbeUsage = (ReflectionProbeUsage)0;
			((Renderer)val3).allowOcclusionWhenDynamic = false;
			((Renderer)val3).forceRenderingOff = false;
			((Renderer)val3).enabled = true;
			val.SetActive(false);
			return val;
		}

		private static bool IsCameraUnderwater()
		{
			//IL_0042: 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)
			if ((Object)(object)GameCamera.instance == (Object)null)
			{
				return false;
			}
			Camera component = ((Component)GameCamera.instance).GetComponent<Camera>();
			if ((Object)(object)component == (Object)null)
			{
				return false;
			}
			float waterLevel;
			return WaterHelper.TryGetWaterLevel(((Component)component).transform.position, out waterLevel) && ((Component)component).transform.position.y < waterLevel - 0.15f;
		}
	}
	[HarmonyPatch(typeof(Player), "UseStamina")]
	internal static class UseStaminaPatch
	{
		private static bool Prefix(Player __instance, ref float v)
		{
			if (!SwimmingReworked.IsEnabled())
			{
				return true;
			}
			if (!SwimmingReworked.DisableVanillaSwimStaminaDrain.Value)
			{
				return true;
			}
			if ((Object)(object)__instance == (Object)null || (Object)(object)__instance != (Object)(object)Player.m_localPlayer)
			{
				return true;
			}
			if (RuntimeFlags.AllowStaminaUseFromSwimSprint)
			{
				return true;
			}
			if (!WaterHelper.IsBodyInWater(__instance))
			{
				return true;
			}
			StackTrace stackTrace = new StackTrace();
			string text = "";
			for (int i = 2; i < stackTrace.FrameCount && i < 10; i++)
			{
				MethodBase methodBase = stackTrace.GetFrame(i)?.GetMethod();
				if (methodBase != null)
				{
					text = text + methodBase.Name + "_";
				}
			}
			if (text.Contains("OnSwimming") || text.Contains("UpdateSwimming"))
			{
				return false;
			}
			return true;
		}
	}
	[HarmonyPatch(typeof(WaterVolume), "UpdateMaterials")]
	internal static class WaterShaderPatch
	{
		private static readonly int ColorTopId = Shader.PropertyToID("_ColorTop");

		private static readonly int ColorBottomId = Shader.PropertyToID("_ColorBottom");

		private static readonly int ColorBottomShallowId = Shader.PropertyToID("_ColorBottomShallow");

		private static readonly int SurfaceColorId = Shader.PropertyToID("_SurfaceColor");

		private static readonly int DepthFadeId = Shader.PropertyToID("_DepthFade");

		private static readonly int CullId = Shader.PropertyToID("_Cull");

		private static Color _originalColorTop;

		private static Color _originalColorBottom;

		private static Color _originalColorBottomShallow;

		private static Color _originalSurfaceColor;

		private static float _originalDepthFade;

		private static bool _originalValuesSaved;

		private static Material _instanceMaterial;

		private static MeshRenderer _lastRenderer;

		private static void Postfix(WaterVolume __instance)
		{
			if (SwimmingReworked.IsEnabled() && !((Object)(object)__instance.m_waterSurface == (Object)null))
			{
				MeshRenderer waterSurface = __instance.m_waterSurface;
				if ((Object)(object)_instanceMaterial == (Object)null || (Object)(object)_lastRenderer != (Object)(object)waterSurface)
				{
					_instanceMaterial = ((Renderer)waterSurface).material;
					_lastRenderer = waterSurface;
					SaveOriginalValues(_instanceMaterial);
				}
				if (_instanceMaterial.HasProperty(CullId))
				{
					_instanceMaterial.SetInt(CullId, 0);
				}
				ApplyUnderwaterSettings(_instanceMaterial);
			}
		}

		private static void SaveOriginalValues(Material mat)
		{
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			//IL_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_0054: Unknown result type (might be due to invalid IL or missing references)
			//IL_0059: Unknown result type (might be due to invalid IL or missing references)
			//IL_0073: Unknown result type (might be due to invalid IL or missing references)
			//IL_0078: Unknown result type (might be due to invalid IL or missing references)
			if (mat.HasProperty(ColorTopId))
			{
				_originalColorTop = mat.GetColor(ColorTopId);
			}
			if (mat.HasProperty(ColorBottomId))
			{
				_originalColorBottom = mat.GetColor(ColorBottomId);
			}
			if (mat.HasProperty(ColorBottomShallowId))
			{
				_originalColorBottomShallow = mat.GetColor(ColorBottomShallowId);
			}
			if (mat.HasProperty(SurfaceColorId))
			{
				_originalSurfaceColor = mat.GetColor(SurfaceColorId);
			}
			if (mat.HasProperty(DepthFadeId))
			{
				_originalDepthFade = mat.GetFloat(DepthFadeId);
			}
			_originalValuesSaved = true;
		}

		private static void ApplyUnderwaterSettings(Material mat)
		{
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			//IL_005e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0092: 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)
			if (mat.HasProperty(ColorTopId))
			{
				mat.SetColor(ColorTopId, new Color(0.05f, 0.35f, 0.35f, 0.95f));
			}
			if (mat.HasProperty(ColorBottomId))
			{
				mat.SetColor(ColorBottomId, new Color(0.02f, 0.05f, 0.15f, 0.98f));
			}
			if (mat.HasProperty(ColorBottomShallowId))
			{
				mat.SetColor(ColorBottomShallowId, new Color(0.08f, 0.3f, 0.4f, 0.9f));
			}
			if (mat.HasProperty(SurfaceColorId))
			{
				mat.SetColor(SurfaceColorId, new Color(0.1f, 0.35f, 0.45f, 0.85f));
			}
			if (mat.HasProperty(DepthFadeId))
			{
				mat.SetFloat(DepthFadeId, _originalDepthFade * 2f);
			}
		}
	}
}
namespace SwimmingReworked.Effects
{
	internal class DiveImmersionEffect : MonoBehaviour
	{
		internal static bool IsUnderwaterImmersionActive;

		private AudioLowPassFilter _lowPass;

		private bool _active;

		private float _intensity;

		private bool _fogSaved;

		private bool _savedFog;

		private FogMode _savedFogMode;

		private float _savedFogDensity;

		private Color _savedFogColor;

		private Behaviour _ownedHeatDistort;

		private Type _heatDistortType;

		private Behaviour _sunShafts;

		private bool _sunShaftsSaved;

		private bool _sunShaftsWasEnabled;

		private float _savedSunShaftIntensity;

		private float _savedSunShaftBlurRadius;

		private float _savedSunShaftMaxRadius;

		private int _savedSunShaftRadialBlurIterations;

		private const float EnterSwimDepth = 2.15f;

		private const float ExitSwimDepth = 1.75f;

		private const float EnterCameraDepth = 0.45f;

		private const float ExitCameraDepth = 0.2f;

		private const float FadeSpeed = 2.5f;

		private const float UnderwaterFogDensity = 0.018f;

		private const float HeatDistortionIntensity = 2f;

		private static readonly Color UnderwaterFogColor = new Color(0.025f, 0.1f, 0.13f, 1f);

		private static readonly Color HeatDistortionColor = new Color(0.05f, 0.35f, 0.55f, 0.2f);

		private void Update()
		{
			if (ShouldUseDiveEffect())
			{
				_active = true;
			}
			else if (_active && ShouldExitDiveEffect())
			{
				_active = false;
			}
			_intensity = Mathf.MoveTowards(_intensity, _active ? 1f : 0f, Time.deltaTime * 2.5f);
			bool flag = (IsUnderwaterImmersionActive = _intensity > 0.001f);
			EnsureHeatDistortion();
			if ((Object)(object)_ownedHeatDistort != (Object)null)
			{
				_ownedHeatDistort.enabled = flag;
				ApplyHeatDistortionValues();
			}
			UpdateSunShafts(flag);
			if (flag)
			{
				ApplyFog();
				ApplyAudio();
			}
			else
			{
				RestoreFog();
				RestoreAudio();
			}
		}

		private void LateUpdate()
		{
			if (IsUnderwaterImmersionActive)
			{
				UpdateSunShafts(underwater: true);
			}
		}

		private bool ShouldUseDiveEffect()
		{
			//IL_007d: 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)
			if (!SwimmingReworked.IsEnabled())
			{
				return false;
			}
			Player localPlayer = Player.m_localPlayer;
			if ((Object)(object)localPlayer == (Object)null || (Object)(object)GameCamera.instance == (Object)null)
			{
				return false;
			}
			if (!WaterHelper.IsBodyInWater(localPlayer))
			{
				return false;
			}
			Camera component = ((Component)GameCamera.instance).GetComponent<Camera>();
			if ((Object)(object)component == (Object)null)
			{
				return false;
			}
			if (!WaterHelper.TryGetWaterLevel(((Component)component).transform.position, out var waterLevel))
			{
				return false;
			}
			float num = waterLevel - ((Component)component).transform.position.y;
			return ((Character)localPlayer).m_swimDepth >= 2.15f && num >= 0.45f;
		}

		private bool ShouldExitDiveEffect()
		{
			//IL_0066: 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)
			Player localPlayer = Player.m_localPlayer;
			if ((Object)(object)localPlayer == (Object)null || (Object)(object)GameCamera.instance == (Object)null)
			{
				return true;
			}
			if (!WaterHelper.IsBodyInWater(localPlayer))
			{
				return true;
			}
			Camera component = ((Component)GameCamera.instance).GetComponent<Camera>();
			if ((Object)(object)component == (Object)null)
			{
				return true;
			}
			if (!WaterHelper.TryGetWaterLevel(((Component)component).transform.position, out var waterLevel))
			{
				return true;
			}
			float num = waterLevel - ((Component)component).transform.position.y;
			return ((Character)localPlayer).m_swimDepth <= 1.75f || num <= 0.2f;
		}

		private void EnsureHeatDistortion()
		{
			if ((Object)(object)_ownedHeatDistort != (Object)null)
			{
				return;
			}
			GameCamera instance = GameCamera.instance;
			Camera val = ((instance != null) ? ((Component)instance).GetComponent<Camera>() : null);
			if ((Object)(object)val == (Object)null)
			{
				return;
			}
			_heatDistortType = AccessTools.TypeByName("HeatDistortImageEffect");
			if (_heatDistortType == null)
			{
				SwimmingReworked.LogDebug("[DiveImmersion] HeatDistortImageEffect type not found.");
				return;
			}
			Component component = ((Component)val).GetComponent(_heatDistortType);
			ref Behaviour ownedHeatDistort = ref _ownedHeatDistort;
			Component obj = ((Component)val).gameObject.AddComponent(_heatDistortType);
			ownedHeatDistort = (Behaviour)(object)((obj is Behaviour) ? obj : null);
			if ((Object)(object)_ownedHeatDistort == (Object)null)
			{
				Debug.LogWarning((object)"[DiveImmersion] Failed to add owned HeatDistortImageEffect.");
				return;
			}
			if ((Object)(object)component != (Object)null)
			{
				CopyFields(component, (Component)(object)_ownedHeatDistort);
			}
			_ownedHeatDistort.enabled = false;
			ApplyHeatDistortionValues();
			SwimmingReworked.LogDebug("[DiveImmersion] Created owned HeatDistortImageEffect.");
		}

		private void ApplyHeatDistortionValues()
		{
			//IL_004a: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)_ownedHeatDistort == (Object)null))
			{
				Type type = ((object)_ownedHeatDistort).GetType();
				SetField(type, _ownedHeatDistort, "m_intensity", 2f * _intensity);
				SetField<Color>(type, _ownedHeatDistort, "m_color", HeatDistortionColor);
			}
		}

		private void EnsureSunShafts()
		{
			if ((Object)(object)_sunShafts != (Object)null || (Object)(object)GameCamera.instance == (Object)null)
			{
				return;
			}
			Camera component = ((Component)GameCamera.instance).GetComponent<Camera>();
			if ((Object)(object)component == (Object)null)
			{
				return;
			}
			Behaviour[] components = ((Component)component).GetComponents<Behaviour>();
			foreach (Behaviour val in components)
			{
				if (!((Object)(object)val == (Object)null))
				{
					string text = ((object)val).GetType().FullName ?? ((object)val).GetType().Name;
					if (text == "UnityStandardAssets.ImageEffects.SunShafts" || text.Contains("SunShafts"))
					{
						_sunShafts = val;
						SwimmingReworked.LogDebug("[DiveImmersion] Found SunShafts: " + text);
						break;
					}
				}
			}
		}

		private void UpdateSunShafts(bool underwater)
		{
			EnsureSunShafts();
			if ((Object)(object)_sunShafts == (Object)null)
			{
				return;
			}
			Type type = ((object)_sunShafts).GetType();
			if (underwater)
			{
				if (!_sunShaftsSaved)
				{
					_sunShaftsWasEnabled = _sunShafts.enabled;
					_savedSunShaftIntensity = GetField(type, _sunShafts, "sunShaftIntensity", 1.15f);
					_savedSunShaftBlurRadius = GetField(type, _sunShafts, "sunShaftBlurRadius", 2.5f);
					_savedSunShaftMaxRadius = GetField(type, _sunShafts, "maxRadius", 0.75f);
					_savedSunShaftRadialBlurIterations = GetField(type, _sunShafts, "radialBlurIterations", 2);
					_sunShaftsSaved = true;
				}
				SetField(type, _sunShafts, "sunShaftIntensity", 0f);
				SetField(type, _sunShafts, "sunShaftBlurRadius", 0f);
				SetField(type, _sunShafts, "maxRadius", 0f);
				SetField(type, _sunShafts, "radialBlurIterations", 0);
				_sunShafts.enabled = false;
			}
			else if (_sunShaftsSaved)
			{
				SetField(type, _sunShafts, "sunShaftIntensity", _savedSunShaftIntensity);
				SetField(type, _sunShafts, "sunShaftBlurRadius", _savedSunShaftBlurRadius);
				SetField(type, _sunShafts, "maxRadius", _savedSunShaftMaxRadius);
				SetField(type, _sunShafts, "radialBlurIterations", _savedSunShaftRadialBlurIterations);
				_sunShafts.enabled = _sunShaftsWasEnabled;
				_sunShaftsSaved = false;
			}
		}

		private static void CopyFields(Component source, Component target)
		{
			if ((Object)(object)source == (Object)null || (Object)(object)target == (Object)null)
			{
				return;
			}
			Type type = ((object)source).GetType();
			FieldInfo[] fields = type.GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
			foreach (FieldInfo fieldInfo in fields)
			{
				if (!fieldInfo.IsInitOnly && !fieldInfo.IsLiteral)
				{
					try
					{
						fieldInfo.SetValue(target, fieldInfo.GetValue(source));
					}
					catch
					{
					}
				}
			}
		}

		private static void SetField<T>(Type type, object instance, string fieldName, T value)
		{
			FieldInfo field = type.GetField(fieldName, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
			if (field == null)
			{
				return;
			}
			try
			{
				field.SetValue(instance, value);
			}
			catch
			{
			}
		}

		private static T GetField<T>(Type type, object instance, string fieldName, T fallback)
		{
			FieldInfo field = type.GetField(fieldName, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
			if (field == null)
			{
				return fallback;
			}
			try
			{
				object value = field.GetValue(instance);
				if (value is T)
				{
					T result = (T)value;
					if (true)
					{
						return result;
					}
				}
			}
			catch
			{
			}
			return fallback;
		}

		private void ApplyFog()
		{
			//IL_006e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0073: Unknown result type (might be due to invalid IL or missing references)
			//IL_007e: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			//IL_0031: Unknown result type (might be due to invalid IL or missing references)
			//IL_0036: Unknown result type (might be due to invalid IL or missing references)
			if (!_fogSaved)
			{
				_savedFog = RenderSettings.fog;
				_savedFogMode = RenderSettings.fogMode;
				_savedFogDensity = RenderSettings.fogDensity;
				_savedFogColor = RenderSettings.fogColor;
				_fogSaved = true;
			}
			RenderSettings.fog = true;
			RenderSettings.fogMode = (FogMode)2;
			RenderSettings.fogDensity = Mathf.Lerp(_savedFogDensity, 0.018f, _intensity);
			RenderSettings.fogColor = Color.Lerp(_savedFogColor, UnderwaterFogColor, _intensity);
		}

		private void RestoreFog()
		{
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0036: Unknown result type (might be due to invalid IL or missing references)
			if (_fogSaved)
			{
				RenderSettings.fog = _savedFog;
				RenderSettings.fogMode = _savedFogMode;
				RenderSettings.fogDensity = _savedFogDensity;
				RenderSettings.fogColor = _savedFogColor;
				_fogSaved = false;
			}
		}

		private void ApplyAudio()
		{
			AudioListener val = Object.FindFirstObjectByType<AudioListener>();
			if ((Object)(object)val == (Object)null)
			{
				return;
			}
			if ((Object)(object)_lowPass == (Object)null)
			{
				_lowPass = ((Component)val).gameObject.GetComponent<AudioLowPassFilter>();
				if ((Object)(object)_lowPass == (Object)null)
				{
					_lowPass = ((Component)val).gameObject.AddComponent<AudioLowPassFilter>();
				}
			}
			((Behaviour)_lowPass).enabled = true;
			_lowPass.cutoffFrequency = Mathf.Lerp(22000f, 1700f, _intensity);
			_lowPass.lowpassResonanceQ = Mathf.Lerp(1f, 1.25f, _intensity);
		}

		private void RestoreAudio()
		{
			if ((Object)(object)_lowPass != (Object)null)
			{
				((Behaviour)_lowPass).enabled = false;
				_lowPass = null;
			}
		}

		private void OnDestroy()
		{
			IsUnderwaterImmersionActive = false;
			UpdateSunShafts(underwater: false);
			RestoreFog();
			RestoreAudio();
			if ((Object)(object)_ownedHeatDistort != (Object)null)
			{
				Object.Destroy((Object)(object)_ownedHeatDistort);
			}
		}
	}
}