Decompiled source of HqExtra v1.0.1

HqExtra.dll

Decompiled 2 months ago
using 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 BepInEx.Logging;
using GameNetcodeStuff;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using TMPro;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.UI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: AssemblyTitle("HqExtra")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("HqExtra")]
[assembly: AssemblyCopyright("Copyright ©  2023")]
[assembly: AssemblyTrademark("")]
[assembly: ComVisible(false)]
[assembly: Guid("c9dfa95d-75b1-4796-9f58-e9aa57cedc41")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyVersion("1.0.0.0")]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.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 j_red
{
	public class ModConfig
	{
		public ConfigEntry<bool> headBobbing;

		public ConfigEntry<bool> toggleSprint;
	}
	[BepInPlugin("asta.HqExtra", "HqExtra", "1.0.0")]
	public class ModBase : BaseUnityPlugin
	{
		private const string GUID = "asta.HqExtra";

		private const string ModName = "HqExtra";

		private const string ModVersion = "1.0.0";

		private readonly Harmony harmony = new Harmony("asta.HqExtra");

		private static ModBase Instance;

		public static ModConfig config;

		internal ManualLogSource logger;

		internal static ManualLogSource Log => Instance?.logger;

		private void Awake()
		{
			if ((Object)(object)Instance == (Object)null)
			{
				Instance = this;
				config = new ModConfig();
				config.toggleSprint = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "Toggle Sprint", false, "If sprinting should toggle on key press instead of requiring the key to be held.");
				config.headBobbing = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "Head Bobbing", true, "If head bobbing should be enabled.");
			}
			logger = Logger.CreateLogSource("asta.HqExtra");
			logger.LogInfo((object)"HqExtra v1.0.0 initialized.");
			harmony.PatchAll();
		}
	}
}
namespace j_red.Patches
{
	[HarmonyPatch(typeof(PlayerControllerB))]
	internal class PlayerControllerBPatch
	{
		public static Camera playerCam = null;

		private static float initialFov;

		private static readonly Vector3 cameraRotation = new Vector3(90f, 0f, 0f);

		[HarmonyPatch("Awake")]
		[HarmonyPostfix]
		private static void CacheCameraContainer(ref PlayerControllerB __instance)
		{
			Transform transform = ((Component)__instance).transform;
			playerCam = ((Component)transform.Find("ScavengerModel/metarig/CameraContainer/MainCamera")).GetComponent<Camera>();
			initialFov = playerCam.fieldOfView;
		}

		[HarmonyPatch("LateUpdate")]
		[HarmonyPrefix]
		private static void LateUpdatePatch(ref PlayerControllerB __instance)
		{
			//IL_004a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0060: Unknown result type (might be due to invalid IL or missing references)
			//IL_0071: Unknown result type (might be due to invalid IL or missing references)
			//IL_007b: Unknown result type (might be due to invalid IL or missing references)
			//IL_008d: 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)
			if (!__instance.inTerminalMenu && !__instance.inSpecialInteractAnimation && !__instance.playingQuickSpecialAnimation && !ModBase.config.headBobbing.Value)
			{
				__instance.cameraContainerTransform.position = new Vector3(__instance.cameraContainerTransform.position.x, ((Component)__instance.playerModelArmsMetarig).transform.position.y, __instance.cameraContainerTransform.position.z);
				__instance.cameraContainerTransform.localRotation = Quaternion.Euler(cameraRotation);
			}
		}
	}
	[HarmonyPatch]
	internal static class SettingsMenuPatch
	{
		private const string ClonePrefix = "Accessibility_";

		private const float VerticalSpacing = 25f;

		private static bool hasLoggedSuccessfulInjection;

		private static bool hasLoggedMissingTemplate;

		private static readonly Dictionary<ConfigEntry<bool>, bool> PendingValues = new Dictionary<ConfigEntry<bool>, bool>();

