Decompiled source of UnderTheSea v0.1.0

UnderTheSea.dll

Decompiled a day ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Reflection;
using System.Reflection.Emit;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using Configs;
using HarmonyLib;
using Jotunn.Extensions;
using Jotunn.Utils;
using Logging;
using Microsoft.CodeAnalysis;
using UnityEngine;
using UnityEngine.Rendering;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: AssemblyTitle("UnderTheSea")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("UnderTheSea")]
[assembly: AssemblyCopyright("Copyright ©  2024")]
[assembly: AssemblyTrademark("")]
[assembly: ComVisible(false)]
[assembly: Guid("08a6f7d7-cf93-4931-aecd-abf2ce6ed34c")]
[assembly: AssemblyFileVersion("0.1.0")]
[assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("0.1.0.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.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace Logging
{
	internal static class Log
	{
		internal enum InfoLevel
		{
			Low,
			Medium,
			High
		}

		private static ManualLogSource logSource;

		internal static ConfigEntry<InfoLevel> Verbosity { get; set; }

		internal static InfoLevel VerbosityLevel => Verbosity.Value;

		internal static bool IsVerbosityLow => Verbosity.Value >= InfoLevel.Low;

		internal static bool IsVerbosityMedium => Verbosity.Value >= InfoLevel.Medium;

		internal static bool IsVerbosityHigh => Verbosity.Value >= InfoLevel.High;

		internal static void Init(ManualLogSource logSource)
		{
			Log.logSource = logSource;
		}

		internal static void LogDebug(object data)
		{
			logSource.LogDebug(data);
		}

		internal static void LogError(object data)
		{
			logSource.LogError(data);
		}

		internal static void LogFatal(object data)
		{
			logSource.LogFatal(data);
		}

		internal static void LogMessage(object data)
		{
			logSource.LogMessage(data);
		}

		internal static void LogWarning(object data)
		{
			logSource.LogWarning(data);
		}

		internal static void LogInfo(object data, InfoLevel level = InfoLevel.Low)
		{
			if (Verbosity == null || VerbosityLevel >= level)
			{
				logSource.LogInfo(data);
			}
		}

		internal static void LogGameObject(GameObject prefab, bool includeChildren = false)
		{
			//IL_006b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0071: Expected O, but got Unknown
			LogInfo("***** " + ((Object)prefab).name + " *****");
			Component[] components = prefab.GetComponents<Component>();
			for (int i = 0; i < components.Length; i++)
			{
				LogComponent(components[i]);
			}
			if (!includeChildren)
			{
				return;
			}
			LogInfo("***** " + ((Object)prefab).name + " (children) *****");
			foreach (Transform item in prefab.transform)
			{
				Transform val = item;
				if (Object.op_Implicit((Object)(object)val))
				{
					LogInfo(" - " + ((Object)val).name);
					components = ((Component)val).GetComponents<Component>();
					for (int i = 0; i < components.Length; i++)
					{
						LogComponent(components[i]);
					}
				}
			}
		}

		internal static void LogComponent(Component compo)
		{
			if (!Object.op_Implicit((Object)(object)compo))
			{
				return;
			}
			try
			{
				LogInfo("--- " + ((object)compo).GetType().Name + ": " + ((Object)compo).name + " ---");
			}
			catch (Exception ex)
			{
				LogError(ex.ToString());
				LogWarning("Could not get type name for component!");
				return;
			}
			try
			{
				foreach (PropertyInfo declaredProperty in AccessTools.GetDeclaredProperties(((object)compo).GetType()))
				{
					try
					{
						LogInfo($" - {declaredProperty.Name} = {declaredProperty.GetValue(compo)}");
					}
					catch (Exception ex2)
					{
						LogError(ex2.ToString());
						LogWarning("Could not get property: " + declaredProperty.Name + " for component!");
					}
				}
			}
			catch (Exception ex3)
			{
				LogError(ex3.ToString());
				LogWarning("Could not get properties for component!");
			}
			try
			{
				foreach (FieldInfo declaredField in AccessTools.GetDeclaredFields(((object)compo).GetType()))
				{
					try
					{
						LogInfo($" - {declaredField.Name} = {declaredField.GetValue(compo)}");
					}
					catch (Exception ex4)
					{
						LogError(ex4.ToString());
						LogWarning("Could not get field: " + declaredField.Name + " for component!");
					}
				}
			}
			catch (Exception ex5)
			{
				LogError(ex5.ToString());
				LogWarning("Could not get fields for component!");
			}
		}
	}
}
namespace UnderTheSea
{
	internal class Diver : MonoBehaviour
	{
		public enum DiveDirection
		{
			NEUTRAL,
			UP,
			DOWN
		}

		private const float Tol = 0.01f;

		private static readonly Dictionary<Player, Diver> Divers = new Dictionary<Player, Diver>();

		private Vector3 LastDiveDirection = Vector3.zero;

		public Player player;

		public const float DefaultSwimDepth = 1.4f;

		public const float DivingSwimDepth = 2.5f;

		public float BaseSwimSpeed { get; private set; }

		public float RestingStaminaRegenDelay => (0f - UnderTheSea.Instance.RestingStaminaRegenDelay.Value) * player.m_staminaRegenDelay;

		public float RestingStaminaRegenRate => UnderTheSea.Instance.RestingStaminaRegenRate.Value * player.m_staminaRegen;

		public void Awake()
		{
			player = ((Component)this).GetComponent<Player>();
			((Character)player).m_swimDepth = 1.4f;
			BaseSwimSpeed = ((Character)player).m_swimSpeed;
			Divers.Add(player, this);
		}

		public void ResetSwimDepthIfNotInWater()
		{
			if (!((Character)player).InWater())
			{
				ResetSwimDepthToDefault();
			}
		}

		public void ResetSwimDepthToDefault()
		{
			((Character)player).m_swimDepth = 1.4f;
		}

		public bool CanDive()
		{
			//IL_003a: 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)
			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;
		}

		public bool IsInsideLiquid()
		{
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			return Mathf.Max(0f, ((Character)player).GetLiquidLevel() - ((Component)player).transform.position.y) > 1.4f;
		}

		public bool IsUnderSurface()
		{
			return ((Character)player).m_swimDepth > 1.4f;
		}

		public bool IsDiving()
		{
			return ((Character)player).m_swimDepth > 2.5f;
		}

		public bool IsSurfacing()
		{
			if (!IsDiving())
			{
				return IsUnderSurface();
			}
			return false;
		}

		public bool IsRestingInWater()
		{
			//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)
			if (!IsDiving() && ((Character)player).IsSwimming())
			{
				Vector3 velocity = ((Character)player).GetVelocity();
				return ((Vector3)(ref velocity)).magnitude < 1f;
			}
			return false;
		}

		public void RegenRestingStamina(float dt)
		{
			Player obj = player;
			obj.m_staminaRegenTimer -= dt;
			if (player.GetStamina() < ((Character)player).GetMaxStamina() && player.m_staminaRegenTimer <= RestingStaminaRegenDelay)
			{
				float skillFactor = player.m_skills.GetSkillFactor((SkillType)103);
				float num = (1f + skillFactor) * RestingStaminaRegenRate;
				player.m_stamina = Mathf.Min(((Character)player).GetMaxStamina(), player.m_stamina + num * dt * Game.m_staminaRegenRate);
			}
		}

		public void DrainDivingStamina(float dt)
		{
			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);
			((Character)player).UseStamina(dt * num * Game.m_moveStaminaRate * UnderTheSea.Instance.UnderwaterRestingStaminaDrainRate.Value);
		}

		public void UpdateSwimSkill(float dt)
		{
			Player obj = player;
			obj.m_swimSkillImproveTimer += dt;
			if (player.m_swimSkillImproveTimer > 1f)
			{
				player.m_swimSkillImproveTimer = 0f;
				((Character)player).RaiseSkill((SkillType)103, 1f);
			}
		}

		public void UpdateSwimSpeed(float dt)
		{
			float num = (ZInput.GetButton("Run") ? dt : (0f - dt));
			float num2 = ((Character)player).m_swimSpeed + ((Character)player).m_swimAcceleration * num;
			((Character)player).m_swimSpeed = Mathf.Clamp(num2, BaseSwimSpeed, UnderTheSea.Instance.MaxSwimSpeed.Value);
		}

		public void Dive(float dt, bool ascend, out Vector3? defaultMoveDir)
		{
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			//IL_0029: 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_003a: 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);
		}

		public Vector3 GetDiveDirection(bool ascend)
		{
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0003: Unknown result type (might be due to invalid IL or missing references)
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			//IL_004a: Unknown result type (might be due to invalid IL or missing references)
			//IL_004b: Unknown result type (might be due to invalid IL or missing references)
			//IL_004c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0051: 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_0044: Unknown result type (might be due to invalid IL or missing references)
			//IL_0049: Unknown result type (might be due to invalid IL or missing references)
			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 = GetHorizontalLookDir(scale);
			}
			Vector3 result = val2 + val;
			((Vector3)(ref result)).Normalize();
			return result;
		}

		private Vector3 GetHorizontalLookDir(float scale = 0.05f)
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: 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_0021: 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;
		}

		public Vector3 CalculateSwimVelocity()
		{
			//IL_003e: Unknown result type (might be due to invalid IL or missing references)
			//IL_004e: Unknown result type (might be due to invalid IL or missing references)
			//IL_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_0060: Unknown result type (might be due to invalid IL or missing references)
			//IL_0065: Unknown result type (might be due to invalid IL or missing references)
			//IL_0071: Unknown result type (might be due to invalid IL or missing references)
			//IL_0076: Unknown result type (might be due to invalid IL or missing references)
			//IL_0084: Unknown result type (might be due to invalid IL or missing references)
			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;
		}
	}
	[BepInPlugin("Searica.Valheim.UnderTheSea", "UnderTheSea", "0.1.0")]
	[BepInDependency("com.jotunn.jotunn", "2.23.0")]
	[NetworkCompatibility(/*Could not decode attribute arguments.*/)]
	[SynchronizationMode(/*Could not decode attribute arguments.*/)]
	[BepInIncompatibility("ch.easy.develope.vh.diving.mod")]
	[BepInIncompatibility("blacks7ar.VikingsDoSwim")]
	[BepInIncompatibility("projjm.improvedswimming")]
	[BepInIncompatibility("MainStreetGaming.BetterDiving")]
	internal sealed class UnderTheSea : BaseUnityPlugin
	{
		public const string PluginName = "UnderTheSea";

		internal const string Author = "Searica";

		public const string PluginGUID = "Searica.Valheim.UnderTheSea";

		public const string PluginVersion = "0.1.0";

		internal static UnderTheSea Instance;

		internal static ConfigFile ConfigFile;

		internal static ConfigFileWatcher ConfigFileWatcher;

		internal string CurrentEnvName = string.Empty;

		internal const string GlobalSection = "Global";

		public ConfigEntry<float> RestingStaminaRegenDelay;

		public ConfigEntry<float> RestingStaminaRegenRate;

		public ConfigEntry<float> UnderwaterRestingStaminaDrainRate;

		public ConfigEntry<float> MaxSwimSpeed;

		public ConfigEntry<float> ColorDarknessFactor;

		public ConfigEntry<float> FogDensityFactor;

		public ConfigEntry<float> MinFogDensity;

		public ConfigEntry<float> MaxFogDensity;

		public ConfigEntry<bool> UseEquipInWater;

		public static string EnvName = "";

		public void Awake()
		{
			Instance = this;
			ConfigFile = ((BaseUnityPlugin)this).Config;
			Log.Init(((BaseUnityPlugin)this).Logger);
			((BaseUnityPlugin)this).Config.DisableSaveOnConfigSet();
			SetUpConfigEntries();
			((BaseUnityPlugin)this).Config.Save();
			((BaseUnityPlugin)this).Config.SaveOnConfigSet = true;
			Harmony.CreateAndPatchAll(Assembly.GetExecutingAssembly(), "Searica.Valheim.UnderTheSea");
			Game.isModded = true;
			ConfigFileWatcher = new ConfigFileWatcher(((BaseUnityPlugin)this).Config);
		}

		internal void SetUpConfigEntries()
		{
			UseEquipInWater = ConfigFileExtensions.BindConfigInOrder<bool>(((BaseUnityPlugin)this).Config, "Global", "Use Equipment in Water", true, "Whether you can use equipment while in water.", true, true, true, (AcceptableValueBase)null, (Action<ConfigEntryBase>)null, (ConfigurationManagerAttributes)null);
			RestingStaminaRegenDelay = ConfigFileExtensions.BindConfigInOrder<float>(((BaseUnityPlugin)this).Config, "Global", "Treading Water Stamina Regen Delay", 2f, "How long before you regenerate stamina when treading water as a mulitple of the default delay while on ground.", true, true, true, (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 5f), (Action<ConfigEntryBase>)null, (ConfigurationManagerAttributes)null);
			RestingStaminaRegenRate = ConfigFileExtensions.BindConfigInOrder<float>(((BaseUnityPlugin)this).Config, "Global", "Treading Water Stamina Regen Rate", 0.5f, "How fast you regenerate stamina while treading water as a mulitple of the default regen rate while on ground.", true, true, true, (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 1f), (Action<ConfigEntryBase>)null, (ConfigurationManagerAttributes)null);
			UnderwaterRestingStaminaDrainRate = ConfigFileExtensions.BindConfigInOrder<float>(((BaseUnityPlugin)this).Config, "Global", "Underwater Stamina Drain", 0.5f, "How fast you drain stamina while floating underwater without moving as a mulitple of the default swimming drain.", true, true, true, (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 2f), (Action<ConfigEntryBase>)null, (ConfigurationManagerAttributes)null);
			MaxSwimSpeed = ConfigFileExtensions.BindConfigInOrder<float>(((BaseUnityPlugin)this).Config, "Global", "Max Swim Speed", 3f, "Peak speed when sprinting while swimming.", true, true, true, (AcceptableValueBase)(object)new AcceptableValueRange<float>(2f, 5f), (Action<ConfigEntryBase>)null, (ConfigurationManagerAttributes)null);
			ColorDarknessFactor = ConfigFileExtensions.BindConfigInOrder<float>(((BaseUnityPlugin)this).Config, "Global", "Color Darkness Factor", 0.0092f, "How quickly colors become darker as you dive deeper.", false, true, true, (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 1f), (Action<ConfigEntryBase>)null, (ConfigurationManagerAttributes)null);
			FogDensityFactor = ConfigFileExtensions.BindConfigInOrder<float>(((BaseUnityPlugin)this).Config, "Global", "Fog Density Factor", 0.00092f, "How quickly the fog gets thicker as you dive deeper.", false, true, true, (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 0.5f), (Action<ConfigEntryBase>)null, (ConfigurationManagerAttributes)null);
			MinFogDensity = ConfigFileExtensions.BindConfigInOrder<float>(((BaseUnityPlugin)this).Config, "Global", "Min Fog Density", 0.1f, "Minimum fog density underwater regardless of depth.", false, true, true, (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.05f, 1f), (Action<ConfigEntryBase>)null, (ConfigurationManagerAttributes)null);
			MaxFogDensity = ConfigFileExtensions.BindConfigInOrder<float>(((BaseUnityPlugin)this).Config, "Global", "Max Fog Density", 2f, "Maximum fog density underwater regardless of depth.", false, true, true, (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 5f), (Action<ConfigEntryBase>)null, (ConfigurationManagerAttributes)null);
		}

		public void OnDestroy()
		{
			((BaseUnityPlugin)this).Config.Save();
		}

		public bool IsEnvAllowed()
		{
			return EnvMan.instance.GetCurrentEnvironment().m_name != "SunkenCrypt";
		}
	}
	internal static class Utils
	{
		public static bool TryGetDiver(Character character, out Diver diver)
		{
			if (!IsValidLocalPlayer(character, out var player))
			{
				diver = null;
				return false;
			}
			return ((Component)player).TryGetComponent<Diver>(ref diver);
		}

		public static bool TryGetDiver(Player player, out Diver diver)
		{
			if (!IsValidLocalPlayer(player))
			{
				diver = null;
				return false;
			}
			return ((Component)player).TryGetComponent<Diver>(ref diver);
		}

		public static bool IsValidLocalPlayer(Character character, out Player player)
		{
			if (Object.op_Implicit((Object)(object)character) && character.IsPlayer() && (Object)(object)character == (Object)(object)Player.m_localPlayer)
			{
				player = Player.m_localPlayer;
				return true;
			}
			player = null;
			return false;
		}

		public static bool IsValidLocalPlayer(Player player)
		{
			if (Object.op_Implicit((Object)(object)player))
			{
				return (Object)(object)player == (Object)(object)Player.m_localPlayer;
			}
			return false;
		}
	}
}
namespace UnderTheSea.Patches
{
	[HarmonyPatch]
	internal static class DivingPatches
	{
		private static bool InUpdateSwimming;

