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;
}
}
}