		[HarmonyPatch(typeof(QuickMenuManager), "OpenQuickMenu")]
		[HarmonyPostfix]
		private static void InjectSettingsOnQuickMenuOpen(QuickMenuManager __instance)
		{
			ManualLogSource log = ModBase.Log;
			if (log != null)
			{
				log.LogInfo((object)"QuickMenuManager.OpenQuickMenu called.");
			}
			object settingsPanelRoot;
			if (!((Object)(object)__instance != (Object)null))
			{
				settingsPanelRoot = null;
			}
			else
			{
				GameObject settingsPanel = __instance.settingsPanel;
				settingsPanelRoot = ((settingsPanel != null) ? settingsPanel.transform : null);
			}
			EnsureInjected((Transform)settingsPanelRoot, "QuickMenu");
		}

		[HarmonyPatch(typeof(MenuManager), "EnableUIPanel")]
		[HarmonyPostfix]
		private static void InjectSettingsOnEnablePanel(GameObject enablePanel)
		{
			if (!((Object)(object)enablePanel == (Object)null))
			{
				ManualLogSource log = ModBase.Log;
				if (log != null)
				{
					log.LogInfo((object)("MenuManager.EnableUIPanel called for: " + ((Object)enablePanel).name));
				}
				if (((Object)enablePanel).name == "SettingsPanel")
				{
					EnsureInjected(enablePanel.transform, "MainMenu");
				}
			}
		}

		[HarmonyPatch(typeof(IngamePlayerSettings), "SaveChangedSettings")]
		[HarmonyPostfix]
		private static void ApplyPendingSettingsOnConfirm()
		{
			ApplyPendingValues();
		}

		[HarmonyPatch(typeof(IngamePlayerSettings), "DiscardChangedSettings")]
		[HarmonyPostfix]
		private static void DiscardPendingSettingsOnCancel()
		{
			DiscardPendingValues();
		}

		internal static void EnsureInjected(Transform settingsPanelRoot, string source)
		{
			if (ModBase.config == null || (Object)(object)settingsPanelRoot == (Object)null)
			{
				return;
			}
			GameObject val = FindTemplateToggle(settingsPanelRoot);
			if ((Object)(object)val == (Object)null)
			{
				if (!hasLoggedMissingTemplate)
				{
					ManualLogSource log = ModBase.Log;
					if (log != null)
					{
						log.LogInfo((object)("ControlsOptions template toggle not found in " + source + " settings panel."));
					}
					DumpControlsOptionsCandidates(settingsPanelRoot);
					hasLoggedMissingTemplate = true;
				}
				return;
			}
			hasLoggedMissingTemplate = false;
			Transform parent = val.transform.parent;
			if ((Object)(object)parent == (Object)null)
			{
				return;
			}
			LayoutAnchor orCreateLayoutAnchor = GetOrCreateLayoutAnchor(val);
			float baseAnchoredY = orCreateLayoutAnchor.BaseAnchoredY;
			int baseSiblingIndex = orCreateLayoutAnchor.BaseSiblingIndex;
			CreateOrRefreshToggle(parent, val, "ToggleSprint", "Toggle Sprint", ModBase.config.toggleSprint, baseAnchoredY, baseSiblingIndex);
			CreateOrRefreshToggle(parent, val, "HeadBobbing", "Head Bobbing", ModBase.config.headBobbing, baseAnchoredY - 25f, baseSiblingIndex + 1);
			RepositionOriginal(val, baseAnchoredY - 50f, baseSiblingIndex + 2);
			RemoveInjectedToggle(parent, "LockFOV");
			RemoveInjectedToggle(parent, "DisableMotionSway");
			RectTransform val2 = (RectTransform)(object)((parent is RectTransform) ? parent : null);
			if (val2 != null)
			{
				LayoutRebuilder.ForceRebuildLayoutImmediate(val2);
			}
			if (!hasLoggedSuccessfulInjection)
			{
				ManualLogSource log2 = ModBase.Log;
				if (log2 != null)
				{
					log2.LogInfo((object)("Accessibility toggles injected under ControlsOptions from " + source + "."));
				}
				hasLoggedSuccessfulInjection = true;
			}
		}

		private static GameObject FindTemplateToggle(Transform settingsPanelRoot)
		{
			Transform[] componentsInChildren = ((Component)settingsPanelRoot).GetComponentsInChildren<Transform>(true);
			foreach (Transform val in componentsInChildren)
			{
				if (!((Object)(object)val == (Object)null) && !(((Object)val).name != "ControlsOptions"))
				{
					GameObject val2 = FindPreferredTemplate(val);
					if ((Object)(object)val2 != (Object)null)
					{
						return val2;
					}
				}
			}
			return null;
		}