		[HarmonyPostfix]
		[HarmonyPatch(typeof(Player), "Awake")]
		private static void Player_Awake_Prefix(Player __instance)
		{
			((Component)__instance).gameObject.AddComponent<Diver>();
		}

		[HarmonyPrefix]
		[HarmonyPatch(typeof(Character), "UpdateMotion")]
		private static void Character_UpdateMotion_Prefix(Character __instance)
		{
			if (Utils.TryGetDiver(__instance, out var diver) && UnderTheSea.Instance.IsEnvAllowed())
			{
				diver.ResetSwimDepthIfNotInWater();
				if (diver.IsUnderSurface() && diver.IsInsideLiquid())
				{
					((Character)diver.player).m_lastGroundTouch = 0.3f;
					((Character)diver.player).m_swimTimer = 0f;
				}
			}
		}

		[HarmonyPrefix]
		[HarmonyPatch(typeof(Character), "UpdateSwimming")]
		public static void UpdateSwimming_Prefix(Character __instance, float dt, out Vector3? __state)
		{
			InUpdateSwimming = true;
			__state = null;
			if (Utils.TryGetDiver(__instance, out var diver))
			{
				diver.UpdateSwimSpeed(dt);
				if (ZInput.GetButton("Jump") && diver.IsUnderSurface())
				{
					diver.Dive(dt, ascend: true, out __state);
				}
				else if (ZInput.GetButton("Crouch") && diver.CanDive())
				{
					diver.Dive(dt, ascend: false, out __state);
				}
				else if ((__instance.IsOnGround() || !diver.IsDiving()) && !diver.IsRestingInWater())
				{
					diver.ResetSwimDepthToDefault();
				}
			}
		}

