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 HqExtra v1.0.1
HqExtra.dll
Decompiled 2 months agousing 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; } } }