		private static GameObject FindPreferredTemplate(Transform controlsOptions)
		{
			GameObject val = null;
			for (int i = 0; i < controlsOptions.childCount; i++)
			{
				Transform child = controlsOptions.GetChild(i);
				if ((Object)(object)child == (Object)null)
				{
					continue;
				}
				SettingsOption component = ((Component)child).GetComponent<SettingsOption>();
				TextMeshProUGUI componentInChildren = ((Component)child).GetComponentInChildren<TextMeshProUGUI>(true);
				if (!((Object)(object)component == (Object)null) && !((Object)(object)componentInChildren == (Object)null))
				{
					if ((Object)(object)val == (Object)null)
					{
						val = ((Component)child).gameObject;
					}
					string text = ((Object)child).name ?? string.Empty;
					string text2 = ((TMP_Text)componentInChildren).text ?? string.Empty;
					if (text.Contains("Arachn") || text2.Contains("Arachn"))
					{
						return ((Component)child).gameObject;
					}
				}
			}
			return val;
		}

		private static void DumpControlsOptionsCandidates(Transform settingsPanelRoot)
		{
			Transform[] componentsInChildren = ((Component)settingsPanelRoot).GetComponentsInChildren<Transform>(true);
			int num = 0;
			foreach (Transform val in componentsInChildren)
			{
				if ((Object)(object)val == (Object)null || ((Object)val).name != "ControlsOptions")
				{
					continue;
				}
				num++;
				ManualLogSource log = ModBase.Log;
				if (log != null)
				{
					log.LogInfo((object)("Found ControlsOptions: " + GetTransformPath(val)));
				}
				for (int j = 0; j < val.childCount; j++)
				{
					Transform child = val.GetChild(j);
					TextMeshProUGUI val2 = (((Object)(object)child != (Object)null) ? ((Component)child).GetComponentInChildren<TextMeshProUGUI>(true) : null);
					SettingsOption val3 = (((Object)(object)child != (Object)null) ? ((Component)child).GetComponent<SettingsOption>() : null);
					string text = (((Object)(object)val2 != (Object)null) ? ((TMP_Text)val2).text : "<no text>");
					ManualLogSource log2 = ModBase.Log;
					if (log2 != null)
					{
						log2.LogInfo((object)("ControlsOptions child: " + ((child != null) ? ((Object)child).name : null) + " | text=" + text + " | settingsOption=" + ((Object)(object)val3 != (Object)null)));
					}
				}
			}
			ManualLogSource log3 = ModBase.Log;
			if (log3 != null)
			{
				log3.LogInfo((object)("ControlsOptions count: " + num));
			}
		}

		private static string GetTransformPath(Transform transform)
		{
			string text = ((Object)transform).name;
			Transform parent = transform.parent;
			while ((Object)(object)parent != (Object)null)
			{
				text = ((Object)parent).name + "/" + text;
				parent = parent.parent;
			}
			return text;
		}

		private static void CreateOrRefreshToggle(Transform parent, GameObject original, string id, string label, ConfigEntry<bool> entry, float targetY, int targetSiblingIndex)
		{
			string text = "Accessibility_" + id;
			Transform val = parent.Find(text);
			if ((Object)(object)val != (Object)null)
			{
				ModSettingsToggle component = ((Component)val).GetComponent<ModSettingsToggle>();
				if ((Object)(object)component != (Object)null)
				{
					component.Refresh();
				}
				UpdatePosition(((Component)val).gameObject, original, targetY);
				val.SetSiblingIndex(Mathf.Max(0, targetSiblingIndex));
				return;
			}
			GameObject val2 = Object.Instantiate<GameObject>(original, parent);
			((Object)val2).name = text;
			SetLabel(val2, label);
			ReplaceToggleBehaviour(val2, entry, label);
			UpdatePosition(val2, original, targetY);
			val2.transform.SetSiblingIndex(Mathf.Max(0, targetSiblingIndex));
			ManualLogSource log = ModBase.Log;
			if (log != null)
			{
				log.LogInfo((object)("Added settings toggle: " + text));
			}
		}