		[HarmonyPostfix]
		[HarmonyPatch(typeof(Character), "UpdateSwimming")]
		public static void UpdateSwimming_Postfix(Character __instance, float dt, ref Vector3? __state)
		{
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			InUpdateSwimming = false;
			if (__state.HasValue)
			{
				__instance.m_moveDir = __state.Value;
				__state = null;
			}
		}

		[HarmonyPrefix]
		[HarmonyPatch(typeof(Character), "UpdateRotation")]
		public static void UpdateRotation_Postfix(Character __instance, out Quaternion? __state)
		{
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			if (InUpdateSwimming)
			{
				__state = ((Component)__instance).transform.rotation;
			}
			else
			{
				__state = null;
			}
		}

		[HarmonyPostfix]
		[HarmonyPatch(typeof(Character), "UpdateRotation")]
		public static void UpdateRotation_Postfix(Character __instance, float turnSpeed, float dt, ref Quaternion? __state)
		{
			//IL_001e: 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_0073: 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_0078: Unknown result type (might be due to invalid IL or missing references)
			//IL_008e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0093: Unknown result type (might be due to invalid IL or missing references)
			//IL_0097: 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)
			if (InUpdateSwimming && __state.HasValue && Object.op_Implicit((Object)(object)__instance) && !(((Component)__instance).transform.rotation != __state.Value) && Utils.TryGetDiver(__instance, out var diver) && diver.IsUnderSurface())
			{
				Player player = diver.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")]
		public static void Player_OnSwimming_Prefix(Player __instance, Vector3 targetVel, float dt)
		{
			if (!(((Vector3)(ref targetVel)).magnitude >= 0.1f) && Utils.TryGetDiver(__instance, out var diver))
			{
				if (diver.IsDiving())
				{
					diver.DrainDivingStamina(dt);
					diver.UpdateSwimSkill(dt);
				}
				else if (diver.IsRestingInWater())
				{
					diver.RegenRestingStamina(dt);
				}
			}
		}
	}
	[HarmonyPatch]
	internal static class UseEquipPatches
	{
		private static readonly CodeMatch[] CodeMatches = (CodeMatch[])(object)new CodeMatch[5]
		{
			new CodeMatch((OpCode?)OpCodes.Ldarg_0, (object)null, (string)null),
			new CodeMatch((OpCode?)OpCodes.Call, (object)AccessTools.Method(typeof(Character), "IsSwimming", (Type[])null, (Type[])null), (string)null),
			new CodeMatch((OpCode?)OpCodes.Brfalse, (object)null, (string)null),
			new CodeMatch((OpCode?)OpCodes.Ldarg_0, (object)null, (string)null),
			new CodeMatch((OpCode?)OpCodes.Call, (object)AccessTools.Method(typeof(Character), "IsOnGround", (Type[])null, (Type[])null), (string)null)
		};

		private static readonly int InstructionMatchCount = CodeMatches.Length + 1;

		private static bool ShouldHideItem()
		{
			return !UnderTheSea.Instance.UseEquipInWater.Value;
		}

		[HarmonyTranspiler]
		[HarmonyPatch(typeof(Humanoid), "UpdateEquipment")]
		private static IEnumerable<CodeInstruction> UpdateEquipment_Transpiler(IEnumerable<CodeInstruction> instructions)
		{
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_000e: Expected O, but got Unknown
			//IL_007e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0088: Expected O, but got Unknown
			string text = "Humanoid.UpdateEquipment";
			CodeMatcher val = new CodeMatcher(instructions, (ILGenerator)null);
			val.MatchStartForward(CodeMatches).ThrowIfNotMatch("Failed to find match in " + text + "!", Array.Empty<CodeMatch>());
			val.Advance(InstructionMatchCount);
			return val.InsertAndAdvance((IEnumerable<CodeInstruction>)new List<CodeInstruction>
			{
				Transpilers.EmitDelegate<Func<bool>>((Func<bool>)ShouldHideItem),
				new CodeInstruction(OpCodes.Brfalse, val.InstructionAt(-1).operand)
			}).ThrowIfInvalid("Failed to patch " + text + "!").InstructionEnumeration();
		}

		[HarmonyTranspiler]
		[HarmonyPatch(typeof(Humanoid), "EquipItem")]
		private static IEnumerable<CodeInstruction> EquipItem_Transpiler(IEnumerable<CodeInstruction> instructions)
		{
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_000e: Expected O, but got Unknown
			//IL_007e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0088: Expected O, but got Unknown
			string text = "Humanoid.EquipItem";
			CodeMatcher val = new CodeMatcher(instructions, (ILGenerator)null);
			val.MatchStartForward(CodeMatches).ThrowIfNotMatch("Failed to find match in " + text + "!", Array.Empty<CodeMatch>());
			val.Advance(InstructionMatchCount);
			return val.InsertAndAdvance((IEnumerable<CodeInstruction>)new List<CodeInstruction>
			{
				Transpilers.EmitDelegate<Func<bool>>((Func<bool>)ShouldHideItem),
				new CodeInstruction(OpCodes.Brfalse, val.InstructionAt(-1).operand)
			}).ThrowIfInvalid("Failed to patch " + text + "!").InstructionEnumeration();
		}

		[HarmonyTranspiler]
		[HarmonyPatch(typeof(Player), "Update")]
		private static IEnumerable<CodeInstruction> UpdatePlayer_Transpiler(IEnumerable<CodeInstruction> instructions)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			return new CodeMatcher(instructions, (ILGenerator)null).MatchStartForward(CodeMatches).Advance(1).RemoveInstructions(InstructionMatchCount)
				.ThrowIfInvalid("Failed to patch Player.Update!")
				.InstructionEnumeration();
		}
	}
	[HarmonyPatch]
	internal static class WaterCameraPatches
	{
		private static float WaterLevelCamera;

