Decompiled source of Physics v1.0.6

Physics.dll

Decompiled 4 days ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.CompilerServices;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: AssemblyVersion("0.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 ValheimPhysics
{
	[BepInPlugin("com.razaotium.physics", "Physics", "1.0.6")]
	[BepInProcess("valheim.exe")]
	public sealed class PhysicsPlugin : BaseUnityPlugin
	{
		internal static ManualLogSource Log;

		internal static ConfigEntry<bool> EnabledMod;

		internal static ConfigEntry<bool> PlayersOnly;

		internal static ConfigEntry<bool> ShipCameraFix;

		internal static ConfigEntry<bool> DeckGrip;

		internal static ConfigEntry<bool> DeckJump;

		internal static ConfigEntry<bool> SmoothStairClimb;

		internal static ConfigEntry<bool> StairFeet;

		internal static ConfigEntry<bool> FootMagnet;

		internal static ConfigEntry<bool> MountFooting;

		internal static ConfigEntry<float> Strength;

		internal static ConfigEntry<float> DeckGripLimit;

		internal static ConfigEntry<float> MaxAirSeconds;

		internal static ConfigEntry<float> FadeSeconds;

		internal static ConfigEntry<float> MountSlideAngle;

		internal static ConfigEntry<float> RampClearance;

		internal static bool BoatReady;

		internal static bool StairReady;

		internal static bool CameraReady;

		internal static bool MountReady;

		private Harmony harmony;

		private ConfigEntry<bool> Bind(string section, string name, bool value, string description)
		{
			return ((BaseUnityPlugin)this).Config.Bind<bool>(section, name, value, description);
		}

		private ConfigEntry<float> Bind(string section, string name, float value, float min, float max, string description)
		{
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			//IL_0023: Expected O, but got Unknown
			return ((BaseUnityPlugin)this).Config.Bind<float>(section, name, value, new ConfigDescription(description, (AcceptableValueBase)(object)new AcceptableValueRange<float>(min, max), Array.Empty<object>()));
		}

		private void Awake()
		{
			//IL_01fa: Unknown result type (might be due to invalid IL or missing references)
			//IL_0204: Expected O, but got Unknown
			Log = ((BaseUnityPlugin)this).Logger;
			EnabledMod = Bind("General", "Enabled", value: true, "Enable corrections. No hotkeys or wall climbing.");
			PlayersOnly = Bind("General", "PlayersOnly", value: false, "Limit ship inertia correction to players.");
			ShipCameraFix = Bind("General", "ShipCameraFix", value: true, "Follow the player's actual position while jumping above a ship, instead of vanilla's lagging camera.");
			Strength = Bind("Tuning", "Strength", 1f, 0f, 1f, "Fraction of ship-frame velocity changes carried into airborne movement.");
			DeckGrip = Bind("Tuning", "DeckGrip", value: true, "Cap the idle deck spring of the ship owner. Passengers keep vanilla repositioning.");
			DeckGripLimit = Bind("Tuning", "DeckGripLimit", 2f, 0.5f, 40f, "Maximum idle deck spring speed for the ship owner, in m/s. Vanilla pulls at 10 m/s per meter of offset.");
			DeckJump = Bind("Tuning", "DeckJump", value: true, "Jump relative to the deck, so ship speed, deck tilt and waves do not change jump height.");
			MaxAirSeconds = Bind("Tuning", "MaxAirSeconds", 3f, 0.5f, 3f, "Airborne carry duration before fading, in seconds.");
			FadeSeconds = Bind("Tuning", "FadeSeconds", 1f, 0f, 1f, "Airborne carry fade after MaxAirSeconds, in seconds.");
			SmoothStairClimb = Bind("Stairs", "SmoothStairClimb", value: true, "Cover supported vanilla ladders with an invisible walking ramp laid just over their tread noses, and hold the player still on it when idle.");
			StairFeet = Bind("Stairs", "StairFeet", value: true, "On the ramps, move the character model to the tread under its standing foot and place each foot on the real tread beneath it. Visual only.");
			FootMagnet = Bind("Stairs", "FootMagnet", value: false, "With StairFeet: hold each planted foot on the tread spot under it until the animation lifts it. Visual only.");
			RampClearance = Bind("Stairs", "RampClearance", 0.01f, -0.05f, 0.1f, "Gap between the invisible ramp and the tread noses, in meters. Lower brings the feet closer to the treads; below 0 the noses poke through the ramp and every tread becomes a small bump.");
			MountFooting = Bind("Mounts", "MountFooting", value: true, "Use configured slide threshold for ridden creatures.");
			MountSlideAngle = Bind("Mounts", "MountSlideAngle", 85f, 38f, 90f, "Ridden slide threshold. Gameplay setting, not a guarantee of collision or dismount safety on steep terrain. Vanilla is 45.");
			harmony = new Harmony("com.razaotium.physics");
			try
			{
				Access.Init();
				BoatReady = true;
				harmony.PatchAll(typeof(BoatPatch));
				harmony.PatchAll(typeof(BoatAirPatch));
				harmony.PatchAll(typeof(BoatJumpPatch));
			}
			catch (Exception ex)
			{
				Fail(ref BoatReady, "boat initialization", ex);
			}
			try
			{
				StairReady = true;
				harmony.PatchAll(typeof(StairTriggerPatch));
				harmony.PatchAll(typeof(StairPiecePatch));
				harmony.PatchAll(typeof(StairSlidePatch));
				harmony.PatchAll(typeof(StairHoldPatch));
				StairStride.Init();
				harmony.PatchAll(typeof(StairStrideIKPatch));
				harmony.PatchAll(typeof(StairStrideCameraPatch));
				harmony.PatchAll(typeof(StairStrideCollisionPatch));
			}
			catch (Exception ex2)
			{
				Fail(ref StairReady, "stairs initialization", ex2);
			}
			try
			{
				if (!BoatReady)
				{
					throw new InvalidOperationException("Character access unavailable");
				}
				CameraPatch.Init();
				CameraReady = true;
				harmony.PatchAll(typeof(CameraPatch));
			}
			catch (Exception ex3)
			{
				Fail(ref CameraReady, "camera initialization", ex3);
			}
			try
			{
				MountReady = true;
				harmony.PatchAll(typeof(MountPatch));
			}
			catch (Exception ex4)
			{
				Fail(ref MountReady, "mount initialization", ex4);
			}
			EnabledMod.SettingChanged += Reset;
			PlayersOnly.SettingChanged += Reset;
			SmoothStairClimb.SettingChanged += Reset;
			RampClearance.SettingChanged += Reset;
			StairFeet.SettingChanged += Reset;
			FootMagnet.SettingChanged += Reset;
			((BaseUnityPlugin)this).Logger.LogInfo((object)("Physics 1.0.6: boat=" + BoatReady + ", stairs=" + StairReady + ", camera=" + CameraReady + ", mount=" + MountReady));
		}

		private void Update()
		{
			if (StairReady)
			{
				LadderRamp.Tick();
			}
		}

		private void FixedUpdate()
		{
			if (!StairReady)
			{
				return;
			}
			try
			{
				StairStride.Step(Time.fixedDeltaTime);
			}
			catch (Exception ex)
			{
				StairStride.Clear();
				Fail(ref StairReady, "stair feet", ex);
			}
		}

		private void Reset(object sender, EventArgs args)
		{
			BoatPatch.Clear();
			LadderRamp.DestroyAll();
			StairStride.Clear();
		}

		private void OnDestroy()
		{
			if (EnabledMod != null)
			{
				EnabledMod.SettingChanged -= Reset;
			}
			if (PlayersOnly != null)
			{
				PlayersOnly.SettingChanged -= Reset;
			}
			if (SmoothStairClimb != null)
			{
				SmoothStairClimb.SettingChanged -= Reset;
			}
			if (RampClearance != null)
			{
				RampClearance.SettingChanged -= Reset;
			}
			if (StairFeet != null)
			{
				StairFeet.SettingChanged -= Reset;
			}
			if (FootMagnet != null)
			{
				FootMagnet.SettingChanged -= Reset;
			}
			Harmony obj = harmony;
			if (obj != null)
			{
				obj.UnpatchSelf();
			}
			Reset(null, null);
		}

		internal static void Fail(ref bool ready, string feature, Exception ex)
		{
			ready = false;
			Log.LogError((object)("Physics disabled " + feature + " for this session; vanilla fallback. " + ex.GetType().Name + ": " + ex.Message));
		}

		internal static float Value(ConfigEntry<float> setting, float fallback, float min, float max)
		{
			return Safety.Bounded(setting.Value, fallback, min, max);
		}

		internal static bool Finite(Vector3 v)
		{
			//IL_0000: 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_001a: Unknown result type (might be due to invalid IL or missing references)
			if (Safety.Finite(v.x) && Safety.Finite(v.y))
			{
				return Safety.Finite(v.z);
			}
			return false;
		}
	}
	internal static class Access
	{
		internal static FieldRef<Character, Rigidbody> Body;

		internal static FieldRef<Character, Rigidbody> AttachBody;

		internal static FieldRef<Character, ZNetView> View;

		internal static FieldRef<Character, Vector3> AttachPos;

		internal static FieldRef<Character, float> GroundTouch;

		internal static FieldRef<Character, float> GroundTimer;

		internal static Func<Character, bool> SwimDepth;

		internal static void Init()
		{
			Body = AccessTools.FieldRefAccess<Character, Rigidbody>("m_body");
			AttachBody = AccessTools.FieldRefAccess<Character, Rigidbody>("m_lastAttachBody");
			View = AccessTools.FieldRefAccess<Character, ZNetView>("m_nview");
			AttachPos = AccessTools.FieldRefAccess<Character, Vector3>("m_lastAttachPos");
			GroundTouch = AccessTools.FieldRefAccess<Character, float>("m_lastGroundTouch");
			GroundTimer = AccessTools.FieldRefAccess<Character, float>("m_groundForceTimer");
			SwimDepth = AccessTools.MethodDelegate<Func<Character, bool>>(AccessTools.Method(typeof(Character), "InLiquidSwimDepth", (Type[])null, (Type[])null), (object)null, true);
		}

		internal static bool Valid(Character c)
		{
			if (!Object.op_Implicit((Object)(object)c) || !PhysicsPlugin.EnabledMod.Value || c.IsDead() || c.IsTeleporting() || c.IsAttached() || c.IsSwimming() || SwimDepth(c) || c.IsDebugFlying() || c.InIntro())
			{
				return false;
			}
			ZNetView val = View.Invoke(c);
			if (Object.op_Implicit((Object)(object)val) && val.IsValid() && val.IsOwner() && Object.op_Implicit((Object)(object)Body.Invoke(c)))
			{
				return !Body.Invoke(c).isKinematic;
			}
			return false;
		}
	}
	internal sealed class DeckState
	{
		internal Ship Ship;

		internal Rigidbody Body;

		internal Collider Deck;

		internal ZNetView ShipView;

		internal long Owner;

		internal Vector3 FrameVelocity;

		internal Vector3 CarriedVelocity;

		internal Vector3 LocalPoint;

		internal float ContactTime;
	}
	[HarmonyPatch(typeof(Character), "ApplyGroundForce")]
	internal static class BoatPatch
	{
		private const float MaxDeckHeave = 4f;

		private static ConditionalWeakTable<Character, DeckState> states = new ConditionalWeakTable<Character, DeckState>();

		private static readonly RaycastHit[] deckHits = (RaycastHit[])(object)new RaycastHit[32];

		internal static void Clear()
		{
			states = new ConditionalWeakTable<Character, DeckState>();
		}

		internal static bool Nearby(Character c)
		{
			if (!Object.op_Implicit((Object)(object)c))
			{
				return false;
			}
			if (c.IsPlayer() || c.InNumShipVolumes > 0)
			{
				return true;
			}
			states.Remove(c);
			return false;
		}

		internal static bool Eligible(Character c)
		{
			if (Access.Valid(c) && (!PhysicsPlugin.PlayersOnly.Value || c.IsPlayer()))
			{
				return !c.IsKnockedBack();
			}
			return false;
		}

		private static void Prefix(Character __instance, Vector3 targetVel)
		{
			//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_00bf: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00eb: 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_012e: 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_0137: 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_0146: Unknown result type (might be due to invalid IL or missing references)
			//IL_014b: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a4: Unknown result type (might be due to invalid IL or missing references)
			if (!PhysicsPlugin.BoatReady || !Nearby(__instance))
			{
				return;
			}
			try
			{
				if (!Eligible(__instance))
				{
					states.Remove(__instance);
					return;
				}
				Ship standingOnShip = __instance.GetStandingOnShip();
				if (!__instance.IsOnGround())
				{
					return;
				}
				if (!Object.op_Implicit((Object)(object)standingOnShip))
				{
					states.Remove(__instance);
				}
				else
				{
					if (Access.GroundTouch.Invoke(__instance) > 0.001f)
					{
						return;
					}
					Collider lastGroundCollider = __instance.GetLastGroundCollider();
					Rigidbody val = (Object.op_Implicit((Object)(object)lastGroundCollider) ? lastGroundCollider.attachedRigidbody : null);
					if (!Object.op_Implicit((Object)(object)val) || (Object)(object)((Component)val).GetComponent<Ship>() != (Object)(object)standingOnShip)
					{
						states.Remove(__instance);
						return;
					}
					Vector3 position = ((Component)__instance).transform.position;
					Vector3 pointVelocity = val.GetPointVelocity(position);
					pointVelocity.y = 0f;
					if (!PhysicsPlugin.Finite(pointVelocity) || ((Vector3)(ref pointVelocity)).magnitude > 20f || !PhysicsPlugin.Finite(position))
					{
						states.Remove(__instance);
						return;
					}
					DeckState orCreateValue = states.GetOrCreateValue(__instance);
					orCreateValue.Ship = standingOnShip;
					orCreateValue.Body = val;
					orCreateValue.Deck = lastGroundCollider;
					orCreateValue.FrameVelocity = pointVelocity;
					orCreateValue.CarriedVelocity = pointVelocity;
					orCreateValue.LocalPoint = ((Component)val).transform.InverseTransformPoint(position);
					orCreateValue.ContactTime = Time.time;
					orCreateValue.ShipView = ((Component)standingOnShip).GetComponent<ZNetView>();
					orCreateValue.Owner = ((Object.op_Implicit((Object)(object)orCreateValue.ShipView) && orCreateValue.ShipView.IsValid()) ? orCreateValue.ShipView.GetZDO().GetOwner() : 0);
					GripDeck(__instance, standingOnShip, val, targetVel);
				}
			}
			catch (Exception ex)
			{
				Clear();
				PhysicsPlugin.Fail(ref PhysicsPlugin.BoatReady, "boat", ex);
			}
		}

		private static void GripDeck(Character c, Ship ship, Rigidbody body, Vector3 targetVel)
		{
			//IL_0055: Unknown result type (might be due to invalid IL or missing references)
			//IL_005a: Unknown result type (might be due to invalid IL or missing references)
			//IL_005f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0060: 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_006c: Unknown result type (might be due to invalid IL or missing references)
			//IL_006d: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c0: 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_00c7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cc: 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_00d5: 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_00f3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f8: Unknown result type (might be due to invalid IL or missing references)
			if (!PhysicsPlugin.DeckGrip.Value || ((Vector3)(ref targetVel)).magnitude > 0.01f || (Object)(object)Access.AttachBody.Invoke(c) != (Object)(object)body || !ship.IsOwner())
			{
				return;
			}
			Rigidbody val = Access.Body.Invoke(c);
			Vector3 val2 = ((Component)body).transform.TransformPoint(Access.AttachPos.Invoke(c));
			Vector3 val3 = val2 - val.position;
			if (PhysicsPlugin.Finite(val3) && !(((Vector3)(ref val3)).magnitude >= 4f))
			{
				val3.y = 0f;
				float num = Safety.GripScale(((Vector3)(ref val3)).magnitude, PhysicsPlugin.Value(PhysicsPlugin.DeckGripLimit, 2f, 0.5f, 40f));
				if (!(num >= 1f))
				{
					Vector3 val4 = val.position + val3 * num;
					val4.y = val2.y;
					Access.AttachPos.Invoke(c) = ((Component)body).transform.InverseTransformPoint(val4);
				}
			}
		}

		private static void Postfix(Character __instance, ref Vector3 vel)
		{
			//IL_003d: 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_0049: 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_0054: Unknown result type (might be due to invalid IL or missing references)
			//IL_005d: Unknown result type (might be due to invalid IL or missing references)
			//IL_005e: Unknown result type (might be due to invalid IL or missing references)
			if (!PhysicsPlugin.BoatReady || !Nearby(__instance))
			{
				return;
			}
			try
			{
				if (GetAirState(__instance, out var s, out var fade) && !__instance.IsOnGround() && !(Access.GroundTimer.Invoke(__instance) > 0f))
				{
					Vector3 val = vel + s.CarriedVelocity * fade;
					if (PhysicsPlugin.Finite(val))
					{
						vel = val;
					}
				}
			}
			catch (Exception ex)
			{
				Clear();
				PhysicsPlugin.Fail(ref PhysicsPlugin.BoatReady, "boat", ex);
			}
		}

		internal static bool GetAirState(Character c, out DeckState s, out float fade)
		{
			//IL_00c1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c6: Unknown result type (might be due to invalid IL or missing references)
			//IL_0103: Unknown result type (might be due to invalid IL or missing references)
			//IL_012b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0130: 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_013c: Unknown result type (might be due to invalid IL or missing references)
			fade = 0f;
			s = null;
			if (!PhysicsPlugin.BoatReady || !Eligible(c))
			{
				if (Object.op_Implicit((Object)(object)c))
				{
					states.Remove(c);
				}
				return false;
			}
			if (!states.TryGetValue(c, out s))
			{
				return false;
			}
			float age = Time.time - s.ContactTime;
			bool flag = Object.op_Implicit((Object)(object)s.ShipView) && s.ShipView.IsValid() && s.ShipView.GetZDO().GetOwner() == s.Owner;
			float keep = PhysicsPlugin.Value(PhysicsPlugin.MaxAirSeconds, 3f, 0.5f, 3f);
			float fade2 = PhysicsPlugin.Value(PhysicsPlugin.FadeSeconds, 1f, 0f, 1f);
			Vector3 position = ((Component)c).transform.position;
			if (!Object.op_Implicit((Object)(object)s.Ship) || !Object.op_Implicit((Object)(object)s.Body) || !Object.op_Implicit((Object)(object)s.Deck) || !s.Deck.enabled || !flag || !PhysicsPlugin.Finite(position))
			{
				states.Remove(c);
				s = null;
				return false;
			}
			Vector3 val = ((Component)s.Body).transform.TransformPoint(s.LocalPoint);
			if (!Safety.AirValid(age, keep, fade2, Vector3.Distance(position, val)))
			{
				states.Remove(c);
				s = null;
				return false;
			}
			if (c.IsOnGround() && (Object)(object)c.GetStandingOnShip() != (Object)(object)s.Ship)
			{
				states.Remove(c);
				s = null;
				return false;
			}
			fade = Safety.Fade(age, keep, fade2);
			return fade > 0f;
		}

		internal static void CarryAirborne(Character c)
		{
			//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)
			//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_0045: Unknown result type (might be due to invalid IL or missing references)
			//IL_0052: Unknown result type (might be due to invalid IL or missing references)
			//IL_0079: 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_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_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_00ae: 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_00fe: Unknown result type (might be due to invalid IL or missing references)
			//IL_0103: Unknown result type (might be due to invalid IL or missing references)
			//IL_0107: Unknown result type (might be due to invalid IL or missing references)
			//IL_010c: Unknown result type (might be due to invalid IL or missing references)
			//IL_010e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0113: Unknown result type (might be due to invalid IL or missing references)
			//IL_0116: Unknown result type (might be due to invalid IL or missing references)
			//IL_011b: Unknown result type (might be due to invalid IL or missing references)
			//IL_011d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0122: Unknown result type (might be due to invalid IL or missing references)
			//IL_0124: Unknown result type (might be due to invalid IL or missing references)
			//IL_012d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0138: Unknown result type (might be due to invalid IL or missing references)
			//IL_0140: Unknown result type (might be due to invalid IL or missing references)
			//IL_0142: Unknown result type (might be due to invalid IL or missing references)
			if (!PhysicsPlugin.BoatReady || !Nearby(c))
			{
				return;
			}
			try
			{
				if (!GetAirState(c, out var s, out var fade))
				{
					return;
				}
				Vector3 val = ((Component)s.Body).transform.TransformPoint(s.LocalPoint);
				Vector3 pointVelocity = s.Body.GetPointVelocity(val);
				pointVelocity.y = 0f;
				if (!PhysicsPlugin.Finite(pointVelocity) || ((Vector3)(ref pointVelocity)).magnitude > 20f)
				{
					states.Remove(c);
					return;
				}
				Vector3 val2 = pointVelocity - s.FrameVelocity;
				s.FrameVelocity = pointVelocity;
				if (!c.IsOnGround() && !(Access.GroundTimer.Invoke(c) > 0f) && PhysicsPlugin.Finite(val2) && !(((Vector3)(ref val2)).magnitude > 5f) && OverDeck(c, s))
				{
					Rigidbody val3 = Access.Body.Invoke(c);
					Vector3 val4 = val2 * (PhysicsPlugin.Value(PhysicsPlugin.Strength, 1f, 0f, 1f) * fade);
					Vector3 val5 = val3.linearVelocity + val4;
					Vector3 val6 = s.CarriedVelocity + val4;
					if (PhysicsPlugin.Finite(val5) && PhysicsPlugin.Finite(val6))
					{
						val3.linearVelocity = val5;
						s.CarriedVelocity = val6;
					}
				}
			}
			catch (Exception ex)
			{
				Clear();
				PhysicsPlugin.Fail(ref PhysicsPlugin.BoatReady, "boat", ex);
			}
		}

		internal static bool OverDeck(Character c, DeckState s)
		{
			//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_0015: Unknown result type (might be due to invalid IL or missing references)
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			//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.RaycastNonAlloc(new Ray(((Component)c).transform.position + Vector3.up * 0.3f, Vector3.down), deckHits, 8.3f, -5, (QueryTriggerInteraction)1);
			for (int i = 0; i < num && i < deckHits.Length; i++)
			{
				Collider collider = ((RaycastHit)(ref deckHits[i])).collider;
				if (Object.op_Implicit((Object)(object)collider) && (Object)(object)collider.attachedRigidbody == (Object)(object)s.Body)
				{
					return true;
				}
			}
			return false;
		}

		internal static bool CameraOnDeck(Player p, out DeckState s)
		{
			if (GetAirState((Character)(object)p, out s, out var _))
			{
				return OverDeck((Character)(object)p, s);
			}
			return false;
		}

		internal static bool DeckJumpFrame(Character c, bool force, out Vector3 velocity)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_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_0090: Unknown result type (might be due to invalid IL or missing references)
			//IL_0091: Unknown result type (might be due to invalid IL or missing references)
			//IL_0096: Unknown result type (might be due to invalid IL or missing references)
			//IL_0098: 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_00a9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b5: 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_00c1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d5: 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_00f3: Unknown result type (might be due to invalid IL or missing references)
			velocity = Vector3.zero;
			if (!Nearby(c) || !Eligible(c) || !c.IsOnGround() || (!force && c.InAttack()) || Access.GroundTimer.Invoke(c) > 0f)
			{
				return false;
			}
			Ship standingOnShip = c.GetStandingOnShip();
			Collider lastGroundCollider = c.GetLastGroundCollider();
			Rigidbody val = (Object.op_Implicit((Object)(object)lastGroundCollider) ? lastGroundCollider.attachedRigidbody : null);
			if (!Object.op_Implicit((Object)(object)standingOnShip) || !Object.op_Implicit((Object)(object)val) || (Object)(object)((Component)val).GetComponent<Ship>() != (Object)(object)standingOnShip)
			{
				return false;
			}
			Vector3 position = ((Component)c).transform.position;
			Vector3 pointVelocity = val.GetPointVelocity(position);
			if (PhysicsPlugin.Finite(position) && PhysicsPlugin.Finite(pointVelocity))
			{
				Vector3 val2 = new Vector3(pointVelocity.x, 0f, pointVelocity.z);
				if (!(((Vector3)(ref val2)).magnitude > 20f))
				{
					pointVelocity.y = Mathf.Clamp(pointVelocity.y, -4f, 4f);
					velocity = pointVelocity;
					return true;
				}
			}
			return false;
		}
	}
	[HarmonyPatch(typeof(Character), "UpdateWalking")]
	internal static class BoatAirPatch
	{
		private static void Postfix(Character __instance)
		{
			BoatPatch.CarryAirborne(__instance);
		}
	}
	internal struct JumpFrame
	{
		internal Rigidbody Body;

		internal Vector3 Velocity;
	}
	[HarmonyPatch(typeof(Character), "Jump")]
	internal static class BoatJumpPatch
	{
		private static void Prefix(Character __instance, bool force, out JumpFrame __state)
		{
			//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)
			//IL_003e: 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_0051: Unknown result type (might be due to invalid IL or missing references)
			__state = default(JumpFrame);
			if (!PhysicsPlugin.BoatReady || !PhysicsPlugin.DeckJump.Value)
			{
				return;
			}
			try
			{
				if (BoatPatch.DeckJumpFrame(__instance, force, out var velocity))
				{
					Rigidbody val = Access.Body.Invoke(__instance);
					val.linearVelocity -= velocity;
					__state.Body = val;
					__state.Velocity = velocity;
				}
			}
			catch (Exception ex)
			{
				BoatPatch.Clear();
				PhysicsPlugin.Fail(ref PhysicsPlugin.BoatReady, "boat", ex);
			}
		}

		private static void Finalizer(JumpFrame __state)
		{
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			if (!Object.op_Implicit((Object)(object)__state.Body))
			{
				return;
			}
			try
			{
				__state.Body.linearVelocity = __state.Body.linearVelocity + __state.Velocity;
			}
			catch (Exception ex)
			{
				PhysicsPlugin.Fail(ref PhysicsPlugin.BoatReady, "boat", ex);
			}
		}
	}
	[HarmonyPatch(typeof(GameCamera), "UpdateBaseOffset")]
	internal static class CameraPatch
	{
		private static FieldRef<GameCamera, Vector3> pos;

		private static FieldRef<GameCamera, Vector3> vel;

		internal static void Init()
		{
			pos = AccessTools.FieldRefAccess<GameCamera, Vector3>("m_playerPos");
			vel = AccessTools.FieldRefAccess<GameCamera, Vector3>("m_playerVel");
		}

		private static void Postfix(GameCamera __instance, Player player)
		{
			//IL_003d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0042: 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_005d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0072: 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_0083: Unknown result type (might be due to invalid IL or missing references)
			//IL_0084: Unknown result type (might be due to invalid IL or missing references)
			if (!PhysicsPlugin.CameraReady || !PhysicsPlugin.ShipCameraFix.Value)
			{
				return;
			}
			try
			{
				if (Object.op_Implicit((Object)(object)player) && !((Object)(object)((Character)player).GetStandingOnShip() != (Object)null) && BoatPatch.CameraOnDeck(player, out var _))
				{
					Vector3 position = ((Component)player).transform.position;
					Vector3 linearVelocity = Access.Body.Invoke((Character)(object)player).linearVelocity;
					if (PhysicsPlugin.Finite(position) && PhysicsPlugin.Finite(linearVelocity))
					{
						pos.Invoke(__instance) = position;
						vel.Invoke(__instance) = linearVelocity;
					}
				}
			}
			catch (Exception ex)
			{
				PhysicsPlugin.Fail(ref PhysicsPlugin.CameraReady, "camera", ex);
			}
		}
	}
	internal static class LadderRamp
	{
		private const string ObjectName = "Razaotium_Physics_LadderRamp";

		private const float Width = 1.3f;

		private const float MaxTreadHeight = 1f;

		private const float Thickness = 0.08f;

		private static readonly Dictionary<int, GameObject> ramps = new Dictionary<int, GameObject>();

		private static readonly Dictionary<int, float> rejectedUntil = new Dictionary<int, float>();

		private static readonly List<int> stale = new List<int>();

		private static float nextCleanup;

		internal static bool Ensure(Piece ladder, Vector3 ladderForward)
		{
			//IL_0078: 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_00aa: Unknown result type (might be due to invalid IL or missing references)
			//IL_00af: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b5: 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_00ed: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ee: Unknown result type (might be due to invalid IL or missing references)
			//IL_0153: Unknown result type (might be due to invalid IL or missing references)
			//IL_0186: 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_018e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0193: Unknown result type (might be due to invalid IL or missing references)
			//IL_0198: Unknown result type (might be due to invalid IL or missing references)
			//IL_019c: 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_01a3: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a8: 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_01b0: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b5: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b9: Unknown result type (might be due to invalid IL or missing references)
			//IL_01be: 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_01cc: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d1: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d5: Unknown result type (might be due to invalid IL or missing references)
			//IL_01da: Unknown result type (might be due to invalid IL or missing references)
			//IL_01df: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ef: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f4: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f9: Unknown result type (might be due to invalid IL or missing references)
			//IL_021e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0225: Expected O, but got Unknown
			//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_0265: Unknown result type (might be due to invalid IL or missing references)
			//IL_026a: Unknown result type (might be due to invalid IL or missing references)
			//IL_027b: Unknown result type (might be due to invalid IL or missing references)
			//IL_027d: Unknown result type (might be due to invalid IL or missing references)
			//IL_027f: Unknown result type (might be due to invalid IL or missing references)
			//IL_02af: Unknown result type (might be due to invalid IL or missing references)
			if (!Object.op_Implicit((Object)(object)ladder) || !PhysicsPlugin.StairReady || !PhysicsPlugin.EnabledMod.Value || !PhysicsPlugin.SmoothStairClimb.Value)
			{
				return false;
			}
			int instanceID = ((Object)ladder).GetInstanceID();
			if (ramps.TryGetValue(instanceID, out var value) && Object.op_Implicit((Object)(object)value))
			{
				return true;
			}
			if (rejectedUntil.TryGetValue(instanceID, out var value2) && Time.unscaledTime < value2)
			{
				return false;
			}
			if (!Safety.KnownStair(Utils.GetPrefabName(((Component)ladder).gameObject)))
			{
				return false;
			}
			Vector3 val = default(Vector3);
			((Vector3)(ref val))..ctor(ladderForward.x, 0f, ladderForward.z);
			if (((Vector3)(ref val)).sqrMagnitude < 0.01f)
			{
				return Reject(instanceID);
			}
			((Vector3)(ref val)).Normalize();
			Vector3 val2 = Vector3.Cross(Vector3.up, val);
			Vector3 normalized = ((Vector3)(ref val2)).normalized;
			List<float> list = new List<float>();
			List<float> list2 = new List<float>();
			float num = 0f;
			Collider[] componentsInChildren = ((Component)ladder).GetComponentsInChildren<Collider>(true);
			foreach (Collider obj in componentsInChildren)
			{
				if (TreadNose((BoxCollider)(object)((obj is BoxCollider) ? obj : null), val, normalized, out var along, out var top, out var side))
				{
					list.Add(along);
					list2.Add(top);
					num += side;
				}
			}
			float clearance = PhysicsPlugin.Value(PhysicsPlugin.RampClearance, 0.01f, -0.05f, 0.1f);
			if (!Safety.TryNoseRamp(list.ToArray(), list2.ToArray(), ((Component)ladder).transform.position.y, clearance, out var slope, out var _, out var start, out var end, out var startHeight, out var topHeight))
			{
				return Reject(instanceID);
			}
			float num2 = num / (float)list.Count;
			val2 = val + Vector3.up * slope;
			Vector3 normalized2 = ((Vector3)(ref val2)).normalized;
			val2 = Vector3.up - val * slope;
			Vector3 normalized3 = ((Vector3)(ref val2)).normalized;
			Vector3 val3 = val * ((start + end) * 0.5f) + normalized * num2 + Vector3.up * ((startHeight + topHeight) * 0.5f);
			float num3 = Mathf.Sqrt((end - start) * (end - start) + (topHeight - startHeight) * (topHeight - startHeight));
			GameObject val4 = new GameObject("Razaotium_Physics_LadderRamp");
			((Object)val4).hideFlags = (HideFlags)61;
			int num4 = LayerMask.NameToLayer("blocker");
			val4.layer = ((num4 >= 0) ? num4 : ((Component)ladder).gameObject.layer);
			val4.transform.position = val3 - normalized3 * 0.04f;
			val4.transform.rotation = Quaternion.LookRotation(normalized2, normalized3);
			val4.transform.SetParent(((Component)ladder).transform, true);
			val4.AddComponent<BoxCollider>().size = new Vector3(1.3f, 0.08f, num3);
			ramps[instanceID] = val4;
			rejectedUntil.Remove(instanceID);
			return true;
		}

		private static bool TreadNose(BoxCollider box, Vector3 forward, Vector3 right, out float along, out float top, out float side)
		{
			//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_0068: 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_00ab: Unknown result type (might be due to invalid IL or missing references)
			//IL_0153: 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_015d: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d2: 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_00f7: Unknown result type (might be due to invalid IL or missing references)
			//IL_0102: Unknown result type (might be due to invalid IL or missing references)
			//IL_0107: Unknown result type (might be due to invalid IL or missing references)
			//IL_010c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0111: Unknown result type (might be due to invalid IL or missing references)
			//IL_0116: Unknown result type (might be due to invalid IL or missing references)
			//IL_0118: Unknown result type (might be due to invalid IL or missing references)
			//IL_0129: Unknown result type (might be due to invalid IL or missing references)
			along = (top = (side = 0f));
			if (!Object.op_Implicit((Object)(object)box) || ((Collider)box).isTrigger || ((Object)((Component)box).gameObject).name == "Razaotium_Physics_LadderRamp")
			{
				return false;
			}
			Transform transform = ((Component)box).transform;
			float num = Vector3.Dot(transform.up, Vector3.up);
			if (Mathf.Abs(num) < 0.995f)
			{
				return false;
			}
			float num2 = Mathf.Abs(box.size.y * transform.lossyScale.y);
			if (num2 < 0.02f || num2 > 1f)
			{
				return false;
			}
			float num3 = ((num > 0f) ? 0.5f : (-0.5f)) * box.size.y;
			along = float.MaxValue;
			top = float.MinValue;
			for (int i = -1; i <= 1; i += 2)
			{
				for (int j = -1; j <= 1; j += 2)
				{
					Vector3 val = transform.TransformPoint(box.center + new Vector3((float)i * 0.5f * box.size.x, num3, (float)j * 0.5f * box.size.z));
					along = Mathf.Min(along, Vector3.Dot(val, forward));
					top = Mathf.Max(top, val.y);
				}
			}
			side = Vector3.Dot(transform.TransformPoint(box.center), right);
			if (Safety.Finite(along) && Safety.Finite(top))
			{
				return Safety.Finite(side);
			}
			return false;
		}

		private static bool Reject(int id)
		{
			rejectedUntil[id] = Time.unscaledTime + 2f;
			return false;
		}

		internal static bool IsRampCollider(Collider collider)
		{
			if (Object.op_Implicit((Object)(object)collider))
			{
				return ((Object)((Component)collider).gameObject).name == "Razaotium_Physics_LadderRamp";
			}
			return false;
		}

		internal static void Tick()
		{
			if (!PhysicsPlugin.EnabledMod.Value || !PhysicsPlugin.SmoothStairClimb.Value)
			{
				DestroyAll();
			}
			else
			{
				if (Time.unscaledTime < nextCleanup)
				{
					return;
				}
				nextCleanup = Time.unscaledTime + 1f;
				stale.Clear();
				foreach (KeyValuePair<int, GameObject> ramp in ramps)
				{
					if (!Object.op_Implicit((Object)(object)ramp.Value))
					{
						stale.Add(ramp.Key);
					}
				}
				foreach (int item in stale)
				{
					ramps.Remove(item);
				}
			}
		}

		internal static void DestroyAll()
		{
			foreach (GameObject value in ramps.Values)
			{
				if (Object.op_Implicit((Object)(object)value))
				{
					value.SetActive(false);
					Object.Destroy((Object)(object)value);
				}
			}
			ramps.Clear();
			rejectedUntil.Clear();
			stale.Clear();
			nextCleanup = 0f;
		}
	}
	[HarmonyPatch(typeof(AutoJumpLedge), "OnTriggerStay")]
	internal static class StairTriggerPatch
	{
		private static bool Prefix(AutoJumpLedge __instance, Collider __0)
		{
			//IL_0079: Unknown result type (might be due to invalid IL or missing references)
			if (!PhysicsPlugin.StairReady || !PhysicsPlugin.EnabledMod.Value || !PhysicsPlugin.SmoothStairClimb.Value)
			{
				return true;
			}
			try
			{
				Character val = (Object.op_Implicit((Object)(object)__0) ? ((Component)__0).GetComponent<Character>() : null);
				if (!Object.op_Implicit((Object)(object)val) || (Object)(object)val != (Object)(object)Player.m_localPlayer)
				{
					return true;
				}
				Piece componentInParent = ((Component)__instance).GetComponentInParent<Piece>();
				if (!Object.op_Implicit((Object)(object)componentInParent) || !Safety.KnownStair(Utils.GetPrefabName(((Component)componentInParent).gameObject)))
				{
					return true;
				}
				return !LadderRamp.Ensure(componentInParent, ((Component)__instance).transform.forward);
			}
			catch (Exception ex)
			{
				LadderRamp.DestroyAll();
				PhysicsPlugin.Fail(ref PhysicsPlugin.StairReady, "stairs", ex);
				return true;
			}
		}
	}
	[HarmonyPatch(typeof(Piece), "Awake")]
	internal static class StairPiecePatch
	{
		private static void Postfix(Piece __instance)
		{
			//IL_006d: Unknown result type (might be due to invalid IL or missing references)
			if (!PhysicsPlugin.StairReady || !PhysicsPlugin.EnabledMod.Value || !PhysicsPlugin.SmoothStairClimb.Value || !Object.op_Implicit((Object)(object)__instance))
			{
				return;
			}
			try
			{
				if (!Safety.KnownStair(Utils.GetPrefabName(((Component)__instance).gameObject)))
				{
					return;
				}
				ZNetView component = ((Component)__instance).GetComponent<ZNetView>();
				if (Object.op_Implicit((Object)(object)component) && component.IsValid())
				{
					AutoJumpLedge componentInChildren = ((Component)__instance).GetComponentInChildren<AutoJumpLedge>(true);
					if (Object.op_Implicit((Object)(object)componentInChildren))
					{
						LadderRamp.Ensure(__instance, ((Component)componentInChildren).transform.forward);
					}
				}
			}
			catch (Exception ex)
			{
				LadderRamp.DestroyAll();
				PhysicsPlugin.Fail(ref PhysicsPlugin.StairReady, "stairs", ex);
			}
		}
	}
	[HarmonyPatch(typeof(Character), "GetSlideAngle")]
	internal static class StairSlidePatch
	{
		private static void Postfix(Character __instance, ref float __result)
		{
			if (PhysicsPlugin.StairReady && (Object)(object)__instance == (Object)(object)Player.m_localPlayer && LadderRamp.IsRampCollider(__instance.GetLastGroundCollider()))
			{
				__result = Mathf.Max(__result, 55f);
			}
		}
	}
	[HarmonyPatch(typeof(Character), "UpdateWalking")]
	internal static class StairHoldPatch
	{
		private static void Postfix(Character __instance)
		{
			//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_00a3: Unknown result type (might be due to invalid IL or missing references)
			if (!PhysicsPlugin.StairReady || !PhysicsPlugin.EnabledMod.Value || !PhysicsPlugin.SmoothStairClimb.Value || (object)__instance != Player.m_localPlayer)
			{
				return;
			}
			try
			{
				if (!__instance.IsOnGround())
				{
					return;
				}
				Vector3 moveDir = __instance.GetMoveDir();
				if (!(((Vector3)(ref moveDir)).sqrMagnitude >= 0.01f) && LadderRamp.IsRampCollider(__instance.GetLastGroundCollider()) && !__instance.IsDead() && !__instance.IsAttached() && !__instance.InAttack() && !__instance.InDodge() && !__instance.IsKnockedBack() && !__instance.IsStaggering())
				{
					Rigidbody component = ((Component)__instance).GetComponent<Rigidbody>();
					if (Object.op_Implicit((Object)(object)component) && !component.isKinematic)
					{
						component.linearVelocity = Vector3.zero;
						component.useGravity = false;
					}
				}
			}
			catch (Exception ex)
			{
				LadderRamp.DestroyAll();
				PhysicsPlugin.Fail(ref PhysicsPlugin.StairReady, "stairs", ex);
			}
		}
	}
	internal static class StairStride
	{
		private sealed class Foot
		{
			internal float Stance;

			internal float Ik;

			internal float Support;

			internal float Lift;

			internal float PlantBlend;

			internal float Drift;

			internal float LastHit;

			internal float HitX;

			internal float HitZ;

			internal float TreadX;

			internal float TreadZ;

			internal float Stand;

			internal bool Planted;

			internal bool Spent;

			internal bool Hit;

			internal bool Valid;

			internal bool Seen;

			internal bool HasStand;

			internal Vector3 Position;

			internal Vector3 Normal = Vector3.up;

			internal Vector3 PlantPos;

			internal Vector3 PlantNormal = Vector3.up;

			internal Quaternion Rotation;
		}

		private sealed class Stride
		{
			internal Character Character;

			internal Transform Visual;

			internal Vector3 Baseline;

			internal float Offset;

			internal float OffsetVelocity;

			internal float Target;

			internal float LastContact;

			internal float Speed;

			internal bool Active;

			internal bool Still;

			internal bool HasPivot;

			internal Vector3 LastPivot;

			internal readonly Foot Left = new Foot();

			internal readonly Foot Right = new Foot();
		}

		private const float Smooth = 0.08f;

		private const float MaxDown = 1f;

		private const float MaxUp = 0.8f;

		private const float RampProbe = 0.6f;

		private const float RampReach = 1f;

		private const float ProbeAbove = 1.3f;

		private const float ProbeDepth = 2.8f;

		private const float MaxDrift = 0.3f;

		private const float ContactGrace = 0.25f;

		private const float MissHold = 0.25f;

		private const float HoldRadius = 0.12f;

		private const float EdgeMargin = 0.05f;

		private const float SameTread = 0.3f;

		private const float StillEnter = 0.5f;

		private const float StillExit = 1f;

		private static readonly Dictionary<CharacterAnimEvent, Stride> strides = new Dictionary<CharacterAnimEvent, Stride>();

		private static readonly List<CharacterAnimEvent> finished = new List<CharacterAnimEvent>();

		private static FieldRef<CharacterAnimEvent, Character> characterOf;

		private static FieldRef<CharacterAnimEvent, Animator> animatorOf;

		private static int groundMask;

		private static int rampMask;

		private static bool Enabled
		{
			get
			{
				if (PhysicsPlugin.StairReady && PhysicsPlugin.EnabledMod.Value && PhysicsPlugin.SmoothStairClimb.Value)
				{
					return PhysicsPlugin.StairFeet.Value;
				}
				return false;
			}
		}

		internal static void Init()
		{
			characterOf = AccessTools.FieldRefAccess<CharacterAnimEvent, Character>("m_character");
			animatorOf = AccessTools.FieldRefAccess<CharacterAnimEvent, Animator>("m_animator");
			groundMask = LayerMask.GetMask(new string[6] { "Default", "static_solid", "Default_small", "piece", "terrain", "vehicle" });
			rampMask = LayerMask.GetMask(new string[1] { "blocker" });
		}

		internal static void Clear()
		{
			//IL_0049: Unknown result type (might be due to invalid IL or missing references)
			foreach (KeyValuePair<CharacterAnimEvent, Stride> stride in strides)
			{
				if (Object.op_Implicit((Object)(object)stride.Key) && Object.op_Implicit((Object)(object)stride.Value.Visual))
				{
					stride.Value.Visual.localPosition = stride.Value.Baseline;
				}
			}
			strides.Clear();
		}

		internal static void Step(float dt)
		{
			//IL_010c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0111: Unknown result type (might be due to invalid IL or missing references)
			//IL_011c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0121: 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)
			if (strides.Count == 0)
			{
				return;
			}
			finished.Clear();
			float fixedTime = Time.fixedTime;
			foreach (KeyValuePair<CharacterAnimEvent, Stride> stride in strides)
			{
				Stride value = stride.Value;
				if (!Object.op_Implicit((Object)(object)stride.Key) || !Object.op_Implicit((Object)(object)value.Visual))
				{
					finished.Add(stride.Key);
					continue;
				}
				value.Active = Enabled && fixedTime - value.LastContact <= 0.25f;
				value.Offset = Mathf.SmoothDamp(value.Offset, value.Active ? value.Target : 0f, ref value.OffsetVelocity, 0.08f, 20f, dt);
				if (!value.Active && Mathf.Abs(value.Offset) < 0.002f)
				{
					value.Visual.localPosition = value.Baseline;
					finished.Add(stride.Key);
				}
				else
				{
					value.Visual.localPosition = value.Baseline + Vector3.up * value.Offset;
				}
			}
			foreach (CharacterAnimEvent item in finished)
			{
				strides.Remove(item);
			}
		}

		internal static float OffsetOf(Character c)
		{
			foreach (Stride value in strides.Values)
			{
				if (value.Character == c)
				{
					return value.Offset;
				}
			}
			return 0f;
		}

		internal static void BeforeIK(CharacterAnimEvent e)
		{
			//IL_0049: 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_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_0060: Unknown result type (might be due to invalid IL or missing references)
			//IL_0065: 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_00c7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cc: Unknown result type (might be due to invalid IL or missing references)
			//IL_017e: Unknown result type (might be due to invalid IL or missing references)
			//IL_017f: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b3: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c6: Unknown result type (might be due to invalid IL or missing references)
			//IL_024c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0150: Unknown result type (might be due to invalid IL or missing references)
			//IL_0153: Unknown result type (might be due to invalid IL or missing references)
			//IL_0265: Unknown result type (might be due to invalid IL or missing references)
			if (!Enabled || !Object.op_Implicit((Object)(object)e) || !e.m_footIK)
			{
				return;
			}
			Character val = characterOf.Invoke(e);
			Animator val2 = animatorOf.Invoke(e);
			if (!(val is Player) || !Object.op_Implicit((Object)(object)val2))
			{
				return;
			}
			Vector3 position = ((Component)val).transform.position;
			float fixedTime = Time.fixedTime;
			RaycastHit val3 = default(RaycastHit);
			bool flag = Physics.Raycast(position + Vector3.up * 0.6f, Vector3.down, ref val3, 1f, rampMask, (QueryTriggerInteraction)1) && LadderRamp.IsRampCollider(((RaycastHit)(ref val3)).collider);
			if (!strides.TryGetValue(e, out var value))
			{
				if (!flag)
				{
					return;
				}
				value = new Stride
				{
					Character = val,
					Visual = ((Component)e).transform,
					Baseline = ((Component)e).transform.localPosition,
					LastContact = fixedTime
				};
				strides[e] = value;
			}
			if (flag)
			{
				value.LastContact = fixedTime;
			}
			value.Active = fixedTime - value.LastContact <= 0.25f;
			if (!value.Active)
			{
				Release(value.Left);
				Release(value.Right);
				return;
			}
			float deltaTime = Time.deltaTime;
			if (value.HasPivot && deltaTime > 0f)
			{
				value.Speed += (Vector3.Distance(position, value.LastPivot) / deltaTime - value.Speed) * Mathf.Clamp01(deltaTime * 10f);
			}
			value.LastPivot = position;
			value.HasPivot = true;
			value.Still = Safety.StillBody(value.Still, value.Speed, 0.5f, 1f);
			Sample(e, val2, (AvatarIKGoal)0, position, fixedTime, deltaTime, value.Left);
			Sample(e, val2, (AvatarIKGoal)1, position, fixedTime, deltaTime, value.Right);
			float num = ((!value.Still || !value.Left.HasStand || !value.Right.HasStand) ? Safety.StanceSupport(Deciding(value.Left), Tread(value.Left), Deciding(value.Right), Tread(value.Right), position.y + value.Target) : Mathf.Min(value.Left.Stand, value.Right.Stand));
			value.Target = Mathf.Clamp(num - position.y, -1f, 0.8f);
		}

		private static void Release(Foot foot)
		{
			foot.Planted = (foot.Spent = (foot.Seen = (foot.Valid = (foot.HasStand = false))));
			foot.PlantBlend = 0f;
		}

		private static float Horizontal(float x, float z)
		{
			return Mathf.Sqrt(x * x + z * z);
		}

		private static bool Supported(Foot foot)
		{
			if (!foot.Valid)
			{
				return foot.Planted;
			}
			return true;
		}

		private static float Standing(Foot foot)
		{
			return Mathf.Max(foot.Stance, foot.PlantBlend);
		}

		private static float Deciding(Foot foot)
		{
			if (!Supported(foot))
			{
				return 0f;
			}
			return Standing(foot);
		}

		private static float Tread(Foot foot)
		{
			return Mathf.Lerp(foot.Support, foot.PlantPos.y, foot.PlantBlend);
		}

		private static void Sample(CharacterAnimEvent e, Animator animator, AvatarIKGoal goal, Vector3 pivot, float now, float dt, Foot foot)
		{
			//IL_0003: Unknown result type (might be due to invalid IL or missing references)
			//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_0011: 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_0024: 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_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_0044: 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_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_00ec: Unknown result type (might be due to invalid IL or missing references)
			//IL_010d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0120: Unknown result type (might be due to invalid IL or missing references)
			//IL_0125: Unknown result type (might be due to invalid IL or missing references)
			//IL_0256: Unknown result type (might be due to invalid IL or missing references)
			//IL_0346: Unknown result type (might be due to invalid IL or missing references)
			//IL_034b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0354: Unknown result type (might be due to invalid IL or missing references)
			//IL_0359: Unknown result type (might be due to invalid IL or missing references)
			foot.Position = animator.GetIKPosition(goal);
			foot.Rotation = animator.GetIKRotation(goal);
			float num = Safety.StanceWeight(((Component)e).transform.InverseTransformPoint(foot.Position - ((Component)e).transform.up * e.m_footOffset).y, e.m_footDownMax);
			RaycastHit val = default(RaycastHit);
			foot.Hit = Physics.Raycast(new Vector3(foot.Position.x, pivot.y + 1.3f, foot.Position.z), Vector3.down, ref val, 2.8f, groundMask, (QueryTriggerInteraction)1);
			if (foot.Hit)
			{
				float moved = Horizontal(foot.Position.x - foot.TreadX, foot.Position.z - foot.TreadZ);
				if (Safety.TakeTread(foot.Seen, foot.Support, ((RaycastHit)(ref val)).point.y, moved, 0.3f, 0.05f))
				{
					foot.Support = ((RaycastHit)(ref val)).point.y;
					foot.Normal = ((RaycastHit)(ref val)).normal;
					foot.TreadX = foot.Position.x;
					foot.TreadZ = foot.Position.z;
				}
				foot.LastHit = now;
				foot.HitX = foot.Position.x;
				foot.HitZ = foot.Position.z;
				foot.Seen = true;
			}
			foot.Valid = foot.Hit || (foot.Seen && (now - foot.LastHit <= 0.25f || Horizontal(foot.Position.x - foot.HitX, foot.Position.z - foot.HitZ) <= 0.12f));
			if (foot.Valid && num >= 0.9f)
			{
				foot.Stand = foot.Support;
				foot.HasStand = true;
			}
			foot.Stance = Mathf.MoveTowards(foot.Stance, num, dt * 10f);
			float num2 = (foot.Valid ? Mathf.Max(0f, foot.Support - ((Component)e).transform.position.y) : 0f);
			foot.Lift = Mathf.MoveTowards(foot.Lift, num2, dt * 8f);
			float num3 = foot.Position.x - foot.PlantPos.x;
			float num4 = foot.Position.z - foot.PlantPos.z;
			foot.Drift = (foot.Planted ? Mathf.Sqrt(num3 * num3 + num4 * num4) : 0f);
			if (!PhysicsPlugin.FootMagnet.Value || num < 0.4f)
			{
				foot.Planted = (foot.Spent = false);
			}
			else if (foot.Planted)
			{
				if (foot.Drift > 0.3f)
				{
					foot.Planted = false;
				}
			}
			else if (!foot.Spent && num >= 0.9f && foot.Hit)
			{
				foot.PlantPos = ((RaycastHit)(ref val)).point;
				foot.PlantNormal = ((RaycastHit)(ref val)).normal;
				foot.Planted = (foot.Spent = true);
			}
			foot.PlantBlend = Mathf.MoveTowards(foot.PlantBlend, (float)(foot.Planted ? 1 : 0), dt * 12f);
			if (Supported(foot))
			{
				foot.Ik = Mathf.MoveTowards(foot.Ik, Mathf.Max((foot.Lift > 0.02f) ? 1f : num, foot.PlantBlend), dt * 10f);
			}
			else
			{
				foot.Ik = Mathf.MoveTowards(foot.Ik, 0f, dt * 4f);
			}
		}

		internal static void AfterIK(CharacterAnimEvent e)
		{
			if (Enabled && Object.op_Implicit((Object)(object)e) && strides.TryGetValue(e, out var value) && value.Active)
			{
				Animator val = animatorOf.Invoke(e);
				if (Object.op_Implicit((Object)(object)val))
				{
					Place(val, (AvatarIKGoal)0, value.Left, e.m_footOffset);
					Place(val, (AvatarIKGoal)1, value.Right, e.m_footOffset);
				}
			}
		}

		private static void Place(Animator animator, AvatarIKGoal goal, Foot foot, float footOffset)
		{
			//IL_0017: 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_008e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0094: 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_009f: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00af: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cb: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00da: 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_00e1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00eb: 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_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)
			float num = (foot.Seen ? foot.Ik : 0f);
			animator.SetIKPositionWeight(goal, num);
			animator.SetIKRotationWeight(goal, Mathf.Min(Standing(foot), num) * 0.5f);
			if (!(num <= 0f))
			{
				float num2 = ((foot.Lift > 0.02f) ? Mathf.Max(foot.Position.y + foot.Lift, foot.Support + footOffset) : (foot.Support + footOffset));
				Vector3 val = Vector3.Lerp(new Vector3(foot.Position.x, num2, foot.Position.z), foot.PlantPos + Vector3.up * footOffset, foot.PlantBlend);
				Vector3 val2 = ((foot.PlantBlend > 0.5f) ? foot.PlantNormal : foot.Normal);
				animator.SetIKPosition(goal, val);
				animator.SetIKRotation(goal, Quaternion.LookRotation(Vector3.Cross(foot.Rotation * Vector3.right, val2), val2));
			}
		}
	}
	[HarmonyPatch(typeof(CharacterAnimEvent), "OnAnimatorIK")]
	internal static class StairStrideIKPatch
	{
		private static void Prefix(CharacterAnimEvent __instance)
		{
			if (!PhysicsPlugin.StairReady)
			{
				return;
			}
			try
			{
				StairStride.BeforeIK(__instance);
			}
			catch (Exception ex)
			{
				StairStride.Clear();
				PhysicsPlugin.Fail(ref PhysicsPlugin.StairReady, "stair feet", ex);
			}
		}

		private static void Postfix(CharacterAnimEvent __instance)
		{
			if (!PhysicsPlugin.StairReady)
			{
				return;
			}
			try
			{
				StairStride.AfterIK(__instance);
			}
			catch (Exception ex)
			{
				StairStride.Clear();
				PhysicsPlugin.Fail(ref PhysicsPlugin.StairReady, "stair feet", ex);
			}
		}
	}
	[HarmonyPatch(typeof(GameCamera), "GetCameraBaseOffset")]
	internal static class StairStrideCameraPatch
	{
		private static void Postfix(Player player, ref Vector3 __result)
		{
			if (!PhysicsPlugin.StairReady || !Object.op_Implicit((Object)(object)player) || ((Character)player).InBed() || ((Character)player).IsAttached() || ((Character)player).IsSitting())
			{
				return;
			}
			try
			{
				__result.y -= StairStride.OffsetOf((Character)(object)player);
			}
			catch (Exception ex)
			{
				StairStride.Clear();
				PhysicsPlugin.Fail(ref PhysicsPlugin.StairReady, "stair feet", ex);
			}
		}
	}
	[HarmonyPatch(typeof(GameCamera), "CollideRay2")]
	internal static class StairStrideCollisionPatch
	{
		private static void Prefix(ref Vector3 eyePos)
		{
			if (!PhysicsPlugin.StairReady)
			{
				return;
			}
			try
			{
				eyePos.y -= StairStride.OffsetOf((Character)(object)Player.m_localPlayer);
			}
			catch (Exception ex)
			{
				StairStride.Clear();
				PhysicsPlugin.Fail(ref PhysicsPlugin.StairReady, "stair feet", ex);
			}
		}
	}
	[HarmonyPatch(typeof(Character), "GetSlideAngle")]
	internal static class MountPatch
	{
		private static void Postfix(Character __instance, ref float __result)
		{
			if (!PhysicsPlugin.MountReady || !PhysicsPlugin.EnabledMod.Value || !PhysicsPlugin.MountFooting.Value)
			{
				return;
			}
			try
			{
				if (Object.op_Implicit((Object)(object)__instance) && !__instance.IsPlayer() && __instance.HaveRider())
				{
					__result = PhysicsPlugin.Value(PhysicsPlugin.MountSlideAngle, 85f, 38f, 90f);
				}
			}
			catch (Exception ex)
			{
				PhysicsPlugin.Fail(ref PhysicsPlugin.MountReady, "mount", ex);
			}
		}
	}
	internal static class Safety
	{
		internal const float MaxCarryDistance = 8f;

		internal static bool Finite(float v)
		{
			if (!float.IsNaN(v))
			{
				return !float.IsInfinity(v);
			}
			return false;
		}

		internal static float Bounded(float v, float fallback, float min, float max)
		{
			if (!Finite(v))
			{
				return fallback;
			}
			return Math.Max(min, Math.Min(max, v));
		}

		internal static float Fade(float age, float keep, float fade)
		{
			if (!(age < 0f))
			{
				if (!(age <= keep))
				{
					if (!(fade <= 0f))
					{
						return Math.Max(0f, 1f - (age - keep) / fade);
					}
					return 0f;
				}
				return 1f;
			}
			return 0f;
		}

		internal static bool AirValid(float age, float keep, float fade, float displacement)
		{
			if (Finite(age) && age >= 0f && age <= keep + fade && Finite(displacement))
			{
				return displacement <= 8f;
			}
			return false;
		}

		internal static float GripScale(float offset, float limitSpeed)
		{
			if (!Finite(offset) || !Finite(limitSpeed) || offset <= 0f || limitSpeed <= 0f)
			{
				return 1f;
			}
			float num = limitSpeed / 10f;
			if (!(offset <= num))
			{
				return num / offset;
			}
			return 1f;
		}

		internal static bool StairVelocity(float y, float speed)
		{
			if (Finite(y) && y >= -1f)
			{
				return y <= speed + 0.25f;
			}
			return false;
		}

		internal static bool StairGrace(float age)
		{
			if (Finite(age) && age >= 0f)
			{
				return age <= 0.25f;
			}
			return false;
		}

		internal static bool StairContact(bool grounded, bool sameStair, float age)
		{
			if (!grounded)
			{
				if (sameStair)
				{
					return StairGrace(age);
				}
				return false;
			}
			return true;
		}

		internal static bool CeilingNormal(float y)
		{
			if (Finite(y))
			{
				return y < -0.5f;
			}
			return false;
		}

		internal static bool StepSurface(float width, float height, float depth)
		{
			if (!Finite(width) || !Finite(height) || !Finite(depth) || width <= 0f || height <= 0f || depth <= 0f)
			{
				return false;
			}
			if (height <= 0.35f)
			{
				return height <= Math.Max(width, depth) * 0.5f;
			}
			return false;
		}

		internal static bool TryNoseRamp(float[] along, float[] top, float baseHeight, float clearance, out float slope, out float intercept, out float start, out float end, out float startHeight, out float topHeight)
		{
			slope = (intercept = (start = (end = (startHeight = (topHeight = 0f)))));
			if (along == null || top == null || along.Length != top.Length || along.Length < 2 || !Finite(baseHeight) || !Finite(clearance) || clearance < -0.1f || clearance > 0.5f)
			{
				return false;
			}
			int num = along.Length;
			int[] array = new int[num];
			for (int i = 0; i < num; i++)
			{
				if (!Finite(along[i]) || !Finite(top[i]))
				{
					return false;
				}
				array[i] = i;
			}
			Array.Sort((float[])along.Clone(), array);
			List<float> list = new List<float>();
			for (int j = 1; j < num; j++)
			{
				float num2 = along[array[j]] - along[array[j - 1]];
				float num3 = top[array[j]] - top[array[j - 1]];
				if (num2 > 0.05f && num3 > 0.05f)
				{
					list.Add(num3 / num2);
				}
			}
			if (list.Count == 0)
			{
				return false;
			}
			list.Sort();
			int num4 = list.Count / 2;
			float num5 = ((list.Count % 2 == 1) ? list[num4] : ((list[num4 - 1] + list[num4]) * 0.5f));
			if (!Finite(num5) || num5 < 0.4f || num5 > 2.5f)
			{
				return false;
			}
			slope = Math.Min(num5, 1.35f);
			float num6 = float.MinValue;
			float num7 = float.MaxValue;
			topHeight = float.MinValue;
			for (int k = 0; k < num; k++)
			{
				num6 = Math.Max(num6, top[k] - slope * along[k]);
				topHeight = Math.Max(topHeight, top[k]);
				num7 = Math.Min(num7, top[k]);
			}
			intercept = num6 + clearance * (float)Math.Sqrt(1f + slope * slope);
			startHeight = Math.Min(baseHeight, num7);
			start = (startHeight - intercept) / slope;
			end = (topHeight - intercept) / slope;
			if (Finite(intercept) && Finite(start) && Finite(end) && end - start > 0.25f)
			{
				return end - start < 12f;
			}
			return false;
		}

		internal static float StanceWeight(float lifted, float downMax)
		{
			if (!Finite(lifted) || !Finite(downMax) || downMax <= 0f)
			{
				return 0f;
			}
			return 1f - Math.Max(0f, Math.Min(1f, lifted / downMax));
		}

		internal static float StanceSupport(float leftWeight, float leftSupport, float rightWeight, float rightSupport, float previous)
		{
			if (!Finite(leftWeight) || !Finite(rightWeight) || !Finite(leftSupport) || !Finite(rightSupport))
			{
				return previous;
			}
			float num = Math.Max(0f, Math.Min(1f, leftWeight));
			float num2 = Math.Max(0f, Math.Min(1f, rightWeight));
			if (num + num2 < 0.05f)
			{
				return previous;
			}
			float num3 = ((leftSupport <= rightSupport) ? num : num2);
			float num4 = ((leftSupport <= rightSupport) ? num2 : num);
			float num5 = Math.Min(leftSupport, rightSupport);
			float num6 = Math.Max(leftSupport, rightSupport);
			if (num3 < 0.05f && num4 < 0.05f)
			{
				return previous;
			}
			return num5 + (num6 - num5) * num4 * (1f - num3);
		}

		internal static bool StillBody(bool still, float speed, float enter, float exit)
		{
			if (!Finite(speed))
			{
				return still;
			}
			if (!still)
			{
				return speed < enter;
			}
			return speed <= exit;
		}

		internal static bool TakeTread(bool known, float tread, float hitHeight, float moved, float sameTread, float margin)
		{
			if (!Finite(hitHeight))
			{
				return false;
			}
			if (!known || !Finite(tread) || Math.Abs(hitHeight - tread) < sameTread)
			{
				return true;
			}
			if (Finite(moved))
			{
				return moved > margin;
			}
			return false;
		}

		internal static bool TryEndpointRamp(float lowerAlong, float lowerTop, float upperAlong, float upperTop, out float slope, out float surfaceLength)
		{
			slope = 0f;
			surfaceLength = 0f;
			if (!Finite(lowerAlong) || !Finite(lowerTop) || !Finite(upperAlong) || !Finite(upperTop))
			{
				return false;
			}
			float num = upperAlong - lowerAlong;
			float num2 = upperTop - lowerTop;
			if (num < 0.25f || num2 < 0.1f)
			{
				return false;
			}
			float num3 = num2 / num;
			if (!Finite(num3) || num3 < 0.4f || num3 > 2.5f)
			{
				return false;
			}
			slope = Math.Min(num3, 1.35f);
			surfaceLength = num * (float)Math.Sqrt(1f + slope * slope);
			if (Finite(surfaceLength))
			{
				return surfaceLength > 0f;
			}
			return false;
		}

		internal static bool TryCappedRamp(float centerAlong, float centerHeight, float slope, float requestedLength, float topHeight, out float start, out float startHeight, out float end, out float endHeight, out float landingEnd)
		{
			start = (startHeight = (end = (endHeight = (landingEnd = 0f))));
			if (!Finite(centerAlong) || !Finite(centerHeight) || !Finite(slope) || !Finite(requestedLength) || !Finite(topHeight) || slope <= 0f || requestedLength <= 0f)
			{
				return false;
			}
			float num = requestedLength / (2f * (float)Math.Sqrt(1f + slope * slope));
			float num2 = num * slope;
			start = centerAlong - num;
			startHeight = centerHeight - num2;
			endHeight = Math.Min(centerHeight + num2, topHeight + 0.02f);
			if (endHeight - startHeight < 0.01f)
			{
				return false;
			}
			end = start + (endHeight - startHeight) / slope;
			landingEnd = Math.Max(end, centerAlong + num);
			if (Finite(start) && Finite(startHeight) && Finite(end) && Finite(endHeight))
			{
				return Finite(landingEnd);
			}
			return false;
		}

		internal static bool KnownStair(string name)
		{
			if (string.IsNullOrEmpty(name))
			{
				return false;
			}
			int num = name.IndexOf("(Clone)", StringComparison.OrdinalIgnoreCase);
			if (num >= 0)
			{
				name = name.Substring(0, num);
			}
			name = name.Trim().ToLowerInvariant();
			switch (name)
			{
			default:
				return name == "grausten_stone_ladder";
			case "piece_wood_ladder":
			case "piece_wood_ladder_45":
			case "piece_woodstepladder":
			case "piece_grausten_stoneladder":
			case "piece_grausten_stone_ladder":
			case "wood_ladder":
			case "wood_stepladder":
			case "woodstepladder":
			case "grausten_ladder":
				return true;
			}
		}
	}
}