		private static void RemoveInjectedToggle(Transform parent, string id)
		{
			Transform val = parent.Find("Accessibility_" + id);
			if ((Object)(object)val != (Object)null)
			{
				Object.Destroy((Object)(object)((Component)val).gameObject);
			}
		}

		private static void SetLabel(GameObject clone, string label)
		{
			TextMeshProUGUI[] componentsInChildren = clone.GetComponentsInChildren<TextMeshProUGUI>(true);
			if (componentsInChildren != null && componentsInChildren.Length != 0)
			{
				((TMP_Text)componentsInChildren[0]).text = label;
			}
		}

		private static void ReplaceToggleBehaviour(GameObject clone, ConfigEntry<bool> entry, string label)
		{
			SettingsOption component = clone.GetComponent<SettingsOption>();
			TMP_Text text = (TMP_Text)(object)(((Object)(object)component != (Object)null) ? component.textElement : clone.GetComponentInChildren<TextMeshProUGUI>(true));
			Image val = (((Object)(object)component != (Object)null) ? component.toggleImage : FindBestToggleImage(clone));
			Sprite enabled = (((Object)(object)component != (Object)null) ? component.enabledImage : null);
			Sprite disabled = (((Object)(object)component != (Object)null) ? component.disabledImage : null);
			SettingsOption[] componentsInChildren = clone.GetComponentsInChildren<SettingsOption>(true);
			foreach (SettingsOption val2 in componentsInChildren)
			{
				Object.DestroyImmediate((Object)(object)val2);
			}
			if ((Object)(object)val == (Object)null)
			{
				ManualLogSource log = ModBase.Log;
				if (log != null)
				{
					log.LogWarning((object)("Toggle image not found for " + label));
				}
				return;
			}
			ModSettingsToggle modSettingsToggle = clone.GetComponent<ModSettingsToggle>();
			if ((Object)(object)modSettingsToggle == (Object)null)
			{
				modSettingsToggle = clone.AddComponent<ModSettingsToggle>();
			}
			modSettingsToggle.Initialize(entry, label, text, val, enabled, disabled);
			modSettingsToggle.Refresh();
		}

		private static Image FindBestToggleImage(GameObject clone)
		{
			Image[] componentsInChildren = clone.GetComponentsInChildren<Image>(true);
			for (int num = componentsInChildren.Length - 1; num >= 0; num--)
			{
				Image val = componentsInChildren[num];
				if ((Object)(object)val != (Object)null && (Object)(object)((Component)val).gameObject != (Object)(object)clone)
				{
					return val;
				}
			}
			return clone.GetComponentInChildren<Image>(true);
		}

		internal static bool GetCurrentValue(ConfigEntry<bool> entry)
		{
			if (entry == null)
			{
				return false;
			}
			bool value;
			return PendingValues.TryGetValue(entry, out value) ? value : entry.Value;
		}

		internal static void TogglePendingValue(ConfigEntry<bool> entry)
		{
			if (entry != null)
			{
				bool value = !GetCurrentValue(entry);
				PendingValues[entry] = value;
				MarkSettingsDirty();
				RefreshAllInjectedToggles();
			}
		}

		private static void ApplyPendingValues()
		{
			if (PendingValues.Count == 0)
			{
				return;
			}
			foreach (KeyValuePair<ConfigEntry<bool>, bool> pendingValue in PendingValues)
			{
				pendingValue.Key.Value = pendingValue.Value;
				ManualLogSource log = ModBase.Log;
				if (log != null)
				{
					log.LogInfo((object)("Applied setting on confirm: " + ((ConfigEntryBase)pendingValue.Key).Definition.Key + " -> " + pendingValue.Value));
				}
			}
			PendingValues.Clear();
			RefreshAllInjectedToggles();
		}

		private static void DiscardPendingValues()
		{
			if (PendingValues.Count != 0)
			{
				ManualLogSource log = ModBase.Log;
				if (log != null)
				{
					log.LogInfo((object)"Discarded pending settings changes.");
				}
				PendingValues.Clear();
				RefreshAllInjectedToggles();
			}
		}