		private static float WaterLevelPlayer;

		private static bool ShouldResetCamera;

		[HarmonyPrefix]
		[HarmonyPatch(typeof(GameCamera), "UpdateCamera")]
		private static void GameCamera_UpdateCamera_Prefix(GameCamera __instance)
		{
			//IL_006f: Unknown result type (might be due to invalid IL or missing references)
			//IL_016a: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ce: Unknown result type (might be due to invalid IL or missing references)
			//IL_00dc: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fa: 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_0101: Unknown result type (might be due to invalid IL or missing references)
			if (!Utils.TryGetDiver(Player.m_localPlayer, out var diver) || !Object.op_Implicit((Object)(object)__instance))
			{
				return;
			}
			Camera camera = __instance.m_camera;
			bool flag = diver.IsDiving() || ((Character)diver.player).IsSwimming();
			if (flag && !diver.IsRestingInWater() && UnderTheSea.Instance.IsEnvAllowed())
			{
				__instance.m_minWaterDistance = -5000f;
			}
			else
			{
				__instance.m_minWaterDistance = 0.3f;
			}
			if (((Component)camera).gameObject.transform.position.y < WaterLevelCamera && flag && UnderTheSea.Instance.IsEnvAllowed())
			{
				if (__instance.m_minWaterDistance != -5000f)
				{
					__instance.m_minWaterDistance = -5000f;
				}
				EnvSetup currentEnvironment = EnvMan.instance.GetCurrentEnvironment();
				Color color = ((!EnvMan.IsNight()) ? currentEnvironment.m_fogColorDay : currentEnvironment.m_fogColorNight);
				color.a = 1f;
				color = ChangeColorBrightness(color, ((Character)diver.player).m_swimDepth * (0f - UnderTheSea.Instance.ColorDarknessFactor.Value));
				RenderSettings.fogColor = color;
				RenderSettings.fogDensity = Mathf.Clamp(RenderSettings.fogDensity + ((Character)diver.player).m_swimDepth * UnderTheSea.Instance.FogDensityFactor.Value, UnderTheSea.Instance.MinFogDensity.Value, UnderTheSea.Instance.MaxFogDensity.Value);
				ShouldResetCamera = true;
			}
			else if (ShouldResetCamera && ((Component)camera).gameObject.transform.position.y > WaterLevelCamera)
			{
				EnvMan.instance.SetForceEnvironment(EnvMan.instance.GetCurrentEnvironment().m_name);
				EnvMan.instance.SetForceEnvironment(string.Empty);
				ShouldResetCamera = false;
			}
		}

