Decompiled source of ClimbingMod v1.0.0

Valheim-Climbing-Mod.dll

Decompiled 3 hours 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.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")]
[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;
		}

		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_0063: Unknown result type (might be due to invalid IL or missing references)
			//IL_0068: Unknown result type (might be due to invalid IL or missing references)
			//IL_0071: 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_0085: Unknown result type (might be due to invalid IL or missing references)
			//IL_008b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0090: Unknown result type (might be due to invalid IL or missing references)
			//IL_0099: Unknown result type (might be due to invalid IL or missing references)
			//IL_009b: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a4: 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_00b1: 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_00bc: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d6: 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_00e2: 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_010a: Unknown result type (might be due to invalid IL or missing references)
			//IL_010b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0111: Unknown result type (might be due to invalid IL or missing references)
			//IL_0112: 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_011a: 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);
			PlayableOutputExtensions.SetSourcePlayable<AnimationPlayableOutput, AnimationMixerPlayable>(AnimationPlayableOutput.Create(val, "ClimbOutput", animator), 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_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			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_009a: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ab: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bc: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c9: Unknown result type (might be due to invalid IL or missing references)
			//IL_0086: Unknown result type (might be due to invalid IL or missing references)
			//IL_0038: Unknown result type (might be due to invalid IL or missing references)
			//IL_0049: Unknown result type (might be due to invalid IL or missing references)
			//IL_005a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0067: 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)
			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 = 10f;

		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.6f;

		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<float> ClimbSpeedUp;

		public static ConfigEntry<float> ClimbSpeedDown;

		public static ConfigEntry<float> StaminaDrainPerSecond;

		public static ConfigEntry<bool> ToggleClimbKey;

		private void Awake()
		{
			//IL_00b5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cf: Unknown result type (might be due to invalid IL or missing references)
			ClimbKey = ((BaseUnityPlugin)this).Config.Bind<KeyCode>("General", "ClimbKey", (KeyCode)308, "Key to trigger climbing (default: LeftAlt)");
			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).");
			new Harmony("com.rotceh.valheimclimbingmod").PatchAll();
			((BaseUnityPlugin)this).Logger.LogInfo((object)$"Valheim Climbing Mod loaded. Climb key: {ClimbKey.Value}");
			ClimbAnimationController.Initialize(((BaseUnityPlugin)this).Logger);
		}
	}
	[HarmonyPatch(typeof(Player), "FixedUpdate")]
	public class Player_FixedUpdate_Patch
	{
		[CompilerGenerated]
		private sealed class <EnumerateProbeDirections>d__12 : IEnumerable<Vector3>, IEnumerable, IEnumerator<Vector3>, IDisposable, IEnumerator
		{
			private int <>1__state;

			private Vector3 <>2__current;

			private int <>l__initialThreadId;

			private Vector3 preferredNormal;

			public Vector3 <>3__preferredNormal;

			private Player player;

			public Player <>3__player;

			private Transform <t>5__2;

			private Vector3[] <>7__wrap2;

			private int <>7__wrap3;

			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__12(int <>1__state)
			{
				this.<>1__state = <>1__state;
				<>l__initialThreadId = Environment.CurrentManagedThreadId;
			}

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

			private bool MoveNext()
			{
				//IL_003b: Unknown result type (might be due to invalid IL or missing references)
				//IL_0040: Unknown result type (might be due to invalid IL or missing references)
				//IL_00ab: Unknown result type (might be due to invalid IL or missing references)
				//IL_00b0: Unknown result type (might be due to invalid IL or missing references)
				//IL_00b5: Unknown result type (might be due to invalid IL or missing references)
				//IL_00d1: Unknown result type (might be due to invalid IL or missing references)
				//IL_00d6: Unknown result type (might be due to invalid IL or missing references)
				//IL_00f2: Unknown result type (might be due to invalid IL or missing references)
				//IL_00f7: Unknown result type (might be due to invalid IL or missing references)
				//IL_00fc: Unknown result type (might be due to invalid IL or missing references)
				//IL_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_0139: 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_0143: 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_008f: Unknown result type (might be due to invalid IL or missing references)
				//IL_0053: Unknown result type (might be due to invalid IL or missing references)
				//IL_0058: 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_0178: Unknown result type (might be due to invalid IL or missing references)
				//IL_017d: Unknown result type (might be due to invalid IL or missing references)
				//IL_017f: Unknown result type (might be due to invalid IL or missing references)
				//IL_0180: 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_0072;
				case 1:
					<>1__state = -1;
					goto IL_0072;
				case 2:
					<>1__state = -1;
					<>2__current = -<t>5__2.forward;
					<>1__state = 3;
					return true;
				case 3:
					<>1__state = -1;
					<>2__current = <t>5__2.up;
					<>1__state = 4;
					return true;
				case 4:
					<>1__state = -1;
					<>2__current = -<t>5__2.up;
					<>1__state = 5;
					return true;
				case 5:
					<>1__state = -1;
					<>2__current = <t>5__2.right;
					<>1__state = 6;
					return true;
				case 6:
					<>1__state = -1;
					<>2__current = -<t>5__2.right;
					<>1__state = 7;
					return true;
				case 7:
					<>1__state = -1;
					<>7__wrap2 = WorldProbeDirections;
					<>7__wrap3 = 0;
					break;
				case 8:
					{
						<>1__state = -1;
						<>7__wrap3++;
						break;
					}
					IL_0072:
					<t>5__2 = ((Component)player).transform;
					<>2__current = <t>5__2.forward;
					<>1__state = 2;
					return true;
				}
				if (<>7__wrap3 < <>7__wrap2.Length)
				{
					Vector3 val = <>7__wrap2[<>7__wrap3];
					<>2__current = val;
					<>1__state = 8;
					return true;
				}
				<>7__wrap2 = 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__12 <EnumerateProbeDirections>d__;
				if (<>1__state == -2 && <>l__initialThreadId == Environment.CurrentManagedThreadId)
				{
					<>1__state = 0;
					<EnumerateProbeDirections>d__ = this;
				}
				else
				{
					<EnumerateProbeDirections>d__ = new <EnumerateProbeDirections>d__12(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 static readonly float[] ProbeHeights = new float[3] { 1.2f, 0.7f, 0.2f };

		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_00a2: 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_00f2: 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_0100: 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);
				bool flag = ClimbingModPlugin.ToggleClimbKey?.Value ?? false;
				bool flag2 = false;
				if (CallTakeInput(__instance))
				{
					if (flag)
					{
						if (Input.GetKeyDown(ClimbingModPlugin.ClimbKey.Value))
						{
							orCreate.toggleActive = !orCreate.toggleActive;
							if (!orCreate.toggleActive && orCreate.isClimbing)
							{
								StopClimbing(__instance, orCreate);
							}
						}
						flag2 = orCreate.toggleActive;
					}
					else
					{
						flag2 = Input.GetKey(ClimbingModPlugin.ClimbKey.Value);
						if (!flag2)
						{
							orCreate.toggleActive = false;
						}
					}
				}
				else
				{
					flag2 = orCreate.toggleActive;
				}
				Vector3 normal;
				if (!orCreate.isClimbing)
				{
					if (flag2)
					{
						TryStartClimbing(__instance, orCreate);
					}
				}
				else if (!flag2)
				{
					StopClimbing(__instance, orCreate);
				}
				else if (!PlayerHasClimbStamina(__instance))
				{
					StopClimbing(__instance, orCreate);
				}
				else if (TryGetSurfaceNormal(__instance, out normal, orCreate.surfaceNormal))
				{
					orCreate.surfaceNormal = normal;
				}
				else
				{
					StopClimbing(__instance, orCreate);
				}
			}
		}

		private static void HandleRemotePlayer(Player player)
		{
			ZNetView component = ((Component)player).GetComponent<ZNetView>();
			if (!((Object)(object)component == (Object)null) && component.IsValid())
			{
				bool @bool = component.GetZDO().GetBool("IsClimbing", false);
				bool flag = ClimbAnimationController.IsActive(player);
				if (@bool && !flag)
				{
					ClimbAnimationController.Begin(player);
				}
				else if (!@bool && flag)
				{
					ClimbAnimationController.End(player);
				}
				if (@bool)
				{
					ClimbAnimationController.Update(player, 0f, 1f);
				}
			}
		}

		private static void TryStartClimbing(Player player, ClimbingState.ClimbingData climbData)
		{
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			if (PlayerHasClimbStamina(player) && TryGetSurfaceNormal(player, out var normal))
			{
				StartClimbing(player, climbData, normal);
			}
		}

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

		private static void StartClimbing(Player player, ClimbingState.ClimbingData climbData, Vector3 surfaceNormal)
		{
			//IL_0008: 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_005b: 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)
			climbData.isClimbing = true;
			climbData.surfaceNormal = surfaceNormal;
			ZNetView component = ((Component)player).GetComponent<ZNetView>();
			if ((Object)(object)component != (Object)null && component.IsValid())
			{
				component.GetZDO().Set("IsClimbing", true);
			}
			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 StopClimbing(Player player, ClimbingState.ClimbingData climbData)
		{
			climbData.isClimbing = false;
			ZNetView component = ((Component)player).GetComponent<ZNetView>();
			if ((Object)(object)component != (Object)null && component.IsValid())
			{
				component.GetZDO().Set("IsClimbing", false);
			}
			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_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_0028: Unknown result type (might be due to invalid IL or missing references)
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0032: 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_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_0046: 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_004d: 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_0065: 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_008d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0092: 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 >= 10f && num3 <= 240f)
						{
							normal = ((RaycastHit)(ref val2)).normal;
							return true;
						}
					}
				}
			}
			normal = Vector3.zero;
			return false;
		}

		[IteratorStateMachine(typeof(<EnumerateProbeDirections>d__12))]
		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__12(-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_002e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0033: Unknown result type (might be due to invalid IL or missing references)
			//IL_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_0063: Unknown result type (might be due to invalid IL or missing references)
			//IL_0055: Unknown result type (might be due to invalid IL or missing references)
			//IL_005a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0068: Unknown result type (might be due to invalid IL or missing references)
			//IL_006a: 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_007b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0080: Unknown result type (might be due to invalid IL or missing references)
			//IL_0082: 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_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_010f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0111: Unknown result type (might be due to invalid IL or missing references)
			//IL_0116: Unknown result type (might be due to invalid IL or missing references)
			//IL_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_0121: Unknown result type (might be due to invalid IL or missing references)
			//IL_0122: Unknown result type (might be due to invalid IL or missing references)
			//IL_0129: Unknown result type (might be due to invalid IL or missing references)
			//IL_012e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0133: Unknown result type (might be due to invalid IL or missing references)
			//IL_0135: Unknown result type (might be due to invalid IL or missing references)
			//IL_013f: 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_00f6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fe: 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_0109: 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_00be: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bf: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d0: 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_00da: 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;
				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);
				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 num2 = ((axis > 0f) ? ClimbingConfig.CLIMB_SPEED_UP : ClimbingConfig.CLIMB_SPEED_DOWN);
					val += val3 * num2 * axis * num;
				}
				if (Mathf.Abs(axis2) > 0.1f && ((Vector3)(ref val4)).sqrMagnitude > 0.01f)
				{
					val += val4 * ClimbingConfig.CLIMB_SPEED_DOWN * axis2;
				}
				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 verticalInput = ResolveAnimationInput(axis, axis2);
				ClimbAnimationController.Update(player, verticalInput, num);
				ApplyClimbStaminaDrain(player, axis, axis2);
			}
		}

		private static float CalculateSlopeSpeedFactor(Vector3 surfaceNormal)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0005: 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.6f, num2), 0.1f, 3f);
		}

		private static Vector3 ResolveClimbDirection(Vector3 surfaceNormal, Transform transform)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//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)
			//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_0035: 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_003c: 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_0058: 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)
			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);
			}
			if (!(((Vector3)(ref val)).sqrMagnitude > 0.01f))
			{
				return Vector3.forward;
			}
			return ((Vector3)(ref val)).normalized;
		}

		private static Vector3 ResolveLateralDirection(Vector3 surfaceNormal, Vector3 climbDirection)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_0016: 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_0021: Unknown result type (might be due to invalid IL or missing references)
			//IL_0038: Unknown result type (might be due to invalid IL or missing references)
			//IL_0030: 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);
			}
			if (!(((Vector3)(ref val)).sqrMagnitude > 0.01f))
			{
				return Vector3.zero;
			}
			return ((Vector3)(ref val)).normalized;
		}

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

		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_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			//IL_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)
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			//IL_0039: Unknown result type (might be due to invalid IL or missing references)
			//IL_005f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0060: Unknown result type (might be due to invalid IL or missing references)
			//IL_0061: Unknown result type (might be due to invalid IL or missing references)
			//IL_008f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0096: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a5: Unknown result type (might be due to invalid IL or missing references)
			//IL_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)
			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_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: 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_0039: 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_003e: Unknown result type (might be due to invalid IL or missing references)
			//IL_003f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0040: Unknown result type (might be due to invalid IL or missing references)
			//IL_0041: Unknown result type (might be due to invalid IL or missing references)
			//IL_0046: 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_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_0071: 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_007a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0055: Unknown result type (might be due to invalid IL or missing references)
			//IL_005a: 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_005c: 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_0062: 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_008c: 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_0092: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b2: 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_008a: 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_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0020: Invalid comparison between Unknown and I4
			//IL_0029: 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))
			{
				if ((int)hit.m_hitType == 3)
				{
					hit.m_damage = default(DamageTypes);
					hit.m_pushForce = 0f;
				}
				else if (hit.m_pushForce > 5f)
				{
					ClimbingState.ClimbingData orCreate = ClimbingState.GetOrCreate(val);
					Player_FixedUpdate_Patch.StopClimbing(val, orCreate);
				}
			}
		}
	}
	public static class ClimbingState
	{
		public class ClimbingData
		{
			public bool isClimbing;

			public Vector3 surfaceNormal = Vector3.zero;

			public bool wasGravityEnabled = true;

			public bool toggleActive;
		}

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

		public static ClimbingData GetOrCreate(Player player)
		{
			if (!climbingPlayers.ContainsKey(player))
			{
				climbingPlayers[player] = new ClimbingData();
			}
			return climbingPlayers[player];
		}

		public static bool IsClimbing(Player player)
		{
			if (climbingPlayers.ContainsKey(player))
			{
				return climbingPlayers[player].isClimbing;
			}
			return false;
		}

		public static void Cleanup(Player player)
		{
			climbingPlayers.Remove(player);
		}
	}
}