		private static void MarkSettingsDirty()
		{
			IngamePlayerSettings instance = IngamePlayerSettings.Instance;
			if (!((Object)(object)instance == (Object)null))
			{
				Traverse.Create((object)instance).Field("changesNotApplied").SetValue((object)true);
				AccessTools.Method(typeof(IngamePlayerSettings), "SetChangesNotAppliedTextVisible", (Type[])null, (Type[])null)?.Invoke(instance, new object[1] { true });
			}
		}

		private static void RefreshAllInjectedToggles()
		{
			ModSettingsToggle[] array = Object.FindObjectsOfType<ModSettingsToggle>(true);
			for (int i = 0; i < array.Length; i++)
			{
				array[i].Refresh();
			}
		}

		private static void RepositionOriginal(GameObject original, float targetY, int targetSiblingIndex)
		{
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			RectTransform component = original.GetComponent<RectTransform>();
			if (!((Object)(object)component == (Object)null))
			{
				component.anchoredPosition = new Vector2(component.anchoredPosition.x, targetY);
				original.transform.SetSiblingIndex(Mathf.Max(0, targetSiblingIndex));
			}
		}

		private static void UpdatePosition(GameObject clone, GameObject original, float targetY)
		{
			//IL_002b: 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_0045: Unknown result type (might be due to invalid IL or missing references)
			//IL_0052: Unknown result type (might be due to invalid IL or missing references)
			//IL_005f: Unknown result type (might be due to invalid IL or missing references)
			//IL_006a: Unknown result type (might be due to invalid IL or missing references)
			RectTransform component = clone.GetComponent<RectTransform>();
			RectTransform component2 = original.GetComponent<RectTransform>();
			if (!((Object)(object)component == (Object)null) && !((Object)(object)component2 == (Object)null))
			{
				component.anchorMin = component2.anchorMin;
				component.anchorMax = component2.anchorMax;
				component.pivot = component2.pivot;
				component.sizeDelta = component2.sizeDelta;
				component.anchoredPosition = new Vector2(component2.anchoredPosition.x, targetY);
			}
		}

		private static LayoutAnchor GetOrCreateLayoutAnchor(GameObject original)
		{
			//IL_0038: Unknown result type (might be due to invalid IL or missing references)
			LayoutAnchor component = original.GetComponent<LayoutAnchor>();
			if ((Object)(object)component != (Object)null)
			{
				return component;
			}
			RectTransform component2 = original.GetComponent<RectTransform>();
			component = original.AddComponent<LayoutAnchor>();
			component.BaseAnchoredY = (((Object)(object)component2 != (Object)null) ? component2.anchoredPosition.y : 0f);
			component.BaseSiblingIndex = original.transform.GetSiblingIndex();
			return component;
		}
	}
	internal sealed class ModSettingsToggle : MonoBehaviour, IPointerClickHandler, IEventSystemHandler, ISubmitHandler
	{
		private ConfigEntry<bool> configEntry;

		private string label;

		private TMP_Text labelText;

		private Image toggleImage;

		private Sprite enabledSprite;

		private Sprite disabledSprite;

		internal void Initialize(ConfigEntry<bool> entry, string labelValue, TMP_Text text, Image image, Sprite enabled, Sprite disabled)
		{
			configEntry = entry;
			label = labelValue;
			labelText = text;
			toggleImage = image;
			enabledSprite = enabled;
			disabledSprite = disabled;
		}

		public void OnPointerClick(PointerEventData eventData)
		{
			ToggleValue();
		}

		public void OnSubmit(BaseEventData eventData)
		{
			ToggleValue();
		}

		private void ToggleValue()
		{
			if (configEntry != null)
			{
				SettingsMenuPatch.TogglePendingValue(configEntry);
				ManualLogSource log = ModBase.Log;
				if (log != null)
				{
					log.LogInfo((object)(label + " pending -> " + SettingsMenuPatch.GetCurrentValue(configEntry)));
				}
			}
		}

