Decompiled source of VBDiving v0.0.4

VBDiving.dll

Decompiled 2 days ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Reflection.Emit;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using System.Security.Permissions;
using System.Text;
using BepInEx;
using BepInEx.Configuration;
using HarmonyLib;
using Jotunn;
using Jotunn.Entities;
using Jotunn.Extensions;
using Jotunn.Managers;
using Jotunn.Utils;
using Microsoft.CodeAnalysis;
using TMPro;
using UnityEngine;
using UnityEngine.Rendering;
using UnityEngine.UI;
using VBDiving.Effects;
using VBDiving.Mobs;
using VBDiving.Patches;
using YamlDotNet.Serialization;
using YamlDotNet.Serialization.NamingConventions;

[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.3")]
[assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.0.3.0")]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableAttribute : Attribute
	{
		public readonly byte[] NullableFlags;

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

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

		public NullableContextAttribute(byte P_0)
		{
			Flag = P_0;
		}
	}
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace VBDiving
{
	internal class BreathHud : MonoBehaviour
	{
		private GameObject _root;

		private RectTransform _container;

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

		private Sprite _bubbleSprite;

		private TextMeshProUGUI _breathText;

		private float _cachedOffsetX;

		private float _cachedOffsetY;

		private float _cachedScale;

		private bool _cachedShowLabels;

		private const int MaxBubbles = 12;

		private const float BubbleSize = 12f;

		private void Awake()
		{
			CreateHud();
		}

		private void Start()
		{
			ApplyPositionAndScale();
		}

		private void Update()
		{
			Player localPlayer = Player.m_localPlayer;
			if (!Object.op_Implicit((Object)(object)localPlayer) || !Object.op_Implicit((Object)(object)Camera.main))
			{
				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.IsHeadUnderwater(localPlayer);
			bool flag2 = currentBreath < maxBreath - 0.01f;
			bool flag3 = flag || flag2;
			SetVisible(flag3);
			if (flag3)
			{
				float skillLevel = ((Character)localPlayer).GetSkillLevel((SkillType)103);
				UpdateBubblesHorizontal(percent, skillLevel);
				if (Object.op_Implicit((Object)(object)_breathText) && ((Component)_breathText).gameObject.activeSelf)
				{
					((TMP_Text)_breathText).text = $"{Mathf.CeilToInt(currentBreath)}";
				}
			}
		}

		private void UpdateBubblesHorizontal(float percent, float swimSkillLevel)
		{
			//IL_015a: Unknown result type (might be due to invalid IL or missing references)
			//IL_017b: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cf: Unknown result type (might be due to invalid IL or missing references)
			//IL_011a: Unknown result type (might be due to invalid IL or missing references)
			int num = 2 + Mathf.FloorToInt(swimSkillLevel / 10f);
			num = Mathf.Clamp(num, 2, 12);
			int num2 = Mathf.CeilToInt(percent * (float)num);
			float num3 = 12f;
			float num4 = (float)num * 12f;
			float num5 = 0f - num4 / 2f + 6f;
			for (int i = 0; i < _bubbles.Count; i++)
			{
				Image val = _bubbles[i];
				bool flag = i < num;
				((Component)val).gameObject.SetActive(flag);
				if (flag)
				{
					bool flag2 = i < num2;
					float num6 = num5 + (float)i * num3;
					if (flag2)
					{
						RectTransform rectTransform = ((Graphic)val).rectTransform;
						float num7 = Mathf.Sin(Time.time * 5f + (float)i * 0.5f) * 2f;
						rectTransform.anchoredPosition = new Vector2(num6, num7);
						float num8 = 0.6f + 0.4f * Mathf.PingPong(Time.time * 2f + (float)i * 0.3f, 1f);
						((Graphic)val).color = new Color(0.8f, 0.92f, 1f, num8);
					}
					else
					{
						RectTransform rectTransform2 = ((Graphic)val).rectTransform;
						float num9 = Mathf.Sin(Time.time * 5f + (float)i * 0.5f) * 2f;
						rectTransform2.anchoredPosition = new Vector2(num6, num9);
						((Graphic)val).color = new Color(0.3f, 0.4f, 0.5f, 0.3f);
					}
				}
			}
		}

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

		private void ApplyPositionAndScale()
		{
			//IL_0048: 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)
			if (Object.op_Implicit((Object)(object)_container))
			{
				float value = VBDiving.BreathHudOffsetX.Value;
				float value2 = VBDiving.BreathHudOffsetY.Value;
				float value3 = VBDiving.BreathHudScale.Value;
				ApplyPosition(value, value2);
				((Transform)_container).localScale = Vector3.one * value3;
				_cachedOffsetX = value;
				_cachedOffsetY = value2;
				_cachedScale = value3;
				_cachedShowLabels = VBDiving.BreathHudShowLabels.Value;
				if (Object.op_Implicit((Object)(object)_breathText))
				{
					((Component)_breathText).gameObject.SetActive(_cachedShowLabels);
				}
			}
		}

		private void ApplyPosition(float offsetXPercent, float offsetYPercent)
		{
			//IL_0028: 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_005e: 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 (Object.op_Implicit((Object)(object)_container))
			{
				_container.anchorMin = new Vector2(0.5f, 0.5f);
				_container.anchorMax = new Vector2(0.5f, 0.5f);
				_container.pivot = new Vector2(0.5f, 0.5f);
				float num = offsetXPercent / 100f * (float)Screen.width;
				float num2 = offsetYPercent / 100f * (float)Screen.height;
				_container.anchoredPosition = new Vector2(num, num2);
				if (VBDiving.DebugLogging.Value)
				{
					VBDiving.LogDebug($"BreathHud position applied: X={num}, Y={num2}");
				}
			}
		}

		private void SetVisible(bool visible)
		{
			if (Object.op_Implicit((Object)(object)_root) && _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_0084: Unknown result type (might be due to invalid IL or missing references)
			//IL_008a: Expected O, but got Unknown
			//IL_00c0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fa: Expected O, but got Unknown
			//IL_0123: Unknown result type (might be due to invalid IL or missing references)
			//IL_013a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0151: Unknown result type (might be due to invalid IL or missing references)
			//IL_0168: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a9: 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_01e4: Expected O, but got Unknown
			//IL_0263: 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_029e: Unknown result type (might be due to invalid IL or missing references)
			//IL_02b5: Unknown result type (might be due to invalid IL or missing references)
			//IL_02cc: Unknown result type (might be due to invalid IL or missing references)
			//IL_02e3: 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);
			val2.matchWidthOrHeight = 0.5f;
			_root.AddComponent<GraphicRaycaster>();
			GameObject val3 = new GameObject("Container");
			val3.transform.SetParent(_root.transform, false);
			_container = val3.AddComponent<RectTransform>();
			float num = 144f;
			_container.sizeDelta = new Vector2(num, 30f);
			_bubbleSprite = CreateBubbleSprite(64);
			for (int i = 0; i < 12; 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);
				val5.anchorMin = new Vector2(0.5f, 0.5f);
				val5.anchorMax = new Vector2(0.5f, 0.5f);
				val5.pivot = new Vector2(0.5f, 0.5f);
				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<TextMeshProUGUI>();
			((TMP_Text)_breathText).fontSize = 16f;
			((TMP_Text)_breathText).fontSizeMin = 10f;
			((TMP_Text)_breathText).fontSizeMax = 24f;
			((TMP_Text)_breathText).alignment = (TextAlignmentOptions)4097;
			((Graphic)_breathText).color = new Color(0.8f, 0.92f, 1f, 0.9f);
			RectTransform rectTransform = ((TMP_Text)_breathText).rectTransform;
			rectTransform.sizeDelta = new Vector2(60f, 25f);
			rectTransform.anchorMin = new Vector2(1f, 0.5f);
			rectTransform.anchorMax = new Vector2(1f, 0.5f);
			rectTransform.pivot = new Vector2(0f, 0.5f);
			rectTransform.anchoredPosition = new Vector2(8f, 0f);
			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 sealed class PlayerDiveController : MonoBehaviour
	{
		private const float HeadUnderwaterTolerance = 0.01f;

		internal const float DefaultSwimDepth = 1.3f;

		internal const float DivingThreshold = 1.5f;

		internal const float MinSwimDepth = 1.3f;

		internal const float MaxSwimDepth = 100f;

		internal const float DepthChangeSpeed = 0.025f;

		private const float LegacyDepthChangeSpeed = 0.04f;

		[NonSerialized]
		internal bool toggleDive;

		[NonSerialized]
		internal bool is_diving;

		[NonSerialized]
		internal bool isUnderwater;

		[NonSerialized]
		internal string lastDiveCancel = "None";

		private bool _underwaterMovementActive;

		private float _baseSwimSpeed;

		private int _swimmingUpdateContextDepth;

		private int _swimmingUpdateContextFrame = -1;

		private float _diveAxis;

		private float _legacyDiveVertical;

		private bool _legacyDiveActive;

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

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


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

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

		internal void HandleDiveToggle()
		{
			if (!((Character)Player).InWater() || ((Character)Player).IsOnGround() || !((Character)Player).IsSwimming())
			{
				if (toggleDive)
				{
					toggleDive = false;
					is_diving = false;
					_legacyDiveActive = false;
					_legacyDiveVertical = 0f;
					lastDiveCancel = "PlayerOnLand";
				}
			}
			else if (VBDiving.UseLegacyDiveControls.Value)
			{
				HandleLegacyControls();
			}
			else if (ZInput.GetButtonDown("Crouch") || ZInput.GetButtonDown("JoyCrouch"))
			{
				if (!toggleDive)
				{
					toggleDive = true;
					lastDiveCancel = "None";
				}
				else if (toggleDive && ((Character)Player).m_swimDepth <= 1.5f)
				{
					toggleDive = false;
					lastDiveCancel = "PlayerCancelled";
				}
			}
		}

		private void HandleLegacyControls()
		{
			bool flag = ZInput.GetButton("Crouch") || ZInput.GetButton("JoyCrouch");
			bool flag2 = ZInput.GetButton("Jump") || ZInput.GetButton("JoyJump");
			if (flag && !flag2)
			{
				toggleDive = true;
				_legacyDiveActive = true;
				_legacyDiveVertical = 1f;
				lastDiveCancel = "None";
			}
			else if (flag2 && !flag)
			{
				_legacyDiveActive = true;
				_legacyDiveVertical = -1f;
				if (((Character)Player).m_swimDepth <= 1.4f)
				{
					toggleDive = false;
					_legacyDiveActive = false;
					_legacyDiveVertical = 0f;
					lastDiveCancel = "PlayerSurfaced";
				}
			}
			else if (flag && flag2)
			{
				toggleDive = true;
				_legacyDiveActive = true;
				_legacyDiveVertical = 1f;
			}
			else
			{
				_legacyDiveVertical = 0f;
				if (((Character)Player).m_swimDepth <= 1.5f)
				{
					toggleDive = false;
					_legacyDiveActive = false;
					lastDiveCancel = "PlayerSurfaced";
				}
				else
				{
					_legacyDiveActive = false;
				}
			}
		}

		internal void UpdateDiveState()
		{
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_007c: Unknown result type (might be due to invalid IL or missing references)
			if (ShieldGenerator.IsInsideShield(((Component)Player).transform.position))
			{
				DisableUnderwaterMovement();
				return;
			}
			if (!((Character)Player).InWater())
			{
				((Character)Player).m_swimDepth = 1.3f;
				return;
			}
			if (((Character)Player).m_swimDepth > 1.5f && Mathf.Max(0f, ((Character)Player).GetLiquidLevel() - ((Component)Player).transform.position.y) > 1.5f)
			{
				is_diving = true;
				isUnderwater = true;
				return;
			}
			if (is_diving)
			{
				is_diving = false;
				if (!VBDiving.UseLegacyDiveControls.Value || ((Character)Player).m_swimDepth <= 1.4f)
				{
					toggleDive = false;
				}
				lastDiveCancel = "PlayerSurfaced";
			}
			isUnderwater = false;
		}

		internal void UpdateDiveDepth(Vector3 lookDir)
		{
			//IL_0062: Unknown result type (might be due to invalid IL or missing references)
			//IL_0080: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d5: Unknown result type (might be due to invalid IL or missing references)
			//IL_0125: Unknown result type (might be due to invalid IL or missing references)
			//IL_013c: Unknown result type (might be due to invalid IL or missing references)
			//IL_019e: 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_01a1: Unknown result type (might be due to invalid IL or missing references)
			//IL_0224: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c5: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ca: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f5: Unknown result type (might be due to invalid IL or missing references)
			//IL_01fb: Unknown result type (might be due to invalid IL or missing references)
			//IL_0200: Unknown result type (might be due to invalid IL or missing references)
			//IL_0207: Unknown result type (might be due to invalid IL or missing references)
			//IL_020c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0211: Unknown result type (might be due to invalid IL or missing references)
			//IL_0215: Unknown result type (might be due to invalid IL or missing references)
			//IL_021a: Unknown result type (might be due to invalid IL or missing references)
			if (!((Character)Player).InWater() || ((Character)Player).IsOnGround() || !((Character)Player).IsSwimming())
			{
				return;
			}
			if (VBDiving.UseLegacyDiveControls.Value)
			{
				UpdateLegacyDiveMovement();
			}
			else
			{
				if (!toggleDive)
				{
					return;
				}
				if (lookDir.y < -0.15f)
				{
					_diveAxis = 1f;
				}
				else if (lookDir.y > 0.15f)
				{
					_diveAxis = 0f;
				}
				if (!ZInput.GetButton("Forward") && !ZInput.GetButton("JoyLStickUp"))
				{
					return;
				}
				float num2;
				if (_diveAxis == 1f)
				{
					float num = Mathf.Abs(lookDir.y);
					num2 = num * 0.025f;
					if (num2 < 0.005f && num > 0.9f)
					{
						num2 = 0.005f;
					}
				}
				else if (_diveAxis == 0f)
				{
					num2 = lookDir.y * 0.025f;
					if (num2 < 0.005f && lookDir.y > 0.9f)
					{
						num2 = 0.005f;
					}
				}
				else
				{
					num2 = 0f;
				}
				if (num2 > 0.025f)
				{
					num2 = 0.025f;
				}
				ApplyVerticalMovement(num2);
				if (!(((Character)Player).m_swimDepth > 1.5f))
				{
					return;
				}
				Vector3 moveDir = lookDir;
				if (Mathf.Abs(lookDir.y) > 0.95f)
				{
					Vector3 forward = ((Component)Player).transform.forward;
					forward.y = 0f;
					if (((Vector3)(ref forward)).magnitude > 0.01f)
					{
						((Vector3)(ref forward)).Normalize();
						Vector3 val = lookDir * 0.7f + forward * 0.3f;
						moveDir = ((Vector3)(ref val)).normalized;
					}
				}
				((Character)Player).SetMoveDir(moveDir);
			}
		}

		private void UpdateLegacyDiveMovement()
		{
			//IL_0184: Unknown result type (might be due to invalid IL or missing references)
			//IL_0189: Unknown result type (might be due to invalid IL or missing references)
			//IL_018d: 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_00a7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ac: 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_00bc: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f6: Unknown result type (might be due to invalid IL or missing references)
			//IL_01fb: Unknown result type (might be due to invalid IL or missing references)
			//IL_01bb: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c5: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ca: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d4: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d9: Unknown result type (might be due to invalid IL or missing references)
			//IL_01de: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e2: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e7: Unknown result type (might be due to invalid IL or missing references)
			//IL_0119: Unknown result type (might be due to invalid IL or missing references)
			//IL_011e: Unknown result type (might be due to invalid IL or missing references)
			//IL_00de: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ed: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fc: Unknown result type (might be due to invalid IL or missing references)
			//IL_0101: Unknown result type (might be due to invalid IL or missing references)
			//IL_0105: Unknown result type (might be due to invalid IL or missing references)
			//IL_010a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0226: Unknown result type (might be due to invalid IL or missing references)
			//IL_0230: Unknown result type (might be due to invalid IL or missing references)
			//IL_0235: Unknown result type (might be due to invalid IL or missing references)
			//IL_023f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0244: 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_024d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0252: Unknown result type (might be due to invalid IL or missing references)
			//IL_021d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0222: Unknown result type (might be due to invalid IL or missing references)
			//IL_0149: Unknown result type (might be due to invalid IL or missing references)
			//IL_0153: Unknown result type (might be due to invalid IL or missing references)
			//IL_0158: Unknown result type (might be due to invalid IL or missing references)
			//IL_0162: Unknown result type (might be due to invalid IL or missing references)
			//IL_0167: Unknown result type (might be due to invalid IL or missing references)
			//IL_016c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0170: Unknown result type (might be due to invalid IL or missing references)
			//IL_0175: Unknown result type (might be due to invalid IL or missing references)
			//IL_0140: Unknown result type (might be due to invalid IL or missing references)
			//IL_0145: Unknown result type (might be due to invalid IL or missing references)
			//IL_025b: Unknown result type (might be due to invalid IL or missing references)
			float legacyDiveVertical = _legacyDiveVertical;
			if (Mathf.Abs(legacyDiveVertical) < 0.01f)
			{
				return;
			}
			if (legacyDiveVertical < 0f && ((Character)Player).m_swimDepth <= 1.3f)
			{
				((Character)Player).m_swimDepth = 1.3f;
				return;
			}
			float num = legacyDiveVertical * 0.04f;
			float num2 = ((Character)Player).m_swimDepth + num;
			num2 = Mathf.Clamp(num2, 1.3f, 100f);
			((Character)Player).m_swimDepth = num2;
			Vector3 val2;
			Vector3 normalized;
			if (legacyDiveVertical > 0f)
			{
				Vector3 lookDir = ((Character)Player).GetLookDir();
				Vector3 val = default(Vector3);
				((Vector3)(ref val))..ctor(lookDir.x, 0f, lookDir.z);
				if (((Vector3)(ref val)).magnitude > 0.1f)
				{
					val2 = ((Vector3)(ref val)).normalized * 0.7f + Vector3.down * 0.3f;
					normalized = ((Vector3)(ref val2)).normalized;
				}
				else
				{
					Vector3 forward = ((Component)Player).transform.forward;
					forward.y = 0f;
					if (((Vector3)(ref forward)).magnitude < 0.1f)
					{
						forward = Vector3.forward;
					}
					val2 = ((Vector3)(ref forward)).normalized * 0.3f + Vector3.down * 0.7f;
					normalized = ((Vector3)(ref val2)).normalized;
				}
			}
			else
			{
				Vector3 lookDir2 = ((Character)Player).GetLookDir();
				Vector3 val3 = default(Vector3);
				((Vector3)(ref val3))..ctor(lookDir2.x, 0f, lookDir2.z);
				if (((Vector3)(ref val3)).magnitude > 0.1f)
				{
					val2 = ((Vector3)(ref val3)).normalized * 0.7f + Vector3.up * 0.3f;
					normalized = ((Vector3)(ref val2)).normalized;
				}
				else
				{
					Vector3 forward2 = ((Component)Player).transform.forward;
					forward2.y = 0f;
					if (((Vector3)(ref forward2)).magnitude < 0.1f)
					{
						forward2 = Vector3.forward;
					}
					val2 = ((Vector3)(ref forward2)).normalized * 0.3f + Vector3.up * 0.7f;
					normalized = ((Vector3)(ref val2)).normalized;
				}
			}
			((Character)Player).SetMoveDir(normalized);
		}

		private void ApplyVerticalMovement(float multiplier)
		{
			if (_diveAxis == 1f)
			{
				Player player = Player;
				((Character)player).m_swimDepth = ((Character)player).m_swimDepth + multiplier;
			}
			else if (_diveAxis == 0f)
			{
				if (((Character)Player).m_swimDepth > 1.3f)
				{
					Player player2 = Player;
					((Character)player2).m_swimDepth = ((Character)player2).m_swimDepth - multiplier;
				}
				if (((Character)Player).m_swimDepth < 1.3f)
				{
					((Character)Player).m_swimDepth = 1.3f;
				}
			}
			if (((Character)Player).m_swimDepth > 100f)
			{
				((Character)Player).m_swimDepth = 100f;
			}
		}

		internal void DisableUnderwaterMovement()
		{
			_underwaterMovementActive = false;
			toggleDive = false;
			is_diving = false;
			_legacyDiveActive = false;
			_legacyDiveVertical = 0f;
			ResetSwimDepthToDefault();
			((Character)Player).m_swimSpeed = _baseSwimSpeed;
		}

		internal void ResetSwimDepthIfNotInWater()
		{
			if (!WaterHelper.IsBodyInWater(Player))
			{
				DisableUnderwaterMovement();
			}
		}

		internal void ResetSwimDepthToDefault()
		{
			//IL_0056: Unknown result type (might be due to invalid IL or missing references)
			//IL_005b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0075: Unknown result type (might be due to invalid IL or missing references)
			((Character)Player).m_swimDepth = 1.3f;
			if (WaterHelper.IsBodyInWater(Player) && !toggleDive && !is_diving && !_legacyDiveActive)
			{
				float liquidLevel = ((Character)Player).GetLiquidLevel();
				Vector3 position = ((Component)Player).transform.position;
				position.y = liquidLevel - 1.3f;
				((Component)Player).transform.position = position;
			}
		}

		internal bool CanDive()
		{
			if (!WaterHelper.IsBodyInWater(Player) || ((Character)Player).IsOnGround())
			{
				return false;
			}
			return true;
		}

		internal bool IsHeadUnderwater()
		{
			//IL_0035: 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)
			float num = (Object.op_Implicit((Object)(object)((Character)Player).m_eye) ? ((Character)Player).m_eye.position.y : ((Component)Player).transform.position.y);
			return ((Character)Player).GetLiquidLevel() - num > 0.01f;
		}

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

		internal bool ShouldForceSwimming()
		{
			return _underwaterMovementActive && WaterHelper.IsBodyInWater(Player) && IsHeadUnderwater();
		}

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

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

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

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

		internal bool IsIdleInWater()
		{
			//IL_0028: 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)
			int result;
			if (WaterHelper.IsBodyInWater(Player) && (WaterHelper.IsBodyInWater(Player) || ShouldForceSwimming()))
			{
				Vector3 velocity = ((Character)Player).GetVelocity();
				result = ((((Vector3)(ref velocity)).magnitude < 1f) ? 1 : 0);
			}
			else
			{
				result = 0;
			}
			return (byte)result != 0;
		}

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

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

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

		internal void UpdateSwimSpeed()
		{
			float num = 1f;
			if (InputHelper.GetRun())
			{
				float skillFactor = Player.m_skills.GetSkillFactor((SkillType)103);
				float num2 = Mathf.Max(1f, VBDiving.SprintSwimMultiplier.Value);
				num = Mathf.Lerp(1f, num2, Mathf.Pow(skillFactor, 1.5f));
			}
			((Character)Player).m_swimSpeed = _baseSwimSpeed * num;
		}
	}
	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.op_Implicit((Object)(object)player))
			{
				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.op_Implicit((Object)(object)player))
			{
				return false;
			}
			return WaterHelper.IsHeadUnderwater(player);
		}

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

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

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

		public static float GetMaxBreath(Player player)
		{
			if (!Object.op_Implicit((Object)(object)player))
			{
				return VBDiving.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.op_Implicit((Object)(object)player))
			{
				return 0f;
			}
			return ((Character)player).GetSkillFactor((SkillType)103);
		}

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

		public static float GetExternalSwimSpeedMultiplier(Player player)
		{
			if (!Object.op_Implicit((Object)(object)player))
			{
				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.op_Implicit((Object)(object)player) && !(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.op_Implicit((Object)(object)player) && !(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.op_Implicit((Object)(object)player) && !(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.op_Implicit((Object)(object)player))
			{
				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.op_Implicit((Object)(object)player))
			{
				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.op_Implicit((Object)(object)player) && !(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.op_Implicit((Object)(object)player))
			{
				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("VitByr.VBDiving", "VBDiving", "0.0.4")]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[BepInIncompatibility("sighsorry.DiveIn")]
	[BepInIncompatibility("ch.easy.develope.vh.diving.mod")]
	[BepInIncompatibility("blacks7ar.VikingsDoSwim")]
	[BepInIncompatibility("projjm.improvedswimming")]
	[BepInIncompatibility("dzk.SwimmingReworked")]
	[SynchronizationMode(/*Could not decode attribute arguments.*/)]
	internal class VBDiving : BaseUnityPlugin
	{
		public const string PluginGUID = "VitByr.VBDiving";

		public const string PluginName = "VBDiving";

		public const string PluginVersion = "0.0.4";

		internal static VBDiving Instance;

		internal static Harmony Harmony;

		internal static ConfigEntry<bool> EnableMod;

		internal static ConfigEntry<float> MaxBreathSeconds;

		internal static ConfigEntry<float> MaxBreathBonusAtSkill100;

		internal static ConfigEntry<float> BreathRecoveryPerSecond;

		internal static ConfigEntry<float> SprintSwimMultiplier;

		internal static ConfigEntry<float> BaseUnderwaterStaminaRegenPerSecond;

		internal static ConfigEntry<bool> DebugLogging;

		internal static ConfigEntry<bool> UseLegacyDiveControls;

		internal static float SwimStaminaDrainMinSkill = 4f;

		internal static float SwimStaminaDrainMaxSkill = 2f;

		internal static ConfigEntry<float> BreathHudOffsetX;

		internal static ConfigEntry<float> BreathHudOffsetY;

		internal static ConfigEntry<float> BreathHudScale;

		internal static ConfigEntry<bool> BreathHudShowLabels;

		internal static ConfigEntry<bool> SyncMonsterConfigs;

		internal static ConfigEntry<bool> UseServerMonsterConfigsOnly;

		private ConfigFileWatcher _configWatcher;

		internal static string ConfigFolderPath;

		private CustomRPC _monsterConfigRPC;

		private bool _hasRequestedConfigs;

		private void Awake()
		{
			//IL_0087: Unknown result type (might be due to invalid IL or missing references)
			//IL_0091: Expected O, but got Unknown
			Instance = this;
			ConfigFolderPath = Path.Combine(Paths.ConfigPath, "VitByr", "VBDiving");
			Directory.CreateDirectory(ConfigFolderPath);
			CreateConfig();
			CreateConfigWatcher();
			SynchronizationManager.OnConfigurationSynchronized += OnConfigurationSynchronized;
			SynchronizationManager.OnAdminStatusChanged += OnAdminStatusChanged;
			((Component)this).gameObject.AddComponent<BreathHud>();
			((Component)this).gameObject.AddComponent<DiveImmersionEffect>();
			((MonoBehaviour)this).StartCoroutine(InitDiveControllerWhenReady());
			Harmony = new Harmony("VitByr.VBDiving");
			Harmony.PatchAll();
			SetupMonsterConfigSync();
			MonsterDiveSystem.Initialize();
		}

		private IEnumerator InitDiveControllerWhenReady()
		{
			while (!Object.op_Implicit((Object)(object)Player.m_localPlayer))
			{
				yield return null;
			}
			Player player = Player.m_localPlayer;
			PlayerDiveController playerDiveController = default(PlayerDiveController);
			if (!((Component)player).TryGetComponent<PlayerDiveController>(ref playerDiveController))
			{
				((Component)player).gameObject.AddComponent<PlayerDiveController>();
				((BaseUnityPlugin)this).Logger.LogDebug((object)"DiveController added to local player");
			}
		}

		private void SetupMonsterConfigSync()
		{
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0029: Expected O, but got Unknown
			//IL_0029: Expected O, but got Unknown
			_monsterConfigRPC = NetworkManager.Instance.AddRPC("VBDiving_SyncMonsterConfigs", new CoroutineHandler(OnServerReceiveRequest), new CoroutineHandler(OnClientReceiveConfigs));
			if ((Object)(object)ZNet.instance != (Object)null && ZNet.instance.IsServer())
			{
				((BaseUnityPlugin)this).Logger.LogInfo((object)"[VBDiving] Server mode: loading monster configs");
				MonsterDiveSystem.LoadAllMonsterDiveConfigs();
			}
			else if ((Object)(object)ZNet.instance != (Object)null && ZNetExtension.IsClientInstance(ZNet.instance))
			{
				((BaseUnityPlugin)this).Logger.LogInfo((object)"[VBDiving] Client mode: will request monster configs from server");
			}
		}

		private IEnumerator OnServerReceiveRequest(long sender, ZPackage package)
		{
			int flag = package.ReadInt();
			((BaseUnityPlugin)this).Logger.LogInfo((object)$"[VBDiving] Server received request from client {sender}, flag={flag}");
			if (flag == 0)
			{
				SendMonsterConfigsToClient(sender);
			}
			yield break;
		}

		private IEnumerator OnClientReceiveConfigs(long sender, ZPackage package)
		{
			int flag = package.ReadInt();
			((BaseUnityPlugin)this).Logger.LogInfo((object)$"[VBDiving] Client received configs from server, flag={flag}");
			if (flag == 1)
			{
				string configData = package.ReadString();
				((BaseUnityPlugin)this).Logger.LogInfo((object)$"[VBDiving] Received monster configs from server ({configData.Length} bytes)");
				if (string.IsNullOrEmpty(configData))
				{
					((BaseUnityPlugin)this).Logger.LogWarning((object)"[VBDiving] Received empty config data from server");
				}
				else if (UseServerMonsterConfigsOnly.Value)
				{
					((BaseUnityPlugin)this).Logger.LogInfo((object)"[VBDiving] Using server configs only (ignoring local)");
					MonsterDiveSystem.LoadSerializedConfigs(configData, useServerOnly: true);
				}
				else
				{
					((BaseUnityPlugin)this).Logger.LogInfo((object)"[VBDiving] Merging server configs with local (server priority)");
					MonsterDiveSystem.LoadSerializedConfigs(configData);
				}
			}
			yield break;
		}

		private void SendMonsterConfigsToAllClients()
		{
			//IL_0071: Unknown result type (might be due to invalid IL or missing references)
			//IL_0077: Expected O, but got Unknown
			if (!SyncMonsterConfigs.Value)
			{
				((BaseUnityPlugin)this).Logger.LogInfo((object)"[VBDiving] SyncMonsterConfigs is disabled, not sending");
				return;
			}
			string serializedConfigs = MonsterDiveSystem.GetSerializedConfigs();
			if (string.IsNullOrEmpty(serializedConfigs))
			{
				((BaseUnityPlugin)this).Logger.LogWarning((object)"[VBDiving] No configs to send to clients");
				return;
			}
			((BaseUnityPlugin)this).Logger.LogInfo((object)$"[VBDiving] Sending monster configs to all clients ({serializedConfigs.Length} bytes)");
			ZPackage val = new ZPackage();
			val.Write(1);
			val.Write(serializedConfigs);
			foreach (ZNetPeer peer in ZNet.instance.m_peers)
			{
				if (peer.m_uid != ZRoutedRpc.instance.GetServerPeerID())
				{
					_monsterConfigRPC.SendPackage(peer.m_uid, val);
				}
			}
		}

		private void SendMonsterConfigsToClient(long clientId)
		{
			//IL_00b1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b7: Expected O, but got Unknown
			if (!SyncMonsterConfigs.Value)
			{
				((BaseUnityPlugin)this).Logger.LogInfo((object)"[VBDiving] SyncMonsterConfigs is disabled, not sending to client");
				return;
			}
			string serializedConfigs = MonsterDiveSystem.GetSerializedConfigs();
			if (string.IsNullOrEmpty(serializedConfigs))
			{
				((BaseUnityPlugin)this).Logger.LogWarning((object)$"[VBDiving] No configs to send to client {clientId}");
				return;
			}
			((BaseUnityPlugin)this).Logger.LogInfo((object)$"[VBDiving] Sending monster configs to client {clientId} ({serializedConfigs.Length} bytes)");
			((BaseUnityPlugin)this).Logger.LogDebug((object)("[VBDiving] Configs preview: " + serializedConfigs.Substring(0, Math.Min(200, serializedConfigs.Length)) + "..."));
			ZPackage val = new ZPackage();
			val.Write(1);
			val.Write(serializedConfigs);
			_monsterConfigRPC.SendPackage(clientId, val);
		}

		internal static void RequestMonsterConfigsFromServer()
		{
			//IL_007a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0080: Expected O, but got Unknown
			if (!((Object)(object)Instance == (Object)null) && !((Object)(object)ZNet.instance == (Object)null) && !ZNet.instance.IsServer() && SyncMonsterConfigs.Value && !Instance._hasRequestedConfigs)
			{
				Instance._hasRequestedConfigs = true;
				((BaseUnityPlugin)Instance).Logger.LogInfo((object)"[VBDiving] Requesting monster configs from server...");
				ZPackage val = new ZPackage();
				val.Write(0);
				Instance._monsterConfigRPC.SendPackage(ZRoutedRpc.instance.GetServerPeerID(), val);
			}
		}

		internal static void OnServerConfigsChanged()
		{
			if ((Object)(object)Instance != (Object)null && (Object)(object)ZNet.instance != (Object)null && ZNet.instance.IsServer() && SyncMonsterConfigs.Value)
			{
				((BaseUnityPlugin)Instance).Logger.LogInfo((object)"[VBDiving] Server configs changed, sending updates to all clients");
				Instance.SendMonsterConfigsToAllClients();
			}
		}

		private void CreateConfig()
		{
			//IL_01e8: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f2: Expected O, but got Unknown
			((BaseUnityPlugin)this).Config.SaveOnConfigSet = false;
			EnableMod = ConfigFileExtensions.BindConfig<bool>(((BaseUnityPlugin)this).Config, "00 - Main", "EnableMod", true, "Включить или отключить мод.", true, (int?)null, (AcceptableValueBase)null, (Action<ConfigEntryBase>)null, (ConfigurationManagerAttributes)null);
			SyncMonsterConfigs = ConfigFileExtensions.BindConfig<bool>(((BaseUnityPlugin)this).Config, "00 - Main", "SyncMonsterConfigs", true, "Синхронизировать конфиги монстров с сервера.", true, (int?)null, (AcceptableValueBase)null, (Action<ConfigEntryBase>)null, (ConfigurationManagerAttributes)null);
			UseServerMonsterConfigsOnly = ConfigFileExtensions.BindConfig<bool>(((BaseUnityPlugin)this).Config, "00 - Main", "UseServerMonsterConfigsOnly", true, "Использовать ТОЛЬКО конфиги с сервера (игнорировать локальные файлы). Если false - серверные конфиги имеют приоритет над локальными.", true, (int?)null, (AcceptableValueBase)null, (Action<ConfigEntryBase>)null, (ConfigurationManagerAttributes)null);
			UseLegacyDiveControls = ((BaseUnityPlugin)this).Config.Bind<bool>("01 - Control", "UseLegacyDiveControls", true, "Если true: зажать Crouch для погружения, Jump для всплытия.\nЕсли false: нажать Crouch для переключения режима ныряния, затем направление взгляда + Forward для движения вверх/вниз.");
			MaxBreathSeconds = ConfigFileExtensions.BindConfig<float>(((BaseUnityPlugin)this).Config, "02 - Breath", "MaxBreathSeconds", 30f, "Максимальное время под водой при навыке плавания 0.", true, (int?)null, (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 600f), (Action<ConfigEntryBase>)null, (ConfigurationManagerAttributes)null);
			MaxBreathBonusAtSkill100 = ConfigFileExtensions.BindConfig<float>(((BaseUnityPlugin)this).Config, "02 - Breath", "MaxBreathBonusAtSkill100", 150f, "Дополнительное время под водой при навыке плавания 100.", true, (int?)null, (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 600f), (Action<ConfigEntryBase>)null, (ConfigurationManagerAttributes)null);
			BreathRecoveryPerSecond = ConfigFileExtensions.BindConfig<float>(((BaseUnityPlugin)this).Config, "02 - Breath", "BreathRecoveryPerSecond", 30f, "Скорость восстановления дыхания.", true, (int?)null, (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 300f), (Action<ConfigEntryBase>)null, (ConfigurationManagerAttributes)null);
			BreathHudOffsetX = ((BaseUnityPlugin)this).Config.Bind<float>("03 - BreathHud", "OffsetX", 0f, "Смещение индикатора по горизонтали от центра экрана (в процентах от ширины экрана).\nОтрицательное = левее, положительное = правее.");
			BreathHudOffsetY = ((BaseUnityPlugin)this).Config.Bind<float>("03 - BreathHud", "OffsetY", -30f, "Смещение индикатора по вертикали от центра экрана (в процентах от высоты экрана).\nОтрицательное = ниже, положительное = выше.");
			BreathHudScale = ((BaseUnityPlugin)this).Config.Bind<float>("03 - BreathHud", "Scale", 1f, new ConfigDescription("Масштаб индикатора дыхания.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.3f, 3f), Array.Empty<object>()));
			BreathHudShowLabels = ((BaseUnityPlugin)this).Config.Bind<bool>("03 - BreathHud", "ShowLabels", true, "Показывать числовое значение дыхания справа от пузырьков.");
			SprintSwimMultiplier = ConfigFileExtensions.BindConfig<float>(((BaseUnityPlugin)this).Config, "04 - Swimming", "SprintSwimMultiplier", 2.25f, "Множитель скорости при спринте в воде.", true, (int?)null, (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 5f), (Action<ConfigEntryBase>)null, (ConfigurationManagerAttributes)null);
			BaseUnderwaterStaminaRegenPerSecond = ConfigFileExtensions.BindConfig<float>(((BaseUnityPlugin)this).Config, "04 - Swimming", "BaseUnderwaterStaminaRegenPerSecond", 1.25f, "Базовая скорость восстановления выносливости на поверхности без движения.", true, (int?)null, (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 50f), (Action<ConfigEntryBase>)null, (ConfigurationManagerAttributes)null);
			PlayerEquipInWater.EquipInWaterList = ConfigFileExtensions.BindConfig<string>(((BaseUnityPlugin)this).Config, "06 - EquipInWater", "EiW_Custom", "KnifeFlint,KnifeCopper,KnifeChitin,KnifeSilver,KnifeBlackMetal,KnifeButcher,KnifeSkollAndHati,SpearFlint,SpearBronze,SpearElderbark,SpearWolfFang,SpearChitin,SpearCarapace,PickaxeAntler,PickaxeBronze,PickaxeIron,PickaxeBlackMetal,Hammer,Hoe,FistFenrirClaw", "Разрешить использовать оружие/инструмент в воде", true, (int?)null, (AcceptableValueBase)null, (Action<ConfigEntryBase>)null, (ConfigurationManagerAttributes)null);
			PlayerEquipInWater.EquipInWaterList.SettingChanged += delegate
			{
				HashSet<string> hashSet2 = new HashSet<string>();
				string[] array2 = PlayerEquipInWater.EquipInWaterList.Value.Split(new char[1] { ',' }, StringSplitOptions.RemoveEmptyEntries);
				foreach (string item2 in array2)
				{
					hashSet2.Add(item2);
				}
				PlayerEquipInWater.EquipInWaterItems = hashSet2;
			};
			HashSet<string> hashSet = new HashSet<string>();
			string[] array = PlayerEquipInWater.EquipInWaterList.Value.Split(new char[1] { ',' }, StringSplitOptions.RemoveEmptyEntries);
			foreach (string item in array)
			{
				hashSet.Add(item);
			}
			PlayerEquipInWater.EquipInWaterItems = hashSet;
			DebugLogging = ((BaseUnityPlugin)this).Config.Bind<bool>("Debug", "DebugLogging", false, "Включить отладочные логи.");
			((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.");
			};
		}

		internal static float GetClampedSkillFactor(Player player, SkillType skillType)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			float skillLevel = ((Character)player).GetSkillLevel(skillType);
			float num = Mathf.Min(skillLevel, 100f);
			return num / 100f;
		}

		internal static float GetClampedSwimFactor(Player player)
		{
			float skillLevel = ((Character)player).GetSkillLevel((SkillType)103);
			float num = Mathf.Min(skillLevel, 100f);
			return num / 100f;
		}

		private void OnConfigurationSynchronized(object sender, ConfigurationSynchronizationEventArgs e)
		{
			if (e.InitialSynchronization)
			{
				((BaseUnityPlugin)this).Logger.LogInfo((object)"Initial config sync received.");
				if ((Object)(object)ZNet.instance != (Object)null && ZNetExtension.IsClientInstance(ZNet.instance))
				{
					((MonoBehaviour)this).StartCoroutine(RequestConfigsAfterSync());
				}
			}
			else
			{
				((BaseUnityPlugin)this).Logger.LogInfo((object)"Config sync update received.");
			}
			if ((Object)(object)ZNet.instance != (Object)null && ZNet.instance.IsServer() && SyncMonsterConfigs.Value)
			{
				SendMonsterConfigsToAllClients();
			}
		}

		private IEnumerator RequestConfigsAfterSync()
		{
			yield return (object)new WaitForSeconds(2f);
			RequestMonsterConfigsFromServer();
		}

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

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

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

		internal static void LogDebug(string msg)
		{
			if (Object.op_Implicit((Object)(object)Instance) && 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.op_Implicit((Object)(object)player))
			{
				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_001c: 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_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_0023: 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_0027: Unknown result type (might be due to invalid IL or missing references)
			if (!Object.op_Implicit((Object)(object)player))
			{
				return Vector3.zero;
			}
			return ((Character)player).GetHeadPoint();
		}

		public static Vector3 GetChestPosition(Player player)
		{
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_0030: Unknown result type (might be due to invalid IL or missing references)
			//IL_0035: Unknown result type (might be due to invalid IL or missing references)
			//IL_003a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_003c: Unknown result type (might be due to invalid IL or missing references)
			//IL_003d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0040: Unknown result type (might be due to invalid IL or missing references)
			if (!Object.op_Implicit((Object)(object)player))
			{
				return Vector3.zero;
			}
			return ((Component)player).transform.position + Vector3.up * 1f;
		}

		public static bool IsBodyInWater(Player player)
		{
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			if (!Object.op_Implicit((Object)(object)player))
			{
				return false;
			}
			Vector3 chestPosition = GetChestPosition(player);
			float waterLevel;
			return TryGetWaterLevel(chestPosition, out waterLevel) && chestPosition.y < waterLevel;
		}

		public static bool IsHeadUnderwater(Player player)
		{
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			if (!Object.op_Implicit((Object)(object)player))
			{
				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_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			if (!Object.op_Implicit((Object)(object)player))
			{
				return false;
			}
			Vector3 headPosition = GetHeadPosition(player);
			float waterLevel;
			return TryGetWaterLevel(headPosition, out waterLevel) && Mathf.Abs(headPosition.y - waterLevel) <= tolerance;
		}
	}
}
namespace VBDiving.Patches
{
	[HarmonyPatch(typeof(Character), "CustomFixedUpdate")]
	internal static class CharacterSurfaceFix
	{
		[HarmonyPostfix]
		private static void Postfix(Character __instance)
		{
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0031: Expected O, but got Unknown
			//IL_0098: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bb: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e7: Unknown result type (might be due to invalid IL or missing references)
			//IL_0102: Unknown result type (might be due to invalid IL or missing references)
			//IL_011f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0124: Unknown result type (might be due to invalid IL or missing references)
			//IL_0128: 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)
			if (!VBDiving.IsEnabled() || (Object)(object)__instance != (Object)(object)Player.m_localPlayer)
			{
				return;
			}
			Player val = (Player)__instance;
			if (!WaterHelper.IsBodyInWater(val))
			{
				return;
			}
			PlayerDiveController localInstance = PlayerDiveController.LocalInstance;
			if (!Object.op_Implicit((Object)(object)localInstance) || localInstance.toggleDive || localInstance.is_diving || localInstance.IsHeadUnderwater())
			{
				return;
			}
			float liquidLevel = ((Character)val).GetLiquidLevel();
			float num = liquidLevel - 1.3f;
			if (((Component)val).transform.position.y < num - 0.1f)
			{
				Vector3 position = ((Component)val).transform.position;
				position.y = Mathf.Lerp(position.y, num, Time.fixedDeltaTime * 8f);
				((Component)val).transform.position = position;
				Rigidbody component = ((Component)val).GetComponent<Rigidbody>();
				if (Object.op_Implicit((Object)(object)component) && component.linearVelocity.y < 0f)
				{
					Vector3 linearVelocity = component.linearVelocity;
					linearVelocity.y = Mathf.Max(linearVelocity.y, 0f);
					component.linearVelocity = linearVelocity;
				}
			}
			((Character)val).m_swimDepth = 1.3f;
		}
	}
	[HarmonyPatch]
	internal static class CharacterWaterStatePatch
	{
		[HarmonyPostfix]
		[HarmonyPatch(typeof(Character), "IsOnGround")]
		private static void CharacterIsOnGroundPostfix(Character __instance, ref bool __result)
		{
			if (VBDiving.IsEnabled())
			{
				Player val = (Player)(object)((__instance is Player) ? __instance : null);
				if (Object.op_Implicit((Object)(object)val) && !((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 (VBDiving.IsEnabled())
			{
				Player val = (Player)(object)((__instance is Player) ? __instance : null);
				if (Object.op_Implicit((Object)(object)val) && !((Object)(object)val != (Object)(object)Player.m_localPlayer) && WaterHelper.IsBodyInWater(val))
				{
					__result = true;
				}
			}
		}
	}
	[HarmonyPatch]
	internal static class DiveControllerPatches
	{
		[HarmonyPostfix]
		[HarmonyPatch(typeof(Player), "Awake")]
		private static void PlayerAwakePostfix(Player __instance)
		{
			if ((Object)(object)__instance == (Object)(object)Player.m_localPlayer)
			{
				EnsureLocalDiver();
			}
		}

		[HarmonyPrefix]
		[HarmonyPatch(typeof(Character), "UpdateMotion")]
		private static void CharacterUpdateMotionPrefix(Character __instance, ref float ___m_lastGroundTouch, ref float ___m_swimTimer)
		{
			if ((Object)(object)__instance != (Object)(object)Player.m_localPlayer)
			{
				return;
			}
			PlayerDiveController playerDiveController = EnsureLocalDiver();
			if (Object.op_Implicit((Object)(object)playerDiveController))
			{
				playerDiveController.ResetSwimDepthIfNotInWater();
				if (playerDiveController.is_diving || WaterHelper.IsBodyInWater((Player)(object)((__instance is Player) ? __instance : null)))
				{
					___m_lastGroundTouch = 0.3f;
					___m_swimTimer = 0f;
				}
			}
		}

		[HarmonyPrefix]
		[HarmonyPatch(typeof(Character), "UpdateSwimming")]
		private static void CharacterUpdateSwimmingPrefix(Character __instance)
		{
			if ((Object)(object)__instance != (Object)(object)Player.m_localPlayer)
			{
				return;
			}
			Player val = (Player)(object)((__instance is Player) ? __instance : null);
			if (Object.op_Implicit((Object)(object)val))
			{
				PlayerDiveController playerDiveController = EnsureLocalDiver();
				if (Object.op_Implicit((Object)(object)playerDiveController))
				{
					playerDiveController.UpdateSwimSpeed();
					ApplySwimStaminaSettings(val);
				}
			}
		}

		private static void ApplySwimStaminaSettings(Player player)
		{
			if (WaterHelper.IsBodyInWater(player))
			{
				float num = VBDiving.SwimStaminaDrainMinSkill;
				float num2 = VBDiving.SwimStaminaDrainMaxSkill;
				if (WaterHelper.IsHeadUnderwater(player))
				{
					num *= 2f;
					num2 *= 2f;
				}
				if (InputHelper.GetRun() && player.GetStamina() > 0f)
				{
					num *= 1.5f;
					num2 *= 1.5f;
				}
				player.m_swimStaminaDrainMinSkill = num;
				player.m_swimStaminaDrainMaxSkill = num2;
			}
		}

		[HarmonyPrefix]
		[HarmonyPatch(typeof(Character), "CustomFixedUpdate")]
		private static void CharacterCustomFixedUpdatePrefix(Character __instance, ref Vector3 ___m_moveDir, ref Vector3 ___m_lookDir)
		{
			//IL_0094: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)__instance != (Object)(object)Player.m_localPlayer || !__instance.IsPlayer())
			{
				return;
			}
			PlayerDiveController playerDiveController = EnsureLocalDiver();
			if (Object.op_Implicit((Object)(object)playerDiveController))
			{
				playerDiveController.HandleDiveToggle();
				playerDiveController.UpdateDiveState();
				if (!__instance.InWater())
				{
					__instance.m_swimDepth = 1.3f;
				}
				else if (playerDiveController.toggleDive && __instance.InWater() && !__instance.IsOnGround() && __instance.IsSwimming())
				{
					playerDiveController.UpdateDiveDepth(___m_lookDir);
				}
				else if ((__instance.IsOnGround() || !playerDiveController.is_diving) && !playerDiveController.isUnderwater)
				{
					__instance.m_swimDepth = 1.3f;
				}
			}
		}

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

		[HarmonyPostfix]
		[HarmonyPatch(typeof(Character), "UpdateRotation")]
		private static void CharacterUpdateRotationPostfix(Character __instance, float turnSpeed, float dt, ref Quaternion? __state)
		{
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0099: 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)
			//IL_007f: 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_00b4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bd: Unknown result type (might be due to invalid IL or missing references)
			//IL_008c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0091: Unknown result type (might be due to invalid IL or missing references)
			if (__state.HasValue && Object.op_Implicit((Object)(object)__instance) && !((Object)(object)__instance != (Object)(object)Player.m_localPlayer) && !(((Component)__instance).transform.rotation != __state.Value))
			{
				PlayerDiveController localInstance = PlayerDiveController.LocalInstance;
				if (Object.op_Implicit((Object)(object)localInstance) && localInstance.is_diving)
				{
					Player player = localInstance.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), "SetControls")]
		private static void PlayerSetControlsPrefix(Player __instance, ref bool crouch)
		{
			if ((Object)(object)__instance == (Object)(object)Player.m_localPlayer && ((Character)__instance).InWater())
			{
				crouch = false;
			}
		}

		private static PlayerDiveController? EnsureLocalDiver()
		{
			Player localPlayer = Player.m_localPlayer;
			if (!Object.op_Implicit((Object)(object)localPlayer))
			{
				return null;
			}
			PlayerDiveController playerDiveController = PlayerDiveController.LocalInstance;
			if (Object.op_Implicit((Object)(object)playerDiveController) && (Object)(object)playerDiveController.Player == (Object)(object)localPlayer)
			{
				return playerDiveController;
			}
			if (!((Component)localPlayer).TryGetComponent<PlayerDiveController>(ref playerDiveController))
			{
				playerDiveController = ((Component)localPlayer).gameObject.AddComponent<PlayerDiveController>();
			}
			return playerDiveController;
		}
	}
	[HarmonyPatch(typeof(GameCamera), "UpdateCamera")]
	internal static class GameCameraPatch
	{
		private static float _originalMaxDistance;

		private static float _originalMinWaterDistance;

		private static bool _cachedOriginalValues;

		[HarmonyPrefix]
		private static void Prefix(GameCamera __instance, Camera ___m_camera)
		{
			if (!VBDiving.IsEnabled())
			{
				return;
			}
			Player localPlayer = Player.m_localPlayer;
			if (Object.op_Implicit((Object)(object)localPlayer) && Object.op_Implicit((Object)(object)___m_camera))
			{
				PlayerDiveController localInstance = PlayerDiveController.LocalInstance;
				if (!_cachedOriginalValues)
				{
					_originalMaxDistance = __instance.m_maxDistance;
					_originalMinWaterDistance = __instance.m_minWaterDistance;
					_cachedOriginalValues = true;
				}
				bool flag = Object.op_Implicit((Object)(object)localInstance) && localInstance.toggleDive;
				bool flag2 = Object.op_Implicit((Object)(object)localInstance) && localInstance.is_diving;
				if (flag || flag2)
				{
					__instance.m_minWaterDistance = -5000f;
					return;
				}
				__instance.m_minWaterDistance = _originalMinWaterDistance;
				__instance.m_maxDistance = _originalMaxDistance;
			}
		}

		[HarmonyPostfix]
		private static void Postfix(GameCamera __instance, Camera ___m_camera)
		{
			//IL_0073: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ed: Unknown result type (might be due to invalid IL or missing references)
			//IL_008c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0106: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cd: Unknown result type (might be due to invalid IL or missing references)
			//IL_012f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0134: Unknown result type (might be due to invalid IL or missing references)
			//IL_0145: Unknown result type (might be due to invalid IL or missing references)
			if (!VBDiving.IsEnabled())
			{
				return;
			}
			Player localPlayer = Player.m_localPlayer;
			if (!Object.op_Implicit((Object)(object)localPlayer) || !Object.op_Implicit((Object)(object)___m_camera))
			{
				return;
			}
			PlayerDiveController localInstance = PlayerDiveController.LocalInstance;
			bool flag = Object.op_Implicit((Object)(object)localInstance) && localInstance.toggleDive;
			bool flag2 = Object.op_Implicit((Object)(object)localInstance) && localInstance.is_diving;
			float waterLevel2;
			if (flag || flag2)
			{
				if (WaterHelper.TryGetWaterLevel(((Component)___m_camera).transform.position, out var waterLevel))
				{
					float y = ((Component)___m_camera).transform.position.y;
					if (y > waterLevel - 0.5f)
					{
						Vector3 position = ((Component)___m_camera).transform.position;
						position.y = waterLevel - 0.5f;
						((Component)___m_camera).transform.position = position;
					}
				}
			}
			else if (WaterHelper.IsBodyInWater(localPlayer) && WaterHelper.TryGetWaterLevel(((Component)___m_camera).transform.position, out waterLevel2))
			{
				float y2 = ((Component)___m_camera).transform.position.y;
				float num = waterLevel2 + 0.3f;
				if (y2 < num)
				{
					Vector3 position2 = ((Component)___m_camera).transform.position;
					position2.y = num;
					((Component)___m_camera).transform.position = position2;
				}
			}
		}
	}
	[HarmonyPatch]
	internal static class PlayerEquipInWater
	{
		internal static ConfigEntry<string> EquipInWaterList;

		internal static HashSet<string> EquipInWaterItems = new HashSet<string>();

		private static readonly CodeMatch[] Matches = (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)
		};

		public static bool VB_CheckWaterItem(ItemData item)
		{
			if (item == null)
			{
				HandleNullItemCase();
				return false;
			}
			return IsItemAllowed(item.m_shared.m_name);
		}

		private static void HandleNullItemCase()
		{
			Player localPlayer = Player.m_localPlayer;
			if (Object.op_Implicit((Object)(object)localPlayer))
			{
				CheckAndUnequipItem(((Humanoid)localPlayer).m_leftItem);
				CheckAndUnequipItem(((Humanoid)localPlayer).m_rightItem);
			}
		}

		private static void CheckAndUnequipItem(ItemData item)
		{
			if (item != null && !IsItemAllowed(((Object)item.m_dropPrefab).name))
			{
				Player localPlayer = Player.m_localPlayer;
				if (localPlayer != null)
				{
					((Humanoid)localPlayer).UnequipItem(item, true);
				}
			}
		}

		private static bool IsItemAllowed(string itemName)
		{
			return EquipInWaterItems.Contains(itemName);
		}

		private static IEnumerable<MethodBase> TargetMethods()
		{
			return new <>z__ReadOnlyArray<MethodBase>(new MethodBase[3]
			{
				AccessTools.Method(typeof(Player), "Update", (Type[])null, (Type[])null),
				AccessTools.Method(typeof(Humanoid), "EquipItem", (Type[])null, (Type[])null),
				AccessTools.Method(typeof(Humanoid), "UpdateEquipment", (Type[])null, (Type[])null)
			});
		}

		public static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instructions, MethodBase original)
		{
			//IL_0003: Unknown result type (might be due to invalid IL or missing references)
			CodeMatcher val = new CodeMatcher(instructions, (ILGenerator)null).MatchStartForward(Matches);
			try
			{
				switch (original.Name)
				{
				case "Update":
					val.Advance(1).RemoveInstructions(6);
					break;
				case "EquipItem":
					val.Advance(6).Insert((IEnumerable<CodeInstruction>)GenerateInjectionCode(val, OpCodes.Ldarg_1));
					break;
				case "UpdateEquipment":
					val.Advance(6).Insert((IEnumerable<CodeInstruction>)GenerateInjectionCode(val, OpCodes.Ldnull));
					break;
				}
			}
			catch (ArgumentException ex)
			{
				Debug.LogError((object)("IL Transpiler Error in VB_EquipInWater: " + ex.Message));
				Debug.LogError((object)"Plugin initialization failed. Valheim will shutdown.");
				Environment.Exit(1);
			}
			return val.InstructionEnumeration();
		}

		private static List<CodeInstruction> GenerateInjectionCode(CodeMatcher matcher, OpCode loadOpCode)
		{
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0014: Expected O, but got Unknown
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0039: Expected O, but got Unknown
			//IL_004c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0056: Expected O, but got Unknown
			List<CodeInstruction> list = new List<CodeInstruction>();
			list.Add(new CodeInstruction(loadOpCode, (object)null));
			list.Add(new CodeInstruction(OpCodes.Call, (object)typeof(PlayerEquipInWater).GetMethod("VB_CheckWaterItem")));
			list.Add(new CodeInstruction(OpCodes.Brfalse, matcher.InstructionAt(-1).operand));
			return list;
		}
	}
	[HarmonyPatch(typeof(Player), "FixedUpdate")]
	internal static class PlayerFixedUpdatePatch
	{
		private static void Postfix(Player __instance)
		{
			//IL_00c0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cb: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00da: Unknown result type (might be due to invalid IL or missing references)
			if (!VBDiving.IsEnabled() || !Object.op_Implicit((Object)(object)__instance) || (Object)(object)__instance != (Object)(object)Player.m_localPlayer || ((Character)__instance).IsDebugFlying())
			{
				return;
			}
			bool flag = WaterHelper.IsBodyInWater(__instance);
			bool flag2 = WaterHelper.IsHeadUnderwater(__instance);
			Rigidbody component = ((Component)__instance).GetComponent<Rigidbody>();
			if (!Object.op_Implicit((Object)(object)component))
			{
				return;
			}
			if (!flag)
			{
				Traverse.Create((object)__instance).Field("m_staminaRegenTimer").SetValue((object)0f);
				component.useGravity = true;
				HandleBreath(__instance, headUnderwater: false);
				return;
			}
			component.useGravity = true;
			HandleBreath(__instance, flag2);
			Vector2 val = new Vector2(component.linearVelocity.x, component.linearVelocity.z);
			float magnitude = ((Vector2)(ref val)).magnitude;
			bool flag3 = magnitude > 0.5f;
			if (!flag2 && !IsDivingDeep(__instance) && !flag3)
			{
				Traverse.Create((object)__instance).Field("m_staminaRegenTimer").SetValue((object)0f);
				HandleWaterStaminaRegen(__instance);
			}
			else
			{
				Traverse.Create((object)__instance).Field("m_staminaRegenTimer").SetValue((object)10f);
			}
			PlayerDiveController localInstance = PlayerDiveController.LocalInstance;
			if (Object.op_Implicit((Object)(object)localInstance))
			{
				localInstance.UpdateSwimSpeed();
			}
		}

		private static bool IsDivingDeep(Player player)
		{
			PlayerDiveController localInstance = PlayerDiveController.LocalInstance;
			if (Object.op_Implicit((Object)(object)localInstance))
			{
				return localInstance.toggleDive || localInstance.is_diving || localInstance.IsUnderSurface();
			}
			return ((Character)player).m_swimDepth > 1.4f;
		}

		private static void HandleBreath(Player player, bool headUnderwater)
		{
			SwimState swimState = SwimStateManager.Get(player);
			float fixedDeltaTime = Time.fixedDeltaTime;
			float maxBreath = SwimAPI.GetMaxBreath(player);
			if (headUnderwater)
			{
				swimState.Breath -= fixedDeltaTime;
				if (swimState.Breath < 0f)
				{
					swimState.Breath = 0f;
				}
				if (swimState.Breath <= 0f && ((Character)player).HaveStamina(0f))
				{
					((Character)player).UseStamina(5f * fixedDeltaTime);
				}
			}
			else
			{
				swimState.Breath += VBDiving.BreathRecoveryPerSecond.Value * fixedDeltaTime;
				if (swimState.Breath > maxBreath)
				{
					swimState.Breath = maxBreath;
				}
			}
			SwimAPI.UpdateEvents(player);
			swimState.WasHeadUnderwater = headUnderwater;
		}

		private static void HandleWaterStaminaRegen(Player player)
		{
			float value = VBDiving.BaseUnderwaterStaminaRegenPerSecond.Value;
			float value2 = Traverse.Create((object)player).Field("m_stamina").GetValue<float>();
			float maxStamina = ((Character)player).GetMaxStamina();
			if (value2 < maxStamina)
			{
				value2 += value * Time.fixedDeltaTime;
				if (value2 > maxStamina)
				{
					value2 = maxStamina;
				}
				Traverse.Create((object)player).Field("m_stamina").SetValue((object)value2);
			}
		}
	}
	[HarmonyPatch(typeof(Player), "UpdateStats", new Type[] { typeof(float) })]
	internal static class PlayerUpdateStatsPatch
	{
		private static void Postfix(Player __instance, float dt)
		{
			if (VBDiving.IsEnabled() && Object.op_Implicit((Object)(object)__instance) && !((Object)(object)__instance != (Object)(object)Player.m_localPlayer) && WaterHelper.IsBodyInWater(__instance))
			{
				bool flag = WaterHelper.IsHeadUnderwater(__instance);
				PlayerDiveController localInstance = PlayerDiveController.LocalInstance;
				bool flag2 = Object.op_Implicit((Object)(object)localInstance) && (localInstance.toggleDive || localInstance.is_diving || localInstance.IsUnderSurface());
				if (flag || flag2)
				{
					Traverse.Create((object)__instance).Field("m_staminaRegenTimer").SetValue((object)float.MaxValue);
				}
				if (Object.op_Implicit((Object)(object)localInstance))
				{
					localInstance.UpdateSwimSpeed();
				}
			}
		}
	}
	[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.02f;

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

		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("VBDiving_UnderwaterSurface");
			val.transform.SetParent(original.transform, false);
			val.transform.localPosition = new Vector3(0f, -0.05f, 0f);
			val.transform.localRotation = Quaternion.Euler(180f, 0f, 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_003a: 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)
			if (!Object.op_Implicit((Object)(object)GameCamera.instance))
			{
				return false;
			}
			Camera component = ((Component)GameCamera.instance).GetComponent<Camera>();
			if (!Object.op_Implicit((Object)(object)component))
			{
				return false;
			}
			if (!WaterHelper.TryGetWaterLevel(((Component)component).transform.position, out var waterLevel))
			{
				return false;
			}
			return ((Component)component).transform.position.y < waterLevel - 0.15f;
		}
	}
	[HarmonyPatch(typeof(Player), "UseStamina")]
	internal static class UseStaminaPatch
	{
		private static bool AllowStaminaUseFromSwimSprint;

		private static bool Prefix(Player __instance, ref float v)
		{
			if (!VBDiving.IsEnabled())
			{
				return true;
			}
			if (AllowStaminaUseFromSwimSprint)
			{
				return true;
			}
			if (!Object.op_Implicit((Object)(object)__instance) || (Object)(object)__instance != (Object)(object)Player.m_localPlayer)
			{
				return true;
			}
			if (!WaterHelper.IsBodyInWater(__instance))
			{
				return true;
			}
			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 (VBDiving.IsEnabled() && Object.op_Implicit((Object)(object)__instance.m_waterSurface))
			{
				MeshRenderer waterSurface = __instance.m_waterSurface;
				if (!Object.op_Implicit((Object)(object)_instanceMaterial) || (Object)(object)_lastRenderer != (Object)(object)waterSurface)
				{
					_instanceMaterial = ((Renderer)waterSurface).material;
					_lastRenderer = waterSurface;
					SaveOriginalValues(_instanceMaterial);
				}
				if (_instanceMaterial.HasProperty(CullId))
				{
					_instanceMaterial.SetInt(CullId, 0);
				}
				if (Object.op_Implicit((Object)(object)PlayerDiveController.LocalInstance) && PlayerDiveController.LocalInstance.isUnderwater)
				{
					ApplyUnderwaterSettings(_instanceMaterial);
				}
				else
				{
					ApplyWaterSettings(_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 ApplyWaterSettings(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.2f, 0.25f, 0.2f, 0.95f));
			}
			if (mat.HasProperty(ColorBottomId))
			{
				mat.SetColor(ColorBottomId, new Color(0.15f, 0.2f, 0.2f, 0.95f));
			}
			if (mat.HasProperty(ColorBottomShallowId))
			{
				mat.SetColor(ColorBottomShallowId, new Color(0.2f, 0.25f, 0.2f, 0.95f));
			}
			if (mat.HasProperty(SurfaceColorId))
			{
				mat.SetColor(SurfaceColorId, new Color(0.3f, 0.35f, 0.35f, 0.95f));
			}
			if (mat.HasProperty(DepthFadeId))
			{
				mat.SetFloat(DepthFadeId, _originalDepthFade * 1f);
			}
		}

		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.2f, 0.25f, 0.2f, 0.95f));
			}
			if (mat.HasProperty(ColorBottomId))
			{
				mat.SetColor(ColorBottomId, new Color(0.15f, 0.2f, 0.2f, 0.95f));
			}
			if (mat.HasProperty(ColorBottomShallowId))
			{
				mat.SetColor(ColorBottomShallowId, new Color(0.2f, 0.25f, 0.2f, 0.95f));
			}
			if (mat.HasProperty(SurfaceColorId))
			{
				mat.SetColor(SurfaceColorId, new Color(0.3f, 0.35f, 0.35f, 0.95f));
			}
			if (mat.HasProperty(DepthFadeId))
			{
				mat.SetFloat(DepthFadeId, _originalDepthFade * 1.25f);
			}
		}
	}
}
namespace VBDiving.Mobs
{
	[HarmonyPatch]
	internal static class MonsterDivePatches
	{
		[HarmonyPostfix]
		[HarmonyPatch(typeof(MonsterAI), "Awake")]
		private static void MonsterAIAwakePostfix(MonsterAI __instance)
		{
			if (VBDiving.IsEnabled() && MonsterDiveSystem.IsConfiguredMonster(__instance))
			{
				MonsterDiveSystem.EnsureDiveFlags(__instance);
			}
		}

		[HarmonyPrefix]
		[HarmonyPatch(typeof(MonsterAI), "UpdateAI")]
		private static void MonsterAIUpdateAIPrefix(MonsterAI __instance)
		{
			if (VBDiving.IsEnabled() && MonsterDiveSystem.IsConfiguredMonster(__instance))
			{
				MonsterDiveSystem.EnsureDiveFlags(__instance);
			}
		}

		[HarmonyPrefix]
		[HarmonyPatch(typeof(BaseAI), "HavePath")]
		private static bool BaseAIHavePathPrefix(BaseAI __instance, Vector3 target, ref bool __result)
		{
			//IL_0064: Unknown result type (might be due to invalid IL or missing references)
			if (!VBDiving.IsEnabled())
			{
				return true;
			}
			MonsterAI val = (MonsterAI)(object)((__instance is MonsterAI) ? __instance : null);
			if (val == null)
			{
				return true;
			}
			if (!MonsterDiveSystem.IsConfiguredMonster(val) || !MonsterDiveSystem.ShouldUseWaterDiveMode(val))
			{
				return true;
			}
			Character character = ((BaseAI)val).m_character;
			if (!Object.op_Implicit((Object)(object)character))
			{
				return true;
			}
			__result = MonsterDiveSystem.HasReasonableUnderwaterRoute(__instance, character, target);
			return false;
		}

		[HarmonyPrefix]
		[HarmonyPatch(typeof(BaseAI), "MoveTo")]
		private static bool BaseAIMoveToPrefix(BaseAI __instance, float dt, Vector3 point, float dist, bool run, ref bool __result)
		{
			//IL_0075: Unknown result type (might be due to invalid IL or missing references)
			//IL_0094: Unknown result type (might be due to invalid IL or missing references)
			//IL_009b: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cc: Unknown result type (might be due to invalid IL or missing references)
			//IL_0119: Unknown result type (might be due to invalid IL or missing references)
			//IL_0120: Unknown result type (might be due to invalid IL or missing references)
			//IL_0125: Unknown result type (might be due to invalid IL or missing references)
			//IL_012a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0156: Unknown result type (might be due to invalid IL or missing references)
			//IL_0157: Unknown result type (might be due to invalid IL or missing references)
			//IL_015c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0187: Unknown result type (might be due to invalid IL or missing references)
			if (!VBDiving.IsEnabled())
			{
				return true;
			}
			MonsterAI val = (MonsterAI)(object)((__instance is MonsterAI) ? __instance : null);
			if (val == null)
			{
				return true;
			}
			if (!MonsterDiveSystem.IsConfiguredMonster(val) || !MonsterDiveSystem.ShouldUseWaterDiveMode(val))
			{
				return true;
			}
			Character character = ((BaseAI)val).m_character;
			if (!Object.op_Implicit((Object)(object)character))
			{
				return true;
			}
			float num = MonsterDiveSystem.UpdateSwimDepthTowardsTarget(val, character, point, dt);
			float num2 = Mathf.Max(dist, run ? 1f : 0.5f);
			float num3 = Utils.DistanceXZ(point, ((Component)__instance).transform.position);
			float num4 = Mathf.Abs(point.y - ((Component)__instance).transform.position.y);
			float num5 = Mathf.Abs(num - ((Component)__instance).transform.position.y);
			if (num3 < num2 && (num4 < 0.75f || num5 < 0.35f))
			{
				__instance.StopMoving();
				__result = true;
				return false;
			}
			Vector3 val2 = point - ((Component)__instance).transform.position;
			if (((Vector3)(ref val2)).sqrMagnitude <= 0.0001f)
			{
				__instance.StopMoving();
				__result = true;
				return false;
			}
			Vector3 val3 = MonsterDiveSystem.BuildSteerDirectionWithAvoidance(__instance, character, point);
			if (((Vector3)(ref val3)).sqrMagnitude <= 0.0001f)
			{
				__instance.StopMoving();
				__result = true;
				return false;
			}
			__instance.MoveTowards(val3, run);
			__result = false;
			return false;
		}

		[HarmonyPrefix]
		[HarmonyPatch(typeof(Character), "IsOnGround")]
		private static bool CharacterIsOnGroundPrefix(Character __instance, ref bool __result)
		{
			if (!VBDiving.IsEnabled())
			{
				return true;
			}
			if (__instance is Player)
			{
				return true;
			}
			MonsterAI component = ((Component)__instance).GetComponent<MonsterAI>();
			if (!Object.op_Implicit((Object)(object)component))
			{
				return true;
			}
			if (!MonsterDiveSystem.IsConfiguredMonster(component))
			{
				return true;
			}
			if (MonsterDiveSystem.ShouldUseWaterDiveMode(component))
			{
				__result = false;
				return false;
			}
			return true;
		}

		[HarmonyPostfix]
		[HarmonyPatch(typeof(MonsterAI), "UpdateAI")]
		private static void MonsterAIUpdateAIPostfix(MonsterAI __instance, float dt)
		{
			//IL_008c: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ad: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00de: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fb: Unknown result type (might be due to invalid IL or missing references)
			//IL_0100: Unknown result type (might be due to invalid IL or missing references)
			//IL_0110: Unknown result type (might be due to invalid IL or missing references)
			if (!VBDiving.IsEnabled() || !MonsterDiveSystem.IsConfiguredMonster(__instance))
			{
				return;
			}
			Character character = ((BaseAI)__instance).m_character;
			if (!Object.op_Implicit((Object)(object)character) || !MonsterDiveSystem.ShouldUseWaterDiveMode(__instance))
			{
				return;
			}
			character.m_lastGroundTouch = 1f;
			if (character.IsOnGround() && character.InWater())
			{
				float liquidLevel = character.GetLiquidLevel();
				float num = liquidLevel - character.m_swimDepth;
				if (((Component)character).transform.position.y < num + 0.5f)
				{
					Vector3 position = ((Component)character).transform.position;
					position.y = num;
					((Component)character).transform.position = position;
					Rigidbody component = ((Component)character).GetComponent<Rigidbody>();
					if (Object.op_Implicit((Object)(object)component) && component.linearVelocity.y < 0f)
					{
						Vector3 linearVelocity = component.linearVelocity;
						linearVelocity.y = 0f;
						component.linearVelocity = linearVelocity;
					}
				}
			}
			character.m_swimTimer = 0f;
		}
	}
	internal static class MonsterDiveSystem
	{
		private readonly struct RouteCacheEntry
		{
			public readonly float Time;

			public readonly Vector3Int PositionBucket;

			public readonly Vector3Int TargetBucket;

			public readonly bool Result;

			public RouteCacheEntry(float time, Vector3Int positionBucket, Vector3Int targetBucket, bool result)
			{
				//IL_0009: Unknown result type (might be due to invalid IL or missing references)
				//IL_000a