Run.dll

Decompiled 3 weeks ago
using System;
using System.Diagnostics;
using System.Reflection;
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 HarmonyLib;
using Microsoft.CodeAnalysis;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: AssemblyTitle("Run")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("HP")]
[assembly: AssemblyProduct("Run")]
[assembly: AssemblyCopyright("Copyright © HP 2026")]
[assembly: AssemblyTrademark("")]
[assembly: ComVisible(false)]
[assembly: Guid("07f7a2d6-6812-4679-a53d-8ba964c5b75b")]
[assembly: AssemblyFileVersion("2.1.1.0")]
[assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = "")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("2.1.1.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableAttribute : Attribute
	{
		public readonly byte[] NullableFlags;

		public NullableAttribute(byte P_0)
		{
			NullableFlags = new byte[1] { P_0 };
		}

		public NullableAttribute(byte[] P_0)
		{
			NullableFlags = P_0;
		}
	}
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableContextAttribute : Attribute
	{
		public readonly byte Flag;

		public NullableContextAttribute(byte P_0)
		{
			Flag = P_0;
		}
	}
	[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 Run
{
	[BepInPlugin("YouDied.run", "Run!", "2.1.1")]
	public class Run : BaseUnityPlugin
	{
		public const string PluginGUID = "YouDied.run";

		public const string PluginName = "Run!";

		public const string PluginVersion = "2.1.1";

		internal static ManualLogSource Log = null;

		private static ConfigEntry<int> _cfgMinMultiplier = null;

		private static ConfigEntry<int> _cfgMaxMultiplier = null;

		private static ConfigEntry<int> _cfgStep = null;

		private static ConfigEntry<int> _cfgCurrentMultiplier = null;

		private static ConfigEntry<bool> _cfgLudicrousEnabled = null;

		private static ConfigEntry<int> _cfgLudicrousMultiplier = null;

		private static ConfigEntry<KeyboardShortcut> _cfgKeyIncrease = null;

		private static ConfigEntry<KeyboardShortcut> _cfgKeyDecrease = null;

		private static int s_multiplier = 100;

		private static bool s_uiGuardBroken;

		private Harmony _harmony = null;

		private static FieldRef<Character, bool>? s_mRun;

		private static MethodInfo? s_isRunning;

		private void Awake()
		{
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			//IL_003e: Expected O, but got Unknown
			//IL_006e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0078: Expected O, but got Unknown
			//IL_00a1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ab: Expected O, but got Unknown
			//IL_00d8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e2: Expected O, but got Unknown
			//IL_012a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0134: Expected O, but got Unknown
			//IL_0153: Unknown result type (might be due to invalid IL or missing references)
			//IL_0181: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b9: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c3: Expected O, but got Unknown
			//IL_02e2: Unknown result type (might be due to invalid IL or missing references)
			//IL_02e7: Unknown result type (might be due to invalid IL or missing references)
			//IL_0305: Unknown result type (might be due to invalid IL or missing references)
			//IL_030a: Unknown result type (might be due to invalid IL or missing references)
			Log = ((BaseUnityPlugin)this).Logger;
			_cfgMinMultiplier = ((BaseUnityPlugin)this).Config.Bind<int>("Speed Range", "MinimumMultiplier", 100, new ConfigDescription("Lowest run speed percentage allowed (100 = default game speed).", (AcceptableValueBase)(object)new AcceptableValueRange<int>(100, 500), Array.Empty<object>()));
			_cfgMaxMultiplier = ((BaseUnityPlugin)this).Config.Bind<int>("Speed Range", "MaximumMultiplier", 200, new ConfigDescription("Highest run speed percentage reachable with arrow keys.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(100, 500), Array.Empty<object>()));
			_cfgStep = ((BaseUnityPlugin)this).Config.Bind<int>("Speed Range", "AdjustmentPercent", 10, new ConfigDescription("How much each arrow key press changes speed, in percentage points. e.g. 10 moves from 100% to 110% per press.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 100), Array.Empty<object>()));
			_cfgCurrentMultiplier = ((BaseUnityPlugin)this).Config.Bind<int>("Current Speed", "CurrentMultiplier", 100, new ConfigDescription("Your last-used run speed percentage. Updated automatically in-game.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(100, 500), Array.Empty<object>()));
			_cfgLudicrousEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("Ludicrous Speed", "LudicrousEnabled", false, "Set to true to enable Ludicrous Speed. Run speed is further multiplied by LudicrousMultiplier on top of your current setting. Edit and restart to toggle.");
			_cfgLudicrousMultiplier = ((BaseUnityPlugin)this).Config.Bind<int>("Ludicrous Speed", "LudicrousMultiplier", 3, new ConfigDescription("Extra speed factor stacked on top of normal multiplier when Ludicrous Speed is on. Try 2-3 before going higher.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(2, 10), Array.Empty<object>()));
			_cfgKeyIncrease = ((BaseUnityPlugin)this).Config.Bind<KeyboardShortcut>("Keybinds", "IncreaseSpeed", new KeyboardShortcut((KeyCode)273, Array.Empty<KeyCode>()), "Key to increase run speed.");
			_cfgKeyDecrease = ((BaseUnityPlugin)this).Config.Bind<KeyboardShortcut>("Keybinds", "DecreaseSpeed", new KeyboardShortcut((KeyCode)274, Array.Empty<KeyCode>()), "Key to decrease run speed.");
			s_multiplier = Mathf.Clamp(_cfgCurrentMultiplier.Value, GetMin(), GetMax());
			_harmony = new Harmony("YouDied.run");
			PatchRunSpeed();
			PatchLiquidResistance();
			Log.LogInfo((object)"Run! v2.1.1 by YouDied loaded.");
			Log.LogInfo((object)("  Speed range : " + GetMin() + "% – " + GetMax() + "%"));
			Log.LogInfo((object)("  Step        : " + _cfgStep.Value + "%"));
			Log.LogInfo((object)("  Current     : " + s_multiplier + "%"));
			Log.LogInfo((object)("  Ludicrous   : " + (_cfgLudicrousEnabled.Value ? ("ON (x" + _cfgLudicrousMultiplier.Value + ")") : "off")));
			Log.LogInfo((object)("  Controls    : " + ((object)_cfgKeyIncrease.Value/*cast due to .constrained prefix*/).ToString() + " / " + ((object)_cfgKeyDecrease.Value/*cast due to .constrained prefix*/).ToString() + " to adjust speed"));
		}

		private void Update()
		{
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			//IL_002f: 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 ((Object)(object)Player.m_localPlayer == (Object)null || IsUiBlocking())
			{
				return;
			}
			bool flag = false;
			KeyboardShortcut value = _cfgKeyIncrease.Value;
			if (((KeyboardShortcut)(ref value)).IsDown())
			{
				s_multiplier = Mathf.Min(s_multiplier + _cfgStep.Value, GetMax());
				flag = true;
			}
			else
			{
				value = _cfgKeyDecrease.Value;
				if (((KeyboardShortcut)(ref value)).IsDown())
				{
					s_multiplier = Mathf.Max(s_multiplier - _cfgStep.Value, GetMin());
					flag = true;
				}
			}
			if (flag)
			{
				_cfgCurrentMultiplier.Value = s_multiplier;
				string text = ((s_multiplier <= GetMin()) ? " (min)" : ((s_multiplier >= GetMax()) ? " (max)" : ""));
				string text2 = "Run Speed: " + s_multiplier + "%" + text;
				if (_cfgLudicrousEnabled.Value)
				{
					text2 = text2 + "  [LUDICROUS x" + _cfgLudicrousMultiplier.Value + "]";
				}
				((Character)Player.m_localPlayer).Message((MessageType)1, text2, 0, (Sprite)null, false);
				Log.LogInfo((object)("Run speed -> " + s_multiplier + "%"));
			}
		}

		private void OnDestroy()
		{
			Harmony harmony = _harmony;
			if (harmony != null)
			{
				harmony.UnpatchSelf();
			}
		}

		private static int GetMin()
		{
			return Mathf.Max(100, _cfgMinMultiplier.Value);
		}

		private static int GetMax()
		{
			return Mathf.Clamp(_cfgMaxMultiplier.Value, GetMin(), 500);
		}

		private static float GetEffectiveMultiplier()
		{
			float num = (float)s_multiplier / 100f;
			if (!_cfgLudicrousEnabled.Value)
			{
				return num;
			}
			return num * (float)Mathf.Max(2, _cfgLudicrousMultiplier.Value);
		}

		private static bool IsUiBlocking()
		{
			if (s_uiGuardBroken)
			{
				return false;
			}
			try
			{
				return CheckUi();
			}
			catch (Exception ex)
			{
				s_uiGuardBroken = true;
				Log.LogWarning((object)("Menu/chat check unavailable on this Valheim build, hotkeys will work everywhere: " + ex.Message));
				return false;
			}
		}

		private static bool CheckUi()
		{
			if ((Object)(object)Chat.instance != (Object)null && Chat.instance.HasFocus())
			{
				return true;
			}
			if (InventoryGui.IsVisible())
			{
				return true;
			}
			if (Menu.IsVisible())
			{
				return true;
			}
			return false;
		}

		private static bool IsSprinting(Character c)
		{
			if (s_mRun != null)
			{
				return s_mRun.Invoke(c);
			}
			if (s_isRunning != null)
			{
				object obj = s_isRunning.Invoke(c, null);
				bool flag = default(bool);
				int num;
				if (obj is bool)
				{
					flag = (bool)obj;
					num = 1;
				}
				else
				{
					num = 0;
				}
				return (byte)((uint)num & (flag ? 1u : 0u)) != 0;
			}
			return false;
		}

		private static void ResolveSprintState()
		{
			FieldInfo fieldInfo = AccessTools.Field(typeof(Character), "m_run");
			if (fieldInfo != null && fieldInfo.FieldType == typeof(bool))
			{
				s_mRun = AccessTools.FieldRefAccess<Character, bool>(fieldInfo);
				return;
			}
			MethodInfo methodInfo = AccessTools.Method(typeof(Character), "IsRunning", Type.EmptyTypes, (Type[])null);
			if (methodInfo != null && methodInfo.ReturnType == typeof(bool))
			{
				s_isRunning = methodInfo;
				Log.LogInfo((object)"Character.m_run not found, using Character.IsRunning() instead.");
			}
			else
			{
				Log.LogWarning((object)"Could not find Character.m_run or IsRunning(); shallow-water sprint fix disabled.");
			}
		}

		private void PatchRunSpeed()
		{
			MethodInfo methodInfo = AccessTools.DeclaredMethod(typeof(Player), "GetRunSpeedFactor", (Type[])null, (Type[])null) ?? AccessTools.Method(typeof(Character), "GetRunSpeedFactor", (Type[])null, (Type[])null);
			if (methodInfo == null || methodInfo.ReturnType != typeof(float))
			{
				Log.LogError((object)"GetRunSpeedFactor not found on this Valheim build. Run speed cannot be changed.");
			}
			else
			{
				TryPatch(methodInfo, null, "RunSpeedPostfix");
			}
		}

		private static void RunSpeedPostfix(Character __instance, ref float __result)
		{
			Player val = (Player)(object)((__instance is Player) ? __instance : null);
			if (val != null && !((Object)(object)val != (Object)(object)Player.m_localPlayer))
			{
				__result *= GetEffectiveMultiplier();
			}
		}

		private void PatchLiquidResistance()
		{
			ResolveSprintState();
			if (s_mRun == null && s_isRunning == null)
			{
				return;
			}
			MethodInfo methodInfo = AccessTools.Method(typeof(Character), "ApplyLiquidResistance", (Type[])null, (Type[])null);
			if (methodInfo == null)
			{
				Log.LogWarning((object)"Character.ApplyLiquidResistance not found; shallow-water sprint fix disabled.");
				return;
			}
			ParameterInfo[] parameters = methodInfo.GetParameters();
			bool flag = parameters.Length != 0 && (parameters[0].ParameterType == typeof(float) || parameters[0].ParameterType == typeof(float).MakeByRefType());
			if (methodInfo.ReturnType == typeof(void))
			{
				TryPatch(methodInfo, "LiquidPrefixVoid");
			}
			else if (methodInfo.ReturnType == typeof(float) && flag)
			{
				TryPatch(methodInfo, "LiquidPrefixReturn");
			}
			else
			{
				Log.LogWarning((object)("ApplyLiquidResistance has an unexpected signature (" + methodInfo?.ToString() + "); shallow-water sprint fix disabled."));
			}
		}

		private static bool ShouldSkipLiquid(Character c)
		{
			Player val = (Player)(object)((c is Player) ? c : null);
			return val != null && (Object)(object)val == (Object)(object)Player.m_localPlayer && IsSprinting(c);
		}

		private static bool LiquidPrefixVoid(Character __instance)
		{
			return !ShouldSkipLiquid(__instance);
		}

		private static bool LiquidPrefixReturn(Character __instance, object[] __args, ref float __result)
		{
			if (!ShouldSkipLiquid(__instance))
			{
				return true;
			}
			__result = (float)__args[0];
			return false;
		}

		private void TryPatch(MethodInfo target, string? prefix = null, string? postfix = null)
		{
			//IL_0011: 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)
			try
			{
				HarmonyMethod val = ((prefix == null) ? ((HarmonyMethod)null) : new HarmonyMethod(typeof(Run), prefix, (Type[])null));
				HarmonyMethod val2 = ((postfix == null) ? ((HarmonyMethod)null) : new HarmonyMethod(typeof(Run), postfix, (Type[])null));
				_harmony.Patch((MethodBase)target, val, val2, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
				Log.LogInfo((object)("Patched " + target.DeclaringType?.Name + "." + target.Name));
			}
			catch (Exception ex)
			{
				Log.LogError((object)("Failed to patch " + target.DeclaringType?.Name + "." + target.Name + ": " + ex));
			}
		}
	}
}