		internal void Refresh()
		{
			if (configEntry != null)
			{
				if ((Object)(object)labelText != (Object)null)
				{
					labelText.text = label;
				}
				if ((Object)(object)toggleImage != (Object)null)
				{
					bool currentValue = SettingsMenuPatch.GetCurrentValue(configEntry);
					toggleImage.sprite = (currentValue ? enabledSprite : disabledSprite);
				}
			}
		}

		private void OnEnable()
		{
			Refresh();
		}
	}
	internal sealed class LayoutAnchor : MonoBehaviour
	{
		internal float BaseAnchoredY;

		internal int BaseSiblingIndex;
	}
	[HarmonyPatch(typeof(PlayerControllerB))]
	internal static class ToggleSprintPatch
	{
		private static readonly CodeSearch SprintLookupSearch = new CodeSearch(new CodeSearchDescriptor((CodeInstruction i) => i.opcode == OpCodes.Call && i.operand != null && i.operand.ToString().Contains("IngamePlayerSettings")), new CodeSearchDescriptor((CodeInstruction i) => i.opcode == OpCodes.Stloc_0), new CodeSearchDescriptor[3]
		{
			new CodeSearchDescriptor((CodeInstruction i) => i.opcode == OpCodes.Ldstr && i.operand != null && i.operand.ToString().Contains("Sprint")),
			new CodeSearchDescriptor((CodeInstruction i) => i.opcode == OpCodes.Callvirt && i.operand != null && i.operand.ToString().Contains("FindAction")),
			new CodeSearchDescriptor((CodeInstruction i) => i.opcode == OpCodes.Callvirt && i.operand != null && i.operand.ToString().Contains("ReadValue"))
		});

		private static readonly Dictionary<PlayerControllerB, bool> SprintToggled = new Dictionary<PlayerControllerB, bool>();

		private static readonly Dictionary<PlayerControllerB, bool> WasPressedLastFrame = new Dictionary<PlayerControllerB, bool>();

		private static float GetSprintInput(PlayerControllerB instance)
		{
			//IL_0047: Unknown result type (might be due to invalid IL or missing references)
			//IL_004c: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)instance == (Object)null)
			{
				return 0f;
			}
			if (!ModBase.config.toggleSprint.Value || !SprintToggled.TryGetValue(instance, out var value) || !value)
			{
				MovementActions movement = instance.playerActions.Movement;
				return ((MovementActions)(ref movement)).Sprint.ReadValue<float>();
			}
			return 1f;
		}

		private static bool SprintIsTogglable(PlayerControllerB player)
		{
			//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)
			if ((Object)(object)player == (Object)null || (Object)(object)IngamePlayerSettings.Instance == (Object)null)
			{
				return false;
			}
			Vector2 val = IngamePlayerSettings.Instance.playerInput.actions.FindAction("Move", false).ReadValue<Vector2>();
			if (((Vector2)(ref val)).sqrMagnitude < 0.05f)
			{
				return false;
			}
			if (player.inTerminalMenu || player.isTypingChat || player.inSpecialInteractAnimation || player.playingQuickSpecialAnimation)
			{
				return false;
			}
			return true;
		}

		[HarmonyPatch("Start")]
		[HarmonyPostfix]
		private static void StartPostfix(PlayerControllerB __instance)
		{
			SprintToggled[__instance] = false;
			WasPressedLastFrame[__instance] = false;
		}

		[HarmonyPatch("OnDisable")]
		[HarmonyPostfix]
		private static void OnDisablePostfix(PlayerControllerB __instance)
		{
			SprintToggled.Remove(__instance);
			WasPressedLastFrame.Remove(__instance);
		}

