Decompiled source of ClimbingMod v1.1.5

Valheim-Climbing-Mod.dll

Decompiled 3 weeks ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
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 Microsoft.CodeAnalysis;
using UnityEngine;
using UnityEngine.Animations;
using UnityEngine.Playables;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = "")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("0.0.0.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.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 Valheim_Climbing_Mod
{
	public static class ClimbAnimationController
	{
		private enum ClipDirection
		{
			Up,
			Down
		}

		private class PlayerAnimationState
		{
			public Animator Animator;

			public PlayableGraph Graph;

			public AnimationClipPlayable UpPlayable;

			public AnimationClipPlayable DownPlayable;

			public AnimationMixerPlayable Mixer;

			public ClipDirection CurrentDirection = ClipDirection.Up;
		}

		private static readonly Dictionary<Player, PlayerAnimationState> ActiveStates = new Dictionary<Player, PlayerAnimationState>();

		private static ManualLogSource _logger;

		private static AnimationClip _upClip;

		private static AnimationClip _downClip;

		private static bool _initialized;

		private static readonly FieldInfo AnimatorField = AccessTools.Field(typeof(Character), "m_animator");

		public static void Initialize(ManualLogSource logger)
		{
			if (_initialized)
			{
				return;
			}
			_initialized = true;
			_logger = logger;
			_upClip = LoadClip("climbingup");
			_downClip = LoadClip("climbingdown");
			if ((Object)(object)_upClip == (Object)null || (Object)(object)_downClip == (Object)null)
			{
				ManualLogSource logger2 = _logger;
				if (logger2 != null)
				{
					logger2.LogWarning((object)"Climbing animation clips were not loaded. Default animations will be used instead.");
				}
			}
		}

		private static AnimationClip LoadClip(string bundleName)
		{
			try
			{
				string directoryName = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
				if (string.IsNullOrEmpty(directoryName))
				{
					ManualLogSource logger = _logger;
					if (logger != null)
					{
						logger.LogWarning((object)("Unable to determine plugin directory while loading '" + bundleName + "'."));
					}
					return null;
				}
				string text = Path.Combine(directoryName, bundleName);
				if (!File.Exists(text))
				{
					ManualLogSource logger2 = _logger;
					if (logger2 != null)
					{
						logger2.LogWarning((object)("Animation asset bundle '" + text + "' was not found."));
					}
					return null;
				}
				AssetBundle val = AssetBundle.LoadFromFile(text);
				if ((Object)(object)val == (Object)null)
				{
					ManualLogSource logger3 = _logger;
					if (logger3 != null)
					{
						logger3.LogWarning((object)("Failed to load AssetBundle from '" + text + "'."));
					}
					return null;
				}
				try
				{
					AnimationClip val2 = val.LoadAsset<AnimationClip>(bundleName);
					if ((Object)(object)val2 == (Object)null)
					{
						AnimationClip[] array = val.LoadAllAssets<AnimationClip>();
						if (array.Length != 0)
						{
							val2 = array[0];
						}
					}
					if ((Object)(object)val2 == (Object)null)
					{
						ManualLogSource logger4 = _logger;
						if (logger4 != null)
						{
							logger4.LogWarning((object)("No AnimationClip found inside '" + bundleName + "'."));
						}
					}
					return val2;
				}
				finally
				{
					val.Unload(false);
				}
			}
			catch (Exception arg)
			{
				ManualLogSource logger5 = _logger;
				if (logger5 != null)
				{
					logger5.LogError((object)$"Failed to load animation clip '{bundleName}': {arg}");
				}
				return null;
			}
		}

		private static Animator GetAnimator(Player player)
		{
			if (AnimatorField != null)
			{
				object? value = AnimatorField.GetValue(player);
				Animator val = (Animator)((value is Animator) ? value : null);
				if (val != null && (Object)(object)val != (Object)null)
				{
					return val;
				}
			}
			return ((Component)player).GetComponentInChildren<Animator>();
		}

		public static void Begin(Player player)
		{
			//IL_0084: 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_0093: 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_009e: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ae: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bf: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ca: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e0: 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_00fc: 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_0108: Unknown result type (might be due to invalid IL or missing references)
			//IL_010a: 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_012f: 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_0136: 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_013d: Unknown result type (might be due to invalid IL or missing references)
			//IL_013e: 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)
			if ((Object)(object)_upClip == (Object)null || (Object)(object)_downClip == (Object)null || ActiveStates.ContainsKey(player))
			{
				return;
			}
			Animator animator = GetAnimator(player);
			if ((Object)(object)animator == (Object)null)
			{
				ManualLogSource logger = _logger;
				if (logger != null)
				{
					logger.LogWarning((object)"Unable to locate player Animator component for climbing animations.");
				}
				return;
			}
			PlayableGraph val = PlayableGraph.Create($"ClimbGraph_{player.GetPlayerID()}");
			((PlayableGraph)(ref val)).SetTimeUpdateMode((DirectorUpdateMode)1);
			AnimationClipPlayable val2 = AnimationClipPlayable.Create(val, _upClip);
			((AnimationClipPlayable)(ref val2)).SetApplyFootIK(true);
			AnimationClipPlayable val3 = AnimationClipPlayable.Create(val, _downClip);
			((AnimationClipPlayable)(ref val3)).SetApplyFootIK(true);
			AnimationMixerPlayable val4 = AnimationMixerPlayable.Create(val, 2);
			((PlayableGraph)(ref val)).Connect<AnimationClipPlayable, AnimationMixerPlayable>(val2, 0, val4, 0);
			((PlayableGraph)(ref val)).Connect<AnimationClipPlayable, AnimationMixerPlayable>(val3, 0, val4, 1);
			PlayableExtensions.SetInputWeight<AnimationMixerPlayable>(val4, 0, 1f);
			PlayableExtensions.SetInputWeight<AnimationMixerPlayable>(val4, 1, 0f);
			AnimationPlayableOutput val5 = AnimationPlayableOutput.Create(val, "ClimbOutput", animator);
			PlayableOutputExtensions.SetSourcePlayable<AnimationPlayableOutput, AnimationMixerPlayable>(val5, val4);
			((PlayableGraph)(ref val)).Play();
			ActiveStates[player] = new PlayerAnimationState
			{
				Animator = animator,
				Graph = val,
				UpPlayable = val2,
				DownPlayable = val3,
				Mixer = val4,
				CurrentDirection = ClipDirection.Up
			};
		}

		public static void Update(Player player, float verticalInput, float animationSpeedMultiplier = 0.9f)
		{
			if (ActiveStates.TryGetValue(player, out var value))
			{
				if (Mathf.Abs(verticalInput) <= 0.05f)
				{
					Pause(value);
				}
				else if (verticalInput > 0f)
				{
					SwitchClip(value, ClipDirection.Up, Mathf.Abs(verticalInput), animationSpeedMultiplier);
				}
				else
				{
					SwitchClip(value, ClipDirection.Down, Mathf.Abs(verticalInput), animationSpeedMultiplier);
				}
			}
		}

		private static void Pause(PlayerAnimationState state)
		{
			//IL_0002: 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)
			PlayableExtensions.SetSpeed<AnimationClipPlayable>(state.UpPlayable, 0.0);
			PlayableExtensions.SetSpeed<AnimationClipPlayable>(state.DownPlayable, 0.0);
		}

		private static void SwitchClip(PlayerAnimationState state, ClipDirection direction, float speed, float animationSpeedMultiplier)
		{
			//IL_00b9: 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_00dd: 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_00a3: 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_0059: Unknown result type (might be due to invalid IL or missing references)
			//IL_006b: 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_0031: Unknown result type (might be due to invalid IL or missing references)
			float num = Mathf.Max(speed * Mathf.Max(animationSpeedMultiplier, 0.01f), 0.25f);
			if (direction == ClipDirection.Up)
			{
				if (state.CurrentDirection != 0)
				{
					PlayableExtensions.SetTime<AnimationClipPlayable>(state.UpPlayable, 0.0);
				}
				PlayableExtensions.SetInputWeight<AnimationMixerPlayable>(state.Mixer, 0, 1f);
				PlayableExtensions.SetInputWeight<AnimationMixerPlayable>(state.Mixer, 1, 0f);
				PlayableExtensions.SetSpeed<AnimationClipPlayable>(state.UpPlayable, (double)num);
				PlayableExtensions.SetSpeed<AnimationClipPlayable>(state.DownPlayable, 0.0);
			}
			else
			{
				if (state.CurrentDirection != ClipDirection.Down)
				{
					PlayableExtensions.SetTime<AnimationClipPlayable>(state.DownPlayable, 0.0);
				}
				PlayableExtensions.SetInputWeight<AnimationMixerPlayable>(state.Mixer, 0, 0f);
				PlayableExtensions.SetInputWeight<AnimationMixerPlayable>(state.Mixer, 1, 1f);
				PlayableExtensions.SetSpeed<AnimationClipPlayable>(state.DownPlayable, (double)num);
				PlayableExtensions.SetSpeed<AnimationClipPlayable>(state.UpPlayable, 0.0);
			}
			state.CurrentDirection = direction;
			if (!((PlayableGraph)(ref state.Graph)).IsPlaying())
			{
				((PlayableGraph)(ref state.Graph)).Play();
			}
		}

		public static void End(Player player)
		{
			if (ActiveStates.TryGetValue(player, out var value))
			{
				if (((PlayableGraph)(ref value.Graph)).IsValid())
				{
					((PlayableGraph)(ref value.Graph)).Destroy();
				}
				ActiveStates.Remove(player);
			}
		}

		public static void Cleanup(Player player)
		{
			End(player);
		}

		public static bool IsActive(Player player)
		{
			return ActiveStates.ContainsKey(player);
		}
	}
	public static class ClimbingConfig
	{
		public const float DETECTION_DISTANCE = 0.6f;

		public const float MIN_SURFACE_ANGLE = 55f;

		public const float MAX_SURFACE_ANGLE = 240f;

		public const float STICK_FORCE = 0.5f;

		public const float SURFACE_TARGET_DISTANCE = 0.18f;

		public const float SURFACE_REPEL_FORCE = 0.15f;

		public const float FACE_SURFACE_TURN_SPEED = 10f;

		public const float STEEP_SURFACE_ANGLE = 90f;

		public const float SHALLOW_SURFACE_ANGLE = 10f;

		public const float STEEP_SURFACE_SPEED_FACTOR = 1f;

		public const float SHALLOW_SURFACE_SPEED_FACTOR = 1.4f;

		public const float REPEL_DISABLE_SURFACE_ANGLE = 25f;

		public const float REPEL_FULL_STRENGTH_SURFACE_ANGLE = 60f;

		public static float CLIMB_SPEED_UP => ClimbingModPlugin.ClimbSpeedUp?.Value ?? 1f;

		public static float CLIMB_SPEED_DOWN => ClimbingModPlugin.ClimbSpeedDown?.Value ?? 1f;

		public static float STAMINA_DRAIN_PER_SECOND => ClimbingModPlugin.StaminaDrainPerSecond?.Value ?? 3f;
	}
	[BepInPlugin("com.rotceh.valheimclimbingmod", "Valheim Climbing Mod", "1.0.0")]
	public class ClimbingModPlugin : BaseUnityPlugin
	{
		public static ConfigEntry<KeyCode> ClimbKey;

		public static ConfigEntry<KeyCode> ClimbKey2;

		public static ConfigEntry<float> ClimbSpeedUp;

		public static ConfigEntry<float> ClimbSpeedDown;

		public static ConfigEntry<float> StaminaDrainPerSecond;

		public static ConfigEntry<float> ClimbSkillXpPerSecond;

		public static ConfigEntry<float> ClimbSkillBaseXpPerLevel;

		public static ConfigEntry<float> ClimbSkillXpIncreasePerLevel;

		public static ConfigEntry<bool> ToggleClimbKey;

		private void Awake()
		{
			//IL_0142: Unknown result type (might be due to invalid IL or missing references)
			//IL_0148: Expected O, but got Unknown
			//IL_015f: Unknown result type (might be due to invalid IL or missing references)
			//IL_016e: Unknown result type (might be due to invalid IL or missing references)
			ClimbKey = ((BaseUnityPlugin)this).Config.Bind<KeyCode>("General", "ClimbKey", (KeyCode)308, "Key to trigger climbing (default: LeftAlt)");
			ClimbKey2 = ((BaseUnityPlugin)this).Config.Bind<KeyCode>("General", "ClimbKey2", (KeyCode)0, "Optional second key that must be held along with ClimbKey.");
			ToggleClimbKey = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "ToggleClimbKey", false, "When enabled, pressing the climb key toggles climbing instead of requiring the key to be held.");
			ClimbSpeedUp = ((BaseUnityPlugin)this).Config.Bind<float>("Movement", "ClimbSpeedUp", 1f, "Base climb speed when moving upward (W).");
			ClimbSpeedDown = ((BaseUnityPlugin)this).Config.Bind<float>("Movement", "ClimbSpeedDown", 1f, "Base climb speed when moving downward or sideways (S/A/D).");
			StaminaDrainPerSecond = ((BaseUnityPlugin)this).Config.Bind<float>("Movement", "StaminaDrainPerSecond", 2f, "Stamina drained per second while climbing (scaled by movement).");
			ClimbSkillXpPerSecond = ((BaseUnityPlugin)this).Config.Bind<float>("Progression", "ClimbSkillXpPerSecond", 6f, "Climbing XP gained per second while climbing.");
			ClimbSkillBaseXpPerLevel = ((BaseUnityPlugin)this).Config.Bind<float>("Progression", "ClimbSkillBaseXpPerLevel", 100f, "XP required for level 0 -> 1.");
			ClimbSkillXpIncreasePerLevel = ((BaseUnityPlugin)this).Config.Bind<float>("Progression", "ClimbSkillXpIncreasePerLevel", 40f, "Additional XP required per level.");
			Harmony val = new Harmony("com.rotceh.valheimclimbingmod");
			val.PatchAll();
			((BaseUnityPlugin)this).Logger.LogInfo((object)$"Valheim Climbing Mod loaded. Climb key: {ClimbKey.Value} + Modifier: {ClimbKey2.Value}");
			ClimbAnimationController.Initialize(((BaseUnityPlugin)this).Logger);
		}
	}
	[HarmonyPatch(typeof(Player), "FixedUpdate")]
	public class Player_FixedUpdate_Patch
	{
		[CompilerGenerated]
		private sealed class <EnumerateProbeDirections>d__29 : IEnumerable<Vector3>, IEnumerable, IEnumerator<Vector3>, IDisposable, IEnumerator
		{
			private int <>1__state;

			private Vector3 <>2__current;

			private int <>l__initialThreadId;

			private Player player;

			public Player <>3__player;

			private Vector3 preferredNormal;

			public Vector3 <>3__preferredNormal;

			private Transform <t>5__1;

			private Vector3[] <>s__2;

			private int <>s__3;

			private Vector3 <dir>5__4;

			Vector3 IEnumerator<Vector3>.Current
			{
				[DebuggerHidden]
				get
				{
					//IL_0001: Unknown result type (might be due to invalid IL or missing references)
					return <>2__current;
				}
			}

			object IEnumerator.Current
			{
				[DebuggerHidden]
				get
				{
					//IL_0001: Unknown result type (might be due to invalid IL or missing references)
					return <>2__current;
				}
			}

			[DebuggerHidden]
			public <EnumerateProbeDirections>d__29(int <>1__state)
			{
				this.<>1__state = <>1__state;
				<>l__initialThreadId = Environment.CurrentManagedThreadId;
			}

			[DebuggerHidden]
			void IDisposable.Dispose()
			{
				<t>5__1 = null;
				<>s__2 = null;
				<>1__state = -2;
			}

			private bool MoveNext()
			{
				//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_00d9: Unknown result type (might be due to invalid IL or missing references)
				//IL_00de: Unknown result type (might be due to invalid IL or missing references)
				//IL_00e3: Unknown result type (might be due to invalid IL or missing references)
				//IL_00ff: Unknown result type (might be due to invalid IL or missing references)
				//IL_0104: 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_012a: 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_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_0171: 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_00bd: 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_008a: 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_01ad: 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_01ba: Unknown result type (might be due to invalid IL or missing references)
				switch (<>1__state)
				{
				default:
					return false;
				case 0:
					<>1__state = -1;
					if (preferredNormal != Vector3.zero)
					{
						<>2__current = -((Vector3)(ref preferredNormal)).normalized;
						<>1__state = 1;
						return true;
					}
					goto IL_00a0;
				case 1:
					<>1__state = -1;
					goto IL_00a0;
				case 2:
					<>1__state = -1;
					<>2__current = -<t>5__1.forward;
					<>1__state = 3;
					return true;
				case 3:
					<>1__state = -1;
					<>2__current = <t>5__1.up;
					<>1__state = 4;
					return true;
				case 4:
					<>1__state = -1;
					<>2__current = -<t>5__1.up;
					<>1__state = 5;
					return true;
				case 5:
					<>1__state = -1;
					<>2__current = <t>5__1.right;
					<>1__state = 6;
					return true;
				case 6:
					<>1__state = -1;
					<>2__current = -<t>5__1.right;
					<>1__state = 7;
					return true;
				case 7:
					<>1__state = -1;
					<>s__2 = WorldProbeDirections;
					<>s__3 = 0;
					break;
				case 8:
					{
						<>1__state = -1;
						<>s__3++;
						break;
					}
					IL_00a0:
					<t>5__1 = ((Component)player).transform;
					<>2__current = <t>5__1.forward;
					<>1__state = 2;
					return true;
				}
				if (<>s__3 < <>s__2.Length)
				{
					<dir>5__4 = <>s__2[<>s__3];
					<>2__current = <dir>5__4;
					<>1__state = 8;
					return true;
				}
				<>s__2 = null;
				return false;
			}

			bool IEnumerator.MoveNext()
			{
				//ILSpy generated this explicit interface implementation from .override directive in MoveNext
				return this.MoveNext();
			}

			[DebuggerHidden]
			void IEnumerator.Reset()
			{
				throw new NotSupportedException();
			}

			[DebuggerHidden]
			IEnumerator<Vector3> IEnumerable<Vector3>.GetEnumerator()
			{
				//IL_0037: Unknown result type (might be due to invalid IL or missing references)
				//IL_003c: Unknown result type (might be due to invalid IL or missing references)
				<EnumerateProbeDirections>d__29 <EnumerateProbeDirections>d__;
				if (<>1__state == -2 && <>l__initialThreadId == Environment.CurrentManagedThreadId)
				{
					<>1__state = 0;
					<EnumerateProbeDirections>d__ = this;
				}
				else
				{
					<EnumerateProbeDirections>d__ = new <EnumerateProbeDirections>d__29(0);
				}
				<EnumerateProbeDirections>d__.player = <>3__player;
				<EnumerateProbeDirections>d__.preferredNormal = <>3__preferredNormal;
				return <EnumerateProbeDirections>d__;
			}

			[DebuggerHidden]
			IEnumerator IEnumerable.GetEnumerator()
			{
				return ((IEnumerable<Vector3>)this).GetEnumerator();
			}
		}

		private static readonly int SurfaceLayerMask = LayerMask.GetMask(new string[5] { "Default", "static_solid", "terrain", "piece", "Default_small" });

		private const float TopOutProbeHeight = 1.2f;

		private const float TopOutProbeForwardOffset = 0.55f;

		private const float TopOutGroundCheckDistance = 1.6f;

		private const float TopOutWallCheckDistance = 0.65f;

		private const float TopOutJumpUpSpeed = 5.5f;

		private const float TopOutJumpForwardSpeed = 2.2f;

		private static readonly FieldInfo MaxAirAltitudeField = AccessTools.Field(typeof(Character), "m_maxAirAltitude");

		private static readonly FieldInfo LastGroundPointField = AccessTools.Field(typeof(Character), "m_lastGroundPoint");

		private static readonly float[] ProbeHeights = new float[3] { 1.2f, 0.7f, 0.2f };

		private static readonly float[] StartProbeHeights = new float[2] { 1.15f, 0.8f };

		private static readonly float[] StartProbeYawOffsets = new float[3] { 0f, -20f, 20f };

		private const int RequiredStableStartFrames = 3;

		private const float MinFacingWallDot = 0.55f;

		private const float MinStartHitHeightOffset = 0.25f;

		private static readonly Vector3[] WorldProbeDirections = (Vector3[])(object)new Vector3[6]
		{
			Vector3.up,
			Vector3.down,
			Vector3.right,
			Vector3.left,
			Vector3.forward,
			Vector3.back
		};

		private static MethodInfo _takeInputMethod;

		private static bool CallTakeInput(Player player)
		{
			if (_takeInputMethod == null)
			{
				_takeInputMethod = typeof(Player).GetMethod("TakeInput", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
			}
			if (_takeInputMethod != null)
			{
				return (bool)_takeInputMethod.Invoke(player, null);
			}
			return true;
		}

		private static void Postfix(Player __instance)
		{
			//IL_0093: 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_01b5: 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_00bf: 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_01ff: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c7: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c9: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)__instance == (Object)null)
			{
				return;
			}
			if ((Object)(object)__instance != (Object)(object)Player.m_localPlayer)
			{
				HandleRemotePlayer(__instance);
			}
			else
			{
				if (((Character)__instance).IsDead() || ((Character)__instance).InCutscene() || ((Character)__instance).IsTeleporting())
				{
					return;
				}
				ClimbingState.ClimbingData orCreate = ClimbingState.GetOrCreate(__instance);
				float skill = ClimbSkillProgression.GetSkill(__instance);
				orCreate.climbSkill = skill;
				bool flag = ClimbingModPlugin.ToggleClimbKey?.Value ?? false;
				bool flag2 = false;
				if (CallTakeInput(__instance))
				{
					bool flag3 = (int)ClimbingModPlugin.ClimbKey2.Value == 0 || Input.GetKey(ClimbingModPlugin.ClimbKey2.Value);
					if (flag)
					{
						if (flag3 && Input.GetKeyDown(ClimbingModPlugin.ClimbKey.Value))
						{
							orCreate.toggleActive = !orCreate.toggleActive;
							if (!orCreate.toggleActive && orCreate.isClimbing)
							{
								StopClimbing(__instance, orCreate);
							}
						}
						flag2 = orCreate.toggleActive;
					}
					else
					{
						flag2 = flag3 && Input.GetKey(ClimbingModPlugin.ClimbKey.Value);
						if (!flag2)
						{
							orCreate.toggleActive = false;
							orCreate.validStartSurfaceFrames = 0;
						}
					}
				}
				else
				{
					flag2 = orCreate.toggleActive;
				}
				Vector3 normal;
				if (!orCreate.isClimbing)
				{
					if (flag2)
					{
						TryStartClimbing(__instance, orCreate);
					}
					else
					{
						orCreate.validStartSurfaceFrames = 0;
					}
				}
				else if (!flag2)
				{
					StopClimbing(__instance, orCreate);
				}
				else if (!PlayerHasClimbStamina(__instance))
				{
					StopClimbing(__instance, orCreate);
				}
				else if (TryGetSurfaceNormal(__instance, out normal, orCreate.surfaceNormal))
				{
					orCreate.surfaceNormal = normal;
					ClimbSkillProgression.AddSkill(__instance, Time.deltaTime);
					float skill2 = ClimbSkillProgression.GetSkill(__instance);
					orCreate.climbSkill = skill2;
				}
				else
				{
					Vector3 surfaceNormal = orCreate.surfaceNormal;
					StopClimbing(__instance, orCreate);
					TryAutoTopOutJump(__instance, surfaceNormal);
				}
			}
		}

		private static void TryAutoTopOutJump(Player player, Vector3 previousSurfaceNormal)
		{
			//IL_000a: 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_002b: Unknown result type (might be due to invalid IL or missing references)
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0031: Unknown result type (might be due to invalid IL or missing references)
			//IL_0036: Unknown result type (might be due to invalid IL or missing references)
			//IL_003b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0052: Unknown result type (might be due to invalid IL or missing references)
			//IL_0057: Unknown result type (might be due to invalid IL or missing references)
			//IL_005c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0061: Unknown result type (might be due to invalid IL or missing references)
			//IL_0086: Unknown result type (might be due to invalid IL or missing references)
			//IL_008b: Unknown result type (might be due to invalid IL or missing references)
			//IL_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_009f: 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_00a6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ca: Unknown result type (might be due to invalid IL or missing references)
			//IL_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_00de: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ee: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ef: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f0: Unknown result type (might be due to invalid IL or missing references)
			//IL_0115: 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_0155: Unknown result type (might be due to invalid IL or missing references)
			//IL_015a: Unknown result type (might be due to invalid IL or missing references)
			//IL_015c: Unknown result type (might be due to invalid IL or missing references)
			//IL_015e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0163: Unknown result type (might be due to invalid IL or missing references)
			//IL_0168: Unknown result type (might be due to invalid IL or missing references)
			//IL_016a: Unknown result type (might be due to invalid IL or missing references)
			//IL_016c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0172: Unknown result type (might be due to invalid IL or missing references)
			//IL_0177: Unknown result type (might be due to invalid IL or missing references)
			//IL_017c: 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_0193: 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_01a3: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)player == (Object)null || previousSurfaceNormal == Vector3.zero)
			{
				return;
			}
			Transform transform = ((Component)player).transform;
			Vector3 val = Vector3.ProjectOnPlane(-previousSurfaceNormal, Vector3.up);
			if (((Vector3)(ref val)).sqrMagnitude < 0.01f)
			{
				val = Vector3.ProjectOnPlane(transform.forward, Vector3.up);
			}
			if (((Vector3)(ref val)).sqrMagnitude < 0.01f)
			{
				return;
			}
			((Vector3)(ref val)).Normalize();
			Vector3 val2 = transform.position + Vector3.up * 1f;
			RaycastHit val3 = default(RaycastHit);
			if (Physics.SphereCast(val2, 0.25f, val, ref val3, 0.65f, SurfaceLayerMask))
			{
				return;
			}
			Vector3 val4 = transform.position + Vector3.up * 1.2f + val * 0.55f;
			RaycastHit val5 = default(RaycastHit);
			if (!Physics.Raycast(val4, Vector3.down, ref val5, 1.6f, SurfaceLayerMask))
			{
				return;
			}
			float num = Vector3.Angle(Vector3.up, ((RaycastHit)(ref val5)).normal);
			if (!(num > 50f))
			{
				Rigidbody component = ((Component)player).GetComponent<Rigidbody>();
				if (!((Object)(object)component == (Object)null))
				{
					Vector3 linearVelocity = component.linearVelocity;
					Vector3 val6 = Vector3.ProjectOnPlane(linearVelocity, Vector3.up);
					val6 += val * 2.2f;
					float num2 = Mathf.Max(linearVelocity.y, 5.5f);
					component.linearVelocity = new Vector3(val6.x, num2, val6.z);
				}
			}
		}

		private static void HandleRemotePlayer(Player player)
		{
			ZNetView component = ((Component)player).GetComponent<ZNetView>();
			if (!((Object)(object)component == (Object)null) && component.IsValid())
			{
				ZDO zDO = component.GetZDO();
				bool @bool = zDO.GetBool("IsClimbing", false);
				float @float = zDO.GetFloat("RotcehClimbSkill", 0f);
				bool flag = ClimbAnimationController.IsActive(player);
				if (@bool && !flag)
				{
					ClimbAnimationController.Begin(player);
				}
				else if (!@bool && flag)
				{
					ClimbAnimationController.End(player);
				}
				if (@bool)
				{
					float float2 = zDO.GetFloat("ClimbInput", 0f);
					float speedMultiplier = ClimbSkillProgression.GetSpeedMultiplier(@float);
					ClimbAnimationController.Update(player, float2, speedMultiplier);
				}
			}
		}

		private static void TryStartClimbing(Player player, ClimbingState.ClimbingData climbData)
		{
			//IL_0046: Unknown result type (might be due to invalid IL or missing references)
			Vector3 normal;
			if (!PlayerHasClimbStamina(player))
			{
				climbData.validStartSurfaceFrames = 0;
			}
			else if (TryGetStartSurfaceNormal(player, out normal))
			{
				climbData.validStartSurfaceFrames++;
				if (climbData.validStartSurfaceFrames >= 3)
				{
					StartClimbing(player, climbData, normal);
				}
			}
			else
			{
				climbData.validStartSurfaceFrames = 0;
			}
		}

		private static bool TryGetStartSurfaceNormal(Player player, out Vector3 normal)
		{
			//IL_0009: Unknown result type (might be due to invalid IL or missing references)
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0032: Unknown result type (might be due to invalid IL or missing references)
			//IL_005b: 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_0071: Unknown result type (might be due to invalid IL or missing references)
			//IL_0183: Unknown result type (might be due to invalid IL or missing references)
			//IL_0188: 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_0093: 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_0099: 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_00a0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c5: 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_00f8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fd: Unknown result type (might be due to invalid IL or missing references)
			//IL_0101: Unknown result type (might be due to invalid IL or missing references)
			//IL_0106: 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_0124: Unknown result type (might be due to invalid IL or missing references)
			//IL_012f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0150: Unknown result type (might be due to invalid IL or missing references)
			//IL_0155: Unknown result type (might be due to invalid IL or missing references)
			Transform transform = ((Component)player).transform;
			Vector3 val = Vector3.ProjectOnPlane(transform.forward, Vector3.up);
			if (((Vector3)(ref val)).sqrMagnitude < 0.01f)
			{
				val = transform.forward;
			}
			((Vector3)(ref val)).Normalize();
			float num = 0.8f;
			float[] startProbeHeights = StartProbeHeights;
			RaycastHit val4 = default(RaycastHit);
			foreach (float num2 in startProbeHeights)
			{
				Vector3 val2 = transform.position + Vector3.up * num2;
				float[] startProbeYawOffsets = StartProbeYawOffsets;
				foreach (float num3 in startProbeYawOffsets)
				{
					Vector3 val3 = Quaternion.AngleAxis(num3, transform.up) * val;
					if (!Physics.SphereCast(val2, 0.3f, val3, ref val4, num, SurfaceLayerMask))
					{
						continue;
					}
					float num4 = Vector3.Angle(Vector3.up, ((RaycastHit)(ref val4)).normal);
					if (!(num4 < 55f) && !(num4 > 240f))
					{
						Vector3 normal2 = ((RaycastHit)(ref val4)).normal;
						float num5 = Vector3.Dot(-((Vector3)(ref normal2)).normalized, ((Vector3)(ref val3)).normalized);
						if (!(num5 < 0.55f) && !(((RaycastHit)(ref val4)).point.y < transform.position.y + 0.25f))
						{
							normal = ((RaycastHit)(ref val4)).normal;
							return true;
						}
					}
				}
			}
			normal = Vector3.zero;
			return false;
		}

		public static bool HasReliableClimbSurface(Player player, ClimbingState.ClimbingData climbData)
		{
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)player == (Object)null || climbData == null || !climbData.isClimbing)
			{
				return false;
			}
			Vector3 normal;
			return TryGetSurfaceNormal(player, out normal, climbData.surfaceNormal);
		}

		private static bool PlayerHasClimbStamina(Player player)
		{
			return player.GetStamina() > 0.25f;
		}

		private static void StartClimbing(Player player, ClimbingState.ClimbingData climbData, Vector3 surfaceNormal)
		{
			//IL_0009: Unknown result type (might be due to invalid IL or missing references)
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			//IL_008d: 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)
			climbData.isClimbing = true;
			climbData.surfaceNormal = surfaceNormal;
			climbData.validStartSurfaceFrames = 0;
			ResetFallCalculation(player);
			ZNetView component = ((Component)player).GetComponent<ZNetView>();
			if ((Object)(object)component != (Object)null && component.IsValid())
			{
				component.GetZDO().Set("IsClimbing", true);
				component.GetZDO().Set("RotcehClimbSkill", ClimbSkillProgression.GetSkill(player));
			}
			Rigidbody component2 = ((Component)player).GetComponent<Rigidbody>();
			if ((Object)(object)component2 != (Object)null)
			{
				climbData.wasGravityEnabled = component2.useGravity;
				component2.useGravity = false;
				component2.linearVelocity = Vector3.zero;
				component2.angularVelocity = Vector3.zero;
			}
			ClimbAnimationController.Begin(player);
		}

		public static void ResetFallCalculation(Player player)
		{
			//IL_0015: 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)
			if (!((Object)(object)player == (Object)null))
			{
				float y = ((Component)player).transform.position.y;
				if (MaxAirAltitudeField != null)
				{
					MaxAirAltitudeField.SetValue(player, y);
				}
				if (LastGroundPointField != null)
				{
					LastGroundPointField.SetValue(player, ((Component)player).transform.position);
				}
			}
		}

		public static void StopClimbing(Player player, ClimbingState.ClimbingData climbData)
		{
			climbData.isClimbing = false;
			climbData.validStartSurfaceFrames = 0;
			ZNetView component = ((Component)player).GetComponent<ZNetView>();
			if ((Object)(object)component != (Object)null && component.IsValid())
			{
				component.GetZDO().Set("IsClimbing", false);
				component.GetZDO().Set("RotcehClimbSkill", ClimbSkillProgression.GetSkill(player));
			}
			Rigidbody component2 = ((Component)player).GetComponent<Rigidbody>();
			if ((Object)(object)component2 != (Object)null)
			{
				component2.useGravity = climbData.wasGravityEnabled;
			}
			ClimbAnimationController.End(player);
		}

		private static bool TryGetSurfaceNormal(Player player, out Vector3 normal, Vector3 preferredNormal = default(Vector3))
		{
			//IL_0020: 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_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_0035: 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_00e0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e5: Unknown result type (might be due to invalid IL or missing references)
			//IL_004a: Unknown result type (might be due to invalid IL or missing references)
			//IL_004f: 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_0059: Unknown result type (might be due to invalid IL or missing references)
			//IL_0074: Unknown result type (might be due to invalid IL or missing references)
			//IL_007b: 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_00ae: Unknown result type (might be due to invalid IL or missing references)
			float num = 1.35f;
			float[] probeHeights = ProbeHeights;
			RaycastHit val2 = default(RaycastHit);
			foreach (float num2 in probeHeights)
			{
				Vector3 val = ((Component)player).transform.position + Vector3.up * num2;
				foreach (Vector3 item in EnumerateProbeDirections(player, preferredNormal))
				{
					if (Physics.SphereCast(val, 0.4f, item, ref val2, num, SurfaceLayerMask))
					{
						float num3 = Vector3.Angle(Vector3.up, ((RaycastHit)(ref val2)).normal);
						if (num3 >= 55f && num3 <= 240f)
						{
							normal = ((RaycastHit)(ref val2)).normal;
							return true;
						}
					}
				}
			}
			normal = Vector3.zero;
			return false;
		}

		[IteratorStateMachine(typeof(<EnumerateProbeDirections>d__29))]
		private static IEnumerable<Vector3> EnumerateProbeDirections(Player player, Vector3 preferredNormal)
		{
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
			return new <EnumerateProbeDirections>d__29(-2)
			{
				<>3__player = player,
				<>3__preferredNormal = preferredNormal
			};
		}
	}
	[HarmonyPatch(typeof(Character), "UpdateMotion")]
	internal class Character_UpdateMotion_Patch
	{
		private static readonly int SurfaceLayerMask = LayerMask.GetMask(new string[5] { "Default", "static_solid", "terrain", "piece", "Default_small" });

		private static bool Prefix(Character __instance)
		{
			Player val = (Player)(object)((__instance is Player) ? __instance : null);
			if (val != null && ClimbingState.IsClimbing(val))
			{
				HandleClimbingMovement(val);
				return false;
			}
			return true;
		}

		private static void HandleClimbingMovement(Player player)
		{
			//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_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_0074: Unknown result type (might be due to invalid IL or missing references)
			//IL_0066: Unknown result type (might be due to invalid IL or missing references)
			//IL_006b: 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_00ae: 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_00bb: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bd: Unknown result type (might be due to invalid IL or missing references)
			//IL_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_0103: Unknown result type (might be due to invalid IL or missing references)
			//IL_0104: Unknown result type (might be due to invalid IL or missing references)
			//IL_0108: Unknown result type (might be due to invalid IL or missing references)
			//IL_010e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0115: 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_011f: 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_0169: Unknown result type (might be due to invalid IL or missing references)
			//IL_016e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0172: Unknown result type (might be due to invalid IL or missing references)
			//IL_0177: Unknown result type (might be due to invalid IL or missing references)
			//IL_0179: Unknown result type (might be due to invalid IL or missing references)
			//IL_017a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0181: 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_018b: Unknown result type (might be due to invalid IL or missing references)
			//IL_018d: 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_01a1: 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_0147: Unknown result type (might be due to invalid IL or missing references)
			//IL_014e: 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_015b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0160: Unknown result type (might be due to invalid IL or missing references)
			//IL_0165: Unknown result type (might be due to invalid IL or missing references)
			Rigidbody component = ((Component)player).GetComponent<Rigidbody>();
			if (!((Object)(object)component == (Object)null))
			{
				component.useGravity = false;
				Player_FixedUpdate_Patch.ResetFallCalculation(player);
				float axis = Input.GetAxis("Vertical");
				float axis2 = Input.GetAxis("Horizontal");
				Vector3 val = Vector3.zero;
				ClimbingState.ClimbingData orCreate = ClimbingState.GetOrCreate(player);
				Vector3 val2 = ((orCreate.surfaceNormal != Vector3.zero) ? orCreate.surfaceNormal : (-((Component)player).transform.forward));
				float num = CalculateSlopeSpeedFactor(val2);
				float num2 = Mathf.Lerp(1f, 3f, Mathf.Clamp01(orCreate.climbSkill / 100f));
				float num3 = num * num2;
				Vector3 val3 = ResolveClimbDirection(val2, ((Component)player).transform);
				Vector3 val4 = ResolveLateralDirection(val2, val3);
				if (Mathf.Abs(axis) > 0.1f && ((Vector3)(ref val3)).sqrMagnitude > 0.01f)
				{
					float num4 = ((axis > 0f) ? ClimbingConfig.CLIMB_SPEED_UP : ClimbingConfig.CLIMB_SPEED_DOWN);
					val += val3 * num4 * axis * num3;
				}
				if (Mathf.Abs(axis2) > 0.1f && ((Vector3)(ref val4)).sqrMagnitude > 0.01f)
				{
					val += val4 * ClimbingConfig.CLIMB_SPEED_DOWN * axis2 * num3;
				}
				Vector3 val5 = -val2;
				Vector3 normalized = ((Vector3)(ref val5)).normalized;
				val += normalized * 0.5f;
				ApplySurfaceRepulsion(player, val2, ref val);
				AlignWithSurface(player, val2);
				component.linearVelocity = val;
				float num5 = ResolveAnimationInput(axis, axis2);
				ClimbAnimationController.Update(player, num5, num3);
				ZNetView component2 = ((Component)player).GetComponent<ZNetView>();
				if ((Object)(object)component2 != (Object)null && component2.IsValid())
				{
					component2.GetZDO().Set("ClimbInput", num5);
				}
				ApplyClimbStaminaDrain(player, axis, axis2);
			}
		}

		private static float CalculateSlopeSpeedFactor(Vector3 surfaceNormal)
		{
			//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)
			float num = Vector3.Angle(Vector3.up, surfaceNormal);
			float num2 = Mathf.InverseLerp(90f, 10f, num);
			return Mathf.Clamp(Mathf.Lerp(1f, 1.4f, num2), 0.1f, 3f);
		}

		private static Vector3 ResolveClimbDirection(Vector3 surfaceNormal, Transform transform)
		{
			//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_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_000c: 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)
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0041: Unknown result type (might be due to invalid IL or missing references)
			//IL_0043: Unknown result type (might be due to invalid IL or missing references)
			//IL_0048: Unknown result type (might be due to invalid IL or missing references)
			//IL_004d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0066: 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_006b: Unknown result type (might be due to invalid IL or missing references)
			//IL_006e: Unknown result type (might be due to invalid IL or missing references)
			Vector3 val = Vector3.ProjectOnPlane(Vector3.up, surfaceNormal);
			if (((Vector3)(ref val)).sqrMagnitude < 0.01f)
			{
				val = Vector3.ProjectOnPlane(transform.forward, surfaceNormal);
			}
			if (((Vector3)(ref val)).sqrMagnitude < 0.01f)
			{
				val = Vector3.Cross(surfaceNormal, transform.right);
			}
			return (((Vector3)(ref val)).sqrMagnitude > 0.01f) ? ((Vector3)(ref val)).normalized : Vector3.forward;
		}

		private static Vector3 ResolveLateralDirection(Vector3 surfaceNormal, Vector3 climbDirection)
		{
			//IL_0001: 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_0003: Unknown result type (might be due to invalid IL or missing references)
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_001c: Unknown result type (might be due to invalid IL or missing references)
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			//IL_0040: 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_0045: 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)
			Vector3 val = Vector3.Cross(surfaceNormal, climbDirection);
			if (((Vector3)(ref val)).sqrMagnitude < 0.01f)
			{
				val = Vector3.Cross(surfaceNormal, Vector3.up);
			}
			return (((Vector3)(ref val)).sqrMagnitude > 0.01f) ? ((Vector3)(ref val)).normalized : Vector3.zero;
		}

		private static float ResolveAnimationInput(float forwardInput, float rightInput)
		{
			if (Mathf.Abs(forwardInput) > 0.05f)
			{
				return forwardInput;
			}
			return (Mathf.Abs(rightInput) > 0.1f) ? Mathf.Abs(rightInput) : 0f;
		}

		private static void ApplyClimbStaminaDrain(Player player, float forwardInput, float rightInput)
		{
			float sTAMINA_DRAIN_PER_SECOND = ClimbingConfig.STAMINA_DRAIN_PER_SECOND;
			if (!(sTAMINA_DRAIN_PER_SECOND <= 0f))
			{
				float num = Mathf.Clamp01(Mathf.Max(Mathf.Abs(forwardInput), Mathf.Abs(rightInput)));
				float num2 = ((num <= 0.05f) ? 0.1f : Mathf.Lerp(0.5f, 1f, num));
				((Character)player).UseStamina(num2 * sTAMINA_DRAIN_PER_SECOND * Time.deltaTime);
			}
		}

		private static void ApplySurfaceRepulsion(Player player, Vector3 surfaceNormal, ref Vector3 climbVelocity)
		{
			//IL_0001: 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_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0032: Unknown result type (might be due to invalid IL or missing references)
			//IL_0037: Unknown result type (might be due to invalid IL or missing references)
			//IL_003e: 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_0074: Unknown result type (might be due to invalid IL or missing references)
			//IL_0075: Unknown result type (might be due to invalid IL or missing references)
			//IL_0076: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c6: 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_00d0: Unknown result type (might be due to invalid IL or missing references)
			if (surfaceNormal == Vector3.zero)
			{
				return;
			}
			Vector3 val = ((Component)player).transform.position + Vector3.up * 1f;
			float num = 0.93f;
			float num2 = Vector3.Angle(Vector3.up, surfaceNormal);
			float num3 = Mathf.Clamp01(Mathf.InverseLerp(25f, 60f, num2));
			RaycastHit val2 = default(RaycastHit);
			if (!(num3 <= 0.001f) && Physics.Raycast(val, -surfaceNormal, ref val2, num, SurfaceLayerMask))
			{
				float num4 = 0.18f - ((RaycastHit)(ref val2)).distance;
				if (num4 > 0f)
				{
					climbVelocity += ((Vector3)(ref surfaceNormal)).normalized * (0.15f * num4 * num3);
				}
			}
		}

		private static void AlignWithSurface(Player player, Vector3 surfaceNormal)
		{
			//IL_0001: 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_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)
			//IL_0025: 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_0043: Unknown result type (might be due to invalid IL or missing references)
			//IL_003c: 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_0049: Unknown result type (might be due to invalid IL or missing references)
			//IL_004a: Unknown result type (might be due to invalid IL or missing references)
			//IL_004b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0050: Unknown result type (might be due to invalid IL or missing references)
			//IL_007d: Unknown result type (might be due to invalid IL or missing references)
			//IL_007e: Unknown result type (might be due to invalid IL or missing references)
			//IL_007f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0084: 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_008d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0066: Unknown result type (might be due to invalid IL or missing references)
			//IL_006b: 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_006e: 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_00a6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ad: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bb: 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_00cd: 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_00a4: Unknown result type (might be due to invalid IL or missing references)
			if (!(surfaceNormal == Vector3.zero))
			{
				Vector3 val = -((Vector3)(ref surfaceNormal)).normalized;
				Vector3 val2 = ((Mathf.Abs(Vector3.Dot(val, Vector3.up)) > 0.95f) ? Vector3.forward : Vector3.up);
				Vector3 val3 = Vector3.Cross(val2, val);
				if (((Vector3)(ref val3)).sqrMagnitude < 0.0001f)
				{
					val2 = Vector3.right;
					val3 = Vector3.Cross(val2, val);
				}
				((Vector3)(ref val3)).Normalize();
				Vector3 val4 = Vector3.Cross(val, val3);
				Vector3 val5 = ((Vector3)(ref val4)).normalized;
				if (((Vector3)(ref val5)).sqrMagnitude < 0.0001f)
				{
					val5 = val2;
				}
				Quaternion val6 = Quaternion.LookRotation(val, val5);
				((Component)player).transform.rotation = Quaternion.Slerp(((Component)player).transform.rotation, val6, Time.deltaTime * 10f);
			}
		}
	}
	[HarmonyPatch(typeof(Character), "ApplySlide")]
	internal class Character_ApplySlide_Patch
	{
		private static bool Prefix(Character __instance)
		{
			Player val = (Player)(object)((__instance is Player) ? __instance : null);
			if (val != null && ClimbingState.IsClimbing(val))
			{
				return false;
			}
			return true;
		}
	}
	[HarmonyPatch(typeof(Player), "OnDestroy")]
	internal class Player_OnDestroy_Patch
	{
		private static void Postfix(Player __instance)
		{
			ClimbingState.Cleanup(__instance);
			ClimbAnimationController.Cleanup(__instance);
		}
	}
	[HarmonyPatch(typeof(Humanoid), "StartAttack")]
	internal class Humanoid_StartAttack_Patch
	{
		private static bool Prefix(Humanoid __instance)
		{
			Player val = (Player)(object)((__instance is Player) ? __instance : null);
			if (val != null && ClimbingState.IsClimbing(val))
			{
				return false;
			}
			return true;
		}
	}
	[HarmonyPatch(typeof(Character), "Damage")]
	internal class Character_Damage_Patch
	{
		private static void Prefix(Character __instance, ref HitData hit)
		{
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0033: Invalid comparison between Unknown and I4
			//IL_005d: Unknown result type (might be due to invalid IL or missing references)
			if (hit == null)
			{
				return;
			}
			Player val = (Player)(object)((__instance is Player) ? __instance : null);
			if (val == null || !ClimbingState.IsClimbing(val))
			{
				return;
			}
			if ((int)hit.m_hitType == 3)
			{
				ClimbingState.ClimbingData orCreate = ClimbingState.GetOrCreate(val);
				if (Player_FixedUpdate_Patch.HasReliableClimbSurface(val, orCreate))
				{
					hit.m_damage = default(DamageTypes);
					hit.m_pushForce = 0f;
				}
			}
			else if (hit.m_pushForce > 5f)
			{
				ClimbingState.ClimbingData orCreate2 = ClimbingState.GetOrCreate(val);
				Player_FixedUpdate_Patch.StopClimbing(val, orCreate2);
			}
		}
	}
	public static class ClimbingState
	{
		public class ClimbingData
		{
			public bool isClimbing = false;

			public Vector3 surfaceNormal = Vector3.zero;

			public bool wasGravityEnabled = true;

			public bool toggleActive = false;

			public float climbSkill = 0f;

			public int validStartSurfaceFrames = 0;
		}

		private static Dictionary<Player, ClimbingData> climbingPlayers = new Dictionary<Player, ClimbingData>();

		public static ClimbingData GetOrCreate(Player player)
		{
			if (!climbingPlayers.TryGetValue(player, out var value))
			{
				value = new ClimbingData();
				climbingPlayers[player] = value;
			}
			return value;
		}

		public static bool IsClimbing(Player player)
		{
			ClimbingData value;
			return climbingPlayers.TryGetValue(player, out value) && value.isClimbing;
		}

		public static void Cleanup(Player player)
		{
			climbingPlayers.Remove(player);
		}
	}
	public static class ClimbSkillProgression
	{
		public const string SkillKey = "RotcehClimbSkill";

		public const string SkillLevelKey = "RotcehClimbSkillLevel";

		public const string SkillXpKey = "RotcehClimbSkillXp";

		public const float MaxSkill = 100f;

		private static readonly FieldInfo SkillLevelupFxField = AccessTools.Field(typeof(Player), "m_skillLevelupEffects") ?? AccessTools.Field(typeof(Player), "m_skillLevelUpEffects") ?? AccessTools.Field(typeof(Player), "m_levelupEffects");

		public static float GetSkill(Player player)
		{
			if ((Object)(object)player == (Object)null)
			{
				return 0f;
			}
			ReadProgress(player, out var level, out var xp);
			if (level >= 100)
			{
				return 100f;
			}
			float xpToNextLevel = GetXpToNextLevel(level);
			float num = ((xpToNextLevel > 0f) ? Mathf.Clamp01(xp / xpToNextLevel) : 0f);
			return Mathf.Clamp((float)level + num, 0f, 100f);
		}

		public static void SetSkill(Player player, float skill)
		{
			if (!((Object)(object)player == (Object)null))
			{
				skill = Mathf.Clamp(skill, 0f, 100f);
				int num = Mathf.FloorToInt(skill);
				float xp = 0f;
				if (num < 100)
				{
					float num2 = skill - (float)num;
					xp = num2 * GetXpToNextLevel(num);
				}
				WriteProgress(player, num, xp);
			}
		}

		public static void AddSkill(Player player, float deltaTime)
		{
			if ((Object)(object)player == (Object)null || deltaTime <= 0f)
			{
				return;
			}
			ReadProgress(player, out var level, out var xp);
			if (level >= 100)
			{
				return;
			}
			float num = ClimbingModPlugin.ClimbSkillXpPerSecond?.Value ?? 1.5f;
			float num2 = Mathf.Max(0f, num) * deltaTime;
			xp += num2;
			while (level < 100)
			{
				float xpToNextLevel = GetXpToNextLevel(level);
				if (xp < xpToNextLevel)
				{
					break;
				}
				xp -= xpToNextLevel;
				level++;
				ShowLevelUpFeedback(player, level);
				if (level >= 100)
				{
					level = 100;
					xp = 0f;
					break;
				}
			}
			WriteProgress(player, level, xp);
		}

		private static float GetXpToNextLevel(int level)
		{
			float num = ClimbingModPlugin.ClimbSkillBaseXpPerLevel?.Value ?? 100f;
			float num2 = ClimbingModPlugin.ClimbSkillXpIncreasePerLevel?.Value ?? 40f;
			return Mathf.Max(1f, num + Mathf.Max(0f, num2) * (float)Mathf.Clamp(level, 0, 100));
		}

		private static void ReadProgress(Player player, out int level, out float xp)
		{
			level = 0;
			xp = 0f;
			ZNetView component = ((Component)player).GetComponent<ZNetView>();
			if ((Object)(object)component == (Object)null || !component.IsValid())
			{
				return;
			}
			ZDO zDO = component.GetZDO();
			level = zDO.GetInt("RotcehClimbSkillLevel", -1);
			xp = zDO.GetFloat("RotcehClimbSkillXp", 0f);
			if (level < 0)
			{
				float num = Mathf.Clamp(zDO.GetFloat("RotcehClimbSkill", 0f), 0f, 100f);
				level = Mathf.FloorToInt(num);
				float num2 = num - (float)level;
				if (level >= 100)
				{
					level = 100;
					xp = 0f;
				}
				else
				{
					xp = num2 * GetXpToNextLevel(level);
				}
				zDO.Set("RotcehClimbSkillLevel", level);
				zDO.Set("RotcehClimbSkillXp", xp);
			}
			level = Mathf.Clamp(level, 0, 100);
			xp = Mathf.Max(0f, xp);
			if (level >= 100)
			{
				xp = 0f;
			}
		}

		private static void WriteProgress(Player player, int level, float xp)
		{
			ZNetView component = ((Component)player).GetComponent<ZNetView>();
			if (!((Object)(object)component == (Object)null) && component.IsValid())
			{
				level = Mathf.Clamp(level, 0, 100);
				xp = ((level >= 100) ? 0f : Mathf.Max(0f, xp));
				ZDO zDO = component.GetZDO();
				zDO.Set("RotcehClimbSkillLevel", level);
				zDO.Set("RotcehClimbSkillXp", xp);
				float num = level;
				if (level < 100)
				{
					float xpToNextLevel = GetXpToNextLevel(level);
					num += ((xpToNextLevel > 0f) ? Mathf.Clamp01(xp / xpToNextLevel) : 0f);
				}
				zDO.Set("RotcehClimbSkill", Mathf.Clamp(num, 0f, 100f));
			}
		}

		public static void ShowLevelUpFeedback(Player player, int level)
		{
			if (!((Object)(object)player == (Object)null) && !((Object)(object)player != (Object)(object)Player.m_localPlayer))
			{
				((Character)player).Message((MessageType)2, $"Climbing skill increased to {level}", 0, (Sprite)null);
				TryPlayNativeSkillLevelupFx(player);
			}
		}

		private static void TryPlayNativeSkillLevelupFx(Player player)
		{
			//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_006f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0074: Unknown result type (might be due to invalid IL or missing references)
			//IL_0079: Unknown result type (might be due to invalid IL or missing references)
			//IL_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_00a6: 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_00f6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ff: Unknown result type (might be due to invalid IL or missing references)
			//IL_013d: 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)
			if (SkillLevelupFxField == null)
			{
				return;
			}
			object value = SkillLevelupFxField.GetValue(player);
			if (value == null)
			{
				return;
			}
			MethodInfo methodInfo = AccessTools.Method(value.GetType(), "Create", (Type[])null, (Type[])null);
			if (!(methodInfo == null))
			{
				Vector3 val = ((Component)player).transform.position + Vector3.up * 1.6f;
				Quaternion rotation = ((Component)player).transform.rotation;
				ParameterInfo[] parameters = methodInfo.GetParameters();
				if (parameters.Length == 5)
				{
					methodInfo.Invoke(value, new object[5]
					{
						val,
						rotation,
						((Component)player).transform,
						1f,
						-1
					});
				}
				else if (parameters.Length == 4)
				{
					methodInfo.Invoke(value, new object[4]
					{
						val,
						rotation,
						((Component)player).transform,
						1f
					});
				}
				else if (parameters.Length == 3)
				{
					methodInfo.Invoke(value, new object[3]
					{
						val,
						rotation,
						((Component)player).transform
					});
				}
			}
		}

		public static float GetSpeedMultiplier(float skill)
		{
			return Mathf.Lerp(1f, 3f, Mathf.Clamp01(skill / 100f));
		}
	}
}