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 HelmWind v1.0.2
plugins/HelmWind.dll
Decompiled 3 hours agousing System; using System.Diagnostics; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; using Microsoft.CodeAnalysis; using UnityEngine; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETStandard,Version=v2.0", FrameworkDisplayName = ".NET Standard 2.0")] [assembly: AssemblyCompany("SirRomey")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyCopyright("Copyright (c) 2026 SirRomey")] [assembly: AssemblyDescription("Locks the wind to a fixed angle off your ship's heading while you are at the helm with sails up. Client-side; wind strength and ship stats are untouched.")] [assembly: AssemblyFileVersion("1.0.2.0")] [assembly: AssemblyInformationalVersion("1.0.2+35929e141fb8d0470c70ff1e563129af6bc5b10a")] [assembly: AssemblyProduct("HelmWind")] [assembly: AssemblyTitle("HelmWind")] [assembly: AssemblyVersion("1.0.2.0")] [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 HelmWind { public enum SailMode { Off, DeadAstern, Offset } [BepInPlugin("SirRomey.HelmWind", "HelmWind", "1.0.2")] public class Plugin : BaseUnityPlugin { public const string GUID = "SirRomey.HelmWind"; public const string ModName = "HelmWind"; public const string ModVersion = "1.0.2"; internal static ManualLogSource Log; private static ConfigEntry<bool> _enabled; private static ConfigEntry<float> _offset; private static ConfigEntry<KeyboardShortcut> _toggleKey; private static SailMode _mode = SailMode.Offset; private static bool _active; private static bool _focusCheckStoodDown; private Harmony _harmony; private static readonly KeyCode[] BlockingModifiers; public static bool Enabled { get { if (_enabled != null) { return _enabled.Value; } return false; } } public static SailMode Mode => _mode; public static float OffsetDegrees => Mathf.Clamp(_offset.Value, -90f, 90f); public static float ActiveOffsetDegrees { get { if (_mode != SailMode.DeadAstern) { return OffsetDegrees; } return 0f; } } private void Awake() { //IL_0059: Unknown result type (might be due to invalid IL or missing references) //IL_0063: Expected O, but got Unknown //IL_0082: Unknown result type (might be due to invalid IL or missing references) //IL_0092: Unknown result type (might be due to invalid IL or missing references) //IL_009c: Expected O, but got Unknown //IL_00a7: Unknown result type (might be due to invalid IL or missing references) //IL_00b1: Expected O, but got Unknown //IL_0152: Unknown result type (might be due to invalid IL or missing references) Log = ((BaseUnityPlugin)this).Logger; _enabled = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "Enabled", true, "Master switch. With this off the wind is never touched, whatever mode is showing."); _offset = ((BaseUnityPlugin)this).Config.Bind<float>("General", "Offset", 60f, new ConfigDescription("Angle in degrees between the wind and the ship's heading, used by Offset mode. The sign picks the side the wind comes over: negative is one side, positive the other. Valheim's sail physics is symmetric about the centreline, so the sign changes which way you heel and nothing else - only the magnitude affects speed. Sail force peaks near 63 degrees, which is why the default is 60.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(-90f, 90f), Array.Empty<object>())); _toggleKey = ((BaseUnityPlugin)this).Config.Bind<KeyboardShortcut>("General", "ToggleKey", new KeyboardShortcut((KeyCode)289, Array.Empty<KeyCode>()), new ConfigDescription("Cycles Off, then DeadAstern, then Offset, then back to Off. Modifiers work, so LeftControl+F8 and the like are valid. Ignored while the console, chat, or a text prompt has the keyboard.", (AcceptableValueBase)null, Array.Empty<object>())); _harmony = new Harmony("SirRomey.HelmWind"); if (AccessTools.Method(typeof(EnvMan), "SetTargetWind", new Type[2] { typeof(Vector3), typeof(float) }, (Type[])null) == null) { Log.LogError((object)"could not find EnvMan.SetTargetWind(Vector3, float) - game update? wind override is off"); return; } _harmony.PatchAll(typeof(WindPatch)); _active = true; Log.LogInfo((object)string.Format("loaded v{0}, mode {1}, offset {2:0.#} deg, key {3}", "1.0.2", _mode, OffsetDegrees, _toggleKey.Value)); } private void OnDestroy() { Harmony harmony = _harmony; if (harmony != null) { harmony.UnpatchSelf(); } } private void Update() { if (_active && Enabled && !TypingSomewhere() && ToggleKeyPressed()) { CycleMode(); } } private static bool ToggleKeyPressed() { //IL_0005: 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_000d: 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_005a: Unknown result type (might be due to invalid IL or missing references) //IL_005c: 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) KeyboardShortcut value = _toggleKey.Value; if ((int)((KeyboardShortcut)(ref value)).MainKey == 0 || !Input.GetKeyDown(((KeyboardShortcut)(ref value)).MainKey)) { return false; } KeyCode[] array = ((KeyboardShortcut)(ref value)).Modifiers.ToArray(); KeyCode[] array2 = array; for (int i = 0; i < array2.Length; i++) { if (!Input.GetKey(array2[i])) { return false; } } array2 = BlockingModifiers; foreach (KeyCode val in array2) { if (Input.GetKey(val) && Array.IndexOf(array, val) < 0) { return false; } } return true; } private static bool TypingSomewhere() { if (_focusCheckStoodDown) { return false; } try { if (Console.IsVisible() || TextInput.IsVisible()) { return true; } return (Object)(object)Chat.instance != (Object)null && Chat.instance.HasFocus(); } catch (Exception arg) { _focusCheckStoodDown = true; Log.LogError((object)$"focus check threw, treating as not typing from here on: {arg}"); return false; } } private static void CycleMode() { string text; switch (_mode) { case SailMode.Off: _mode = SailMode.DeadAstern; text = "HelmWind: dead astern"; break; case SailMode.DeadAstern: _mode = SailMode.Offset; text = $"HelmWind: offset {OffsetDegrees:0.#} deg"; break; default: _mode = SailMode.Off; text = "HelmWind: off, vanilla wind"; break; } Log.LogInfo((object)$"mode {_mode}"); if ((Object)(object)Player.m_localPlayer != (Object)null) { ((Character)Player.m_localPlayer).Message((MessageType)1, text, 0, (Sprite)null, false); } } static Plugin() { KeyCode[] array = new KeyCode[6]; RuntimeHelpers.InitializeArray(array, (RuntimeFieldHandle)/*OpCode not supported: LdMemberToken*/); BlockingModifiers = (KeyCode[])(object)array; } } [HarmonyPatch(typeof(EnvMan), "SetTargetWind")] internal static class WindPatch { private const float MinHeadingMagnitude = 0.0001f; private static bool _stoodDown; private static bool Prefix(ref Vector3 dir) { //IL_0014: 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) if (_stoodDown) { return true; } try { if (TryGetHeadingWind(out var wind)) { dir = wind; } } catch (Exception arg) { _stoodDown = true; Plugin.Log.LogError((object)$"wind override threw, standing down for this session: {arg}"); } return true; } private static bool TryGetHeadingWind(out Vector3 wind) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_006f: Unknown result type (might be due to invalid IL or missing references) //IL_0074: Unknown result type (might be due to invalid IL or missing references) //IL_0097: Unknown result type (might be due to invalid IL or missing references) //IL_009c: Unknown result type (might be due to invalid IL or missing references) //IL_00a3: Unknown result type (might be due to invalid IL or missing references) //IL_00a8: 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) wind = Vector3.zero; if (!Plugin.Enabled || Plugin.Mode == SailMode.Off) { return false; } EnvMan instance = EnvMan.instance; if ((Object)(object)instance == (Object)null || instance.m_debugWind) { return false; } Player localPlayer = Player.m_localPlayer; if ((Object)(object)localPlayer == (Object)null) { return false; } Ship controlledShip = localPlayer.GetControlledShip(); if ((Object)(object)controlledShip == (Object)null) { return false; } if (!controlledShip.IsSailUp() || !controlledShip.IsOwner()) { return false; } Vector3 forward = ((Component)controlledShip).transform.forward; forward.y = 0f; if (((Vector3)(ref forward)).sqrMagnitude < 9.999999E-09f) { return false; } wind = Quaternion.AngleAxis(Plugin.ActiveOffsetDegrees, Vector3.up) * ((Vector3)(ref forward)).normalized; return true; } } }