using System; using System.Diagnostics; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.Versioning; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; using UnityEngine; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)] [assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")] [assembly: AssemblyTitle("SwiftDodge")] [assembly: AssemblyDescription("")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("")] [assembly: AssemblyProduct("SwiftDodge")] [assembly: AssemblyCopyright("Copyright © 2026")] [assembly: AssemblyTrademark("")] [assembly: ComVisible(false)] [assembly: Guid("d594ab47-946c-494f-a967-bfe78b32d002")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyVersion("1.0.0.0")] namespace SwiftDodge { [BepInPlugin("hoskope.valheim.swiftdodge", "SwiftDodge", "1.0.0")] public class SwiftDodgePlugin : BaseUnityPlugin { internal enum DodgeInputMode { DoubleTap, DodgeKey, Both } public const string PluginGuid = "hoskope.valheim.swiftdodge"; public const string PluginName = "SwiftDodge"; public const string PluginVersion = "1.0.0"; internal static ManualLogSource Log; internal static ConfigEntry ModEnabled; internal static ConfigEntry DebugEnabled; internal static ConfigEntry DodgeMode; internal static ConfigEntry DoubleTapWindow; internal static ConfigEntry DodgeCooldownGuard; internal static ConfigEntry DodgeKey; private Harmony _harmony; private void Awake() { //IL_009a: Unknown result type (might be due to invalid IL or missing references) //IL_00a4: Expected O, but got Unknown //IL_00d7: Unknown result type (might be due to invalid IL or missing references) //IL_00e1: Expected O, but got Unknown //IL_0100: Unknown result type (might be due to invalid IL or missing references) //IL_012b: Unknown result type (might be due to invalid IL or missing references) //IL_0135: Expected O, but got Unknown Log = ((BaseUnityPlugin)this).Logger; ModEnabled = ((BaseUnityPlugin)this).Config.Bind("General", "Mod enabled", true, "Enable SwiftDodge."); DebugEnabled = ((BaseUnityPlugin)this).Config.Bind("General", "Debug enabled", false, "Enable debug logging."); DodgeMode = ((BaseUnityPlugin)this).Config.Bind("General", "Dodge mode", DodgeInputMode.DoubleTap, "How SwiftDodge should trigger dodge rolls."); DoubleTapWindow = ((BaseUnityPlugin)this).Config.Bind("Double Tap", "Double-tap window", 0.3f, new ConfigDescription("Maximum time in seconds between two direction taps.", (AcceptableValueBase)(object)new AcceptableValueRange(0.1f, 0.75f), Array.Empty())); DodgeCooldownGuard = ((BaseUnityPlugin)this).Config.Bind("General", "Dodge cooldown guard", 0.45f, new ConfigDescription("Minimum time in seconds between SwiftDodge-triggered dodge attempts.", (AcceptableValueBase)(object)new AcceptableValueRange(0.1f, 1.5f), Array.Empty())); DodgeKey = ((BaseUnityPlugin)this).Config.Bind("Dodge Key", "Dodge key", new KeyboardShortcut((KeyCode)308, Array.Empty()), "Dedicated dodge key. Dodge direction uses current movement direction, or backward if standing still."); ((BaseUnityPlugin)this).Logger.LogInfo((object)"SwiftDodge config initialized."); _harmony = new Harmony("hoskope.valheim.swiftdodge"); _harmony.PatchAll(); ((BaseUnityPlugin)this).Logger.LogInfo((object)"SwiftDodge 1.0.0 loaded."); } private void OnDestroy() { if (_harmony != null) { _harmony.UnpatchSelf(); } } } } namespace SwiftDodge.Patch { [HarmonyPatch(typeof(Player), "SetControls")] public static class PlayerSetControlsPatch { private enum DodgeDirection { None, Forward, Backward, Left, Right } private static readonly MethodInfo DodgeMethod = AccessTools.Method(typeof(Player), "Dodge", new Type[1] { typeof(Vector3) }, (Type[])null); private static readonly FieldInfo LookDirField = AccessTools.Field(typeof(Player), "m_lookDir"); private static DodgeDirection _lastTapDirection = DodgeDirection.None; private static float _lastTapTime; private static float _lastDodgeTime; private static bool _wasForwardPressed; private static bool _wasBackwardPressed; private static bool _wasLeftPressed; private static bool _wasRightPressed; private const float DirectionThreshold = 0.5f; private static void Prefix(Player __instance, Vector3 movedir) { //IL_0097: Unknown result type (might be due to invalid IL or missing references) //IL_00c0: Unknown result type (might be due to invalid IL or missing references) //IL_00ce: Unknown result type (might be due to invalid IL or missing references) //IL_00dd: Unknown result type (might be due to invalid IL or missing references) //IL_00ec: Unknown result type (might be due to invalid IL or missing references) if ((SwiftDodgePlugin.ModEnabled != null && !SwiftDodgePlugin.ModEnabled.Value) || (Object)(object)__instance == (Object)null || (Object)(object)__instance != (Object)(object)Player.m_localPlayer) { return; } if (!CanAttemptDodge(__instance)) { ResetInputState(); return; } SwiftDodgePlugin.DodgeInputMode value = SwiftDodgePlugin.DodgeMode.Value; bool flag = value == SwiftDodgePlugin.DodgeInputMode.DoubleTap || value == SwiftDodgePlugin.DodgeInputMode.Both; if ((value == SwiftDodgePlugin.DodgeInputMode.DodgeKey || value == SwiftDodgePlugin.DodgeInputMode.Both) && IsDodgeKeyDownRelaxed() && TryDodgeFromKey(__instance, movedir)) { return; } if (!flag) { ResetInputState(); return; } bool flag2 = movedir.z > 0.5f; bool flag3 = movedir.z < -0.5f; bool flag4 = movedir.x < -0.5f; bool flag5 = movedir.x > 0.5f; if (flag2 && !_wasForwardPressed) { RegisterTap(__instance, DodgeDirection.Forward); } if (flag3 && !_wasBackwardPressed) { RegisterTap(__instance, DodgeDirection.Backward); } if (flag4 && !_wasLeftPressed) { RegisterTap(__instance, DodgeDirection.Left); } if (flag5 && !_wasRightPressed) { RegisterTap(__instance, DodgeDirection.Right); } _wasForwardPressed = flag2; _wasBackwardPressed = flag3; _wasLeftPressed = flag4; _wasRightPressed = flag5; } private static bool IsDodgeKeyDownRelaxed() { //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_000e: Unknown result type (might be due to invalid IL or missing references) //IL_0014: Invalid comparison between Unknown and I4 //IL_0030: Unknown result type (might be due to invalid IL or missing references) //IL_0035: Unknown result type (might be due to invalid IL or missing references) //IL_0038: Unknown result type (might be due to invalid IL or missing references) //IL_003b: Invalid comparison between Unknown and I4 //IL_0046: 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) KeyboardShortcut value = SwiftDodgePlugin.DodgeKey.Value; if ((int)((KeyboardShortcut)(ref value)).MainKey == 0) { return false; } foreach (KeyCode modifier in ((KeyboardShortcut)(ref value)).Modifiers) { if ((int)modifier == 0 || Input.GetKey(modifier)) { continue; } return false; } return Input.GetKeyDown(((KeyboardShortcut)(ref value)).MainKey); } private static bool CanAttemptDodge(Player player) { if (((Character)player).IsDead()) { return false; } if (((Character)player).InDodge()) { return false; } if (((Character)player).IsEncumbered()) { return false; } if (InventoryGui.IsVisible()) { return false; } if (Menu.IsVisible()) { return false; } if (Hud.InRadial()) { return false; } if (Hud.IsPieceSelectionVisible()) { return false; } if (((Character)player).InPlaceMode()) { return false; } return true; } private static void RegisterTap(Player player, DodgeDirection direction) { //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) //IL_004b: Unknown result type (might be due to invalid IL or missing references) float time = Time.time; if (_lastTapDirection == direction && time - _lastTapTime <= SwiftDodgePlugin.DoubleTapWindow.Value && time - _lastDodgeTime >= SwiftDodgePlugin.DodgeCooldownGuard.Value) { Vector3 worldDodgeDirection = GetWorldDodgeDirection(player, direction); if (InvokeDodge(player, worldDodgeDirection)) { _lastDodgeTime = time; } _lastTapDirection = DodgeDirection.None; _lastTapTime = 0f; } else { _lastTapDirection = direction; _lastTapTime = time; } } private static Vector3 GetWorldDodgeDirection(Player player, DodgeDirection direction) { //IL_0002: 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_0048: Unknown result type (might be due to invalid IL or missing references) //IL_004d: 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_0053: Unknown result type (might be due to invalid IL or missing references) //IL_002d: Unknown result type (might be due to invalid IL or missing references) //IL_0032: Unknown result type (might be due to invalid IL or missing references) //IL_008a: Unknown result type (might be due to invalid IL or missing references) //IL_008b: 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_008f: Unknown result type (might be due to invalid IL or missing references) //IL_0094: Unknown result type (might be due to invalid IL or missing references) //IL_0097: Unknown result type (might be due to invalid IL or missing references) //IL_0098: Unknown result type (might be due to invalid IL or missing references) //IL_009d: Unknown result type (might be due to invalid IL or missing references) //IL_00a0: Unknown result type (might be due to invalid IL or missing references) //IL_00a1: Unknown result type (might be due to invalid IL or missing references) //IL_00c1: Unknown result type (might be due to invalid IL or missing references) //IL_00c2: Unknown result type (might be due to invalid IL or missing references) //IL_00a4: Unknown result type (might be due to invalid IL or missing references) //IL_00a5: Unknown result type (might be due to invalid IL or missing references) //IL_00aa: Unknown result type (might be due to invalid IL or missing references) //IL_00c6: Unknown result type (might be due to invalid IL or missing references) Vector3 val = GetLookDir(player); val.y = 0f; if (((Vector3)(ref val)).sqrMagnitude < 0.001f) { val = ((Component)player).transform.forward; val.y = 0f; } ((Vector3)(ref val)).Normalize(); Vector3 val2 = Vector3.Cross(Vector3.up, val); val2.y = 0f; ((Vector3)(ref val2)).Normalize(); Vector3 result = (Vector3)(direction switch { DodgeDirection.Forward => val, DodgeDirection.Backward => -val, DodgeDirection.Left => -val2, DodgeDirection.Right => val2, _ => -val, }); result.y = 0f; ((Vector3)(ref result)).Normalize(); return result; } private static Vector3 GetLookDir(Player player) { //IL_003c: Unknown result type (might be due to invalid IL or missing references) //IL_0041: Unknown result type (might be due to invalid IL or missing references) //IL_0017: Unknown result type (might be due to invalid IL or missing references) //IL_001c: 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_002c: Unknown result type (might be due to invalid IL or missing references) //IL_0031: Unknown result type (might be due to invalid IL or missing references) if (LookDirField == null) { return ((Component)player).transform.forward; } try { return (Vector3)LookDirField.GetValue(player); } catch { return ((Component)player).transform.forward; } } private static bool InvokeDodge(Player player, Vector3 dodgeDir) { //IL_0035: Unknown result type (might be due to invalid IL or missing references) if (DodgeMethod == null) { SwiftDodgePlugin.Log.LogWarning((object)"Failed to invoke vanilla dodge: Player.Dodge method was not found."); return false; } try { DodgeMethod.Invoke(player, new object[1] { dodgeDir }); return true; } catch (Exception ex) { SwiftDodgePlugin.Log.LogWarning((object)("Failed to invoke vanilla dodge: " + ex.Message)); return false; } } private static void ResetInputState() { _wasForwardPressed = false; _wasBackwardPressed = false; _wasLeftPressed = false; _wasRightPressed = false; _lastTapDirection = DodgeDirection.None; _lastTapTime = 0f; } private static bool TryDodgeFromKey(Player player, Vector3 movedir) { //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_003b: Unknown result type (might be due to invalid IL or missing references) //IL_0040: Unknown result type (might be due to invalid IL or missing references) //IL_0042: Unknown result type (might be due to invalid IL or missing references) float time = Time.time; if (time - _lastDodgeTime < SwiftDodgePlugin.DodgeCooldownGuard.Value) { return false; } DodgeDirection dodgeDirection = GetDirectionFromMoveInput(movedir); if (dodgeDirection == DodgeDirection.None) { dodgeDirection = DodgeDirection.Backward; } Vector3 worldDodgeDirection = GetWorldDodgeDirection(player, dodgeDirection); if (!InvokeDodge(player, worldDodgeDirection)) { return false; } _lastDodgeTime = time; _lastTapDirection = DodgeDirection.None; _lastTapTime = 0f; return true; } private static DodgeDirection GetDirectionFromMoveInput(Vector3 movedir) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_000c: 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_001e: 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_0034: Unknown result type (might be due to invalid IL or missing references) if (Mathf.Abs(movedir.x) > Mathf.Abs(movedir.z)) { if (movedir.x < -0.5f) { return DodgeDirection.Left; } if (movedir.x > 0.5f) { return DodgeDirection.Right; } } else { if (movedir.z > 0.5f) { return DodgeDirection.Forward; } if (movedir.z < -0.5f) { return DodgeDirection.Backward; } } return DodgeDirection.None; } } }