Decompiled source of Always Auto Sprint v0.1.1

plugins/AlwaysAutoSprint/AlwaysAutoSprint.dll

Decompiled 11 hours ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using System.Reflection.Emit;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Configuration;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using RoR2;
using RoR2.CameraModes;
using RoR2.Skills;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("AlwaysAutoSprint")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("0.1.1.0")]
[assembly: AssemblyInformationalVersion("0.1.1")]
[assembly: AssemblyProduct("AlwaysAutoSprint")]
[assembly: AssemblyTitle("AlwaysAutoSprint")]
[assembly: AssemblyVersion("0.1.1.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 AlwaysAutoSprint
{
	[BepInPlugin("local.ror2.alwaysautosprint", "Always Auto Sprint", "0.1.1")]
	public sealed class Plugin : BaseUnityPlugin
	{
		private sealed class Recovery
		{
			public float until;

			public GenericSkill[] skills;

			public EntityStateMachine[] machines;
		}

		public const string Id = "local.ror2.alwaysautosprint";

		private static Plugin instance;

		private Harmony harmony;

		private ConfigEntry<bool> modEnabled;

		private ConfigEntry<bool> holdToWalk;

		private ConfigEntry<float> resumeDelay;

		private ConfigEntry<string> disabledStates;

		private ConfigEntry<string> disabledBodies;

		private ConfigEntry<string> fovMode;

		private static readonly ConditionalWeakTable<CharacterBody, Recovery> recoveries = new ConditionalWeakTable<CharacterBody, Recovery>();

		private void Awake()
		{
			//IL_0077: Unknown result type (might be due to invalid IL or missing references)
			//IL_0081: Expected O, but got Unknown
			//IL_0113: Unknown result type (might be due to invalid IL or missing references)
			//IL_011d: Expected O, but got Unknown
			//IL_0128: Unknown result type (might be due to invalid IL or missing references)
			//IL_0132: Expected O, but got Unknown
			//IL_0160: Unknown result type (might be due to invalid IL or missing references)
			//IL_016c: Expected O, but got Unknown
			//IL_019b: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a7: Expected O, but got Unknown
			instance = this;
			modEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "Enabled", true, "Sprint automatically when moving.");
			holdToWalk = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "Hold sprint to walk", true, "Hold your normal sprint binding to walk. Applies to keyboard and controller.");
			resumeDelay = ((BaseUnityPlugin)this).Config.Bind<float>("General", "Resume delay", 0.12f, new ConfigDescription("Seconds to wait after a sprint-blocking skill ends.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 2f), Array.Empty<object>()));
			disabledStates = ((BaseUnityPlugin)this).Config.Bind<string>("Compatibility", "Blocked states", "", "Comma-separated full entity state names during which automatic sprint is disabled.");
			disabledBodies = ((BaseUnityPlugin)this).Config.Bind<string>("Compatibility", "Disabled bodies", "", "Comma-separated body prefab names to leave on vanilla sprint behavior.");
			fovMode = ((BaseUnityPlugin)this).Config.Bind<string>("Camera", "Sprint FOV", "Always", new ConfigDescription("Always keeps sprint FOV; Never keeps walking FOV; Vanilla follows actual sprint state.", (AcceptableValueBase)(object)new AcceptableValueList<string>(new string[3] { "Always", "Never", "Vanilla" }), Array.Empty<object>()));
			harmony = new Harmony("local.ror2.alwaysautosprint");
			harmony.Patch((MethodBase)AccessTools.Method(typeof(PlayerCharacterMasterController), "PollButtonInput", (Type[])null, (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, new HarmonyMethod(typeof(Plugin), "SprintInput", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null);
			harmony.Patch((MethodBase)AccessTools.Method(typeof(CameraModePlayerBasic), "UpdateInternal", (Type[])null, (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, new HarmonyMethod(typeof(Plugin), "CameraFov", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null);
			((BaseUnityPlugin)this).Logger.LogInfo((object)"Always Auto Sprint loaded using the Hallowed Concepts button input path.");
		}

		private static IEnumerable<CodeInstruction> SprintInput(IEnumerable<CodeInstruction> source)
		{
			//IL_00d4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00da: Expected O, but got Unknown
			//IL_00e2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e8: Expected O, but got Unknown
			List<CodeInstruction> list = new List<CodeInstruction>(source);
			FieldInfo objB = AccessTools.Field(typeof(InputBankTest), "sprint");
			MethodInfo methodInfo = AccessTools.Method(typeof(ButtonState), "PushState", (Type[])null, (Type[])null);
			MethodInfo methodInfo2 = AccessTools.Method(typeof(Plugin), "ChooseSprint", (Type[])null, (Type[])null);
			bool flag = false;
			for (int i = 0; i < list.Count; i++)
			{
				if (list[i].opcode == OpCodes.Ldflda && object.Equals(list[i].operand, objB))
				{
					int j;
					for (j = i + 1; j < list.Count && !CodeInstructionExtensions.Calls(list[j], methodInfo); j++)
					{
					}
					if (j >= list.Count)
					{
						throw new InvalidOperationException("Sprint input write not found; refusing an incomplete patch.");
					}
					list.InsertRange(j, (IEnumerable<CodeInstruction>)(object)new CodeInstruction[2]
					{
						new CodeInstruction(OpCodes.Ldarg_0, (object)null),
						new CodeInstruction(OpCodes.Call, (object)methodInfo2)
					});
					flag = true;
					break;
				}
			}
			if (!flag)
			{
				throw new InvalidOperationException("Sprint input field not found; game input layout changed.");
			}
			((BaseUnityPlugin)instance).Logger.LogInfo((object)"Installed sprint input filter (one sprint PushState per poll).");
			return list;
		}

		public static bool ChooseSprint(bool vanilla, PlayerCharacterMasterController controller)
		{
			if (!instance.modEnabled.Value || !controller.hasEffectiveAuthority)
			{
				return vanilla;
			}
			CharacterMaster master = controller.master;
			CharacterBody val = ((master != null) ? master.GetBody() : null);
			NetworkUser networkUser = controller.networkUser;
			if (!Object.op_Implicit((Object)(object)val) || !Object.op_Implicit((Object)(object)val.inputBank) || !Object.op_Implicit((Object)(object)networkUser) || networkUser.localUser == null || val.isRemoteOp || Listed(instance.disabledBodies.Value, ((Object)val).name.Replace("(Clone)", "")))
			{
				return vanilla;
			}
			if (networkUser.localUser.isUIFocused || !Object.op_Implicit((Object)(object)networkUser.cameraRigController) || !networkUser.cameraRigController.isControlAllowed)
			{
				return vanilla;
			}
			if (instance.holdToWalk.Value && networkUser.inputPlayer != null && networkUser.inputPlayer.GetButton(18))
			{
				return false;
			}
			if (((Vector3)(ref val.inputBank.moveVector)).sqrMagnitude < 0.001f)
			{
				return false;
			}
			Recovery value = recoveries.GetValue(val, (CharacterBody _) => new Recovery());
			bool flag = false;
			if (value.skills == null)
			{
				value.skills = ((Component)val).GetComponents<GenericSkill>();
				value.machines = ((Component)val).GetComponents<EntityStateMachine>();
			}
			if (value.skills != null)
			{
				GenericSkill[] skills = value.skills;
				foreach (GenericSkill val2 in skills)
				{
					if (Object.op_Implicit((Object)(object)val2) && Object.op_Implicit((Object)(object)val2.skillDef) && Object.op_Implicit((Object)(object)val2.stateMachine) && !val2.stateMachine.IsInMainState())
					{
						SkillDef skillDef = val2.skillDef;
						if (!skillDef.forceSprintDuringState && (skillDef.cancelSprintingOnActivation || skillDef.canceledFromSprinting))
						{
							flag = true;
							break;
						}
					}
				}
			}
			EntityStateMachine[] machines = value.machines;
			foreach (EntityStateMachine val3 in machines)
			{
				if (val3.state != null && Listed(instance.disabledStates.Value, ((object)val3.state).GetType().FullName))
				{
					flag = true;
					break;
				}
			}
			if (flag)
			{
				value.until = Time.fixedTime + instance.resumeDelay.Value;
				return false;
			}
			return Time.fixedTime >= value.until;
		}

		private static bool Listed(string list, string name)
		{
			string[] array = list.Split(',');
			for (int i = 0; i < array.Length; i++)
			{
				if (array[i].Trim().Equals(name, StringComparison.Ordinal))
				{
					return true;
				}
			}
			return false;
		}

		private static IEnumerable<CodeInstruction> CameraFov(IEnumerable<CodeInstruction> source)
		{
			bool applied = false;
			foreach (CodeInstruction instruction in source)
			{
				yield return instruction;
				if (!applied && instruction.opcode == OpCodes.Ldfld && instruction.operand is FieldInfo { Name: "isSprinting" })
				{
					yield return new CodeInstruction(OpCodes.Call, (object)AccessTools.Method(typeof(Plugin), "ChooseFov", (Type[])null, (Type[])null));
					applied = true;
				}
			}
			if (!applied)
			{
				throw new InvalidOperationException("Sprint FOV branch not found.");
			}
		}

		public static bool ChooseFov(bool vanilla)
		{
			if (instance.modEnabled.Value && !(instance.fovMode.Value == "Vanilla"))
			{
				return instance.fovMode.Value == "Always";
			}
			return vanilla;
		}

		private void OnDestroy()
		{
			Harmony obj = harmony;
			if (obj != null)
			{
				obj.UnpatchSelf();
			}
			if ((Object)(object)instance == (Object)(object)this)
			{
				instance = null;
			}
		}
	}
}