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 UnderTheSea v1.1.0
UnderTheSea.dll
Decompiled 3 days agousing System; using System.Collections.Generic; using System.Diagnostics; 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("1.1.0")] [assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("1.1.0.0")] [module: UnverifiableCode] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [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 float RestingStaminaDrainUnderWater => UnderTheSea.Instance.UnderwaterRestingStaminaDrainRate.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() { if (!IsDiving() && ((Character)player).IsSwimming()) { return !IsMoving(); } return false; } public bool IsMoving() { //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) Vector3 velocity = ((Character)player).GetVelocity(); return ((Vector3)(ref velocity)).magnitude >= 1f; } 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 UpdateStaminaUnderWater(float dt, Vector3 targetVel) { float skillFactor = player.m_skills.GetSkillFactor((SkillType)103); if (RestingStaminaDrainUnderWater < 0f && ((Vector3)(ref targetVel)).magnitude < 1f) { float num = (1f + skillFactor) * Mathf.Abs(RestingStaminaDrainUnderWater); player.m_stamina = Mathf.Min(((Character)player).GetMaxStamina(), player.m_stamina + num * dt * Game.m_staminaRegenRate); return; } float num2 = Mathf.Lerp(player.m_swimStaminaDrainMinSkill, player.m_swimStaminaDrainMaxSkill, skillFactor); num2 += num2 * ((Character)player).GetEquipmentSwimStaminaModifier(); ((Character)player).m_seman.ModifySwimStaminaUsage(num2, ref num2, true); ((Character)player).UseStamina(dt * num2 * Game.m_moveStaminaRate * UnderTheSea.Instance.UnderwaterRestingStaminaDrainRate.Value); UpdateSwimSkill(dt); } 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", "1.1.0")] [BepInDependency("com.jotunn.jotunn", "2.30.1")] [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 = "1.1.0"; 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() { //IL_0067: Unknown result type (might be due to invalid IL or missing references) //IL_0071: Expected O, but got Unknown 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, 1000L); } 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. If set to a negative value then you will regen stamina while resting underwater.", true, true, true, (AcceptableValueBase)(object)new AcceptableValueRange<float>(-0.5f, 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) { //IL_0023: Unknown result type (might be due to invalid IL or missing references) if (!(((Vector3)(ref targetVel)).magnitude >= 0.1f) && Utils.TryGetDiver(__instance, out var diver)) { if (diver.IsDiving()) { diver.UpdateStaminaUnderWater(dt, targetVel); } else if (diver.IsRestingInWater()) { diver.RegenRestingStamina(dt); } } } [HarmonyPrefix] [HarmonyAfter(new string[] { "afilbert.ValheimToggleMovementMod" })] [HarmonyPatch(typeof(Player), "SetControls")] private static void PreventCrouchWhileSwimming(Player __instance, ref bool crouch) { Diver diver = default(Diver); if (Utils.IsValidLocalPlayer(__instance) && (((Character)__instance).IsSwimming() || (((Component)__instance).TryGetComponent<Diver>(ref diver) && diver.IsInsideLiquid()))) { __instance.m_crouchToggled = false; crouch = false; } } } [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 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}"); } } } } }