		[HarmonyPrefix]
		[HarmonyPatch(typeof(WaterVolume), "UpdateMaterials")]
		private static void WaterVolume_UpdateMaterials_Prefix(WaterVolume __instance)
		{
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_0043: Unknown result type (might be due to invalid IL or missing references)
			//IL_006d: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c4: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c9: Unknown result type (might be due to invalid IL or missing references)
			//IL_01cc: Unknown result type (might be due to invalid IL or missing references)
			//IL_0096: Unknown result type (might be due to invalid IL or missing references)
			//IL_009b: Unknown result type (might be due to invalid IL or missing references)
			//IL_009e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0199: Unknown result type (might be due to invalid IL or missing references)
			//IL_019e: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a1: 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_01b7: Unknown result type (might be due to invalid IL or missing references)
			//IL_028d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0292: Unknown result type (might be due to invalid IL or missing references)
			//IL_0295: Unknown result type (might be due to invalid IL or missing references)
			//IL_02a0: Unknown result type (might be due to invalid IL or missing references)
			//IL_02ab: Unknown result type (might be due to invalid IL or missing references)
			if (!Object.op_Implicit((Object)(object)GameCamera.instance) || !Object.op_Implicit((Object)(object)Player.m_localPlayer))
			{
				return;
			}
			WaterLevelCamera = __instance.GetWaterSurface(((Component)GameCamera.instance).transform.position, 1f);
			WaterLevelPlayer = __instance.GetWaterSurface(((Component)Player.m_localPlayer).transform.position, 1f);
			MeshRenderer component = ((Component)__instance.m_waterSurface).GetComponent<MeshRenderer>();
			Quaternion rotation;
			if (((Component)GameCamera.instance).transform.position.y < WaterLevelCamera && ((Character)Player.m_localPlayer).IsSwimming())
			{
				rotation = ((Component)component).transform.rotation;
				if (((Quaternion)(ref rotation)).eulerAngles.y != 180f && UnderTheSea.Instance.IsEnvAllowed())
				{
					((Component)__instance.m_waterSurface).transform.Rotate(180f, 0f, 0f);
					((Renderer)__instance.m_waterSurface).shadowCastingMode = (ShadowCastingMode)2;
					if (__instance.m_forceDepth >= 0f)
					{
						((Renderer)__instance.m_waterSurface).material.SetFloatArray(Shader.PropertyToID("_depth"), new float[4] { __instance.m_forceDepth, __instance.m_forceDepth, __instance.m_forceDepth, __instance.m_forceDepth });
					}
					else
					{
						((Renderer)__instance.m_waterSurface).material.SetFloatArray(Shader.PropertyToID("_depth"), __instance.m_normalizedDepth);
					}
					((Renderer)__instance.m_waterSurface).material.SetFloat(Shader.PropertyToID("_UseGlobalWind"), __instance.m_useGlobalWind ? 1f : 0f);
				}
				Transform transform = ((Component)__instance.m_waterSurface).transform;
				Vector3 position = transform.position;
				((Vector3)(ref position))..ctor(position.x, WaterLevelCamera, position.z);
				transform.position = position;
				return;
			}
			rotation = ((Component)component).transform.rotation;
			if (((Quaternion)(ref rotation)).eulerAngles.y == 180f && UnderTheSea.Instance.IsEnvAllowed())
			{
				((Component)__instance.m_waterSurface).transform.Rotate(-180f, 0f, 0f);
				if (__instance.m_forceDepth >= 0f)
				{
					((Renderer)__instance.m_waterSurface).material.SetFloatArray(Shader.PropertyToID("_depth"), new float[4] { __instance.m_forceDepth, __instance.m_forceDepth, __instance.m_forceDepth, __instance.m_forceDepth });
				}
				else
				{
					((Renderer)__instance.m_waterSurface).material.SetFloatArray(Shader.PropertyToID("_depth"), __instance.m_normalizedDepth);
				}
				Transform transform2 = ((Component)__instance.m_waterSurface).transform;
				Vector3 position2 = transform2.position;
				((Vector3)(ref position2))..ctor(position2.x, 30f, position2.z);
				transform2.position = position2;
				((Renderer)__instance.m_waterSurface).material.SetFloat(Shader.PropertyToID("_UseGlobalWind"), __instance.m_useGlobalWind ? 1f : 0f);
			}
		}

