Decompiled source of UltraHook v1.3.4

UltraHook.dll

Decompiled a day ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Logging;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using PluginConfig.API;
using PluginConfig.API.Decorators;
using PluginConfig.API.Fields;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("UltraHook")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyDescription("Lets V1's Whiplash latch onto solid surfaces and pull toward them.")]
[assembly: AssemblyFileVersion("1.3.4.0")]
[assembly: AssemblyInformationalVersion("1.3.4+f78cfaa84619023ccf773a408748cf475c69cbf5")]
[assembly: AssemblyProduct("UltraHook")]
[assembly: AssemblyTitle("UltraHook")]
[assembly: AssemblyVersion("1.3.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 UltraHook
{
	internal static class GrappleHook
	{
		private enum Phase
		{
			Idle,
			Pulling,
			Taut
		}

		private sealed class RaycastHitDistanceComparer : IComparer<RaycastHit>
		{
			public static readonly RaycastHitDistanceComparer Instance = new RaycastHitDistanceComparer();

			public int Compare(RaycastHit x, RaycastHit y)
			{
				return ((RaycastHit)(ref x)).distance.CompareTo(((RaycastHit)(ref y)).distance);
			}
		}

		private const int IgnoreRaycastLayer = 2;

		private const int SolidClinkLayer = 26;

		private const float ThrowSpeed = 250f;

		private const float NoSwingExtraDamping = 5f;

		private const float TipEndTolerance = 0.05f;

		private const float EndpointContactTolerance = 0.05f;

		private const int AttachGraceFrames = 2;

		private const float MinNormalSqr = 1E-06f;

		private static readonly AnimationCurve MomentumCurve = AnimationCurve.EaseInOut(0f, 0f, 1f, 1f);

		private static readonly FieldRef<HookArm, HookState> StateRef = AccessTools.FieldRefAccess<HookArm, HookState>("state");

		private static readonly FieldRef<HookArm, bool> ReturningRef = AccessTools.FieldRefAccess<HookArm, bool>("returning");

		private static readonly FieldRef<HookArm, Vector3> HookPointRef = AccessTools.FieldRefAccess<HookArm, Vector3>("hookPoint");

		private static readonly FieldRef<HookArm, Vector3> ThrowDirectionRef = AccessTools.FieldRefAccess<HookArm, Vector3>("throwDirection");

		private static readonly FieldRef<HookArm, LayerMask> EnviroMaskRef = AccessTools.FieldRefAccess<HookArm, LayerMask>("enviroMask");

		private static readonly FieldRef<HookArm, LayerMask> ThrowMaskRef = AccessTools.FieldRefAccess<HookArm, LayerMask>("throwMask");

		private static readonly FieldRef<HookArm, Vector3> CaughtPointRef = AccessTools.FieldRefAccess<HookArm, Vector3>("caughtPoint");

		private static readonly FieldRef<HookArm, Transform> CaughtTransformRef = AccessTools.FieldRefAccess<HookArm, Transform>("caughtTransform");

		private static readonly FieldRef<HookArm, Collider> CaughtColliderRef = AccessTools.FieldRefAccess<HookArm, Collider>("caughtCollider");

		private static readonly FieldRef<HookArm, bool> LightTargetRef = AccessTools.FieldRefAccess<HookArm, bool>("lightTarget");

		private static readonly FieldInfo CaughtObjectsField = AccessTools.Field(typeof(HookArm), "caughtObjects");

		private static readonly FieldInfo PortalTraversalsField = AccessTools.Field(typeof(HookArm), "portalTraversals");

		private static readonly FieldInfo CaughtEidField = AccessTools.Field(typeof(HookArm), "caughtEid");

		private static readonly FieldInfo CaughtHookField = AccessTools.Field(typeof(HookArm), "caughtHook");

		private static readonly FieldInfo HitSoundField = AccessTools.Field(typeof(HookArm), "hitSound");

		private static readonly FieldInfo AudField = AccessTools.Field(typeof(HookArm), "aud");

		private static readonly RaycastHit[] CastBuffer = (RaycastHit[])(object)new RaycastHit[64];

		private static readonly Collider[] OverlapBuffer = (Collider[])(object)new Collider[64];

		private static readonly HashSet<Collider> SelfColliders = new HashSet<Collider>();

		private static bool _selfCollidersBuilt;

		private static GameObject _anchor;

		private static SphereCollider _anchorCollider;

		private static CapsuleCollider _playerCollider;

		private static Phase _phase;

		private static bool _tipTracking;

		private static Vector3 _prevTipPosition;

		private static Collider _hookedCollider;

		private static bool _trackCollider;

		private static Vector3 _localAnchor;

		private static Vector3 _worldAnchor;

		private static Vector3 _anchorNormal;

		private static int _graceFrames;

		private static bool _active;

		private static float _initialDistance;

		private static float _currentRopeLength;

		private static float _storedReleaseSpeed;

		private static Vector3 _filteredRopeDir;

		private static Vector3 _naturalVelocity;

		private static bool _jumpSuppressed;

		private static bool _savedLightTarget;

		private static bool _playerReleaseRequested;

		private static bool _groundSuppressed;

		private static float _groundTimer;

		private static GroundCheckGroup _suppressedGc;

		private static GroundCheckGroup _suppressedSlope;

		private static int _diagSweepCount;

		private static int _diagRayCount;

		private static bool AnchorActive
		{
			get
			{
				if ((Object)(object)_anchor != (Object)null)
				{
					return _anchor.activeSelf;
				}
				return false;
			}
		}

		private static float TipRadius => Mathf.Max(UltraHookConfig.SphereCastRadius, 0.02f);

		private static Rigidbody PlayerRigidbody
		{
			get
			{
				NewMovement instance = MonoSingleton<NewMovement>.Instance;
				if (!((Object)(object)instance != (Object)null))
				{
					return null;
				}
				return instance.rb;
			}
		}

		internal static bool OnFixedUpdatePre(HookArm hook)
		{
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			//IL_0027: 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_00c7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c9: Invalid comparison between Unknown and I4
			//IL_00d6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00db: Unknown result type (might be due to invalid IL or missing references)
			//IL_0095: Unknown result type (might be due to invalid IL or missing references)
			//IL_007c: 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_0086: 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)
			TickGroundSuppression();
			if (_graceFrames > 0)
			{
				_graceFrames--;
			}
			HookState val = StateRef.Invoke(hook);
			HandleDetection(hook, val);
			if (AnchorActive && (int)val != 0)
			{
				if (_trackCollider && !ColliderUsable(_hookedCollider))
				{
					if (UltraHookConfig.DebugLogging)
					{
						Plugin.Log.LogInfo((object)"UltraHook detach: AnchorColliderDestroyed or AnchorColliderDisabled");
					}
					ForceDetach(hook);
					return true;
				}
				if (_trackCollider)
				{
					_worldAnchor = ((Component)_hookedCollider).transform.TransformPoint(_localAnchor);
				}
				_anchor.transform.position = _worldAnchor;
				Rigidbody playerRigidbody = PlayerRigidbody;
				if ((Object)(object)playerRigidbody != (Object)null)
				{
					_naturalVelocity = playerRigidbody.velocity;
				}
			}
			if (UltraHookConfig.SwingMode && AnchorActive && (int)val == 3)
			{
				HookPointRef.Invoke(hook) = _worldAnchor;
				hook.beingPulled = true;
				return false;
			}
			return true;
		}

		internal static void OnFixedUpdatePost(HookArm hook)
		{
			//IL_003f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0044: 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_004a: Unknown result type (might be due to invalid IL or missing references)
			//IL_004b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0050: Unknown result type (might be due to invalid IL or missing references)
			//IL_0064: Unknown result type (might be due to invalid IL or missing references)
			//IL_0067: Unknown result type (might be due to invalid IL or missing references)
			//IL_006c: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cd: 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_00d6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00da: Unknown result type (might be due to invalid IL or missing references)
			//IL_00df: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ea: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fc: Unknown result type (might be due to invalid IL or missing references)
			//IL_0101: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ac: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ae: Unknown result type (might be due to invalid IL or missing references)
			//IL_018e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0192: Unknown result type (might be due to invalid IL or missing references)
			//IL_0197: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b4: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c0: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c5: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d2: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d4: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d9: Unknown result type (might be due to invalid IL or missing references)
			//IL_025c: Unknown result type (might be due to invalid IL or missing references)
			//IL_025e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0262: Unknown result type (might be due to invalid IL or missing references)
			//IL_0267: Unknown result type (might be due to invalid IL or missing references)
			//IL_02b8: Unknown result type (might be due to invalid IL or missing references)
			//IL_02c6: Unknown result type (might be due to invalid IL or missing references)
			//IL_02cb: Unknown result type (might be due to invalid IL or missing references)
			//IL_031b: Unknown result type (might be due to invalid IL or missing references)
			//IL_031c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0321: Unknown result type (might be due to invalid IL or missing references)
			//IL_032b: Unknown result type (might be due to invalid IL or missing references)
			//IL_032c: Unknown result type (might be due to invalid IL or missing references)
			//IL_032e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0338: Unknown result type (might be due to invalid IL or missing references)
			//IL_0339: Unknown result type (might be due to invalid IL or missing references)
			//IL_033d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0342: Unknown result type (might be due to invalid IL or missing references)
			if (!AnchorActive || (int)StateRef.Invoke(hook) != 3)
			{
				_active = false;
				SetPhase(Phase.Idle, "NotPulling");
				return;
			}
			Rigidbody playerRigidbody = PlayerRigidbody;
			if ((Object)(object)playerRigidbody == (Object)null)
			{
				return;
			}
			float fixedDeltaTime = Time.fixedDeltaTime;
			Vector3 position = playerRigidbody.position;
			Vector3 val = _worldAnchor - position;
			float magnitude = ((Vector3)(ref val)).magnitude;
			if (magnitude < 0.0001f)
			{
				return;
			}
			Vector3 val2 = val / magnitude;
			float num = ResolvedMinRopeLength();
			if (!_active)
			{
				_active = true;
				SetPhase(Phase.Pulling, "StartedTerrainPull");
				_initialDistance = Mathf.Max(magnitude, num);
				_currentRopeLength = magnitude;
				_storedReleaseSpeed = 0f;
				_filteredRopeDir = val2;
			}
			float num2 = 1f - Mathf.Exp((0f - UltraHookConfig.DirectionFilterSpeed) * fixedDeltaTime);
			Vector3 val3 = Vector3.Slerp(_filteredRopeDir, val2, num2);
			_filteredRopeDir = ((Vector3)(ref val3)).normalized;
			Vector3 naturalVelocity = _naturalVelocity;
			float num3 = Vector3.Dot(naturalVelocity, val2);
			Vector3 val4 = naturalVelocity - val2 * num3;
			_currentRopeLength = Mathf.Max(num, _currentRopeLength - UltraHookConfig.ReelSpeed * fixedDeltaTime);
			AccumulateMomentum(magnitude, num, num3);
			float num4 = num + UltraHookConfig.TautTolerance;
			bool flag = false;
			float storedReleaseSpeed = _storedReleaseSpeed;
			if (_phase == Phase.Pulling && magnitude <= num4)
			{
				SetPhase(Phase.Taut, "ReachedRopeEndpoint");
				flag = true;
				ClearStoredPullMomentum();
			}
			else if (_phase == Phase.Taut && magnitude > num4 + 1f)
			{
				SetPhase(Phase.Pulling, "RopeExtendedPastEndpoint");
			}
			float num5 = UltraHookConfig.MaxAngularSpeed * Mathf.Max(magnitude, num);
			val4 = Vector3.ClampMagnitude(val4, num5);
			float num6 = UltraHookConfig.TangentialDamping + (UltraHookConfig.SwingMode ? 0f : 5f);
			val4 *= Mathf.Exp((0f - num6) * fixedDeltaTime);
			float num7;
			if (flag)
			{
				num7 = 0f;
				val4 = ProjectOffSurface(val4);
			}
			else if (_phase == Phase.Pulling)
			{
				float num8 = Mathf.Max(0f, magnitude - _currentRopeLength);
				float num9 = Mathf.Clamp(UltraHookConfig.MinPullSpeed + num8 * UltraHookConfig.PullSpeedGain, UltraHookConfig.MinPullSpeed, UltraHookConfig.MaxPullSpeed);
				num7 = Mathf.MoveTowards(num3, num9, UltraHookConfig.PullAcceleration * fixedDeltaTime);
			}
			else
			{
				float num10 = Mathf.Clamp((magnitude - num) * UltraHookConfig.TautCorrectionGain, 0f - UltraHookConfig.MaxOutwardCorrectionSpeed, UltraHookConfig.MaxInwardCorrectionSpeed);
				num7 = Mathf.MoveTowards(num3, num10, UltraHookConfig.TautAcceleration * fixedDeltaTime);
			}
			playerRigidbody.velocity = val4 + val2 * num7;
			if (UltraHookConfig.DebugLogging)
			{
				if (flag)
				{
					ManualLogSource log = Plugin.Log;
					object[] obj = new object[5] { num3, storedReleaseSpeed, _storedReleaseSpeed, playerRigidbody.velocity, null };
					val3 = playerRigidbody.velocity;
					obj[4] = ((Vector3)(ref val3)).magnitude;
					log.LogInfo((object)("UltraHook taut entry (PullMomentumConsumedAtEndpoint, EndpointRadialVelocityRemoved, EnteredTautWithTangentialVelocity): " + string.Format("radialBefore={0:0.00} storedBefore={1:0.00} storedAfter={2:0.00} velAfter={3} mag={4:0.00}", obj)));
				}
				if (_phase == Phase.Taut && _storedReleaseSpeed > 0.01f)
				{
					Plugin.Log.LogWarning((object)$"UltraHook UnexpectedMomentumAppliedDuringTaut: storedReleaseSpeed={_storedReleaseSpeed:0.00}");
				}
				Debug.DrawLine(position, _worldAnchor, Color.cyan);
				Debug.DrawRay(position, val4, Color.yellow);
				Debug.DrawRay(position, val2 * num7, Color.green);
			}
		}

		private static void AccumulateMomentum(float distance, float minRope, float radialSpeed)
		{
			if (!UltraHookConfig.Momentum)
			{
				_storedReleaseSpeed = 0f;
			}
			else if (_phase == Phase.Pulling)
			{
				float num = Mathf.Max(_initialDistance - minRope, 0.001f);
				float num2 = Mathf.Clamp01((_initialDistance - distance) / num);
				float num3 = MomentumCurve.Evaluate(num2) * UltraHookConfig.MaxMomentumBonus;
				_storedReleaseSpeed = Mathf.Min(Mathf.Max(_storedReleaseSpeed, Mathf.Max(0f, radialSpeed) + num3), UltraHookConfig.MaxReleaseSpeed);
			}
		}

		private static void ClearStoredPullMomentum()
		{
			_storedReleaseSpeed = 0f;
		}

		private static Vector3 ProjectOffSurface(Vector3 velocity)
		{
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_003a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			//IL_0028: Unknown result type (might be due to invalid IL or missing references)
			//IL_002e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0033: 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)
			if (((Vector3)(ref _anchorNormal)).sqrMagnitude < 1E-06f)
			{
				return velocity;
			}
			float num = Vector3.Dot(velocity, _anchorNormal);
			if (num < 0f)
			{
				velocity -= _anchorNormal * num;
			}
			return velocity;
		}

		private static void HandleDetection(HookArm hook, HookState state)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0002: Invalid comparison between Unknown and I4
			//IL_0033: 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_0046: 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)
			//IL_0068: Unknown result type (might be due to invalid IL or missing references)
			//IL_0069: Unknown result type (might be due to invalid IL or missing references)
			//IL_0070: Unknown result type (might be due to invalid IL or missing references)
			if ((int)state != 1 || !UltraHookConfig.Enabled || !hook.equipped || ReturningRef.Invoke(hook))
			{
				_tipTracking = false;
				return;
			}
			Vector3 val = HookPointRef.Invoke(hook);
			if (!_tipTracking)
			{
				_tipTracking = true;
				_prevTipPosition = val;
			}
			if (Count(CaughtObjectsField, hook) > 0 || Count(PortalTraversalsField, hook) > 0)
			{
				_prevTipPosition = val;
			}
			else
			{
				SweepTip(hook, val);
			}
		}

		private static void SweepTip(HookArm hook, Vector3 tip)
		{
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			//IL_0028: Unknown result type (might be due to invalid IL or missing references)
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			//IL_003a: Unknown result type (might be due to invalid IL or missing references)
			//IL_003f: 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)
			//IL_0041: Unknown result type (might be due to invalid IL or missing references)
			//IL_0043: Unknown result type (might be due to invalid IL or missing references)
			//IL_0048: Unknown result type (might be due to invalid IL or missing references)
			//IL_004d: Unknown result type (might be due to invalid IL or missing references)
			//IL_004e: 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_0054: Unknown result type (might be due to invalid IL or missing references)
			//IL_0055: 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_005b: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: 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_0070: Unknown result type (might be due to invalid IL or missing references)
			//IL_0074: Unknown result type (might be due to invalid IL or missing references)
			//IL_0079: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ae: 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_00d9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00dc: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cb: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cd: 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_00cf: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ed: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ef: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f5: Unknown result type (might be due to invalid IL or missing references)
			Vector3 val = ThrowDirectionRef.Invoke(hook);
			if (((Vector3)(ref val)).sqrMagnitude < 1E-08f)
			{
				_prevTipPosition = tip;
				return;
			}
			val = ((Vector3)(ref val)).normalized;
			float num = 250f * Time.fixedDeltaTime;
			Vector3 prevTipPosition = _prevTipPosition;
			Vector3 val2 = tip + val * num;
			_prevTipPosition = tip;
			Vector3 val3 = val2 - prevTipPosition;
			float magnitude = ((Vector3)(ref val3)).magnitude;
			if (magnitude < 0.0001f)
			{
				return;
			}
			Vector3 sweepDir = val3 / magnitude;
			int num2 = DetectionMask(hook);
			int catchMask = ((LayerMask)(ref ThrowMaskRef.Invoke(hook))).value & ~num2;
			bool queriesHitBackfaces = Physics.queriesHitBackfaces;
			if (UltraHookConfig.BackfaceCompatibility)
			{
				Physics.queriesHitBackfaces = true;
			}
			try
			{
				if (TryTerrainImpact(prevTipPosition, sweepDir, magnitude, num2, catchMask, out var collider, out var point, out var normal, out var distance))
				{
					CommitTerrainAnchor(hook, collider, point, normal, val, prevTipPosition, val2, distance);
				}
				else if (TryEndpointOverlap(val2, num2, val, out collider, out point, out normal))
				{
					CommitTerrainAnchor(hook, collider, point, normal, val, prevTipPosition, val2, Vector3.Distance(prevTipPosition, point));
				}
			}
			finally
			{
				Physics.queriesHitBackfaces = queriesHitBackfaces;
			}
		}

		private static bool TryTerrainImpact(Vector3 start, Vector3 sweepDir, float length, int detectMask, int catchMask, out Collider collider, out Vector3 point, out Vector3 normal, out float distance)
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0012: 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_002e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			//IL_0086: 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_00e8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e9: 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_00bc: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ca: Unknown result type (might be due to invalid IL or missing references)
			//IL_0127: Unknown result type (might be due to invalid IL or missing references)
			//IL_012c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0135: Unknown result type (might be due to invalid IL or missing references)
			//IL_013a: Unknown result type (might be due to invalid IL or missing references)
			//IL_015c: Unknown result type (might be due to invalid IL or missing references)
			//IL_015d: Unknown result type (might be due to invalid IL or missing references)
			collider = null;
			point = Vector3.zero;
			normal = Vector3.zero;
			distance = float.MaxValue;
			bool flag = false;
			float num = length + 0.05f;
			int num2 = (_diagSweepCount = Physics.SphereCastNonAlloc(start, TipRadius, sweepDir, CastBuffer, num, detectMask, (QueryTriggerInteraction)1));
			if (num2 >= CastBuffer.Length && UltraHookConfig.DebugLogging)
			{
				Plugin.Log.LogWarning((object)"UltraHook TipSweepBufferFull");
			}
			Array.Sort(CastBuffer, 0, num2, RaycastHitDistanceComparer.Instance);
			for (int i = 0; i < num2; i++)
			{
				RaycastHit val = CastBuffer[i];
				if (!(((RaycastHit)(ref val)).distance <= 0f) && IsHookableHit(((RaycastHit)(ref val)).collider))
				{
					collider = ((RaycastHit)(ref val)).collider;
					point = ((RaycastHit)(ref val)).point;
					normal = ((RaycastHit)(ref val)).normal;
					distance = ((RaycastHit)(ref val)).distance;
					flag = true;
					break;
				}
			}
			RaycastHit val2 = default(RaycastHit);
			if (Physics.Raycast(start, sweepDir, ref val2, num, detectMask, (QueryTriggerInteraction)1) && IsHookableHit(((RaycastHit)(ref val2)).collider))
			{
				_diagRayCount = 1;
				if (!flag || ((RaycastHit)(ref val2)).distance < distance)
				{
					collider = ((RaycastHit)(ref val2)).collider;
					point = ((RaycastHit)(ref val2)).point;
					normal = ((RaycastHit)(ref val2)).normal;
					distance = ((RaycastHit)(ref val2)).distance;
					flag = true;
				}
			}
			else
			{
				_diagRayCount = 0;
			}
			if (!flag)
			{
				return false;
			}
			if (catchMask != 0 && CatchableStruckCloser(start, sweepDir, distance, catchMask))
			{
				collider = null;
				return false;
			}
			return true;
		}

		private static bool CatchableStruckCloser(Vector3 start, Vector3 sweepDir, float terrainDistance, int catchMask)
		{
			//IL_0000: 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_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			int num = Physics.SphereCastNonAlloc(start, TipRadius, sweepDir, CastBuffer, terrainDistance, catchMask, (QueryTriggerInteraction)2);
			for (int i = 0; i < num; i++)
			{
				RaycastHit val = CastBuffer[i];
				Collider collider = ((RaycastHit)(ref val)).collider;
				if (!((Object)(object)collider == (Object)null) && !((Object)(object)collider == (Object)(object)_anchorCollider) && !IsSelf(collider) && ((RaycastHit)(ref val)).distance <= terrainDistance - 0.01f)
				{
					return true;
				}
			}
			return false;
		}

		private static bool TryEndpointOverlap(Vector3 endpoint, int detectMask, Vector3 fallbackDir, out Collider collider, out Vector3 point, out Vector3 normal)
		{
			//IL_0005: 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_000d: Unknown result type (might be due to invalid IL or missing references)
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0013: 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_0046: 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)
			//IL_004c: Unknown result type (might be due to invalid IL or missing references)
			//IL_004e: 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_006e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0070: Unknown result type (might be due to invalid IL or missing references)
			//IL_0075: 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)
			//IL_0078: Unknown result type (might be due to invalid IL or missing references)
			//IL_007d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0099: 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_0090: Unknown result type (might be due to invalid IL or missing references)
			//IL_009e: Unknown result type (might be due to invalid IL or missing references)
			collider = null;
			point = endpoint;
			normal = -fallbackDir;
			int num = Physics.OverlapSphereNonAlloc(endpoint, TipRadius, OverlapBuffer, detectMask, (QueryTriggerInteraction)1);
			float num2 = float.MaxValue;
			for (int i = 0; i < num; i++)
			{
				Collider val = OverlapBuffer[i];
				if (IsHookableHit(val))
				{
					Vector3 val2 = val.ClosestPoint(endpoint);
					float num3 = Vector3.Distance(endpoint, val2);
					if (num3 <= 0.05f && num3 < num2)
					{
						num2 = num3;
						collider = val;
						point = val2;
						Vector3 val3 = endpoint - val2;
						normal = ((((Vector3)(ref val3)).sqrMagnitude > 1E-06f) ? ((Vector3)(ref val3)).normalized : (-fallbackDir));
					}
				}
			}
			return (Object)(object)collider != (Object)null;
		}

		private static void CommitTerrainAnchor(HookArm hook, Collider collider, Vector3 point, Vector3 normal, Vector3 travelDir, Vector3 from, Vector3 to, float distance)
		{
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: 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_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0030: 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_0062: Unknown result type (might be due to invalid IL or missing references)
			//IL_0067: 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)
			//IL_0078: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ec: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ed: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f3: Unknown result type (might be due to invalid IL or missing references)
			//IL_012e: Unknown result type (might be due to invalid IL or missing references)
			//IL_012f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0169: Unknown result type (might be due to invalid IL or missing references)
			//IL_016a: Unknown result type (might be due to invalid IL or missing references)
			//IL_016d: Unknown result type (might be due to invalid IL or missing references)
			//IL_016f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0171: Unknown result type (might be due to invalid IL or missing references)
			Vector3 val = ((((Vector3)(ref normal)).sqrMagnitude > 1E-06f) ? ((Vector3)(ref normal)).normalized : (-travelDir));
			Vector3 val2 = point + val * UltraHookConfig.SurfaceOffset;
			Transform anchor = GetAnchor();
			anchor.position = val2;
			((Component)anchor).gameObject.SetActive(true);
			CaughtTransformRef.Invoke(hook) = anchor;
			CaughtPointRef.Invoke(hook) = Vector3.zero;
			HookPointRef.Invoke(hook) = val2;
			CaughtColliderRef.Invoke(hook) = (Collider)(object)_anchorCollider;
			LightTargetRef.Invoke(hook) = false;
			CaughtEidField.SetValue(hook, null);
			CaughtHookField.SetValue(hook, null);
			StateRef.Invoke(hook) = (HookState)2;
			_hookedCollider = collider;
			_trackCollider = ColliderUsable(collider);
			_localAnchor = (_trackCollider ? ((Component)collider).transform.InverseTransformPoint(val2) : val2);
			_worldAnchor = val2;
			_anchorNormal = val;
			_active = false;
			_phase = Phase.Idle;
			_tipTracking = false;
			_graceFrames = 2;
			object? value = HitSoundField.GetValue(hook);
			GameObject val3 = (GameObject)((value is GameObject) ? value : null);
			if (val3 != null && (Object)(object)val3 != (Object)null)
			{
				Object.Instantiate<GameObject>(val3, point, Quaternion.identity);
			}
			object? value2 = AudField.GetValue(hook);
			AudioSource val4 = (AudioSource)((value2 is AudioSource) ? value2 : null);
			if (val4 != null && (Object)(object)val4 != (Object)null)
			{
				val4.Stop();
			}
			if (UltraHookConfig.DebugLogging)
			{
				LogImpact(collider, point, val, distance, travelDir, from, to);
			}
		}

		internal static void OnRelease()
		{
			//IL_0076: 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_0067: 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)
			//IL_007b: 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_0090: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ad: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b3: 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)
			bool flag = UltraHookConfig.SwingMode && AnchorActive && _active && _phase == Phase.Taut;
			if (_active)
			{
				Rigidbody playerRigidbody = PlayerRigidbody;
				if ((Object)(object)playerRigidbody != (Object)null && UltraHookConfig.Momentum && _storedReleaseSpeed > 0f)
				{
					Vector3 normalized;
					if (!(((Vector3)(ref _filteredRopeDir)).sqrMagnitude > 0.5f))
					{
						Vector3 velocity = playerRigidbody.velocity;
						normalized = ((Vector3)(ref velocity)).normalized;
					}
					else
					{
						normalized = ((Vector3)(ref _filteredRopeDir)).normalized;
					}
					Vector3 val = normalized;
					if (((Vector3)(ref val)).sqrMagnitude > 0.5f)
					{
						float num = Vector3.Dot(playerRigidbody.velocity, val);
						float num2 = Mathf.Max(num, _storedReleaseSpeed);
						playerRigidbody.velocity += val * (num2 - num);
					}
				}
				BeginGroundSuppression();
			}
			if (UltraHookConfig.DebugLogging)
			{
				if (flag && !_playerReleaseRequested)
				{
					Plugin.Log.LogWarning((object)"UltraHook UnexpectedEndpointDetach: released during a persistent swing without an explicit hook input");
				}
				else
				{
					Plugin.Log.LogInfo((object)string.Format("UltraHook release: reason={0} phase={1} swing={2}", _playerReleaseRequested ? "ExplicitSwingRelease" : "NonSwingOrForced", _phase, UltraHookConfig.SwingMode));
				}
			}
			_playerReleaseRequested = false;
			ResetLatchState();
		}

		internal static void SuppressJumpCancel(HookArm hook)
		{
			if (AnchorActive && (int)StateRef.Invoke(hook) == 3)
			{
				if (HookInputPressedThisFrame())
				{
					_playerReleaseRequested = true;
				}
				_savedLightTarget = LightTargetRef.Invoke(hook);
				LightTargetRef.Invoke(hook) = true;
				_jumpSuppressed = true;
			}
		}

		private static bool HookInputPressedThisFrame()
		{
			InputManager instance = MonoSingleton<InputManager>.Instance;
			if ((Object)(object)instance != (Object)null && instance.InputSource != null)
			{
				return instance.InputSource.Hook.WasPerformedThisFrame;
			}
			return false;
		}

		internal static void RestoreJumpCancel(HookArm hook)
		{
			if (_jumpSuppressed)
			{
				LightTargetRef.Invoke(hook) = _savedLightTarget;
				_jumpSuppressed = false;
			}
		}

		internal static void ScaleLineDistance(ref float result)
		{
			float maxHookDistance = UltraHookConfig.MaxHookDistance;
			if (float.IsPositiveInfinity(maxHookDistance))
			{
				if (result > 299f)
				{
					result = 299f;
				}
			}
			else if (maxHookDistance > 0f && !Mathf.Approximately(maxHookDistance, 300f))
			{
				result *= 300f / maxHookDistance;
			}
		}

		private static void BeginGroundSuppression()
		{
			float groundSnapSuppressTime = UltraHookConfig.GroundSnapSuppressTime;
			if (groundSnapSuppressTime <= 0f)
			{
				return;
			}
			NewMovement instance = MonoSingleton<NewMovement>.Instance;
			if (!((Object)(object)instance == (Object)null))
			{
				EndGroundSuppression();
				_suppressedGc = instance.gc;
				_suppressedSlope = instance.slopeCheck;
				if ((Object)(object)_suppressedGc != (Object)null)
				{
					_suppressedGc.ForceOff();
				}
				if ((Object)(object)_suppressedSlope != (Object)null)
				{
					_suppressedSlope.ForceOff();
				}
				_groundSuppressed = true;
				_groundTimer = groundSnapSuppressTime;
			}
		}

		private static void TickGroundSuppression()
		{
			if (_groundSuppressed)
			{
				_groundTimer -= Time.fixedDeltaTime;
				if (_groundTimer <= 0f)
				{
					EndGroundSuppression();
				}
			}
		}

		private static void EndGroundSuppression()
		{
			if (_groundSuppressed)
			{
				if ((Object)(object)_suppressedGc != (Object)null)
				{
					_suppressedGc.StopForceOff();
				}
				if ((Object)(object)_suppressedSlope != (Object)null)
				{
					_suppressedSlope.StopForceOff();
				}
				_suppressedGc = null;
				_suppressedSlope = null;
				_groundSuppressed = false;
			}
		}

		private static void ForceDetach(HookArm hook)
		{
			_active = false;
			hook.StopThrow(0f, false);
		}

		private static void ResetLatchState()
		{
			_active = false;
			_phase = Phase.Idle;
			_tipTracking = false;
			_graceFrames = 0;
			_storedReleaseSpeed = 0f;
			_hookedCollider = null;
			_trackCollider = false;
			if ((Object)(object)_anchor != (Object)null && _anchor.activeSelf)
			{
				_anchor.SetActive(false);
			}
		}

		internal static void Cleanup()
		{
			EndGroundSuppression();
			if ((Object)(object)_anchor != (Object)null)
			{
				Object.Destroy((Object)(object)_anchor);
			}
			_anchor = null;
			_anchorCollider = null;
			_playerCollider = null;
			_active = false;
			_phase = Phase.Idle;
			_jumpSuppressed = false;
			_tipTracking = false;
			_graceFrames = 0;
			_trackCollider = false;
			_hookedCollider = null;
			_playerReleaseRequested = false;
			SelfColliders.Clear();
			_selfCollidersBuilt = false;
		}

		private static Transform GetAnchor()
		{
			//IL_0012: 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_0023: Expected O, but got Unknown
			if ((Object)(object)_anchor == (Object)null)
			{
				_anchor = new GameObject("UltraHookAnchor")
				{
					layer = 2
				};
				Object.DontDestroyOnLoad((Object)(object)_anchor);
				_anchorCollider = _anchor.AddComponent<SphereCollider>();
				_anchorCollider.radius = 0.1f;
				((Collider)_anchorCollider).isTrigger = true;
				_anchor.SetActive(false);
			}
			return _anchor.transform;
		}

		private static int DetectionMask(HookArm hook)
		{
			return (UltraHookConfig.HookableMask | ((LayerMask)(ref EnviroMaskRef.Invoke(hook))).value | 0x4000000) & ~UltraHookConfig.UnhookableMask & -5;
		}

		private static bool IsHookableHit(Collider collider)
		{
			if ((Object)(object)collider == (Object)null || !collider.enabled || collider.isTrigger)
			{
				return false;
			}
			if ((Object)(object)collider == (Object)(object)_anchorCollider || IsSelf(collider))
			{
				return false;
			}
			return true;
		}

		private static bool IsSelf(Collider collider)
		{
			if ((Object)(object)collider == (Object)null)
			{
				return false;
			}
			EnsureSelfColliders();
			if (SelfColliders.Contains(collider))
			{
				return true;
			}
			NewMovement instance = MonoSingleton<NewMovement>.Instance;
			if ((Object)(object)instance != (Object)null && (Object)(object)collider.attachedRigidbody != (Object)null)
			{
				return (Object)(object)collider.attachedRigidbody == (Object)(object)instance.rb;
			}
			return false;
		}

		private static void EnsureSelfColliders()
		{
			if (_selfCollidersBuilt)
			{
				return;
			}
			NewMovement instance = MonoSingleton<NewMovement>.Instance;
			if ((Object)(object)instance == (Object)null)
			{
				return;
			}
			SelfColliders.Clear();
			Collider[] componentsInChildren = ((Component)instance).GetComponentsInChildren<Collider>(true);
			foreach (Collider item in componentsInChildren)
			{
				SelfColliders.Add(item);
			}
			HookArm instance2 = MonoSingleton<HookArm>.Instance;
			if ((Object)(object)instance2 != (Object)null)
			{
				componentsInChildren = ((Component)instance2).GetComponentsInChildren<Collider>(true);
				foreach (Collider item2 in componentsInChildren)
				{
					SelfColliders.Add(item2);
				}
			}
			_selfCollidersBuilt = true;
		}

		private static bool ColliderUsable(Collider collider)
		{
			if ((Object)(object)collider != (Object)null && collider.enabled)
			{
				return ((Component)collider).gameObject.activeInHierarchy;
			}
			return false;
		}

		private static void SetPhase(Phase next, string reason)
		{
			if (_phase != next)
			{
				if (UltraHookConfig.DebugLogging)
				{
					Plugin.Log.LogInfo((object)($"UltraHook phase: {_phase} -> {next} ({reason}) swing={UltraHookConfig.SwingMode} " + $"anchorActive={AnchorActive} rope={_currentRopeLength:0.00} min={ResolvedMinRopeLength():0.00} grace={_graceFrames}"));
				}
				_phase = next;
			}
		}

		private static float ResolvedMinRopeLength()
		{
			float num = PlayerRadius();
			return Mathf.Max(UltraHookConfig.MinRopeLength, num + 0.3f);
		}

		private static float PlayerRadius()
		{
			if ((Object)(object)_playerCollider == (Object)null)
			{
				NewMovement instance = MonoSingleton<NewMovement>.Instance;
				if ((Object)(object)instance != (Object)null)
				{
					_playerCollider = ((Component)instance).GetComponent<CapsuleCollider>();
				}
			}
			if (!((Object)(object)_playerCollider != (Object)null))
			{
				return 0.5f;
			}
			return _playerCollider.radius;
		}

		private static int Count(FieldInfo listField, HookArm hook)
		{
			if (!(listField.GetValue(hook) is ICollection collection))
			{
				return 0;
			}
			return collection.Count;
		}

		private static void LogImpact(Collider collider, Vector3 point, Vector3 normal, float distance, Vector3 travelDir, Vector3 from, Vector3 to)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_006e: 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)
			//IL_00bc: Unknown result type (might be due to invalid IL or missing references)
			//IL_00be: Unknown result type (might be due to invalid IL or missing references)
			float num = Vector3.Dot(-travelDir, normal);
			string text = (((Object)(object)collider != (Object)null) ? $"{LayerMask.LayerToName(((Component)collider).gameObject.layer)}({((Component)collider).gameObject.layer})" : "none");
			Plugin.Log.LogInfo((object)($"UltraHook tip impact: collider={((collider != null) ? ((Object)collider).name : null)} layer={text} point={point} normal={normal} dist={distance:0.00} " + $"impactDot={num:0.00} sweepHits={_diagSweepCount} rayHits={_diagRayCount} segment={Vector3.Distance(from, to):0.00}"));
		}
	}
	[HarmonyPatch(typeof(HookArm))]
	internal static class HookArmPatches
	{
		private static bool _errorLogged;

		[HarmonyPrefix]
		[HarmonyPatch("FixedUpdate")]
		private static bool FixedUpdatePrefix(HookArm __instance)
		{
			try
			{
				return GrappleHook.OnFixedUpdatePre(__instance);
			}
			catch (Exception arg)
			{
				LogOnce($"UltraHook detection/tracking failed and is now inert for this session: {arg}");
				return true;
			}
		}

		[HarmonyPostfix]
		[HarmonyPatch("FixedUpdate")]
		private static void FixedUpdatePostfix(HookArm __instance)
		{
			try
			{
				GrappleHook.OnFixedUpdatePost(__instance);
			}
			catch (Exception arg)
			{
				LogOnce($"UltraHook pull update failed and is now inert for this session: {arg}");
			}
		}

		[HarmonyPrefix]
		[HarmonyPatch("Update")]
		private static void UpdatePrefix(HookArm __instance)
		{
			try
			{
				GrappleHook.SuppressJumpCancel(__instance);
			}
			catch (Exception arg)
			{
				LogOnce($"UltraHook jump-suppress failed and is now inert for this session: {arg}");
			}
		}

		[HarmonyFinalizer]
		[HarmonyPatch("Update")]
		private static void UpdateFinalizer(HookArm __instance)
		{
			GrappleHook.RestoreJumpCancel(__instance);
		}

		[HarmonyPostfix]
		[HarmonyPatch("GetTotalLineDistance")]
		private static void GetTotalLineDistancePostfix(ref float __result)
		{
			try
			{
				GrappleHook.ScaleLineDistance(ref __result);
			}
			catch (Exception arg)
			{
				LogOnce($"UltraHook max-distance failed and is now inert for this session: {arg}");
			}
		}

		[HarmonyPostfix]
		[HarmonyPatch("StopThrow")]
		private static void StopThrowPostfix()
		{
			try
			{
				GrappleHook.OnRelease();
			}
			catch (Exception arg)
			{
				LogOnce($"UltraHook release failed and is now inert for this session: {arg}");
			}
		}

		[HarmonyPostfix]
		[HarmonyPatch("Cancel")]
		private static void CancelPostfix()
		{
			try
			{
				GrappleHook.OnRelease();
			}
			catch (Exception arg)
			{
				LogOnce($"UltraHook release failed and is now inert for this session: {arg}");
			}
		}

		private static void LogOnce(string message)
		{
			if (!_errorLogged)
			{
				_errorLogged = true;
				Plugin.Log.LogError((object)message);
			}
		}
	}
	[BepInPlugin("ultrahook.kiyroprower.ultrakill", "UltraHook", "1.3.4")]
	[BepInProcess("ULTRAKILL.exe")]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	public class Plugin : BaseUnityPlugin
	{
		public const string Guid = "ultrahook.kiyroprower.ultrakill";

		public const string PluginConfiguratorGuid = "com.eternalUnion.pluginConfigurator";

		internal static ManualLogSource Log;

		private Harmony _harmony;

		private void Awake()
		{
			//IL_001c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0026: Expected O, but got Unknown
			Log = ((BaseUnityPlugin)this).Logger;
			UltraHookConfig.Initialize(((BaseUnityPlugin)this).Logger);
			_harmony = new Harmony("ultrahook.kiyroprower.ultrakill");
			_harmony.PatchAll(typeof(HookArmPatches));
			Log.LogInfo((object)("UltraHook loaded (ultrahook.kiyroprower.ultrakill). Wall latching " + (UltraHookConfig.Enabled ? "enabled" : "disabled") + ", swing mode " + (UltraHookConfig.SwingMode ? "on" : "off") + "."));
		}

		private void OnDestroy()
		{
			Harmony harmony = _harmony;
			if (harmony != null)
			{
				harmony.UnpatchSelf();
			}
			GrappleHook.Cleanup();
		}
	}
	internal static class UltraHookConfig
	{
		[Serializable]
		[CompilerGenerated]
		private sealed class <>c
		{
			public static readonly <>c <>9 = new <>c();

			public static PostBoolValueChangeEvent <>9__107_0;

			internal void <CreateMenu>b__107_0(bool _)
			{
				UpdateMomentumVisibility();
			}
		}

		public const float VanillaMaxHookDistance = 300f;

		public const float DefaultSphereCastRadius = 0.12f;

		public const float DefaultSurfaceOffset = 0.5f;

		public const float DefaultMinRopeLength = 2.5f;

		public const float DefaultReelSpeed = 40f;

		public const float DefaultMinPullSpeed = 25f;

		public const float DefaultMaxPullSpeed = 90f;

		public const float DefaultPullAcceleration = 220f;

		public const float DefaultPullSpeedGain = 8f;

		public const float DefaultTautTolerance = 0.5f;

		public const float DefaultTautCorrectionGain = 10f;

		public const float DefaultTautAcceleration = 60f;

		public const float DefaultMaxInwardCorrectionSpeed = 20f;

		public const float DefaultMaxOutwardCorrectionSpeed = 30f;

		public const float DefaultMaxAngularSpeed = 6f;

		public const float DefaultTangentialDamping = 1.5f;

		public const float DefaultMaxMomentumBonus = 60f;

		public const float DefaultMaxReleaseSpeed = 150f;

		public const float DefaultDirectionFilterSpeed = 12f;

		public const float DefaultGroundSnapSuppressTime = 0.08f;

		private static PluginConfigurator _configurator;

		private static ManualLogSource _log;

		private static BoolField _enabledField;

		private static BoolField _swingModeField;

		private static BoolField _momentumField;

		private static StringField _maxHookDistanceField;

		private static FloatSliderField _sphereCastRadiusField;

		private static FloatSliderField _surfaceOffsetField;

		private static BoolField _backfaceField;

		private static StringField _extraHookableLayersField;

		private static StringField _unhookableLayersField;

		private static FloatSliderField _minRopeLengthField;

		private static FloatSliderField _reelSpeedField;

		private static FloatSliderField _minPullSpeedField;

		private static FloatSliderField _maxPullSpeedField;

		private static FloatSliderField _pullAccelerationField;

		private static FloatSliderField _pullSpeedGainField;

		private static FloatSliderField _tautToleranceField;

		private static FloatSliderField _tautCorrectionGainField;

		private static FloatSliderField _tautAccelerationField;

		private static FloatSliderField _maxInwardCorrectionField;

		private static FloatSliderField _maxOutwardCorrectionField;

		private static FloatSliderField _maxAngularSpeedField;

		private static FloatSliderField _tangentialDampingField;

		private static FloatSliderField _maxMomentumBonusField;

		private static FloatSliderField _maxReleaseSpeedField;

		private static FloatSliderField _directionFilterSpeedField;

		private static FloatSliderField _groundSnapSuppressField;

		private static BoolField _debugLoggingField;

		private static ConfigHeader _momentumBonusDescription;

		private static ConfigHeader _releaseSpeedDescription;

		private static ConfigHeader _directionFilterDescription;

		private static readonly Color TitleColor = new Color(1f, 0.62f, 0.16f);

		private static readonly Color EnabledColor = new Color(0.56f, 0.86f, 0.56f);

		private static readonly Color SwingColor = new Color(0.45f, 0.8f, 1f);

		private static readonly Color MomentumColor = new Color(1f, 0.8f, 0.35f);

		public static bool Enabled
		{
			get
			{
				if (_enabledField != null)
				{
					return _enabledField.value;
				}
				return true;
			}
		}

		public static bool SwingMode
		{
			get
			{
				if (_swingModeField != null)
				{
					return _swingModeField.value;
				}
				return false;
			}
		}

		public static bool Momentum
		{
			get
			{
				if (_momentumField != null)
				{
					return _momentumField.value;
				}
				return true;
			}
		}

		public static bool BackfaceCompatibility
		{
			get
			{
				if (_backfaceField != null)
				{
					return _backfaceField.value;
				}
				return false;
			}
		}

		public static bool DebugLogging
		{
			get
			{
				if (_debugLoggingField != null)
				{
					return _debugLoggingField.value;
				}
				return false;
			}
		}

		public static float SphereCastRadius => Slider(_sphereCastRadiusField, 0.12f, 0.01f);

		public static float SurfaceOffset => Slider(_surfaceOffsetField, 0.5f, 0.01f);

		public static float MinRopeLength => Slider(_minRopeLengthField, 2.5f, 0.5f);

		public static float ReelSpeed => Slider(_reelSpeedField, 40f, 0f);

		public static float MinPullSpeed => Slider(_minPullSpeedField, 25f, 0f);

		public static float MaxPullSpeed => Slider(_maxPullSpeedField, 90f, MinPullSpeed);

		public static float PullAcceleration => Slider(_pullAccelerationField, 220f, 1f);

		public static float PullSpeedGain => Slider(_pullSpeedGainField, 8f, 0f);

		public static float TautTolerance => Slider(_tautToleranceField, 0.5f, 0f);

		public static float TautCorrectionGain => Slider(_tautCorrectionGainField, 10f, 0f);

		public static float TautAcceleration => Slider(_tautAccelerationField, 60f, 1f);

		public static float MaxInwardCorrectionSpeed => Slider(_maxInwardCorrectionField, 20f, 0f);

		public static float MaxOutwardCorrectionSpeed => Slider(_maxOutwardCorrectionField, 30f, 0f);

		public static float MaxAngularSpeed => Slider(_maxAngularSpeedField, 6f, 0.1f);

		public static float TangentialDamping => Slider(_tangentialDampingField, 1.5f, 0f);

		public static float MaxMomentumBonus => Slider(_maxMomentumBonusField, 60f, 0f);

		public static float MaxReleaseSpeed => Slider(_maxReleaseSpeedField, 150f, 0f);

		public static float DirectionFilterSpeed => Slider(_directionFilterSpeedField, 12f, 0.1f);

		public static float GroundSnapSuppressTime => Slider(_groundSnapSuppressField, 0.08f, 0f);

		public static int HookableMask
		{
			get
			{
				//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)
				LayerMask val = LayerMaskDefaults.Get((LMD)1);
				int value = ((LayerMask)(ref val)).value;
				StringField extraHookableLayersField = _extraHookableLayersField;
				int num = value | ParseLayers((extraHookableLayersField != null) ? extraHookableLayersField.value : null);
				StringField unhookableLayersField = _unhookableLayersField;
				return num & ~ParseLayers((unhookableLayersField != null) ? unhookableLayersField.value : null) & -5;
			}
		}

		public static int UnhookableMask
		{
			get
			{
				StringField unhookableLayersField = _unhookableLayersField;
				return ParseLayers((unhookableLayersField != null) ? unhookableLayersField.value : null);
			}
		}

		public static float MaxHookDistance
		{
			get
			{
				if (_maxHookDistanceField == null)
				{
					return 300f;
				}
				string text = _maxHookDistanceField.value?.Trim();
				if (string.IsNullOrEmpty(text))
				{
					return 300f;
				}
				if (text.Equals("inf", StringComparison.OrdinalIgnoreCase) || text.Equals("infinite", StringComparison.OrdinalIgnoreCase))
				{
					return float.PositiveInfinity;
				}
				if (!float.TryParse(text, NumberStyles.Float, CultureInfo.InvariantCulture, out var result) || !(result > 0f))
				{
					return 300f;
				}
				return result;
			}
		}

		public static void Initialize(ManualLogSource log)
		{
			_log = log;
			try
			{
				CreateMenu();
				_log.LogInfo((object)"Config menu initialized.");
			}
			catch (Exception ex)
			{
				_log.LogWarning((object)("PluginConfigurator menu could not be initialized: " + ex.GetType().Name + ": " + ex.Message));
			}
		}

		private static void CreateMenu()
		{
			//IL_0033: Unknown result type (might be due to invalid IL or missing references)
			//IL_003d: Expected O, but got Unknown
			//IL_0043: Unknown result type (might be due to invalid IL or missing references)
			//IL_005b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0065: Expected O, but got Unknown
			//IL_006b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0083: Unknown result type (might be due to invalid IL or missing references)
			//IL_008d: Expected O, but got Unknown
			//IL_00bc: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f6: Unknown result type (might be due to invalid IL or missing references)
			//IL_0100: Expected O, but got Unknown
			//IL_017b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0185: Expected O, but got Unknown
			//IL_01a2: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ac: Expected O, but got Unknown
			//IL_01c9: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d3: Expected O, but got Unknown
			//IL_056e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0578: Expected O, but got Unknown
			//IL_00a6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ab: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b1: Expected O, but got Unknown
			if (_configurator != null)
			{
				return;
			}
			_configurator = PluginConfigurator.Create("UltraHook", "ultrahook.kiyroprower.ultrakill");
			ConfigPanel rootPanel = _configurator.rootPanel;
			_enabledField = new BoolField(rootPanel, "Enabled", "ultrahook.enabled", true, true);
			AddDescription(rootPanel, "Let the Whiplash grapple onto solid surfaces.", EnabledColor);
			_swingModeField = new BoolField(rootPanel, "Swing Mode", "ultrahook.swingMode", false, true);
			AddDescription(rootPanel, "On, the hook is a rope you swing on and it stays attached until you press the hook key again. Off, it reels V1 straight to the surface.", SwingColor);
			_momentumField = new BoolField(rootPanel, "Momentum", "ultrahook.momentum", true, true);
			BoolField momentumField = _momentumField;
			object obj = <>c.<>9__107_0;
			if (obj == null)
			{
				PostBoolValueChangeEvent val = delegate
				{
					UpdateMomentumVisibility();
				};
				<>c.<>9__107_0 = val;
				obj = (object)val;
			}
			momentumField.postValueChangeEvent += (PostBoolValueChangeEvent)obj;
			AddDescription(rootPanel, "Build launch speed as the pull travels. Cancel with the hook key to keep it, ride to the end and it fades.", MomentumColor);
			AddTitle(rootPanel, "Detection");
			_maxHookDistanceField = new StringField(rootPanel, "Max Hook Distance", "ultrahook.maxHookDistance", 300f.ToString("0", CultureInfo.InvariantCulture), true);
			AddDescription(rootPanel, "How far the hook can reach. Default is the vanilla range. Type \"inf\" for unlimited.");
			_sphereCastRadiusField = Slider(rootPanel, "Sphere Cast Radius", "ultrahook.sphereRadius", 0.05f, 0.5f, 0.12f, 2);
			AddDescription(rootPanel, "Thickness of the travelling hook tip. Larger values catch edges, seams, and shallow angles more easily.");
			_surfaceOffsetField = Slider(rootPanel, "Surface Offset", "ultrahook.surfaceOffset", 0.1f, 3f, 0.5f, 2);
			AddDescription(rootPanel, "How far off the surface the anchor sits. Lower values pull V1 closer into the surface.");
			_backfaceField = new BoolField(rootPanel, "Backface Compatibility", "ultrahook.backface", false, true);
			AddDescription(rootPanel, "Allow the aim probe to hit the reverse side of one-sided meshes. Enable only if some surfaces refuse to hook.");
			_extraHookableLayersField = new StringField(rootPanel, "Extra Hookable Layers", "ultrahook.extraLayers", "", true);
			AddDescription(rootPanel, "Advanced. Extra layer numbers to treat as hookable, separated by spaces or commas.");
			_unhookableLayersField = new StringField(rootPanel, "Unhookable Layers", "ultrahook.unhookableLayers", "", true);
			AddDescription(rootPanel, "Advanced. Layer numbers to never hook, separated by spaces or commas.");
			AddTitle(rootPanel, "Pull");
			_minRopeLengthField = Slider(rootPanel, "Minimum Rope Length", "ultrahook.minRope", 1f, 10f, 2.5f, 1);
			AddDescription(rootPanel, "How far from the anchor V1 settles when the rope goes taut. Keeps V1 clear of the surface.");
			_reelSpeedField = Slider(rootPanel, "Reel Speed", "ultrahook.reelSpeed", 0f, 150f, 40f, 0);
			AddDescription(rootPanel, "How fast the virtual rope shortens toward its minimum length.");
			_minPullSpeedField = Slider(rootPanel, "Minimum Pull Speed", "ultrahook.minPull", 0f, 120f, 25f, 0);
			AddDescription(rootPanel, "Slowest speed V1 is drawn toward the anchor at.");
			_maxPullSpeedField = Slider(rootPanel, "Maximum Pull Speed", "ultrahook.maxPull", 10f, 250f, 90f, 0);
			AddDescription(rootPanel, "Fastest speed V1 is drawn toward the anchor at.");
			_pullAccelerationField = Slider(rootPanel, "Pull Acceleration", "ultrahook.pullAccel", 10f, 1000f, 220f, 0);
			AddDescription(rootPanel, "How quickly the pull speed ramps up. Lower feels heavier.");
			_pullSpeedGainField = Slider(rootPanel, "Pull Speed Gain", "ultrahook.pullGain", 0f, 40f, 8f, 1);
			AddDescription(rootPanel, "How much the pull speeds up when the rope is stretched far past its length.");
			AddTitle(rootPanel, "Taut and Swing");
			_tautToleranceField = Slider(rootPanel, "Taut Tolerance", "ultrahook.tautTolerance", 0f, 3f, 0.5f, 2);
			AddDescription(rootPanel, "How close to the minimum length the rope is before it counts as taut.");
			_tautCorrectionGainField = Slider(rootPanel, "Taut Correction Gain", "ultrahook.tautGain", 0f, 40f, 10f, 1);
			AddDescription(rootPanel, "How firmly the taut rope holds its length.");
			_tautAccelerationField = Slider(rootPanel, "Taut Acceleration", "ultrahook.tautAccel", 5f, 400f, 60f, 0);
			AddDescription(rootPanel, "How quickly the taut correction is applied.");
			_maxInwardCorrectionField = Slider(rootPanel, "Max Inward Correction Speed", "ultrahook.maxInward", 0f, 120f, 20f, 0);
			AddDescription(rootPanel, "Fastest the taut rope pulls V1 back in when it drifts too far out.");
			_maxOutwardCorrectionField = Slider(rootPanel, "Max Outward Correction Speed", "ultrahook.maxOutward", 0f, 120f, 30f, 0);
			AddDescription(rootPanel, "Fastest the taut rope lets V1 ease back out when it is pushed too close.");
			_maxAngularSpeedField = Slider(rootPanel, "Max Angular Speed", "ultrahook.maxAngular", 0.5f, 20f, 6f, 1);
			AddDescription(rootPanel, "Caps how fast V1 can swing around the anchor. Prevents runaway orbiting.");
			_tangentialDampingField = Slider(rootPanel, "Tangential Damping", "ultrahook.tangentialDamping", 0f, 10f, 1.5f, 2);
			AddDescription(rootPanel, "How quickly swinging motion bleeds off. Higher settles the swing sooner.");
			AddTitle(rootPanel, "Momentum");
			_maxMomentumBonusField = Slider(rootPanel, "Max Momentum Bonus", "ultrahook.maxMomentum", 0f, 200f, 60f, 0);
			_momentumBonusDescription = AddDescription(rootPanel, "Extra launch speed a full-length pull can bank for the cancel.");
			_maxReleaseSpeedField = Slider(rootPanel, "Max Release Speed", "ultrahook.maxRelease", 0f, 400f, 150f, 0);
			_releaseSpeedDescription = AddDescription(rootPanel, "Hard cap on the speed a cancel can fling V1 at.");
			_directionFilterSpeedField = Slider(rootPanel, "Direction Filter Speed", "ultrahook.dirFilter", 1f, 60f, 12f, 0);
			_directionFilterDescription = AddDescription(rootPanel, "How quickly the release direction tracks the rope. Lower smooths out sudden angle changes.");
			UpdateMomentumVisibility();
			AddTitle(rootPanel, "Release and Diagnostics");
			_groundSnapSuppressField = Slider(rootPanel, "Ground Snap Suppression", "ultrahook.groundSuppress", 0f, 0.3f, 0.08f, 2);
			AddDescription(rootPanel, "Seconds after a cancel where ground snapping is held off so the launch is not redirected upward.");
			_debugLoggingField = new BoolField(rootPanel, "Debug Logging", "ultrahook.debug", false, true);
			AddDescription(rootPanel, "Log failed hook attempts and draw debug lines. For troubleshooting only.");
		}

		private static void UpdateMomentumVisibility()
		{
			bool hidden = !Momentum;
			SetHidden(_maxMomentumBonusField, _momentumBonusDescription, hidden);
			SetHidden(_maxReleaseSpeedField, _releaseSpeedDescription, hidden);
			SetHidden(_directionFilterSpeedField, _directionFilterDescription, hidden);
		}

		private static void SetHidden(FloatSliderField field, ConfigHeader description, bool hidden)
		{
			if (field != null)
			{
				((ConfigField)field).hidden = hidden;
			}
			if (description != null)
			{
				((ConfigField)description).hidden = hidden;
			}
		}

		private static FloatSliderField Slider(ConfigPanel panel, string name, string guid, float min, float max, float value, int decimals)
		{
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			//IL_0016: Expected O, but got Unknown
			return new FloatSliderField(panel, name, guid, new Tuple<float, float>(min, max), value, decimals, true);
		}

		private static float Slider(FloatSliderField field, float fallback, float min)
		{
			if (field != null)
			{
				return Mathf.Max(field.value, min);
			}
			return fallback;
		}

		private static int ParseLayers(string raw)
		{
			if (string.IsNullOrWhiteSpace(raw))
			{
				return 0;
			}
			int num = 0;
			string[] array = raw.Split(new char[4] { ' ', ',', ';', '\t' }, StringSplitOptions.RemoveEmptyEntries);
			for (int i = 0; i < array.Length; i++)
			{
				if (int.TryParse(array[i], NumberStyles.Integer, CultureInfo.InvariantCulture, out var result) && result >= 0 && result <= 31)
				{
					num |= 1 << result;
				}
			}
			return num;
		}

		private static ConfigHeader AddTitle(ConfigPanel panel, string text)
		{
			//IL_0004: Unknown result type (might be due to invalid IL or missing references)
			//IL_0009: Unknown result type (might be due to invalid IL or missing references)
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0015: Expected O, but got Unknown
			return new ConfigHeader(panel, text, 18)
			{
				textColor = TitleColor
			};
		}

		private static ConfigHeader AddDescription(ConfigPanel panel, string text)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			return AddDescription(panel, text, Color.gray);
		}

		private static ConfigHeader AddDescription(ConfigPanel panel, string text, Color color)
		{
			//IL_0004: Unknown result type (might be due to invalid IL or missing references)
			//IL_0009: Unknown result type (might be due to invalid IL or missing references)
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0011: Expected O, but got Unknown
			return new ConfigHeader(panel, text, 14)
			{
				textColor = color
			};
		}
	}
}