Decompiled source of AutoGrabClimb v1.0.4

AutoGrabClimb.dll

Decompiled a week ago
using System;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using BepInEx;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using UnityEngine;
using UnityEngine.InputSystem;
using Zorro.ControllerSupport;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: AssemblyTitle("PEAK Auto Grab Climb")]
[assembly: AssemblyDescription("Automatic grab-release climbing with terrain-aware vanilla fallback for PEAK.")]
[assembly: AssemblyCompany("TaXueXuex")]
[assembly: AssemblyProduct("PEAK Auto Grab Climb")]
[assembly: AssemblyCopyright("Copyright © 2026 TaXueXuex")]
[assembly: AssemblyFileVersion("1.0.4.0")]
[assembly: AssemblyInformationalVersion("1.0.4 (2026-09-13)")]
[assembly: AssemblyMetadata("Author", "TaXueXuex")]
[assembly: AssemblyMetadata("ReleaseDate", "2026-09-13")]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyVersion("1.0.4.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 TaXueXuex.AutoGrabClimb
{
	[BepInPlugin("TaXueXuex.AutoGrabClimb", "Auto Grab Climb", "1.0.4")]
	public sealed class Plugin : BaseUnityPlugin
	{
		private enum CyclePhase
		{
			Idle,
			Grab,
			Release
		}

		public const string PluginGuid = "TaXueXuex.AutoGrabClimb";

		public const string PluginName = "Auto Grab Climb";

		public const string PluginVersion = "1.0.4";

		public const string AuthorName = "TaXueXuex";

		public const string ReleaseDate = "2026-09-13";

		private const KeyCode ToggleKey = (KeyCode)291;

		private const int GrabPhysicsTicks = 7;

		private const int ReleasePhysicsTicks = 12;

		private const int ConfirmationTimeoutTicks = 4;

		private const float PeakWallRegrabCooldownSeconds = 0.2f;

		private const float RegrabPitchDegrees = 1f;

		private const float FavorableSlopeAimCompensation = 1f;

		private const float WallAngleDeadZoneDegrees = 1f;

		private const float OverhangFallbackDegrees = 1f;

		private const float AutoResumeDegrees = 0.25f;

		private const float AutoResumeConfirmationSeconds = 0.05f;

		private const float InitialHoldConfirmationSeconds = 0.14f;

		internal static Plugin Instance;

		internal static bool ModeEnabled;

		private Harmony _harmony;

		private CharacterClimbing _activeClimbing;

		private bool _overridingInput;

		private CyclePhase _phase;

		private int _phaseFixedSteps;

		private int _effectiveGrabTicks;

		private int _effectiveReleaseTicks;

		private bool _grabConfirmed;

		private bool _releaseRequested;

		private bool _grabRequested;

		private bool _retryGrabRequested;

		private bool _retryReleaseRequested;

		private bool _regrabTimingReady;

		private bool _restoreLookDirection;

		private CharacterData _lookDirectionOwner;

		private Vector3 _savedLookDirection;

		private bool _releaseSurfaceValid;

		private float _releaseWallDegrees;

		private bool _surfaceBypassActive;

		private float _normalSurfaceCandidateSince = -1f;

		private float _physicalGrabHeldSince = -1f;

		private float _initialPhysicalGrabObservedAt = -1f;

		private bool _automationHoldCommitted;

		private static bool _controllerForwardHeld;

		private float _controllerToggleSince = -1f;

		private bool _controllerToggleConsumed;

		private CharacterClimbing _temporaryToggleOwner;

		private bool _savedClimbToggle;

		private static readonly FieldInfo ClimbToggledOnField = AccessTools.Field(typeof(CharacterClimbing), "climbToggledOn");

		private bool _lastGamepadScheme;

		private bool _loggedRuntimeFailure;

		private string _noticeText;

		private float _noticeUntil;

		private GUIStyle _noticeTitleStyle;

		private GUIStyle _noticeBodyStyle;

		private static readonly FieldInfo ClimbingCharacterField = AccessTools.Field(typeof(CharacterClimbing), "character");

		private static readonly MethodInfo CanDoInputMethod = AccessTools.Method(typeof(Character), "CanDoInput", (Type[])null, (Type[])null);

		private void Awake()
		{
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			//IL_001c: Expected O, but got Unknown
			Instance = this;
			ModeEnabled = false;
			_harmony = new Harmony("TaXueXuex.AutoGrabClimb");
			_harmony.PatchAll();
			((BaseUnityPlugin)this).Logger.LogInfo((object)"Auto Grab Climb 1.0.4 loaded. Author=TaXueXuex, ReleaseDate=2026-09-13, Toggle=F10, default=OFF, G7/R12, Aim=+1deg, SlopeK=1, dynamic terrain routing=ON, keyboard/mouse and native gamepad support=ON");
		}

		private void OnDestroy()
		{
			RestoreControllerClimbToggle();
			RestoreOriginalLookDirection();
			if (_harmony != null)
			{
				_harmony.UnpatchSelf();
			}
			if ((Object)(object)Instance == (Object)(object)this)
			{
				Instance = null;
			}
		}

		private void Update()
		{
			bool flag = IsGamepadInput();
			if (flag != _lastGamepadScheme)
			{
				StopOverriding();
				ResetActivationHold();
				ResetSurfaceRouting();
				_controllerForwardHeld = false;
				_lastGamepadScheme = flag;
			}
			if (!IsMovementChordHeld())
			{
				ResetSurfaceRouting();
				ResetActivationHold();
			}
			else if (!IsPhysicalGrabHeld())
			{
				FinishPhysicalGrabPress();
			}
			bool flag2 = CheckControllerToggle();
			if (Input.GetKeyDown((KeyCode)291) || flag2)
			{
				ModeEnabled = !ModeEnabled;
				StopOverriding();
				ResetActivationHold();
				if (!ModeEnabled)
				{
					ResetSurfaceRouting();
				}
				ShowToggleNotice();
				((BaseUnityPlugin)this).Logger.LogInfo((object)("Auto Grab Climb mode = " + ModeEnabled));
			}
		}

		private void ShowToggleNotice()
		{
			_noticeText = (ModeEnabled ? "Auto Grab Climb: ON\nHold Sprint first, then hold Forward + Grab (keep Sprint held)" : "Auto Grab Climb: OFF");
			_noticeUntil = Time.unscaledTime + 3.5f;
		}

		private void OnGUI()
		{
			//IL_0068: Unknown result type (might be due to invalid IL or missing references)
			//IL_0081: Unknown result type (might be due to invalid IL or missing references)
			//IL_008b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0154: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d1: Unknown result type (might be due to invalid IL or missing references)
			//IL_0112: Unknown result type (might be due to invalid IL or missing references)
			if (!string.IsNullOrEmpty(_noticeText) && !(Time.unscaledTime > _noticeUntil))
			{
				EnsureNoticeStyles();
				float num = Mathf.Min(680f, (float)Screen.width - 32f);
				float num2 = (ModeEnabled ? 72f : 48f);
				Rect val = default(Rect);
				((Rect)(ref val))..ctor(((float)Screen.width - num) * 0.5f, 30f, num, num2);
				Color color = GUI.color;
				GUI.color = new Color(0.06f, 0.06f, 0.06f, 0.92f);
				GUI.Box(val, GUIContent.none);
				GUI.color = color;
				if (ModeEnabled)
				{
					GUI.Label(new Rect(((Rect)(ref val)).x + 14f, ((Rect)(ref val)).y + 7f, ((Rect)(ref val)).width - 28f, 26f), "Auto Grab Climb: ON", _noticeTitleStyle);
					GUI.Label(new Rect(((Rect)(ref val)).x + 14f, ((Rect)(ref val)).y + 35f, ((Rect)(ref val)).width - 28f, 25f), "Hold Sprint first, then hold Forward + Grab (keep Sprint held)", _noticeBodyStyle);
				}
				else
				{
					GUI.Label(new Rect(((Rect)(ref val)).x + 14f, ((Rect)(ref val)).y + 8f, ((Rect)(ref val)).width - 28f, 27f), "Auto Grab Climb: OFF", _noticeTitleStyle);
				}
			}
		}

		private void EnsureNoticeStyles()
		{
			//IL_001c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0026: Expected O, but got Unknown
			//IL_006a: Unknown result type (might be due to invalid IL or missing references)
			//IL_007f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0089: Expected O, but got Unknown
			//IL_00b9: Unknown result type (might be due to invalid IL or missing references)
			if (_noticeTitleStyle == null || _noticeBodyStyle == null)
			{
				_noticeTitleStyle = new GUIStyle(GUI.skin.label);
				_noticeTitleStyle.fontSize = 20;
				_noticeTitleStyle.fontStyle = (FontStyle)1;
				_noticeTitleStyle.alignment = (TextAnchor)4;
				_noticeTitleStyle.normal.textColor = new Color(0.45f, 1f, 0.45f, 1f);
				_noticeBodyStyle = new GUIStyle(GUI.skin.label);
				_noticeBodyStyle.fontSize = 17;
				_noticeBodyStyle.fontStyle = (FontStyle)1;
				_noticeBodyStyle.alignment = (TextAnchor)4;
				_noticeBodyStyle.normal.textColor = Color.white;
			}
		}

		internal void BeforeClimbingUpdate(CharacterClimbing climbing)
		{
			try
			{
				Character localCharacter = Character.localCharacter;
				Character ownerCharacter = GetOwnerCharacter(climbing);
				if ((Object)(object)localCharacter == (Object)null || (Object)(object)ownerCharacter == (Object)null || (Object)(object)ownerCharacter != (Object)(object)localCharacter)
				{
					return;
				}
				if ((Object)(object)_activeClimbing != (Object)(object)climbing)
				{
					_activeClimbing = climbing;
					StopOverriding();
					ResetSurfaceRouting();
					ResetActivationHold();
				}
				CharacterInput input = localCharacter.input;
				if ((Object)(object)input == (Object)null)
				{
					return;
				}
				if (ShouldPreserveOriginalTap(localCharacter))
				{
					StopOverriding();
					return;
				}
				if (ShouldUseVanillaClimbing(localCharacter))
				{
					StopOverriding();
					return;
				}
				if (!IsEligible(localCharacter))
				{
					StopOverriding();
					return;
				}
				PrepareContinuousClimbInput(input);
				if (!_overridingInput || _phase == CyclePhase.Idle)
				{
					if (_automationHoldCommitted && (Object)(object)localCharacter.data != (Object)null && localCharacter.data.isClimbing)
					{
						BeginRelease(localCharacter, input);
					}
					else
					{
						BeginGrab(localCharacter, input);
					}
				}
				else if (_phase == CyclePhase.Grab)
				{
					if (_releaseRequested)
					{
						BeginRelease(localCharacter, input);
					}
					else if (_retryGrabRequested)
					{
						RetryGrab(localCharacter, input);
					}
					else
					{
						ApplyGrabInput(input, pressedEdge: false);
					}
				}
				else if (_grabRequested)
				{
					BeginGrab(localCharacter, input);
				}
				else if (_retryReleaseRequested)
				{
					RetryRelease(input);
				}
				else
				{
					ApplyReleaseInput(input, releasedEdge: false);
				}
				_overridingInput = true;
				PrepareControllerRelease(climbing);
			}
			catch (Exception ex)
			{
				LogRuntimeFailure("update", ex);
			}
		}

		internal void BeforeClimbingFixedUpdate(CharacterClimbing climbing)
		{
			try
			{
				if (!_overridingInput || (Object)(object)climbing != (Object)(object)_activeClimbing)
				{
					return;
				}
				Character localCharacter = Character.localCharacter;
				Character ownerCharacter = GetOwnerCharacter(climbing);
				if (!((Object)(object)localCharacter == (Object)null) && !((Object)(object)ownerCharacter == (Object)null) && !((Object)(object)ownerCharacter != (Object)(object)localCharacter) && !((Object)(object)localCharacter.input == (Object)null) && IsActivationChordHeld())
				{
					if (ShouldPreserveOriginalTap(localCharacter) || ShouldUseVanillaClimbing(localCharacter))
					{
						StopOverriding();
					}
					else
					{
						PrepareContinuousClimbInput(localCharacter.input);
					}
				}
			}
			catch (Exception ex)
			{
				LogRuntimeFailure("physics input", ex);
			}
		}

		internal void AfterClimbingUpdate(CharacterClimbing climbing)
		{
			if ((Object)(object)climbing == (Object)(object)_temporaryToggleOwner)
			{
				RestoreControllerClimbToggle();
			}
			if ((Object)(object)climbing == (Object)(object)_activeClimbing)
			{
				RestoreOriginalLookDirection();
			}
		}

		internal void AfterClimbingFixedUpdate(CharacterClimbing climbing)
		{
			try
			{
				if (!_overridingInput || (Object)(object)climbing != (Object)(object)_activeClimbing)
				{
					return;
				}
				Character localCharacter = Character.localCharacter;
				Character ownerCharacter = GetOwnerCharacter(climbing);
				if ((Object)(object)localCharacter == (Object)null || (Object)(object)ownerCharacter == (Object)null || (Object)(object)ownerCharacter != (Object)(object)localCharacter || (Object)(object)localCharacter.data == (Object)null)
				{
					return;
				}
				_phaseFixedSteps++;
				if (_phase == CyclePhase.Grab)
				{
					if (localCharacter.data.isClimbing)
					{
						_grabConfirmed = true;
						_effectiveGrabTicks++;
						if (_effectiveGrabTicks >= 7)
						{
							_releaseRequested = true;
						}
					}
					else if (_grabConfirmed || _phaseFixedSteps >= 4)
					{
						_retryGrabRequested = true;
					}
				}
				else if (_phase == CyclePhase.Release)
				{
					if (!localCharacter.data.isClimbing)
					{
						_effectiveReleaseTicks++;
						UpdateExactRelease(localCharacter);
					}
					else if (_phaseFixedSteps >= 4)
					{
						_retryReleaseRequested = true;
					}
				}
			}
			catch (Exception ex)
			{
				LogRuntimeFailure("physics state", ex);
			}
		}

		private void BeginGrab(Character local, CharacterInput input)
		{
			_phase = CyclePhase.Grab;
			_phaseFixedSteps = 0;
			_effectiveGrabTicks = 0;
			_effectiveReleaseTicks = 0;
			_grabConfirmed = (Object)(object)local.data != (Object)null && local.data.isClimbing;
			_releaseRequested = false;
			_grabRequested = false;
			_retryGrabRequested = false;
			_retryReleaseRequested = false;
			_regrabTimingReady = false;
			PrimeOriginalGrab(local, input);
		}

		private void RetryGrab(Character local, CharacterInput input)
		{
			_phaseFixedSteps = 0;
			_effectiveGrabTicks = 0;
			_grabConfirmed = (Object)(object)local.data != (Object)null && local.data.isClimbing;
			_retryGrabRequested = false;
			PrimeOriginalGrab(local, input);
		}

		private void BeginRelease(Character local, CharacterInput input)
		{
			_phase = CyclePhase.Release;
			_phaseFixedSteps = 0;
			_effectiveReleaseTicks = 0;
			_releaseRequested = false;
			_grabRequested = false;
			_retryGrabRequested = false;
			_retryReleaseRequested = false;
			_regrabTimingReady = false;
			CaptureReleaseSurface(local);
			ApplyReleaseInput(input, releasedEdge: true);
		}

		private void RetryRelease(CharacterInput input)
		{
			_phaseFixedSteps = 0;
			_retryReleaseRequested = false;
			ApplyReleaseInput(input, releasedEdge: true);
		}

		private static void PrepareContinuousClimbInput(CharacterInput input)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			Vector2 movementInput = input.movementInput;
			movementInput.x = 0f;
			movementInput.y = 1f;
			input.movementInput = movementInput;
		}

		private void PrimeOriginalGrab(Character local, CharacterInput input)
		{
			ApplyGrabInput(input, pressedEdge: true);
			if ((Object)(object)local != (Object)null && (Object)(object)local.data != (Object)null)
			{
				ApplyTemporaryRegrabAim(local.data);
				local.data.sincePressClimb = 0f;
			}
		}

		private void UpdateExactRelease(Character local)
		{
			if (!_regrabTimingReady && _effectiveReleaseTicks >= 12)
			{
				_regrabTimingReady = true;
			}
			if (_regrabTimingReady && !_grabRequested && !(local.data.sinceClimb + 0.0001f < 0.2f))
			{
				_grabRequested = true;
			}
		}

		private void ApplyTemporaryRegrabAim(CharacterData data)
		{
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			//IL_0032: Unknown result type (might be due to invalid IL or missing references)
			//IL_0037: Unknown result type (might be due to invalid IL or missing references)
			//IL_008f: Unknown result type (might be due to invalid IL or missing references)
			//IL_009a: Unknown result type (might be due to invalid IL or missing references)
			//IL_009f: Unknown result type (might be due to invalid IL or missing references)
			//IL_00aa: Unknown result type (might be due to invalid IL or missing references)
			//IL_00af: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ce: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d3: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)data == (Object)null))
			{
				RestoreOriginalLookDirection();
				Vector3 lookDirection = data.lookDirection;
				Vector3 val = Vector3.ProjectOnPlane(lookDirection, Vector3.up);
				if (((Vector3)(ref val)).sqrMagnitude < 0.0001f)
				{
					val = data.lookDirection_Flat;
				}
				if (!(((Vector3)(ref val)).sqrMagnitude < 0.0001f))
				{
					float num = ((_releaseSurfaceValid && _releaseWallDegrees < -1f) ? (1f * _releaseWallDegrees) : 0f);
					float num2 = Mathf.Clamp(1f + num, -30f, 10f) * (MathF.PI / 180f);
					Vector3 val2 = ((Vector3)(ref val)).normalized * Mathf.Cos(num2) + Vector3.up * Mathf.Sin(num2);
					_savedLookDirection = lookDirection;
					_lookDirectionOwner = data;
					_restoreLookDirection = true;
					data.lookDirection = ((Vector3)(ref val2)).normalized;
				}
			}
		}

		private void RestoreOriginalLookDirection()
		{
			//IL_001e: 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)
			if (_restoreLookDirection)
			{
				if ((Object)(object)_lookDirectionOwner != (Object)null)
				{
					_lookDirectionOwner.lookDirection = _savedLookDirection;
				}
				_restoreLookDirection = false;
				_lookDirectionOwner = null;
			}
		}

		private void CaptureReleaseSurface(Character local)
		{
			//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_0047: Unknown result type (might be due to invalid IL or missing references)
			_releaseSurfaceValid = false;
			if (!((Object)(object)local == (Object)null) && !((Object)(object)local.data == (Object)null))
			{
				Vector3 normalized = ((Vector3)(ref local.data.climbNormal)).normalized;
				if (!(((Vector3)(ref normalized)).sqrMagnitude <= 0.25f))
				{
					_releaseSurfaceValid = true;
					_releaseWallDegrees = GetWallDegrees(normalized);
				}
			}
		}

		private bool ShouldUseVanillaClimbing(Character local)
		{
			//IL_0051: Unknown result type (might be due to invalid IL or missing references)
			//IL_0056: Unknown result type (might be due to invalid IL or missing references)
			//IL_0077: Unknown result type (might be due to invalid IL or missing references)
			if (!ModeEnabled || (Object)(object)local == (Object)null || (Object)(object)local.data == (Object)null || !IsActivationChordHeld())
			{
				return false;
			}
			if (!local.data.isClimbing)
			{
				_normalSurfaceCandidateSince = -1f;
				return _surfaceBypassActive;
			}
			Vector3 normalized = ((Vector3)(ref local.data.climbNormal)).normalized;
			if (((Vector3)(ref normalized)).sqrMagnitude <= 0.25f)
			{
				_normalSurfaceCandidateSince = -1f;
				return _surfaceBypassActive;
			}
			float wallDegrees = GetWallDegrees(normalized);
			if (!_surfaceBypassActive)
			{
				if (wallDegrees <= 1f)
				{
					return false;
				}
				_surfaceBypassActive = true;
				_normalSurfaceCandidateSince = -1f;
				return true;
			}
			if (wallDegrees > 0.25f)
			{
				_normalSurfaceCandidateSince = -1f;
				return true;
			}
			if (_normalSurfaceCandidateSince < 0f)
			{
				_normalSurfaceCandidateSince = Time.unscaledTime;
				return true;
			}
			if (Time.unscaledTime - _normalSurfaceCandidateSince < 0.05f)
			{
				return true;
			}
			_surfaceBypassActive = false;
			_normalSurfaceCandidateSince = -1f;
			return false;
		}

		private static float GetWallDegrees(Vector3 normal)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			return Mathf.Asin(Mathf.Clamp(0f - normal.y, -1f, 1f)) * 57.29578f;
		}

		private void ResetSurfaceRouting()
		{
			_surfaceBypassActive = false;
			_normalSurfaceCandidateSince = -1f;
		}

		private bool ShouldPreserveOriginalTap(Character local)
		{
			if (!ModeEnabled || (Object)(object)local == (Object)null || (Object)(object)local.data == (Object)null || !IsActivationChordHeld())
			{
				return false;
			}
			bool num = IsAutomationHoldConfirmed();
			if (!_overridingInput && local.data.isClimbing && _initialPhysicalGrabObservedAt < 0f)
			{
				_initialPhysicalGrabObservedAt = Time.unscaledTime;
			}
			if (!num)
			{
				return true;
			}
			if (_overridingInput)
			{
				return false;
			}
			if (!local.data.isClimbing || _initialPhysicalGrabObservedAt < 0f)
			{
				return true;
			}
			return Time.unscaledTime - _initialPhysicalGrabObservedAt < 0.14f;
		}

		private bool IsAutomationHoldConfirmed()
		{
			if (!IsActivationChordHeld())
			{
				ResetActivationHold();
				return false;
			}
			if (_automationHoldCommitted)
			{
				return true;
			}
			if (_physicalGrabHeldSince < 0f)
			{
				_physicalGrabHeldSince = Time.unscaledTime;
				return false;
			}
			if (Time.unscaledTime - _physicalGrabHeldSince < 0.14f)
			{
				return false;
			}
			_automationHoldCommitted = true;
			return true;
		}

		private void FinishPhysicalGrabPress()
		{
			ResetActivationHold();
		}

		private void ResetActivationHold()
		{
			_physicalGrabHeldSince = -1f;
			_initialPhysicalGrabObservedAt = -1f;
			_automationHoldCommitted = false;
		}

		private void PrepareControllerRelease(CharacterClimbing climbing)
		{
			if (_phase == CyclePhase.Release && IsGamepadInput() && !((Object)(object)climbing == (Object)null) && !(ClimbToggledOnField == null))
			{
				Character localCharacter = Character.localCharacter;
				if (!((Object)(object)localCharacter == (Object)null) && !((Object)(object)localCharacter.data == (Object)null) && localCharacter.data.isClimbing)
				{
					_savedClimbToggle = (bool)ClimbToggledOnField.GetValue(climbing);
					_temporaryToggleOwner = climbing;
					ClimbToggledOnField.SetValue(climbing, false);
				}
			}
		}

		private void RestoreControllerClimbToggle()
		{
			CharacterClimbing temporaryToggleOwner = _temporaryToggleOwner;
			_temporaryToggleOwner = null;
			if (!((Object)(object)temporaryToggleOwner == (Object)null) && !(ClimbToggledOnField == null))
			{
				Character ownerCharacter = GetOwnerCharacter(temporaryToggleOwner);
				if ((Object)(object)ownerCharacter != (Object)null && (Object)(object)ownerCharacter.data != (Object)null && ownerCharacter.data.isClimbing)
				{
					ClimbToggledOnField.SetValue(temporaryToggleOwner, _savedClimbToggle);
				}
			}
		}

		private static bool IsGamepadInput()
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Invalid comparison between Unknown and I4
			return (int)InputHandler.GetCurrentUsedInputScheme() == 1;
		}

		private static bool IsPhysicalGrabHeld()
		{
			if (!IsGamepadInput())
			{
				return Input.GetMouseButton(0);
			}
			if (CharacterInput.action_usePrimary != null)
			{
				return CharacterInput.action_usePrimary.IsPressed();
			}
			return false;
		}

		private static bool IsMovementChordHeld()
		{
			//IL_006e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0062: Unknown result type (might be due to invalid IL or missing references)
			//IL_0073: Unknown result type (might be due to invalid IL or missing references)
			//IL_0076: Unknown result type (might be due to invalid IL or missing references)
			if (!IsGamepadInput())
			{
				_controllerForwardHeld = false;
				bool flag = Input.GetKey((KeyCode)304) || Input.GetKey((KeyCode)303);
				return Input.GetKey((KeyCode)119) && flag;
			}
			bool num = (CharacterInput.action_sprint != null && CharacterInput.action_sprint.IsPressed()) || (CharacterInput.action_sprintToggle != null && CharacterInput.action_sprintToggle.IsPressed());
			Vector2 val = ((CharacterInput.action_move != null) ? CharacterInput.action_move.ReadValue<Vector2>() : Vector2.zero);
			_controllerForwardHeld = num && val.y >= (_controllerForwardHeld ? 0.35f : 0.55f);
			return _controllerForwardHeld;
		}

		private static bool IsActivationChordHeld()
		{
			if (IsMovementChordHeld())
			{
				return IsPhysicalGrabHeld();
			}
			return false;
		}

		internal bool ShouldBridgeMovementSprint(Character local)
		{
			if (ModeEnabled && _overridingInput && !_surfaceBypassActive && (Object)(object)local != (Object)null && (Object)(object)local == (Object)(object)Character.localCharacter && (Object)(object)local.data != (Object)null && !local.data.isGrounded && IsGamepadInput())
			{
				return IsEligible(local);
			}
			return false;
		}

		private bool CheckControllerToggle()
		{
			//IL_00bf: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00de: Unknown result type (might be due to invalid IL or missing references)
			Gamepad current = Gamepad.current;
			if (current == null || !((InputDevice)current).added || !current.leftStickButton.isPressed || !current.rightStickButton.isPressed)
			{
				_controllerToggleSince = -1f;
				_controllerToggleConsumed = false;
				return false;
			}
			if (_controllerToggleConsumed)
			{
				return false;
			}
			Character localCharacter = Character.localCharacter;
			if ((Object)(object)localCharacter != (Object)null && (Object)(object)localCharacter.data != (Object)null && localCharacter.data.isGrounded && !localCharacter.data.isClimbing && !localCharacter.data.isRopeClimbing && !localCharacter.data.isVineClimbing && !localCharacter.data.passedOut && CanAcceptInput(localCharacter))
			{
				Vector2 val = ((InputControl<Vector2>)(object)current.leftStick).ReadValue();
				if (((Vector2)(ref val)).sqrMagnitude < 0.04f)
				{
					val = ((InputControl<Vector2>)(object)current.rightStick).ReadValue();
					if (((Vector2)(ref val)).sqrMagnitude < 0.04f)
					{
						if (_controllerToggleSince < 0f)
						{
							_controllerToggleSince = Time.unscaledTime;
						}
						if (Time.unscaledTime - _controllerToggleSince < 1f)
						{
							return false;
						}
						_controllerToggleConsumed = true;
						return true;
					}
				}
			}
			_controllerToggleSince = -1f;
			return false;
		}

		private bool IsEligible(Character local)
		{
			if (!ModeEnabled || (Object)(object)local == (Object)null || (Object)(object)local.data == (Object)null || !IsActivationChordHeld())
			{
				return false;
			}
			if (local.inAirport || !CanAcceptInput(local))
			{
				return false;
			}
			if (local.data.passedOut || local.data.isRopeClimbing || local.data.isVineClimbing || local.data.usingEmoteWheel || local.data.usingBackpackWheel || (Object)(object)local.data.currentItem != (Object)null)
			{
				return false;
			}
			return true;
		}

		private bool CanAcceptInput(Character local)
		{
			if (CanDoInputMethod == null)
			{
				return true;
			}
			try
			{
				return (bool)CanDoInputMethod.Invoke(local, null);
			}
			catch (Exception ex)
			{
				LogRuntimeFailure("input availability", ex);
				return true;
			}
		}

		private Character GetOwnerCharacter(CharacterClimbing climbing)
		{
			if ((Object)(object)climbing == (Object)null)
			{
				return null;
			}
			if (ClimbingCharacterField != null)
			{
				object? value = ClimbingCharacterField.GetValue(climbing);
				Character val = (Character)((value is Character) ? value : null);
				if ((Object)(object)val != (Object)null)
				{
					return val;
				}
			}
			return ((Component)climbing).GetComponentInParent<Character>();
		}

		private void StopOverriding()
		{
			RestoreControllerClimbToggle();
			RestoreOriginalLookDirection();
			_overridingInput = false;
			_phase = CyclePhase.Idle;
			_phaseFixedSteps = 0;
			_effectiveGrabTicks = 0;
			_effectiveReleaseTicks = 0;
			_grabConfirmed = false;
			_releaseRequested = false;
			_grabRequested = false;
			_retryGrabRequested = false;
			_retryReleaseRequested = false;
			_regrabTimingReady = false;
		}

		private static void ApplyGrabInput(CharacterInput input, bool pressedEdge)
		{
			input.usePrimaryWasPressed = pressedEdge;
			input.usePrimaryIsPressed = true;
			input.usePrimaryWasReleased = false;
		}

		private static void ApplyReleaseInput(CharacterInput input, bool releasedEdge)
		{
			input.usePrimaryWasPressed = false;
			input.usePrimaryIsPressed = false;
			input.usePrimaryWasReleased = releasedEdge;
		}

		private void LogRuntimeFailure(string stage, Exception ex)
		{
			if (!_loggedRuntimeFailure)
			{
				_loggedRuntimeFailure = true;
				((BaseUnityPlugin)this).Logger.LogError((object)("Auto Grab Climb " + stage + " error: " + UnwrapException(ex).Message));
			}
		}

		private static Exception UnwrapException(Exception ex)
		{
			if (!(ex is TargetInvocationException { InnerException: not null } ex2))
			{
				return ex;
			}
			return ex2.InnerException;
		}
	}
	[HarmonyPatch(typeof(Character), "CalculateWorldMovementDir")]
	internal static class ControllerWorldMovementPatch
	{
		internal struct SavedMovement
		{
			public CharacterInput Input;

			public Vector2 Movement;
		}

		[HarmonyPrefix]
		private static void Prefix(Character __instance, out SavedMovement __state)
		{
			//IL_004a: Unknown result type (might be due to invalid IL or missing references)
			//IL_004f: Unknown result type (might be due to invalid IL or missing references)
			//IL_005a: 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)
			__state = default(SavedMovement);
			Plugin instance = Plugin.Instance;
			if (!((Object)(object)instance == (Object)null) && !((Object)(object)__instance == (Object)null) && !((Object)(object)__instance.input == (Object)null) && instance.ShouldBridgeMovementSprint(__instance))
			{
				__state.Input = __instance.input;
				__state.Movement = __state.Input.movementInput;
				__state.Input.movementInput = Vector2.up;
			}
		}

		[HarmonyFinalizer]
		private static void Finalizer(SavedMovement __state)
		{
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)__state.Input != (Object)null)
			{
				__state.Input.movementInput = __state.Movement;
			}
		}
	}
	[HarmonyPatch(typeof(CharacterMovement), "SetMovementState")]
	internal static class ControllerSprintMovementPatch
	{
		internal struct SavedInput
		{
			public CharacterInput Input;

			public bool SprintHeld;
		}

		[HarmonyPrefix]
		private static void Prefix(Character ___character, out SavedInput __state)
		{
			__state = default(SavedInput);
			Plugin instance = Plugin.Instance;
			if (!((Object)(object)instance == (Object)null) && !((Object)(object)___character == (Object)null) && !((Object)(object)___character.input == (Object)null) && instance.ShouldBridgeMovementSprint(___character))
			{
				__state.Input = ___character.input;
				__state.SprintHeld = __state.Input.sprintIsPressed;
				__state.Input.sprintIsPressed = true;
			}
		}

		[HarmonyFinalizer]
		private static void Finalizer(SavedInput __state)
		{
			if ((Object)(object)__state.Input != (Object)null)
			{
				__state.Input.sprintIsPressed = __state.SprintHeld;
			}
		}
	}
	[HarmonyPatch(typeof(CharacterClimbing), "Update")]
	internal static class CharacterClimbingUpdatePatch
	{
		[HarmonyPrefix]
		private static void Prefix(CharacterClimbing __instance)
		{
			Plugin instance = Plugin.Instance;
			if ((Object)(object)instance != (Object)null)
			{
				instance.BeforeClimbingUpdate(__instance);
			}
		}

		[HarmonyPostfix]
		private static void Postfix(CharacterClimbing __instance)
		{
			Plugin instance = Plugin.Instance;
			if ((Object)(object)instance != (Object)null)
			{
				instance.AfterClimbingUpdate(__instance);
			}
		}
	}
	[HarmonyPatch(typeof(CharacterClimbing), "FixedUpdate")]
	internal static class CharacterClimbingFixedUpdatePatch
	{
		[HarmonyPrefix]
		private static void Prefix(CharacterClimbing __instance)
		{
			Plugin instance = Plugin.Instance;
			if ((Object)(object)instance != (Object)null)
			{
				instance.BeforeClimbingFixedUpdate(__instance);
			}
		}

		[HarmonyPostfix]
		private static void Postfix(CharacterClimbing __instance)
		{
			Plugin instance = Plugin.Instance;
			if ((Object)(object)instance != (Object)null)
			{
				instance.AfterClimbingFixedUpdate(__instance);
			}
		}
	}
}