		private static Color ChangeColorBrightness(Color color, float correctionFactor)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_000e: 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_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_0074: Unknown result type (might be due to invalid IL or missing references)
			//IL_007a: Unknown result type (might be due to invalid IL or missing references)
			float r = color.r;
			float g = color.g;
			float b = color.b;
			if (!(correctionFactor < 0f))
			{
				return new Color(r, g, b, color.a);
			}
			correctionFactor *= -1f;
			r -= r * correctionFactor;
			if (r < 0f)
			{
				r = 0f;
			}
			g -= g * correctionFactor;
			if (g < 0f)
			{
				g = 0f;
			}
			b -= b * correctionFactor;
			if (b < 0f)
			{
				b = 0f;
			}
			return new Color(r, g, b, color.a);
		}
	}
}
namespace Configs
{
	public static class ConfigFileExtensions
	{
		public static bool DisableSaveOnConfigSet(this ConfigFile configFile)
		{
			bool saveOnConfigSet = configFile.SaveOnConfigSet;
			configFile.SaveOnConfigSet = false;
			return saveOnConfigSet;
		}
	}
	internal sealed class ConfigFileWatcher
	{
		private const long RELOAD_DELAY = 10000000L;

		private DateTime lastReadTime = DateTime.MinValue;

		private readonly ConfigFile configFile;

