Decompiled source of Unhindered v0.3.0

Unhindered.dll

Decompiled a week ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using Jotunn.Utils;
using Microsoft.CodeAnalysis;
using Unity.Collections;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: IgnoresAccessChecksTo("assembly_guiutils")]
[assembly: IgnoresAccessChecksTo("assembly_utils")]
[assembly: IgnoresAccessChecksTo("assembly_valheim")]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("Unhindered")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("0.3.0.0")]
[assembly: AssemblyInformationalVersion("0.3.0+401075277446405148177f8c51d5dfe1cca810ca")]
[assembly: AssemblyProduct("Unhindered")]
[assembly: AssemblyTitle("Unhindered")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("0.3.0.0")]
[module: UnverifiableCode]
[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 Unhindered
{
	[HarmonyPatch]
	internal static class CharacterSlide
	{
		private const float Friction = 0.2f;

		private static readonly HashSet<int> s_characters = new HashSet<int>();

		private static Collider s_playerCollider;

		private static int s_player;

		private static bool s_enabled;

		internal static void Init()
		{
			s_enabled = Plugin.CharacterSlideEnabled.Value;
			Physics.ContactModifyEvent += OnContactModify;
		}

		internal static void Shutdown()
		{
			Physics.ContactModifyEvent -= OnContactModify;
			SetEnabled(enabled: false);
		}

		internal static void SetEnabled(bool enabled)
		{
			s_enabled = enabled;
			if ((Object)(object)s_playerCollider != (Object)null)
			{
				s_playerCollider.hasModifiableContacts = enabled;
			}
		}

		[HarmonyPostfix]
		[HarmonyPatch(typeof(Character), "Awake")]
		private static void Awake(Character __instance)
		{
			Track(__instance);
		}

		[HarmonyPostfix]
		[HarmonyPatch(typeof(Character), "CustomFixedUpdate")]
		private static void CustomFixedUpdate(Character __instance)
		{
			Track(__instance);
		}

		private static void Track(Character character)
		{
			if (!((Object)(object)character.m_collider == (Object)null))
			{
				int instanceID = ((Object)character.m_collider).GetInstanceID();
				if (character.IsTamed())
				{
					s_characters.Remove(instanceID);
				}
				else
				{
					s_characters.Add(instanceID);
				}
			}
		}

		[HarmonyPrefix]
		[HarmonyPatch(typeof(Character), "OnDestroy")]
		private static void OnDestroy(Character __instance)
		{
			if ((Object)(object)__instance.m_collider != (Object)null)
			{
				int instanceID = ((Object)__instance.m_collider).GetInstanceID();
				s_characters.Remove(instanceID);
				if (instanceID == s_player)
				{
					s_player = 0;
					s_playerCollider = null;
				}
			}
		}

		[HarmonyPostfix]
		[HarmonyPatch(typeof(Player), "SetLocalPlayer")]
		private static void SetLocalPlayer(Player __instance)
		{
			if ((Object)(object)((Character)__instance).m_collider != (Object)null)
			{
				s_playerCollider = (Collider)(object)((Character)__instance).m_collider;
				s_player = ((Object)s_playerCollider).GetInstanceID();
				s_playerCollider.hasModifiableContacts = s_enabled;
			}
		}

		private static void OnContactModify(PhysicsScene scene, NativeArray<ModifiableContactPair> pairs)
		{
			//IL_001b: 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)
			int num = s_player;
			if (!s_enabled || num == 0)
			{
				return;
			}
			for (int i = 0; i < pairs.Length; i++)
			{
				ModifiableContactPair val = pairs[i];
				int colliderInstanceID = ((ModifiableContactPair)(ref val)).colliderInstanceID;
				int otherColliderInstanceID = ((ModifiableContactPair)(ref val)).otherColliderInstanceID;
				if ((colliderInstanceID == num && s_characters.Contains(otherColliderInstanceID)) || (otherColliderInstanceID == num && s_characters.Contains(colliderInstanceID)))
				{
					for (int j = 0; j < ((ModifiableContactPair)(ref val)).contactCount; j++)
					{
						((ModifiableContactPair)(ref val)).SetStaticFriction(j, Math.Min(((ModifiableContactPair)(ref val)).GetStaticFriction(j), 0.2f));
						((ModifiableContactPair)(ref val)).SetDynamicFriction(j, Math.Min(((ModifiableContactPair)(ref val)).GetDynamicFriction(j), 0.2f));
					}
				}
			}
		}
	}
	[HarmonyPatch]
	internal static class ForgivingJump
	{
		private struct State
		{
			public bool Changed;

			public float LastGroundTouch;

			public Vector3 LastGroundNormal;
		}

		private const float AirborneAfter = 0.05f;

		private const float MaxHeight = 0.35f;

		private const float MinTimeSinceJump = 0.3f;

		private const float MinWalkableY = 0.5f;

		private static readonly RaycastHit[] s_hits = (RaycastHit[])(object)new RaycastHit[16];

		private static float s_lastHitTime = float.NegativeInfinity;

		[HarmonyPatch(typeof(Character), "Jump")]
		[HarmonyPrefix]
		private static void JumpPrefix(Character __instance, out State __state)
		{
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0023: Expected O, but got Unknown
			//IL_006d: 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_00c4: 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)
			__state = default(State);
			if (!Plugin.ForgivingJumpEnabled.Value || (object)__instance != Player.m_localPlayer)
			{
				return;
			}
			Player val = (Player)__instance;
			float lastGroundTouch = ((Character)val).m_lastGroundTouch;
			if (!(lastGroundTouch < 0.05f) && !((Character)val).m_body.IsSleeping() && !((Character)val).InLiquidSwimDepth() && !((Character)val).IsAttached() && !((Object)(object)GrapplingPoint.m_localGrappler != (Object)null))
			{
				__state.Changed = true;
				__state.LastGroundTouch = lastGroundTouch;
				__state.LastGroundNormal = ((Character)val).m_lastGroundNormal;
				if (Time.time - s_lastHitTime <= lastGroundTouch)
				{
					((Character)val).m_lastGroundTouch = 1f;
					return;
				}
				if (((Character)val).IsOnGround() || ((Character)val).m_jumpTimer < 0.3f || !NearGround(val, out var normal))
				{
					__state.Changed = false;
					return;
				}
				((Character)val).m_lastGroundTouch = 0f;
				((Character)val).m_lastGroundNormal = normal;
			}
		}

		[HarmonyPatch(typeof(Character), "Jump")]
		[HarmonyPostfix]
		private static void JumpPostfix(Character __instance, State __state)
		{
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			//IL_0028: Unknown result type (might be due to invalid IL or missing references)
			if (__state.Changed && __instance.m_jumpTimer > 0f)
			{
				__instance.m_lastGroundTouch = __state.LastGroundTouch;
				__instance.m_lastGroundNormal = __state.LastGroundNormal;
			}
		}

		[HarmonyPatch(typeof(Character), "ApplyDamage")]
		[HarmonyPostfix]
		private static void ApplyDamagePostfix(Character __instance, HitData hit)
		{
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			if ((object)__instance == Player.m_localPlayer && __instance.m_lastHit == hit && !IsOngoing(hit.m_hitType))
			{
				s_lastHitTime = Time.time;
			}
		}

		private static bool IsOngoing(HitType type)
		{
			//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_0004: Invalid comparison between Unknown and I4
			//IL_0006: 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_000b: Invalid comparison between Unknown and I4
			if (type - 3 <= 6 || type - 21 <= 1)
			{
				return true;
			}
			return false;
		}

		private static bool NearGround(Player player, out Vector3 normal)
		{
			//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_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0030: Unknown result type (might be due to invalid IL or missing references)
			//IL_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_0062: Unknown result type (might be due to invalid IL or missing references)
			//IL_009e: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a3: 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_00ed: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f2: Unknown result type (might be due to invalid IL or missing references)
			normal = Vector3.up;
			CapsuleCollider collider = ((Character)player).m_collider;
			float num = collider.radius * 0.9f;
			Vector3 val = ((Component)collider).transform.TransformPoint(collider.center) - Vector3.up * (collider.height * 0.5f - collider.radius);
			float num2 = 0.35f + collider.radius - num;
			int num3 = Physics.SphereCastNonAlloc(val, num, Vector3.down, s_hits, num2, Character.s_groundRayMask, (QueryTriggerInteraction)1);
			int selfLayer = 1 << ((Component)collider).gameObject.layer;
			float num4 = float.MaxValue;
			for (int i = 0; i < num3; i++)
			{
				RaycastHit val2 = s_hits[i];
				if (((RaycastHit)(ref val2)).distance > 0f && ((RaycastHit)(ref val2)).distance < num4 && ((RaycastHit)(ref val2)).normal.y >= 0.5f && StepUp.Blocks(((RaycastHit)(ref val2)).collider, selfLayer))
				{
					num4 = ((RaycastHit)(ref val2)).distance;
					normal = ((RaycastHit)(ref val2)).normal;
				}
			}
			return num4 < float.MaxValue;
		}
	}
	[HarmonyPatch]
	internal static class HauledCart
	{
		[HarmonyPostfix]
		[HarmonyPatch(typeof(Vagon), "AttachTo")]
		private static void AttachTo(Vagon __instance, GameObject go)
		{
			if ((Object)(object)Player.m_localPlayer != (Object)null && (Object)(object)go == (Object)(object)((Component)Player.m_localPlayer).gameObject)
			{
				StepUp.s_hauledCart = __instance.m_body;
			}
		}

		[HarmonyPostfix]
		[HarmonyPatch(typeof(Vagon), "Detach")]
		private static void Detach(Vagon __instance)
		{
			if (StepUp.s_hauledCart == __instance.m_body)
			{
				StepUp.s_hauledCart = null;
			}
		}
	}
	[HarmonyPatch(typeof(ZNetScene), "Awake")]
	internal static class PassThrough
	{
		private static int s_characterLayers;

		private static bool s_dirty;

		private static readonly HashSet<string> s_untouchable = new HashSet<string>();

		private static readonly HashSet<string> s_checked = new HashSet<string>();

		[HarmonyPriority(0)]
		private static void Postfix(ZNetScene __instance)
		{
			s_characterLayers = LayerMask.GetMask(new string[4] { "character", "character_net", "character_ghost", "character_noenv" });
			foreach (GameObject item in AllPrefabs(__instance))
			{
				if (s_checked.Add(((Object)item).name) && item.GetComponentsInChildren<Collider>(true).Any((Collider c) => (LayerMask.op_Implicit(c.excludeLayers) & s_characterLayers) != 0))
				{
					s_untouchable.Add(((Object)item).name);
				}
			}
			s_dirty = false;
			Refresh(__instance, includeSpawned: false);
		}

		internal static void MarkDirty()
		{
			s_dirty = true;
		}

		internal static void RefreshIfDirty()
		{
			if (s_dirty && !((Object)(object)ZNetScene.instance == (Object)null))
			{
				s_dirty = false;
				Refresh(ZNetScene.instance, includeSpawned: true);
			}
		}

		private static void Refresh(ZNetScene scene, bool includeSpawned)
		{
			bool value = Plugin.PassThroughEnabled.Value;
			string[] names = Split(Plugin.PassThroughNames.Value);
			string[] exclude = Split(Plugin.PassThroughExclude.Value);
			Dictionary<string, bool> dictionary = new Dictionary<string, bool>();
			foreach (GameObject item in AllPrefabs(scene))
			{
				if (!s_untouchable.Contains(((Object)item).name) && !dictionary.ContainsKey(((Object)item).name))
				{
					bool flag = value && Matches(item, names, exclude);
					dictionary[((Object)item).name] = flag;
					Collider[] componentsInChildren = item.GetComponentsInChildren<Collider>(true);
					for (int i = 0; i < componentsInChildren.Length; i++)
					{
						Set(componentsInChildren[i], flag);
					}
				}
			}
			int num = (includeSpawned ? RefreshSpawned(dictionary) : 0);
			List<string> list = (from kv in dictionary
				where kv.Value
				select kv.Key).ToList();
			Plugin.Log.LogInfo((object)(value ? ($"Pass-through applied to {list.Count} prefabs" + (includeSpawned ? $" ({num} spawned colliders updated)" : "")) : "Pass-through disabled"));
			if (value && Plugin.PassThroughLogMatches.Value)
			{
				list.Sort(StringComparer.OrdinalIgnoreCase);
				Plugin.Log.LogInfo((object)("Pass-through prefabs: " + string.Join(", ", list)));
			}
		}

		private static int RefreshSpawned(Dictionary<string, bool> passable)
		{
			int num = 0;
			Collider[] array = Object.FindObjectsByType<Collider>((FindObjectsSortMode)0);
			foreach (Collider val in array)
			{
				bool? flag = null;
				Transform val2 = ((Component)val).transform;
				while ((Object)(object)val2 != (Object)null)
				{
					if (passable.TryGetValue(Utils.GetPrefabName(((Component)val2).gameObject), out var value))
					{
						flag = value;
					}
					val2 = val2.parent;
				}
				if (flag.HasValue && Set(val, flag.Value))
				{
					num++;
				}
			}
			return num;
		}

		private static bool Set(Collider collider, bool pass)
		{
			//IL_000b: 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)
			if (collider.isTrigger)
			{
				return false;
			}
			int num = LayerMask.op_Implicit(collider.excludeLayers);
			int num2 = (pass ? (num | s_characterLayers) : (num & ~s_characterLayers));
			if (num2 == num)
			{
				return false;
			}
			collider.excludeLayers = LayerMask.op_Implicit(num2);
			return true;
		}

		private static IEnumerable<GameObject> AllPrefabs(ZNetScene scene)
		{
			return from p in scene.m_prefabs.Concat(scene.m_nonNetViewPrefabs)
				where (Object)(object)p != (Object)null
				select p;
		}

		private static bool Matches(GameObject prefab, string[] names, string[] exclude)
		{
			string name = ((Object)prefab).name;
			if (ContainsAny(name, exclude))
			{
				return false;
			}
			if ((!Plugin.PassThroughPickables.Value || !((Object)(object)prefab.GetComponent<Pickable>() != (Object)null)) && (!Plugin.PassThroughPlants.Value || !((Object)(object)prefab.GetComponent<Plant>() != (Object)null)))
			{
				return ContainsAny(name, names);
			}
			return true;
		}

		private static bool ContainsAny(string name, string[] parts)
		{
			foreach (string value in parts)
			{
				if (name.IndexOf(value, StringComparison.OrdinalIgnoreCase) >= 0)
				{
					return true;
				}
			}
			return false;
		}

		private static string[] Split(string list)
		{
			return (from s in list.Split(new char[1] { ',' }, StringSplitOptions.RemoveEmptyEntries)
				select s.Trim() into s
				where s.Length > 0
				select s).ToArray();
		}
	}
	[BepInPlugin("hvalch.Unhindered", "Unhindered", "0.3.0")]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[NetworkCompatibility(/*Could not decode attribute arguments.*/)]
	[SynchronizationMode(/*Could not decode attribute arguments.*/)]
	public class Plugin : BaseUnityPlugin
	{
		public const string Guid = "hvalch.Unhindered";

		public const string Name = "Unhindered";

		public const string Version = "0.3.0";

		internal static ManualLogSource Log;

		internal static ConfigEntry<bool> PassThroughEnabled;

		internal static ConfigEntry<bool> PassThroughPickables;

		internal static ConfigEntry<bool> PassThroughPlants;

		internal static ConfigEntry<string> PassThroughNames;

		internal static ConfigEntry<string> PassThroughExclude;

		internal static ConfigEntry<bool> PassThroughLogMatches;

		internal static ConfigEntry<bool> StepUpEnabled;

		internal static ConfigEntry<float> StepUpMaxHeightWalk;

		internal static ConfigEntry<float> StepUpMaxHeightJog;

		internal static ConfigEntry<float> StepUpMaxHeightSprint;

		internal static ConfigEntry<float> StepUpSpeed;

		internal static ConfigEntry<bool> StepUpOnTerrain;

		internal static ConfigEntry<bool> StepUpDebug;

		internal static ConfigEntry<bool> CharacterSlideEnabled;

		internal static ConfigEntry<bool> ForgivingJumpEnabled;

		private readonly Harmony _harmony = new Harmony("hvalch.Unhindered");

		private void Awake()
		{
			Log = ((BaseUnityPlugin)this).Logger;
			PassThroughEnabled = BindSynced("1 - Pass Through", "Enabled", value: true, "Let characters walk through small plants (bushes, mushrooms, berry bushes, crops...). They can still be picked, chopped and hit.");
			PassThroughPickables = BindSynced("1 - Pass Through", "Pickables", value: true, "Include every pickable object (mushrooms, berries, thistle, flax, stones, branches...).");
			PassThroughPlants = BindSynced("1 - Pass Through", "Plants", value: true, "Include growing plants and saplings (crops, tree saplings).");
			PassThroughNames = BindSynced("1 - Pass Through", "NameContains", "bush,shrub", "Comma-separated, case-insensitive. Any prefab whose name contains one of these is included (e.g. add 'FirTree_small,Beech_small' to walk through small trees).");
			PassThroughExclude = BindSynced("1 - Pass Through", "Exclude", "", "Comma-separated, case-insensitive. Prefabs whose name contains one of these are never changed. Wins over everything above.");
			PassThroughLogMatches = ((BaseUnityPlugin)this).Config.Bind<bool>("1 - Pass Through", "LogMatches", false, "Log every prefab made pass-through (to tune the lists above). Local only, never synced.");
			StepUpEnabled = BindSynced("2 - Step Up", "Enabled", value: true, "Automatically step up onto low obstacles (logs, rocks, ledges) while moving, instead of having to jump.");
			StepUpMaxHeightWalk = BindSynced("2 - Step Up", "MaxHeightWalk", 0.7f, "Tallest obstacle (meters) you can step onto while walking, crouching or encumbered. 0 = never step up.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 2f));
			StepUpMaxHeightJog = BindSynced("2 - Step Up", "MaxHeightJog", 1.2f, "Tallest obstacle (meters) you can step onto at normal running speed. 0 = never step up.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 2f));
			StepUpMaxHeightSprint = BindSynced("2 - Step Up", "MaxHeightSprint", 1.5f, "Tallest obstacle (meters) you can step onto while sprinting. 0 = never step up.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 2f));
			StepUpSpeed = BindSynced("2 - Step Up", "Speed", 6f, "How fast you rise when stepping up (m/s). Higher is snappier; 20 is near-instant.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 20f));
			StepUpOnTerrain = BindSynced("2 - Step Up", "StepOnTerrain", value: false, "Also step up terrain ledges (e.g. hoe-raised ground). Off by default so natural cliffs still need a jump.");
			StepUpDebug = ((BaseUnityPlugin)this).Config.Bind<bool>("2 - Step Up", "DebugLog", false, "Log why each obstacle you walk into is or isn't stepped onto (to LogOutput.log). Local only, never synced.");
			CharacterSlideEnabled = BindSynced("3 - Character Slide", "Enabled", value: true, "Slide around enemies and other players you walk into, the way you slide around trees, instead of sticking to them.");
			ForgivingJumpEnabled = BindSynced("4 - Forgiving Jump", "Enabled", value: true, "Jump when running lifts you slightly off the ground, instead of the jump being ignored. Getting hit in the air cancels it until you land.");
			((BaseUnityPlugin)this).Config.SettingChanged += delegate(object _, SettingChangedEventArgs e)
			{
				if (e.ChangedSetting.Definition.Section == "1 - Pass Through")
				{
					PassThrough.MarkDirty();
				}
				CharacterSlide.SetEnabled(CharacterSlideEnabled.Value);
			};
			CharacterSlide.Init();
			_harmony.PatchAll();
			Log.LogInfo((object)"Unhindered 0.3.0 loaded");
		}

		private void Update()
		{
			PassThrough.RefreshIfDirty();
		}

		private void OnDestroy()
		{
			CharacterSlide.Shutdown();
			_harmony.UnpatchSelf();
		}

		private ConfigEntry<T> BindSynced<T>(string section, string key, T value, string description, AcceptableValueBase range = null)
		{
			//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_0022: Expected O, but got Unknown
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			//IL_002c: Expected O, but got Unknown
			return ((BaseUnityPlugin)this).Config.Bind<T>(section, key, value, new ConfigDescription(description, range, new object[1] { (object)new ConfigurationManagerAttributes
			{
				IsAdminOnly = true
			} }));
		}
	}
	[HarmonyPatch(typeof(Character), "UpdateWalking")]
	internal static class StepUp
	{
		private struct StepState
		{
			public bool Active;

			public Vector3 Start;

			public Vector3 Dir;

			public float TargetY;

			public float Travel;

			public float Timer;

			public Collider Obstacle;
		}

		private const float MinStep = 0.05f;

		private const float MinWalkableY = 0.788f;

		private static int s_mask;

		private static int s_maskWithTerrain;

		private static int s_characterLayers;

		private static readonly RaycastHit[] s_hits = (RaycastHit[])(object)new RaycastHit[16];

		internal static Rigidbody s_hauledCart;

		private static string s_lastDebug;

		private static float s_lastDebugTime;

		private const float StepTimeout = 0.6f;

		private static StepState s_step;

		private const float Skin = 0.03f;

		private const float SweepBackoff = 0.15f;

		private const float SweepLookAhead = 0.15f;

		private const float ProbeStep = 0.05f;

		private const float ProbeBeyond = 0.6f;

		private static readonly Collider[] s_probeOverlaps = (Collider[])(object)new Collider[8];

		private static void Postfix(Character __instance, float dt)
		{
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_001c: Expected O, but got Unknown
			//IL_0024: 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_0095: 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_018f: Unknown result type (might be due to invalid IL or missing references)
			if (!Plugin.StepUpEnabled.Value || (object)__instance != Player.m_localPlayer)
			{
				return;
			}
			Player val = (Player)__instance;
			Rigidbody body = ((Character)val).m_body;
			Vector3 moveDir = ((Character)val).m_moveDir;
			moveDir.y = 0f;
			if (((Character)val).IsAttached() || ((Character)val).InDodge() || ((Character)val).IsStaggering() || ((Character)val).IsRiding() || !((Character)val).CanMove() || body.isKinematic || ((Vector3)(ref moveDir)).sqrMagnitude < 0.01f)
			{
				s_step.Active = false;
				return;
			}
			((Vector3)(ref moveDir)).Normalize();
			if ((!s_step.Active || !ContinueStep(val, body, moveDir, dt)) && ((Character)val).IsOnGround() && !(body.linearVelocity.y > 4f))
			{
				if (s_mask == 0)
				{
					s_mask = LayerMask.GetMask(new string[5] { "Default", "static_solid", "Default_small", "piece", "vehicle" });
					s_maskWithTerrain = s_mask | LayerMask.GetMask(new string[1] { "terrain" });
					s_characterLayers = LayerMask.GetMask(new string[4] { "character", "character_net", "character_ghost", "character_noenv" });
				}
				int mask = (Plugin.StepUpOnTerrain.Value ? s_maskWithTerrain : s_mask);
				int selfLayer = 1 << ((Component)((Character)val).m_collider).gameObject.layer;
				float num = MaxStep(val);
				if (!(num < 0.05f))
				{
					Sweep(val, body, moveDir, dt, num, mask, selfLayer);
				}
			}
		}

		private static float MaxStep(Player player)
		{
			if (((Character)player).m_running)
			{
				return Plugin.StepUpMaxHeightSprint.Value;
			}
			if (((Character)player).m_walking || ((Character)player).IsCrouching() || ((Character)player).IsEncumbered())
			{
				return Plugin.StepUpMaxHeightWalk.Value;
			}
			return Plugin.StepUpMaxHeightJog.Value;
		}

		private static bool Raycast(Vector3 origin, Vector3 dir, float distance, int mask, int selfLayer, out RaycastHit best)
		{
			//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)
			return Nearest(Physics.RaycastNonAlloc(origin, dir, s_hits, distance, mask, (QueryTriggerInteraction)1), selfLayer, 1f, out best);
		}

		private static bool Nearest(int count, int selfLayer, float maxNormalY, out RaycastHit best)
		{
			//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_0037: 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)
			best = default(RaycastHit);
			float num = float.MaxValue;
			for (int i = 0; i < count; i++)
			{
				RaycastHit val = s_hits[i];
				if (((RaycastHit)(ref val)).distance > 0f && ((RaycastHit)(ref val)).distance < num && ((RaycastHit)(ref val)).normal.y <= maxNormalY && Blocks(((RaycastHit)(ref val)).collider, selfLayer))
				{
					best = val;
					num = ((RaycastHit)(ref val)).distance;
				}
			}
			return num < float.MaxValue;
		}

		internal static bool Blocks(Collider collider, int selfLayer)
		{
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_0028: Unknown result type (might be due to invalid IL or missing references)
			Rigidbody attachedRigidbody = collider.attachedRigidbody;
			if ((LayerMask.op_Implicit(collider.excludeLayers) & selfLayer) == 0)
			{
				if (!((Object)(object)attachedRigidbody == (Object)null))
				{
					if (attachedRigidbody != s_hauledCart)
					{
						return (LayerMask.op_Implicit(attachedRigidbody.excludeLayers) & selfLayer) == 0;
					}
					return false;
				}
				return true;
			}
			return false;
		}

		private static void Debug(string what, Collider collider, string detail)
		{
			if (Plugin.StepUpDebug.Value)
			{
				string text = "Step-up " + what + ": " + ((Object)((Component)collider).transform.root).name + "/" + ((Object)collider).name + " layer=" + LayerMask.LayerToName(((Component)collider).gameObject.layer) + " " + detail;
				if (!(text == s_lastDebug) || !(Time.time - s_lastDebugTime < 1f))
				{
					s_lastDebug = text;
					s_lastDebugTime = Time.time;
					Plugin.Log.LogInfo((object)text);
				}
			}
		}

		private static void DebugIgnoredLayer(Vector3 origin, Vector3 dir, float distance)
		{
			//IL_000c: 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_006d: Unknown result type (might be due to invalid IL or missing references)
			RaycastHit val = default(RaycastHit);
			if (Plugin.StepUpDebug.Value && Physics.Raycast(origin, dir, ref val, distance, ~s_characterLayers, (QueryTriggerInteraction)1))
			{
				Debug((((Plugin.StepUpOnTerrain.Value ? s_maskWithTerrain : s_mask) & (1 << ((Component)((RaycastHit)(ref val)).collider).gameObject.layer)) != 0) ? "not blocking (walkable slope, or pass-through)" : "ignored: layer not stepped on", ((RaycastHit)(ref val)).collider, $"normalY={((RaycastHit)(ref val)).normal.y:0.00}");
			}
		}

		private static void Sweep(Player player, Rigidbody body, Vector3 dir, float dt, float maxStep, int mask, int selfLayer)
		{
			//IL_0015: 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_0042: 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_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_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_0081: Unknown result type (might be due to invalid IL or missing references)
			//IL_0082: 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_0095: Unknown result type (might be due to invalid IL or missing references)
			//IL_009a: Unknown result type (might be due to invalid IL or missing references)
			//IL_009c: Unknown result type (might be due to invalid IL or missing references)
			//IL_00aa: Unknown result type (might be due to invalid IL or missing references)
			//IL_00af: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00be: 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_00c8: 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_00d9: 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_0103: 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_0112: Unknown result type (might be due to invalid IL or missing references)
			//IL_0114: 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_011d: Unknown result type (might be due to invalid IL or missing references)
			//IL_011f: 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_0128: Unknown result type (might be due to invalid IL or missing references)
			//IL_019a: 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_01a0: 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_0156: Unknown result type (might be due to invalid IL or missing references)
			//IL_0162: Unknown result type (might be due to invalid IL or missing references)
			//IL_0167: Unknown result type (might be due to invalid IL or missing references)
			//IL_016c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0204: 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_0231: Unknown result type (might be due to invalid IL or missing references)
			//IL_0238: Unknown result type (might be due to invalid IL or missing references)
			//IL_023d: Unknown result type (might be due to invalid IL or missing references)
			//IL_023f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0241: Unknown result type (might be due to invalid IL or missing references)
			//IL_0243: Unknown result type (might be due to invalid IL or missing references)
			//IL_0248: Unknown result type (might be due to invalid IL or missing references)
			//IL_024a: 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_0253: Unknown result type (might be due to invalid IL or missing references)
			//IL_02a2: Unknown result type (might be due to invalid IL or missing references)
			//IL_02a4: Unknown result type (might be due to invalid IL or missing references)
			//IL_02a7: Unknown result type (might be due to invalid IL or missing references)
			//IL_02ac: Unknown result type (might be due to invalid IL or missing references)
			//IL_02b1: Unknown result type (might be due to invalid IL or missing references)
			//IL_02b3: Unknown result type (might be due to invalid IL or missing references)
			//IL_02b5: Unknown result type (might be due to invalid IL or missing references)
			//IL_02b7: Unknown result type (might be due to invalid IL or missing references)
			//IL_02bc: Unknown result type (might be due to invalid IL or missing references)
			//IL_02be: Unknown result type (might be due to invalid IL or missing references)
			//IL_02c0: Unknown result type (might be due to invalid IL or missing references)
			//IL_02c7: Unknown result type (might be due to invalid IL or missing references)
			//IL_031b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0320: Unknown result type (might be due to invalid IL or missing references)
			//IL_0327: Unknown result type (might be due to invalid IL or missing references)
			//IL_0328: Unknown result type (might be due to invalid IL or missing references)
			//IL_0330: Unknown result type (might be due to invalid IL or missing references)
			//IL_0391: Unknown result type (might be due to invalid IL or missing references)
			CapsuleCollider collider = ((Character)player).m_collider;
			Transform transform = ((Component)collider).transform;
			float num = collider.radius * Mathf.Max(Mathf.Abs(transform.lossyScale.x), Mathf.Abs(transform.lossyScale.z));
			float num2 = Mathf.Max(collider.height * Mathf.Abs(transform.lossyScale.y), num * 2f);
			Vector3 val = body.position + (transform.TransformPoint(collider.center) - transform.position);
			Vector3 val2 = val - Vector3.up * (num2 * 0.5f - num);
			Vector3 val3 = val + Vector3.up * (num2 * 0.5f - num);
			Vector3 feet = val2 - Vector3.up * num;
			float num3 = num - 0.03f;
			Vector3 currentVel = ((Character)player).m_currentVel;
			currentVel.y = 0f;
			float num4 = Mathf.Max(((Vector3)(ref currentVel)).magnitude * dt * 2f, 0.15f);
			Vector3 val4 = -dir * 0.15f;
			if (!Nearest(Physics.CapsuleCastNonAlloc(val2 + val4, val3 + val4, num3, dir, s_hits, 0.15f + num4 + 0.03f, mask, (QueryTriggerInteraction)1), selfLayer, 0.788f, out var best))
			{
				DebugIgnoredLayer(val2 - Vector3.up * (num - 0.1f), dir, num + num4);
				return;
			}
			float wallDistance = Mathf.Max(0f, ((RaycastHit)(ref best)).distance - 0.15f);
			float num5 = maxStep + 0.03f;
			if (Nearest(Physics.CapsuleCastNonAlloc(val2, val3, num3, Vector3.up, s_hits, num5, mask, (QueryTriggerInteraction)1), selfLayer, 1f, out var best2))
			{
				num5 = ((RaycastHit)(ref best2)).distance - 0.03f;
			}
			if (num5 < 0.05f)
			{
				Debug("rejected: no headroom", ((RaycastHit)(ref best)).collider, "ceiling=" + ((Object)((RaycastHit)(ref best2)).collider).name);
				return;
			}
			if (!FindStandPoint(feet, dir, wallDistance, num, num5, maxStep, mask, selfLayer, out var distance, out var why))
			{
				Debug(why, ((RaycastHit)(ref best)).collider, "");
				return;
			}
			Vector3 val5 = Vector3.up * num5;
			if (Nearest(Physics.CapsuleCastNonAlloc(val2 + val5, val3 + val5, num3, dir, s_hits, distance, mask, (QueryTriggerInteraction)1), selfLayer, 0.788f, out var best3))
			{
				Debug("rejected: taller than MaxHeight", ((RaycastHit)(ref best)).collider, $"blocked at raise={num5:0.00} by {((Object)((RaycastHit)(ref best3)).collider).name}");
				return;
			}
			Vector3 val6 = val5 + dir * distance;
			RaycastHit best4;
			float num6 = (Nearest(Physics.CapsuleCastNonAlloc(val2 + val6, val3 + val6, num3, Vector3.down, s_hits, num5, mask, (QueryTriggerInteraction)1), selfLayer, 1f, out best4) ? (num5 - ((RaycastHit)(ref best4)).distance) : 0f);
			if (!(num6 < 0.05f))
			{
				s_step = new StepState
				{
					Active = true,
					Start = body.position,
					Dir = dir,
					TargetY = body.position.y + num6 + 0.03f,
					Travel = distance,
					Obstacle = ((RaycastHit)(ref best)).collider
				};
				Debug("STEP", ((RaycastHit)(ref best)).collider, $"rise={num6:0.00} travel={distance:0.00}");
				ContinueStep(player, body, dir, dt);
			}
		}

		private static bool FindStandPoint(Vector3 feet, Vector3 dir, float wallDistance, float radius, float raise, float maxStep, int mask, int selfLayer, out float distance, out string why)
		{
			//IL_0023: 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_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0030: Unknown result type (might be due to invalid IL or missing references)
			//IL_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_0047: Unknown result type (might be due to invalid IL or missing references)
			//IL_0048: Unknown result type (might be due to invalid IL or missing references)
			//IL_005e: 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_0081: Unknown result type (might be due to invalid IL or missing references)
			//IL_008b: Unknown result type (might be due to invalid IL or missing references)
			distance = 0f;
			float num = 0.05f;
			float num2 = wallDistance + radius + 0.6f;
			for (float num3 = 0.05f; num3 <= num2; num3 += 0.05f)
			{
				Vector3 val = feet + dir * num3 + Vector3.up * (raise + 0.03f);
				if (StartsInside(val, mask, selfLayer))
				{
					why = "rejected: taller than MaxHeight";
					return false;
				}
				if (!Raycast(val, Vector3.down, raise + 0.03f + 0.05f, mask, selfLayer, out var best))
				{
					continue;
				}
				float num4 = ((RaycastHit)(ref best)).point.y - feet.y;
				if (num4 < 0.05f)
				{
					if (distance > 0f)
					{
						break;
					}
					continue;
				}
				if (num4 > maxStep)
				{
					why = "rejected: taller than MaxHeight";
					return false;
				}
				if (num4 > num)
				{
					num = num4;
					distance = num3;
				}
			}
			why = ((distance > 0f) ? null : "rejected: no top found");
			return distance > 0f;
		}

		private static bool StartsInside(Vector3 point, int mask, int selfLayer)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			int num = Physics.OverlapSphereNonAlloc(point, 0.01f, s_probeOverlaps, mask, (QueryTriggerInteraction)1);
			for (int i = 0; i < num; i++)
			{
				if (Blocks(s_probeOverlaps[i], selfLayer))
				{
					return true;
				}
			}
			return false;
		}

		private static bool ContinueStep(Player player, Rigidbody body, Vector3 dir, float dt)
		{
			//IL_0010: 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_0029: 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_0058: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00dd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00de: Unknown result type (might be due to invalid IL or missing references)
			//IL_0121: Unknown result type (might be due to invalid IL or missing references)
			//IL_0126: Unknown result type (might be due to invalid IL or missing references)
			//IL_0127: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fc: Unknown result type (might be due to invalid IL or missing references)
			//IL_011a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0141: Unknown result type (might be due to invalid IL or missing references)
			s_step.Timer += dt;
			float num = Vector3.Dot(body.position - s_step.Start, s_step.Dir);
			if (num >= s_step.Travel || s_step.Timer > 0.6f || Vector3.Dot(dir, s_step.Dir) < 0.5f)
			{
				if (num < s_step.Travel && (Object)(object)s_step.Obstacle != (Object)null)
				{
					Debug("step abandoned", s_step.Obstacle, $"traveled={num:0.00}/{s_step.Travel:0.00} time={s_step.Timer:0.00}");
				}
				s_step.Active = false;
				return false;
			}
			Vector3 position = body.position;
			if (position.y < s_step.TargetY)
			{
				position.y = Mathf.Min(s_step.TargetY, position.y + Plugin.StepUpSpeed.Value * dt);
				body.position = position;
			}
			Vector3 linearVelocity = body.linearVelocity;
			if (linearVelocity.y < 0f)
			{
				linearVelocity.y = 0f;
				body.linearVelocity = linearVelocity;
			}
			((Character)player).m_lastGroundTouch = 0f;
			return true;
		}
	}
}
namespace System.Runtime.CompilerServices
{
	[AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)]
	internal sealed class IgnoresAccessChecksToAttribute : Attribute
	{
		public IgnoresAccessChecksToAttribute(string assemblyName)
		{
		}
	}
}