Decompiled source of Mantle v1.0.0

Mantle.dll

Decompiled 7 hours ago
using System;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Text;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Core.Logging.Interpolation;
using BepInEx.Logging;
using BepInEx.Unity.IL2CPP;
using HarmonyLib;
using Il2CppInterop.Runtime.InteropTypes.Arrays;
using Microsoft.CodeAnalysis;
using Rewired;
using UnityEngine;
using UnityStandardAssets.Characters.FirstPerson;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETCoreApp,Version=v6.0", FrameworkDisplayName = ".NET 6.0")]
[assembly: AssemblyCompany("Mantle")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0")]
[assembly: AssemblyProduct("Mantle")]
[assembly: AssemblyTitle("Mantle")]
[assembly: AssemblyVersion("1.0.0.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 Mantle
{
	internal static class Ledge
	{
		private const float Skin = 0.02f;

		private const float Clearance = 0.15f;

		private static readonly float[] Depths = new float[6] { 0.04f, 0.12f, 0.25f, 0.4f, 0.6f, 0.85f };

		private const float ThinProbeRadius = 0.06f;

		private static string lastBlocker = "";

		public static Vector3 Center(Transform t, CharacterController cc)
		{
			//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)
			return t.TransformPoint(cc.center);
		}

		public static bool TryFind(Transform t, CharacterController cc, out Vector3 target, out bool vault)
		{
			//IL_0001: 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_001c: 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_001e: 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_0034: Unknown result type (might be due to invalid IL or missing references)
			//IL_0039: Unknown result type (might be due to invalid IL or missing references)
			//IL_003b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0040: Unknown result type (might be due to invalid IL or missing references)
			//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_004e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0053: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a7: 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_00b9: 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)
			//IL_00d9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fa: Unknown result type (might be due to invalid IL or missing references)
			//IL_013f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0144: Unknown result type (might be due to invalid IL or missing references)
			//IL_014a: Unknown result type (might be due to invalid IL or missing references)
			//IL_014f: 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_0158: Unknown result type (might be due to invalid IL or missing references)
			//IL_0161: 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_0180: Unknown result type (might be due to invalid IL or missing references)
			//IL_0187: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a1: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ab: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f0: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f5: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f8: Unknown result type (might be due to invalid IL or missing references)
			//IL_01fd: Unknown result type (might be due to invalid IL or missing references)
			//IL_0202: Unknown result type (might be due to invalid IL or missing references)
			//IL_0206: Unknown result type (might be due to invalid IL or missing references)
			//IL_020f: Unknown result type (might be due to invalid IL or missing references)
			//IL_021b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0282: Unknown result type (might be due to invalid IL or missing references)
			//IL_0284: Unknown result type (might be due to invalid IL or missing references)
			//IL_0457: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c2: Unknown result type (might be due to invalid IL or missing references)
			//IL_04a2: Unknown result type (might be due to invalid IL or missing references)
			//IL_04a7: Unknown result type (might be due to invalid IL or missing references)
			//IL_04ab: Unknown result type (might be due to invalid IL or missing references)
			//IL_04d4: Unknown result type (might be due to invalid IL or missing references)
			//IL_04d9: Unknown result type (might be due to invalid IL or missing references)
			//IL_04dd: Unknown result type (might be due to invalid IL or missing references)
			//IL_0506: Unknown result type (might be due to invalid IL or missing references)
			//IL_050b: Unknown result type (might be due to invalid IL or missing references)
			//IL_050f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0314: Unknown result type (might be due to invalid IL or missing references)
			//IL_031e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0559: Unknown result type (might be due to invalid IL or missing references)
			//IL_0561: Unknown result type (might be due to invalid IL or missing references)
			//IL_056c: Unknown result type (might be due to invalid IL or missing references)
			//IL_056d: Unknown result type (might be due to invalid IL or missing references)
			//IL_03a6: Unknown result type (might be due to invalid IL or missing references)
			//IL_034e: Unknown result type (might be due to invalid IL or missing references)
			//IL_03db: Unknown result type (might be due to invalid IL or missing references)
			//IL_03c1: Unknown result type (might be due to invalid IL or missing references)
			//IL_0361: Unknown result type (might be due to invalid IL or missing references)
			//IL_036b: Unknown result type (might be due to invalid IL or missing references)
			//IL_05b2: Unknown result type (might be due to invalid IL or missing references)
			//IL_05b7: Unknown result type (might be due to invalid IL or missing references)
			//IL_05ba: Unknown result type (might be due to invalid IL or missing references)
			//IL_05bf: Unknown result type (might be due to invalid IL or missing references)
			//IL_05c4: Unknown result type (might be due to invalid IL or missing references)
			//IL_05c8: Unknown result type (might be due to invalid IL or missing references)
			//IL_05d1: Unknown result type (might be due to invalid IL or missing references)
			//IL_05dd: Unknown result type (might be due to invalid IL or missing references)
			//IL_03eb: Unknown result type (might be due to invalid IL or missing references)
			//IL_03f5: Unknown result type (might be due to invalid IL or missing references)
			//IL_064c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0651: Unknown result type (might be due to invalid IL or missing references)
			//IL_0661: Unknown result type (might be due to invalid IL or missing references)
			//IL_0666: Unknown result type (might be due to invalid IL or missing references)
			//IL_066b: Unknown result type (might be due to invalid IL or missing references)
			//IL_066f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0678: Unknown result type (might be due to invalid IL or missing references)
			//IL_0684: Unknown result type (might be due to invalid IL or missing references)
			//IL_0686: Unknown result type (might be due to invalid IL or missing references)
			//IL_05e8: Unknown result type (might be due to invalid IL or missing references)
			//IL_05ea: Unknown result type (might be due to invalid IL or missing references)
			//IL_0402: Unknown result type (might be due to invalid IL or missing references)
			//IL_0388: Unknown result type (might be due to invalid IL or missing references)
			//IL_071b: Unknown result type (might be due to invalid IL or missing references)
			//IL_05f6: Unknown result type (might be due to invalid IL or missing references)
			//IL_05f8: Unknown result type (might be due to invalid IL or missing references)
			//IL_0412: Unknown result type (might be due to invalid IL or missing references)
			//IL_07c2: Unknown result type (might be due to invalid IL or missing references)
			//IL_0751: Unknown result type (might be due to invalid IL or missing references)
			//IL_07d0: Unknown result type (might be due to invalid IL or missing references)
			//IL_07d2: Unknown result type (might be due to invalid IL or missing references)
			//IL_07e1: Unknown result type (might be due to invalid IL or missing references)
			//IL_07e3: Unknown result type (might be due to invalid IL or missing references)
			target = default(Vector3);
			vault = false;
			int playerMovementLayerMask = Toolbox.Instance.playerMovementLayerMask;
			Vector3 val = Center(t, cc);
			Vector3 val2 = val - Vector3.up * (cc.height * 0.5f);
			Vector3 val3 = Vector3.ProjectOnPlane(t.forward, Vector3.up);
			Vector3 normalized = ((Vector3)(ref val3)).normalized;
			if (((Vector3)(ref normalized)).sqrMagnitude < 0.01f)
			{
				return false;
			}
			float value = Plugin.MinHeight.Value;
			float value2 = Plugin.MaxHeight.Value;
			float num = cc.radius + Plugin.Reach.Value;
			float num2 = Mathf.Cos(Plugin.MaxSlope.Value * ((float)Math.PI / 180f));
			RaycastHit val4 = default(RaycastHit);
			if (!Physics.Raycast(val2 + Vector3.up * (value + 0.05f), normalized, ref val4, num, playerMovementLayerMask, (QueryTriggerInteraction)1))
			{
				return Fail("no wall");
			}
			if (Mathf.Abs(((RaycastHit)(ref val4)).normal.y) > 0.5f)
			{
				return Fail("not a wall");
			}
			float num3 = val2.y + value2 + 0.1f;
			float num4 = float.NaN;
			float num5 = 0f;
			float num6 = 0f;
			bool flag = false;
			bool value3 = Plugin.DebugLogging.Value;
			StringBuilder stringBuilder = (value3 ? new StringBuilder() : null);
			Vector3 val5 = ((RaycastHit)(ref val4)).point + normalized * 0.02f;
			Vector3 val6 = default(Vector3);
			((Vector3)(ref val6))..ctor(val5.x, num3, val5.z);
			if (!Physics.CheckSphere(val6, 0.06f, playerMovementLayerMask, (QueryTriggerInteraction)1))
			{
				flag = true;
				RaycastHit val7 = default(RaycastHit);
				if (Physics.SphereCast(val6, 0.06f, Vector3.down, ref val7, value2 + 0.6f, playerMovementLayerMask, (QueryTriggerInteraction)1))
				{
					float num7 = ((RaycastHit)(ref val7)).point.y - val2.y;
					if (num7 >= value && num7 <= value2)
					{
						num4 = ((RaycastHit)(ref val7)).point.y;
						num5 = (num6 = 0.02f);
					}
				}
			}
			float[] depths = Depths;
			Vector3 val9 = default(Vector3);
			RaycastHit val10 = default(RaycastHit);
			foreach (float num8 in depths)
			{
				Vector3 val8 = ((RaycastHit)(ref val4)).point + normalized * num8;
				((Vector3)(ref val9))..ctor(val8.x, num3, val8.z);
				if (Physics.CheckSphere(val9, 0.03f, playerMovementLayerMask, (QueryTriggerInteraction)1))
				{
					if (stringBuilder != null)
					{
						StringBuilder stringBuilder2 = stringBuilder;
						StringBuilder.AppendInterpolatedStringHandler handler = new StringBuilder.AppendInterpolatedStringHandler(8, 1, stringBuilder2);
						handler.AppendLiteral(" ");
						handler.AppendFormatted(num8, "0.00");
						handler.AppendLiteral(":inside");
						stringBuilder2.Append(ref handler);
					}
					if (!float.IsNaN(num4))
					{
						break;
					}
					continue;
				}
				flag = true;
				bool flag2 = Physics.Raycast(val9, Vector3.down, ref val10, value2 + 0.6f, playerMovementLayerMask, (QueryTriggerInteraction)1);
				stringBuilder?.Append(flag2 ? $" {num8:0.00}:{((RaycastHit)(ref val10)).point.y - val2.y:0.00}" : $" {num8:0.00}:miss");
				if (float.IsNaN(num4))
				{
					if (flag2 && !(((RaycastHit)(ref val10)).normal.y < num2))
					{
						float num9 = ((RaycastHit)(ref val10)).point.y - val2.y;
						if (!(num9 < value) && !(num9 > value2))
						{
							num4 = ((RaycastHit)(ref val10)).point.y;
							num5 = (num6 = num8);
						}
					}
				}
				else if (flag2 && Mathf.Abs(((RaycastHit)(ref val10)).point.y - num4) < 0.2f && ((RaycastHit)(ref val10)).normal.y >= num2)
				{
					num6 = num8;
				}
				else
				{
					if (!flag2 || !(((RaycastHit)(ref val10)).point.y > num4) || !(((RaycastHit)(ref val10)).point.y - val2.y <= value2) || !(((RaycastHit)(ref val10)).normal.y >= num2))
					{
						break;
					}
					num4 = ((RaycastHit)(ref val10)).point.y;
					num5 = (num6 = num8);
				}
			}
			if (float.IsNaN(num4))
			{
				return Fail(flag ? "no usable top surface" : "taller than reach");
			}
			float num10 = num4 - val2.y;
			lastBlocker = "nothing";
			object obj;
			if (value3)
			{
				DefaultInterpolatedStringHandler defaultInterpolatedStringHandler = new DefaultInterpolatedStringHandler(8, 4);
				defaultInterpolatedStringHandler.AppendFormatted(((Object)((RaycastHit)(ref val4)).collider).name);
				defaultInterpolatedStringHandler.AppendLiteral(" size ");
				Bounds bounds = ((RaycastHit)(ref val4)).collider.bounds;
				defaultInterpolatedStringHandler.AppendFormatted(((Bounds)(ref bounds)).size.x, "0.00");
				defaultInterpolatedStringHandler.AppendLiteral("x");
				bounds = ((RaycastHit)(ref val4)).collider.bounds;
				defaultInterpolatedStringHandler.AppendFormatted(((Bounds)(ref bounds)).size.y, "0.00");
				defaultInterpolatedStringHandler.AppendLiteral("x");
				bounds = ((RaycastHit)(ref val4)).collider.bounds;
				defaultInterpolatedStringHandler.AppendFormatted(((Bounds)(ref bounds)).size.z, "0.00");
				obj = defaultInterpolatedStringHandler.ToStringAndClear();
			}
			else
			{
				obj = "";
			}
			string value4 = (string)obj;
			float num11 = num4 + cc.height * 0.5f + cc.skinWidth + 0.02f + 0.15f;
			Vector3 val11 = default(Vector3);
			((Vector3)(ref val11))..ctor(val.x, num11, val.z);
			if (!PathClear(val, val11, cc, playerMovementLayerMask))
			{
				return Fail("no headroom (hit " + lastBlocker + ")");
			}
			float num12 = Mathf.Max(num5, cc.radius + 0.05f);
			if (num6 >= num12)
			{
				Vector3 val12 = ((RaycastHit)(ref val4)).point + normalized * num12;
				Vector3 val13 = default(Vector3);
				((Vector3)(ref val13))..ctor(val12.x, num11, val12.z);
				if (!Blocked(val13, cc, playerMovementLayerMask) && PathClear(val11, val13, cc, playerMovementLayerMask))
				{
					target = val13;
					Log($"mantle onto ledge, height {num10:0.00}m");
					return true;
				}
			}
			if (Plugin.EnableVault.Value)
			{
				Vector3 val14 = ((RaycastHit)(ref val4)).point + normalized * (num6 + cc.radius + 0.15f);
				Vector3 val15 = default(Vector3);
				((Vector3)(ref val15))..ctor(val14.x, num11, val14.z);
				RaycastHit val16 = default(RaycastHit);
				if (!Physics.Raycast(val15, Vector3.down, ref val16, cc.height * 0.5f + Plugin.MaxVaultDrop.Value + num10, playerMovementLayerMask, (QueryTriggerInteraction)1))
				{
					return Fail($"vault: no ground on the far side (height {num10:0.00}m, obstacle {value4}, profile{stringBuilder})");
				}
				if (num4 - ((RaycastHit)(ref val16)).point.y > Plugin.MaxVaultDrop.Value)
				{
					return Fail($"vault: drop too far ({num4 - ((RaycastHit)(ref val16)).point.y:0.00}m, landing on {((Object)((RaycastHit)(ref val16)).collider).name} layer {((Component)((RaycastHit)(ref val16)).collider).gameObject.layer})");
				}
				if (!Blocked(val15, cc, playerMovementLayerMask) && PathClear(val11, val15, cc, playerMovementLayerMask))
				{
					target = val15;
					vault = true;
					Log($"vault over obstacle, height {num10:0.00}m, depth {num6:0.00}m, landing on {((Object)((RaycastHit)(ref val16)).collider).name} (layer {((Component)((RaycastHit)(ref val16)).collider).gameObject.layer})");
					return true;
				}
			}
			return Fail(((num6 >= num12) ? "no room to stand" : "too thin to stand on, can't vault") + $" (height {num10:0.00}m, depth {num6:0.00}m, blocked by {lastBlocker}, obstacle {value4}, profile{stringBuilder})");
		}

		private static bool IsPlayer(Collider c, CharacterController cc)
		{
			if (!((Object)(object)c == (Object)null) && !((Object)(object)c == (Object)(object)cc) && !((Component)c).transform.IsChildOf(((Component)cc).transform))
			{
				return ((Component)cc).transform.IsChildOf(((Component)c).transform);
			}
			return true;
		}

		private static bool PathClear(Vector3 from, Vector3 to, CharacterController cc, int mask)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0001: 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)
			float num = Vector3.Distance(from, to);
			int num2 = Mathf.Max(1, Mathf.CeilToInt(num / 0.1f));
			for (int i = 1; i <= num2; i++)
			{
				if (Overlaps(Vector3.Lerp(from, to, (float)i / (float)num2), cc, mask, cc.radius * 0.9f))
				{
					return false;
				}
			}
			return true;
		}

		private static Vector3 Bottom(Vector3 center, CharacterController cc)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0019: 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)
			return center - Vector3.up * (cc.height * 0.5f - cc.radius);
		}

		private static Vector3 TopPoint(Vector3 center, CharacterController cc)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0019: 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)
			return center + Vector3.up * (cc.height * 0.5f - cc.radius);
		}

		private static bool Blocked(Vector3 center, CharacterController cc, int mask)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			return Overlaps(center, cc, mask, cc.radius * 0.95f);
		}

		private static bool Overlaps(Vector3 center, CharacterController cc, int mask, float radius)
		{
			//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_0009: Unknown result type (might be due to invalid IL or missing references)
			foreach (Collider item in (Il2CppArrayBase<Collider>)(object)Physics.OverlapCapsule(Bottom(center, cc), TopPoint(center, cc), radius, mask, (QueryTriggerInteraction)1))
			{
				if (!IsPlayer(item, cc))
				{
					lastBlocker = ((Object)item).name;
					return true;
				}
			}
			return false;
		}

		private static void Log(string message)
		{
			if (Plugin.DebugLogging.Value)
			{
				Plugin.Logger.LogInfo((object)("Mantle: " + message));
			}
		}

		private static bool Fail(string reason)
		{
			Log(reason);
			return false;
		}
	}
	[BepInPlugin("sodmods.mantle", "Mantle", "1.0.0")]
	public class Plugin : BasePlugin
	{
		internal static ManualLogSource Logger;

		internal static ConfigEntry<float> MinHeight;

		internal static ConfigEntry<float> MaxHeight;

		internal static ConfigEntry<float> Reach;

		internal static ConfigEntry<float> Duration;

		internal static ConfigEntry<float> VaultDuration;

		internal static ConfigEntry<float> SprintSpeedup;

		internal static ConfigEntry<bool> RequireForward;

		internal static ConfigEntry<float> DipAngle;

		internal static ConfigEntry<float> RollAngle;

		internal static ConfigEntry<float> MaxSlope;

		internal static ConfigEntry<bool> EnableVault;

		internal static ConfigEntry<float> MaxVaultDrop;

		internal static ConfigEntry<bool> DebugLogging;

		public override void Load()
		{
			//IL_01d8: Unknown result type (might be due to invalid IL or missing references)
			Logger = ((BasePlugin)this).Log;
			MinHeight = ((BasePlugin)this).Config.Bind<float>("Mantle", "MinLedgeHeight", 0.5f, "Lowest ledge (metres above your feet) that triggers a mantle. Lower things you can just step or jump onto.");
			MaxHeight = ((BasePlugin)this).Config.Bind<float>("Mantle", "MaxLedgeHeight", 2f, "Highest ledge (metres above your feet) you can pull yourself onto. Measured from where your feet are at that moment, so jumping first reaches higher.");
			Reach = ((BasePlugin)this).Config.Bind<float>("Mantle", "Reach", 0.6f, "How far in front of you (metres) a ledge can be.");
			Duration = ((BasePlugin)this).Config.Bind<float>("Mantle", "Duration", 1.2f, "How long climbing onto a ledge takes, in seconds.");
			VaultDuration = ((BasePlugin)this).Config.Bind<float>("Vault", "Duration", 1f, "How long vaulting over an obstacle takes, in seconds.");
			SprintSpeedup = ((BasePlugin)this).Config.Bind<float>("Mantle", "SprintMultiplier", 0.85f, "Duration multiplier when you hit the ledge while sprinting (0.85 = 15% quicker; 1 = no change).");
			MaxSlope = ((BasePlugin)this).Config.Bind<float>("Mantle", "MaxSurfaceSlope", 50f, "Steepest top surface (degrees) you can climb onto, e.g. sloped lids and car trunks.");
			EnableVault = ((BasePlugin)this).Config.Bind<bool>("Vault", "Enabled", true, "Vault over thin obstacles (fences, railings) instead of only climbing onto things.");
			MaxVaultDrop = ((BasePlugin)this).Config.Bind<float>("Vault", "MaxDrop", 4f, "Furthest drop (metres below the top) allowed on the far side of a vault. Drops up to about 4m do not risk fall damage.");
			DipAngle = ((BasePlugin)this).Config.Bind<float>("Camera", "DipAngle", 9f, "How far (degrees) your view tips down as you haul yourself up. 0 = no dip.");
			RollAngle = ((BasePlugin)this).Config.Bind<float>("Camera", "RollAngle", 3f, "How far (degrees) your view tilts sideways during the climb. 0 = no tilt.");
			RequireForward = ((BasePlugin)this).Config.Bind<bool>("Controls", "RequireForward", true, "Only mantle while holding forward, so a plain jump in front of a wall stays a jump.");
			DebugLogging = ((BasePlugin)this).Config.Bind<bool>("Debug", "LogMantles", false, "Log ledge detection results (for tuning and bug reports).");
			new Harmony("sodmods.mantle").PatchAll(typeof(Plugin).Assembly);
			((BasePlugin)this).Log.LogInfo((object)"Mantle loaded");
			PhysicsSelfTest();
		}

		private void PhysicsSelfTest()
		{
			//IL_000f: 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_0015: Unknown result type (might be due to invalid IL or missing references)
			//IL_0029: 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_0038: Unknown result type (might be due to invalid IL or missing references)
			//IL_003d: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				Vector3 val = new Vector3(0f, -10000f, 0f);
				RaycastHit val2 = default(RaycastHit);
				Physics.Raycast(val, Vector3.down, ref val2, 1f, -1, (QueryTriggerInteraction)1);
				Physics.CheckSphere(val, 0.1f, -1, (QueryTriggerInteraction)1);
				Physics.OverlapCapsule(val, val + Vector3.up, 0.3f, -1, (QueryTriggerInteraction)1);
				((BasePlugin)this).Log.LogInfo((object)"Physics self-test OK");
			}
			catch (Exception ex)
			{
				((BasePlugin)this).Log.LogError((object)("Physics self-test FAILED, mantling will not work: " + ex.Message));
			}
		}
	}
	[HarmonyPatch(typeof(FirstPersonController), "UpdateMovement")]
	internal static class MantlePatch
	{
		private static bool active;

		private static Vector3 startCenter;

		private static Vector3 liftCenter;

		private static Vector3 endCenter;

		private static float elapsed;

		private static int stuckSteps;

		private static float cooldownUntil;

		private static float nextErrorLog;

		private static bool hookLogged;

		private static float nextReasonLog;

		private static float duration;

		private static bool Prefix(FirstPersonController __instance)
		{
			//IL_007a: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				CharacterController characterController = __instance.m_CharacterController;
				if ((Object)(object)characterController == (Object)null || !((Collider)characterController).enabled)
				{
					active = false;
					return true;
				}
				float dt = (Game.Instance.updateMovementEveryFrame ? Time.smoothDeltaTime : Time.fixedDeltaTime);
				if (active)
				{
					Step(__instance, characterController, dt);
					return false;
				}
				if (!CanStart(__instance, characterController))
				{
					return true;
				}
				if (!Ledge.TryFind(((Component)__instance).transform, characterController, out var target, out var vault))
				{
					return true;
				}
				Begin(__instance, characterController, target, vault);
				Step(__instance, characterController, dt);
				return false;
			}
			catch (Exception ex)
			{
				if (Time.unscaledTime >= nextErrorLog)
				{
					nextErrorLog = Time.unscaledTime + 10f;
					Plugin.Logger.LogError((object)ex);
				}
				active = false;
				return true;
			}
		}

		private static bool CanStart(FirstPersonController fpc, CharacterController cc)
		{
			if (!hookLogged)
			{
				hookLogged = true;
				Plugin.Logger.LogInfo((object)"Movement hook active");
			}
			InputController instance = InputController.Instance;
			Player val = ((instance != null) ? instance.player : null);
			bool flag = val != null && val.GetButton("Jump");
			string text = null;
			if (Time.unscaledTime < cooldownUntil)
			{
				text = "cooldown";
			}
			else if ((Object)(object)SessionData.Instance == (Object)null || !SessionData.Instance.startedGame || !SessionData.Instance.play)
			{
				text = "game not running";
			}
			else if (!fpc.enableMovement || fpc.ghostMovement || !fpc.clipping)
			{
				text = "movement disabled/ghost";
			}
			else if ((Object)(object)Player.Instance == (Object)null || Player.Instance.transitionActive || ((Actor)Player.Instance).inAirVent)
			{
				text = "transition or vent";
			}
			else if ((Object)(object)ModifiersController.Instance != (Object)null && ModifiersController.Instance.ratDetectiveActive)
			{
				text = "rat mode";
			}
			else if ((Object)(object)InteractionController.Instance != (Object)null && InteractionController.Instance.lockedInInteraction != null)
			{
				text = "locked in interaction";
			}
			else if ((Object)(object)StatusController.Instance != (Object)null && StatusController.Instance.disabledJump)
			{
				text = "jump disabled";
			}
			else if (!flag)
			{
				text = "jump not held";
			}
			else if (Plugin.RequireForward.Value && Forward(val) < 0.3f)
			{
				text = $"forward not held ({Forward(val):0.00})";
			}
			else if (cc.isGrounded && !fpc.m_Jump)
			{
				text = "grounded, no jump pending";
			}
			if (text != null && flag && Plugin.DebugLogging.Value && Time.unscaledTime >= nextReasonLog)
			{
				nextReasonLog = Time.unscaledTime + 0.5f;
				Plugin.Logger.LogInfo((object)("Mantle: not starting: " + text));
			}
			return text == null;
		}

		private static float Forward(Player input)
		{
			if ((Object)(object)InputController.Instance != (Object)null && !InputController.Instance.mouseInputMode)
			{
				return input.GetAxis("MoveVertical");
			}
			return input.GetAxis("MoveForward") + input.GetAxis("MoveBack");
		}

		private static void Begin(FirstPersonController fpc, CharacterController cc, Vector3 target, bool vault)
		{
			//IL_0072: 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_007c: 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_00a0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00dd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e3: Expected O, but got Unknown
			//IL_00f2: Unknown result type (might be due to invalid IL or missing references)
			//IL_0108: Unknown result type (might be due to invalid IL or missing references)
			//IL_011e: Unknown result type (might be due to invalid IL or missing references)
			duration = (vault ? Plugin.VaultDuration.Value : Plugin.Duration.Value);
			if ((Object)(object)Player.Instance != (Object)null && ((Actor)Player.Instance).isRunning)
			{
				duration *= Plugin.SprintSpeedup.Value;
			}
			duration = Mathf.Max(0.1f, duration);
			CameraDip.Begin(duration, vault);
			startCenter = Ledge.Center(((Component)fpc).transform, cc);
			endCenter = target;
			liftCenter = new Vector3(startCenter.x, endCenter.y, startCenter.z);
			elapsed = 0f;
			stuckSteps = 0;
			active = true;
			fpc.m_Jump = false;
			if (Plugin.DebugLogging.Value)
			{
				ManualLogSource logger = Plugin.Logger;
				bool flag = default(bool);
				BepInExInfoLogInterpolatedStringHandler val = new BepInExInfoLogInterpolatedStringHandler(26, 3, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("Mantle: from ");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<Vector3>(startCenter);
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" up to ");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<Vector3>(liftCenter);
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" onto ");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<Vector3>(endCenter);
				}
				logger.LogInfo(val);
			}
		}

		private static void Step(FirstPersonController fpc, CharacterController cc, float dt)
		{
			//IL_004d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0052: Unknown result type (might be due to invalid IL or missing references)
			//IL_0073: 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_0025: Unknown result type (might be due to invalid IL or missing references)
			//IL_002a: 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_0080: Unknown result type (might be due to invalid IL or missing references)
			//IL_0085: Unknown result type (might be due to invalid IL or missing references)
			//IL_0087: Unknown result type (might be due to invalid IL or missing references)
			//IL_0088: Unknown result type (might be due to invalid IL or missing references)
			//IL_0089: Unknown result type (might be due to invalid IL or missing references)
			//IL_008e: Unknown result type (might be due to invalid IL or missing references)
			//IL_009b: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bd: 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)
			//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_013a: Unknown result type (might be due to invalid IL or missing references)
			elapsed += dt;
			float num = Mathf.Clamp01(elapsed / duration);
			Vector3 val = ((!(num < 0.55f)) ? Vector3.Lerp(liftCenter, endCenter, Mathf.SmoothStep(0f, 1f, (num - 0.55f) / 0.45f)) : Vector3.Lerp(startCenter, liftCenter, Mathf.SmoothStep(0f, 1f, num / 0.55f)));
			Vector3 val2 = Ledge.Center(((Component)fpc).transform, cc);
			cc.Move(val - val2);
			Vector3 val3 = Ledge.Center(((Component)fpc).transform, cc);
			fpc.m_MoveDir = Vector3.zero;
			Player instance = Player.Instance;
			if (instance != null)
			{
				instance.UpdateMovementPhysics(false);
			}
			Vector3 val4 = val - val3;
			if (((Vector3)(ref val4)).sqrMagnitude > 0.0225f)
			{
				stuckSteps++;
			}
			else
			{
				stuckSteps = 0;
			}
			if (num >= 1f || stuckSteps >= 4)
			{
				if (stuckSteps >= 4 && Plugin.DebugLogging.Value)
				{
					Plugin.Logger.LogInfo((object)"Mantle: blocked, cancelled");
				}
				active = false;
				fpc.m_Jumping = false;
				fpc.m_MoveDir = new Vector3(0f, 0f - fpc.m_StickToGroundForce, 0f);
				cooldownUntil = Time.unscaledTime + 0.25f;
			}
		}
	}
	[HarmonyPatch(typeof(Player), "Update")]
	internal static class CameraDip
	{
		private static bool active;

		private static float startTime;

		private static float length;

		private static float rollSign;

		private static bool isVault;

		public static void Begin(float duration, bool vault)
		{
			active = true;
			startTime = Time.time;
			length = duration;
			isVault = vault;
			rollSign = ((Random.value < 0.5f) ? (-1f) : 1f);
		}

		private static void Postfix(Player __instance)
		{
			//IL_0047: 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)
			if (!active)
			{
				return;
			}
			Transform camHeightParent = __instance.camHeightParent;
			if ((Object)(object)camHeightParent == (Object)null || __instance.transitionActive)
			{
				active = false;
				return;
			}
			float num = Mathf.Clamp01((Time.time - startTime) / length);
			if (num >= 1f)
			{
				camHeightParent.localRotation = Quaternion.identity;
				active = false;
				return;
			}
			float num2 = Mathf.Sin((float)Math.PI * Mathf.Pow(num, 0.7f));
			float num3 = Plugin.DipAngle.Value * num2 * (isVault ? 0.7f : 1f);
			float num4 = Plugin.RollAngle.Value * rollSign * Mathf.Sin((float)Math.PI * num);
			camHeightParent.localRotation = Quaternion.Euler(num3, 0f, num4);
		}
	}
}