Please disclose if any significant portion of your mod was created using AI tools by adding the 'AI Generated' category. Failing to do so may result in the mod being removed from Thunderstore.
Decompiled source of VBDiving v0.0.6
plugins/VBDiving.dll
Decompiled 4 days ago
The result has been truncated due to the large size, download it to view full contents!
using System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.Globalization; using System.IO; using System.Linq; using System.Reflection; using System.Reflection.Emit; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.Versioning; using System.Security.Permissions; using System.Text; using BepInEx; using BepInEx.Configuration; using HarmonyLib; using Jotunn; using Jotunn.Entities; using Jotunn.Extensions; using Jotunn.Managers; using Jotunn.Utils; using Microsoft.CodeAnalysis; using TMPro; using UnityEngine; using UnityEngine.Rendering; using UnityEngine.UI; using VBDiving.Effects; using VBDiving.Mobs; using VBDiving.Patches; using VBDiving.Utills; using YamlDotNet.Serialization; using YamlDotNet.Serialization.NamingConventions; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)] [assembly: AssemblyTitle("SwimmingReworked")] [assembly: AssemblyDescription("")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("")] [assembly: AssemblyProduct("SwimmingReworked")] [assembly: AssemblyCopyright("Copyright © 2021")] [assembly: AssemblyTrademark("")] [assembly: ComVisible(false)] [assembly: Guid("e3243d22-4307-4008-ba36-9f326008cde5")] [assembly: AssemblyFileVersion("1.0.3")] [assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("1.0.3.0")] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)] internal sealed class NullableAttribute : Attribute { public readonly byte[] NullableFlags; public NullableAttribute(byte P_0) { NullableFlags = new byte[1] { P_0 }; } public NullableAttribute(byte[] P_0) { NullableFlags = P_0; } } [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)] internal sealed class NullableContextAttribute : Attribute { public readonly byte Flag; public NullableContextAttribute(byte P_0) { Flag = P_0; } } [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)] internal sealed class RefSafetyRulesAttribute : Attribute { public readonly int Version; public RefSafetyRulesAttribute(int P_0) { Version = P_0; } } } namespace VBDiving { internal class BreathHud : MonoBehaviour { private GameObject _root; private RectTransform _container; private readonly List<Image> _bubbles = new List<Image>(); private Sprite _bubbleSprite; private TextMeshProUGUI _breathText; private bool _isInitialized; private bool _initializationAttempted; private float _cachedOffsetX; private float _cachedOffsetY; private float _cachedScale; private bool _cachedShowLabels; private const int MaxBubbles = 12; private const float BubbleSize = 12f; private void Awake() { _isInitialized = false; _initializationAttempted = false; } private void Start() { TryInitialize(); } private void TryInitialize() { if (!_isInitialized && !_initializationAttempted && Object.op_Implicit((Object)(object)Player.m_localPlayer)) { _initializationAttempted = true; TMP_FontAsset val = FindFont(); if (!Object.op_Implicit((Object)(object)val)) { VBDiving.LogDebug("[BreathHud] Font not found yet, will retry later"); _initializationAttempted = false; ((MonoBehaviour)this).StartCoroutine(RetryInitialize()); } else { CreateHud(val); ApplyPositionAndScale(); _isInitialized = true; VBDiving.LogDebug("[BreathHud] Successfully initialized"); } } } private IEnumerator RetryInitialize() { for (int i = 0; i < 10; i++) { yield return (object)new WaitForSeconds(1f); TMP_FontAsset font = FindFont(); if (Object.op_Implicit((Object)(object)font) && Object.op_Implicit((Object)(object)Player.m_localPlayer)) { CreateHud(font); ApplyPositionAndScale(); _isInitialized = true; VBDiving.LogDebug("[BreathHud] Successfully initialized on retry"); yield break; } } VBDiving.LogDebug("[BreathHud] Failed to initialize after retries, using fallback"); CreateHudWithFallbackFont(); ApplyPositionAndScale(); _isInitialized = true; } private TMP_FontAsset FindFont() { TMP_FontAsset val = ((IEnumerable<TMP_FontAsset>)Resources.FindObjectsOfTypeAll<TMP_FontAsset>()).FirstOrDefault((Func<TMP_FontAsset, bool>)((TMP_FontAsset f) => ((Object)f).name == "Valheim-Norsebold")); if (!Object.op_Implicit((Object)(object)val)) { val = ((IEnumerable<TMP_FontAsset>)Resources.FindObjectsOfTypeAll<TMP_FontAsset>()).FirstOrDefault((Func<TMP_FontAsset, bool>)((TMP_FontAsset f) => ((Object)f).name == "LiberationSans SDF")); } if (!Object.op_Implicit((Object)(object)val)) { val = Resources.FindObjectsOfTypeAll<TMP_FontAsset>().FirstOrDefault(); } return val; } private void CreateHudWithFallbackFont() { CreateHud(null); ((MonoBehaviour)this).StartCoroutine(AssignFontLater()); } private IEnumerator AssignFontLater() { yield return (object)new WaitForSeconds(2f); TMP_FontAsset font = FindFont(); if (Object.op_Implicit((Object)(object)font) && Object.op_Implicit((Object)(object)_breathText)) { ((TMP_Text)_breathText).font = font; VBDiving.LogDebug("[BreathHud] Font assigned after delay"); } } private void Update() { if (!_isInitialized) { TryInitialize(); return; } Player localPlayer = Player.m_localPlayer; if (!Object.op_Implicit((Object)(object)localPlayer) || !Object.op_Implicit((Object)(object)Camera.main)) { SetVisible(visible: false); return; } CheckConfigChanges(); float currentBreath = SwimAPI.GetCurrentBreath(localPlayer); float maxBreath = SwimAPI.GetMaxBreath(localPlayer); float percent = Mathf.Clamp01(SwimAPI.GetBreathPercent(localPlayer)); bool flag = WaterHelper.IsHeadUnderwater(localPlayer); bool flag2 = currentBreath < maxBreath - 0.01f; bool flag3 = flag || flag2; SetVisible(flag3); if (flag3) { float skillLevel = ((Character)localPlayer).GetSkillLevel((SkillType)103); UpdateBubblesHorizontal(percent, skillLevel); if (Object.op_Implicit((Object)(object)_breathText) && ((Component)_breathText).gameObject.activeSelf) { ((TMP_Text)_breathText).text = $"{Mathf.CeilToInt(currentBreath)}"; } } } private void UpdateBubblesHorizontal(float percent, float swimSkillLevel) { //IL_015a: Unknown result type (might be due to invalid IL or missing references) //IL_017b: Unknown result type (might be due to invalid IL or missing references) //IL_00cf: Unknown result type (might be due to invalid IL or missing references) //IL_011a: Unknown result type (might be due to invalid IL or missing references) int num = 2 + Mathf.FloorToInt(swimSkillLevel / 10f); num = Mathf.Clamp(num, 2, 12); int num2 = Mathf.CeilToInt(percent * (float)num); float num3 = 12f; float num4 = (float)num * 12f; float num5 = 0f - num4 / 2f + 6f; for (int i = 0; i < _bubbles.Count; i++) { Image val = _bubbles[i]; bool flag = i < num; ((Component)val).gameObject.SetActive(flag); if (flag) { bool flag2 = i < num2; float num6 = num5 + (float)i * num3; if (flag2) { RectTransform rectTransform = ((Graphic)val).rectTransform; float num7 = Mathf.Sin(Time.time * 5f + (float)i * 0.5f) * 2f; rectTransform.anchoredPosition = new Vector2(num6, num7); float num8 = 0.6f + 0.4f * Mathf.PingPong(Time.time * 2f + (float)i * 0.3f, 1f); ((Graphic)val).color = new Color(0.8f, 0.92f, 1f, num8); } else { RectTransform rectTransform2 = ((Graphic)val).rectTransform; float num9 = Mathf.Sin(Time.time * 5f + (float)i * 0.5f) * 2f; rectTransform2.anchoredPosition = new Vector2(num6, num9); ((Graphic)val).color = new Color(0.3f, 0.4f, 0.5f, 0.3f); } } } } private void CheckConfigChanges() { //IL_00b6: Unknown result type (might be due to invalid IL or missing references) //IL_00bc: Unknown result type (might be due to invalid IL or missing references) if (!Object.op_Implicit((Object)(object)VBDiving.Instance)) { return; } float value = VBDiving.BreathHudOffsetX.Value; float value2 = VBDiving.BreathHudOffsetY.Value; float value3 = VBDiving.BreathHudScale.Value; bool value4 = VBDiving.BreathHudShowLabels.Value; bool flag = !Mathf.Approximately(_cachedOffsetX, value) || !Mathf.Approximately(_cachedOffsetY, value2); bool flag2 = !Mathf.Approximately(_cachedScale, value3); bool flag3 = _cachedShowLabels != value4; if (flag) { ApplyPosition(value, value2); _cachedOffsetX = value; _cachedOffsetY = value2; } if (flag2) { ((Transform)_container).localScale = Vector3.one * value3; _cachedScale = value3; } if (flag3) { if (Object.op_Implicit((Object)(object)_breathText)) { ((Component)_breathText).gameObject.SetActive(value4); } _cachedShowLabels = value4; } } private void ApplyPositionAndScale() { //IL_0048: Unknown result type (might be due to invalid IL or missing references) //IL_004e: Unknown result type (might be due to invalid IL or missing references) if (Object.op_Implicit((Object)(object)_container)) { float value = VBDiving.BreathHudOffsetX.Value; float value2 = VBDiving.BreathHudOffsetY.Value; float value3 = VBDiving.BreathHudScale.Value; ApplyPosition(value, value2); ((Transform)_container).localScale = Vector3.one * value3; _cachedOffsetX = value; _cachedOffsetY = value2; _cachedScale = value3; _cachedShowLabels = VBDiving.BreathHudShowLabels.Value; if (Object.op_Implicit((Object)(object)_breathText)) { ((Component)_breathText).gameObject.SetActive(_cachedShowLabels); } } } private void ApplyPosition(float offsetXPercent, float offsetYPercent) { //IL_0028: Unknown result type (might be due to invalid IL or missing references) //IL_0043: Unknown result type (might be due to invalid IL or missing references) //IL_005e: Unknown result type (might be due to invalid IL or missing references) //IL_008f: Unknown result type (might be due to invalid IL or missing references) if (Object.op_Implicit((Object)(object)_container)) { _container.anchorMin = new Vector2(0.5f, 0.5f); _container.anchorMax = new Vector2(0.5f, 0.5f); _container.pivot = new Vector2(0.5f, 0.5f); float num = offsetXPercent / 100f * (float)Screen.width; float num2 = offsetYPercent / 100f * (float)Screen.height; _container.anchoredPosition = new Vector2(num, num2); if (VBDiving.DebugLogging.Value) { VBDiving.LogDebug($"BreathHud position applied: X={num}, Y={num2}"); } } } private void SetVisible(bool visible) { if (Object.op_Implicit((Object)(object)_root) && _root.activeSelf != visible) { _root.SetActive(visible); } } private void CreateHud(TMP_FontAsset font) { //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Expected O, but got Unknown //IL_005c: Unknown result type (might be due to invalid IL or missing references) //IL_0084: Unknown result type (might be due to invalid IL or missing references) //IL_008a: Expected O, but got Unknown //IL_00c0: Unknown result type (might be due to invalid IL or missing references) //IL_00f3: Unknown result type (might be due to invalid IL or missing references) //IL_00fa: Expected O, but got Unknown //IL_0123: Unknown result type (might be due to invalid IL or missing references) //IL_013a: Unknown result type (might be due to invalid IL or missing references) //IL_0151: Unknown result type (might be due to invalid IL or missing references) //IL_0168: Unknown result type (might be due to invalid IL or missing references) //IL_01a9: Unknown result type (might be due to invalid IL or missing references) //IL_01dd: Unknown result type (might be due to invalid IL or missing references) //IL_01e4: Expected O, but got Unknown //IL_02a7: Unknown result type (might be due to invalid IL or missing references) //IL_02cb: Unknown result type (might be due to invalid IL or missing references) //IL_02e2: Unknown result type (might be due to invalid IL or missing references) //IL_02f9: Unknown result type (might be due to invalid IL or missing references) //IL_0310: Unknown result type (might be due to invalid IL or missing references) //IL_0327: Unknown result type (might be due to invalid IL or missing references) _root = new GameObject("BreathHud"); Object.DontDestroyOnLoad((Object)(object)_root); Canvas val = _root.AddComponent<Canvas>(); val.renderMode = (RenderMode)0; val.sortingOrder = 5000; CanvasScaler val2 = _root.AddComponent<CanvasScaler>(); val2.uiScaleMode = (ScaleMode)1; val2.referenceResolution = new Vector2(1920f, 1080f); val2.matchWidthOrHeight = 0.5f; _root.AddComponent<GraphicRaycaster>(); GameObject val3 = new GameObject("Container"); val3.transform.SetParent(_root.transform, false); _container = val3.AddComponent<RectTransform>(); float num = 144f; _container.sizeDelta = new Vector2(num, 30f); _bubbleSprite = CreateBubbleSprite(64); for (int i = 0; i < 12; i++) { GameObject val4 = new GameObject($"Bubble_{i}"); val4.transform.SetParent((Transform)(object)_container, false); RectTransform val5 = val4.AddComponent<RectTransform>(); val5.sizeDelta = new Vector2(12f, 12f); val5.anchorMin = new Vector2(0.5f, 0.5f); val5.anchorMax = new Vector2(0.5f, 0.5f); val5.pivot = new Vector2(0.5f, 0.5f); Image val6 = val4.AddComponent<Image>(); val6.sprite = _bubbleSprite; val6.preserveAspect = true; ((Graphic)val6).color = new Color(0.8f, 0.92f, 1f, 0.8f); _bubbles.Add(val6); } GameObject val7 = new GameObject("BreathText"); val7.transform.SetParent((Transform)(object)_container, false); _breathText = val7.AddComponent<TextMeshProUGUI>(); if (Object.op_Implicit((Object)(object)font)) { ((TMP_Text)_breathText).font = font; } else { TMP_FontAsset val8 = Resources.FindObjectsOfTypeAll<TMP_FontAsset>().FirstOrDefault(); if (Object.op_Implicit((Object)(object)val8)) { ((TMP_Text)_breathText).font = val8; } } ((TMP_Text)_breathText).fontSize = 16f; ((TMP_Text)_breathText).fontSizeMin = 10f; ((TMP_Text)_breathText).fontSizeMax = 24f; ((TMP_Text)_breathText).alignment = (TextAlignmentOptions)4097; ((Graphic)_breathText).color = new Color(0.8f, 0.92f, 1f, 0.9f); RectTransform rectTransform = ((TMP_Text)_breathText).rectTransform; rectTransform.sizeDelta = new Vector2(60f, 25f); rectTransform.anchorMin = new Vector2(1f, 0.5f); rectTransform.anchorMax = new Vector2(1f, 0.5f); rectTransform.pivot = new Vector2(0f, 0.5f); rectTransform.anchoredPosition = new Vector2(8f, 0f); SetVisible(visible: false); } private Sprite CreateBubbleSprite(int size) { //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Expected O, but got Unknown //IL_0049: Unknown result type (might be due to invalid IL or missing references) //IL_0058: Unknown result type (might be due to invalid IL or missing references) //IL_0190: Unknown result type (might be due to invalid IL or missing references) //IL_019f: Unknown result type (might be due to invalid IL or missing references) //IL_0095: Unknown result type (might be due to invalid IL or missing references) //IL_0097: Unknown result type (might be due to invalid IL or missing references) //IL_00f6: Unknown result type (might be due to invalid IL or missing references) //IL_00f8: Unknown result type (might be due to invalid IL or missing references) //IL_00b0: Unknown result type (might be due to invalid IL or missing references) //IL_0148: Unknown result type (might be due to invalid IL or missing references) //IL_011b: Unknown result type (might be due to invalid IL or missing references) //IL_012e: Unknown result type (might be due to invalid IL or missing references) //IL_013b: Unknown result type (might be due to invalid IL or missing references) //IL_0140: Unknown result type (might be due to invalid IL or missing references) Texture2D val = new Texture2D(size, size, (TextureFormat)4, false); ((Texture)val).filterMode = (FilterMode)1; ((Texture)val).wrapMode = (TextureWrapMode)1; Vector2 val2 = default(Vector2); ((Vector2)(ref val2))..ctor((float)(size - 1) * 0.5f, (float)(size - 1) * 0.5f); float num = (float)size * 0.42f; float num2 = num * 0.72f; Vector2 val3 = default(Vector2); ((Vector2)(ref val3))..ctor(val2.x - (float)size * 0.12f, val2.y + (float)size * 0.12f); float num3 = (float)size * 0.12f; Vector2 val4 = default(Vector2); Color val5 = default(Color); for (int i = 0; i < size; i++) { for (int j = 0; j < size; j++) { ((Vector2)(ref val4))..ctor((float)j, (float)i); float num4 = Vector2.Distance(val4, val2); if (num4 > num) { val.SetPixel(j, i, Color.clear); continue; } float num5 = Mathf.InverseLerp(num, num2, num4); float num6 = Mathf.Lerp(0.15f, 0.95f, num5); ((Color)(ref val5))..ctor(0.82f, 0.93f, 1f, num6); float num7 = Vector2.Distance(val4, val3); if (num7 < num3) { float num8 = 1f - num7 / num3; val5 = Color.Lerp(val5, new Color(1f, 1f, 1f, num6), num8 * 0.65f); } val.SetPixel(j, i, val5); } } val.Apply(); return Sprite.Create(val, new Rect(0f, 0f, (float)size, (float)size), new Vector2(0.5f, 0.5f), 100f); } } [BepInPlugin("VitByr.VBDiving", "VBDiving", "0.0.6")] [BepInDependency(/*Could not decode attribute arguments.*/)] [BepInIncompatibility("sighsorry.DiveIn")] [BepInIncompatibility("ch.easy.develope.vh.diving.mod")] [BepInIncompatibility("blacks7ar.VikingsDoSwim")] [BepInIncompatibility("projjm.improvedswimming")] [BepInIncompatibility("dzk.SwimmingReworked")] [SynchronizationMode(/*Could not decode attribute arguments.*/)] internal class VBDiving : BaseUnityPlugin { public const string PluginGUID = "VitByr.VBDiving"; public const string PluginName = "VBDiving"; public const string PluginVersion = "0.0.6"; internal static VBDiving Instance; internal static Harmony Harmony; internal static ConfigEntry<bool> EnableMod; internal static ConfigEntry<float> MaxBreathSeconds; internal static ConfigEntry<float> MaxBreathBonusAtSkill100; internal static ConfigEntry<float> BreathRecoveryPerSecond; internal static ConfigEntry<float> SprintSwimMultiplier; internal static ConfigEntry<float> BaseUnderwaterStaminaRegenPerSecond; internal static ConfigEntry<bool> DebugLogging; internal static ConfigEntry<bool> UseLegacyDiveControls; internal static float SwimStaminaDrainMinSkill = 4f; internal static float SwimStaminaDrainMaxSkill = 2f; internal static ConfigEntry<float> BreathHudOffsetX; internal static ConfigEntry<float> BreathHudOffsetY; internal static ConfigEntry<float> BreathHudScale; internal static ConfigEntry<bool> BreathHudShowLabels; internal static ConfigEntry<bool> SyncMonsterConfigs; internal static ConfigEntry<bool> UseServerMonsterConfigsOnly; internal static ConfigEntry<bool> SyncDiveEffectsConfigs; internal static ConfigEntry<bool> UseServerDiveEffectsConfigsOnly; private ConfigFileWatcher _configWatcher; internal static string ConfigFolderPath; private CustomRPC _diveEffectsConfigRPC; private bool _hasRequestedDiveEffectsConfigs; private CustomRPC _monsterConfigRPC; private bool _hasRequestedConfigs; private void Awake() { //IL_0087: Unknown result type (might be due to invalid IL or missing references) //IL_0091: Expected O, but got Unknown Instance = this; ConfigFolderPath = Path.Combine(Paths.ConfigPath, "VitByr", "VBDiving"); Directory.CreateDirectory(ConfigFolderPath); CreateConfig(); CreateConfigWatcher(); SynchronizationManager.OnConfigurationSynchronized += OnConfigurationSynchronized; SynchronizationManager.OnAdminStatusChanged += OnAdminStatusChanged; ((Component)this).gameObject.AddComponent<BreathHud>(); ((Component)this).gameObject.AddComponent<DiveImmersionEffect>(); ((MonoBehaviour)this).StartCoroutine(InitDiveControllerWhenReady()); Harmony = new Harmony("VitByr.VBDiving"); Harmony.PatchAll(); SetupMonsterConfigSync(); MonsterDiveSystem.Initialize(); DiveEffectsConfigSystem.Initialize(); } private IEnumerator InitDiveControllerWhenReady() { while (!Object.op_Implicit((Object)(object)Player.m_localPlayer)) { yield return null; } Player player = Player.m_localPlayer; PlayerDiveController playerDiveController = default(PlayerDiveController); if (!((Component)player).TryGetComponent<PlayerDiveController>(ref playerDiveController)) { ((Component)player).gameObject.AddComponent<PlayerDiveController>(); ((BaseUnityPlugin)this).Logger.LogDebug((object)"DiveController added to local player"); } } private void SetupMonsterConfigSync() { //IL_0013: Unknown result type (might be due to invalid IL or missing references) //IL_001f: Unknown result type (might be due to invalid IL or missing references) //IL_0029: Expected O, but got Unknown //IL_0029: Expected O, but got Unknown _monsterConfigRPC = NetworkManager.Instance.AddRPC("VBDiving_SyncMonsterConfigs", new CoroutineHandler(OnServerReceiveRequest), new CoroutineHandler(OnClientReceiveConfigs)); if ((Object)(object)ZNet.instance != (Object)null && ZNet.instance.IsServer()) { ((BaseUnityPlugin)this).Logger.LogInfo((object)"[VBDiving] Server mode: loading monster configs"); MonsterDiveSystem.LoadAllMonsterDiveConfigs(); } else if ((Object)(object)ZNet.instance != (Object)null && ZNetExtension.IsClientInstance(ZNet.instance)) { ((BaseUnityPlugin)this).Logger.LogInfo((object)"[VBDiving] Client mode: will request monster configs from server"); } } private IEnumerator OnServerReceiveRequest(long sender, ZPackage package) { int flag = package.ReadInt(); ((BaseUnityPlugin)this).Logger.LogInfo((object)$"[VBDiving] Server received request from client {sender}, flag={flag}"); if (flag == 0) { SendMonsterConfigsToClient(sender); } yield break; } private IEnumerator OnClientReceiveConfigs(long sender, ZPackage package) { int flag = package.ReadInt(); ((BaseUnityPlugin)this).Logger.LogInfo((object)$"[VBDiving] Client received configs from server, flag={flag}"); if (flag == 1) { string configData = package.ReadString(); ((BaseUnityPlugin)this).Logger.LogInfo((object)$"[VBDiving] Received monster configs from server ({configData.Length} bytes)"); if (string.IsNullOrEmpty(configData)) { ((BaseUnityPlugin)this).Logger.LogWarning((object)"[VBDiving] Received empty config data from server"); } else if (UseServerMonsterConfigsOnly.Value) { ((BaseUnityPlugin)this).Logger.LogInfo((object)"[VBDiving] Using server configs only (ignoring local)"); MonsterDiveSystem.LoadSerializedConfigs(configData, useServerOnly: true); } else { ((BaseUnityPlugin)this).Logger.LogInfo((object)"[VBDiving] Merging server configs with local (server priority)"); MonsterDiveSystem.LoadSerializedConfigs(configData); } } yield break; } private void SendMonsterConfigsToAllClients() { //IL_0071: Unknown result type (might be due to invalid IL or missing references) //IL_0077: Expected O, but got Unknown if (!SyncMonsterConfigs.Value) { ((BaseUnityPlugin)this).Logger.LogInfo((object)"[VBDiving] SyncMonsterConfigs is disabled, not sending"); return; } string serializedConfigs = MonsterDiveSystem.GetSerializedConfigs(); if (string.IsNullOrEmpty(serializedConfigs)) { ((BaseUnityPlugin)this).Logger.LogWarning((object)"[VBDiving] No configs to send to clients"); return; } ((BaseUnityPlugin)this).Logger.LogInfo((object)$"[VBDiving] Sending monster configs to all clients ({serializedConfigs.Length} bytes)"); ZPackage val = new ZPackage(); val.Write(1); val.Write(serializedConfigs); foreach (ZNetPeer peer in ZNet.instance.m_peers) { if (peer.m_uid != ZRoutedRpc.instance.GetServerPeerID()) { _monsterConfigRPC.SendPackage(peer.m_uid, val); } } } private void SendMonsterConfigsToClient(long clientId) { //IL_00b1: Unknown result type (might be due to invalid IL or missing references) //IL_00b7: Expected O, but got Unknown if (!SyncMonsterConfigs.Value) { ((BaseUnityPlugin)this).Logger.LogInfo((object)"[VBDiving] SyncMonsterConfigs is disabled, not sending to client"); return; } string serializedConfigs = MonsterDiveSystem.GetSerializedConfigs(); if (string.IsNullOrEmpty(serializedConfigs)) { ((BaseUnityPlugin)this).Logger.LogWarning((object)$"[VBDiving] No configs to send to client {clientId}"); return; } ((BaseUnityPlugin)this).Logger.LogInfo((object)$"[VBDiving] Sending monster configs to client {clientId} ({serializedConfigs.Length} bytes)"); ((BaseUnityPlugin)this).Logger.LogDebug((object)("[VBDiving] Configs preview: " + serializedConfigs.Substring(0, Math.Min(200, serializedConfigs.Length)) + "...")); ZPackage val = new ZPackage(); val.Write(1); val.Write(serializedConfigs); _monsterConfigRPC.SendPackage(clientId, val); } internal static void RequestMonsterConfigsFromServer() { //IL_007a: Unknown result type (might be due to invalid IL or missing references) //IL_0080: Expected O, but got Unknown if (!((Object)(object)Instance == (Object)null) && !((Object)(object)ZNet.instance == (Object)null) && !ZNet.instance.IsServer() && SyncMonsterConfigs.Value && !Instance._hasRequestedConfigs) { Instance._hasRequestedConfigs = true; ((BaseUnityPlugin)Instance).Logger.LogInfo((object)"[VBDiving] Requesting monster configs from server..."); ZPackage val = new ZPackage(); val.Write(0); Instance._monsterConfigRPC.SendPackage(ZRoutedRpc.instance.GetServerPeerID(), val); } } internal static void OnServerConfigsChanged() { if ((Object)(object)Instance != (Object)null && (Object)(object)ZNet.instance != (Object)null && ZNet.instance.IsServer() && SyncMonsterConfigs.Value) { ((BaseUnityPlugin)Instance).Logger.LogInfo((object)"[VBDiving] Server configs changed, sending updates to all clients"); Instance.SendMonsterConfigsToAllClients(); } } private void CreateConfig() { //IL_01e8: Unknown result type (might be due to invalid IL or missing references) //IL_01f2: Expected O, but got Unknown ((BaseUnityPlugin)this).Config.SaveOnConfigSet = false; EnableMod = ConfigFileExtensions.BindConfig<bool>(((BaseUnityPlugin)this).Config, "00 - Main", "EnableMod", true, "Включить или отключить мод.", true, (int?)null, (AcceptableValueBase)null, (Action<ConfigEntryBase>)null, (ConfigurationManagerAttributes)null); SyncMonsterConfigs = ConfigFileExtensions.BindConfig<bool>(((BaseUnityPlugin)this).Config, "00 - Main", "SyncMonsterConfigs", true, "Синхронизировать конфиги монстров с сервера.", true, (int?)null, (AcceptableValueBase)null, (Action<ConfigEntryBase>)null, (ConfigurationManagerAttributes)null); UseServerMonsterConfigsOnly = ConfigFileExtensions.BindConfig<bool>(((BaseUnityPlugin)this).Config, "00 - Main", "UseServerMonsterConfigsOnly", true, "Использовать ТОЛЬКО конфиги с сервера (игнорировать локальные файлы). Если false - серверные конфиги имеют приоритет над локальными.", true, (int?)null, (AcceptableValueBase)null, (Action<ConfigEntryBase>)null, (ConfigurationManagerAttributes)null); UseLegacyDiveControls = ((BaseUnityPlugin)this).Config.Bind<bool>("01 - Control", "UseLegacyDiveControls", true, "Если true: зажать Crouch для погружения, Jump для всплытия.\nЕсли false: нажать Crouch для переключения режима ныряния, затем направление взгляда + Forward для движения вверх/вниз."); MaxBreathSeconds = ConfigFileExtensions.BindConfig<float>(((BaseUnityPlugin)this).Config, "02 - Breath", "MaxBreathSeconds", 30f, "Максимальное время под водой при навыке плавания 0.", true, (int?)null, (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 600f), (Action<ConfigEntryBase>)null, (ConfigurationManagerAttributes)null); MaxBreathBonusAtSkill100 = ConfigFileExtensions.BindConfig<float>(((BaseUnityPlugin)this).Config, "02 - Breath", "MaxBreathBonusAtSkill100", 150f, "Дополнительное время под водой при навыке плавания 100.", true, (int?)null, (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 600f), (Action<ConfigEntryBase>)null, (ConfigurationManagerAttributes)null); BreathRecoveryPerSecond = ConfigFileExtensions.BindConfig<float>(((BaseUnityPlugin)this).Config, "02 - Breath", "BreathRecoveryPerSecond", 30f, "Скорость восстановления дыхания.", true, (int?)null, (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 300f), (Action<ConfigEntryBase>)null, (ConfigurationManagerAttributes)null); BreathHudOffsetX = ((BaseUnityPlugin)this).Config.Bind<float>("03 - BreathHud", "OffsetX", 0f, "Смещение индикатора по горизонтали от центра экрана (в процентах от ширины экрана).\nОтрицательное = левее, положительное = правее."); BreathHudOffsetY = ((BaseUnityPlugin)this).Config.Bind<float>("03 - BreathHud", "OffsetY", -30f, "Смещение индикатора по вертикали от центра экрана (в процентах от высоты экрана).\nОтрицательное = ниже, положительное = выше."); BreathHudScale = ((BaseUnityPlugin)this).Config.Bind<float>("03 - BreathHud", "Scale", 1f, new ConfigDescription("Масштаб индикатора дыхания.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.3f, 3f), Array.Empty<object>())); BreathHudShowLabels = ((BaseUnityPlugin)this).Config.Bind<bool>("03 - BreathHud", "ShowLabels", true, "Показывать числовое значение дыхания справа от пузырьков."); SprintSwimMultiplier = ConfigFileExtensions.BindConfig<float>(((BaseUnityPlugin)this).Config, "04 - Swimming", "SprintSwimMultiplier", 2.25f, "Множитель скорости при спринте в воде.", true, (int?)null, (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 5f), (Action<ConfigEntryBase>)null, (ConfigurationManagerAttributes)null); BaseUnderwaterStaminaRegenPerSecond = ConfigFileExtensions.BindConfig<float>(((BaseUnityPlugin)this).Config, "04 - Swimming", "BaseUnderwaterStaminaRegenPerSecond", 1.25f, "Базовая скорость восстановления выносливости на поверхности без движения.", true, (int?)null, (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 50f), (Action<ConfigEntryBase>)null, (ConfigurationManagerAttributes)null); PlayerEquipInWater.EquipInWaterList = ConfigFileExtensions.BindConfig<string>(((BaseUnityPlugin)this).Config, "06 - EquipInWater", "EiW_Custom", "KnifeFlint,KnifeCopper,KnifeChitin,KnifeSilver,KnifeBlackMetal,KnifeButcher,KnifeSkollAndHati,SpearFlint,SpearBronze,SpearElderbark,SpearWolfFang,SpearChitin,SpearCarapace,PickaxeAntler,PickaxeBronze,PickaxeIron,PickaxeBlackMetal,Hammer,Hoe,FistFenrirClaw", "Разрешить использовать оружие/инструмент в воде", true, (int?)null, (AcceptableValueBase)null, (Action<ConfigEntryBase>)null, (ConfigurationManagerAttributes)null); PlayerEquipInWater.EquipInWaterList.SettingChanged += delegate { HashSet<string> hashSet2 = new HashSet<string>(); string[] array2 = PlayerEquipInWater.EquipInWaterList.Value.Split(new char[1] { ',' }, StringSplitOptions.RemoveEmptyEntries); foreach (string item2 in array2) { hashSet2.Add(item2); } PlayerEquipInWater.EquipInWaterItems = hashSet2; }; HashSet<string> hashSet = new HashSet<string>(); string[] array = PlayerEquipInWater.EquipInWaterList.Value.Split(new char[1] { ',' }, StringSplitOptions.RemoveEmptyEntries); foreach (string item in array) { hashSet.Add(item); } PlayerEquipInWater.EquipInWaterItems = hashSet; SyncDiveEffectsConfigs = ConfigFileExtensions.BindConfig<bool>(((BaseUnityPlugin)this).Config, "00 - Main", "SyncDiveEffectsConfigs", true, "Синхронизировать конфиги подводных эффектов с сервера.", true, (int?)null, (AcceptableValueBase)null, (Action<ConfigEntryBase>)null, (ConfigurationManagerAttributes)null); UseServerDiveEffectsConfigsOnly = ConfigFileExtensions.BindConfig<bool>(((BaseUnityPlugin)this).Config, "00 - Main", "UseServerDiveEffectsConfigsOnly", true, "Использовать ТОЛЬКО конфиги с сервера (игнорировать локальные файлы). Если false - серверные конфиги имеют приоритет над локальными.", true, (int?)null, (AcceptableValueBase)null, (Action<ConfigEntryBase>)null, (ConfigurationManagerAttributes)null); DebugLogging = ((BaseUnityPlugin)this).Config.Bind<bool>("Debug", "DebugLogging", false, "Включить отладочные логи."); ((BaseUnityPlugin)this).Config.SaveOnConfigSet = true; ((BaseUnityPlugin)this).Config.Save(); } private void CreateConfigWatcher() { //IL_000e: Unknown result type (might be due to invalid IL or missing references) //IL_0018: Expected O, but got Unknown _configWatcher = new ConfigFileWatcher(((BaseUnityPlugin)this).Config, 1000L); _configWatcher.OnConfigFileReloaded += delegate { ((BaseUnityPlugin)this).Logger.LogInfo((object)"Config file reloaded from disk."); }; } internal static float GetClampedSkillFactor(Player player, SkillType skillType) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) float skillLevel = ((Character)player).GetSkillLevel(skillType); float num = Mathf.Min(skillLevel, 100f); return num / 100f; } internal static float GetClampedSwimFactor(Player player) { float skillLevel = ((Character)player).GetSkillLevel((SkillType)103); float num = Mathf.Min(skillLevel, 100f); return num / 100f; } private void OnConfigurationSynchronized(object sender, ConfigurationSynchronizationEventArgs e) { if (e.InitialSynchronization) { ((BaseUnityPlugin)this).Logger.LogInfo((object)"Initial config sync received."); if ((Object)(object)ZNet.instance != (Object)null && ZNetExtension.IsClientInstance(ZNet.instance)) { ((MonoBehaviour)this).StartCoroutine(RequestConfigsAfterSync()); } } if ((Object)(object)ZNet.instance != (Object)null && ZNet.instance.IsServer()) { if (SyncMonsterConfigs.Value) { SendMonsterConfigsToAllClients(); } if (SyncDiveEffectsConfigs.Value) { SendDiveEffectsConfigsToAllClients(); } } } private IEnumerator RequestConfigsAfterSync() { yield return (object)new WaitForSeconds(2f); RequestMonsterConfigsFromServer(); RequestDiveEffectsConfigsFromServer(); } private void OnAdminStatusChanged() { ((BaseUnityPlugin)this).Logger.LogInfo((object)("Admin status changed: " + (SynchronizationManager.Instance.PlayerIsAdmin ? "admin" : "not admin"))); } private void SetupDiveEffectsConfigSync() { //IL_0013: Unknown result type (might be due to invalid IL or missing references) //IL_001f: Unknown result type (might be due to invalid IL or missing references) //IL_0029: Expected O, but got Unknown //IL_0029: Expected O, but got Unknown _diveEffectsConfigRPC = NetworkManager.Instance.AddRPC("VBDiving_SyncDiveEffectsConfigs", new CoroutineHandler(OnServerReceiveDiveEffectsRequest), new CoroutineHandler(OnClientReceiveDiveEffectsConfigs)); if ((Object)(object)ZNet.instance != (Object)null && ZNet.instance.IsServer()) { DiveEffectsConfigSystem.LoadAllConfigs(); } } private IEnumerator OnServerReceiveDiveEffectsRequest(long sender, ZPackage package) { if (package.ReadInt() == 0) { SendDiveEffectsConfigsToClient(sender); } yield break; } private IEnumerator OnClientReceiveDiveEffectsConfigs(long sender, ZPackage package) { int flag = package.ReadInt(); if (flag != 1) { yield break; } string configData = package.ReadString(); if (!string.IsNullOrEmpty(configData)) { if (UseServerDiveEffectsConfigsOnly.Value) { DiveEffectsConfigSystem.LoadSerializedConfigs(configData, useServerOnly: true); } else { DiveEffectsConfigSystem.LoadSerializedConfigs(configData); } } } private void SendDiveEffectsConfigsToAllClients() { //IL_002c: Unknown result type (might be due to invalid IL or missing references) //IL_0032: Expected O, but got Unknown if (!SyncDiveEffectsConfigs.Value) { return; } string serializedConfigs = DiveEffectsConfigSystem.GetSerializedConfigs(); if (string.IsNullOrEmpty(serializedConfigs)) { return; } ZPackage val = new ZPackage(); val.Write(1); val.Write(serializedConfigs); foreach (ZNetPeer peer in ZNet.instance.m_peers) { if (peer.m_uid != ZRoutedRpc.instance.GetServerPeerID()) { _diveEffectsConfigRPC.SendPackage(peer.m_uid, val); } } } private void SendDiveEffectsConfigsToClient(long clientId) { //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_002c: Expected O, but got Unknown if (SyncDiveEffectsConfigs.Value) { string serializedConfigs = DiveEffectsConfigSystem.GetSerializedConfigs(); if (!string.IsNullOrEmpty(serializedConfigs)) { ZPackage val = new ZPackage(); val.Write(1); val.Write(serializedConfigs); _diveEffectsConfigRPC.SendPackage(clientId, val); } } } internal static void RequestDiveEffectsConfigsFromServer() { //IL_0062: Unknown result type (might be due to invalid IL or missing references) //IL_0068: Expected O, but got Unknown if (!((Object)(object)Instance == (Object)null) && !((Object)(object)ZNet.instance == (Object)null) && !ZNet.instance.IsServer() && SyncDiveEffectsConfigs.Value && !Instance._hasRequestedDiveEffectsConfigs) { Instance._hasRequestedDiveEffectsConfigs = true; ZPackage val = new ZPackage(); val.Write(0); Instance._diveEffectsConfigRPC.SendPackage(ZRoutedRpc.instance.GetServerPeerID(), val); } } internal static void OnDiveEffectsConfigsChanged() { if ((Object)(object)Instance != (Object)null && (Object)(object)ZNet.instance != (Object)null && ZNet.instance.IsServer() && SyncDiveEffectsConfigs.Value) { Instance.SendDiveEffectsConfigsToAllClients(); } } private void OnDestroy() { SynchronizationManager.OnConfigurationSynchronized -= OnConfigurationSynchronized; SynchronizationManager.OnAdminStatusChanged -= OnAdminStatusChanged; if (_configWatcher != null) { _configWatcher = null; } } internal static bool IsEnabled() { return Object.op_Implicit((Object)(object)Instance) && EnableMod.Value; } internal static void LogDebug(string msg) { if (Object.op_Implicit((Object)(object)Instance) && DebugLogging.Value) { ((BaseUnityPlugin)Instance).Logger.LogInfo((object)msg); } } } } namespace VBDiving.Mobs { [HarmonyPatch] internal static class MonsterDivePatches { [HarmonyPostfix] [HarmonyPatch(typeof(MonsterAI), "Awake")] private static void MonsterAIAwakePostfix(MonsterAI __instance) { if (VBDiving.IsEnabled() && MonsterDiveSystem.IsConfiguredMonster(__instance)) { MonsterDiveSystem.EnsureDiveFlags(__instance); } } [HarmonyPrefix] [HarmonyPatch(typeof(MonsterAI), "UpdateAI")] private static void MonsterAIUpdateAIPrefix(MonsterAI __instance) { if (VBDiving.IsEnabled() && MonsterDiveSystem.IsConfiguredMonster(__instance)) { MonsterDiveSystem.EnsureDiveFlags(__instance); } } [HarmonyPrefix] [HarmonyPatch(typeof(BaseAI), "HavePath")] private static bool BaseAIHavePathPrefix(BaseAI __instance, Vector3 target, ref bool __result) { //IL_0064: Unknown result type (might be due to invalid IL or missing references) if (!VBDiving.IsEnabled()) { return true; } MonsterAI val = (MonsterAI)(object)((__instance is MonsterAI) ? __instance : null); if (val == null) { return true; } if (!MonsterDiveSystem.IsConfiguredMonster(val) || !MonsterDiveSystem.ShouldUseWaterDiveMode(val)) { return true; } Character character = ((BaseAI)val).m_character; if (!Object.op_Implicit((Object)(object)character)) { return true; } __result = MonsterDiveSystem.HasReasonableUnderwaterRoute(__instance, character, target); return false; } [HarmonyPrefix] [HarmonyPatch(typeof(BaseAI), "MoveTo")] private static bool BaseAIMoveToPrefix(BaseAI __instance, float dt, Vector3 point, float dist, bool run, ref bool __result) { //IL_0075: Unknown result type (might be due to invalid IL or missing references) //IL_0094: Unknown result type (might be due to invalid IL or missing references) //IL_009b: Unknown result type (might be due to invalid IL or missing references) //IL_00a7: Unknown result type (might be due to invalid IL or missing references) //IL_00b3: Unknown result type (might be due to invalid IL or missing references) //IL_00cc: Unknown result type (might be due to invalid IL or missing references) //IL_0119: Unknown result type (might be due to invalid IL or missing references) //IL_0120: Unknown result type (might be due to invalid IL or missing references) //IL_0125: Unknown result type (might be due to invalid IL or missing references) //IL_012a: Unknown result type (might be due to invalid IL or missing references) //IL_0156: Unknown result type (might be due to invalid IL or missing references) //IL_0157: Unknown result type (might be due to invalid IL or missing references) //IL_015c: Unknown result type (might be due to invalid IL or missing references) //IL_0187: Unknown result type (might be due to invalid IL or missing references) if (!VBDiving.IsEnabled()) { return true; } MonsterAI val = (MonsterAI)(object)((__instance is MonsterAI) ? __instance : null); if (val == null) { return true; } if (!MonsterDiveSystem.IsConfiguredMonster(val) || !MonsterDiveSystem.ShouldUseWaterDiveMode(val)) { return true; } Character character = ((BaseAI)val).m_character; if (!Object.op_Implicit((Object)(object)character)) { return true; } float num = MonsterDiveSystem.UpdateSwimDepthTowardsTarget(val, character, point, dt); float num2 = Mathf.Max(dist, run ? 1f : 0.5f); float num3 = Utils.DistanceXZ(point, ((Component)__instance).transform.position); float num4 = Mathf.Abs(point.y - ((Component)__instance).transform.position.y); float num5 = Mathf.Abs(num - ((Component)__instance).transform.position.y); if (num3 < num2 && (num4 < 0.75f || num5 < 0.35f)) { __instance.StopMoving(); __result = true; return false; } Vector3 val2 = point - ((Component)__instance).transform.position; if (((Vector3)(ref val2)).sqrMagnitude <= 0.0001f) { __instance.StopMoving(); __result = true; return false; } Vector3 val3 = MonsterDiveSystem.BuildSteerDirectionWithAvoidance(__instance, character, point); if (((Vector3)(ref val3)).sqrMagnitude <= 0.0001f) { __instance.StopMoving(); __result = true; return false; } __instance.MoveTowards(val3, run); __result = false; return false; } [HarmonyPrefix] [HarmonyPatch(typeof(Character), "IsOnGround")] private static bool CharacterIsOnGroundPrefix(Character __instance, ref bool __result) { if (!VBDiving.IsEnabled()) { return true; } if (__instance is Player) { return true; } MonsterAI component = ((Component)__instance).GetComponent<MonsterAI>(); if (!Object.op_Implicit((Object)(object)component)) { return true; } if (!MonsterDiveSystem.IsConfiguredMonster(component)) { return true; } if (MonsterDiveSystem.ShouldUseWaterDiveMode(component)) { __result = false; return false; } return true; } [HarmonyPostfix] [HarmonyPatch(typeof(MonsterAI), "UpdateAI")] private static void MonsterAIUpdateAIPostfix(MonsterAI __instance, float dt) { //IL_008c: Unknown result type (might be due to invalid IL or missing references) //IL_00ad: Unknown result type (might be due to invalid IL or missing references) //IL_00b2: Unknown result type (might be due to invalid IL or missing references) //IL_00c3: Unknown result type (might be due to invalid IL or missing references) //IL_00de: Unknown result type (might be due to invalid IL or missing references) //IL_00fb: Unknown result type (might be due to invalid IL or missing references) //IL_0100: Unknown result type (might be due to invalid IL or missing references) //IL_0110: Unknown result type (might be due to invalid IL or missing references) if (!VBDiving.IsEnabled() || !MonsterDiveSystem.IsConfiguredMonster(__instance)) { return; } Character character = ((BaseAI)__instance).m_character; if (!Object.op_Implicit((Object)(object)character) || !MonsterDiveSystem.ShouldUseWaterDiveMode(__instance)) { return; } character.m_lastGroundTouch = 1f; if (character.IsOnGround() && character.InWater()) { float liquidLevel = character.GetLiquidLevel(); float num = liquidLevel - character.m_swimDepth; if (((Component)character).transform.position.y < num + 0.5f) { Vector3 position = ((Component)character).transform.position; position.y = num; ((Component)character).transform.position = position; Rigidbody component = ((Component)character).GetComponent<Rigidbody>(); if (Object.op_Implicit((Object)(object)component) && component.linearVelocity.y < 0f) { Vector3 linearVelocity = component.linearVelocity; linearVelocity.y = 0f; component.linearVelocity = linearVelocity; } } } character.m_swimTimer = 0f; } } internal static class MonsterDiveSystem { private readonly struct RouteCacheEntry { public readonly float Time; public readonly Vector3Int PositionBucket; public readonly Vector3Int TargetBucket; public readonly bool Result; public RouteCacheEntry(float time, Vector3Int positionBucket, Vector3Int targetBucket, bool result) { //IL_0009: Unknown result type (might be due to invalid IL or missing references) //IL_000a: Unknown result type (might be due to invalid IL or missing references) //IL_0010: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Unknown result type (might be due to invalid IL or missing references) Time = time; PositionBucket = positionBucket; TargetBucket = targetBucket; Result = result; } } private readonly struct SteerCacheEntry { public readonly float Time; public readonly Vector3Int PositionBucket; public readonly Vector3Int TargetBucket; public readonly Vector3 Direction; public SteerCacheEntry(float time, Vector3Int positionBucket, Vector3Int targetBucket, Vector3 direction) { //IL_0009: Unknown result type (might be due to invalid IL or missing references) //IL_000a: Unknown result type (might be due to invalid IL or missing references) //IL_0010: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_0017: Unknown result type (might be due to invalid IL or missing references) //IL_0019: Unknown result type (might be due to invalid IL or missing references) Time = time; PositionBucket = positionBucket; TargetBucket = targetBucket; Direction = direction; } } private readonly struct PassiveDepthProfile { public readonly float MinDepth; public readonly float CenterDepth; public readonly float MaxPassiveDepth; public readonly float MaxAgroDepth; public PassiveDepthProfile(float minDepth, float centerDepth, float maxPassiveDepth, float maxAgroDepth) { MinDepth = Mathf.Max(0f, minDepth); MaxAgroDepth = Mathf.Max(0f, maxAgroDepth); MaxPassiveDepth = Mathf.Clamp(maxPassiveDepth, MinDepth, MaxAgroDepth); CenterDepth = Mathf.Clamp(centerDepth, MinDepth, MaxPassiveDepth); } public PassiveDepthProfile(float centerDepth, float minDepth, float maxDepth) { MinDepth = Mathf.Max(0f, minDepth); MaxAgroDepth = Mathf.Max(0f, maxDepth); MaxPassiveDepth = Mathf.Clamp(maxDepth, MinDepth, MaxAgroDepth); CenterDepth = Mathf.Clamp(centerDepth, MinDepth, MaxPassiveDepth); } } private readonly struct OriginalDiveFlags { public readonly MonsterAI MonsterAI; public readonly bool AvoidWater; public readonly bool CanSwim; public OriginalDiveFlags(MonsterAI monsterAI, bool avoidWater, bool canSwim) { MonsterAI = monsterAI; AvoidWater = avoidWater; CanSwim = canSwim; } } private readonly struct ConfiguredDiveProfile { public readonly string GroupName; public readonly PassiveDepthProfile DepthProfile; public readonly float ActiveDepthAdjustSpeed; public readonly bool UseBreath; public readonly float MaxBreathSeconds; public readonly float BreathRecoverySpeed; public readonly float SurfaceTime; public readonly float SurfaceThresholdPercent; public ConfiguredDiveProfile(string groupName, PassiveDepthProfile depthProfile, float activeDepthAdjustSpeed, bool useBreath, float maxBreathSeconds, float breathRecoverySpeed, float surfaceTime, float surfaceThresholdPercent) { GroupName = groupName; DepthProfile = depthProfile; ActiveDepthAdjustSpeed = activeDepthAdjustSpeed; UseBreath = useBreath; MaxBreathSeconds = (useBreath ? Mathf.Max(0f, maxBreathSeconds) : 0f); BreathRecoverySpeed = (useBreath ? Mathf.Max(0.1f, breathRecoverySpeed) : 0f); SurfaceTime = (useBreath ? Mathf.Max(0f, surfaceTime) : 0f); SurfaceThresholdPercent = (useBreath ? Mathf.Clamp01(surfaceThresholdPercent) : 0f); } } private sealed class MonsterDiveYamlRoot : Dictionary<string, MonsterDiveYamlGroup> { public MonsterDiveYamlRoot() : base((IEqualityComparer<string>?)StringComparer.OrdinalIgnoreCase) { } } private sealed class MonsterDiveYamlGroup { public float? MinDepth { get; set; } public float? CenterDepth { get; set; } public float? MaxDepth { get; set; } public float? MaxPassiveDepth { get; set; } public float? MaxAgroDepth { get; set; } public float? DepthAdjustSpeed { get; set; } public bool? UseBreath { get; set; } public float? MaxBreathSeconds { get; set; } public float? BreathRecoverySpeed { get; set; } public float? SurfaceTime { get; set; } public float? SurfaceThresholdPercent { get; set; } public List<string> Prefabs { get; set; } = new List<string>(); } internal static readonly string MonsterDiveConfigFolderPath; private static readonly object MonsterDiveConfigLock; private static readonly IDeserializer MonsterDiveYamlDeserializer; private static readonly Dictionary<int, RouteCacheEntry> RouteCache; private static readonly Dictionary<int, SteerCacheEntry> SteerCache; private static readonly Dictionary<int, OriginalDiveFlags> OriginalDiveFlagsByInstance; private const int MaxCacheEntries = 2048; private static readonly object PrefabSetLock; private static Dictionary<string, ConfiguredDiveProfile> _configuredDiveProfilesByPrefabName; private static FileSystemWatcher _configFolderWatcher; private static DateTime _lastReloadTime; private static readonly object _reloadLock; private const long ReloadDelayTicks = 10000000L; private static readonly float[] SteerAngles; private static readonly float[] RouteAngles; static MonsterDiveSystem() { //IL_009f: Unknown result type (might be due to invalid IL or missing references) //IL_00ae: Expected O, but got Unknown MonsterDiveConfigLock = new object(); RouteCache = new Dictionary<int, RouteCacheEntry>(); SteerCache = new Dictionary<int, SteerCacheEntry>(); OriginalDiveFlagsByInstance = new Dictionary<int, OriginalDiveFlags>(); PrefabSetLock = new object(); _configuredDiveProfilesByPrefabName = new Dictionary<string, ConfiguredDiveProfile>(StringComparer.OrdinalIgnoreCase); _reloadLock = new object(); SteerAngles = new float[8] { 0f, -35f, 35f, -70f, 70f, -120f, 120f, 180f }; RouteAngles = new float[5] { 0f, -35f, 35f, -70f, 70f }; string text = Path.Combine(Paths.ConfigPath, "VitByr", "VBDiving", "Monsters"); Directory.CreateDirectory(text); MonsterDiveConfigFolderPath = text; MonsterDiveYamlDeserializer = ((BuilderSkeleton<DeserializerBuilder>)new DeserializerBuilder()).WithNamingConvention(UnderscoredNamingConvention.Instance).WithDuplicateKeyChecking().Build(); } public static void Initialize() { LoadAllMonsterDiveConfigs(); SetupConfigFolderWatcher(); if ((Object)(object)ZNet.instance != (Object)null && ZNetExtension.IsClientInstance(ZNet.instance) && VBDiving.SyncMonsterConfigs.Value) { Debug.Log((object)"[VBDiving] Client will request monster configs from server after connection"); ((MonoBehaviour)VBDiving.Instance).StartCoroutine(RequestConfigsDelayed()); } } private static IEnumerator RequestConfigsDelayed() { yield return (object)new WaitForSeconds(3f); VBDiving.RequestMonsterConfigsFromServer(); } public static void LoadAllMonsterDiveConfigs() { if (!VBDiving.IsEnabled()) { Debug.LogWarning((object)"[VBDiving] Mod disabled, skipping monster dive config loading"); return; } lock (MonsterDiveConfigLock) { if (ShouldUseServerConfigs() && (Object)(object)ZNet.instance != (Object)null && !ZNet.instance.IsServer()) { Debug.Log((object)"[VBDiving] Skipping local config load on client - waiting for server sync"); } if (!Directory.Exists(MonsterDiveConfigFolderPath)) { Directory.CreateDirectory(MonsterDiveConfigFolderPath); CreateDefaultConfigFileIfNotExists(); } Dictionary<string, ConfiguredDiveProfile> dictionary = new Dictionary<string, ConfiguredDiveProfile>(StringComparer.OrdinalIgnoreCase); List<string> list = Directory.GetFiles(MonsterDiveConfigFolderPath, "*.yaml").Concat(Directory.GetFiles(MonsterDiveConfigFolderPath, "*.yml")).ToList(); if (list.Count == 0) { Debug.Log((object)("[VBDiving] No monster dive config files found in " + MonsterDiveConfigFolderPath + ", creating default")); CreateDefaultConfigFileIfNotExists(); list = Directory.GetFiles(MonsterDiveConfigFolderPath, "*.yaml").ToList(); } Debug.Log((object)$"[VBDiving] Found {list.Count} monster config file(s)"); foreach (string item in list) { try { LoadConfigFromFile(item, dictionary); } catch (Exception ex) { Debug.LogError((object)("[VBDiving] Failed to load config file " + Path.GetFileName(item) + ": " + ex.Message)); } } lock (PrefabSetLock) { if (_configuredDiveProfilesByPrefabName.Count > 0 && !ZNet.instance.IsServer() && ShouldUseServerConfigs()) { foreach (KeyValuePair<string, ConfiguredDiveProfile> item2 in dictionary) { if (!_configuredDiveProfilesByPrefabName.ContainsKey(item2.Key)) { _configuredDiveProfilesByPrefabName[item2.Key] = item2.Value; } } Debug.Log((object)$"[VBDiving] Merged {dictionary.Count} local prefabs with existing server configs"); } else { _configuredDiveProfilesByPrefabName = dictionary; } } ClearRuntimeCaches(); Debug.Log((object)$"[VBDiving] Loaded {_configuredDiveProfilesByPrefabName.Count} monster prefab configurations"); } } private static void ReloadAndResyncConfigs() { if (!VBDiving.IsEnabled() || (Object)(object)ZNet.instance == (Object)null || !ZNet.instance.IsServer()) { return; } lock (_reloadLock) { try { LoadAllMonsterDiveConfigs(); Debug.Log((object)"[VBDiving] Configs reloaded on server"); } catch (Exception ex) { Debug.LogError((object)("[VBDiving] Error reloading configs: " + ex.Message)); } } } private static void LoadConfigFromFile(string filePath, Dictionary<string, ConfiguredDiveProfile> allProfiles) { string text = File.ReadAllText(filePath); if (string.IsNullOrWhiteSpace(text)) { Debug.LogWarning((object)("[VBDiving] Empty config file: " + Path.GetFileName(filePath))); return; } MonsterDiveYamlRoot monsterDiveYamlRoot = ParseYamlRoot(text); if (monsterDiveYamlRoot == null) { return; } Dictionary<string, ConfiguredDiveProfile> dictionary = new Dictionary<string, ConfiguredDiveProfile>(StringComparer.OrdinalIgnoreCase); string fileName = Path.GetFileName(filePath); foreach (KeyValuePair<string, MonsterDiveYamlGroup> item in monsterDiveYamlRoot) { string text2 = item.Key?.Trim() ?? ""; if (string.IsNullOrEmpty(text2)) { continue; } MonsterDiveYamlGroup monsterDiveYamlGroup = item.Value ?? new MonsterDiveYamlGroup(); float valueOrDefault = monsterDiveYamlGroup.MinDepth.GetValueOrDefault(); float valueOrDefault2 = monsterDiveYamlGroup.CenterDepth.GetValueOrDefault(); float num; float maxPassiveDepth; if (monsterDiveYamlGroup.MaxAgroDepth.HasValue || monsterDiveYamlGroup.MaxPassiveDepth.HasValue) { num = Mathf.Max(0f, monsterDiveYamlGroup.MaxAgroDepth ?? monsterDiveYamlGroup.MaxDepth ?? 30f); maxPassiveDepth = monsterDiveYamlGroup.MaxPassiveDepth ?? num; } else { num = Mathf.Max(0f, monsterDiveYamlGroup.MaxDepth ?? 30f); maxPassiveDepth = num; } PassiveDepthProfile depthProfile = new PassiveDepthProfile(valueOrDefault, valueOrDefault2, maxPassiveDepth, num); float activeDepthAdjustSpeed = Mathf.Max(0f, monsterDiveYamlGroup.DepthAdjustSpeed ?? 2f); bool valueOrDefault3 = monsterDiveYamlGroup.UseBreath.GetValueOrDefault(); float maxBreathSeconds = Mathf.Max(0f, monsterDiveYamlGroup.MaxBreathSeconds ?? 60f); float breathRecoverySpeed = Mathf.Max(0.1f, monsterDiveYamlGroup.BreathRecoverySpeed ?? 1f); float surfaceTime = Mathf.Max(0f, monsterDiveYamlGroup.SurfaceTime ?? 3f); float surfaceThresholdPercent = Mathf.Clamp01(monsterDiveYamlGroup.SurfaceThresholdPercent ?? 0.33f); ConfiguredDiveProfile value = new ConfiguredDiveProfile(text2, depthProfile, activeDepthAdjustSpeed, valueOrDefault3, maxBreathSeconds, breathRecoverySpeed, surfaceTime, surfaceThresholdPercent); if (monsterDiveYamlGroup.Prefabs == null) { continue; } foreach (string prefab in monsterDiveYamlGroup.Prefabs) { string text3 = prefab?.Trim() ?? ""; if (!string.IsNullOrEmpty(text3)) { if (allProfiles.ContainsKey(text3) || dictionary.ContainsKey(text3)) { Debug.LogWarning((object)("[VBDiving] Prefab '" + text3 + "' already configured, skipping duplicate from " + fileName)); } else { dictionary[text3] = value; } } } } foreach (KeyValuePair<string, ConfiguredDiveProfile> item2 in dictionary) { allProfiles[item2.Key] = item2.Value; } Debug.Log((object)$"[VBDiving] Loaded {dictionary.Count} prefabs from {fileName}"); } private static MonsterDiveYamlRoot ParseYamlRoot(string yamlText) { try { MonsterDiveYamlRoot monsterDiveYamlRoot = MonsterDiveYamlDeserializer.Deserialize<MonsterDiveYamlRoot>(yamlText); return monsterDiveYamlRoot ?? new MonsterDiveYamlRoot(); } catch (Exception ex) { Debug.LogError((object)("[VBDiving] Failed to parse YAML: " + ex.Message)); return null; } } private static void CreateDefaultConfigFileIfNotExists() { string text = Path.Combine(MonsterDiveConfigFolderPath, "Vanilla.yaml"); IEnumerable<string> source = Directory.GetFiles(MonsterDiveConfigFolderPath, "*.yaml").Concat(Directory.GetFiles(MonsterDiveConfigFolderPath, "*.yml")); if (!source.Any()) { string contents = BuildDefaultMonsterDiveYaml(); File.WriteAllText(text, contents); Debug.Log((object)("[VBDiving] Created example monster dive config at: " + text)); } } private static void SetupConfigFolderWatcher() { if (_configFolderWatcher == null) { _configFolderWatcher = new FileSystemWatcher(MonsterDiveConfigFolderPath) { NotifyFilter = (NotifyFilters.FileName | NotifyFilters.LastWrite | NotifyFilters.CreationTime), IncludeSubdirectories = false, EnableRaisingEvents = true }; _configFolderWatcher.Changed += OnConfigFileChanged; _configFolderWatcher.Created += OnConfigFileChanged; _configFolderWatcher.Deleted += OnConfigFileChanged; _configFolderWatcher.Renamed += OnConfigFileRenamed; Debug.Log((object)("[VBDiving] Watching monster config folder: " + MonsterDiveConfigFolderPath)); } } private static void OnConfigFileChanged(object sender, FileSystemEventArgs e) { if (e.Name.EndsWith(".tmp") || e.Name.StartsWith("~") || (!e.Name.EndsWith(".yaml", StringComparison.OrdinalIgnoreCase) && !e.Name.EndsWith(".yml", StringComparison.OrdinalIgnoreCase))) { return; } DateTime now = DateTime.Now; if (now.Ticks - _lastReloadTime.Ticks < 10000000) { return; } lock (_reloadLock) { try { Debug.Log((object)$"[VBDiving] Config change detected ({e.ChangeType}: {e.Name}). Reloading all configs..."); LoadAllMonsterDiveConfigs(); if ((Object)(object)ZNet.instance != (Object)null && ZNet.instance.IsServer()) { NotifyServerConfigsChanged(); } _lastReloadTime = now; } catch (Exception ex) { Debug.LogError((object)("[VBDiving] Error reloading monster configs: " + ex.Message)); } } } private static void OnConfigFileRenamed(object sender, RenamedEventArgs e) { if (!e.Name.EndsWith(".yaml", StringComparison.OrdinalIgnoreCase) && !e.Name.EndsWith(".yml", StringComparison.OrdinalIgnoreCase)) { return; } DateTime now = DateTime.Now; if (now.Ticks - _lastReloadTime.Ticks < 10000000) { return; } lock (_reloadLock) { try { Debug.Log((object)("[VBDiving] Config file renamed: " + e.OldName + " -> " + e.Name + ". Reloading all configs...")); if ((Object)(object)ZNet.instance != (Object)null && ZNet.instance.IsServer()) { ReloadAndResyncConfigs(); } else { LoadAllMonsterDiveConfigs(); } _lastReloadTime = now; } catch (Exception ex) { Debug.LogError((object)("[VBDiving] Error reloading monster configs: " + ex.Message)); } } } private static string BuildDefaultMonsterDiveYaml() { StringBuilder stringBuilder = new StringBuilder(); stringBuilder.AppendLine("# Monster dive configuration for VBDiving"); stringBuilder.AppendLine("# You can create multiple .yaml files in this folder"); stringBuilder.AppendLine("# Files are loaded in alphabetical order, later files will NOT override earlier ones"); stringBuilder.AppendLine(); stringBuilder.AppendLine("# Параметры глубины:"); stringBuilder.AppendLine("# min_depth - минимальная глубина (у поверхности)"); stringBuilder.AppendLine("# center_depth - предпочтительная/центральная глубина (в пассивном режиме)"); stringBuilder.AppendLine("# max_passive_depth - максимальная глубина в пассивном режиме"); stringBuilder.AppendLine("# max_agro_depth - максимальная глубина в агрессивном режиме (абсолютный предел)"); stringBuilder.AppendLine(); stringBuilder.AppendLine("# Surface patrol group (патрулирует у поверхности)"); stringBuilder.AppendLine("surface_patrol:"); stringBuilder.AppendLine(" min_depth: 1"); stringBuilder.AppendLine(" center_depth: 2"); stringBuilder.AppendLine(" max_passive_depth: 3 # В спокойствии не глубже 3м"); stringBuilder.AppendLine(" max_agro_depth: 15 # В бою может нырнуть до 10м"); stringBuilder.AppendLine(" depth_adjust_speed: 2"); stringBuilder.AppendLine(" use_breath: true"); stringBuilder.AppendLine(" max_breath_seconds: 60"); stringBuilder.AppendLine(" breath_recovery_speed: 2"); stringBuilder.AppendLine(" surface_time: 3"); stringBuilder.AppendLine(" surface_threshold_percent: 0.33"); stringBuilder.AppendLine(" prefabs:"); stringBuilder.AppendLine(" - Leech"); stringBuilder.AppendLine(); stringBuilder.AppendLine("# Deep hunters (охотники глубин)"); stringBuilder.AppendLine("deep_hunters:"); stringBuilder.AppendLine(" min_depth: 1"); stringBuilder.AppendLine(" center_depth: 5"); stringBuilder.AppendLine(" max_passive_depth: 20 # В спокойствии между 1-20м"); stringBuilder.AppendLine(" max_agro_depth: 50 # В бою может уйти до 50м"); stringBuilder.AppendLine(" depth_adjust_speed: 5"); stringBuilder.AppendLine(" use_breath: true"); stringBuilder.AppendLine(" max_breath_seconds: 120"); stringBuilder.AppendLine(" breath_recovery_speed: 1.5"); stringBuilder.AppendLine(" surface_time: 5"); stringBuilder.AppendLine(" surface_threshold_percent: 0.25"); stringBuilder.AppendLine(" prefabs:"); stringBuilder.AppendLine(" - Serpent"); stringBuilder.AppendLine(" - BonemawSerpent"); stringBuilder.AppendLine(); stringBuilder.AppendLine("# Water creatures without breath (водные без дыхания)"); stringBuilder.AppendLine("water_creatures:"); stringBuilder.AppendLine(" min_depth: 1"); stringBuilder.AppendLine(" center_depth: 5"); stringBuilder.AppendLine(" max_passive_depth: 5 # В спокойствии у поверхности"); stringBuilder.AppendLine(" max_agro_depth: 15"); stringBuilder.AppendLine(" depth_adjust_speed: 3"); stringBuilder.AppendLine(" use_breath: false"); stringBuilder.AppendLine(" prefabs:"); stringBuilder.AppendLine(" - Fish1"); stringBuilder.AppendLine(" - Fish2"); stringBuilder.AppendLine(" - Fish3"); stringBuilder.AppendLine(" - Fish4"); stringBuilder.AppendLine(" - Fish5"); stringBuilder.AppendLine(" - Fish6"); stringBuilder.AppendLine(" - Fish7"); stringBuilder.AppendLine(" - Fish8"); stringBuilder.AppendLine(" - Fish9"); stringBuilder.AppendLine(" - Fish10"); stringBuilder.AppendLine(" - Fish11"); stringBuilder.AppendLine(" - Fish12"); stringBuilder.AppendLine(); return stringBuilder.ToString(); } private static void ClearRuntimeCaches() { RouteCache.Clear(); SteerCache.Clear(); } private static Vector3Int ToCacheBucket(Vector3 value) { //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_0014: Unknown result type (might be due to invalid IL or missing references) //IL_0021: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Unknown result type (might be due to invalid IL or missing references) //IL_0033: Unknown result type (might be due to invalid IL or missing references) //IL_0036: Unknown result type (might be due to invalid IL or missing references) float num = 1f; return new Vector3Int(Mathf.RoundToInt(value.x / num), Mathf.RoundToInt(value.y / num), Mathf.RoundToInt(value.z / num)); } private static void TrimCachesIfNeeded() { if (RouteCache.Count > 2048) { RouteCache.Clear(); } if (SteerCache.Count > 2048) { SteerCache.Clear(); } } private static bool TryGetConfiguredDiveProfile(MonsterAI monsterAI, out ConfiguredDiveProfile profile) { if (!Object.op_Implicit((Object)(object)monsterAI)) { profile = default(ConfiguredDiveProfile); return false; } string prefabName = Utils.GetPrefabName(((Component)monsterAI).gameObject); return _configuredDiveProfilesByPrefabName.TryGetValue(prefabName, out profile); } public static bool IsConfiguredMonster(MonsterAI monsterAI) { ConfiguredDiveProfile profile; return TryGetConfiguredDiveProfile(monsterAI, out profile); } public static bool ShouldUseWaterDiveMode(MonsterAI monsterAI) { Character character = ((BaseAI)monsterAI).m_character; return Object.op_Implicit((Object)(object)character) && character.InWater() && character.InLiquidDepth() > 0.05f; } private static bool IsPassiveDiveState(MonsterAI monsterAI) { return !((BaseAI)monsterAI).IsAlerted() && !Object.op_Implicit((Object)(object)monsterAI.m_targetCreature) && !Object.op_Implicit((Object)(object)monsterAI.m_targetStatic); } private static float GetPassiveDesiredDepth(MonsterAI monsterAI, PassiveDepthProfile profile) { int num = Mathf.Abs(((Object)monsterAI).GetInstanceID()); float num2 = Time.time + (float)(num % 997) * 0.173f; float num3 = Mathf.Sin(Mathf.Repeat(num2, 12f) / 12f * (float)Math.PI * 2f); float num4 = Mathf.Max(0f, profile.MaxPassiveDepth - profile.CenterDepth); float num5 = Mathf.Max(0f, profile.CenterDepth - profile.MinDepth); float num6 = ((!(num3 >= 0f)) ? (profile.CenterDepth + num3 * num5) : (profile.CenterDepth + num3 * num4)); return Mathf.Clamp(num6, profile.MinDepth, profile.MaxPassiveDepth); } public static void EnsureDiveFlags(MonsterAI monsterAI) { int instanceID = ((Object)monsterAI).GetInstanceID(); if (!OriginalDiveFlagsByInstance.ContainsKey(instanceID)) { Character character = ((BaseAI)monsterAI).m_character; OriginalDiveFlagsByInstance[instanceID] = new OriginalDiveFlags(monsterAI, ((BaseAI)monsterAI).m_avoidWater, Object.op_Implicit((Object)(object)character) && character.m_canSwim); if (OriginalDiveFlagsByInstance.Count > 2048) { List<int> list = OriginalDiveFlagsByInstance.Keys.Where((int k) => !Object.op_Implicit((Object)(object)OriginalDiveFlagsByInstance[k].MonsterAI)).ToList(); foreach (int item in list) { OriginalDiveFlagsByInstance.Remove(item); } } } ((BaseAI)monsterAI).m_avoidWater = false; if (Object.op_Implicit((Object)(object)((BaseAI)monsterAI).m_character)) { ((BaseAI)monsterAI).m_character.m_canSwim = true; } } public static Vector3 BuildSteerDirectionWithAvoidance(BaseAI ai, Character character, Vector3 targetPoint) { //IL_000e: Unknown result type (might be due to invalid IL or missing references) //IL_0013: Unknown result type (might be due to invalid IL or missing references) //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_001a: Unknown result type (might be due to invalid IL or missing references) //IL_001f: Unknown result type (might be due to invalid IL or missing references) //IL_0047: Unknown result type (might be due to invalid IL or missing references) //IL_004c: Unknown result type (might be due to invalid IL or missing references) //IL_0078: Unknown result type (might be due to invalid IL or missing references) //IL_007f: Unknown result type (might be due to invalid IL or missing references) //IL_0084: Unknown result type (might be due to invalid IL or missing references) //IL_0089: Unknown result type (might be due to invalid IL or missing references) //IL_006c: Unknown result type (might be due to invalid IL or missing references) //IL_0071: Unknown result type (might be due to invalid IL or missing references) //IL_0056: Unknown result type (might be due to invalid IL or missing references) //IL_005b: Unknown result type (might be due to invalid IL or missing references) //IL_00b8: Unknown result type (might be due to invalid IL or missing references) //IL_00c4: Unknown result type (might be due to invalid IL or missing references) //IL_00d8: Unknown result type (might be due to invalid IL or missing references) //IL_00df: Unknown result type (might be due to invalid IL or missing references) //IL_00a2: Unknown result type (might be due to invalid IL or missing references) //IL_00a7: Unknown result type (might be due to invalid IL or missing references) //IL_023d: Unknown result type (might be due to invalid IL or missing references) //IL_0228: Unknown result type (might be due to invalid IL or missing references) //IL_0229: Unknown result type (might be due to invalid IL or missing references) //IL_022a: Unknown result type (might be due to invalid IL or missing references) //IL_0237: Unknown result type (might be due to invalid IL or missing references) //IL_0239: Unknown result type (might be due to invalid IL or missing references) //IL_011d: Unknown result type (might be due to invalid IL or missing references) //IL_011f: Unknown result type (might be due to invalid IL or missing references) //IL_0147: Unknown result type (might be due to invalid IL or missing references) //IL_014c: Unknown result type (might be due to invalid IL or missing references) //IL_014e: Unknown result type (might be due to invalid IL or missing references) //IL_0153: Unknown result type (might be due to invalid IL or missing references) //IL_0156: Unknown result type (might be due to invalid IL or missing references) //IL_01d4: Unknown result type (might be due to invalid IL or missing references) //IL_01db: Unknown result type (might be due to invalid IL or missing references) //IL_01e2: Unknown result type (might be due to invalid IL or missing references) //IL_01e9: Unknown result type (might be due to invalid IL or missing references) //IL_01ee: Unknown result type (might be due to invalid IL or missing references) //IL_01f2: Unknown result type (might be due to invalid IL or missing references) //IL_01f7: Unknown result type (might be due to invalid IL or missing references) //IL_0206: Unknown result type (might be due to invalid IL or missing references) //IL_0207: Unknown result type (might be due to invalid IL or missing references) //IL_0208: Unknown result type (might be due to invalid IL or missing references) //IL_0215: Unknown result type (might be due to invalid IL or missing references) //IL_0217: Unknown result type (might be due to invalid IL or missing references) //IL_017a: Unknown result type (might be due to invalid IL or missing references) //IL_017f: Unknown result type (might be due to invalid IL or missing references) //IL_01b4: Unknown result type (might be due to invalid IL or missing references) //IL_01b6: Unknown result type (might be due to invalid IL or missing references) int instanceID = ((Object)ai).GetInstanceID(); Vector3Int val = ToCacheBucket(((Component)ai).transform.position); Vector3Int val2 = ToCacheBucket(targetPoint); float time = Time.time; if (SteerCache.TryGetValue(instanceID, out var value) && time - value.Time <= 0.5f && value.PositionBucket == val && value.TargetBucket == val2) { return value.Direction; } Vector3 val3 = targetPoint - ((Component)ai).transform.position; if (((Vector3)(ref val3)).sqrMagnitude <= 0.0001f) { return Vector3.zero; } ((Vector3)(ref val3)).Normalize(); Vector3 val4 = default(Vector3); ((Vector3)(ref val4))..ctor(val3.x, 0f, val3.z); float radius = character.GetRadius(); float num = Mathf.Clamp(Utils.DistanceXZ(targetPoint, ((Component)ai).transform.position), radius + 1f, 6f); if (((Vector3)(ref val4)).sqrMagnitude > 0.0001f) { ((Vector3)(ref val4)).Normalize(); Vector3 val5 = val4; float num2 = float.NegativeInfinity; for (int i = 0; i < SteerAngles.Length; i++) { float num3 = SteerAngles[i]; Vector3 val6 = Quaternion.Euler(0f, num3, 0f) * val4; float num4 = ((!ai.CanMove(val6, radius, num)) ? (ai.Raycast(character.GetCenterPoint(), val6, num * 2f, 0.1f) - Mathf.Abs(num3) * 0.01f) : (1000f - Mathf.Abs(num3))); if (num4 > num2) { num2 = num4; val5 = val6; } } Vector3 val7 = new Vector3(val5.x, val3.y, val5.z); Vector3 normalized = ((Vector3)(ref val7)).normalized; TrimCachesIfNeeded(); SteerCache[instanceID] = new SteerCacheEntry(time, val, val2, normalized); return normalized; } TrimCachesIfNeeded(); SteerCache[instanceID] = new SteerCacheEntry(time, val, val2, val3); return val3; } public static bool HasReasonableUnderwaterRoute(BaseAI ai, Character character, Vector3 targetPoint) { //IL_000e: Unknown result type (might be due to invalid IL or missing references) //IL_0013: Unknown result type (might be due to invalid IL or missing references) //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_001a: Unknown result type (might be due to invalid IL or missing references) //IL_001f: Unknown result type (might be due to invalid IL or missing references) //IL_0047: Unknown result type (might be due to invalid IL or missing references) //IL_004c: Unknown result type (might be due to invalid IL or missing references) //IL_0078: Unknown result type (might be due to invalid IL or missing references) //IL_007f: Unknown result type (might be due to invalid IL or missing references) //IL_0056: Unknown result type (might be due to invalid IL or missing references) //IL_005b: Unknown result type (might be due to invalid IL or missing references) //IL_00c6: Unknown result type (might be due to invalid IL or missing references) //IL_00cd: Unknown result type (might be due to invalid IL or missing references) //IL_00d2: Unknown result type (might be due to invalid IL or missing references) //IL_00d7: Unknown result type (might be due to invalid IL or missing references) //IL_00db: Unknown result type (might be due to invalid IL or missing references) //IL_00e7: Unknown result type (might be due to invalid IL or missing references) //IL_00b0: Unknown result type (might be due to invalid IL or missing references) //IL_00b1: Unknown result type (might be due to invalid IL or missing references) //IL_0112: Unknown result type (might be due to invalid IL or missing references) //IL_0113: Unknown result type (might be due to invalid IL or missing references) //IL_015e: Unknown result type (might be due to invalid IL or missing references) //IL_0163: Unknown result type (might be due to invalid IL or missing references) //IL_0165: Unknown result type (might be due to invalid IL or missing references) //IL_016a: Unknown result type (might be due to invalid IL or missing references) //IL_016e: Unknown result type (might be due to invalid IL or missing references) //IL_0173: Unknown result type (might be due to invalid IL or missing references) //IL_01ce: Unknown result type (might be due to invalid IL or missing references) //IL_01cf: Unknown result type (might be due to invalid IL or missing references) //IL_019c: Unknown result type (might be due to invalid IL or missing references) //IL_019d: Unknown result type (might be due to invalid IL or missing references) int instanceID = ((Object)ai).GetInstanceID(); Vector3Int val = ToCacheBucket(((Component)ai).transform.position); Vector3Int val2 = ToCacheBucket(targetPoint); float time = Time.time; if (RouteCache.TryGetValue(instanceID, out var value) && time - value.Time <= 1f && value.PositionBucket == val && value.TargetBucket == val2) { return value.Result; } float num = Utils.DistanceXZ(targetPoint, ((Component)ai).transform.position); float radius = character.GetRadius(); if (num <= radius + 0.6f) { RouteCache[instanceID] = new RouteCacheEntry(time, val, val2, result: true); return true; } Vector3 val3 = targetPoint - ((Component)ai).transform.position; Vector3 val4 = default(Vector3); ((Vector3)(ref val4))..ctor(val3.x, 0f, val3.z); if (((Vector3)(ref val4)).sqrMagnitude <= 0.0001f) { RouteCache[instanceID] = new RouteCacheEntry(time, val, val2, result: true); return true; } ((Vector3)(ref val4)).Normalize(); float num2 = Mathf.Clamp(num, radius + 1f, 6f); for (int i = 0; i < RouteAngles.Length; i++) { Vector3 val5 = Quaternion.Euler(0f, RouteAngles[i], 0f) * val4; if (ai.Raycast(character.GetCenterPoint(), val5, num2, 0.1f) >= num2 * 0.9f) { RouteCache[instanceID] = new RouteCacheEntry(time, val, val2, result: true); return true; } } RouteCache[instanceID] = new RouteCacheEntry(time, val, val2, result: false); return false; } public static void UpdateMonsterBreath(MonsterAI monsterAI, Character character, float dt) { if (!IsConfiguredMonster(monsterAI) || !TryGetConfiguredDiveProfile(monsterAI, out var profile) || !profile.UseBreath) { return; } MonsterSwimState monsterSwimState = MonsterSwimStateManager.Get(monsterAI); if (monsterSwimState.MaxBreath <= 0f) { monsterSwimState.MaxBreath = profile.MaxBreathSeconds; monsterSwimState.Breath = monsterSwimState.MaxBreath; } bool flag = IsMonsterUnderwater(monsterAI, character); if (!flag && character.IsOnGround() && character.InWater()) { flag = true; } if (flag) { monsterSwimState.Breath -= dt; monsterSwimState.SurfaceTimer = 0f; if (monsterSwimState.Breath < 0f) { monsterSwimState.Breath = 0f; monsterSwimState.IsSurfacing = true; } float num = monsterSwimState.Breath / monsterSwimState.MaxBreath; if (num <= profile.SurfaceThresholdPercent) { monsterSwimState.IsSurfacing = true; } } else { monsterSwimState.Breath += dt * profile.BreathRecoverySpeed; monsterSwimState.SurfaceTimer += dt; if (monsterSwimState.Breath >= monsterSwimState.MaxBreath) { monsterSwimState.Breath = monsterSwimState.MaxBreath; if (monsterSwimState.SurfaceTimer >= profile.SurfaceTime) { monsterSwimState.IsSurfacing = false; } } } monsterSwimState.WasUnderwater = flag; } public static bool IsMonsterUnderwater(MonsterAI monsterAI, Character character) { //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_0023: Unknown result type (might be due to invalid IL or missing references) //IL_002b: Unknown result type (might be due to invalid IL or missing references) if (!Object.op_Implicit((Object)(object)character) || !Object.op_Implicit((Object)(object)monsterAI)) { return false; } Vector3 headPoint = character.GetHeadPoint(); float liquidLevel = character.GetLiquidLevel(); return headPoint.y < liquidLevel - 0.1f; } public static float UpdateSwimDepthTowardsTarget(MonsterAI monsterAI, Character character, Vector3 point, float dt) { //IL_00eb: Unknown result type (might be due to invalid IL or missing references) //IL_00a0: Unknown result type (might be due to invalid IL or missing references) TryGetConfiguredDiveProfile(monsterAI, out var profile); float liquidLevel = character.GetLiquidLevel(); float num = 2f; bool flag = ((BaseAI)monsterAI).IsAlerted() || Object.op_Implicit((Object)(object)monsterAI.m_targetCreature) || Object.op_Implicit((Object)(object)monsterAI.m_targetStatic); float num2 = (flag ? profile.DepthProfile.MaxAgroDepth : profile.DepthProfile.MaxPassiveDepth); MonsterSwimState monsterSwimState = null; float num3; if (profile.UseBreath) { monsterSwimState = MonsterSwimStateManager.Get(monsterAI); if (monsterSwimState.IsSurfacing) { num3 = 0.5f; num = profile.ActiveDepthAdjustSpeed * 1.5f; } else if (flag) { float num4 = liquidLevel - point.y; num3 = Mathf.Clamp(num4, profile.DepthProfile.MinDepth + 0.25f, num2); num = profile.ActiveDepthAdjustSpeed; } else { num3 = GetPassiveDesiredDepth(monsterAI, profile.DepthProfile); } } else if (flag) { float num5 = liquidLevel - point.y; num3 = Mathf.Clamp(num5, profile.DepthProfile.MinDepth + 0.25f, num2); num = profile.ActiveDepthAdjustSpeed; } else { num3 = GetPassiveDesiredDepth(monsterAI, profile.DepthProfile); } if (num <= 0f) { character.m_swimDepth = num3; return liquidLevel - num3; } character.m_swimDepth = Mathf.MoveTowards(character.m_swimDepth, num3, num * Mathf.Max(dt, 0.01f)); return liquidLevel - num3; } public static string GetSerializedConfigs() { lock (MonsterDiveConfigLock) { Debug.Log((object)$"[MonsterDiveSystem] GetSerializedConfigs: {_configuredDiveProfilesByPrefabName.Count} profiles found"); if (_configuredDiveProfilesByPrefabName.Count == 0) { Debug.LogWarning((object)"[MonsterDiveSystem] No profiles to serialize!"); return ""; } StringBuilder stringBuilder = new StringBuilder(); foreach (KeyValuePair<string, ConfiguredDiveProfile> item in _configuredDiveProfilesByPrefabName) { string key = item.Key; ConfiguredDiveProfile value = item.Value; stringBuilder.Append(key); stringBuilder.Append('|'); stringBuilder.Append(value.GroupName); stringBuilder.Append('|'); stringBuilder.Append(value.DepthProfile.MinDepth); stringBuilder.Append('|'); stringBuilder.Append(value.DepthProfile.CenterDepth); stringBuilder.Append('|'); stringBuilder.Append(value.DepthProfile.MaxPassiveDepth); stringBuilder.Append('|'); stringBuilder.Append(value.DepthProfile.MaxAgroDepth); stringBuilder.Append('|'); stringBuilder.Append(value.ActiveDepthAdjustSpeed); stringBuilder.Append('|'); stringBuilder.Append(value.UseBreath ? "1" : "0"); stringBuilder.Append('|'); stringBuilder.Append(value.MaxBreathSeconds); stringBuilder.Append('|'); stringBuilder.Append(value.BreathRecoverySpeed); stringBuilder.Append('|'); stringBuilder.Append(value.SurfaceTime); stringBuilder.Append('|'); stringBuilder.Append(value.SurfaceThresholdPercent); stringBuilder.Append('\n'); Debug.Log((object)$"[MonsterDiveSystem] Serialized: {key} -> {value.GroupName} (passive max: {value.DepthProfile.MaxPassiveDepth}, agro max: {value.DepthProfile.MaxAgroDepth})"); } string text = stringBuilder.ToString(); Debug.Log((object)$"[MonsterDiveSystem] Serialized {_configuredDiveProfilesByPrefabName.Count} prefabs, total length: {text.Length}"); return text; } } public static void LoadSerializedConfigs(string configData, bool useServerOnly = false) { Debug.Log((object)$"[MonsterDiveSystem] LoadSerializedConfigs called, data length: {configData?.Length ?? 0}, useServerOnly: {useServerOnly}"); if (string.IsNullOrEmpty(configData)) { Debug.LogWarning((object)"[MonsterDiveSystem] Empty configData received!"); return; } if (!VBDiving.IsEnabled()) { Debug.LogWarning((object)"[VBDiving] Mod disabled, skipping server config loading"); return; } lock (MonsterDiveConfigLock) { Dictionary<string, ConfiguredDiveProfile> dictionary = new Dictionary<string, ConfiguredDiveProfile>(StringComparer.OrdinalIgnoreCase); string[] array = configData.Split(new char[1] { '\n' }, StringSplitOptions.RemoveEmptyEntries); string[] array2 = array; foreach (string text in array2) { string[] array3 = text.Split(new char[1] { '|' }); if (array3.Length < 12) { Debug.LogWarning((object)$"[MonsterDiveSystem] Invalid line format, expected 12 parts, got {array3.Length}: {text}"); continue; } try { string text2 = array3[0]; string groupName = array3[1]; float minDepth = float.Parse(array3[2]); float centerDepth = float.Parse(array3[3]); float num = float.Parse(array3[4]); float num2 = float.Parse(array3[5]); float activeDepthAdjustSpeed = float.Parse(array3[6]); bool useBreath = array3[7] == "1"; float maxBreathSeconds = float.Parse(array3[8]); float breathRecoverySpeed = float.Parse(array3[9]); float surfaceTime = float.Parse(array3[10]); float surfaceThresholdPercent = float.Parse(array3[11]); PassiveDepthProfile depthProfile = new PassiveDepthProfile(minDepth, centerDepth, num, num2); ConfiguredDiveProfile value = new ConfiguredDiveProfile(groupName, depthProfile, activeDepthAdjustSpeed, useBreath, maxBreathSeconds, breathRecoverySpeed, surfaceTime, surfaceThresholdPercent); dictionary[text2] = value; Debug.Log((object)$"[MonsterDiveSystem] Loaded server config: {text2} -> passive max: {num}, agro max: {num2}"); } catch (Exception ex) { Debug.LogError((object)("[MonsterDiveSystem] Failed to parse config line: " + text + ", error: " + ex.Message)); } } if (dictionary.Count == 0) { Debug.LogWarning((object)"[VBDiving] No valid profiles found in server config data"); return; } if (useServerOnly) { lock (PrefabSetLock) { _configuredDiveProfilesByPrefabName = dictionary; } Debug.Log((object)$"[VBDiving] Loaded {dictionary.Count} monster prefab configurations FROM SERVER ONLY"); } else { lock (PrefabSetLock) { Dictionary<string, ConfiguredDiveProfile> dictionary2 = new Dictionary<string, ConfiguredDiveProfile>(StringComparer.OrdinalIgnoreCase); LoadLocalConfigsToDictionary(dictionary2); foreach (KeyValuePair<string, ConfiguredDiveProfile> item in dictionary) { dictionary2[item.Key] = item.Value; } _configuredDiveProfilesByPrefabName = dictionary2; } Debug.Log((object)$"[VBDiving] Loaded {dictionary.Count} server configs (merged with local, server priority)"); } ClearRuntimeCaches(); } } private static void LoadLocalConfigsToDictionary(Dictionary<string, ConfiguredDiveProfile> targetDict) { if (!Directory.Exists(MonsterDiveConfigFolderPath)) { return; } List<string> list = Directory.GetFiles(MonsterDiveConfigFolderPath, "*.yaml").Concat(Directory.GetFiles(MonsterDiveConfigFolderPath, "*.yml")).ToList(); foreach (string item in list) { try { string text = File.ReadAllText(item); if (string.IsNullOrWhiteSpace(text)) { continue; } MonsterDiveYamlRoot monsterDiveYamlRoot = ParseYamlRoot(text); if (monsterDiveYamlRoot == null) { continue; } foreach (KeyValuePair<string, MonsterDiveYamlGroup> item2 in monsterDiveYamlRoot) { string text2 = item2.Key?.Trim() ?? ""; if (string.IsNullOrEmpty(text2)) { continue; } MonsterDiveYamlGroup monsterDiveYamlGroup = item2.Value ?? new MonsterDiveYamlGroup(); float valueOrDefault = monsterDiveYamlGroup.MinDepth.GetValueOrDefault(); float valueOrDefault2 = monsterDiveYamlGroup.CenterDepth.GetValueOrDefault(); float num; float maxPassiveDepth; if (monsterDiveYamlGroup.MaxAgroDepth.HasValue || monsterDiveYamlGroup.MaxPassiveDepth.HasValue) { num = Mathf.Max(0f, monsterDiveYamlGroup.MaxAgroDepth ?? monsterDiveYamlGroup.MaxDepth ?? 30f); maxPassiveDepth = monsterDiveYamlGroup.MaxPassiveDepth ?? num; } else { num = Mathf.Max(0f, monsterDiveYamlGroup.MaxDepth ?? 30f); maxPassiveDepth = num; } PassiveDepthProfile depthProfile = new PassiveDepthProfile(valueOrDefault, valueOrDefault2, maxPassiveDepth, num); float activeDepthAdjustSpeed = Mathf.Max(0f, monsterDiveYamlGroup.DepthAdjustSpeed ?? 2f); bool valueOrDefault3 = monsterDiveYamlGroup.UseBreath.GetValueOrDefault(); float maxBreathSeconds = Mathf.Max(0f, monsterDiveYamlGroup.MaxBreathSeconds ?? 60f); float breathRecoverySpeed = Mathf.Max(0.1f, monsterDiveYamlGroup.BreathRecoverySpeed ?? 1f); float surfaceTime = Mathf.Max(0f, monsterDiveYamlGroup.SurfaceTime ?? 3f); float surfaceThresholdPercent = Mathf.Clamp01(monsterDiveYamlGroup.SurfaceThresholdPercent ?? 0.33f); ConfiguredDiveProfile value = new ConfiguredDiveProfile(text2, depthProfile, activeDepthAdjustSpeed, valueOrDefault3, maxBreathSeconds, breathRecoverySpeed, surfaceTime, surfaceThresholdPercent); if (monsterDiveYamlGroup.Prefabs == null) { continue; } foreach (string prefab in monsterDiveYamlGroup.Prefabs) { string text3 = prefab?.Trim() ?? ""; if (!string.IsNullOrEmpty(text3)) { targetDict[text3] = value; } } } } catch (Exception ex) { Debug.LogError((object)("[VBDiving] Failed to load local config: " + ex.Message)); } } } private static void NotifyServerConfigsChanged() { if (Object.op_Implicit((Object)(object)ZNet.instance) && ZNet.instance.IsServer()) { VBDiving.OnServerConfigsChanged(); } } public static bool ShouldUseServerConfigs() { if (!Object.op_Implicit((Object)(object)ZNet.instance)) { return false; } if (ZNet.instance.IsServer()) { return false; } return VBDiving.SyncMonsterConfigs?.Value ?? true; } } internal class MonsterSwimState { public float Breath; public float MaxBreath; public bool WasUnderwater; public bool IsSurfacing; public float SurfaceTimer; public bool WasOutOfBreath; public float LastSurfaceTime; public float SuffocationTickTimer; } internal static class MonsterSwimStateManager { private static readonly Dictionary<int, MonsterSwimState> States = new Dictionary<int, MonsterSwimState>(); public static MonsterSwimState Get(MonsterAI monsterAI) { int instanceID = ((Object)monsterAI).GetInstanceID(); if (!States.TryGetValue(instanceID, out var value)) { value = new MonsterSwimState(); States[instanceID] = value; } return value; } public static void Remove(MonsterAI monsterAI) { if (Object.op_Implicit((Object)(object)monsterAI)) { States.Remove(((Object)monsterAI).GetInstanceID()); } } public static void Clear() { States.Clear(); } } } namespace VBDiving.Water { [HarmonyPatch(typeof(WaterVolume), "UpdateMaterials")] internal static class SurfacePatch { private static readonly Dictionary<MeshRenderer, GameObject> UnderwaterCopies = new Dictionary<MeshRenderer, GameObject>(); private const float SurfaceOffset = -0.05f; private const float OverlapScale = 1.02f; private static void Postfix(WaterVolume __instance) { if (!VBDiving.IsEnabled() || !Object.op_Implicit((Object)(object)__instance) || !Object.op_Implicit((Object)(object)__instance.m_waterSurface)) { return; } MeshRenderer component = ((Component)__instance.m_waterSurface).GetComponent<MeshRenderer>(); MeshFilter component2 = ((Component)__instance.m_waterSurface).GetComponent<MeshFilter>(); if (!Object.op_Implicit((Object)(object)component) || !Object.op_Implicit((Object)(object)component2)) { return; } bool flag = WaterHelper.IsCameraUnderwater(); if (!UnderwaterCopies.TryGetValue(component, out var value) || !Object.op_Implicit((Object)(object)value)) { value = CreateUnderwaterSurfaceCopy(((Component)component).gameObject, component, component2); if (Object.op_Implicit((Object)(object)value)) { UnderwaterCopies[component] = value; } } if (Object.op_Implicit((Object)(object)value)) { ((Renderer)component).enabled = !flag; value.SetActive(flag); } } private static GameObject CreateUnderwaterSurfaceCopy(GameObject original, MeshRenderer originalRenderer, MeshFilter originalFilter) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Expected O, but got Unknown //IL_0034: Unknown result type (might be due to invalid IL or missing references) //IL_0054: Unknown result type (might be due to invalid IL or missing references) //IL_0074: Unknown result type (might be due to invalid IL or missing references) GameObject val = new GameObject("VBDiving_UnderwaterSurface"); val.transform.SetParent(original.transform, false); val.transform.localPosition = new Vector3(0f, -0.05f, 0f); val.transform.localRotation = Quaternion.Euler(180f, 0f, 0f); val.transform.localScale = new Vector3(1.02f, 1f, -1.02f); ((Renderer)originalRenderer).shadowCastingMode = (ShadowCastingMode)1; ((Renderer)originalRenderer).receiveShadows = true; MeshFilter val2 = val.AddComponent<MeshFilter>(); val2.sharedMesh = originalFilter.sharedMesh; MeshRenderer val3 = val.AddComponent<MeshRenderer>(); ((Renderer)val3).sharedMaterial = ((Renderer)originalRenderer).sharedMaterial; ((Renderer)val3).shadowCastingMode = (ShadowCastingMode)1; ((Renderer)val3).receiveShadows = true; ((Renderer)val3).lightProbeUsage = (LightProbeUsage)1; ((Renderer)val3).reflectionProbeUsage = (ReflectionProbeUsage)0; ((Renderer)val3).allowOcclusionWhenDynamic = false; ((Renderer)val3).forceRenderingOff = false; ((Renderer)val3).enabled = true; val.SetActive(false); return val; } } [HarmonyPatch(typeof(WaterVolume), "UpdateMaterials")] internal static class WaterShaderPatch { private static readonly int ColorTopId = Shader.PropertyToID("_ColorTop"); private static readonly int ColorBottomId = Shader.PropertyToID("_ColorBottom"); private static readonly int ColorBottomShallowId = Shader.PropertyToID("_ColorBottomShallow"); private static readonly int SurfaceColorId = Shader.PropertyToID("_SurfaceColor"); private static readonly int DepthFadeId = Shader.PropertyToID("_DepthFade"); private static Color _originalColorTop; private static Color _originalColorBottom; private static Color _originalColorBottomShallow; private static Color _originalSurfaceColor; private static float _originalDepthFade; private static bool _originalValuesSaved; private static Material _instanceMaterial; private static MeshRenderer _lastRenderer; private static void Prefix(WaterVolume __instance) { if (VBDiving.IsEnabled() && Object.op_Implicit((Object)(object)__instance.m_waterSurface)) { MeshRenderer waterSurface = __instance.m_waterSurface; if (!Object.op_Implicit((Object)(object)_instanceMaterial) || (Object)(object)_lastRenderer != (Object)(object)waterSurface) { _instanceMaterial = ((Renderer)waterSurface).material; _lastRenderer = waterSurface; SaveOriginalValues(_instanceMaterial); } if (WaterHelper.IsCameraUnderwater()) { ApplyUnderwaterSettings(_instanceMaterial); } else { ApplyWaterSettings(_instanceMaterial); } } } private static void SaveOriginalValues(Material mat) { //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_0029: Unknown result type (might be due to invalid IL or missing references) //IL_0043: Unknown result type (might be due to invalid IL or missing references) //IL_0048: Unknown result type (might be due to invalid IL or missing references) //IL_0062: Unknown result type (might be due to invalid IL or missing references) //IL_0067: Unknown result type (might be due to invalid IL or missing references) //IL_0083: Unknown result type (might be due to invalid IL or missing references) //IL_0088: Unknown result type (might be due to invalid IL or missing references) if (!_originalValuesSaved) { if (mat.HasProperty(ColorTopId)) { _originalColorTop = mat.GetColor(ColorTopId); } if (mat.HasProperty(ColorBottomId)) { _o