Decompiled source of VBDiving v0.0.6

plugins/VBDiving.dll

Decompiled 4 days ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Reflection;
using System.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 VBDiving.Utills;
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 bool _isInitialized;

		private bool _initializationAttempted;

		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()
		{
			_isInitialized = false;
			_initializationAttempted = false;
		}

		private void Start()
		{
			TryInitialize();
		}

		private void TryInitialize()
		{
			if (!_isInitialized && !_initializationAttempted && Object.op_Implicit((Object)(object)Player.m_localPlayer))
			{
				_initializationAttempted = true;
				TMP_FontAsset val = FindFont();
				if (!Object.op_Implicit((Object)(object)val))
				{
					VBDiving.LogDebug("[BreathHud] Font not found yet, will retry later");
					_initializationAttempted = false;
					((MonoBehaviour)this).StartCoroutine(RetryInitialize());
				}
				else
				{
					CreateHud(val);
					ApplyPositionAndScale();
					_isInitialized = true;
					VBDiving.LogDebug("[BreathHud] Successfully initialized");
				}
			}
		}

		private IEnumerator RetryInitialize()
		{
			for (int i = 0; i < 10; i++)
			{
				yield return (object)new WaitForSeconds(1f);
				TMP_FontAsset font = FindFont();
				if (Object.op_Implicit((Object)(object)font) && Object.op_Implicit((Object)(object)Player.m_localPlayer))
				{
					CreateHud(font);
					ApplyPositionAndScale();
					_isInitialized = true;
					VBDiving.LogDebug("[BreathHud] Successfully initialized on retry");
					yield break;
				}
			}
			VBDiving.LogDebug("[BreathHud] Failed to initialize after retries, using fallback");
			CreateHudWithFallbackFont();
			ApplyPositionAndScale();
			_isInitialized = true;
		}

		private TMP_FontAsset FindFont()
		{
			TMP_FontAsset val = ((IEnumerable<TMP_FontAsset>)Resources.FindObjectsOfTypeAll<TMP_FontAsset>()).FirstOrDefault((Func<TMP_FontAsset, bool>)((TMP_FontAsset f) => ((Object)f).name == "Valheim-Norsebold"));
			if (!Object.op_Implicit((Object)(object)val))
			{
				val = ((IEnumerable<TMP_FontAsset>)Resources.FindObjectsOfTypeAll<TMP_FontAsset>()).FirstOrDefault((Func<TMP_FontAsset, bool>)((TMP_FontAsset f) => ((Object)f).name == "LiberationSans SDF"));
			}
			if (!Object.op_Implicit((Object)(object)val))
			{
				val = Resources.FindObjectsOfTypeAll<TMP_FontAsset>().FirstOrDefault();
			}
			return val;
		}

		private void CreateHudWithFallbackFont()
		{
			CreateHud(null);
			((MonoBehaviour)this).StartCoroutine(AssignFontLater());
		}

		private IEnumerator AssignFontLater()
		{
			yield return (object)new WaitForSeconds(2f);
			TMP_FontAsset font = FindFont();
			if (Object.op_Implicit((Object)(object)font) && Object.op_Implicit((Object)(object)_breathText))
			{
				((TMP_Text)_breathText).font = font;
				VBDiving.LogDebug("[BreathHud] Font assigned after delay");
			}
		}

		private void Update()
		{
			if (!_isInitialized)
			{
				TryInitialize();
				return;
			}
			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(TMP_FontAsset font)
		{
			//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_02a7: Unknown result type (might be due to invalid IL or missing references)
			//IL_02cb: Unknown result type (might be due to invalid IL or missing references)
			//IL_02e2: Unknown result type (might be due to invalid IL or missing references)
			//IL_02f9: Unknown result type (might be due to invalid IL or missing references)
			//IL_0310: Unknown result type (might be due to invalid IL or missing references)
			//IL_0327: 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>();
			if (Object.op_Implicit((Object)(object)font))
			{
				((TMP_Text)_breathText).font = font;
			}
			else
			{
				TMP_FontAsset val8 = Resources.FindObjectsOfTypeAll<TMP_FontAsset>().FirstOrDefault();
				if (Object.op_Implicit((Object)(object)val8))
				{
					((TMP_Text)_breathText).font = val8;
				}
			}
			((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);
		}
	}
	[BepInPlugin("VitByr.VBDiving", "VBDiving", "0.0.6")]
	[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.6";

		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;

		internal static ConfigEntry<bool> SyncDiveEffectsConfigs;

		internal static ConfigEntry<bool> UseServerDiveEffectsConfigsOnly;

		private ConfigFileWatcher _configWatcher;

		internal static string ConfigFolderPath;

		private CustomRPC _diveEffectsConfigRPC;

		private bool _hasRequestedDiveEffectsConfigs;

		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();
			DiveEffectsConfigSystem.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;
			SyncDiveEffectsConfigs = ConfigFileExtensions.BindConfig<bool>(((BaseUnityPlugin)this).Config, "00 - Main", "SyncDiveEffectsConfigs", true, "Синхронизировать конфиги подводных эффектов с сервера.", true, (int?)null, (AcceptableValueBase)null, (Action<ConfigEntryBase>)null, (ConfigurationManagerAttributes)null);
			UseServerDiveEffectsConfigsOnly = ConfigFileExtensions.BindConfig<bool>(((BaseUnityPlugin)this).Config, "00 - Main", "UseServerDiveEffectsConfigsOnly", true, "Использовать ТОЛЬКО конфиги с сервера (игнорировать локальные файлы). Если false - серверные конфиги имеют приоритет над локальными.", true, (int?)null, (AcceptableValueBase)null, (Action<ConfigEntryBase>)null, (ConfigurationManagerAttributes)null);
			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());
				}
			}
			if ((Object)(object)ZNet.instance != (Object)null && ZNet.instance.IsServer())
			{
				if (SyncMonsterConfigs.Value)
				{
					SendMonsterConfigsToAllClients();
				}
				if (SyncDiveEffectsConfigs.Value)
				{
					SendDiveEffectsConfigsToAllClients();
				}
			}
		}

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

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

		private void SetupDiveEffectsConfigSync()
		{
			//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
			_diveEffectsConfigRPC = NetworkManager.Instance.AddRPC("VBDiving_SyncDiveEffectsConfigs", new CoroutineHandler(OnServerReceiveDiveEffectsRequest), new CoroutineHandler(OnClientReceiveDiveEffectsConfigs));
			if ((Object)(object)ZNet.instance != (Object)null && ZNet.instance.IsServer())
			{
				DiveEffectsConfigSystem.LoadAllConfigs();
			}
		}

		private IEnumerator OnServerReceiveDiveEffectsRequest(long sender, ZPackage package)
		{
			if (package.ReadInt() == 0)
			{
				SendDiveEffectsConfigsToClient(sender);
			}
			yield break;
		}

		private IEnumerator OnClientReceiveDiveEffectsConfigs(long sender, ZPackage package)
		{
			int flag = package.ReadInt();
			if (flag != 1)
			{
				yield break;
			}
			string configData = package.ReadString();
			if (!string.IsNullOrEmpty(configData))
			{
				if (UseServerDiveEffectsConfigsOnly.Value)
				{
					DiveEffectsConfigSystem.LoadSerializedConfigs(configData, useServerOnly: true);
				}
				else
				{
					DiveEffectsConfigSystem.LoadSerializedConfigs(configData);
				}
			}
		}

		private void SendDiveEffectsConfigsToAllClients()
		{
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0032: Expected O, but got Unknown
			if (!SyncDiveEffectsConfigs.Value)
			{
				return;
			}
			string serializedConfigs = DiveEffectsConfigSystem.GetSerializedConfigs();
			if (string.IsNullOrEmpty(serializedConfigs))
			{
				return;
			}
			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())
				{
					_diveEffectsConfigRPC.SendPackage(peer.m_uid, val);
				}
			}
		}

		private void SendDiveEffectsConfigsToClient(long clientId)
		{
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_002c: Expected O, but got Unknown
			if (SyncDiveEffectsConfigs.Value)
			{
				string serializedConfigs = DiveEffectsConfigSystem.GetSerializedConfigs();
				if (!string.IsNullOrEmpty(serializedConfigs))
				{
					ZPackage val = new ZPackage();
					val.Write(1);
					val.Write(serializedConfigs);
					_diveEffectsConfigRPC.SendPackage(clientId, val);
				}
			}
		}

		internal static void RequestDiveEffectsConfigsFromServer()
		{
			//IL_0062: Unknown result type (might be due to invalid IL or missing references)
			//IL_0068: Expected O, but got Unknown
			if (!((Object)(object)Instance == (Object)null) && !((Object)(object)ZNet.instance == (Object)null) && !ZNet.instance.IsServer() && SyncDiveEffectsConfigs.Value && !Instance._hasRequestedDiveEffectsConfigs)
			{
				Instance._hasRequestedDiveEffectsConfigs = true;
				ZPackage val = new ZPackage();
				val.Write(0);
				Instance._diveEffectsConfigRPC.SendPackage(ZRoutedRpc.instance.GetServerPeerID(), val);
			}
		}

		internal static void OnDiveEffectsConfigsChanged()
		{
			if ((Object)(object)Instance != (Object)null && (Object)(object)ZNet.instance != (Object)null && ZNet.instance.IsServer() && SyncDiveEffectsConfigs.Value)
			{
				Instance.SendDiveEffectsConfigsToAllClients();
			}
		}

		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);
			}
		}
	}
}
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: Unknown result type (might be due to invalid IL or missing references)
				//IL_0010: Unknown result type (might be due to invalid IL or missing references)
				//IL_0011: Unknown result type (might be due to invalid IL or missing references)
				Time = time;
				PositionBucket = positionBucket;
				TargetBucket = targetBucket;
				Result = result;
			}
		}

		private readonly struct SteerCacheEntry
		{
			public readonly float Time;

			public readonly Vector3Int PositionBucket;

			public readonly Vector3Int TargetBucket;

			public readonly Vector3 Direction;

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

		private readonly struct PassiveDepthProfile
		{
			public readonly float MinDepth;

			public readonly float CenterDepth;

			public readonly float MaxPassiveDepth;

			public readonly float MaxAgroDepth;

			public PassiveDepthProfile(float minDepth, float centerDepth, float maxPassiveDepth, float maxAgroDepth)
			{
				MinDepth = Mathf.Max(0f, minDepth);
				MaxAgroDepth = Mathf.Max(0f, maxAgroDepth);
				MaxPassiveDepth = Mathf.Clamp(maxPassiveDepth, MinDepth, MaxAgroDepth);
				CenterDepth = Mathf.Clamp(centerDepth, MinDepth, MaxPassiveDepth);
			}

			public PassiveDepthProfile(float centerDepth, float minDepth, float maxDepth)
			{
				MinDepth = Mathf.Max(0f, minDepth);
				MaxAgroDepth = Mathf.Max(0f, maxDepth);
				MaxPassiveDepth = Mathf.Clamp(maxDepth, MinDepth, MaxAgroDepth);
				CenterDepth = Mathf.Clamp(centerDepth, MinDepth, MaxPassiveDepth);
			}
		}

		private readonly struct OriginalDiveFlags
		{
			public readonly MonsterAI MonsterAI;

			public readonly bool AvoidWater;

			public readonly bool CanSwim;

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

		private readonly struct ConfiguredDiveProfile
		{
			public readonly string GroupName;

			public readonly PassiveDepthProfile DepthProfile;

			public readonly float ActiveDepthAdjustSpeed;

			public readonly bool UseBreath;

			public readonly float MaxBreathSeconds;

			public readonly float BreathRecoverySpeed;

			public readonly float SurfaceTime;

			public readonly float SurfaceThresholdPercent;

			public ConfiguredDiveProfile(string groupName, PassiveDepthProfile depthProfile, float activeDepthAdjustSpeed, bool useBreath, float maxBreathSeconds, float breathRecoverySpeed, float surfaceTime, float surfaceThresholdPercent)
			{
				GroupName = groupName;
				DepthProfile = depthProfile;
				ActiveDepthAdjustSpeed = activeDepthAdjustSpeed;
				UseBreath = useBreath;
				MaxBreathSeconds = (useBreath ? Mathf.Max(0f, maxBreathSeconds) : 0f);
				BreathRecoverySpeed = (useBreath ? Mathf.Max(0.1f, breathRecoverySpeed) : 0f);
				SurfaceTime = (useBreath ? Mathf.Max(0f, surfaceTime) : 0f);
				SurfaceThresholdPercent = (useBreath ? Mathf.Clamp01(surfaceThresholdPercent) : 0f);
			}
		}

		private sealed class MonsterDiveYamlRoot : Dictionary<string, MonsterDiveYamlGroup>
		{
			public MonsterDiveYamlRoot()
				: base((IEqualityComparer<string>?)StringComparer.OrdinalIgnoreCase)
			{
			}
		}

		private sealed class MonsterDiveYamlGroup
		{
			public float? MinDepth { get; set; }

			public float? CenterDepth { get; set; }

			public float? MaxDepth { get; set; }

			public float? MaxPassiveDepth { get; set; }

			public float? MaxAgroDepth { get; set; }

			public float? DepthAdjustSpeed { get; set; }

			public bool? UseBreath { get; set; }

			public float? MaxBreathSeconds { get; set; }

			public float? BreathRecoverySpeed { get; set; }

			public float? SurfaceTime { get; set; }

			public float? SurfaceThresholdPercent { get; set; }

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

		}

		internal static readonly string MonsterDiveConfigFolderPath;

		private static readonly object MonsterDiveConfigLock;

		private static readonly IDeserializer MonsterDiveYamlDeserializer;

		private static readonly Dictionary<int, RouteCacheEntry> RouteCache;

		private static readonly Dictionary<int, SteerCacheEntry> SteerCache;

		private static readonly Dictionary<int, OriginalDiveFlags> OriginalDiveFlagsByInstance;

		private const int MaxCacheEntries = 2048;

		private static readonly object PrefabSetLock;

		private static Dictionary<string, ConfiguredDiveProfile> _configuredDiveProfilesByPrefabName;

		private static FileSystemWatcher _configFolderWatcher;

		private static DateTime _lastReloadTime;

		private static readonly object _reloadLock;

		private const long ReloadDelayTicks = 10000000L;

		private static readonly float[] SteerAngles;

		private static readonly float[] RouteAngles;

		static MonsterDiveSystem()
		{
			//IL_009f: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ae: Expected O, but got Unknown
			MonsterDiveConfigLock = new object();
			RouteCache = new Dictionary<int, RouteCacheEntry>();
			SteerCache = new Dictionary<int, SteerCacheEntry>();
			OriginalDiveFlagsByInstance = new Dictionary<int, OriginalDiveFlags>();
			PrefabSetLock = new object();
			_configuredDiveProfilesByPrefabName = new Dictionary<string, ConfiguredDiveProfile>(StringComparer.OrdinalIgnoreCase);
			_reloadLock = new object();
			SteerAngles = new float[8] { 0f, -35f, 35f, -70f, 70f, -120f, 120f, 180f };
			RouteAngles = new float[5] { 0f, -35f, 35f, -70f, 70f };
			string text = Path.Combine(Paths.ConfigPath, "VitByr", "VBDiving", "Monsters");
			Directory.CreateDirectory(text);
			MonsterDiveConfigFolderPath = text;
			MonsterDiveYamlDeserializer = ((BuilderSkeleton<DeserializerBuilder>)new DeserializerBuilder()).WithNamingConvention(UnderscoredNamingConvention.Instance).WithDuplicateKeyChecking().Build();
		}

		public static void Initialize()
		{
			LoadAllMonsterDiveConfigs();
			SetupConfigFolderWatcher();
			if ((Object)(object)ZNet.instance != (Object)null && ZNetExtension.IsClientInstance(ZNet.instance) && VBDiving.SyncMonsterConfigs.Value)
			{
				Debug.Log((object)"[VBDiving] Client will request monster configs from server after connection");
				((MonoBehaviour)VBDiving.Instance).StartCoroutine(RequestConfigsDelayed());
			}
		}

		private static IEnumerator RequestConfigsDelayed()
		{
			yield return (object)new WaitForSeconds(3f);
			VBDiving.RequestMonsterConfigsFromServer();
		}

		public static void LoadAllMonsterDiveConfigs()
		{
			if (!VBDiving.IsEnabled())
			{
				Debug.LogWarning((object)"[VBDiving] Mod disabled, skipping monster dive config loading");
				return;
			}
			lock (MonsterDiveConfigLock)
			{
				if (ShouldUseServerConfigs() && (Object)(object)ZNet.instance != (Object)null && !ZNet.instance.IsServer())
				{
					Debug.Log((object)"[VBDiving] Skipping local config load on client - waiting for server sync");
				}
				if (!Directory.Exists(MonsterDiveConfigFolderPath))
				{
					Directory.CreateDirectory(MonsterDiveConfigFolderPath);
					CreateDefaultConfigFileIfNotExists();
				}
				Dictionary<string, ConfiguredDiveProfile> dictionary = new Dictionary<string, ConfiguredDiveProfile>(StringComparer.OrdinalIgnoreCase);
				List<string> list = Directory.GetFiles(MonsterDiveConfigFolderPath, "*.yaml").Concat(Directory.GetFiles(MonsterDiveConfigFolderPath, "*.yml")).ToList();
				if (list.Count == 0)
				{
					Debug.Log((object)("[VBDiving] No monster dive config files found in " + MonsterDiveConfigFolderPath + ", creating default"));
					CreateDefaultConfigFileIfNotExists();
					list = Directory.GetFiles(MonsterDiveConfigFolderPath, "*.yaml").ToList();
				}
				Debug.Log((object)$"[VBDiving] Found {list.Count} monster config file(s)");
				foreach (string item in list)
				{
					try
					{
						LoadConfigFromFile(item, dictionary);
					}
					catch (Exception ex)
					{
						Debug.LogError((object)("[VBDiving] Failed to load config file " + Path.GetFileName(item) + ": " + ex.Message));
					}
				}
				lock (PrefabSetLock)
				{
					if (_configuredDiveProfilesByPrefabName.Count > 0 && !ZNet.instance.IsServer() && ShouldUseServerConfigs())
					{
						foreach (KeyValuePair<string, ConfiguredDiveProfile> item2 in dictionary)
						{
							if (!_configuredDiveProfilesByPrefabName.ContainsKey(item2.Key))
							{
								_configuredDiveProfilesByPrefabName[item2.Key] = item2.Value;
							}
						}
						Debug.Log((object)$"[VBDiving] Merged {dictionary.Count} local prefabs with existing server configs");
					}
					else
					{
						_configuredDiveProfilesByPrefabName = dictionary;
					}
				}
				ClearRuntimeCaches();
				Debug.Log((object)$"[VBDiving] Loaded {_configuredDiveProfilesByPrefabName.Count} monster prefab configurations");
			}
		}

		private static void ReloadAndResyncConfigs()
		{
			if (!VBDiving.IsEnabled() || (Object)(object)ZNet.instance == (Object)null || !ZNet.instance.IsServer())
			{
				return;
			}
			lock (_reloadLock)
			{
				try
				{
					LoadAllMonsterDiveConfigs();
					Debug.Log((object)"[VBDiving] Configs reloaded on server");
				}
				catch (Exception ex)
				{
					Debug.LogError((object)("[VBDiving] Error reloading configs: " + ex.Message));
				}
			}
		}

		private static void LoadConfigFromFile(string filePath, Dictionary<string, ConfiguredDiveProfile> allProfiles)
		{
			string text = File.ReadAllText(filePath);
			if (string.IsNullOrWhiteSpace(text))
			{
				Debug.LogWarning((object)("[VBDiving] Empty config file: " + Path.GetFileName(filePath)));
				return;
			}
			MonsterDiveYamlRoot monsterDiveYamlRoot = ParseYamlRoot(text);
			if (monsterDiveYamlRoot == null)
			{
				return;
			}
			Dictionary<string, ConfiguredDiveProfile> dictionary = new Dictionary<string, ConfiguredDiveProfile>(StringComparer.OrdinalIgnoreCase);
			string fileName = Path.GetFileName(filePath);
			foreach (KeyValuePair<string, MonsterDiveYamlGroup> item in monsterDiveYamlRoot)
			{
				string text2 = item.Key?.Trim() ?? "";
				if (string.IsNullOrEmpty(text2))
				{
					continue;
				}
				MonsterDiveYamlGroup monsterDiveYamlGroup = item.Value ?? new MonsterDiveYamlGroup();
				float valueOrDefault = monsterDiveYamlGroup.MinDepth.GetValueOrDefault();
				float valueOrDefault2 = monsterDiveYamlGroup.CenterDepth.GetValueOrDefault();
				float num;
				float maxPassiveDepth;
				if (monsterDiveYamlGroup.MaxAgroDepth.HasValue || monsterDiveYamlGroup.MaxPassiveDepth.HasValue)
				{
					num = Mathf.Max(0f, monsterDiveYamlGroup.MaxAgroDepth ?? monsterDiveYamlGroup.MaxDepth ?? 30f);
					maxPassiveDepth = monsterDiveYamlGroup.MaxPassiveDepth ?? num;
				}
				else
				{
					num = Mathf.Max(0f, monsterDiveYamlGroup.MaxDepth ?? 30f);
					maxPassiveDepth = num;
				}
				PassiveDepthProfile depthProfile = new PassiveDepthProfile(valueOrDefault, valueOrDefault2, maxPassiveDepth, num);
				float activeDepthAdjustSpeed = Mathf.Max(0f, monsterDiveYamlGroup.DepthAdjustSpeed ?? 2f);
				bool valueOrDefault3 = monsterDiveYamlGroup.UseBreath.GetValueOrDefault();
				float maxBreathSeconds = Mathf.Max(0f, monsterDiveYamlGroup.MaxBreathSeconds ?? 60f);
				float breathRecoverySpeed = Mathf.Max(0.1f, monsterDiveYamlGroup.BreathRecoverySpeed ?? 1f);
				float surfaceTime = Mathf.Max(0f, monsterDiveYamlGroup.SurfaceTime ?? 3f);
				float surfaceThresholdPercent = Mathf.Clamp01(monsterDiveYamlGroup.SurfaceThresholdPercent ?? 0.33f);
				ConfiguredDiveProfile value = new ConfiguredDiveProfile(text2, depthProfile, activeDepthAdjustSpeed, valueOrDefault3, maxBreathSeconds, breathRecoverySpeed, surfaceTime, surfaceThresholdPercent);
				if (monsterDiveYamlGroup.Prefabs == null)
				{
					continue;
				}
				foreach (string prefab in monsterDiveYamlGroup.Prefabs)
				{
					string text3 = prefab?.Trim() ?? "";
					if (!string.IsNullOrEmpty(text3))
					{
						if (allProfiles.ContainsKey(text3) || dictionary.ContainsKey(text3))
						{
							Debug.LogWarning((object)("[VBDiving] Prefab '" + text3 + "' already configured, skipping duplicate from " + fileName));
						}
						else
						{
							dictionary[text3] = value;
						}
					}
				}
			}
			foreach (KeyValuePair<string, ConfiguredDiveProfile> item2 in dictionary)
			{
				allProfiles[item2.Key] = item2.Value;
			}
			Debug.Log((object)$"[VBDiving] Loaded {dictionary.Count} prefabs from {fileName}");
		}

		private static MonsterDiveYamlRoot ParseYamlRoot(string yamlText)
		{
			try
			{
				MonsterDiveYamlRoot monsterDiveYamlRoot = MonsterDiveYamlDeserializer.Deserialize<MonsterDiveYamlRoot>(yamlText);
				return monsterDiveYamlRoot ?? new MonsterDiveYamlRoot();
			}
			catch (Exception ex)
			{
				Debug.LogError((object)("[VBDiving] Failed to parse YAML: " + ex.Message));
				return null;
			}
		}

		private static void CreateDefaultConfigFileIfNotExists()
		{
			string text = Path.Combine(MonsterDiveConfigFolderPath, "Vanilla.yaml");
			IEnumerable<string> source = Directory.GetFiles(MonsterDiveConfigFolderPath, "*.yaml").Concat(Directory.GetFiles(MonsterDiveConfigFolderPath, "*.yml"));
			if (!source.Any())
			{
				string contents = BuildDefaultMonsterDiveYaml();
				File.WriteAllText(text, contents);
				Debug.Log((object)("[VBDiving] Created example monster dive config at: " + text));
			}
		}

		private static void SetupConfigFolderWatcher()
		{
			if (_configFolderWatcher == null)
			{
				_configFolderWatcher = new FileSystemWatcher(MonsterDiveConfigFolderPath)
				{
					NotifyFilter = (NotifyFilters.FileName | NotifyFilters.LastWrite | NotifyFilters.CreationTime),
					IncludeSubdirectories = false,
					EnableRaisingEvents = true
				};
				_configFolderWatcher.Changed += OnConfigFileChanged;
				_configFolderWatcher.Created += OnConfigFileChanged;
				_configFolderWatcher.Deleted += OnConfigFileChanged;
				_configFolderWatcher.Renamed += OnConfigFileRenamed;
				Debug.Log((object)("[VBDiving] Watching monster config folder: " + MonsterDiveConfigFolderPath));
			}
		}

		private static void OnConfigFileChanged(object sender, FileSystemEventArgs e)
		{
			if (e.Name.EndsWith(".tmp") || e.Name.StartsWith("~") || (!e.Name.EndsWith(".yaml", StringComparison.OrdinalIgnoreCase) && !e.Name.EndsWith(".yml", StringComparison.OrdinalIgnoreCase)))
			{
				return;
			}
			DateTime now = DateTime.Now;
			if (now.Ticks - _lastReloadTime.Ticks < 10000000)
			{
				return;
			}
			lock (_reloadLock)
			{
				try
				{
					Debug.Log((object)$"[VBDiving] Config change detected ({e.ChangeType}: {e.Name}). Reloading all configs...");
					LoadAllMonsterDiveConfigs();
					if ((Object)(object)ZNet.instance != (Object)null && ZNet.instance.IsServer())
					{
						NotifyServerConfigsChanged();
					}
					_lastReloadTime = now;
				}
				catch (Exception ex)
				{
					Debug.LogError((object)("[VBDiving] Error reloading monster configs: " + ex.Message));
				}
			}
		}

		private static void OnConfigFileRenamed(object sender, RenamedEventArgs e)
		{
			if (!e.Name.EndsWith(".yaml", StringComparison.OrdinalIgnoreCase) && !e.Name.EndsWith(".yml", StringComparison.OrdinalIgnoreCase))
			{
				return;
			}
			DateTime now = DateTime.Now;
			if (now.Ticks - _lastReloadTime.Ticks < 10000000)
			{
				return;
			}
			lock (_reloadLock)
			{
				try
				{
					Debug.Log((object)("[VBDiving] Config file renamed: " + e.OldName + " -> " + e.Name + ". Reloading all configs..."));
					if ((Object)(object)ZNet.instance != (Object)null && ZNet.instance.IsServer())
					{
						ReloadAndResyncConfigs();
					}
					else
					{
						LoadAllMonsterDiveConfigs();
					}
					_lastReloadTime = now;
				}
				catch (Exception ex)
				{
					Debug.LogError((object)("[VBDiving] Error reloading monster configs: " + ex.Message));
				}
			}
		}

		private static string BuildDefaultMonsterDiveYaml()
		{
			StringBuilder stringBuilder = new StringBuilder();
			stringBuilder.AppendLine("# Monster dive configuration for VBDiving");
			stringBuilder.AppendLine("# You can create multiple .yaml files in this folder");
			stringBuilder.AppendLine("# Files are loaded in alphabetical order, later files will NOT override earlier ones");
			stringBuilder.AppendLine();
			stringBuilder.AppendLine("# Параметры глубины:");
			stringBuilder.AppendLine("#   min_depth - минимальная глубина (у поверхности)");
			stringBuilder.AppendLine("#   center_depth - предпочтительная/центральная глубина (в пассивном режиме)");
			stringBuilder.AppendLine("#   max_passive_depth - максимальная глубина в пассивном режиме");
			stringBuilder.AppendLine("#   max_agro_depth - максимальная глубина в агрессивном режиме (абсолютный предел)");
			stringBuilder.AppendLine();
			stringBuilder.AppendLine("# Surface patrol group (патрулирует у поверхности)");
			stringBuilder.AppendLine("surface_patrol:");
			stringBuilder.AppendLine("  min_depth: 1");
			stringBuilder.AppendLine("  center_depth: 2");
			stringBuilder.AppendLine("  max_passive_depth: 3      # В спокойствии не глубже 3м");
			stringBuilder.AppendLine("  max_agro_depth: 15         # В бою может нырнуть до 10м");
			stringBuilder.AppendLine("  depth_adjust_speed: 2");
			stringBuilder.AppendLine("  use_breath: true");
			stringBuilder.AppendLine("  max_breath_seconds: 60");
			stringBuilder.AppendLine("  breath_recovery_speed: 2");
			stringBuilder.AppendLine("  surface_time: 3");
			stringBuilder.AppendLine("  surface_threshold_percent: 0.33");
			stringBuilder.AppendLine("  prefabs:");
			stringBuilder.AppendLine("    - Leech");
			stringBuilder.AppendLine();
			stringBuilder.AppendLine("# Deep hunters (охотники глубин)");
			stringBuilder.AppendLine("deep_hunters:");
			stringBuilder.AppendLine("  min_depth: 1");
			stringBuilder.AppendLine("  center_depth: 5");
			stringBuilder.AppendLine("  max_passive_depth: 20      # В спокойствии между 1-20м");
			stringBuilder.AppendLine("  max_agro_depth: 50         # В бою может уйти до 50м");
			stringBuilder.AppendLine("  depth_adjust_speed: 5");
			stringBuilder.AppendLine("  use_breath: true");
			stringBuilder.AppendLine("  max_breath_seconds: 120");
			stringBuilder.AppendLine("  breath_recovery_speed: 1.5");
			stringBuilder.AppendLine("  surface_time: 5");
			stringBuilder.AppendLine("  surface_threshold_percent: 0.25");
			stringBuilder.AppendLine("  prefabs:");
			stringBuilder.AppendLine("    - Serpent");
			stringBuilder.AppendLine("    - BonemawSerpent");
			stringBuilder.AppendLine();
			stringBuilder.AppendLine("# Water creatures without breath (водные без дыхания)");
			stringBuilder.AppendLine("water_creatures:");
			stringBuilder.AppendLine("  min_depth: 1");
			stringBuilder.AppendLine("  center_depth: 5");
			stringBuilder.AppendLine("  max_passive_depth: 5       # В спокойствии у поверхности");
			stringBuilder.AppendLine("  max_agro_depth: 15");
			stringBuilder.AppendLine("  depth_adjust_speed: 3");
			stringBuilder.AppendLine("  use_breath: false");
			stringBuilder.AppendLine("  prefabs:");
			stringBuilder.AppendLine("    - Fish1");
			stringBuilder.AppendLine("    - Fish2");
			stringBuilder.AppendLine("    - Fish3");
			stringBuilder.AppendLine("    - Fish4");
			stringBuilder.AppendLine("    - Fish5");
			stringBuilder.AppendLine("    - Fish6");
			stringBuilder.AppendLine("    - Fish7");
			stringBuilder.AppendLine("    - Fish8");
			stringBuilder.AppendLine("    - Fish9");
			stringBuilder.AppendLine("    - Fish10");
			stringBuilder.AppendLine("    - Fish11");
			stringBuilder.AppendLine("    - Fish12");
			stringBuilder.AppendLine();
			return stringBuilder.ToString();
		}

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

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

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

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

		public static bool IsConfiguredMonster(MonsterAI monsterAI)
		{
			ConfiguredDiveProfile profile;
			return TryGetConfiguredDiveProfile(monsterAI, out profile);
		}

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

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

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

		public static void EnsureDiveFlags(MonsterAI monsterAI)
		{
			int instanceID = ((Object)monsterAI).GetInstanceID();
			if (!OriginalDiveFlagsByInstance.ContainsKey(instanceID))
			{
				Character character = ((BaseAI)monsterAI).m_character;
				OriginalDiveFlagsByInstance[instanceID] = new OriginalDiveFlags(monsterAI, ((BaseAI)monsterAI).m_avoidWater, Object.op_Implicit((Object)(object)character) && character.m_canSwim);
				if (OriginalDiveFlagsByInstance.Count > 2048)
				{
					List<int> list = OriginalDiveFlagsByInstance.Keys.Where((int k) => !Object.op_Implicit((Object)(object)OriginalDiveFlagsByInstance[k].MonsterAI)).ToList();
					foreach (int item in list)
					{
						OriginalDiveFlagsByInstance.Remove(item);
					}
				}
			}
			((BaseAI)monsterAI).m_avoidWater = false;
			if (Object.op_Implicit((Object)(object)((BaseAI)monsterAI).m_character))
			{
				((BaseAI)monsterAI).m_character.m_canSwim = true;
			}
		}

		public static Vector3 BuildSteerDirectionWithAvoidance(BaseAI ai, Character character, Vector3 targetPoint)
		{
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0047: Unknown result type (might be due to invalid IL or missing references)
			//IL_004c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0078: 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_0084: Unknown result type (might be due to invalid IL or missing references)
			//IL_0089: Unknown result type (might be due to invalid IL or missing references)
			//IL_006c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0071: Unknown result type (might be due to invalid IL or missing references)
			//IL_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_00b8: 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_00d8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00df: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a7: Unknown result type (might be due to invalid IL or missing references)
			//IL_023d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0228: Unknown result type (might be due to invalid IL or missing references)
			//IL_0229: Unknown result type (might be due to invalid IL or missing references)
			//IL_022a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0237: Unknown result type (might be due to invalid IL or missing references)
			//IL_0239: Unknown result type (might be due to invalid IL or missing references)
			//IL_011d: 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_0147: Unknown result type (might be due to invalid IL or missing references)
			//IL_014c: Unknown result type (might be due to invalid IL or missing references)
			//IL_014e: 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_0156: 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_01db: 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_01e9: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ee: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f2: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f7: Unknown result type (might be due to invalid IL or missing references)
			//IL_0206: 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_0208: 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_0217: Unknown result type (might be due to invalid IL or missing references)
			//IL_017a: Unknown result type (might be due to invalid IL or missing references)
			//IL_017f: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b4: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b6: Unknown result type (might be due to invalid IL or missing references)
			int instanceID = ((Object)ai).GetInstanceID();
			Vector3Int val = ToCacheBucket(((Component)ai).transform.position);
			Vector3Int val2 = ToCacheBucket(targetPoint);
			float time = Time.time;
			if (SteerCache.TryGetValue(instanceID, out var value) && time - value.Time <= 0.5f && value.PositionBucket == val && value.TargetBucket == val2)
			{
				return value.Direction;
			}
			Vector3 val3 = targetPoint - ((Component)ai).transform.position;
			if (((Vector3)(ref val3)).sqrMagnitude <= 0.0001f)
			{
				return Vector3.zero;
			}
			((Vector3)(ref val3)).Normalize();
			Vector3 val4 = default(Vector3);
			((Vector3)(ref val4))..ctor(val3.x, 0f, val3.z);
			float radius = character.GetRadius();
			float num = Mathf.Clamp(Utils.DistanceXZ(targetPoint, ((Component)ai).transform.position), radius + 1f, 6f);
			if (((Vector3)(ref val4)).sqrMagnitude > 0.0001f)
			{
				((Vector3)(ref val4)).Normalize();
				Vector3 val5 = val4;
				float num2 = float.NegativeInfinity;
				for (int i = 0; i < SteerAngles.Length; i++)
				{
					float num3 = SteerAngles[i];
					Vector3 val6 = Quaternion.Euler(0f, num3, 0f) * val4;
					float num4 = ((!ai.CanMove(val6, radius, num)) ? (ai.Raycast(character.GetCenterPoint(), val6, num * 2f, 0.1f) - Mathf.Abs(num3) * 0.01f) : (1000f - Mathf.Abs(num3)));
					if (num4 > num2)
					{
						num2 = num4;
						val5 = val6;
					}
				}
				Vector3 val7 = new Vector3(val5.x, val3.y, val5.z);
				Vector3 normalized = ((Vector3)(ref val7)).normalized;
				TrimCachesIfNeeded();
				SteerCache[instanceID] = new SteerCacheEntry(time, val, val2, normalized);
				return normalized;
			}
			TrimCachesIfNeeded();
			SteerCache[instanceID] = new SteerCacheEntry(time, val, val2, val3);
			return val3;
		}

		public static bool HasReasonableUnderwaterRoute(BaseAI ai, Character character, Vector3 targetPoint)
		{
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0047: Unknown result type (might be due to invalid IL or missing references)
			//IL_004c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0078: 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_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_00c6: 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_00d2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00db: 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_00b0: 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_0112: Unknown result type (might be due to invalid IL or missing references)
			//IL_0113: Unknown result type (might be due to invalid IL or missing references)
			//IL_015e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0163: Unknown result type (might be due to invalid IL or missing references)
			//IL_0165: Unknown result type (might be due to invalid IL or missing references)
			//IL_016a: Unknown result type (might be due to invalid IL or missing references)
			//IL_016e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0173: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ce: Unknown result type (might be due to invalid IL or missing references)
			//IL_01cf: Unknown result type (might be due to invalid IL or missing references)
			//IL_019c: Unknown result type (might be due to invalid IL or missing references)
			//IL_019d: Unknown result type (might be due to invalid IL or missing references)
			int instanceID = ((Object)ai).GetInstanceID();
			Vector3Int val = ToCacheBucket(((Component)ai).transform.position);
			Vector3Int val2 = ToCacheBucket(targetPoint);
			float time = Time.time;
			if (RouteCache.TryGetValue(instanceID, out var value) && time - value.Time <= 1f && value.PositionBucket == val && value.TargetBucket == val2)
			{
				return value.Result;
			}
			float num = Utils.DistanceXZ(targetPoint, ((Component)ai).transform.position);
			float radius = character.GetRadius();
			if (num <= radius + 0.6f)
			{
				RouteCache[instanceID] = new RouteCacheEntry(time, val, val2, result: true);
				return true;
			}
			Vector3 val3 = targetPoint - ((Component)ai).transform.position;
			Vector3 val4 = default(Vector3);
			((Vector3)(ref val4))..ctor(val3.x, 0f, val3.z);
			if (((Vector3)(ref val4)).sqrMagnitude <= 0.0001f)
			{
				RouteCache[instanceID] = new RouteCacheEntry(time, val, val2, result: true);
				return true;
			}
			((Vector3)(ref val4)).Normalize();
			float num2 = Mathf.Clamp(num, radius + 1f, 6f);
			for (int i = 0; i < RouteAngles.Length; i++)
			{
				Vector3 val5 = Quaternion.Euler(0f, RouteAngles[i], 0f) * val4;
				if (ai.Raycast(character.GetCenterPoint(), val5, num2, 0.1f) >= num2 * 0.9f)
				{
					RouteCache[instanceID] = new RouteCacheEntry(time, val, val2, result: true);
					return true;
				}
			}
			RouteCache[instanceID] = new RouteCacheEntry(time, val, val2, result: false);
			return false;
		}

		public static void UpdateMonsterBreath(MonsterAI monsterAI, Character character, float dt)
		{
			if (!IsConfiguredMonster(monsterAI) || !TryGetConfiguredDiveProfile(monsterAI, out var profile) || !profile.UseBreath)
			{
				return;
			}
			MonsterSwimState monsterSwimState = MonsterSwimStateManager.Get(monsterAI);
			if (monsterSwimState.MaxBreath <= 0f)
			{
				monsterSwimState.MaxBreath = profile.MaxBreathSeconds;
				monsterSwimState.Breath = monsterSwimState.MaxBreath;
			}
			bool flag = IsMonsterUnderwater(monsterAI, character);
			if (!flag && character.IsOnGround() && character.InWater())
			{
				flag = true;
			}
			if (flag)
			{
				monsterSwimState.Breath -= dt;
				monsterSwimState.SurfaceTimer = 0f;
				if (monsterSwimState.Breath < 0f)
				{
					monsterSwimState.Breath = 0f;
					monsterSwimState.IsSurfacing = true;
				}
				float num = monsterSwimState.Breath / monsterSwimState.MaxBreath;
				if (num <= profile.SurfaceThresholdPercent)
				{
					monsterSwimState.IsSurfacing = true;
				}
			}
			else
			{
				monsterSwimState.Breath += dt * profile.BreathRecoverySpeed;
				monsterSwimState.SurfaceTimer += dt;
				if (monsterSwimState.Breath >= monsterSwimState.MaxBreath)
				{
					monsterSwimState.Breath = monsterSwimState.MaxBreath;
					if (monsterSwimState.SurfaceTimer >= profile.SurfaceTime)
					{
						monsterSwimState.IsSurfacing = false;
					}
				}
			}
			monsterSwimState.WasUnderwater = flag;
		}

		public static bool IsMonsterUnderwater(MonsterAI monsterAI, Character character)
		{
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			if (!Object.op_Implicit((Object)(object)character) || !Object.op_Implicit((Object)(object)monsterAI))
			{
				return false;
			}
			Vector3 headPoint = character.GetHeadPoint();
			float liquidLevel = character.GetLiquidLevel();
			return headPoint.y < liquidLevel - 0.1f;
		}

		public static float UpdateSwimDepthTowardsTarget(MonsterAI monsterAI, Character character, Vector3 point, float dt)
		{
			//IL_00eb: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a0: Unknown result type (might be due to invalid IL or missing references)
			TryGetConfiguredDiveProfile(monsterAI, out var profile);
			float liquidLevel = character.GetLiquidLevel();
			float num = 2f;
			bool flag = ((BaseAI)monsterAI).IsAlerted() || Object.op_Implicit((Object)(object)monsterAI.m_targetCreature) || Object.op_Implicit((Object)(object)monsterAI.m_targetStatic);
			float num2 = (flag ? profile.DepthProfile.MaxAgroDepth : profile.DepthProfile.MaxPassiveDepth);
			MonsterSwimState monsterSwimState = null;
			float num3;
			if (profile.UseBreath)
			{
				monsterSwimState = MonsterSwimStateManager.Get(monsterAI);
				if (monsterSwimState.IsSurfacing)
				{
					num3 = 0.5f;
					num = profile.ActiveDepthAdjustSpeed * 1.5f;
				}
				else if (flag)
				{
					float num4 = liquidLevel - point.y;
					num3 = Mathf.Clamp(num4, profile.DepthProfile.MinDepth + 0.25f, num2);
					num = profile.ActiveDepthAdjustSpeed;
				}
				else
				{
					num3 = GetPassiveDesiredDepth(monsterAI, profile.DepthProfile);
				}
			}
			else if (flag)
			{
				float num5 = liquidLevel - point.y;
				num3 = Mathf.Clamp(num5, profile.DepthProfile.MinDepth + 0.25f, num2);
				num = profile.ActiveDepthAdjustSpeed;
			}
			else
			{
				num3 = GetPassiveDesiredDepth(monsterAI, profile.DepthProfile);
			}
			if (num <= 0f)
			{
				character.m_swimDepth = num3;
				return liquidLevel - num3;
			}
			character.m_swimDepth = Mathf.MoveTowards(character.m_swimDepth, num3, num * Mathf.Max(dt, 0.01f));
			return liquidLevel - num3;
		}

		public static string GetSerializedConfigs()
		{
			lock (MonsterDiveConfigLock)
			{
				Debug.Log((object)$"[MonsterDiveSystem] GetSerializedConfigs: {_configuredDiveProfilesByPrefabName.Count} profiles found");
				if (_configuredDiveProfilesByPrefabName.Count == 0)
				{
					Debug.LogWarning((object)"[MonsterDiveSystem] No profiles to serialize!");
					return "";
				}
				StringBuilder stringBuilder = new StringBuilder();
				foreach (KeyValuePair<string, ConfiguredDiveProfile> item in _configuredDiveProfilesByPrefabName)
				{
					string key = item.Key;
					ConfiguredDiveProfile value = item.Value;
					stringBuilder.Append(key);
					stringBuilder.Append('|');
					stringBuilder.Append(value.GroupName);
					stringBuilder.Append('|');
					stringBuilder.Append(value.DepthProfile.MinDepth);
					stringBuilder.Append('|');
					stringBuilder.Append(value.DepthProfile.CenterDepth);
					stringBuilder.Append('|');
					stringBuilder.Append(value.DepthProfile.MaxPassiveDepth);
					stringBuilder.Append('|');
					stringBuilder.Append(value.DepthProfile.MaxAgroDepth);
					stringBuilder.Append('|');
					stringBuilder.Append(value.ActiveDepthAdjustSpeed);
					stringBuilder.Append('|');
					stringBuilder.Append(value.UseBreath ? "1" : "0");
					stringBuilder.Append('|');
					stringBuilder.Append(value.MaxBreathSeconds);
					stringBuilder.Append('|');
					stringBuilder.Append(value.BreathRecoverySpeed);
					stringBuilder.Append('|');
					stringBuilder.Append(value.SurfaceTime);
					stringBuilder.Append('|');
					stringBuilder.Append(value.SurfaceThresholdPercent);
					stringBuilder.Append('\n');
					Debug.Log((object)$"[MonsterDiveSystem] Serialized: {key} -> {value.GroupName} (passive max: {value.DepthProfile.MaxPassiveDepth}, agro max: {value.DepthProfile.MaxAgroDepth})");
				}
				string text = stringBuilder.ToString();
				Debug.Log((object)$"[MonsterDiveSystem] Serialized {_configuredDiveProfilesByPrefabName.Count} prefabs, total length: {text.Length}");
				return text;
			}
		}

		public static void LoadSerializedConfigs(string configData, bool useServerOnly = false)
		{
			Debug.Log((object)$"[MonsterDiveSystem] LoadSerializedConfigs called, data length: {configData?.Length ?? 0}, useServerOnly: {useServerOnly}");
			if (string.IsNullOrEmpty(configData))
			{
				Debug.LogWarning((object)"[MonsterDiveSystem] Empty configData received!");
				return;
			}
			if (!VBDiving.IsEnabled())
			{
				Debug.LogWarning((object)"[VBDiving] Mod disabled, skipping server config loading");
				return;
			}
			lock (MonsterDiveConfigLock)
			{
				Dictionary<string, ConfiguredDiveProfile> dictionary = new Dictionary<string, ConfiguredDiveProfile>(StringComparer.OrdinalIgnoreCase);
				string[] array = configData.Split(new char[1] { '\n' }, StringSplitOptions.RemoveEmptyEntries);
				string[] array2 = array;
				foreach (string text in array2)
				{
					string[] array3 = text.Split(new char[1] { '|' });
					if (array3.Length < 12)
					{
						Debug.LogWarning((object)$"[MonsterDiveSystem] Invalid line format, expected 12 parts, got {array3.Length}: {text}");
						continue;
					}
					try
					{
						string text2 = array3[0];
						string groupName = array3[1];
						float minDepth = float.Parse(array3[2]);
						float centerDepth = float.Parse(array3[3]);
						float num = float.Parse(array3[4]);
						float num2 = float.Parse(array3[5]);
						float activeDepthAdjustSpeed = float.Parse(array3[6]);
						bool useBreath = array3[7] == "1";
						float maxBreathSeconds = float.Parse(array3[8]);
						float breathRecoverySpeed = float.Parse(array3[9]);
						float surfaceTime = float.Parse(array3[10]);
						float surfaceThresholdPercent = float.Parse(array3[11]);
						PassiveDepthProfile depthProfile = new PassiveDepthProfile(minDepth, centerDepth, num, num2);
						ConfiguredDiveProfile value = new ConfiguredDiveProfile(groupName, depthProfile, activeDepthAdjustSpeed, useBreath, maxBreathSeconds, breathRecoverySpeed, surfaceTime, surfaceThresholdPercent);
						dictionary[text2] = value;
						Debug.Log((object)$"[MonsterDiveSystem] Loaded server config: {text2} -> passive max: {num}, agro max: {num2}");
					}
					catch (Exception ex)
					{
						Debug.LogError((object)("[MonsterDiveSystem] Failed to parse config line: " + text + ", error: " + ex.Message));
					}
				}
				if (dictionary.Count == 0)
				{
					Debug.LogWarning((object)"[VBDiving] No valid profiles found in server config data");
					return;
				}
				if (useServerOnly)
				{
					lock (PrefabSetLock)
					{
						_configuredDiveProfilesByPrefabName = dictionary;
					}
					Debug.Log((object)$"[VBDiving] Loaded {dictionary.Count} monster prefab configurations FROM SERVER ONLY");
				}
				else
				{
					lock (PrefabSetLock)
					{
						Dictionary<string, ConfiguredDiveProfile> dictionary2 = new Dictionary<string, ConfiguredDiveProfile>(StringComparer.OrdinalIgnoreCase);
						LoadLocalConfigsToDictionary(dictionary2);
						foreach (KeyValuePair<string, ConfiguredDiveProfile> item in dictionary)
						{
							dictionary2[item.Key] = item.Value;
						}
						_configuredDiveProfilesByPrefabName = dictionary2;
					}
					Debug.Log((object)$"[VBDiving] Loaded {dictionary.Count} server configs (merged with local, server priority)");
				}
				ClearRuntimeCaches();
			}
		}

		private static void LoadLocalConfigsToDictionary(Dictionary<string, ConfiguredDiveProfile> targetDict)
		{
			if (!Directory.Exists(MonsterDiveConfigFolderPath))
			{
				return;
			}
			List<string> list = Directory.GetFiles(MonsterDiveConfigFolderPath, "*.yaml").Concat(Directory.GetFiles(MonsterDiveConfigFolderPath, "*.yml")).ToList();
			foreach (string item in list)
			{
				try
				{
					string text = File.ReadAllText(item);
					if (string.IsNullOrWhiteSpace(text))
					{
						continue;
					}
					MonsterDiveYamlRoot monsterDiveYamlRoot = ParseYamlRoot(text);
					if (monsterDiveYamlRoot == null)
					{
						continue;
					}
					foreach (KeyValuePair<string, MonsterDiveYamlGroup> item2 in monsterDiveYamlRoot)
					{
						string text2 = item2.Key?.Trim() ?? "";
						if (string.IsNullOrEmpty(text2))
						{
							continue;
						}
						MonsterDiveYamlGroup monsterDiveYamlGroup = item2.Value ?? new MonsterDiveYamlGroup();
						float valueOrDefault = monsterDiveYamlGroup.MinDepth.GetValueOrDefault();
						float valueOrDefault2 = monsterDiveYamlGroup.CenterDepth.GetValueOrDefault();
						float num;
						float maxPassiveDepth;
						if (monsterDiveYamlGroup.MaxAgroDepth.HasValue || monsterDiveYamlGroup.MaxPassiveDepth.HasValue)
						{
							num = Mathf.Max(0f, monsterDiveYamlGroup.MaxAgroDepth ?? monsterDiveYamlGroup.MaxDepth ?? 30f);
							maxPassiveDepth = monsterDiveYamlGroup.MaxPassiveDepth ?? num;
						}
						else
						{
							num = Mathf.Max(0f, monsterDiveYamlGroup.MaxDepth ?? 30f);
							maxPassiveDepth = num;
						}
						PassiveDepthProfile depthProfile = new PassiveDepthProfile(valueOrDefault, valueOrDefault2, maxPassiveDepth, num);
						float activeDepthAdjustSpeed = Mathf.Max(0f, monsterDiveYamlGroup.DepthAdjustSpeed ?? 2f);
						bool valueOrDefault3 = monsterDiveYamlGroup.UseBreath.GetValueOrDefault();
						float maxBreathSeconds = Mathf.Max(0f, monsterDiveYamlGroup.MaxBreathSeconds ?? 60f);
						float breathRecoverySpeed = Mathf.Max(0.1f, monsterDiveYamlGroup.BreathRecoverySpeed ?? 1f);
						float surfaceTime = Mathf.Max(0f, monsterDiveYamlGroup.SurfaceTime ?? 3f);
						float surfaceThresholdPercent = Mathf.Clamp01(monsterDiveYamlGroup.SurfaceThresholdPercent ?? 0.33f);
						ConfiguredDiveProfile value = new ConfiguredDiveProfile(text2, depthProfile, activeDepthAdjustSpeed, valueOrDefault3, maxBreathSeconds, breathRecoverySpeed, surfaceTime, surfaceThresholdPercent);
						if (monsterDiveYamlGroup.Prefabs == null)
						{
							continue;
						}
						foreach (string prefab in monsterDiveYamlGroup.Prefabs)
						{
							string text3 = prefab?.Trim() ?? "";
							if (!string.IsNullOrEmpty(text3))
							{
								targetDict[text3] = value;
							}
						}
					}
				}
				catch (Exception ex)
				{
					Debug.LogError((object)("[VBDiving] Failed to load local config: " + ex.Message));
				}
			}
		}

		private static void NotifyServerConfigsChanged()
		{
			if (Object.op_Implicit((Object)(object)ZNet.instance) && ZNet.instance.IsServer())
			{
				VBDiving.OnServerConfigsChanged();
			}
		}

		public static bool ShouldUseServerConfigs()
		{
			if (!Object.op_Implicit((Object)(object)ZNet.instance))
			{
				return false;
			}
			if (ZNet.instance.IsServer())
			{
				return false;
			}
			return VBDiving.SyncMonsterConfigs?.Value ?? true;
		}
	}
	internal class MonsterSwimState
	{
		public float Breath;

		public float MaxBreath;

		public bool WasUnderwater;

		public bool IsSurfacing;

		public float SurfaceTimer;

		public bool WasOutOfBreath;

		public float LastSurfaceTime;

		public float SuffocationTickTimer;
	}
	internal static class MonsterSwimStateManager
	{
		private static readonly Dictionary<int, MonsterSwimState> States = new Dictionary<int, MonsterSwimState>();

		public static MonsterSwimState Get(MonsterAI monsterAI)
		{
			int instanceID = ((Object)monsterAI).GetInstanceID();
			if (!States.TryGetValue(instanceID, out var value))
			{
				value = new MonsterSwimState();
				States[instanceID] = value;
			}
			return value;
		}

		public static void Remove(MonsterAI monsterAI)
		{
			if (Object.op_Implicit((Object)(object)monsterAI))
			{
				States.Remove(((Object)monsterAI).GetInstanceID());
			}
		}

		public static void Clear()
		{
			States.Clear();
		}
	}
}
namespace VBDiving.Water
{
	[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 = WaterHelper.IsCameraUnderwater();
			if (!UnderwaterCopies.TryGetValue(component, out var value) || !Object.op_Implicit((Object)(object)value))
			{
				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);
			((Renderer)originalRenderer).shadowCastingMode = (ShadowCastingMode)1;
			((Renderer)originalRenderer).receiveShadows = true;
			MeshFilter val2 = val.AddComponent<MeshFilter>();
			val2.sharedMesh = originalFilter.sharedMesh;
			MeshRenderer val3 = val.AddComponent<MeshRenderer>();
			((Renderer)val3).sharedMaterial = ((Renderer)originalRenderer).sharedMaterial;
			((Renderer)val3).shadowCastingMode = (ShadowCastingMode)1;
			((Renderer)val3).receiveShadows = true;
			((Renderer)val3).lightProbeUsage = (LightProbeUsage)1;
			((Renderer)val3).reflectionProbeUsage = (ReflectionProbeUsage)0;
			((Renderer)val3).allowOcclusionWhenDynamic = false;
			((Renderer)val3).forceRenderingOff = false;
			((Renderer)val3).enabled = true;
			val.SetActive(false);
			return val;
		}
	}
	[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 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 Prefix(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 (WaterHelper.IsCameraUnderwater())
				{
					ApplyUnderwaterSettings(_instanceMaterial);
				}
				else
				{
					ApplyWaterSettings(_instanceMaterial);
				}
			}
		}

		private static void SaveOriginalValues(Material mat)
		{
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_0029: Unknown result type (might be due to invalid IL or missing references)
			//IL_0043: Unknown result type (might be due to invalid IL or missing references)
			//IL_0048: Unknown result type (might be due to invalid IL or missing references)
			//IL_0062: Unknown result type (might be due to invalid IL or missing references)
			//IL_0067: Unknown result type (might be due to invalid IL or missing references)
			//IL_0083: Unknown result type (might be due to invalid IL or missing references)
			//IL_0088: Unknown result type (might be due to invalid IL or missing references)
			if (!_originalValuesSaved)
			{
				if (mat.HasProperty(ColorTopId))
				{
					_originalColorTop = mat.GetColor(ColorTopId);
				}
				if (mat.HasProperty(ColorBottomId))
				{
					_o