Please disclose if your mod was created primarily 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 UnderTheSea v0.1.1
UnderTheSea.dll
Decompiled a year agousing System; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Reflection; using System.Reflection.Emit; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.Versioning; using System.Security; using System.Security.Permissions; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using Configs; using HarmonyLib; using Jotunn.Extensions; using Jotunn.Utils; using Logging; using Microsoft.CodeAnalysis; using UnityEngine; using UnityEngine.Rendering; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: AssemblyTitle("UnderTheSea")] [assembly: AssemblyDescription("")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("")] [assembly: AssemblyProduct("UnderTheSea")] [assembly: AssemblyCopyright("Copyright © 2024")] [assembly: AssemblyTrademark("")] [assembly: ComVisible(false)] [assembly: Guid("08a6f7d7-cf93-4931-aecd-abf2ce6ed34c")] [assembly: AssemblyFileVersion("0.1.1")] [assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("0.1.1.0")] [module: UnverifiableCode] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)] internal sealed class RefSafetyRulesAttribute : Attribute { public readonly int Version; public RefSafetyRulesAttribute(int P_0) { Version = P_0; } } } namespace Logging { internal static class Log { internal enum InfoLevel { Low, Medium, High } private static ManualLogSource logSource; internal static ConfigEntry<InfoLevel> Verbosity { get; set; } internal static InfoLevel VerbosityLevel => Verbosity.Value; internal static bool IsVerbosityLow => Verbosity.Value >= InfoLevel.Low; internal static bool IsVerbosityMedium => Verbosity.Value >= InfoLevel.Medium; internal static bool IsVerbosityHigh => Verbosity.Value >= InfoLevel.High; internal static void Init(ManualLogSource logSource) { Log.logSource = logSource; } internal static void LogDebug(object data) { logSource.LogDebug(data); } internal static void LogError(object data) { logSource.LogError(data); } internal static void LogFatal(object data) { logSource.LogFatal(data); } internal static void LogMessage(object data) { logSource.LogMessage(data); } internal static void LogWarning(object data) { logSource.LogWarning(data); } internal static void LogInfo(object data, InfoLevel level = InfoLevel.Low) { if (Verbosity == null || VerbosityLevel >= level) { logSource.LogInfo(data); } } internal static void LogGameObject(GameObject prefab, bool includeChildren = false) { //IL_006b: Unknown result type (might be due to invalid IL or missing references) //IL_0071: Expected O, but got Unknown LogInfo("***** " + ((Object)prefab).name + " *****"); Component[] components = prefab.GetComponents<Component>(); for (int i = 0; i < components.Length; i++) { LogComponent(components[i]); } if (!includeChildren) { return; } LogInfo("***** " + ((Object)prefab).name + " (children) *****"); foreach (Transform item in prefab.transform) { Transform val = item; if (Object.op_Implicit((Object)(object)val)) { LogInfo(" - " + ((Object)val).name); components = ((Component)val).GetComponents<Component>(); for (int i = 0; i < components.Length; i++) { LogComponent(components[i]); } } } } internal static void LogComponent(Component compo) { if (!Object.op_Implicit((Object)(object)compo)) { return; } try { LogInfo("--- " + ((object)compo).GetType().Name + ": " + ((Object)compo).name + " ---"); } catch (Exception ex) { LogError(ex.ToString()); LogWarning("Could not get type name for component!"); return; } try { foreach (PropertyInfo declaredProperty in AccessTools.GetDeclaredProperties(((object)compo).GetType())) { try { LogInfo($" - {declaredProperty.Name} = {declaredProperty.GetValue(compo)}"); } catch (Exception ex2) { LogError(ex2.ToString()); LogWarning("Could not get property: " + declaredProperty.Name + " for component!"); } } } catch (Exception ex3) { LogError(ex3.ToString()); LogWarning("Could not get properties for component!"); } try { foreach (FieldInfo declaredField in AccessTools.GetDeclaredFields(((object)compo).GetType())) { try { LogInfo($" - {declaredField.Name} = {declaredField.GetValue(compo)}"); } catch (Exception ex4) { LogError(ex4.ToString()); LogWarning("Could not get field: " + declaredField.Name + " for component!"); } } } catch (Exception ex5) { LogError(ex5.ToString()); LogWarning("Could not get fields for component!"); } } } } namespace UnderTheSea { internal class Diver : MonoBehaviour { public enum DiveDirection { NEUTRAL, UP, DOWN } private const float Tol = 0.01f; private static readonly Dictionary<Player, Diver> Divers = new Dictionary<Player, Diver>(); private Vector3 LastDiveDirection = Vector3.zero; public Player player; public const float DefaultSwimDepth = 1.4f; public const float DivingSwimDepth = 2.5f; public float BaseSwimSpeed { get; private set; } public float RestingStaminaRegenDelay => (0f - UnderTheSea.Instance.RestingStaminaRegenDelay.Value) * player.m_staminaRegenDelay; public float RestingStaminaRegenRate => UnderTheSea.Instance.RestingStaminaRegenRate.Value * player.m_staminaRegen; public void Awake() { player = ((Component)this).GetComponent<Player>(); ((Character)player).m_swimDepth = 1.4f; BaseSwimSpeed = ((Character)player).m_swimSpeed; Divers.Add(player, this); } public void ResetSwimDepthIfNotInWater() { if (!((Character)player).InWater()) { ResetSwimDepthToDefault(); } } public void ResetSwimDepthToDefault() { ((Character)player).m_swimDepth = 1.4f; } public bool CanDive() { //IL_003a: Unknown result type (might be due to invalid IL or missing references) //IL_0055: Unknown result type (might be due to invalid IL or missing references) if (!((Character)player).InWater() || ((Character)player).IsOnGround() || !((Character)player).IsSwimming()) { return false; } float num = default(float); Vector3 val = default(Vector3); if (((Character)player).GetGroundHeight(((Component)player).transform.position, ref num, ref val) && ((Component)player).transform.position.y - num < 1f) { return false; } return true; } public bool IsInsideLiquid() { //IL_001b: Unknown result type (might be due to invalid IL or missing references) return Mathf.Max(0f, ((Character)player).GetLiquidLevel() - ((Component)player).transform.position.y) > 1.4f; } public bool IsUnderSurface() { return ((Character)player).m_swimDepth > 1.4f; } public bool IsDiving() { return ((Character)player).m_swimDepth > 2.5f; } public bool IsSurfacing() { if (!IsDiving()) { return IsUnderSurface(); } return false; } public bool IsRestingInWater() { //IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_0020: Unknown result type (might be due to invalid IL or missing references) if (!IsDiving() && ((Character)player).IsSwimming()) { Vector3 velocity = ((Character)player).GetVelocity(); return ((Vector3)(ref velocity)).magnitude < 1f; } return false; } public void RegenRestingStamina(float dt) { Player obj = player; obj.m_staminaRegenTimer -= dt; if (player.GetStamina() < ((Character)player).GetMaxStamina() && player.m_staminaRegenTimer <= RestingStaminaRegenDelay) { float skillFactor = player.m_skills.GetSkillFactor((SkillType)103); float num = (1f + skillFactor) * RestingStaminaRegenRate; player.m_stamina = Mathf.Min(((Character)player).GetMaxStamina(), player.m_stamina + num * dt * Game.m_staminaRegenRate); } } public void DrainDivingStamina(float dt) { float skillFactor = player.m_skills.GetSkillFactor((SkillType)103); float num = Mathf.Lerp(player.m_swimStaminaDrainMinSkill, player.m_swimStaminaDrainMaxSkill, skillFactor); num += num * ((Character)player).GetEquipmentSwimStaminaModifier(); ((Character)player).m_seman.ModifySwimStaminaUsage(num, ref num, true); ((Character)player).UseStamina(dt * num * Game.m_moveStaminaRate * UnderTheSea.Instance.UnderwaterRestingStaminaDrainRate.Value); } public void UpdateSwimSkill(float dt) { Player obj = player; obj.m_swimSkillImproveTimer += dt; if (player.m_swimSkillImproveTimer > 1f) { player.m_swimSkillImproveTimer = 0f; ((Character)player).RaiseSkill((SkillType)103, 1f); } } public void UpdateSwimSpeed(float dt) { float num = (ZInput.GetButton("Run") ? dt : (0f - dt)); float num2 = ((Character)player).m_swimSpeed + ((Character)player).m_swimAcceleration * num; ((Character)player).m_swimSpeed = Mathf.Clamp(num2, BaseSwimSpeed, UnderTheSea.Instance.MaxSwimSpeed.Value); } public void Dive(float dt, bool ascend, out Vector3? defaultMoveDir) { //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_0023: Unknown result type (might be due to invalid IL or missing references) //IL_0029: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Unknown result type (might be due to invalid IL or missing references) //IL_003a: Unknown result type (might be due to invalid IL or missing references) defaultMoveDir = ((Character)player).m_moveDir; ((Character)player).m_moveDir = GetDiveDirection(ascend); Vector3 val = CalculateSwimVelocity(); float num = ((Character)player).m_swimDepth - val.y * dt; ((Character)player).m_swimDepth = Mathf.Max(num, 1.4f); } public Vector3 GetDiveDirection(bool ascend) { //IL_000a: Unknown result type (might be due to invalid IL or missing references) //IL_0003: Unknown result type (might be due to invalid IL or missing references) //IL_000f: Unknown result type (might be due to invalid IL or missing references) //IL_0016: Unknown result type (might be due to invalid IL or missing references) //IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_004a: Unknown result type (might be due to invalid IL or missing references) //IL_004b: Unknown result type (might be due to invalid IL or missing references) //IL_004c: Unknown result type (might be due to invalid IL or missing references) //IL_0051: Unknown result type (might be due to invalid IL or missing references) //IL_0059: Unknown result type (might be due to invalid IL or missing references) //IL_0044: Unknown result type (might be due to invalid IL or missing references) //IL_0049: Unknown result type (might be due to invalid IL or missing references) Vector3 val = (ascend ? Vector3.up : Vector3.down); Vector3 val2 = ((Character)player).m_moveDir; if (((Vector3)(ref val2)).magnitude < 0.1f) { float scale = ((ascend && IsSurfacing()) ? 0.6f : 0.05f); val2 = GetHorizontalLookDir(scale); } Vector3 result = val2 + val; ((Vector3)(ref result)).Normalize(); return result; } private Vector3 GetHorizontalLookDir(float scale = 0.05f) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_001f: Unknown result type (might be due to invalid IL or missing references) //IL_0021: Unknown result type (might be due to invalid IL or missing references) Vector3 lookDir = ((Character)player).m_lookDir; lookDir.y = 0f; ((Vector3)(ref lookDir)).Normalize(); return lookDir * scale; } public Vector3 CalculateSwimVelocity() { //IL_003e: Unknown result type (might be due to invalid IL or missing references) //IL_004e: Unknown result type (might be due to invalid IL or missing references) //IL_0054: Unknown result type (might be due to invalid IL or missing references) //IL_0059: Unknown result type (might be due to invalid IL or missing references) //IL_0060: Unknown result type (might be due to invalid IL or missing references) //IL_0065: Unknown result type (might be due to invalid IL or missing references) //IL_0071: Unknown result type (might be due to invalid IL or missing references) //IL_0076: Unknown result type (might be due to invalid IL or missing references) //IL_0084: Unknown result type (might be due to invalid IL or missing references) float num = ((Character)player).m_swimSpeed * ((Character)player).GetAttackSpeedFactorMovement(); if (((Character)player).InMinorActionSlowdown()) { num = 0f; } ((Character)player).m_seman.ApplyStatusEffectSpeedMods(ref num, ((Character)player).m_moveDir); Vector3 val = ((Character)player).m_moveDir * num; val = Vector3.Lerp(((Character)player).m_currentVel, val, ((Character)player).m_swimAcceleration); ((Character)player).AddPushbackForce(ref val); return val; } } [BepInPlugin("Searica.Valheim.UnderTheSea", "UnderTheSea", "0.1.1")] [BepInDependency("com.jotunn.jotunn", "2.23.2")] [NetworkCompatibility(/*Could not decode attribute arguments.*/)] [SynchronizationMode(/*Could not decode attribute arguments.*/)] [BepInIncompatibility("ch.easy.develope.vh.diving.mod")] [BepInIncompatibility("blacks7ar.VikingsDoSwim")] [BepInIncompatibility("projjm.improvedswimming")] [BepInIncompatibility("MainStreetGaming.BetterDiving")] internal sealed class UnderTheSea : BaseUnityPlugin { public const string PluginName = "UnderTheSea"; internal const string Author = "Searica"; public const string PluginGUID = "Searica.Valheim.UnderTheSea"; public const string PluginVersion = "0.1.1"; internal static UnderTheSea Instance; internal static ConfigFile ConfigFile; internal static ConfigFileWatcher ConfigFileWatcher; internal string CurrentEnvName = string.Empty; internal const string GlobalSection = "Global"; public ConfigEntry<float> RestingStaminaRegenDelay; public ConfigEntry<float> RestingStaminaRegenRate; public ConfigEntry<float> UnderwaterRestingStaminaDrainRate; public ConfigEntry<float> MaxSwimSpeed; public ConfigEntry<float> ColorDarknessFactor; public ConfigEntry<float> FogDensityFactor; public ConfigEntry<float> MinFogDensity; public ConfigEntry<float> MaxFogDensity; public ConfigEntry<bool> UseEquipInWater; public static string EnvName = ""; public void Awake() { Instance = this; ConfigFile = ((BaseUnityPlugin)this).Config; Log.Init(((BaseUnityPlugin)this).Logger); ((BaseUnityPlugin)this).Config.DisableSaveOnConfigSet(); SetUpConfigEntries(); ((BaseUnityPlugin)this).Config.Save(); ((BaseUnityPlugin)this).Config.SaveOnConfigSet = true; Harmony.CreateAndPatchAll(Assembly.GetExecutingAssembly(), "Searica.Valheim.UnderTheSea"); Game.isModded = true; ConfigFileWatcher = new ConfigFileWatcher(((BaseUnityPlugin)this).Config); } internal void SetUpConfigEntries() { UseEquipInWater = ConfigFileExtensions.BindConfigInOrder<bool>(((BaseUnityPlugin)this).Config, "Global", "Use Equipment in Water", true, "Whether you can use equipment while in water.", true, true, true, (AcceptableValueBase)null, (Action<ConfigEntryBase>)null, (ConfigurationManagerAttributes)null); RestingStaminaRegenDelay = ConfigFileExtensions.BindConfigInOrder<float>(((BaseUnityPlugin)this).Config, "Global", "Treading Water Stamina Regen Delay", 2f, "How long before you regenerate stamina when treading water as a mulitple of the default delay while on ground.", true, true, true, (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 5f), (Action<ConfigEntryBase>)null, (ConfigurationManagerAttributes)null); RestingStaminaRegenRate = ConfigFileExtensions.BindConfigInOrder<float>(((BaseUnityPlugin)this).Config, "Global", "Treading Water Stamina Regen Rate", 0.5f, "How fast you regenerate stamina while treading water as a mulitple of the default regen rate while on ground.", true, true, true, (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 1f), (Action<ConfigEntryBase>)null, (ConfigurationManagerAttributes)null); UnderwaterRestingStaminaDrainRate = ConfigFileExtensions.BindConfigInOrder<float>(((BaseUnityPlugin)this).Config, "Global", "Underwater Stamina Drain", 0.5f, "How fast you drain stamina while floating underwater without moving as a multiple of the default swimming drain.", true, true, true, (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 2f), (Action<ConfigEntryBase>)null, (ConfigurationManagerAttributes)null); MaxSwimSpeed = ConfigFileExtensions.BindConfigInOrder<float>(((BaseUnityPlugin)this).Config, "Global", "Max Swim Speed", 3f, "Peak speed when sprinting while swimming.", true, true, true, (AcceptableValueBase)(object)new AcceptableValueRange<float>(2f, 5f), (Action<ConfigEntryBase>)null, (ConfigurationManagerAttributes)null); ColorDarknessFactor = ConfigFileExtensions.BindConfigInOrder<float>(((BaseUnityPlugin)this).Config, "Global", "Color Darkness Factor", 0.08298756f, "How quickly colors become darker as you dive deeper.", false, true, true, (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 1f), (Action<ConfigEntryBase>)null, (ConfigurationManagerAttributes)null); FogDensityFactor = ConfigFileExtensions.BindConfigInOrder<float>(((BaseUnityPlugin)this).Config, "Global", "Fog Density Factor", 0f, "How quickly the fog gets thicker as you dive deeper.", false, true, true, (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 0.5f), (Action<ConfigEntryBase>)null, (ConfigurationManagerAttributes)null); MinFogDensity = ConfigFileExtensions.BindConfigInOrder<float>(((BaseUnityPlugin)this).Config, "Global", "Min Fog Density", 0.06452283f, "Minimum fog density underwater regardless of depth.", false, true, true, (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.05f, 1f), (Action<ConfigEntryBase>)null, (ConfigurationManagerAttributes)null); MaxFogDensity = ConfigFileExtensions.BindConfigInOrder<float>(((BaseUnityPlugin)this).Config, "Global", "Max Fog Density", 1.518672f, "Maximum fog density underwater regardless of depth.", false, true, true, (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 5f), (Action<ConfigEntryBase>)null, (ConfigurationManagerAttributes)null); } public void OnDestroy() { ((BaseUnityPlugin)this).Config.Save(); } public bool IsEnvAllowed() { return EnvMan.instance.GetCurrentEnvironment().m_name != "SunkenCrypt"; } } internal static class Utils { public static bool TryGetDiver(Character character, out Diver diver) { if (!IsValidLocalPlayer(character, out var player)) { diver = null; return false; } return ((Component)player).TryGetComponent<Diver>(ref diver); } public static bool TryGetDiver(Player player, out Diver diver) { if (!IsValidLocalPlayer(player)) { diver = null; return false; } return ((Component)player).TryGetComponent<Diver>(ref diver); } public static bool IsValidLocalPlayer(Character character, out Player player) { if (Object.op_Implicit((Object)(object)character) && character.IsPlayer() && (Object)(object)character == (Object)(object)Player.m_localPlayer) { player = Player.m_localPlayer; return true; } player = null; return false; } public static bool IsValidLocalPlayer(Player player) { if (Object.op_Implicit((Object)(object)player)) { return (Object)(object)player == (Object)(object)Player.m_localPlayer; } return false; } } } namespace UnderTheSea.Patches { [HarmonyPatch] internal static class DivingPatches { private static bool InUpdateSwimming; [HarmonyPostfix] [HarmonyPatch(typeof(Player), "Awake")] private static void Player_Awake_Prefix(Player __instance) { ((Component)__instance).gameObject.AddComponent<Diver>(); } [HarmonyPrefix] [HarmonyPatch(typeof(Character), "UpdateMotion")] private static void Character_UpdateMotion_Prefix(Character __instance) { if (Utils.TryGetDiver(__instance, out var diver) && UnderTheSea.Instance.IsEnvAllowed()) { diver.ResetSwimDepthIfNotInWater(); if (diver.IsUnderSurface() && diver.IsInsideLiquid()) { ((Character)diver.player).m_lastGroundTouch = 0.3f; ((Character)diver.player).m_swimTimer = 0f; } } } [HarmonyPrefix] [HarmonyPatch(typeof(Character), "UpdateSwimming")] public static void UpdateSwimming_Prefix(Character __instance, float dt, out Vector3? __state) { InUpdateSwimming = true; __state = null; if (Utils.TryGetDiver(__instance, out var diver)) { diver.UpdateSwimSpeed(dt); if (ZInput.GetButton("Jump") && diver.IsUnderSurface()) { diver.Dive(dt, ascend: true, out __state); } else if (ZInput.GetButton("Crouch") && diver.CanDive()) { diver.Dive(dt, ascend: false, out __state); } else if ((__instance.IsOnGround() || !diver.IsDiving()) && !diver.IsRestingInWater()) { diver.ResetSwimDepthToDefault(); } } } [HarmonyPostfix] [HarmonyPatch(typeof(Character), "UpdateSwimming")] public static void UpdateSwimming_Postfix(Character __instance, float dt, ref Vector3? __state) { //IL_0010: Unknown result type (might be due to invalid IL or missing references) //IL_0015: Unknown result type (might be due to invalid IL or missing references) InUpdateSwimming = false; if (__state.HasValue) { __instance.m_moveDir = __state.Value; __state = null; } } [HarmonyPrefix] [HarmonyPatch(typeof(Character), "UpdateRotation")] public static void UpdateRotation_Postfix(Character __instance, out Quaternion? __state) { //IL_000e: Unknown result type (might be due to invalid IL or missing references) if (InUpdateSwimming) { __state = ((Component)__instance).transform.rotation; } else { __state = null; } } [HarmonyPostfix] [HarmonyPatch(typeof(Character), "UpdateRotation")] public static void UpdateRotation_Postfix(Character __instance, float turnSpeed, float dt, ref Quaternion? __state) { //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_0073: Unknown result type (might be due to invalid IL or missing references) //IL_0054: Unknown result type (might be due to invalid IL or missing references) //IL_0059: Unknown result type (might be due to invalid IL or missing references) //IL_0078: Unknown result type (might be due to invalid IL or missing references) //IL_008e: Unknown result type (might be due to invalid IL or missing references) //IL_0093: Unknown result type (might be due to invalid IL or missing references) //IL_0097: Unknown result type (might be due to invalid IL or missing references) //IL_0066: Unknown result type (might be due to invalid IL or missing references) //IL_006b: Unknown result type (might be due to invalid IL or missing references) if (InUpdateSwimming && __state.HasValue && Object.op_Implicit((Object)(object)__instance) && !(((Component)__instance).transform.rotation != __state.Value) && Utils.TryGetDiver(__instance, out var diver) && diver.IsUnderSurface()) { Player player = diver.player; Quaternion val = ((((Character)player).AlwaysRotateCamera() || ((Character)player).m_moveDir == Vector3.zero) ? ((Character)player).m_lookYaw : Quaternion.LookRotation(((Character)player).m_moveDir)); float num = turnSpeed * ((Character)player).GetAttackSpeedFactorRotation(); ((Component)player).transform.rotation = Quaternion.RotateTowards(((Component)player).transform.rotation, val, num * dt); } } [HarmonyPrefix] [HarmonyPatch(typeof(Player), "OnSwimming")] public static void Player_OnSwimming_Prefix(Player __instance, Vector3 targetVel, float dt) { if (!(((Vector3)(ref targetVel)).magnitude >= 0.1f) && Utils.TryGetDiver(__instance, out var diver)) { if (diver.IsDiving()) { diver.DrainDivingStamina(dt); diver.UpdateSwimSkill(dt); } else if (diver.IsRestingInWater()) { diver.RegenRestingStamina(dt); } } } } [HarmonyPatch] internal static class UseEquipPatches { private static readonly CodeMatch[] CodeMatches = (CodeMatch[])(object)new CodeMatch[5] { new CodeMatch((OpCode?)OpCodes.Ldarg_0, (object)null, (string)null), new CodeMatch((OpCode?)OpCodes.Call, (object)AccessTools.Method(typeof(Character), "IsSwimming", (Type[])null, (Type[])null), (string)null), new CodeMatch((OpCode?)OpCodes.Brfalse, (object)null, (string)null), new CodeMatch((OpCode?)OpCodes.Ldarg_0, (object)null, (string)null), new CodeMatch((OpCode?)OpCodes.Call, (object)AccessTools.Method(typeof(Character), "IsOnGround", (Type[])null, (Type[])null), (string)null) }; private static readonly int InstructionMatchCount = CodeMatches.Length + 1; private static bool ShouldHideItem() { return !UnderTheSea.Instance.UseEquipInWater.Value; } [HarmonyTranspiler] [HarmonyPatch(typeof(Humanoid), "UpdateEquipment")] private static IEnumerable<CodeInstruction> UpdateEquipment_Transpiler(IEnumerable<CodeInstruction> instructions) { //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_000e: Expected O, but got Unknown //IL_007e: Unknown result type (might be due to invalid IL or missing references) //IL_0088: Expected O, but got Unknown string text = "Humanoid.UpdateEquipment"; CodeMatcher val = new CodeMatcher(instructions, (ILGenerator)null); val.MatchStartForward(CodeMatches).ThrowIfNotMatch("Failed to find match in " + text + "!", Array.Empty<CodeMatch>()); val.Advance(InstructionMatchCount); return val.InsertAndAdvance((IEnumerable<CodeInstruction>)new List<CodeInstruction> { Transpilers.EmitDelegate<Func<bool>>((Func<bool>)ShouldHideItem), new CodeInstruction(OpCodes.Brfalse, val.InstructionAt(-1).operand) }).ThrowIfInvalid("Failed to patch " + text + "!").InstructionEnumeration(); } [HarmonyTranspiler] [HarmonyPatch(typeof(Humanoid), "EquipItem")] private static IEnumerable<CodeInstruction> EquipItem_Transpiler(IEnumerable<CodeInstruction> instructions) { //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_000e: Expected O, but got Unknown //IL_007e: Unknown result type (might be due to invalid IL or missing references) //IL_0088: Expected O, but got Unknown string text = "Humanoid.EquipItem"; CodeMatcher val = new CodeMatcher(instructions, (ILGenerator)null); val.MatchStartForward(CodeMatches).ThrowIfNotMatch("Failed to find match in " + text + "!", Array.Empty<CodeMatch>()); val.Advance(InstructionMatchCount); return val.InsertAndAdvance((IEnumerable<CodeInstruction>)new List<CodeInstruction> { Transpilers.EmitDelegate<Func<bool>>((Func<bool>)ShouldHideItem), new CodeInstruction(OpCodes.Brfalse, val.InstructionAt(-1).operand) }).ThrowIfInvalid("Failed to patch " + text + "!").InstructionEnumeration(); } [HarmonyTranspiler] [HarmonyPatch(typeof(Player), "Update")] private static IEnumerable<CodeInstruction> UpdatePlayer_Transpiler(IEnumerable<CodeInstruction> instructions) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) return new CodeMatcher(instructions, (ILGenerator)null).MatchStartForward(CodeMatches).Advance(1).RemoveInstructions(InstructionMatchCount) .ThrowIfInvalid("Failed to patch Player.Update!") .InstructionEnumeration(); } } [HarmonyPatch] internal static class WaterCameraPatches { private static float WaterLevelCamera; private static float WaterLevelPlayer; private static bool ShouldResetCamera; private const float UnderWaterCameraMinWaterDistance = -5000f; private static float? CachedMinWaterDistance; private static void SetMinWaterDistanceUnderWater(GameCamera gameCamera) { if (!CachedMinWaterDistance.HasValue) { CachedMinWaterDistance = gameCamera.m_minWaterDistance; } gameCamera.m_minWaterDistance = -5000f; } private static void ResetMinWaterDistance(GameCamera gameCamera) { if (CachedMinWaterDistance.HasValue) { gameCamera.m_minWaterDistance = CachedMinWaterDistance.Value; CachedMinWaterDistance = null; } } [HarmonyPrefix] [HarmonyPatch(typeof(GameCamera), "UpdateCamera")] private static void GameCamera_UpdateCamera_Prefix(GameCamera __instance) { //IL_0065: Unknown result type (might be due to invalid IL or missing references) //IL_015b: Unknown result type (might be due to invalid IL or missing references) //IL_00ba: Unknown result type (might be due to invalid IL or missing references) //IL_00b2: Unknown result type (might be due to invalid IL or missing references) //IL_00bf: 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_00eb: Unknown result type (might be due to invalid IL or missing references) //IL_00f0: Unknown result type (might be due to invalid IL or missing references) //IL_00f2: Unknown result type (might be due to invalid IL or missing references) if (!Utils.TryGetDiver(Player.m_localPlayer, out var diver) || !Object.op_Implicit((Object)(object)__instance)) { return; } Camera camera = __instance.m_camera; bool flag = diver.IsDiving() || ((Character)diver.player).IsSwimming(); if (flag && !diver.IsRestingInWater() && UnderTheSea.Instance.IsEnvAllowed()) { SetMinWaterDistanceUnderWater(__instance); } else { ResetMinWaterDistance(__instance); } if (((Component)camera).gameObject.transform.position.y < WaterLevelCamera && flag && UnderTheSea.Instance.IsEnvAllowed()) { if (__instance.m_minWaterDistance != -5000f) { SetMinWaterDistanceUnderWater(__instance); } EnvSetup currentEnvironment = EnvMan.instance.GetCurrentEnvironment(); Color color = ((!EnvMan.IsNight()) ? currentEnvironment.m_fogColorDay : currentEnvironment.m_fogColorNight); color.a = 1f; color = ChangeColorBrightness(color, ((Character)diver.player).m_swimDepth * (0f - UnderTheSea.Instance.ColorDarknessFactor.Value)); RenderSettings.fogColor = color; RenderSettings.fogDensity = Mathf.Clamp(RenderSettings.fogDensity + ((Character)diver.player).m_swimDepth * UnderTheSea.Instance.FogDensityFactor.Value, UnderTheSea.Instance.MinFogDensity.Value, UnderTheSea.Instance.MaxFogDensity.Value); ShouldResetCamera = true; } else if (ShouldResetCamera && ((Component)camera).gameObject.transform.position.y > WaterLevelCamera) { EnvMan.instance.SetForceEnvironment(EnvMan.instance.GetCurrentEnvironment().m_name); EnvMan.instance.SetForceEnvironment(string.Empty); ShouldResetCamera = false; } } [HarmonyPrefix] [HarmonyPatch(typeof(WaterVolume), "UpdateMaterials")] private static void WaterVolume_UpdateMaterials_Prefix(WaterVolume __instance) { //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_0043: Unknown result type (might be due to invalid IL or missing references) //IL_006d: Unknown result type (might be due to invalid IL or missing references) //IL_01c4: Unknown result type (might be due to invalid IL or missing references) //IL_01c9: Unknown result type (might be due to invalid IL or missing references) //IL_01cc: Unknown result type (might be due to invalid IL or missing references) //IL_0096: Unknown result type (might be due to invalid IL or missing references) //IL_009b: Unknown result type (might be due to invalid IL or missing references) //IL_009e: Unknown result type (might be due to invalid IL or missing references) //IL_0199: Unknown result type (might be due to invalid IL or missing references) //IL_019e: Unknown result type (might be due to invalid IL or missing references) //IL_01a1: Unknown result type (might be due to invalid IL or missing references) //IL_01ac: Unknown result type (might be due to invalid IL or missing references) //IL_01b7: Unknown result type (might be due to invalid IL or missing references) //IL_028d: Unknown result type (might be due to invalid IL or missing references) //IL_0292: Unknown result type (might be due to invalid IL or missing references) //IL_0295: Unknown result type (might be due to invalid IL or missing references) //IL_02a0: Unknown result type (might be due to invalid IL or missing references) //IL_02ab: Unknown result type (might be due to invalid IL or missing references) if (!Object.op_Implicit((Object)(object)GameCamera.instance) || !Object.op_Implicit((Object)(object)Player.m_localPlayer)) { return; } WaterLevelCamera = __instance.GetWaterSurface(((Component)GameCamera.instance).transform.position, 1f); WaterLevelPlayer = __instance.GetWaterSurface(((Component)Player.m_localPlayer).transform.position, 1f); MeshRenderer component = ((Component)__instance.m_waterSurface).GetComponent<MeshRenderer>(); Quaternion rotation; if (((Component)GameCamera.instance).transform.position.y < WaterLevelCamera && ((Character)Player.m_localPlayer).IsSwimming()) { rotation = ((Component)component).transform.rotation; if (((Quaternion)(ref rotation)).eulerAngles.y != 180f && UnderTheSea.Instance.IsEnvAllowed()) { ((Component)__instance.m_waterSurface).transform.Rotate(180f, 0f, 0f); ((Renderer)__instance.m_waterSurface).shadowCastingMode = (ShadowCastingMode)2; if (__instance.m_forceDepth >= 0f) { ((Renderer)__instance.m_waterSurface).material.SetFloatArray(Shader.PropertyToID("_depth"), new float[4] { __instance.m_forceDepth, __instance.m_forceDepth, __instance.m_forceDepth, __instance.m_forceDepth }); } else { ((Renderer)__instance.m_waterSurface).material.SetFloatArray(Shader.PropertyToID("_depth"), __instance.m_normalizedDepth); } ((Renderer)__instance.m_waterSurface).material.SetFloat(Shader.PropertyToID("_UseGlobalWind"), __instance.m_useGlobalWind ? 1f : 0f); } Transform transform = ((Component)__instance.m_waterSurface).transform; Vector3 position = transform.position; ((Vector3)(ref position))..ctor(position.x, WaterLevelCamera, position.z); transform.position = position; return; } rotation = ((Component)component).transform.rotation; if (((Quaternion)(ref rotation)).eulerAngles.y == 180f && UnderTheSea.Instance.IsEnvAllowed()) { ((Component)__instance.m_waterSurface).transform.Rotate(-180f, 0f, 0f); if (__instance.m_forceDepth >= 0f) { ((Renderer)__instance.m_waterSurface).material.SetFloatArray(Shader.PropertyToID("_depth"), new float[4] { __instance.m_forceDepth, __instance.m_forceDepth, __instance.m_forceDepth, __instance.m_forceDepth }); } else { ((Renderer)__instance.m_waterSurface).material.SetFloatArray(Shader.PropertyToID("_depth"), __instance.m_normalizedDepth); } Transform transform2 = ((Component)__instance.m_waterSurface).transform; Vector3 position2 = transform2.position; ((Vector3)(ref position2))..ctor(position2.x, 30f, position2.z); transform2.position = position2; ((Renderer)__instance.m_waterSurface).material.SetFloat(Shader.PropertyToID("_UseGlobalWind"), __instance.m_useGlobalWind ? 1f : 0f); } } private static Color ChangeColorBrightness(Color color, float correctionFactor) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_000e: Unknown result type (might be due to invalid IL or missing references) //IL_0020: Unknown result type (might be due to invalid IL or missing references) //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_0074: Unknown result type (might be due to invalid IL or missing references) //IL_007a: Unknown result type (might be due to invalid IL or missing references) float r = color.r; float g = color.g; float b = color.b; if (!(correctionFactor < 0f)) { return new Color(r, g, b, color.a); } correctionFactor *= -1f; r -= r * correctionFactor; if (r < 0f) { r = 0f; } g -= g * correctionFactor; if (g < 0f) { g = 0f; } b -= b * correctionFactor; if (b < 0f) { b = 0f; } return new Color(r, g, b, color.a); } } } namespace Configs { public static class ConfigFileExtensions { public static bool DisableSaveOnConfigSet(this ConfigFile configFile) { bool saveOnConfigSet = configFile.SaveOnConfigSet; configFile.SaveOnConfigSet = false; return saveOnConfigSet; } } internal sealed class ConfigFileWatcher { private const long RELOAD_DELAY = 10000000L; private DateTime lastReadTime = DateTime.MinValue; private readonly ConfigFile configFile; private readonly string ConfigFileDir; private readonly string ConfigFileName; internal event Action OnConfigFileReloaded; internal ConfigFileWatcher(ConfigFile configFile) { this.configFile = configFile; ConfigFileDir = Directory.GetParent(configFile.ConfigFilePath).FullName; ConfigFileName = Path.GetFileName(configFile.ConfigFilePath); FileSystemWatcher fileSystemWatcher = new FileSystemWatcher(ConfigFileDir, ConfigFileName); fileSystemWatcher.Changed += ReloadConfigFile; fileSystemWatcher.Created += ReloadConfigFile; fileSystemWatcher.Renamed += ReloadConfigFile; fileSystemWatcher.IncludeSubdirectories = true; fileSystemWatcher.SynchronizingObject = ThreadingHelper.SynchronizingObject; fileSystemWatcher.EnableRaisingEvents = true; } private void InvokeOnConfigFileReloaded() { this.OnConfigFileReloaded?.SafeInvoke(); } internal void ReloadConfigFile(object sender, FileSystemEventArgs eventArgs) { DateTime now = DateTime.Now; long num = now.Ticks - lastReadTime.Ticks; if (!File.Exists(configFile.ConfigFilePath) || num < 10000000) { return; } try { Log.LogInfo("Reloading " + configFile.ConfigFilePath); bool saveOnConfigSet = configFile.DisableSaveOnConfigSet(); configFile.Reload(); configFile.SaveOnConfigSet = saveOnConfigSet; lastReadTime = now; InvokeOnConfigFileReloaded(); } catch { Log.LogError("There was an issue loading " + configFile.ConfigFilePath); Log.LogError("Please check your config entries for spelling and format!"); } } } internal static class SafeInvokeEvent { internal static void SafeInvoke(this Action events) { if (events == null) { return; } Delegate[] invocationList = events.GetInvocationList(); for (int i = 0; i < invocationList.Length; i++) { Action action = (Action)invocationList[i]; try { action(); } catch (Exception arg) { Log.LogWarning("Exception thrown at event " + new StackFrame(1).GetMethod().Name + $" in {action.Method.DeclaringType.Name}.{action.Method.Name}:\n{arg}"); } } } } }