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 _bubbles = new List(); 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)Resources.FindObjectsOfTypeAll()).FirstOrDefault((Func)((TMP_FontAsset f) => ((Object)f).name == "Valheim-Norsebold")); if (!Object.op_Implicit((Object)(object)val)) { val = ((IEnumerable)Resources.FindObjectsOfTypeAll()).FirstOrDefault((Func)((TMP_FontAsset f) => ((Object)f).name == "LiberationSans SDF")); } if (!Object.op_Implicit((Object)(object)val)) { val = Resources.FindObjectsOfTypeAll().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(); val.renderMode = (RenderMode)0; val.sortingOrder = 5000; CanvasScaler val2 = _root.AddComponent(); val2.uiScaleMode = (ScaleMode)1; val2.referenceResolution = new Vector2(1920f, 1080f); val2.matchWidthOrHeight = 0.5f; _root.AddComponent(); GameObject val3 = new GameObject("Container"); val3.transform.SetParent(_root.transform, false); _container = val3.AddComponent(); 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(); 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(); 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(); if (Object.op_Implicit((Object)(object)font)) { ((TMP_Text)_breathText).font = font; } else { TMP_FontAsset val8 = Resources.FindObjectsOfTypeAll().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 EnableMod; internal static ConfigEntry MaxBreathSeconds; internal static ConfigEntry MaxBreathBonusAtSkill100; internal static ConfigEntry BreathRecoveryPerSecond; internal static ConfigEntry SprintSwimMultiplier; internal static ConfigEntry BaseUnderwaterStaminaRegenPerSecond; internal static ConfigEntry DebugLogging; internal static ConfigEntry UseLegacyDiveControls; internal static float SwimStaminaDrainMinSkill = 4f; internal static float SwimStaminaDrainMaxSkill = 2f; internal static ConfigEntry BreathHudOffsetX; internal static ConfigEntry BreathHudOffsetY; internal static ConfigEntry BreathHudScale; internal static ConfigEntry BreathHudShowLabels; internal static ConfigEntry SyncMonsterConfigs; internal static ConfigEntry UseServerMonsterConfigsOnly; internal static ConfigEntry SyncDiveEffectsConfigs; internal static ConfigEntry 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(); ((Component)this).gameObject.AddComponent(); ((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(ref playerDiveController)) { ((Component)player).gameObject.AddComponent(); ((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(((BaseUnityPlugin)this).Config, "00 - Main", "EnableMod", true, "Включить или отключить мод.", true, (int?)null, (AcceptableValueBase)null, (Action)null, (ConfigurationManagerAttributes)null); SyncMonsterConfigs = ConfigFileExtensions.BindConfig(((BaseUnityPlugin)this).Config, "00 - Main", "SyncMonsterConfigs", true, "Синхронизировать конфиги монстров с сервера.", true, (int?)null, (AcceptableValueBase)null, (Action)null, (ConfigurationManagerAttributes)null); UseServerMonsterConfigsOnly = ConfigFileExtensions.BindConfig(((BaseUnityPlugin)this).Config, "00 - Main", "UseServerMonsterConfigsOnly", true, "Использовать ТОЛЬКО конфиги с сервера (игнорировать локальные файлы). Если false - серверные конфиги имеют приоритет над локальными.", true, (int?)null, (AcceptableValueBase)null, (Action)null, (ConfigurationManagerAttributes)null); UseLegacyDiveControls = ((BaseUnityPlugin)this).Config.Bind("01 - Control", "UseLegacyDiveControls", true, "Если true: зажать Crouch для погружения, Jump для всплытия.\nЕсли false: нажать Crouch для переключения режима ныряния, затем направление взгляда + Forward для движения вверх/вниз."); MaxBreathSeconds = ConfigFileExtensions.BindConfig(((BaseUnityPlugin)this).Config, "02 - Breath", "MaxBreathSeconds", 30f, "Максимальное время под водой при навыке плавания 0.", true, (int?)null, (AcceptableValueBase)(object)new AcceptableValueRange(1f, 600f), (Action)null, (ConfigurationManagerAttributes)null); MaxBreathBonusAtSkill100 = ConfigFileExtensions.BindConfig(((BaseUnityPlugin)this).Config, "02 - Breath", "MaxBreathBonusAtSkill100", 150f, "Дополнительное время под водой при навыке плавания 100.", true, (int?)null, (AcceptableValueBase)(object)new AcceptableValueRange(0f, 600f), (Action)null, (ConfigurationManagerAttributes)null); BreathRecoveryPerSecond = ConfigFileExtensions.BindConfig(((BaseUnityPlugin)this).Config, "02 - Breath", "BreathRecoveryPerSecond", 30f, "Скорость восстановления дыхания.", true, (int?)null, (AcceptableValueBase)(object)new AcceptableValueRange(0f, 300f), (Action)null, (ConfigurationManagerAttributes)null); BreathHudOffsetX = ((BaseUnityPlugin)this).Config.Bind("03 - BreathHud", "OffsetX", 0f, "Смещение индикатора по горизонтали от центра экрана (в процентах от ширины экрана).\nОтрицательное = левее, положительное = правее."); BreathHudOffsetY = ((BaseUnityPlugin)this).Config.Bind("03 - BreathHud", "OffsetY", -30f, "Смещение индикатора по вертикали от центра экрана (в процентах от высоты экрана).\nОтрицательное = ниже, положительное = выше."); BreathHudScale = ((BaseUnityPlugin)this).Config.Bind("03 - BreathHud", "Scale", 1f, new ConfigDescription("Масштаб индикатора дыхания.", (AcceptableValueBase)(object)new AcceptableValueRange(0.3f, 3f), Array.Empty())); BreathHudShowLabels = ((BaseUnityPlugin)this).Config.Bind("03 - BreathHud", "ShowLabels", true, "Показывать числовое значение дыхания справа от пузырьков."); SprintSwimMultiplier = ConfigFileExtensions.BindConfig(((BaseUnityPlugin)this).Config, "04 - Swimming", "SprintSwimMultiplier", 2.25f, "Множитель скорости при спринте в воде.", true, (int?)null, (AcceptableValueBase)(object)new AcceptableValueRange(1f, 5f), (Action)null, (ConfigurationManagerAttributes)null); BaseUnderwaterStaminaRegenPerSecond = ConfigFileExtensions.BindConfig(((BaseUnityPlugin)this).Config, "04 - Swimming", "BaseUnderwaterStaminaRegenPerSecond", 1.25f, "Базовая скорость восстановления выносливости на поверхности без движения.", true, (int?)null, (AcceptableValueBase)(object)new AcceptableValueRange(0f, 50f), (Action)null, (ConfigurationManagerAttributes)null); PlayerEquipInWater.EquipInWaterList = ConfigFileExtensions.BindConfig(((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)null, (ConfigurationManagerAttributes)null); PlayerEquipInWater.EquipInWaterList.SettingChanged += delegate { HashSet hashSet2 = new HashSet(); string[] array2 = PlayerEquipInWater.EquipInWaterList.Value.Split(new char[1] { ',' }, StringSplitOptions.RemoveEmptyEntries); foreach (string item2 in array2) { hashSet2.Add(item2); } PlayerEquipInWater.EquipInWaterItems = hashSet2; }; HashSet hashSet = new HashSet(); 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(((BaseUnityPlugin)this).Config, "00 - Main", "SyncDiveEffectsConfigs", true, "Синхронизировать конфиги подводных эффектов с сервера.", true, (int?)null, (AcceptableValueBase)null, (Action)null, (ConfigurationManagerAttributes)null); UseServerDiveEffectsConfigsOnly = ConfigFileExtensions.BindConfig(((BaseUnityPlugin)this).Config, "00 - Main", "UseServerDiveEffectsConfigsOnly", true, "Использовать ТОЛЬКО конфиги с сервера (игнорировать локальные файлы). Если false - серверные конфиги имеют приоритет над локальными.", true, (int?)null, (AcceptableValueBase)null, (Action)null, (ConfigurationManagerAttributes)null); DebugLogging = ((BaseUnityPlugin)this).Config.Bind("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(); 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(); 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 { public MonsterDiveYamlRoot() : base((IEqualityComparer?)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 Prefabs { get; set; } = new List(); } internal static readonly string MonsterDiveConfigFolderPath; private static readonly object MonsterDiveConfigLock; private static readonly IDeserializer MonsterDiveYamlDeserializer; private static readonly Dictionary RouteCache; private static readonly Dictionary SteerCache; private static readonly Dictionary OriginalDiveFlagsByInstance; private const int MaxCacheEntries = 2048; private static readonly object PrefabSetLock; private static Dictionary _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(); SteerCache = new Dictionary(); OriginalDiveFlagsByInstance = new Dictionary(); PrefabSetLock = new object(); _configuredDiveProfilesByPrefabName = new Dictionary(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)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 dictionary = new Dictionary(StringComparer.OrdinalIgnoreCase); List 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 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 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 dictionary = new Dictionary(StringComparer.OrdinalIgnoreCase); string fileName = Path.GetFileName(filePath); foreach (KeyValuePair 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 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(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 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 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 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 dictionary = new Dictionary(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 dictionary2 = new Dictionary(StringComparer.OrdinalIgnoreCase); LoadLocalConfigsToDictionary(dictionary2); foreach (KeyValuePair 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 targetDict) { if (!Directory.Exists(MonsterDiveConfigFolderPath)) { return; } List 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 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 States = new Dictionary(); 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 UnderwaterCopies = new Dictionary(); 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(); MeshFilter component2 = ((Component)__instance.m_waterSurface).GetComponent(); 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(); val2.sharedMesh = originalFilter.sharedMesh; MeshRenderer val3 = val.AddComponent(); ((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)) { _originalColorBottom = mat.GetColor(ColorBottomId); } if (mat.HasProperty(ColorBottomShallowId)) { _originalColorBottomShallow = mat.GetColor(ColorBottomShallowId); } if (mat.HasProperty(SurfaceColorId)) { _originalSurfaceColor = mat.GetColor(SurfaceColorId); } if (mat.HasProperty(DepthFadeId)) { _originalDepthFade = mat.GetFloat(DepthFadeId); } _originalValuesSaved = true; } } private static void ApplyWaterSettings(Material mat) { //IL_002a: Unknown result type (might be due to invalid IL or missing references) //IL_005e: Unknown result type (might be due to invalid IL or missing references) //IL_0092: Unknown result type (might be due to invalid IL or missing references) //IL_00c6: Unknown result type (might be due to invalid IL or missing references) if (mat.HasProperty(ColorTopId)) { mat.SetColor(ColorTopId, new Color(0.2f, 0.25f, 0.2f, 0.95f)); } if (mat.HasProperty(ColorBottomId)) { mat.SetColor(ColorBottomId, new Color(0.15f, 0.2f, 0.2f, 0.95f)); } if (mat.HasProperty(ColorBottomShallowId)) { mat.SetColor(ColorBottomShallowId, new Color(0.2f, 0.25f, 0.2f, 0.95f)); } if (mat.HasProperty(SurfaceColorId)) { mat.SetColor(SurfaceColorId, new Color(0.3f, 0.35f, 0.35f, 0.95f)); } if (mat.HasProperty(DepthFadeId)) { mat.SetFloat(DepthFadeId, _originalDepthFade); } } private static void ApplyUnderwaterSettings(Material mat) { //IL_002a: Unknown result type (might be due to invalid IL or missing references) //IL_005e: Unknown result type (might be due to invalid IL or missing references) //IL_0092: Unknown result type (might be due to invalid IL or missing references) //IL_00c6: Unknown result type (might be due to invalid IL or missing references) if (mat.HasProperty(ColorTopId)) { mat.SetColor(ColorTopId, new Color(0.2f, 0.25f, 0.2f, 0.95f)); } if (mat.HasProperty(ColorBottomId)) { mat.SetColor(ColorBottomId, new Color(0.15f, 0.2f, 0.2f, 0.95f)); } if (mat.HasProperty(ColorBottomShallowId)) { mat.SetColor(ColorBottomShallowId, new Color(0.2f, 0.25f, 0.2f, 0.95f)); } if (mat.HasProperty(SurfaceColorId)) { mat.SetColor(SurfaceColorId, new Color(0.3f, 0.35f, 0.35f, 0.95f)); } if (mat.HasProperty(DepthFadeId)) { mat.SetFloat(DepthFadeId, _originalDepthFade * 2.25f); } } } } namespace VBDiving.Utills { internal sealed class PlayerDiveController : MonoBehaviour { private const float HeadUnderwaterTolerance = 0.01f; internal const float DefaultSwimDepth = 1.2f; internal const float DivingThreshold = 1.35f; internal const float MinSwimDepth = 1.1f; internal const float MaxSwimDepth = 100f; internal const float DepthChangeSpeed = 0.05f; private const float LegacyDepthChangeSpeed = 0.04f; [NonSerialized] internal bool toggleDive; [NonSerialized] internal bool is_diving; [NonSerialized] internal bool isUnderwater; [NonSerialized] internal string lastDiveCancel = "None"; private bool _underwaterMovementActive; private float _baseSwimSpeed; private int _swimmingUpdateContextDepth; private int _swimmingUpdateContextFrame = -1; private float _diveAxis; private float _legacyDiveVertical; private bool _legacyDiveActive; internal static PlayerDiveController? LocalInstance { get; private set; } internal Player Player { get; private set; } = null; private void Awake() { Player = ((Component)this).GetComponent(); if (!Object.op_Implicit((Object)(object)Player)) { Object.Destroy((Object)(object)this); return; } if ((Object)(object)Player != (Object)(object)Player.m_localPlayer) { Object.Destroy((Object)(object)this); return; } LocalInstance = this; ((Character)Player).m_swimDepth = 1.2f; _baseSwimSpeed = ((Character)Player).m_swimSpeed; } private void OnDestroy() { if ((Object)(object)LocalInstance == (Object)(object)this) { LocalInstance = null; } } internal void HandleDiveToggle() { if (!((Character)Player).InWater() || ((Character)Player).IsOnGround() || !((Character)Player).IsSwimming()) { if (toggleDive) { toggleDive = false; is_diving = false; _legacyDiveActive = false; _legacyDiveVertical = 0f; lastDiveCancel = "PlayerOnLand"; } } else if (VBDiving.UseLegacyDiveControls.Value) { HandleLegacyControls(); } else if (ZInput.GetButtonDown("Crouch") || ZInput.GetButtonDown("JoyCrouch")) { if (!toggleDive) { toggleDive = true; lastDiveCancel = "None"; } else if (toggleDive && ((Character)Player).m_swimDepth <= 1.35f) { toggleDive = false; lastDiveCancel = "PlayerCancelled"; } } } private void HandleLegacyControls() { bool flag = ZInput.GetButton("Crouch") || ZInput.GetButton("JoyCrouch"); bool flag2 = ZInput.GetButton("Jump") || ZInput.GetButton("JoyJump"); if (flag && !flag2) { toggleDive = true; _legacyDiveActive = true; _legacyDiveVertical = 1f; lastDiveCancel = "None"; } else if (flag2 && !flag) { _legacyDiveActive = true; _legacyDiveVertical = -1f; if (((Character)Player).m_swimDepth <= 1.3000001f) { toggleDive = false; _legacyDiveActive = false; _legacyDiveVertical = 0f; lastDiveCancel = "PlayerSurfaced"; } } else if (flag && flag2) { toggleDive = true; _legacyDiveActive = true; _legacyDiveVertical = 1f; } else { _legacyDiveVertical = 0f; if (((Character)Player).m_swimDepth <= 1.35f) { toggleDive = false; _legacyDiveActive = false; lastDiveCancel = "PlayerSurfaced"; } else { _legacyDiveActive = false; } } } internal void UpdateDiveState() { //IL_0056: Unknown result type (might be due to invalid IL or missing references) if (!((Character)Player).InWater()) { ((Character)Player).m_swimDepth = 1.2f; return; } if (((Character)Player).m_swimDepth > 1.35f && Mathf.Max(0f, ((Character)Player).GetLiquidLevel() - ((Component)Player).transform.position.y) > 1.35f) { is_diving = true; isUnderwater = true; return; } if (is_diving) { is_diving = false; if (!VBDiving.UseLegacyDiveControls.Value || ((Character)Player).m_swimDepth <= 1.3000001f) { toggleDive = false; } lastDiveCancel = "PlayerSurfaced"; } isUnderwater = false; } internal void UpdateDiveDepth(Vector3 lookDir) { //IL_0062: Unknown result type (might be due to invalid IL or missing references) //IL_0080: Unknown result type (might be due to invalid IL or missing references) //IL_00d5: Unknown result type (might be due to invalid IL or missing references) //IL_0125: Unknown result type (might be due to invalid IL or missing references) //IL_013c: Unknown result type (might be due to invalid IL or missing references) //IL_019e: Unknown result type (might be due to invalid IL or missing references) //IL_019f: Unknown result type (might be due to invalid IL or missing references) //IL_01a1: Unknown result type (might be due to invalid IL or missing references) //IL_0224: Unknown result type (might be due to invalid IL or missing references) //IL_01c5: Unknown result type (might be due to invalid IL or missing references) //IL_01ca: Unknown result type (might be due to invalid IL or missing references) //IL_01f5: Unknown result type (might be due to invalid IL or missing references) //IL_01fb: Unknown result type (might be due to invalid IL or missing references) //IL_0200: Unknown result type (might be due to invalid IL or missing references) //IL_0207: Unknown result type (might be due to invalid IL or missing references) //IL_020c: Unknown result type (might be due to invalid IL or missing references) //IL_0211: Unknown result type (might be due to invalid IL or missing references) //IL_0215: Unknown result type (might be due to invalid IL or missing references) //IL_021a: Unknown result type (might be due to invalid IL or missing references) if (!((Character)Player).InWater() || ((Character)Player).IsOnGround() || !((Character)Player).IsSwimming()) { return; } if (VBDiving.UseLegacyDiveControls.Value) { UpdateLegacyDiveMovement(); } else { if (!toggleDive) { return; } if (lookDir.y < -0.15f) { _diveAxis = 1f; } else if (lookDir.y > 0.15f) { _diveAxis = 0f; } if (!ZInput.GetButton("Forward") && !ZInput.GetButton("JoyLStickUp")) { return; } float num2; if (_diveAxis == 1f) { float num = Mathf.Abs(lookDir.y); num2 = num * 0.05f; if (num2 < 0.005f && num > 0.9f) { num2 = 0.005f; } } else if (_diveAxis == 0f) { num2 = lookDir.y * 0.05f; if (num2 < 0.005f && lookDir.y > 0.9f) { num2 = 0.005f; } } else { num2 = 0f; } if (num2 > 0.05f) { num2 = 0.05f; } ApplyVerticalMovement(num2); if (!(((Character)Player).m_swimDepth > 1.35f)) { return; } Vector3 moveDir = lookDir; if (Mathf.Abs(lookDir.y) > 0.95f) { Vector3 forward = ((Component)Player).transform.forward; forward.y = 0f; if (((Vector3)(ref forward)).magnitude > 0.01f) { ((Vector3)(ref forward)).Normalize(); Vector3 val = lookDir * 0.7f + forward * 0.3f; moveDir = ((Vector3)(ref val)).normalized; } } ((Character)Player).SetMoveDir(moveDir); } } private void UpdateLegacyDiveMovement() { //IL_0184: Unknown result type (might be due to invalid IL or missing references) //IL_0189: Unknown result type (might be due to invalid IL or missing references) //IL_018d: Unknown result type (might be due to invalid IL or missing references) //IL_0199: Unknown result type (might be due to invalid IL or missing references) //IL_00a7: Unknown result type (might be due to invalid IL or missing references) //IL_00ac: Unknown result type (might be due to invalid IL or missing references) //IL_00b0: Unknown result type (might be due to invalid IL or missing references) //IL_00bc: Unknown result type (might be due to invalid IL or missing references) //IL_01f6: Unknown result type (might be due to invalid IL or missing references) //IL_01fb: Unknown result type (might be due to invalid IL or missing references) //IL_01bb: Unknown result type (might be due to invalid IL or missing references) //IL_01c5: Unknown result type (might be due to invalid IL or missing references) //IL_01ca: Unknown result type (might be due to invalid IL or missing references) //IL_01d4: Unknown result type (might be due to invalid IL or missing references) //IL_01d9: Unknown result type (might be due to invalid IL or missing references) //IL_01de: Unknown result type (might be due to invalid IL or missing references) //IL_01e2: Unknown result type (might be due to invalid IL or missing references) //IL_01e7: Unknown result type (might be due to invalid IL or missing references) //IL_0119: Unknown result type (might be due to invalid IL or missing references) //IL_011e: Unknown result type (might be due to invalid IL or missing references) //IL_00de: Unknown result type (might be due to invalid IL or missing references) //IL_00e8: Unknown result type (might be due to invalid IL or missing references) //IL_00ed: Unknown result type (might be due to invalid IL or missing references) //IL_00f7: Unknown result type (might be due to invalid IL or missing references) //IL_00fc: Unknown result type (might be due to invalid IL or missing references) //IL_0101: Unknown result type (might be due to invalid IL or missing references) //IL_0105: Unknown result type (might be due to invalid IL or missing references) //IL_010a: Unknown result type (might be due to invalid IL or missing references) //IL_0226: Unknown result type (might be due to invalid IL or missing references) //IL_0230: Unknown result type (might be due to invalid IL or missing references) //IL_0235: Unknown result type (might be due to invalid IL or missing references) //IL_023f: Unknown result type (might be due to invalid IL or missing references) //IL_0244: Unknown result type (might be due to invalid IL or missing references) //IL_0249: Unknown result type (might be due to invalid IL or missing references) //IL_024d: Unknown result type (might be due to invalid IL or missing references) //IL_0252: Unknown result type (might be due to invalid IL or missing references) //IL_021d: Unknown result type (might be due to invalid IL or missing references) //IL_0222: Unknown result type (might be due to invalid IL or missing references) //IL_0149: Unknown result type (might be due to invalid IL or missing references) //IL_0153: Unknown result type (might be due to invalid IL or missing references) //IL_0158: Unknown result type (might be due to invalid IL or missing references) //IL_0162: Unknown result type (might be due to invalid IL or missing references) //IL_0167: Unknown result type (might be due to invalid IL or missing references) //IL_016c: Unknown result type (might be due to invalid IL or missing references) //IL_0170: Unknown result type (might be due to invalid IL or missing references) //IL_0175: Unknown result type (might be due to invalid IL or missing references) //IL_0140: Unknown result type (might be due to invalid IL or missing references) //IL_0145: Unknown result type (might be due to invalid IL or missing references) //IL_025b: Unknown result type (might be due to invalid IL or missing references) float legacyDiveVertical = _legacyDiveVertical; if (Mathf.Abs(legacyDiveVertical) < 0.01f) { return; } if (legacyDiveVertical < 0f && ((Character)Player).m_swimDepth <= 1.2f) { ((Character)Player).m_swimDepth = 1.2f; return; } float num = legacyDiveVertical * 0.04f; float num2 = ((Character)Player).m_swimDepth + num; num2 = Mathf.Clamp(num2, 1.2f, 100f); ((Character)Player).m_swimDepth = num2; Vector3 val2; Vector3 normalized; if (legacyDiveVertical > 0f) { Vector3 lookDir = ((Character)Player).GetLookDir(); Vector3 val = default(Vector3); ((Vector3)(ref val))..ctor(lookDir.x, 0f, lookDir.z); if (((Vector3)(ref val)).magnitude > 0.1f) { val2 = ((Vector3)(ref val)).normalized * 0.7f + Vector3.down * 0.3f; normalized = ((Vector3)(ref val2)).normalized; } else { Vector3 forward = ((Component)Player).transform.forward; forward.y = 0f; if (((Vector3)(ref forward)).magnitude < 0.1f) { forward = Vector3.forward; } val2 = ((Vector3)(ref forward)).normalized * 0.3f + Vector3.down * 0.7f; normalized = ((Vector3)(ref val2)).normalized; } } else { Vector3 lookDir2 = ((Character)Player).GetLookDir(); Vector3 val3 = default(Vector3); ((Vector3)(ref val3))..ctor(lookDir2.x, 0f, lookDir2.z); if (((Vector3)(ref val3)).magnitude > 0.1f) { val2 = ((Vector3)(ref val3)).normalized * 0.7f + Vector3.up * 0.3f; normalized = ((Vector3)(ref val2)).normalized; } else { Vector3 forward2 = ((Component)Player).transform.forward; forward2.y = 0f; if (((Vector3)(ref forward2)).magnitude < 0.1f) { forward2 = Vector3.forward; } val2 = ((Vector3)(ref forward2)).normalized * 0.3f + Vector3.up * 0.7f; normalized = ((Vector3)(ref val2)).normalized; } } ((Character)Player).SetMoveDir(normalized); } private void ApplyVerticalMovement(float multiplier) { if (_diveAxis == 1f) { Player player = Player; ((Character)player).m_swimDepth = ((Character)player).m_swimDepth + multiplier; } else if (_diveAxis == 0f) { if (((Character)Player).m_swimDepth > 1.2f) { Player player2 = Player; ((Character)player2).m_swimDepth = ((Character)player2).m_swimDepth - multiplier; } if (((Character)Player).m_swimDepth < 1.2f) { ((Character)Player).m_swimDepth = 1.2f; } } if (((Character)Player).m_swimDepth > 100f) { ((Character)Player).m_swimDepth = 100f; } } internal void DisableUnderwaterMovement() { _underwaterMovementActive = false; toggleDive = false; is_diving = false; _legacyDiveActive = false; _legacyDiveVertical = 0f; ResetSwimDepthToDefault(); ((Character)Player).m_swimSpeed = _baseSwimSpeed; } internal void ResetSwimDepthIfNotInWater() { if (!WaterHelper.IsBodyInWater(Player)) { DisableUnderwaterMovement(); } } internal void ResetSwimDepthToDefault() { //IL_0056: Unknown result type (might be due to invalid IL or missing references) //IL_005b: Unknown result type (might be due to invalid IL or missing references) //IL_0075: Unknown result type (might be due to invalid IL or missing references) ((Character)Player).m_swimDepth = 1.2f; if (WaterHelper.IsBodyInWater(Player) && !toggleDive && !is_diving && !_legacyDiveActive) { float liquidLevel = ((Character)Player).GetLiquidLevel(); Vector3 position = ((Component)Player).transform.position; position.y = liquidLevel - 1.2f; ((Component)Player).transform.position = position; } } internal bool CanDive() { if (!WaterHelper.IsBodyInWater(Player) || ((Character)Player).IsOnGround()) { return false; } return true; } internal bool IsHeadUnderwater() { //IL_0035: Unknown result type (might be due to invalid IL or missing references) //IL_001e: Unknown result type (might be due to invalid IL or missing references) float num = (Object.op_Implicit((Object)(object)((Character)Player).m_eye) ? ((Character)Player).m_eye.position.y : ((Component)Player).transform.position.y); return ((Character)Player).GetLiquidLevel() - num > 0.01f; } internal void RefreshUnderwaterMovementState() { if (!WaterHelper.IsBodyInWater(Player) || !IsHeadUnderwater()) { _underwaterMovementActive = false; } else if (IsUnderSurface()) { _underwaterMovementActive = true; } } internal bool ShouldForceSwimming() { return _underwaterMovementActive && WaterHelper.IsBodyInWater(Player) && IsHeadUnderwater(); } internal bool ShouldForceDive() { return ShouldForceSwimming() && !((Character)Player).IsOnGround(); } internal bool IsUnderSurface() { return ((Character)Player).m_swimDepth > 1.2f; } internal bool IsDiving() { return ((Character)Player).m_swimDepth > 1.35f; } internal bool IsSurfacing() { return !IsDiving() && IsUnderSurface(); } internal bool IsIdleInWater() { //IL_0028: Unknown result type (might be due to invalid IL or missing references) //IL_002d: Unknown result type (might be due to invalid IL or missing references) int result; if (WaterHelper.IsBodyInWater(Player) && (WaterHelper.IsBodyInWater(Player) || ShouldForceSwimming())) { Vector3 velocity = ((Character)Player).GetVelocity(); result = ((((Vector3)(ref velocity)).magnitude < 1f) ? 1 : 0); } else { result = 0; } return (byte)result != 0; } internal void BeginSwimmingUpdateContext() { _swimmingUpdateContextDepth++; _swimmingUpdateContextFrame = Time.frameCount; } internal void EndSwimmingUpdateContext() { if (_swimmingUpdateContextDepth > 0) { _swimmingUpdateContextDepth--; } if (_swimmingUpdateContextDepth == 0) { _swimmingUpdateContextFrame = -1; } } internal bool IsInSwimmingUpdateContext() { return _swimmingUpdateContextDepth > 0 && _swimmingUpdateContextFrame == Time.frameCount; } internal void UpdateSwimSpeed() { float num = 1f; if (InputHelper.GetRun()) { float skillFactor = Player.m_skills.GetSkillFactor((SkillType)103); float num2 = Mathf.Max(1f, VBDiving.SprintSwimMultiplier.Value); num = Mathf.Lerp(1f, num2, Mathf.Pow(skillFactor, 1.5f)); } ((Character)Player).m_swimSpeed = _baseSwimSpeed * num; } } internal struct BiomeUnderwaterSettings { public Color FogColor; public Color FogColorSun; public float FogDensity; public float LightFalloffStartDepth; public float LightFalloffEndDepth; public float LightMultiplierMin; public float SurfaceFogMultiplier; public float DepthFogMultiplier; public BiomeUnderwaterSettings(Color fog, Color fogSun, float density, float lightFalloffStart = 5f, float lightFalloffEnd = 25f, float lightMin = 0.15f, float surfaceFogMult = 1.2f, float depthFogMult = 0.9f) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0003: Unknown result type (might be due to invalid IL or missing references) //IL_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) FogColor = fog; FogColorSun = fogSun; FogDensity = density; LightFalloffStartDepth = lightFalloffStart; LightFalloffEndDepth = lightFalloffEnd; LightMultiplierMin = lightMin; SurfaceFogMultiplier = surfaceFogMult; DepthFogMultiplier = depthFogMult; } public BiomeUnderwaterSettings(BiomeUnderwaterSettings other) { //IL_0003: Unknown result type (might be due to invalid IL or missing references) //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_000f: Unknown result type (might be due to invalid IL or missing references) //IL_0014: Unknown result type (might be due to invalid IL or missing references) FogColor = other.FogColor; FogColorSun = other.FogColorSun; FogDensity = other.FogDensity; LightFalloffStartDepth = other.LightFalloffStartDepth; LightFalloffEndDepth = other.LightFalloffEndDepth; LightMultiplierMin = other.LightMultiplierMin; SurfaceFogMultiplier = other.SurfaceFogMultiplier; DepthFogMultiplier = other.DepthFogMultiplier; } public static BiomeUnderwaterSettings Lerp(BiomeUnderwaterSettings a, BiomeUnderwaterSettings b, float t) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_000e: Unknown result type (might be due to invalid IL or missing references) //IL_0014: 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_0020: Unknown result type (might be due to invalid IL or missing references) return new BiomeUnderwaterSettings(Color.Lerp(a.FogColor, b.FogColor, t), Color.Lerp(a.FogColorSun, b.FogColorSun, t), Mathf.Lerp(a.FogDensity, b.FogDensity, t), Mathf.Lerp(a.LightFalloffStartDepth, b.LightFalloffStartDepth, t), Mathf.Lerp(a.LightFalloffEndDepth, b.LightFalloffEndDepth, t), Mathf.Lerp(a.LightMultiplierMin, b.LightMultiplierMin, t), Mathf.Lerp(a.SurfaceFogMultiplier, b.SurfaceFogMultiplier, t), Mathf.Lerp(a.DepthFogMultiplier, b.DepthFogMultiplier, t)); } } internal static class InputHelper { public static bool GetRun() { return ZInput.GetButton("Run"); } public static bool GetJump() { return ZInput.GetButton("Jump"); } public static bool GetCrouch() { return ZInput.GetButton("Crouch"); } public static float GetHorizontal() { return Input.GetAxisRaw("Horizontal"); } public static float GetVertical() { return Input.GetAxisRaw("Vertical"); } public static float GetDiveVertical() { float num = 0f; if (GetJump()) { num += 1f; } if (GetCrouch()) { num -= 1f; } return num; } } public static class SwimAPI { public static event Action OnEnterWater; public static event Action OnExitWater; public static event Action OnHeadUnderwater; public static event Action OnHeadAboveWater; public static event Action OnOutOfBreath; public static float GetBreathPercent(Player player) { if (!Object.op_Implicit((Object)(object)player)) { return 1f; } SwimState swimState = SwimStateManager.Get(player); float maxBreath = GetMaxBreath(player); if (maxBreath <= 0f) { return 0f; } return Mathf.Clamp01(swimState.Breath / maxBreath); } public static bool IsUnderwater(Player player) { if (!Object.op_Implicit((Object)(object)player)) { return false; } return WaterHelper.IsHeadUnderwater(player); } public static bool IsSwimming(Player player) { if (!Object.op_Implicit((Object)(object)player)) { return false; } return WaterHelper.IsBodyInWater(player); } public static float GetCurrentBreath(Player player) { if (!Object.op_Implicit((Object)(object)player)) { return 0f; } return SwimStateManager.Get(player).Breath; } public static float GetBaseMaxBreath(Player player) { if (!Object.op_Implicit((Object)(object)player)) { return VBDiving.MaxBreathSeconds.Value; } float skillFactor = ((Character)player).GetSkillFactor((SkillType)103); return VBDiving.MaxBreathSeconds.Value + VBDiving.MaxBreathBonusAtSkill100.Value * skillFactor; } public static float GetMaxBreath(Player player) { if (!Object.op_Implicit((Object)(object)player)) { return VBDiving.MaxBreathSeconds.Value; } SwimState swimState = SwimStateManager.Get(player); return GetBaseMaxBreath(player) + swimState.ExtraBreathBonus; } public static bool IsOutOfBreath(Player player) { return GetCurrentBreath(player) <= 0f; } public static float GetSwimSkillFactor(Player player) { if (!Object.op_Implicit((Object)(object)player)) { return 0f; } return ((Character)player).GetSkillFactor((SkillType)103); } public static bool HasInfiniteBreath(Player player) { if (!Object.op_Implicit((Object)(object)player)) { return false; } SwimState swimState = SwimStateManager.Get(player); return Time.time < swimState.InfiniteBreathUntil; } public static float GetExternalSwimSpeedMultiplier(Player player) { if (!Object.op_Implicit((Object)(object)player)) { return 1f; } SwimState swimState = SwimStateManager.Get(player); if (Time.time >= swimState.SwimSpeedMultiplierUntil) { swimState.SwimSpeedMultiplier = 1f; return 1f; } return swimState.SwimSpeedMultiplier; } public static void RestoreBreath(Player player, float amount) { if (Object.op_Implicit((Object)(object)player) && !(amount <= 0f)) { SwimState swimState = SwimStateManager.Get(player); swimState.Breath = Mathf.Min(GetMaxBreath(player), swimState.Breath + amount); } } public static void DrainBreath(Player player, float amount) { if (Object.op_Implicit((Object)(object)player) && !(amount <= 0f)) { SwimState swimState = SwimStateManager.Get(player); swimState.Breath = Mathf.Max(0f, swimState.Breath - amount); } } public static void SetInfiniteBreath(Player player, float duration) { if (Object.op_Implicit((Object)(object)player) && !(duration <= 0f)) { SwimState swimState = SwimStateManager.Get(player); swimState.InfiniteBreathUntil = Mathf.Max(swimState.InfiniteBreathUntil, Time.time + duration); swimState.Breath = GetMaxBreath(player); } } public static void AddBreathBonus(Player player, float bonusSeconds) { if (Object.op_Implicit((Object)(object)player)) { SwimState swimState = SwimStateManager.Get(player); swimState.ExtraBreathBonus = Mathf.Max(0f, swimState.ExtraBreathBonus + bonusSeconds); swimState.Breath = Mathf.Min(swimState.Breath, GetMaxBreath(player)); } } public static void SetBreathBonus(Player player, float bonusSeconds) { if (Object.op_Implicit((Object)(object)player)) { SwimState swimState = SwimStateManager.Get(player); swimState.ExtraBreathBonus = Mathf.Max(0f, bonusSeconds); swimState.Breath = Mathf.Min(swimState.Breath, GetMaxBreath(player)); } } public static void AddSwimSpeedBonus(Player player, float multiplier, float duration) { if (Object.op_Implicit((Object)(object)player) && !(multiplier <= 0f) && !(duration <= 0f)) { SwimState swimState = SwimStateManager.Get(player); swimState.SwimSpeedMultiplier = Mathf.Max(swimState.SwimSpeedMultiplier, multiplier); swimState.SwimSpeedMultiplierUntil = Mathf.Max(swimState.SwimSpeedMultiplierUntil, Time.time + duration); } } internal static void UpdateEvents(Player player) { if (Object.op_Implicit((Object)(object)player)) { SwimState swimState = SwimStateManager.Get(player); bool flag = IsSwimming(player); bool flag2 = IsUnderwater(player); bool flag3 = IsOutOfBreath(player); if (flag && !swimState.WasSwimming) { SwimAPI.OnEnterWater?.Invoke(player); } else if (!flag && swimState.WasSwimming) { SwimAPI.OnExitWater?.Invoke(player); } if (flag2 && !swimState.WasHeadUnderwater) { SwimAPI.OnHeadUnderwater?.Invoke(player); } else if (!flag2 && swimState.WasHeadUnderwater) { SwimAPI.OnHeadAboveWater?.Invoke(player); } if (flag3 && !swimState.WasOutOfBreath) { SwimAPI.OnOutOfBreath?.Invoke(player); } swimState.WasSwimming = flag; swimState.WasHeadUnderwater = flag2; swimState.WasOutOfBreath = flag3; } } } internal class SwimState { public float Breath; public bool WasHeadUnderwater; public bool WasSwimming; public float LastSurfaceTime; public float SuffocationTickTimer; public float ExtraBreathBonus; public float InfiniteBreathUntil; public float SwimSpeedMultiplier = 1f; public float SwimSpeedMultiplierUntil; public bool WasOutOfBreath; } internal static class SwimStateManager { private static readonly Dictionary States = new Dictionary(); public static SwimState Get(Player player) { long playerID = player.GetPlayerID(); if (!States.TryGetValue(playerID, out var value)) { value = new SwimState { Breath = SwimAPI.GetBaseMaxBreath(player), WasHeadUnderwater = false, WasSwimming = false, LastSurfaceTime = 0f, SuffocationTickTimer = 0f, ExtraBreathBonus = 0f, InfiniteBreathUntil = 0f, SwimSpeedMultiplier = 1f, SwimSpeedMultiplierUntil = 0f, WasOutOfBreath = false }; States[playerID] = value; } return value; } public static void Remove(Player player) { if (Object.op_Implicit((Object)(object)player)) { States.Remove(player.GetPlayerID()); } } } internal static class WaterHelper { public static bool TryGetWaterLevel(Vector3 position, out float waterLevel) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) waterLevel = Floating.GetLiquidLevel(position, 1f, (LiquidType)0); return waterLevel > -10000f; } public static float GetPlayerDepth(Player player) { //IL_0035: Unknown result type (might be due to invalid IL or missing references) //IL_003a: Unknown result type (might be due to invalid IL or missing references) //IL_003b: 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) if (!Object.op_Implicit((Object)(object)player)) { return 0f; } if (!((Character)player).InWater()) { return 0f; } float liquidLevel = ((Character)player).GetLiquidLevel(); Vector3 headPoint = ((Character)player).GetHeadPoint(); if (headPoint.y >= liquidLevel) { return 0f; } return liquidLevel - headPoint.y; } public static Vector3 GetHeadPosition(Player player) { //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_0010: Unknown result type (might be due to invalid IL or missing references) //IL_0015: Unknown result type (might be due to invalid IL or missing references) //IL_001f: Unknown result type (might be due to invalid IL or missing references) //IL_0020: Unknown result type (might be due to invalid IL or missing references) //IL_0023: Unknown result type (might be due to invalid IL or missing references) if (!Object.op_Implicit((Object)(object)player)) { return Vector3.zero; } return ((Character)player).GetHeadPoint(); } public static Vector3 GetChestPosition(Player player) { //IL_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_002d: Unknown result type (might be due to invalid IL or missing references) //IL_0032: Unknown result type (might be due to invalid IL or missing references) //IL_0037: 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_0015: Unknown result type (might be due to invalid IL or missing references) //IL_0038: Unknown result type (might be due to invalid IL or missing references) //IL_0039: Unknown result type (might be due to invalid IL or missing references) //IL_003c: Unknown result type (might be due to invalid IL or missing references) if (!Object.op_Implicit((Object)(object)player)) { return Vector3.zero; } return ((Component)player).transform.position + Vector3.up * 1f; } public static bool IsBodyInWater(Player player) { //IL_0016: Unknown result type (might be due to invalid IL or missing references) //IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_002d: Unknown result type (might be due to invalid IL or missing references) if (!Object.op_Implicit((Object)(object)player)) { return false; } Vector3 chestPosition = GetChestPosition(player); float waterLevel; return TryGetWaterLevel(chestPosition, out waterLevel) && chestPosition.y < waterLevel; } public static bool IsHeadUnderwater(Player player) { //IL_0016: Unknown result type (might be due to invalid IL or missing references) //IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_002d: Unknown result type (might be due to invalid IL or missing references) if (!Object.op_Implicit((Object)(object)player)) { return false; } Vector3 headPosition = GetHeadPosition(player); float waterLevel; return TryGetWaterLevel(headPosition, out waterLevel) && headPosition.y < waterLevel - 0.02f; } public static bool IsNearSurface(Player player, float tolerance = 0.35f) { //IL_0016: Unknown result type (might be due to invalid IL or missing references) //IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_002d: Unknown result type (might be due to invalid IL or missing references) if (!Object.op_Implicit((Object)(object)player)) { return false; } Vector3 headPosition = GetHeadPosition(player); float waterLevel; return TryGetWaterLevel(headPosition, out waterLevel) && Mathf.Abs(headPosition.y - waterLevel) <= tolerance; } public static bool IsCameraUnderwater() { //IL_003a: Unknown result type (might be due to invalid IL or missing references) //IL_0059: Unknown result type (might be due to invalid IL or missing references) if (!Object.op_Implicit((Object)(object)GameCamera.instance)) { return false; } Camera component = ((Component)GameCamera.instance).GetComponent(); if (!Object.op_Implicit((Object)(object)component)) { return false; } if (!TryGetWaterLevel(((Component)component).transform.position, out var waterLevel)) { return false; } return ((Component)component).transform.position.y < waterLevel - 0.01f; } } } namespace VBDiving.Patches { [HarmonyPatch(typeof(Player), "UseStamina")] internal static class UseStaminaPatch { private static bool AllowStaminaUseFromSwimSprint; private static bool Prefix(Player __instance, ref float v) { if (!VBDiving.IsEnabled()) { return true; } if (AllowStaminaUseFromSwimSprint) { return true; } if (!Object.op_Implicit((Object)(object)__instance) || (Object)(object)__instance != (Object)(object)Player.m_localPlayer) { return true; } if (!WaterHelper.IsBodyInWater(__instance)) { return true; } return true; } } [HarmonyPatch(typeof(Character), "CustomFixedUpdate")] internal static class CharacterSurfaceFix { [HarmonyPostfix] private static void Postfix(Character __instance) { //IL_002b: Unknown result type (might be due to invalid IL or missing references) //IL_0031: Expected O, but got Unknown //IL_0098: Unknown result type (might be due to invalid IL or missing references) //IL_00bb: Unknown result type (might be due to invalid IL or missing references) //IL_00c0: Unknown result type (might be due to invalid IL or missing references) //IL_00c4: Unknown result type (might be due to invalid IL or missing references) //IL_00e7: Unknown result type (might be due to invalid IL or missing references) //IL_0102: Unknown result type (might be due to invalid IL or missing references) //IL_011f: Unknown result type (might be due to invalid IL or missing references) //IL_0124: Unknown result type (might be due to invalid IL or missing references) //IL_0128: Unknown result type (might be due to invalid IL or missing references) //IL_0140: Unknown result type (might be due to invalid IL or missing references) if (!VBDiving.IsEnabled() || (Object)(object)__instance != (Object)(object)Player.m_localPlayer) { return; } Player val = (Player)__instance; if (!WaterHelper.IsBodyInWater(val)) { return; } PlayerDiveController localInstance = PlayerDiveController.LocalInstance; if (!Object.op_Implicit((Object)(object)localInstance) || localInstance.toggleDive || localInstance.is_diving || localInstance.IsHeadUnderwater()) { return; } float liquidLevel = ((Character)val).GetLiquidLevel(); float num = liquidLevel - 1.2f; if (((Component)val).transform.position.y < num - 0.1f) { Vector3 position = ((Component)val).transform.position; position.y = Mathf.Lerp(position.y, num, Time.fixedDeltaTime * 8f); ((Component)val).transform.position = position; Rigidbody component = ((Component)val).GetComponent(); if (Object.op_Implicit((Object)(object)component) && component.linearVelocity.y < 0f) { Vector3 linearVelocity = component.linearVelocity; linearVelocity.y = Mathf.Max(linearVelocity.y, 0f); component.linearVelocity = linearVelocity; } } ((Character)val).m_swimDepth = 1.2f; } } [HarmonyPatch] internal static class CharacterWaterStatePatch { [HarmonyPostfix] [HarmonyPatch(typeof(Character), "IsOnGround")] private static void CharacterIsOnGroundPostfix(Character __instance, ref bool __result) { if (VBDiving.IsEnabled()) { Player val = (Player)(object)((__instance is Player) ? __instance : null); if (Object.op_Implicit((Object)(object)val) && !((Object)(object)val != (Object)(object)Player.m_localPlayer) && WaterHelper.IsBodyInWater(val)) { __result = false; } } } [HarmonyPostfix] [HarmonyPatch(typeof(Character), "InWater")] private static void CharacterInWaterPostfix(Character __instance, ref bool __result) { if (VBDiving.IsEnabled()) { Player val = (Player)(object)((__instance is Player) ? __instance : null); if (Object.op_Implicit((Object)(object)val) && !((Object)(object)val != (Object)(object)Player.m_localPlayer) && WaterHelper.IsBodyInWater(val)) { __result = true; } } } } [HarmonyPatch] internal static class DiveControllerPatches { [HarmonyPostfix] [HarmonyPatch(typeof(Player), "Awake")] private static void PlayerAwakePostfix(Player __instance) { if ((Object)(object)__instance == (Object)(object)Player.m_localPlayer) { EnsureLocalDiver(); } } [HarmonyPrefix] [HarmonyPatch(typeof(Character), "UpdateMotion")] private static void CharacterUpdateMotionPrefix(Character __instance, ref float ___m_lastGroundTouch, ref float ___m_swimTimer) { if ((Object)(object)__instance != (Object)(object)Player.m_localPlayer) { return; } PlayerDiveController playerDiveController = EnsureLocalDiver(); if (Object.op_Implicit((Object)(object)playerDiveController)) { playerDiveController.ResetSwimDepthIfNotInWater(); if (playerDiveController.is_diving || WaterHelper.IsBodyInWater((Player)(object)((__instance is Player) ? __instance : null))) { ___m_lastGroundTouch = 0.3f; ___m_swimTimer = 0f; } } } [HarmonyPrefix] [HarmonyPatch(typeof(Character), "UpdateSwimming")] private static void CharacterUpdateSwimmingPrefix(Character __instance) { if ((Object)(object)__instance != (Object)(object)Player.m_localPlayer) { return; } Player val = (Player)(object)((__instance is Player) ? __instance : null); if (Object.op_Implicit((Object)(object)val)) { PlayerDiveController playerDiveController = EnsureLocalDiver(); if (Object.op_Implicit((Object)(object)playerDiveController)) { playerDiveController.UpdateSwimSpeed(); ApplySwimStaminaSettings(val); } } } private static void ApplySwimStaminaSettings(Player player) { if (WaterHelper.IsBodyInWater(player)) { float num = VBDiving.SwimStaminaDrainMinSkill; float num2 = VBDiving.SwimStaminaDrainMaxSkill; if (WaterHelper.IsHeadUnderwater(player)) { num *= 2f; num2 *= 2f; } if (InputHelper.GetRun() && player.GetStamina() > 0f) { num *= 1.5f; num2 *= 1.5f; } player.m_swimStaminaDrainMinSkill = num; player.m_swimStaminaDrainMaxSkill = num2; } } [HarmonyPrefix] [HarmonyPatch(typeof(Character), "CustomFixedUpdate")] private static void CharacterCustomFixedUpdatePrefix(Character __instance, ref Vector3 ___m_moveDir, ref Vector3 ___m_lookDir) { //IL_0094: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)__instance != (Object)(object)Player.m_localPlayer || !__instance.IsPlayer()) { return; } PlayerDiveController playerDiveController = EnsureLocalDiver(); if (Object.op_Implicit((Object)(object)playerDiveController)) { playerDiveController.HandleDiveToggle(); playerDiveController.UpdateDiveState(); if (!__instance.InWater()) { __instance.m_swimDepth = 1.2f; } else if (playerDiveController.toggleDive && __instance.InWater() && !__instance.IsOnGround() && __instance.IsSwimming()) { playerDiveController.UpdateDiveDepth(___m_lookDir); } else if ((__instance.IsOnGround() || !playerDiveController.is_diving) && !playerDiveController.isUnderwater) { __instance.m_swimDepth = 1.2f; } } } [HarmonyPrefix] [HarmonyPatch(typeof(Character), "UpdateRotation")] private static void CharacterUpdateRotationPrefix(Character __instance, out Quaternion? __state) { //IL_003c: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)__instance != (Object)(object)Player.m_localPlayer) { __state = null; return; } PlayerDiveController localInstance = PlayerDiveController.LocalInstance; if (Object.op_Implicit((Object)(object)localInstance) && localInstance.is_diving) { __state = ((Component)__instance).transform.rotation; } else { __state = null; } } [HarmonyPostfix] [HarmonyPatch(typeof(Character), "UpdateRotation")] private static void CharacterUpdateRotationPostfix(Character __instance, float turnSpeed, float dt, ref Quaternion? __state) { //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_002a: Unknown result type (might be due to invalid IL or missing references) //IL_0099: Unknown result type (might be due to invalid IL or missing references) //IL_007a: Unknown result type (might be due to invalid IL or missing references) //IL_007f: Unknown result type (might be due to invalid IL or missing references) //IL_009e: Unknown result type (might be due to invalid IL or missing references) //IL_00b4: Unknown result type (might be due to invalid IL or missing references) //IL_00b9: Unknown result type (might be due to invalid IL or missing references) //IL_00bd: Unknown result type (might be due to invalid IL or missing references) //IL_008c: Unknown result type (might be due to invalid IL or missing references) //IL_0091: Unknown result type (might be due to invalid IL or missing references) if (__state.HasValue && Object.op_Implicit((Object)(object)__instance) && !((Object)(object)__instance != (Object)(object)Player.m_localPlayer) && !(((Component)__instance).transform.rotation != __state.Value)) { PlayerDiveController localInstance = PlayerDiveController.LocalInstance; if (Object.op_Implicit((Object)(object)localInstance) && localInstance.is_diving) { Player player = localInstance.Player; Quaternion val = ((((Character)player).AlwaysRotateCamera() || ((Character)player).m_moveDir == Vector3.zero) ? ((Character)player).m_lookYaw : Quaternion.LookRotation(((Character)player).m_moveDir)); float num = turnSpeed * ((Character)player).GetAttackSpeedFactorRotation(); ((Component)player).transform.rotation = Quaternion.RotateTowards(((Component)player).transform.rotation, val, num * dt); } } } [HarmonyPrefix] [HarmonyPatch(typeof(Player), "SetControls")] private static void PlayerSetControlsPrefix(Player __instance, ref bool crouch) { if ((Object)(object)__instance == (Object)(object)Player.m_localPlayer && ((Character)__instance).InWater()) { crouch = false; } } private static PlayerDiveController? EnsureLocalDiver() { Player localPlayer = Player.m_localPlayer; if (!Object.op_Implicit((Object)(object)localPlayer)) { return null; } PlayerDiveController playerDiveController = PlayerDiveController.LocalInstance; if (Object.op_Implicit((Object)(object)playerDiveController) && (Object)(object)playerDiveController.Player == (Object)(object)localPlayer) { return playerDiveController; } if (!((Component)localPlayer).TryGetComponent(ref playerDiveController)) { playerDiveController = ((Component)localPlayer).gameObject.AddComponent(); } return playerDiveController; } } [HarmonyPatch(typeof(GameCamera), "UpdateCamera")] internal static class GameCameraPatch { private static float _originalMaxDistance; private static float _originalMinWaterDistance; private static bool _cachedOriginalValues; [HarmonyPrefix] private static void Prefix(GameCamera __instance, Camera ___m_camera) { if (!VBDiving.IsEnabled()) { return; } Player localPlayer = Player.m_localPlayer; if (Object.op_Implicit((Object)(object)localPlayer) && Object.op_Implicit((Object)(object)___m_camera)) { PlayerDiveController localInstance = PlayerDiveController.LocalInstance; if (!_cachedOriginalValues) { _originalMaxDistance = __instance.m_maxDistance; _originalMinWaterDistance = __instance.m_minWaterDistance; _cachedOriginalValues = true; } bool flag = Object.op_Implicit((Object)(object)localInstance) && localInstance.toggleDive; bool flag2 = Object.op_Implicit((Object)(object)localInstance) && localInstance.is_diving; if (flag || flag2) { __instance.m_minWaterDistance = -5000f; return; } __instance.m_minWaterDistance = _originalMinWaterDistance; __instance.m_maxDistance = _originalMaxDistance; } } [HarmonyPostfix] private static void Postfix(GameCamera __instance, Camera ___m_camera) { //IL_0080: Unknown result type (might be due to invalid IL or missing references) //IL_00fa: Unknown result type (might be due to invalid IL or missing references) //IL_0099: 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_00be: 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_00da: Unknown result type (might be due to invalid IL or missing references) //IL_013c: Unknown result type (might be due to invalid IL or missing references) //IL_0141: Unknown result type (might be due to invalid IL or missing references) //IL_0152: Unknown result type (might be due to invalid IL or missing references) if (!VBDiving.IsEnabled()) { return; } Player localPlayer = Player.m_localPlayer; if (!Object.op_Implicit((Object)(object)localPlayer) || !Object.op_Implicit((Object)(object)___m_camera)) { return; } PlayerDiveController localInstance = PlayerDiveController.LocalInstance; float waterLevel2; if (Object.op_Implicit((Object)(object)localInstance) && ((Character)localPlayer).InWater() && !((Character)localPlayer).IsOnGround() && (localInstance.toggleDive || localInstance.is_diving || localInstance.IsHeadUnderwater())) { if (WaterHelper.TryGetWaterLevel(((Component)___m_camera).transform.position, out var waterLevel)) { float y = ((Component)___m_camera).transform.position.y; if (y > waterLevel - 0.5f) { Vector3 position = ((Component)___m_camera).transform.position; position.y = waterLevel - 0.5f; ((Component)___m_camera).transform.position = position; } } } else if (WaterHelper.IsBodyInWater(localPlayer) && WaterHelper.TryGetWaterLevel(((Component)___m_camera).transform.position, out waterLevel2)) { float y2 = ((Component)___m_camera).transform.position.y; float num = waterLevel2 + 0.3f; if (y2 < num) { Vector3 position2 = ((Component)___m_camera).transform.position; position2.y = num; ((Component)___m_camera).transform.position = position2; } } } } [HarmonyPatch] internal static class PlayerEquipInWater { internal static ConfigEntry EquipInWaterList; internal static HashSet EquipInWaterItems = new HashSet(); private static readonly CodeMatch[] Matches = (CodeMatch[])(object)new CodeMatch[5] { new CodeMatch((OpCode?)OpCodes.Ldarg_0, (object)null, (string)null), new CodeMatch((OpCode?)OpCodes.Call, (object)AccessTools.Method(typeof(Character), "IsSwimming", (Type[])null, (Type[])null), (string)null), new CodeMatch((OpCode?)OpCodes.Brfalse, (object)null, (string)null), new CodeMatch((OpCode?)OpCodes.Ldarg_0, (object)null, (string)null), new CodeMatch((OpCode?)OpCodes.Call, (object)AccessTools.Method(typeof(Character), "IsOnGround", (Type[])null, (Type[])null), (string)null) }; public static bool VB_CheckWaterItem(ItemData item) { if (item == null) { HandleNullItemCase(); return false; } return IsItemAllowed(item.m_shared.m_name); } private static void HandleNullItemCase() { Player localPlayer = Player.m_localPlayer; if (Object.op_Implicit((Object)(object)localPlayer)) { CheckAndUnequipItem(((Humanoid)localPlayer).m_leftItem); CheckAndUnequipItem(((Humanoid)localPlayer).m_rightItem); } } private static void CheckAndUnequipItem(ItemData item) { if (item != null && !IsItemAllowed(((Object)item.m_dropPrefab).name)) { Player localPlayer = Player.m_localPlayer; if (localPlayer != null) { ((Humanoid)localPlayer).UnequipItem(item, true); } } } private static bool IsItemAllowed(string itemName) { return EquipInWaterItems.Contains(itemName); } private static IEnumerable TargetMethods() { return new <>z__ReadOnlyArray(new MethodBase[3] { AccessTools.Method(typeof(Player), "Update", (Type[])null, (Type[])null), AccessTools.Method(typeof(Humanoid), "EquipItem", (Type[])null, (Type[])null), AccessTools.Method(typeof(Humanoid), "UpdateEquipment", (Type[])null, (Type[])null) }); } public static IEnumerable Transpiler(IEnumerable instructions, MethodBase original) { //IL_0003: Unknown result type (might be due to invalid IL or missing references) CodeMatcher val = new CodeMatcher(instructions, (ILGenerator)null).MatchStartForward(Matches); try { switch (original.Name) { case "Update": val.Advance(1).RemoveInstructions(6); break; case "EquipItem": val.Advance(6).Insert((IEnumerable)GenerateInjectionCode(val, OpCodes.Ldarg_1)); break; case "UpdateEquipment": val.Advance(6).Insert((IEnumerable)GenerateInjectionCode(val, OpCodes.Ldnull)); break; } } catch (ArgumentException ex) { Debug.LogError((object)("IL Transpiler Error in VB_EquipInWater: " + ex.Message)); Debug.LogError((object)"Plugin initialization failed. Valheim will shutdown."); Environment.Exit(1); } return val.InstructionEnumeration(); } private static List GenerateInjectionCode(CodeMatcher matcher, OpCode loadOpCode) { //IL_000a: Unknown result type (might be due to invalid IL or missing references) //IL_0014: Expected O, but got Unknown //IL_002f: Unknown result type (might be due to invalid IL or missing references) //IL_0039: Expected O, but got Unknown //IL_004c: Unknown result type (might be due to invalid IL or missing references) //IL_0056: Expected O, but got Unknown List list = new List(); list.Add(new CodeInstruction(loadOpCode, (object)null)); list.Add(new CodeInstruction(OpCodes.Call, (object)typeof(PlayerEquipInWater).GetMethod("VB_CheckWaterItem"))); list.Add(new CodeInstruction(OpCodes.Brfalse, matcher.InstructionAt(-1).operand)); return list; } } [HarmonyPatch(typeof(Player), "FixedUpdate")] internal static class PlayerFixedUpdatePatch { private static void Postfix(Player __instance) { //IL_00c0: Unknown result type (might be due to invalid IL or missing references) //IL_00cb: Unknown result type (might be due to invalid IL or missing references) //IL_00d5: Unknown result type (might be due to invalid IL or missing references) //IL_00da: Unknown result type (might be due to invalid IL or missing references) if (!VBDiving.IsEnabled() || !Object.op_Implicit((Object)(object)__instance) || (Object)(object)__instance != (Object)(object)Player.m_localPlayer || ((Character)__instance).IsDebugFlying()) { return; } bool flag = WaterHelper.IsBodyInWater(__instance); bool flag2 = WaterHelper.IsHeadUnderwater(__instance); Rigidbody component = ((Component)__instance).GetComponent(); if (!Object.op_Implicit((Object)(object)component)) { return; } if (!flag) { Traverse.Create((object)__instance).Field("m_staminaRegenTimer").SetValue((object)0f); component.useGravity = true; HandleBreath(__instance, headUnderwater: false); return; } component.useGravity = true; HandleBreath(__instance, flag2); Vector2 val = new Vector2(component.linearVelocity.x, component.linearVelocity.z); float magnitude = ((Vector2)(ref val)).magnitude; bool flag3 = magnitude > 0.5f; if (!flag2 && !IsDivingDeep(__instance) && !flag3) { Traverse.Create((object)__instance).Field("m_staminaRegenTimer").SetValue((object)0f); HandleWaterStaminaRegen(__instance); } else { Traverse.Create((object)__instance).Field("m_staminaRegenTimer").SetValue((object)10f); } PlayerDiveController localInstance = PlayerDiveController.LocalInstance; if (Object.op_Implicit((Object)(object)localInstance)) { localInstance.UpdateSwimSpeed(); } } private static bool IsDivingDeep(Player player) { PlayerDiveController localInstance = PlayerDiveController.LocalInstance; if (Object.op_Implicit((Object)(object)localInstance)) { return localInstance.toggleDive || localInstance.is_diving || localInstance.IsUnderSurface(); } return ((Character)player).m_swimDepth > 1.3000001f; } private static void HandleBreath(Player player, bool headUnderwater) { SwimState swimState = SwimStateManager.Get(player); float fixedDeltaTime = Time.fixedDeltaTime; float maxBreath = SwimAPI.GetMaxBreath(player); if (headUnderwater) { swimState.Breath -= fixedDeltaTime; if (swimState.Breath < 0f) { swimState.Breath = 0f; } if (swimState.Breath <= 0f && ((Character)player).HaveStamina(0f)) { ((Character)player).UseStamina(5f * fixedDeltaTime); } } else { swimState.Breath += VBDiving.BreathRecoveryPerSecond.Value * fixedDeltaTime; if (swimState.Breath > maxBreath) { swimState.Breath = maxBreath; } } SwimAPI.UpdateEvents(player); swimState.WasHeadUnderwater = headUnderwater; } private static void HandleWaterStaminaRegen(Player player) { float value = VBDiving.BaseUnderwaterStaminaRegenPerSecond.Value; float value2 = Traverse.Create((object)player).Field("m_stamina").GetValue(); float maxStamina = ((Character)player).GetMaxStamina(); if (value2 < maxStamina) { value2 += value * Time.fixedDeltaTime; if (value2 > maxStamina) { value2 = maxStamina; } Traverse.Create((object)player).Field("m_stamina").SetValue((object)value2); } } } [HarmonyPatch(typeof(Player), "UpdateStats", new Type[] { typeof(float) })] internal static class PlayerUpdateStatsPatch { private static void Postfix(Player __instance, float dt) { if (VBDiving.IsEnabled() && Object.op_Implicit((Object)(object)__instance) && !((Object)(object)__instance != (Object)(object)Player.m_localPlayer) && WaterHelper.IsBodyInWater(__instance)) { bool flag = WaterHelper.IsHeadUnderwater(__instance); PlayerDiveController localInstance = PlayerDiveController.LocalInstance; bool flag2 = Object.op_Implicit((Object)(object)localInstance) && (localInstance.toggleDive || localInstance.is_diving || localInstance.IsUnderSurface()); if (flag || flag2) { Traverse.Create((object)__instance).Field("m_staminaRegenTimer").SetValue((object)float.MaxValue); } if (Object.op_Implicit((Object)(object)localInstance)) { localInstance.UpdateSwimSpeed(); } } } } } namespace VBDiving.Effects { internal static class DiveEffectsConfigSystem { internal static readonly string ConfigFolderPath; private static readonly object ConfigLock; private static readonly IDeserializer YamlDeserializer; private static Dictionary _biomeSettings; private static BiomeUnderwaterSettings _defaultSettings; private static FileSystemWatcher _configFolderWatcher; private static DateTime _lastReloadTime; private static readonly object ReloadLock; private const long ReloadDelayTicks = 10000000L; private static bool _hasServerConfigs; private static Dictionary _serverSettings; private static float _globalHeatDistortionIntensity; private static Color _globalHeatDistortionColor; public static float GetHeatDistortionIntensity() { return _globalHeatDistortionIntensity; } public static Color GetHeatDistortionColor() { //IL_0000: Unknown result type (might be due to invalid IL or missing references) return _globalHeatDistortionColor; } static DiveEffectsConfigSystem() { //IL_003c: Unknown result type (might be due to invalid IL or missing references) //IL_0041: Unknown result type (might be due to invalid IL or missing references) //IL_0069: Unknown result type (might be due to invalid IL or missing references) //IL_0078: Expected O, but got Unknown ConfigLock = new object(); _biomeSettings = new Dictionary(); ReloadLock = new object(); _globalHeatDistortionIntensity = 0.5f; _globalHeatDistortionColor = new Color(0.2f, 0.4f, 0.65f, 1f); string text = Path.Combine(Paths.ConfigPath, "VitByr", "VBDiving"); Directory.CreateDirectory(text); ConfigFolderPath = text; YamlDeserializer = ((BuilderSkeleton)new DeserializerBuilder()).WithNamingConvention(UnderscoredNamingConvention.Instance).IgnoreUnmatchedProperties().Build(); } public static BiomeUnderwaterSettings GetSettingsForBiome(Biome biome) { //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_0042: Unknown result type (might be due to invalid IL or missing references) lock (ConfigLock) { if (_hasServerConfigs && _serverSettings != null && _serverSettings.TryGetValue(biome, out var value)) { return value; } if (_biomeSettings.TryGetValue(biome, out var value2)) { return value2; } return _defaultSettings; } } public static string GetSerializedConfigs() { //IL_00c5: Unknown result type (might be due to invalid IL or missing references) //IL_00ca: Unknown result type (might be due to invalid IL or missing references) //IL_0106: Unknown result type (might be due to invalid IL or missing references) //IL_011a: 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_0142: Unknown result type (might be due to invalid IL or missing references) //IL_0176: Unknown result type (might be due to invalid IL or missing references) //IL_018a: Unknown result type (might be due to invalid IL or missing references) //IL_019e: Unknown result type (might be due to invalid IL or missing references) //IL_01b2: Unknown result type (might be due to invalid IL or missing references) lock (ConfigLock) { StringBuilder stringBuilder = new StringBuilder(); stringBuilder.Append("General|"); stringBuilder.Append($"{_globalHeatDistortionIntensity:F4}|"); stringBuilder.Append($"{_globalHeatDistortionColor.r:F4},{_globalHeatDistortionColor.g:F4},{_globalHeatDistortionColor.b:F4},{_globalHeatDistortionColor.a:F4}"); stringBuilder.Append('\n'); foreach (KeyValuePair biomeSetting in _biomeSettings) { Biome key = biomeSetting.Key; string value = ((object)(Biome)(ref key)).ToString(); BiomeUnderwaterSettings value2 = biomeSetting.Value; stringBuilder.Append(value); stringBuilder.Append('|'); stringBuilder.Append($"{value2.FogColor.r:F4},{value2.FogColor.g:F4},{value2.FogColor.b:F4},{value2.FogColor.a:F4}"); stringBuilder.Append('|'); stringBuilder.Append($"{value2.FogColorSun.r:F4},{value2.FogColorSun.g:F4},{value2.FogColorSun.b:F4},{value2.FogColorSun.a:F4}"); stringBuilder.Append('|'); stringBuilder.Append($"{value2.FogDensity:F4}"); stringBuilder.Append('|'); stringBuilder.Append($"{value2.LightFalloffStartDepth:F4}"); stringBuilder.Append('|'); stringBuilder.Append($"{value2.LightFalloffEndDepth:F4}"); stringBuilder.Append('|'); stringBuilder.Append($"{value2.LightMultiplierMin:F4}"); stringBuilder.Append('|'); stringBuilder.Append($"{value2.SurfaceFogMultiplier:F4}"); stringBuilder.Append('|'); stringBuilder.Append($"{value2.DepthFogMultiplier:F4}"); stringBuilder.Append('\n'); } stringBuilder.Append("__DEFAULT__|"); stringBuilder.Append($"{_defaultSettings.FogColor.r:F4},{_defaultSettings.FogColor.g:F4},{_defaultSettings.FogColor.b:F4},{_defaultSettings.FogColor.a:F4}"); stringBuilder.Append('|'); stringBuilder.Append($"{_defaultSettings.FogColorSun.r:F4},{_defaultSettings.FogColorSun.g:F4},{_defaultSettings.FogColorSun.b:F4},{_defaultSettings.FogColorSun.a:F4}"); stringBuilder.Append('|'); stringBuilder.Append($"{_defaultSettings.FogDensity:F4}"); stringBuilder.Append('|'); stringBuilder.Append($"{_defaultSettings.LightFalloffStartDepth:F4}"); stringBuilder.Append('|'); stringBuilder.Append($"{_defaultSettings.LightFalloffEndDepth:F4}"); stringBuilder.Append('|'); stringBuilder.Append($"{_defaultSettings.LightMultiplierMin:F4}"); stringBuilder.Append('|'); stringBuilder.Append($"{_defaultSettings.SurfaceFogMultiplier:F4}"); stringBuilder.Append('|'); stringBuilder.Append($"{_defaultSettings.DepthFogMultiplier:F4}"); stringBuilder.Append('\n'); return stringBuilder.ToString(); } } public static void LoadSerializedConfigs(string configData, bool useServerOnly = false) { //IL_0131: Unknown result type (might be due to invalid IL or missing references) //IL_0136: 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_013f: Unknown result type (might be due to invalid IL or missing references) //IL_0281: Unknown result type (might be due to invalid IL or missing references) //IL_00da: Unknown result type (might be due to invalid IL or missing references) //IL_00df: Unknown result type (might be due to invalid IL or missing references) //IL_0299: Unknown result type (might be due to invalid IL or missing references) //IL_01a1: Unknown result type (might be due to invalid IL or missing references) //IL_01a3: Unknown result type (might be due to invalid IL or missing references) //IL_02e0: Unknown result type (might be due to invalid IL or missing references) //IL_01e5: Unknown result type (might be due to invalid IL or missing references) if (string.IsNullOrEmpty(configData)) { return; } lock (ConfigLock) { Dictionary dictionary = new Dictionary(); 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 < 2) { continue; } try { string text2 = array3[0]; if (text2 == "General") { if (array3.Length >= 3) { _globalHeatDistortionIntensity = float.Parse(array3[1]); string[] array4 = array3[2].Split(new char[1] { ',' }); if (array4.Length >= 3) { _globalHeatDistortionColor = ParseColorFromArray(array4); } } } else if (array3.Length >= 7) { string text3 = array3[0]; string[] parts = array3[1].Split(new char[1] { ',' }); string[] parts2 = array3[2].Split(new char[1] { ',' }); Color fog = ParseColorFromArray(parts); Color fogSun = ParseColorFromArray(parts2); float density = float.Parse(array3[3]); float lightFalloffStart = float.Parse(array3[4]); float lightFalloffEnd = float.Parse(array3[5]); float lightMin = float.Parse(array3[6]); float surfaceFogMult = ((array3.Length > 7) ? float.Parse(array3[7]) : 1.2f); float depthFogMult = ((array3.Length > 8) ? float.Parse(array3[8]) : 0.9f); BiomeUnderwaterSettings biomeUnderwaterSettings = new BiomeUnderwaterSettings(fog, fogSun, density, lightFalloffStart, lightFalloffEnd, lightMin, surfaceFogMult, depthFogMult); Biome result; if (text3 == "__DEFAULT__") { _defaultSettings = biomeUnderwaterSettings; } else if (Enum.TryParse(text3, ignoreCase: true, out result)) { dictionary[result] = biomeUnderwaterSettings; } } } catch (Exception ex) { Debug.LogError((object)("[VBDiving] Failed to parse serialized config line: " + ex.Message)); } } if (useServerOnly) { _biomeSettings = new Dictionary(dictionary); _hasServerConfigs = true; _serverSettings = new Dictionary(dictionary); return; } _serverSettings = new Dictionary(dictionary); _hasServerConfigs = true; Dictionary dictionary2 = new Dictionary(); foreach (KeyValuePair biomeSetting in _biomeSettings) { if (!dictionary.ContainsKey(biomeSetting.Key)) { dictionary2[biomeSetting.Key] = biomeSetting.Value; } } foreach (KeyValuePair item in dictionary) { dictionary2[item.Key] = item.Value; } _biomeSettings = dictionary2; } } private static Color ParseColorFromArray(string[] parts) { //IL_005b: Unknown result type (might be due to invalid IL or missing references) //IL_0060: Unknown result type (might be due to invalid IL or missing references) //IL_0064: Unknown result type (might be due to invalid IL or missing references) float num = ((parts.Length != 0) ? float.Parse(parts[0]) : 0f); float num2 = ((parts.Length > 1) ? float.Parse(parts[1]) : 0f); float num3 = ((parts.Length > 2) ? float.Parse(parts[2]) : 0f); float num4 = ((parts.Length > 3) ? float.Parse(parts[3]) : 1f); return new Color(num, num2, num3, num4); } public static void Initialize() { SetDefaultSettings(); LoadAllConfigs(); SetupConfigFolderWatcher(); if (ShouldRequestFromServer()) { ((MonoBehaviour)VBDiving.Instance).StartCoroutine(RequestConfigsDelayed()); } } private static void SetDefaultSettings() { //IL_0015: 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) _defaultSettings = new BiomeUnderwaterSettings(new Color(0.16f, 0.24f, 0.3f, 1f), new Color(0.2f, 0.3f, 0.35f, 1f), 0.06f); } private static bool ShouldRequestFromServer() { if ((Object)(object)ZNet.instance == (Object)null) { return false; } if (ZNet.instance.IsServer()) { return false; } return VBDiving.SyncDiveEffectsConfigs?.Value ?? true; } private static IEnumerator RequestConfigsDelayed() { yield return (object)new WaitForSeconds(3f); VBDiving.RequestDiveEffectsConfigsFromServer(); } public static void LoadAllConfigs() { //IL_01a1: Unknown result type (might be due to invalid IL or missing references) //IL_01b9: Unknown result type (might be due to invalid IL or missing references) //IL_0204: Unknown result type (might be due to invalid IL or missing references) if (!VBDiving.IsEnabled()) { return; } lock (ConfigLock) { if (!Directory.Exists(ConfigFolderPath)) { Directory.CreateDirectory(ConfigFolderPath); } Dictionary dictionary = new Dictionary(); HashSet loadedBiomes = new HashSet(); List list = Directory.GetFiles(ConfigFolderPath, "*.yaml").Concat(Directory.GetFiles(ConfigFolderPath, "*.yml")).ToList(); if (list.Count == 0) { CreateDefaultConfigFile(); list = Directory.GetFiles(ConfigFolderPath, "*.yaml").ToList(); } Debug.Log((object)$"[VBDiving] Found {list.Count} dive effects config file(s)"); foreach (string item in list) { try { LoadConfigFromFile(item, dictionary, loadedBiomes); } catch (Exception ex) { Debug.LogError((object)("[VBDiving] Failed to load " + Path.GetFileName(item) + ": " + ex.Message)); } } Debug.Log((object)$"[VBDiving] Loaded {dictionary.Count} biome configurations from YAML"); if (_hasServerConfigs && _serverSettings != null && (Object)(object)ZNet.instance != (Object)null && !ZNet.instance.IsServer()) { Dictionary dictionary2 = new Dictionary(); foreach (KeyValuePair item2 in dictionary) { if (!_serverSettings.ContainsKey(item2.Key)) { dictionary2[item2.Key] = item2.Value; } } foreach (KeyValuePair serverSetting in _serverSettings) { dictionary2[serverSetting.Key] = serverSetting.Value; } _biomeSettings = dictionary2; } else { _biomeSettings = dictionary; } } } private static void LoadConfigFromFile(string filePath, Dictionary allSettings, HashSet loadedBiomes) { //IL_01b1: 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) //IL_01bb: Unknown result type (might be due to invalid IL or missing references) //IL_026d: Unknown result type (might be due to invalid IL or missing references) //IL_0270: Invalid comparison between Unknown and I4 //IL_02ad: Unknown result type (might be due to invalid IL or missing references) //IL_02b2: Unknown result type (might be due to invalid IL or missing references) //IL_02b7: Unknown result type (might be due to invalid IL or missing references) //IL_02cf: Unknown result type (might be due to invalid IL or missing references) //IL_02d4: Unknown result type (might be due to invalid IL or missing references) //IL_02d9: Unknown result type (might be due to invalid IL or missing references) //IL_03a9: Unknown result type (might be due to invalid IL or missing references) //IL_03ab: Unknown result type (might be due to invalid IL or missing references) //IL_03bf: Unknown result type (might be due to invalid IL or missing references) //IL_03e8: Unknown result type (might be due to invalid IL or missing references) //IL_03f3: Unknown result type (might be due to invalid IL or missing references) string text = File.ReadAllText(filePath); if (string.IsNullOrWhiteSpace(text)) { return; } DiveEffectsYamlDocument diveEffectsYamlDocument = null; try { diveEffectsYamlDocument = YamlDeserializer.Deserialize(text); } catch (Exception ex) { Debug.LogWarning((object)("[VBDiving] Failed to parse " + Path.GetFileName(filePath) + " as structured document: " + ex.Message + ". Trying legacy format...")); } if (diveEffectsYamlDocument == null || (diveEffectsYamlDocument.General == null && (diveEffectsYamlDocument.Biomes == null || diveEffectsYamlDocument.Biomes.Count == 0))) { try { Dictionary dictionary = YamlDeserializer.Deserialize>(text); if (dictionary != null && dictionary.Count > 0) { diveEffectsYamlDocument = new DiveEffectsYamlDocument(); diveEffectsYamlDocument.Biomes = dictionary; Debug.Log((object)("[VBDiving] Successfully parsed " + Path.GetFileName(filePath) + " as legacy format.")); } } catch (Exception ex2) { Debug.LogError((object)("[VBDiving] Failed to parse " + Path.GetFileName(filePath) + " as legacy format: " + ex2.Message)); return; } } if (diveEffectsYamlDocument == null) { return; } string fileName = Path.GetFileName(filePath); int num = 0; if (diveEffectsYamlDocument.General != null) { if (diveEffectsYamlDocument.General.HeatDistortionIntensity.HasValue) { _globalHeatDistortionIntensity = diveEffectsYamlDocument.General.HeatDistortionIntensity.Value; } if (!string.IsNullOrEmpty(diveEffectsYamlDocument.General.HeatDistortionColor)) { _globalHeatDistortionColor = ParseColor(diveEffectsYamlDocument.General.HeatDistortionColor, new Color(0.2f, 0.4f, 0.65f)); } } if (diveEffectsYamlDocument.Biomes != null) { foreach (KeyValuePair biome in diveEffectsYamlDocument.Biomes) { string text2 = biome.Key?.Trim() ?? ""; if (string.IsNullOrEmpty(text2)) { continue; } if (!Enum.TryParse(text2, ignoreCase: true, out Biome result)) { Debug.LogWarning((object)("[VBDiving] Unknown biome '" + text2 + "' in " + fileName + ", skipping")); } else { if ((int)result == 4) { continue; } DiveEffectsYamlConfig value = biome.Value; if (value != null) { Color fog = ParseColor(value.FogColor, new Color(0.16f, 0.24f, 0.3f)); Color fogSun = ParseColor(value.FogColorSun, new Color(0.2f, 0.3f, 0.35f)); float density = value.FogDensity ?? 0.06f; float lightFalloffStart = value.LightFalloffStartDepth ?? 5f; float lightFalloffEnd = value.LightFalloffEndDepth ?? 25f; float lightMin = value.LightMultiplierMin ?? 0.15f; float surfaceFogMult = value.SurfaceFogMultiplier ?? 1.2f; float depthFogMult = value.DepthFogMultiplier ?? 0.9f; BiomeUnderwaterSettings value2 = new BiomeUnderwaterSettings(fog, fogSun, density, lightFalloffStart, lightFalloffEnd, lightMin, surfaceFogMult, depthFogMult); if (loadedBiomes.Contains(result)) { Debug.LogWarning((object)("[VBDiving] Biome " + text2 + " already configured, skipping duplicate in " + fileName)); continue; } allSettings[result] = value2; loadedBiomes.Add(result); num++; } } } } Debug.Log((object)$"[VBDiving] Loaded {num} biomes from {fileName}"); } private static Color ParseColor(string colorStr, Color defaultColor) { //IL_00fc: Unknown result type (might be due to invalid IL or missing references) //IL_00fd: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_0100: 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_002f: Unknown result type (might be due to invalid IL or missing references) //IL_00d4: Unknown result type (might be due to invalid IL or missing references) //IL_00d9: Unknown result type (might be due to invalid IL or missing references) if (string.IsNullOrEmpty(colorStr)) { return defaultColor; } string[] array = colorStr.Split(new char[1] { ',' }); if (array.Length < 3) { return defaultColor; } try { float num = float.Parse(array[0].Trim(), NumberStyles.Any, CultureInfo.InvariantCulture); float num2 = float.Parse(array[1].Trim(), NumberStyles.Any, CultureInfo.InvariantCulture); float num3 = float.Parse(array[2].Trim(), NumberStyles.Any, CultureInfo.InvariantCulture); float num4 = ((array.Length > 3) ? float.Parse(array[3].Trim(), NumberStyles.Any, CultureInfo.InvariantCulture) : 1f); num = Mathf.Clamp01(num); num2 = Mathf.Clamp01(num2); num3 = Mathf.Clamp01(num3); num4 = Mathf.Clamp01(num4); return new Color(num, num2, num3, num4); } catch (Exception ex) { Debug.LogWarning((object)("[VBDiving] Failed to parse color '" + colorStr + "': " + ex.Message)); return defaultColor; } } private static void SetupConfigFolderWatcher() { if (_configFolderWatcher == null) { _configFolderWatcher = new FileSystemWatcher(ConfigFolderPath) { 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 dive effects config folder: " + ConfigFolderPath)); } } 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..."); LoadAllConfigs(); if ((Object)(object)ZNet.instance != (Object)null && ZNet.instance.IsServer()) { VBDiving.OnDiveEffectsConfigsChanged(); } _lastReloadTime = now; } catch (Exception ex) { Debug.LogError((object)("[VBDiving] Error reloading: " + 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 renamed: " + e.OldName + " -> " + e.Name + ". Reloading...")); LoadAllConfigs(); if ((Object)(object)ZNet.instance != (Object)null && ZNet.instance.IsServer()) { VBDiving.OnDiveEffectsConfigsChanged(); } _lastReloadTime = now; } catch (Exception ex) { Debug.LogError((object)("[VBDiving] Error reloading: " + ex.Message)); } } } private static void CreateDefaultConfigFile() { string text = Path.Combine(ConfigFolderPath, "DiveEffects.yaml"); IEnumerable source = Directory.GetFiles(ConfigFolderPath, "*.yaml").Concat(Directory.GetFiles(ConfigFolderPath, "*.yml")); if (!source.Any()) { string contents = "# Dive Effects Configuration for VBDiving\r\n# Подводные эффекты для каждого биома\r\n# Биом Mountain (Горы) исключён\r\n\r\n# === GLOBAL SETTINGS (применяются ко всем биомам) ===\r\nGeneral:\r\n heat_distortion_intensity: 0.5\r\n heat_distortion_color: 0.2,0.4,0.65,1.0\r\n\r\n# === BIOME SETTINGS ===\r\n# Параметры цветов: R,G,B,A (0-1, альфа опциональна)\r\n# fog_color: цвет тумана\r\n# fog_color_sun: цвет солнечного тумана\r\n# fog_density: плотность тумана (0-0.5)\r\n# light_falloff_start_depth: с какой глубины начинается затемнение (метры)\r\n# light_falloff_end_depth: на какой глубине затемнение максимально (метры)\r\n# light_multiplier_min: минимальный множитель освещения (0-1)\r\n# surface_fog_multiplier: множитель тумана у поверхности (1.0 = нормально, 1.5 = гуще)\r\n# depth_fog_multiplier: множитель тумана на глубине (1.0 = нормально, 0.8 = реже)\r\n\r\nBiomes:\r\n Meadows:\r\n fog_color: 0.22,0.32,0.38\r\n fog_color_sun: 0.28,0.40,0.45\r\n fog_density: 0.045\r\n light_falloff_start_depth: 5\r\n light_falloff_end_depth: 25\r\n light_multiplier_min: 0.15\r\n surface_fog_multiplier: 1.5\r\n depth_fog_multiplier: 0.8\r\n\r\n BlackForest:\r\n fog_color: 0.18,0.28,0.32\r\n fog_color_sun: 0.52,0.32,0.16\r\n fog_density: 0.095\r\n light_falloff_start_depth: 4\r\n light_falloff_end_depth: 20\r\n light_multiplier_min: 0.12\r\n surface_fog_multiplier: 1.5\r\n depth_fog_multiplier: 0.8\r\n\r\n Swamp:\r\n fog_color: 0.15,0.22,0.18\r\n fog_color_sun: 0.20,0.28,0.22\r\n fog_density: 0.075\r\n light_falloff_start_depth: 3\r\n light_falloff_end_depth: 15\r\n light_multiplier_min: 0.10\r\n surface_fog_multiplier: 1.5\r\n depth_fog_multiplier: 0.8\r\n\r\n Plains:\r\n fog_color: 0.20,0.30,0.40\r\n fog_color_sun: 0.25,0.38,0.48\r\n fog_density: 0.050\r\n light_falloff_start_depth: 5\r\n light_falloff_end_depth: 30\r\n light_multiplier_min: 0.18\r\n surface_fog_multiplier: 1.5\r\n depth_fog_multiplier: 0.8\r\n\r\n Ocean:\r\n fog_color: 0.08,0.12,0.22\r\n fog_color_sun: 0.08,0.12,0.22\r\n fog_density: 0.090\r\n light_falloff_start_depth: 3\r\n light_falloff_end_depth: 40\r\n light_multiplier_min: 0.08\r\n surface_fog_multiplier: 1.5\r\n depth_fog_multiplier: 0.8\r\n\r\n Mistlands:\r\n fog_color: 0.12,0.14,0.28\r\n fog_color_sun: 0.10,0.12,0.24\r\n fog_density: 0.080\r\n light_falloff_start_depth: 4\r\n light_falloff_end_depth: 25\r\n light_multiplier_min: 0.12\r\n surface_fog_multiplier: 1.5\r\n depth_fog_multiplier: 0.8\r\n\r\n AshLands:\r\n fog_color: 0.10,0.14,0.12\r\n fog_color_sun: 0.08,0.12,0.10\r\n fog_density: 0.085\r\n light_falloff_start_depth: 4\r\n light_falloff_end_depth: 20\r\n light_multiplier_min: 0.10\r\n surface_fog_multiplier: 1.5\r\n depth_fog_multiplier: 0.8\r\n\r\n DeepNorth:\r\n fog_color: 0.15,0.22,0.35\r\n fog_color_sun: 0.20,0.28,0.42\r\n fog_density: 0.055\r\n light_falloff_start_depth: 5\r\n light_falloff_end_depth: 30\r\n light_multiplier_min: 0.15\r\n surface_fog_multiplier: 1.5\r\n depth_fog_multiplier: 0.8\r\n"; File.WriteAllText(text, contents); Debug.Log((object)("[VBDiving] Created default dive effects config at: " + text)); } } public static void ClearCache() { lock (ConfigLock) { _biomeSettings.Clear(); } } } internal class DiveEffectsYamlDocument { [YamlMember(Alias = "General", ApplyNamingConventions = false)] public DiveEffectsYamlGeneral General { get; set; } [YamlMember(Alias = "Biomes", ApplyNamingConventions = false)] public Dictionary Biomes { get; set; } public DiveEffectsYamlDocument() { Biomes = new Dictionary(); } } internal class DiveEffectsYamlGeneral { public float? HeatDistortionIntensity { get; set; } public string HeatDistortionColor { get; set; } } internal class DiveEffectsYamlConfig { public string FogColor { get; set; } public string FogColorSun { get; set; } public float? FogDensity { get; set; } public float? LightFalloffStartDepth { get; set; } public float? LightFalloffEndDepth { get; set; } public float? LightMultiplierMin { get; set; } public float? SurfaceFogMultiplier { get; set; } public float? DepthFogMultiplier { get; set; } } internal class DiveImmersionEffect : MonoBehaviour { private struct EnvState { public EnvSetup env; public float fogDensityDay; public float fogDensityNight; public float fogDensityMorning; public float fogDensityEvening; public Color fogColorDay; public Color fogColorNight; public Color fogColorMorning; public Color fogColorEvening; public Color fogColorSunDay; public Color fogColorSunNight; public Color fogColorSunMorning; public Color fogColorSunEvening; public void Save(EnvSetup source) { //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_0053: Unknown result type (might be due to invalid IL or missing references) //IL_0058: Unknown result type (might be due to invalid IL or missing references) //IL_005f: Unknown result type (might be due to invalid IL or missing references) //IL_0064: Unknown result type (might be due to invalid IL or missing references) //IL_006b: Unknown result type (might be due to invalid IL or missing references) //IL_0070: Unknown result type (might be due to invalid IL or missing references) //IL_0077: Unknown result type (might be due to invalid IL or missing references) //IL_007c: 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) //IL_008f: Unknown result type (might be due to invalid IL or missing references) //IL_0094: Unknown result type (might be due to invalid IL or missing references) //IL_009b: 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) if (source != null) { env = source; fogDensityDay = source.m_fogDensityDay; fogDensityNight = source.m_fogDensityNight; fogDensityMorning = source.m_fogDensityMorning; fogDensityEvening = source.m_fogDensityEvening; fogColorDay = source.m_fogColorDay; fogColorNight = source.m_fogColorNight; fogColorMorning = source.m_fogColorMorning; fogColorEvening = source.m_fogColorEvening; fogColorSunDay = source.m_fogColorSunDay; fogColorSunNight = source.m_fogColorSunNight; fogColorSunMorning = source.m_fogColorSunMorning; fogColorSunEvening = source.m_fogColorSunEvening; } } public void Restore() { //IL_005e: Unknown result type (might be due to invalid IL or missing references) //IL_0063: Unknown result type (might be due to invalid IL or missing references) //IL_006f: Unknown result type (might be due to invalid IL or missing references) //IL_0074: Unknown result type (might be due to invalid IL or missing references) //IL_0080: Unknown result type (might be due to invalid IL or missing references) //IL_0085: Unknown result type (might be due to invalid IL or missing references) //IL_0091: Unknown result type (might be due to invalid IL or missing references) //IL_0096: Unknown result type (might be due to invalid IL or missing references) //IL_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_00b3: 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_00c9: Unknown result type (might be due to invalid IL or missing references) //IL_00d5: Unknown result type (might be due to invalid IL or missing references) //IL_00da: Unknown result type (might be due to invalid IL or missing references) if (env != null) { env.m_fogDensityDay = fogDensityDay; env.m_fogDensityNight = fogDensityNight; env.m_fogDensityMorning = fogDensityMorning; env.m_fogDensityEvening = fogDensityEvening; env.m_fogColorDay = fogColorDay; env.m_fogColorNight = fogColorNight; env.m_fogColorMorning = fogColorMorning; env.m_fogColorEvening = fogColorEvening; env.m_fogColorSunDay = fogColorSunDay; env.m_fogColorSunNight = fogColorSunNight; env.m_fogColorSunMorning = fogColorSunMorning; env.m_fogColorSunEvening = fogColorSunEvening; } } } private EnvState _savedEnvState; internal static bool IsUnderwaterImmersionActive; internal static Biome CurrentBiome; private float _biomeTransitionTimer; private const float BiomeTransitionDuration = 2f; private BiomeUnderwaterSettings _currentBiomeSettings; private BiomeUnderwaterSettings _previousBiomeSettings; private bool _isBiomeTransitioning; private AudioLowPassFilter _lowPass; private bool _active; private float _intensity; private Behaviour _ownedHeatDistort; private Type _heatDistortType; private float _currentDepthLightMultiplier = 1f; private float _originalSunIntensityDay; private float _originalSunIntensityNight; private const float FadeSpeed = 4f; private bool _originalSaved; private Biome _lastBiome = (Biome)0; private EnvSetup _underwaterEnvClone; private string _lastOriginalEnvName; private bool _isUnderwaterEnvActive; private void Awake() { DiveEffectsConfigSystem.Initialize(); } private BiomeUnderwaterSettings GetInterpolatedSettings() { //IL_000e: Unknown result type (might be due to invalid IL or missing references) if (!_isBiomeTransitioning) { return DiveEffectsConfigSystem.GetSettingsForBiome(CurrentBiome); } float t = Mathf.Clamp01(_biomeTransitionTimer / 2f); return BiomeUnderwaterSettings.Lerp(_previousBiomeSettings, _currentBiomeSettings, t); } private void ModifyEnvironmentForUnderwater(float intensity) { //IL_0105: Unknown result type (might be due to invalid IL or missing references) //IL_01a5: Unknown result type (might be due to invalid IL or missing references) //IL_0223: 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_022b: Unknown result type (might be due to invalid IL or missing references) //IL_0230: Unknown result type (might be due to invalid IL or missing references) //IL_02cc: Unknown result type (might be due to invalid IL or missing references) //IL_02d1: Unknown result type (might be due to invalid IL or missing references) //IL_02d5: Unknown result type (might be due to invalid IL or missing references) //IL_02da: Unknown result type (might be due to invalid IL or missing references) //IL_02eb: Unknown result type (might be due to invalid IL or missing references) //IL_02f0: Unknown result type (might be due to invalid IL or missing references) //IL_02f4: 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_030a: Unknown result type (might be due to invalid IL or missing references) //IL_030f: Unknown result type (might be due to invalid IL or missing references) //IL_0313: Unknown result type (might be due to invalid IL or missing references) //IL_0318: Unknown result type (might be due to invalid IL or missing references) //IL_0329: Unknown result type (might be due to invalid IL or missing references) //IL_032e: Unknown result type (might be due to invalid IL or missing references) //IL_0332: Unknown result type (might be due to invalid IL or missing references) //IL_0337: Unknown result type (might be due to invalid IL or missing references) //IL_0348: Unknown result type (might be due to invalid IL or missing references) //IL_034d: Unknown result type (might be due to invalid IL or missing references) //IL_0351: Unknown result type (might be due to invalid IL or missing references) //IL_0356: Unknown result type (might be due to invalid IL or missing references) //IL_0367: Unknown result type (might be due to invalid IL or missing references) //IL_036c: Unknown result type (might be due to invalid IL or missing references) //IL_0370: Unknown result type (might be due to invalid IL or missing references) //IL_0375: Unknown result type (might be due to invalid IL or missing references) //IL_0386: Unknown result type (might be due to invalid IL or missing references) //IL_038b: Unknown result type (might be due to invalid IL or missing references) //IL_038f: Unknown result type (might be due to invalid IL or missing references) //IL_0394: Unknown result type (might be due to invalid IL or missing references) //IL_03a5: Unknown result type (might be due to invalid IL or missing references) //IL_03aa: Unknown result type (might be due to invalid IL or missing references) //IL_03ae: Unknown result type (might be due to invalid IL or missing references) //IL_03b3: Unknown result type (might be due to invalid IL or missing references) //IL_0417: Unknown result type (might be due to invalid IL or missing references) //IL_041c: Unknown result type (might be due to invalid IL or missing references) //IL_041e: Unknown result type (might be due to invalid IL or missing references) //IL_0420: Unknown result type (might be due to invalid IL or missing references) //IL_0431: Unknown result type (might be due to invalid IL or missing references) //IL_0436: Unknown result type (might be due to invalid IL or missing references) //IL_0438: Unknown result type (might be due to invalid IL or missing references) EnvMan instance = EnvMan.instance; if (!Object.op_Implicit((Object)(object)instance)) { return; } EnvSetup currentEnvironment = instance.GetCurrentEnvironment(); if (currentEnvironment == null) { return; } if (!_originalSaved || _lastOriginalEnvName != currentEnvironment.m_name) { _savedEnvState.Save(currentEnvironment); _originalSunIntensityDay = currentEnvironment.m_lightIntensityDay; _originalSunIntensityNight = currentEnvironment.m_lightIntensityNight; _originalSaved = true; _lastOriginalEnvName = currentEnvironment.m_name; if (VBDiving.DebugLogging.Value) { Debug.Log((object)("[VBDiving] Original environment saved: " + currentEnvironment.m_name)); } } if (_isBiomeTransitioning) { _biomeTransitionTimer += Time.deltaTime; if (_biomeTransitionTimer >= 2f) { _isBiomeTransitioning = false; if (VBDiving.DebugLogging.Value) { Debug.Log((object)$"[VBDiving] Biome transition completed: {CurrentBiome}"); } } } BiomeUnderwaterSettings interpolatedSettings = GetInterpolatedSettings(); if (_underwaterEnvClone == null || _lastOriginalEnvName != currentEnvironment.m_name) { _underwaterEnvClone = currentEnvironment.Clone(); _underwaterEnvClone.m_name = currentEnvironment.m_name + "_VBUnderwater"; if (VBDiving.DebugLogging.Value) { Debug.Log((object)("[VBDiving] Created underwater clone for: " + currentEnvironment.m_name)); } } float liquidLevel = ((Character)Player.m_localPlayer).GetLiquidLevel(); float num = liquidLevel - ((Character)Player.m_localPlayer).GetHeadPoint().y; if (num < 0f) { num = 0f; } float num2 = Mathf.InverseLerp(interpolatedSettings.LightFalloffStartDepth, interpolatedSettings.LightFalloffEndDepth, num); float num3 = Mathf.Lerp(interpolatedSettings.SurfaceFogMultiplier, interpolatedSettings.DepthFogMultiplier, num2); float num4 = CalculateTimeFactor(); float num5 = interpolatedSettings.FogDensity * ((num4 > 0.8f) ? 1f : 1.2f); float num6 = num5 * num3; Color fogColor = interpolatedSettings.FogColor; Color fogColorSun = interpolatedSettings.FogColorSun; _underwaterEnvClone.m_fogDensityDay = Mathf.Lerp(_savedEnvState.fogDensityDay, num6, intensity); _underwaterEnvClone.m_fogDensityNight = Mathf.Lerp(_savedEnvState.fogDensityNight, num6 * 1.2f, intensity); _underwaterEnvClone.m_fogDensityMorning = Mathf.Lerp(_savedEnvState.fogDensityMorning, num6 * 1.1f, intensity); _underwaterEnvClone.m_fogDensityEvening = Mathf.Lerp(_savedEnvState.fogDensityEvening, num6 * 1.15f, intensity); _underwaterEnvClone.m_fogColorDay = Color.Lerp(_savedEnvState.fogColorDay, fogColor, intensity); _underwaterEnvClone.m_fogColorNight = Color.Lerp(_savedEnvState.fogColorNight, fogColor, intensity); _underwaterEnvClone.m_fogColorMorning = Color.Lerp(_savedEnvState.fogColorMorning, fogColor, intensity); _underwaterEnvClone.m_fogColorEvening = Color.Lerp(_savedEnvState.fogColorEvening, fogColor, intensity); _underwaterEnvClone.m_fogColorSunDay = Color.Lerp(_savedEnvState.fogColorSunDay, fogColorSun, intensity); _underwaterEnvClone.m_fogColorSunNight = Color.Lerp(_savedEnvState.fogColorSunNight, fogColorSun, intensity); _underwaterEnvClone.m_fogColorSunMorning = Color.Lerp(_savedEnvState.fogColorSunMorning, fogColorSun, intensity); _underwaterEnvClone.m_fogColorSunEvening = Color.Lerp(_savedEnvState.fogColorSunEvening, fogColorSun, intensity); float num7 = CalculateDepthLightMultiplier(interpolatedSettings); _currentDepthLightMultiplier = Mathf.Lerp(_currentDepthLightMultiplier, num7, Time.deltaTime * 2f); float lightIntensityDay = _originalSunIntensityDay * _currentDepthLightMultiplier; float lightIntensityNight = _originalSunIntensityNight * _currentDepthLightMultiplier; _underwaterEnvClone.m_lightIntensityDay = lightIntensityDay; _underwaterEnvClone.m_lightIntensityNight = lightIntensityNight; Color ambientLight = RenderSettings.ambientLight; Color ambientLight2 = Color.Lerp(ambientLight, Color.black, 1f - _currentDepthLightMultiplier); RenderSettings.ambientLight = ambientLight2; ApplyEnvironment(instance, _underwaterEnvClone); } private void ApplyEnvironment(EnvMan envMan, EnvSetup env) { float dayFraction = envMan.GetDayFraction(); float num = 0f; float num2 = 0f; float num3 = 0f; float num4 = 0f; if (dayFraction >= 0.25f && dayFraction <= 0.75f) { num2 = 1f; } else if (dayFraction < 0.25f) { num3 = 1f; } else { num4 = 1f; } try { MethodInfo method = typeof(EnvMan).GetMethod("SetEnv", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, new Type[6] { typeof(EnvSetup), typeof(float), typeof(float), typeof(float), typeof(float), typeof(float) }, null); if (method != null) { method.Invoke(envMan, new object[6] { env, num2, num, num3, num4, Time.fixedDeltaTime }); } } catch (Exception ex) { if (VBDiving.DebugLogging.Value) { Debug.LogWarning((object)("[VBDiving] Apply environment failed: " + ex.Message)); } } } private float CalculateDepthLightMultiplier(BiomeUnderwaterSettings settings) { //IL_002b: Unknown result type (might be due to invalid IL or missing references) Player localPlayer = Player.m_localPlayer; if (!Object.op_Implicit((Object)(object)localPlayer)) { return 1f; } float liquidLevel = ((Character)localPlayer).GetLiquidLevel(); float num = liquidLevel - ((Character)localPlayer).GetHeadPoint().y; if (num <= 0f) { return 1f; } if (settings.LightFalloffStartDepth <= 0f || num <= settings.LightFalloffStartDepth) { return 1f; } float num2 = (num - settings.LightFalloffStartDepth) / (settings.LightFalloffEndDepth - settings.LightFalloffStartDepth); num2 = Mathf.Clamp01(num2); return Mathf.Lerp(1f, settings.LightMultiplierMin, num2); } private float CalculateTimeFactor() { if (!Object.op_Implicit((Object)(object)EnvMan.instance)) { return 1f; } float dayFraction = EnvMan.instance.GetDayFraction(); if (dayFraction >= 0.25f && dayFraction <= 0.75f) { float num = (dayFraction - 0.25f) / 0.5f; float num2 = 1f - Mathf.Pow(num - 0.5f, 2f) * 0.2f; return Mathf.Clamp(num2, 0.85f, 1.15f); } if (dayFraction < 0.25f) { float num3 = dayFraction / 0.25f; return Mathf.Lerp(0.35f, 0.85f, num3); } float num4 = (dayFraction - 0.75f) / 0.25f; return Mathf.Lerp(0.85f, 0.35f, num4); } private void Update() { if (!VBDiving.IsEnabled()) { ForceFullReset(); return; } Player localPlayer = Player.m_localPlayer; if (!Object.op_Implicit((Object)(object)localPlayer)) { return; } bool flag = ((Character)localPlayer).InWater() && !((Character)localPlayer).IsOnGround(); PlayerDiveController localInstance = PlayerDiveController.LocalInstance; if (!flag) { if (_active || _intensity > 0.01f || _isUnderwaterEnvActive) { if (VBDiving.DebugLogging.Value) { Debug.Log((object)"[VBDiving] Player exited water. Forcing reset."); } ForceFullReset(); } return; } UpdateCurrentBiome(); if (ShouldUseDiveEffect()) { _active = true; } else if (_active && ShouldExitDiveEffect()) { _active = false; } float num = (_active ? 1f : 0f); _intensity = Mathf.MoveTowards(_intensity, num, Time.deltaTime * 4f); IsUnderwaterImmersionActive = _intensity > 0.001f; EnsureHeatDistortion(); if (Object.op_Implicit((Object)(object)_ownedHeatDistort)) { _ownedHeatDistort.enabled = IsUnderwaterImmersionActive; ApplyHeatDistortionValues(); } if (IsUnderwaterImmersionActive || WaterHelper.IsCameraUnderwater()) { ApplyAudio(); ModifyEnvironmentForUnderwater(_intensity); _isUnderwaterEnvActive = true; return; } if (_isUnderwaterEnvActive) { ForceFullReset(); } RestoreAudio(); } private void ForceFullReset() { //IL_012e: Unknown result type (might be due to invalid IL or missing references) //IL_0104: Unknown result type (might be due to invalid IL or missing references) _active = false; _intensity = 0f; IsUnderwaterImmersionActive = false; _isBiomeTransitioning = false; _biomeTransitionTimer = 0f; _currentDepthLightMultiplier = 1f; if (Object.op_Implicit((Object)(object)_ownedHeatDistort)) { _ownedHeatDistort.enabled = false; } RestoreAudio(); if (_isUnderwaterEnvActive && Object.op_Implicit((Object)(object)EnvMan.instance)) { EnvSetup currentEnvironment = EnvMan.instance.GetCurrentEnvironment(); if (currentEnvironment != null && currentEnvironment.m_name.EndsWith("_VBUnderwater")) { string text = currentEnvironment.m_name.Replace("_VBUnderwater", ""); EnvSetup env = EnvMan.instance.GetEnv(text); if (env != null) { ApplyEnvironment(EnvMan.instance, env); if (VBDiving.DebugLogging.Value) { Debug.Log((object)("[VBDiving] Restored original environment: " + env.m_name)); } } } RenderSettings.ambientLight = Color.grey; } _underwaterEnvClone = null; _isUnderwaterEnvActive = false; _originalSaved = false; _lastOriginalEnvName = null; _lastBiome = (Biome)0; if (VBDiving.DebugLogging.Value) { Debug.Log((object)"[VBDiving] Full Reset completed."); } } private void UpdateCurrentBiome() { //IL_0029: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Unknown result type (might be due to invalid IL or missing references) //IL_002f: Unknown result type (might be due to invalid IL or missing references) //IL_0034: Unknown result type (might be due to invalid IL or missing references) //IL_0042: 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_0049: Unknown result type (might be due to invalid IL or missing references) //IL_004a: Unknown result type (might be due to invalid IL or missing references) //IL_0050: Unknown result type (might be due to invalid IL or missing references) //IL_0052: Unknown result type (might be due to invalid IL or missing references) //IL_0077: 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_00ba: Unknown result type (might be due to invalid IL or missing references) //IL_00c1: Unknown result type (might be due to invalid IL or missing references) Player localPlayer = Player.m_localPlayer; if (!Object.op_Implicit((Object)(object)localPlayer) || !Object.op_Implicit((Object)(object)EnvMan.instance)) { return; } Biome currentBiome = EnvMan.instance.GetCurrentBiome(); if (CurrentBiome == currentBiome) { return; } Biome currentBiome2 = CurrentBiome; CurrentBiome = currentBiome; _lastBiome = currentBiome2; if (_active || _intensity > 0.1f) { _previousBiomeSettings = DiveEffectsConfigSystem.GetSettingsForBiome(currentBiome2); _currentBiomeSettings = DiveEffectsConfigSystem.GetSettingsForBiome(CurrentBiome); _isBiomeTransitioning = true; _biomeTransitionTimer = 0f; if (VBDiving.DebugLogging.Value) { Debug.Log((object)$"[VBDiving] Biome changed underwater: {currentBiome2} -> {CurrentBiome}. Transition started."); } } else { _isBiomeTransitioning = false; } } private bool ShouldUseDiveEffect() { Player localPlayer = Player.m_localPlayer; if (!Object.op_Implicit((Object)(object)localPlayer) || !Object.op_Implicit((Object)(object)GameCamera.instance)) { return false; } PlayerDiveController localInstance = PlayerDiveController.LocalInstance; if (!Object.op_Implicit((Object)(object)localInstance)) { return false; } if (localInstance.is_diving) { return true; } if (localInstance.IsHeadUnderwater() || localInstance.IsUnderSurface()) { return true; } return false; } private bool ShouldExitDiveEffect() { Player localPlayer = Player.m_localPlayer; if (!Object.op_Implicit((Object)(object)localPlayer) || !Object.op_Implicit((Object)(object)GameCamera.instance)) { return true; } PlayerDiveController localInstance = PlayerDiveController.LocalInstance; if (!Object.op_Implicit((Object)(object)localInstance)) { return true; } if (!localInstance.toggleDive && !localInstance.is_diving && !localInstance.IsHeadUnderwater()) { return true; } if (!localInstance.IsUnderSurface() && !localInstance.toggleDive) { return true; } return false; } private void ResetEffects() { ForceFullReset(); } private void EnsureHeatDistortion() { if (Object.op_Implicit((Object)(object)_ownedHeatDistort)) { return; } GameCamera instance = GameCamera.instance; Camera val = ((instance != null) ? ((Component)instance).GetComponent() : null); if (!Object.op_Implicit((Object)(object)val)) { return; } _heatDistortType = AccessTools.TypeByName("HeatDistortImageEffect"); if (_heatDistortType == null) { return; } Component component = ((Component)val).GetComponent(_heatDistortType); ref Behaviour ownedHeatDistort = ref _ownedHeatDistort; Component obj = ((Component)val).gameObject.AddComponent(_heatDistortType); ownedHeatDistort = (Behaviour)(object)((obj is Behaviour) ? obj : null); if (Object.op_Implicit((Object)(object)_ownedHeatDistort)) { if (Object.op_Implicit((Object)(object)component)) { CopyFields(component, (Component)(object)_ownedHeatDistort); } _ownedHeatDistort.enabled = false; ApplyHeatDistortionValues(); } } private void ApplyHeatDistortionValues() { //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_0053: Unknown result type (might be due to invalid IL or missing references) if (Object.op_Implicit((Object)(object)_ownedHeatDistort)) { Type type = ((object)_ownedHeatDistort).GetType(); float value = DiveEffectsConfigSystem.GetHeatDistortionIntensity() * _intensity; Color heatDistortionColor = DiveEffectsConfigSystem.GetHeatDistortionColor(); SetField(type, _ownedHeatDistort, "m_intensity", value); SetField(type, _ownedHeatDistort, "m_color", heatDistortionColor); } } private static void CopyFields(Component source, Component target) { if (!Object.op_Implicit((Object)(object)source) || !Object.op_Implicit((Object)(object)target)) { return; } Type type = ((object)source).GetType(); FieldInfo[] fields = type.GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); FieldInfo[] array = fields; foreach (FieldInfo fieldInfo in array) { if (!fieldInfo.IsInitOnly && !fieldInfo.IsLiteral) { try { fieldInfo.SetValue(target, fieldInfo.GetValue(source)); } catch { } } } } private static void SetField(Type type, object instance, string fieldName, T value) { FieldInfo field = type.GetField(fieldName, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); if (field == null) { return; } try { field.SetValue(instance, value); } catch { } } private void ApplyAudio() { AudioListener val = Object.FindFirstObjectByType(); if (!Object.op_Implicit((Object)(object)val)) { return; } if (!Object.op_Implicit((Object)(object)_lowPass)) { _lowPass = ((Component)val).gameObject.GetComponent(); if (!Object.op_Implicit((Object)(object)_lowPass)) { _lowPass = ((Component)val).gameObject.AddComponent(); } } AudioHighPassFilter val2 = ((Component)val).gameObject.GetComponent(); if (!Object.op_Implicit((Object)(object)val2)) { val2 = ((Component)val).gameObject.AddComponent(); } float intensity = _intensity; float cutoffFrequency = Mathf.Lerp(22000f, 800f, intensity); _lowPass.cutoffFrequency = cutoffFrequency; _lowPass.lowpassResonanceQ = Mathf.Lerp(1f, 1.5f, intensity); ((Behaviour)_lowPass).enabled = true; float cutoffFrequency2 = Mathf.Lerp(10f, 150f, intensity); val2.cutoffFrequency = cutoffFrequency2; val2.highpassResonanceQ = Mathf.Lerp(1f, 1.2f, intensity); ((Behaviour)val2).enabled = true; AudioReverbFilter val3 = ((Component)val).gameObject.GetComponent(); if (!Object.op_Implicit((Object)(object)val3)) { val3 = ((Component)val).gameObject.AddComponent(); } if (intensity > 0.1f) { val3.reverbPreset = (AudioReverbPreset)9; val3.dryLevel = Mathf.Lerp(0f, -10f, intensity); val3.room = Mathf.Lerp(-10000f, -2000f, intensity); val3.roomHF = Mathf.Lerp(-1000f, 0f, intensity); val3.decayTime = Mathf.Lerp(0.5f, 2.5f, intensity); ((Behaviour)val3).enabled = true; } else { ((Behaviour)val3).enabled = false; } } private void RestoreAudio() { if (Object.op_Implicit((Object)(object)_lowPass)) { ((Behaviour)_lowPass).enabled = false; _lowPass = null; } AudioListener val = Object.FindFirstObjectByType(); if (Object.op_Implicit((Object)(object)val)) { AudioHighPassFilter component = ((Component)val).gameObject.GetComponent(); if (Object.op_Implicit((Object)(object)component)) { ((Behaviour)component).enabled = false; } AudioReverbFilter component2 = ((Component)val).gameObject.GetComponent(); if (Object.op_Implicit((Object)(object)component2)) { ((Behaviour)component2).enabled = false; } } } private void OnDestroy() { ResetEffects(); if (Object.op_Implicit((Object)(object)_ownedHeatDistort)) { Object.Destroy((Object)(object)_ownedHeatDistort); } } } } internal sealed class <>z__ReadOnlyArray : IEnumerable, IEnumerable, IReadOnlyCollection, IReadOnlyList, ICollection, IList { int IReadOnlyCollection.Count => _items.Length; T IReadOnlyList.this[int index] => _items[index]; int ICollection.Count => _items.Length; bool ICollection.IsReadOnly => true; T IList.this[int index] { get { return _items[index]; } set { throw new NotSupportedException(); } } public <>z__ReadOnlyArray(T[] items) { _items = items; } IEnumerator IEnumerable.GetEnumerator() { return ((IEnumerable)_items).GetEnumerator(); } IEnumerator IEnumerable.GetEnumerator() { return ((IEnumerable)_items).GetEnumerator(); } void ICollection.Add(T item) { throw new NotSupportedException(); } void ICollection.Clear() { throw new NotSupportedException(); } bool ICollection.Contains(T item) { return ((ICollection)_items).Contains(item); } void ICollection.CopyTo(T[] array, int arrayIndex) { ((ICollection)_items).CopyTo(array, arrayIndex); } bool ICollection.Remove(T item) { throw new NotSupportedException(); } int IList.IndexOf(T item) { return ((IList)_items).IndexOf(item); } void IList.Insert(int index, T item) { throw new NotSupportedException(); } void IList.RemoveAt(int index) { throw new NotSupportedException(); } }