		[HarmonyPatch("Update")]
		[HarmonyPrefix]
		private static void UpdatePrefix(PlayerControllerB __instance)
		{
			if ((Object)(object)__instance == (Object)null || !__instance.isPlayerControlled)
			{
				return;
			}
			if (!SprintToggled.ContainsKey(__instance))
			{
				SprintToggled[__instance] = false;
			}
			if (!WasPressedLastFrame.ContainsKey(__instance))
			{
				WasPressedLastFrame[__instance] = false;
			}
			if (!ModBase.config.toggleSprint.Value)
			{
				SprintToggled[__instance] = false;
				WasPressedLastFrame[__instance] = false;
				return;
			}
			if (!SprintIsTogglable(__instance))
			{
				if (SprintToggled[__instance])
				{
					SprintToggled[__instance] = false;
					WasPressedLastFrame[__instance] = false;
				}
				return;
			}
			float num = IngamePlayerSettings.Instance.playerInput.actions.FindAction("Sprint", false).ReadValue<float>();
			if (num > 0.3f)
			{
				if (!WasPressedLastFrame[__instance])
				{
					SprintToggled[__instance] = !SprintToggled[__instance];
					WasPressedLastFrame[__instance] = true;
					ManualLogSource log = ModBase.Log;
					if (log != null)
					{
						log.LogInfo((object)("Toggle Sprint -> " + SprintToggled[__instance]));
					}
				}
			}
			else
			{
				WasPressedLastFrame[__instance] = false;
			}
		}

		[HarmonyPatch("Update")]
		[HarmonyTranspiler]
		private static IEnumerable<CodeInstruction> UpdateTranspiler(IEnumerable<CodeInstruction> instructions)
		{
			//IL_008b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0095: Expected O, but got Unknown
			//IL_00ba: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c4: Expected O, but got Unknown
			List<CodeInstruction> list = new List<CodeInstruction>(instructions);
			Tuple<int, int> tuple = SprintLookupSearch.FindPatch(list);
			if (tuple == null)
			{
				ManualLogSource log = ModBase.Log;
				if (log != null)
				{
					log.LogWarning((object)"Toggle Sprint transpiler could not find sprint lookup in PlayerControllerB.Update.");
				}
				return list;
			}
			for (int i = tuple.Item1; i < tuple.Item2; i++)
			{
				list[i].opcode = OpCodes.Nop;
				list[i].operand = null;
			}
			list[tuple.Item2 - 2] = new CodeInstruction(OpCodes.Ldarg_0, (object)null);
			list[tuple.Item2 - 1] = new CodeInstruction(OpCodes.Call, (object)AccessTools.Method(typeof(ToggleSprintPatch), "GetSprintInput", (Type[])null, (Type[])null));
			ManualLogSource log2 = ModBase.Log;
			if (log2 != null)
			{
				log2.LogInfo((object)"Toggle Sprint transpiler patched PlayerControllerB.Update.");
			}
			return list;
		}
	}
	internal sealed class CodeSearchDescriptor
	{
		private readonly Func<CodeInstruction, bool> matchFunction;

		internal CodeSearchDescriptor(Func<CodeInstruction, bool> matchFunction)
		{
			this.matchFunction = matchFunction ?? throw new ArgumentNullException("matchFunction");
		}

		internal bool Matches(CodeInstruction instruction)
		{
			return matchFunction(instruction);
		}
	}
	internal sealed class CodeSearch
	{
		private readonly CodeSearchDescriptor start;

		private readonly CodeSearchDescriptor end;

		private readonly IReadOnlyList<CodeSearchDescriptor> validators;

		internal CodeSearch(CodeSearchDescriptor start, CodeSearchDescriptor end, IReadOnlyList<CodeSearchDescriptor> validators)
		{
			this.start = start ?? throw new ArgumentNullException("start");
			this.end = end ?? throw new ArgumentNullException("end");
			this.validators = validators;
		}

		internal Tuple<int, int> FindPatch(List<CodeInstruction> instructions)
		{
			int? num = null;
			int? num2 = null;
			int num3 = 0;
			if (instructions == null)
			{
				return null;
			}
			for (int i = 0; i < instructions.Count; i++)
			{
				CodeInstruction val = instructions[i];
				if (val != null)
				{
					if (start.Matches(val))
					{
						num = i;
						num3 = 0;
					}
					if (num.HasValue && validators != null && num3 < validators.Count && validators[num3].Matches(val))
					{
						num3++;
					}
					if (end.Matches(val) && num.HasValue && (validators == null || num3 >= validators.Count))
					{
						num2 = i;
						break;
					}
				}
			}
			return (num.HasValue && num2.HasValue) ? new Tuple<int, int>(num.Value, num2.Value) : null;
		}
	}
}