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 Underwater v1.2.4
Underwater.dll
Decompiled 4 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 BepInEx; using BepInEx.Configuration; using ConditionalConfigSync; using CrystalLib; using HarmonyLib; using UnityEngine; using UnityEngine.InputSystem; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: AssemblyTitle("Underwater")] [assembly: AssemblyDescription("Underwater")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("Crystal")] [assembly: AssemblyProduct("Underwater")] [assembly: AssemblyCopyright("Copyright © 2026 Crystal Ferrai")] [assembly: AssemblyTrademark("")] [assembly: ComVisible(false)] [assembly: Guid("3cdab7b7-951c-4013-8b57-7931e76589d4")] [assembly: AssemblyFileVersion("1.2.4.0")] [assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")] [assembly: AssemblyVersion("1.2.4.0")] namespace Underwater; [BepInPlugin("dev.crystal.underwater", "Underwater", "1.2.4.0")] [BepInDependency(/*Could not decode attribute arguments.*/)] [BepInProcess("valheim.exe")] [BepInProcess("valheim_server.exe")] public class UnderwaterPlugin : BaseUnityPlugin { [HarmonyPatch(typeof(Character))] private static class Character_Patches { [HarmonyPatch("InLiquidDepth")] [HarmonyPrefix] private static bool InLiquidDepth_Prefix(Character __instance, ref float __result) { __result = 0f; if (__instance.IsPlayer()) { return PlayerSwims.Value; } return true; } } [HarmonyPatch(typeof(GameCamera))] private static class GameCamera_Patches { private enum TranspilerState { Searching, Checking, Searching2, Checking2, Updating, Finishing } [HarmonyPatch("GetCameraPosition")] [HarmonyTranspiler] private static IEnumerable<CodeInstruction> GetCameraPosition_Transpiler(IEnumerable<CodeInstruction> instructions) { TranspilerState state = TranspilerState.Searching; CodeInstruction instruction1 = null; CodeInstruction instruction2 = null; CodeInstruction instruction3 = null; foreach (CodeInstruction instruction4 in instructions) { switch (state) { case TranspilerState.Searching: if (instruction4.opcode == OpCodes.Ldloc_S) { instruction1 = instruction4; state = TranspilerState.Checking; } else { yield return instruction4; } break; case TranspilerState.Checking: if (instruction3 != null && instruction4.opcode == OpCodes.Call && ((MethodInfo)instruction4.operand).Name.Equals("GetLiquidLevel")) { CodeInstruction val; instruction3 = (val = null); instruction2 = (val = val); instruction1 = val; state = TranspilerState.Searching2; break; } if (instruction2 != null && instruction4.opcode == OpCodes.Ldc_I4_S && (sbyte)instruction4.operand == 10) { instruction3 = instruction4; break; } if (instruction4.opcode == OpCodes.Ldc_R4 && (float)instruction4.operand == 1f) { instruction2 = instruction4; break; } yield return instruction1; instruction1 = null; if (instruction2 != null) { yield return instruction2; instruction2 = null; } if (instruction3 != null) { yield return instruction3; instruction3 = null; } yield return instruction4; state = TranspilerState.Searching; break; case TranspilerState.Searching2: if (instruction4.opcode == OpCodes.Ldarg_0) { instruction1 = instruction4; state = TranspilerState.Checking2; } break; case TranspilerState.Checking2: if (instruction4.opcode == OpCodes.Ldc_I4_0) { instruction2 = instruction4; state = TranspilerState.Updating; } else { instruction1 = null; state = TranspilerState.Searching2; } break; case TranspilerState.Updating: yield return instruction1; yield return instruction2; yield return instruction4; state = TranspilerState.Finishing; break; case TranspilerState.Finishing: yield return instruction4; break; } } if (state != TranspilerState.Finishing) { throw new InvalidOperationException("[Underwater] Failed to apply camera patch"); } } } public const string ModId = "dev.crystal.underwater"; public const string ModName = "Underwater"; public const string ModVersion = "1.2.4.0"; internal static readonly ConfigSync ConfigSync = new ConfigSync("dev.crystal.underwater") { DisplayName = "Underwater", CurrentVersion = "1.2.4.0", MinimumRequiredVersion = "1.2.4.0", ModRequired = false, ModRequirementMode = (ModRequirementMode)1 }; public static ConfigEntry<bool> ModUseAllowed; public static ConfigEntry<bool> PlayerSwims; public static ConfigEntry<bool> CameraIgnoreWater; public static ConfigEntry<Key> ToggleSwimKey; private static InputBinding sToggleSwimBinding; private static Harmony sCharacterHarmony; private static Harmony sGameCameraHarmony; private void Awake() { //IL_0111: Unknown result type (might be due to invalid IL or missing references) //IL_011b: Expected O, but got Unknown //IL_0136: Unknown result type (might be due to invalid IL or missing references) //IL_0140: Expected O, but got Unknown //IL_0145: Unknown result type (might be due to invalid IL or missing references) //IL_014f: Expected O, but got Unknown ModUseAllowed = ((BaseUnityPlugin)this).Config.Bind<bool>("Underwater", "ModUseAllowed", true, "Whether this mod is allowed to be used. Intended for server owners who wish to disable the mod on their server. [The value will be enforced on a server.]"); ModUseAllowed.SettingChanged += ModUseAllowed_SettingChanged; ((ConditionalConfigSync)ConfigSync).AddConfigEntry<bool>(ModUseAllowed, (ConfigSyncMode)0); PlayerSwims = ((BaseUnityPlugin)this).Config.Bind<bool>("Underwater", "PlayerSwims", true, "Whether players should swim or ignore water, walking along the terrain beneath it. Can also be toggled by pressing the toggle swim key (default Backspace). Game default true."); PlayerSwims.SettingChanged += IgnoreWater_SettingChanged; ((ConditionalConfigSync)ConfigSync).AddConfigEntry<bool>(PlayerSwims, (ConfigSyncMode)2); CameraIgnoreWater = ((BaseUnityPlugin)this).Config.Bind<bool>("Underwater", "CameraIgnoreWater", false, "Whether the camera should ignore water, allowing it to move beneath the surface. This setting is implied true if PlayerSwims is false. Game default false."); CameraIgnoreWater.SettingChanged += IgnoreWater_SettingChanged; ((ConditionalConfigSync)ConfigSync).AddConfigEntry<bool>(CameraIgnoreWater, (ConfigSyncMode)2); ToggleSwimKey = ((BaseUnityPlugin)this).Config.Bind<Key>("Underwater", "ToggleSwimKey", (Key)65, "Binds a shortcut key for toggling the PlayerSwims option."); ((ConditionalConfigSync)ConfigSync).AddConfigEntry<Key>(ToggleSwimKey, (ConfigSyncMode)2); sToggleSwimBinding = new InputBinding("ToggleSwim", ToggleSwimKey); sToggleSwimBinding.InputPressed += ToggleSwimBinding_InputPressed; sCharacterHarmony = new Harmony("dev.crystal.underwater_Character"); sGameCameraHarmony = new Harmony("dev.crystal.underwater_GameCamera"); sCharacterHarmony.PatchAll(typeof(Character_Patches)); if (!PlayerSwims.Value || CameraIgnoreWater.Value) { sGameCameraHarmony.PatchAll(typeof(GameCamera_Patches)); } } private void OnDestroy() { sCharacterHarmony.UnpatchSelf(); sGameCameraHarmony.UnpatchSelf(); sToggleSwimBinding.Dispose(); } private void ModUseAllowed_SettingChanged(object sender, EventArgs e) { if (ModUseAllowed.Value) { sCharacterHarmony.PatchAll(typeof(Character_Patches)); if (!PlayerSwims.Value || CameraIgnoreWater.Value) { sGameCameraHarmony.PatchAll(typeof(GameCamera_Patches)); } } else { sCharacterHarmony.UnpatchSelf(); sGameCameraHarmony.UnpatchSelf(); } } private void IgnoreWater_SettingChanged(object sender, EventArgs e) { sGameCameraHarmony.UnpatchSelf(); if (ModUseAllowed.Value && (!PlayerSwims.Value || CameraIgnoreWater.Value)) { sGameCameraHarmony.PatchAll(typeof(GameCamera_Patches)); } } private void ToggleSwimBinding_InputPressed(object sender, InputEventArgs e) { if (ModUseAllowed.Value) { PlayerSwims.Value = !PlayerSwims.Value; ((Character)e.Player).Message((MessageType)1, PlayerSwims.Value ? "Swimming On" : "Swimming Off", 0, (Sprite)null, false); } else { ((Character)e.Player).Message((MessageType)1, "Underwater mod use disallowed by server or local config", 0, (Sprite)null, false); } } }