		private readonly string ConfigFileDir;

		private readonly string ConfigFileName;

		internal event Action OnConfigFileReloaded;

		internal ConfigFileWatcher(ConfigFile configFile)
		{
			this.configFile = configFile;
			ConfigFileDir = Directory.GetParent(configFile.ConfigFilePath).FullName;
			ConfigFileName = Path.GetFileName(configFile.ConfigFilePath);
			FileSystemWatcher fileSystemWatcher = new FileSystemWatcher(ConfigFileDir, ConfigFileName);
			fileSystemWatcher.Changed += ReloadConfigFile;
			fileSystemWatcher.Created += ReloadConfigFile;
			fileSystemWatcher.Renamed += ReloadConfigFile;
			fileSystemWatcher.IncludeSubdirectories = true;
			fileSystemWatcher.SynchronizingObject = ThreadingHelper.SynchronizingObject;
			fileSystemWatcher.EnableRaisingEvents = true;
		}

		private void InvokeOnConfigFileReloaded()
		{
			this.OnConfigFileReloaded?.SafeInvoke();
		}

		internal void ReloadConfigFile(object sender, FileSystemEventArgs eventArgs)
		{
			DateTime now = DateTime.Now;
			long num = now.Ticks - lastReadTime.Ticks;
			if (!File.Exists(configFile.ConfigFilePath) || num < 10000000)
			{
				return;
			}
			try
			{
				Log.LogInfo("Reloading " + configFile.ConfigFilePath);
				bool saveOnConfigSet = configFile.DisableSaveOnConfigSet();
				configFile.Reload();
				configFile.SaveOnConfigSet = saveOnConfigSet;
				lastReadTime = now;
				InvokeOnConfigFileReloaded();
			}
			catch
			{
				Log.LogError("There was an issue loading " + configFile.ConfigFilePath);
				Log.LogError("Please check your config entries for spelling and format!");
			}
		}
	}
	internal static class SafeInvokeEvent
	{
		internal static void SafeInvoke(this Action events)
		{
			if (events == null)
			{
				return;
			}
			Delegate[] invocationList = events.GetInvocationList();
			for (int i = 0; i < invocationList.Length; i++)
			{
				Action action = (Action)invocationList[i];
				try
				{
					action();
				}
				catch (Exception arg)
				{
					Log.LogWarning("Exception thrown at event " + new StackFrame(1).GetMethod().Name + $" in {action.Method.DeclaringType.Name}.{action.Method.Name}:\n{arg}");
				}
			}
		}
	}
}