Decompiled source of Useable Rescue Hooks v2.0.1

tony4twentys-Useable Rescue Hooks.dll

Decompiled a day ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using System.Reflection.Emit;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Configuration;
using HarmonyLib;
using Photon.Pun;
using TMPro;
using UnityEngine;
using UnityEngine.UI;
using Zorro.Core;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: AssemblyTitle("Useable Rescue Hooks")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("Useable Rescue Hooks")]
[assembly: AssemblyCopyright("Copyright ©  2025")]
[assembly: AssemblyTrademark("")]
[assembly: ComVisible(false)]
[assembly: Guid("9c6253a4-b64d-451f-a3fc-1d2c61bf4882")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")]
[assembly: AssemblyVersion("1.0.0.0")]
namespace UseableRescueHooks;

[BepInPlugin("tony4twentys.Useable_Rescue_Hooks", "Useable Rescue Hooks", "2.0.1")]
public class UseableRescueHooksPlugin : BaseUnityPlugin
{
	[HarmonyPatch(typeof(RescueHook), "RPCA_LetGo")]
	private static class RescueHook_RPCA_LetGo_Remove_Postfix
	{
		private static void Postfix(RescueHook __instance)
		{
			//IL_0098: Unknown result type (might be due to invalid IL or missing references)
			//IL_0091: Unknown result type (might be due to invalid IL or missing references)
			//IL_009a: 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)
			Item val = (Object.op_Implicit((Object)(object)__instance) ? ((ItemComponent)__instance).item : null);
			if ((Object)(object)val != (Object)null && (Object)(object)val.holderCharacter == (Object)(object)__instance.playerHoldingItem)
			{
				ConsumeHookFromInventory_Held(val, "RPCA_LetGo");
				return;
			}
			Character val2 = (((Object)(object)__instance != (Object)null) ? __instance.playerHoldingItem : null);
			if ((Object)(object)val2 != (Object)null && _lastEquippedHook.TryGetValue(val2, out var value) && Object.op_Implicit((Object)(object)value))
			{
				Optionable<byte> value2;
				Optionable<byte> preferredSlot = (_capturedSlotOnEquip.TryGetValue(val2, out value2) ? value2 : Optionable<byte>.None);
				TryRemoveFromInventory(value, preferredSlot, "RPCA_LetGo (stashed)", allowScan: true);
			}
		}
	}

	[HarmonyPatch(typeof(RescueHook), "RPCA_RescueCharacter")]
	private static class RescueHook_RPCA_RescueCharacter_NoRemove_Postfix
	{
		private static void Postfix(RescueHook __instance)
		{
		}
	}

	[HarmonyPatch(typeof(RescueHook), "OnPrimaryFinishedCast")]
	private static class RescueHook_OnPrimaryFinishedCast_Guard
	{
		private static bool Prefix(RescueHook __instance)
		{
			return FireGuardPrefix(__instance);
		}
	}

	[HarmonyPatch(typeof(RescueHook), "FixedUpdate")]
	private static class RescueHook_FixedUpdate_Transpiler
	{
		[CompilerGenerated]
		private sealed class <Transpiler>d__3 : IEnumerable<CodeInstruction>, IEnumerable, IEnumerator<CodeInstruction>, IDisposable, IEnumerator
		{
			private int <>1__state;

			private CodeInstruction <>2__current;

			private int <>l__initialThreadId;

			private IEnumerable<CodeInstruction> instructions;

			public IEnumerable<CodeInstruction> <>3__instructions;

			private float <lastFloat>5__1;

			private IEnumerator<CodeInstruction> <>s__2;

			private CodeInstruction <ci>5__3;

			CodeInstruction IEnumerator<CodeInstruction>.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			object IEnumerator.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

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

			[DebuggerHidden]
			void IDisposable.Dispose()
			{
				int num = <>1__state;
				if (num == -3 || (uint)(num - 1) <= 2u)
				{
					try
					{
					}
					finally
					{
						<>m__Finally1();
					}
				}
				<>s__2 = null;
				<ci>5__3 = null;
				<>1__state = -2;
			}

			private bool MoveNext()
			{
				//IL_0185: Unknown result type (might be due to invalid IL or missing references)
				//IL_018f: Expected O, but got Unknown
				//IL_0221: Unknown result type (might be due to invalid IL or missing references)
				//IL_022b: Expected O, but got Unknown
				try
				{
					switch (<>1__state)
					{
					default:
						return false;
					case 0:
						<>1__state = -1;
						<lastFloat>5__1 = float.NaN;
						<>s__2 = instructions.GetEnumerator();
						<>1__state = -3;
						break;
					case 1:
						<>1__state = -3;
						break;
					case 2:
						<>1__state = -3;
						break;
					case 3:
						<>1__state = -3;
						<ci>5__3 = null;
						break;
					}
					if (<>s__2.MoveNext())
					{
						<ci>5__3 = <>s__2.Current;
						if (<ci>5__3.opcode == OpCodes.Ldc_R4 && <ci>5__3.operand is float)
						{
							<lastFloat>5__1 = (float)<ci>5__3.operand;
						}
						else if (<ci>5__3.opcode == OpCodes.Ldc_R8 && <ci>5__3.operand is double)
						{
							<lastFloat>5__1 = (float)(double)<ci>5__3.operand;
						}
						if (<ci>5__3.opcode == OpCodes.Callvirt && <ci>5__3.operand is MethodInfo && ((MethodInfo)<ci>5__3.operand).Name == "Fall" && ((MethodInfo)<ci>5__3.operand).GetParameters().Length == 2)
						{
							<>2__current = new CodeInstruction(OpCodes.Call, (object)GuardedFallMI);
							<>1__state = 1;
							return true;
						}
						if ((<ci>5__3.opcode == OpCodes.Call || <ci>5__3.opcode == OpCodes.Callvirt) && object.Equals(<ci>5__3.operand, RPCA_LetGoMI) && Mathf.Abs(<lastFloat>5__1 - 0.5f) < 0.0001f)
						{
							<>2__current = new CodeInstruction(OpCodes.Call, (object)GuardLetGoMI);
							<>1__state = 2;
							return true;
						}
						<>2__current = <ci>5__3;
						<>1__state = 3;
						return true;
					}
					<>m__Finally1();
					<>s__2 = null;
					return false;
				}
				catch
				{
					//try-fault
					((IDisposable)this).Dispose();
					throw;
				}
			}

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

			private void <>m__Finally1()
			{
				<>1__state = -1;
				if (<>s__2 != null)
				{
					<>s__2.Dispose();
				}
			}

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

			[DebuggerHidden]
			IEnumerator<CodeInstruction> IEnumerable<CodeInstruction>.GetEnumerator()
			{
				<Transpiler>d__3 <Transpiler>d__;
				if (<>1__state == -2 && <>l__initialThreadId == Environment.CurrentManagedThreadId)
				{
					<>1__state = 0;
					<Transpiler>d__ = this;
				}
				else
				{
					<Transpiler>d__ = new <Transpiler>d__3(0);
				}
				<Transpiler>d__.instructions = <>3__instructions;
				return <Transpiler>d__;
			}

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

		private static readonly MethodInfo GuardedFallMI = AccessTools.Method(typeof(UseableRescueHooksPlugin), "GuardedFall", (Type[])null, (Type[])null);

		private static readonly MethodInfo GuardLetGoMI = AccessTools.Method(typeof(UseableRescueHooksPlugin), "GuardLetGoWallOnly", (Type[])null, (Type[])null);

		private static readonly MethodInfo RPCA_LetGoMI = AccessTools.Method(typeof(RescueHook), "RPCA_LetGo", (Type[])null, (Type[])null);

		[IteratorStateMachine(typeof(<Transpiler>d__3))]
		private static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instructions)
		{
			//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
			return new <Transpiler>d__3(-2)
			{
				<>3__instructions = instructions
			};
		}
	}

	[HarmonyPatch(typeof(RescueHook), "FixedUpdate")]
	[HarmonyPriority(800)]
	private static class RescueHook_FixedUpdate_ModePrefix
	{
		private static void Prefix(RescueHook __instance)
		{
			if (f_isPulling.Invoke(__instance))
			{
				_activeRagdoll = _modeAutoRelease;
				_activeAutoLetGo = _modeAutoRelease;
				return;
			}
			_activeRagdoll = false;
			_activeAutoLetGo = false;
			_pullStartPos.Remove(__instance);
			_pullStartTime.Remove(__instance);
			_reelUntil.Remove(__instance);
			_reelOrigHang.Remove(__instance);
			Character playerHoldingItem = __instance.playerHoldingItem;
			if ((Object)(object)playerHoldingItem != (Object)null && _hangNoFall.Remove(playerHoldingItem))
			{
				StartNoFallGrace(playerHoldingItem, 2f);
			}
		}
	}

	[HarmonyPatch(typeof(RescueHook), "FixedUpdate")]
	private static class RescueHook_FixedUpdate_ZeroLaunch_Patch
	{
		private static readonly Dictionary<RescueHook, float> _launchRestore = new Dictionary<RescueHook, float>();

		private static void Prefix(RescueHook __instance)
		{
			//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_00ac: 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_007d: Unknown result type (might be due to invalid IL or missing references)
			if (!f_isPulling.Invoke(__instance) || (Object)(object)f_targetPlayer.Invoke(__instance) != (Object)null || _activeAutoLetGo)
			{
				return;
			}
			Character playerHoldingItem = __instance.playerHoldingItem;
			if ((Object)(object)playerHoldingItem == (Object)null)
			{
				return;
			}
			if (!_pullStartPos.ContainsKey(__instance))
			{
				_pullStartPos[__instance] = playerHoldingItem.Center;
				_pullStartTime[__instance] = Time.time;
			}
			Vector3 val = f_targetPos.Invoke(__instance);
			float num = Vector3.Distance(playerHoldingItem.Center, val);
			float num2 = Mathf.Max(0f, GetHang(__instance));
			float num3 = 5f;
			float num4 = num2 + num3;
			float value;
			bool flag = _reelUntil.TryGetValue(__instance, out value) && Time.time <= value;
			if (flag)
			{
				float num5 = Mathf.Max(0f, GetHang(__instance));
				float v = Mathf.MoveTowards(num5, 0.2f, 30f * Time.fixedDeltaTime);
				SetHang(__instance, v);
				if (!_launchRestore.ContainsKey(__instance))
				{
					_launchRestore[__instance] = f_launchForce.Invoke(__instance);
				}
				f_launchForce.Invoke(__instance) = _launchRestore[__instance];
				num2 = Mathf.Max(0f, GetHang(__instance));
				num4 = num2 + num3;
				if (num <= 0.25f)
				{
					_reelUntil.Remove(__instance);
					flag = false;
				}
			}
			else if (_reelUntil.ContainsKey(__instance))
			{
				_reelUntil.Remove(__instance);
			}
			if (num > num4)
			{
				if (!flag)
				{
					if (_hangNoFall.Remove(playerHoldingItem))
					{
						StartNoFallGrace(playerHoldingItem, 2f);
					}
					return;
				}
				if (!_launchRestore.ContainsKey(__instance))
				{
					_launchRestore[__instance] = f_launchForce.Invoke(__instance);
				}
				f_launchForce.Invoke(__instance) = _launchRestore[__instance];
				playerHoldingItem.refs.movement.ApplyExtraDrag(0.97f, true);
			}
			if (!_launchRestore.ContainsKey(__instance))
			{
				_launchRestore[__instance] = f_launchForce.Invoke(__instance);
			}
			float num6 = _launchRestore[__instance];
			if (num <= num2)
			{
				_hangNoFall.Add(playerHoldingItem);
				if (!_reelUntil.TryGetValue(__instance, out value) || !(Time.time <= value))
				{
					f_launchForce.Invoke(__instance) = 0f;
				}
			}
			else
			{
				float num7 = Mathf.InverseLerp(num2, num4, num);
				float num8 = num7 * num7 * (3f - 2f * num7);
				f_launchForce.Invoke(__instance) = num6 * num8;
				playerHoldingItem.refs.movement.ApplyExtraDrag(0.97f, true);
			}
		}

		private static void Postfix(RescueHook __instance)
		{
			//IL_008b: 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)
			if (!_launchRestore.TryGetValue(__instance, out var value))
			{
				return;
			}
			Character playerHoldingItem = __instance.playerHoldingItem;
			if ((Object)(object)playerHoldingItem == (Object)null || _activeAutoLetGo || !f_isPulling.Invoke(__instance) || (Object)(object)f_targetPlayer.Invoke(__instance) != (Object)null)
			{
				f_launchForce.Invoke(__instance) = value;
				_launchRestore.Remove(__instance);
				_reelUntil.Remove(__instance);
				_reelOrigHang.Remove(__instance);
				return;
			}
			float num = Vector3.Distance(playerHoldingItem.Center, f_targetPos.Invoke(__instance));
			float num2 = Mathf.Max(0f, GetHang(__instance));
			float num3 = num2 + 5f;
			if (num > num3)
			{
				f_launchForce.Invoke(__instance) = value;
				_launchRestore.Remove(__instance);
				if (_hangNoFall.Remove(playerHoldingItem))
				{
					StartNoFallGrace(playerHoldingItem, 2f);
				}
			}
		}
	}

	[HarmonyPatch(typeof(RescueHook), "Update")]
	private static class RescueHook_Update_Patch
	{
		private static void Postfix(RescueHook __instance)
		{
			//IL_003c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0192: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f3: Unknown result type (might be due to invalid IL or missing references)
			Character val = (((Object)(object)((ItemComponent)__instance).item != (Object)null) ? ((ItemComponent)__instance).item.holderCharacter : null);
			if ((Object)(object)val == (Object)null || !val.IsLocal)
			{
				return;
			}
			if (Input.GetKeyDown(ModeToggleKey))
			{
				_modeAutoRelease = !_modeAutoRelease;
				Notifier.ShowMode(_modeAutoRelease);
			}
			if (Input.GetMouseButtonDown(0) && f_isPulling.Invoke(__instance) && (Object)(object)f_targetPlayer.Invoke(__instance) == (Object)null)
			{
				_reelUntil[__instance] = Time.time + 0.65f;
				float num = Mathf.Max(0f, GetHang(__instance));
				if (!_reelOrigHang.ContainsKey(__instance))
				{
					_reelOrigHang[__instance] = num;
				}
				_pullStartPos[__instance] = val.Center;
				_pullStartTime[__instance] = Time.time;
				SetHang(__instance, Mathf.Max(0.2f, num - 1f));
			}
			float axis = Input.GetAxis("Mouse ScrollWheel");
			if (Mathf.Abs(axis) > 0.0001f && !_activeAutoLetGo && f_isPulling.Invoke(__instance) && (Object)(object)f_targetPlayer.Invoke(__instance) == (Object)null)
			{
				float hang = GetHang(__instance);
				float v = hang + (0f - axis) * 3f;
				SetHang(__instance, v);
			}
			if (Input.GetKeyDown(ManualLetGoKey) && f_isPulling.Invoke(__instance) && !((Object)(object)f_targetPlayer.Invoke(__instance) != (Object)null) && !_activeAutoLetGo)
			{
				SetHang(__instance, 2f);
				DoLetGo(__instance);
			}
		}
	}

	[HarmonyPatch(typeof(CharacterData), "set_currentItem")]
	private static class CharacterData_set_currentItem_Patch
	{
		private static void Postfix(CharacterData __instance, Item value)
		{
			//IL_01b9: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b2: Unknown result type (might be due to invalid IL or missing references)
			//IL_01bb: Unknown result type (might be due to invalid IL or missing references)
			//IL_01bf: 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)
			//IL_00bc: Unknown result type (might be due to invalid IL or missing references)
			Character val = f_cd_character.Invoke(__instance);
			if ((Object)(object)val == (Object)null || !val.IsLocal)
			{
				return;
			}
			RescueHook val2 = (((Object)(object)value != (Object)null) ? ((Component)value).GetComponent<RescueHook>() : null);
			if ((Object)(object)val2 != (Object)null)
			{
				_modeAutoRelease = false;
				SetHang(val2, 2f);
				Notifier.ShowMode(autoRelease: false);
				_lastEquippedHook[val] = ((ItemComponent)val2).item;
				CharacterItems val3 = ((val.refs != null) ? val.refs.items : null);
				if ((Object)(object)val3 != (Object)null && val3.currentSelectedSlot.IsSome)
				{
					_capturedSlotOnEquip[val] = val3.currentSelectedSlot;
				}
				else
				{
					_capturedSlotOnEquip[val] = Optionable<byte>.None;
				}
				float num = f_range.Invoke(val2);
				if (num > 40f)
				{
					f_range.Invoke(val2) = 40f;
				}
				return;
			}
			Notifier.Hide();
			bool flag = false;
			if (_hangNoFall.Remove(val))
			{
				StartNoFallGrace(val, 2f);
				flag = true;
			}
			bool flag2 = false;
			float num2 = 999f;
			try
			{
				flag2 = __instance.isClimbingAnything;
			}
			catch
			{
			}
			try
			{
				num2 = __instance.sinceStartClimb;
			}
			catch
			{
			}
			bool flag3 = num2 < 0.35f;
			if (_lastEquippedHook.TryGetValue(val, out var value2) && Object.op_Implicit((Object)(object)value2) && (WasHangingRecently(val) || flag || flag2 || flag3))
			{
				Optionable<byte> value3;
				Optionable<byte> preferredSlot = (_capturedSlotOnEquip.TryGetValue(val, out value3) ? value3 : Optionable<byte>.None);
				TryRemoveFromInventory(value2, preferredSlot, "Unequip during hang→climb", allowScan: true);
			}
			_lastEquippedHook.Remove(val);
			_capturedSlotOnEquip.Remove(val);
		}
	}

	[HarmonyPatch(typeof(CharacterMovement), "CheckFallDamage")]
	private static class CharacterMovement_CheckFallDamage_Patch
	{
		private static bool Prefix(CharacterMovement __instance)
		{
			Character val = (((Object)(object)__instance != (Object)null) ? ((Component)__instance).GetComponent<Character>() : null);
			if ((Object)(object)val != (Object)null && IsNoFallActive(val))
			{
				return false;
			}
			return true;
		}
	}

	[HarmonyPatch(typeof(CharacterItems), "DoDropping")]
	private static class CharacterItems_DoDropping_BlockDuringRescueHook
	{
		private static bool Prefix(CharacterItems __instance)
		{
			try
			{
				if ((Object)(object)__instance == (Object)null)
				{
					return true;
				}
				Character val = f_ci_character.Invoke(__instance);
				if ((Object)(object)val == (Object)null || !val.IsLocal)
				{
					return true;
				}
				Item val2 = (((Object)(object)val.data != (Object)null) ? val.data.currentItem : null);
				if ((Object)(object)val2 == (Object)null)
				{
					return true;
				}
				RescueHook component = ((Component)val2).GetComponent<RescueHook>();
				if ((Object)(object)component == (Object)null)
				{
					return true;
				}
				bool flag = f_isPulling.Invoke(component);
				Character val3 = f_targetPlayer.Invoke(component);
				if (flag && (Object)(object)val3 == (Object)null)
				{
					f_ci_throwChargeLevel.Invoke(__instance) = 0f;
					return false;
				}
				return true;
			}
			catch (Exception ex)
			{
				LogCritical("[URH] DoDropping Prefix exception: " + ex);
				return true;
			}
		}
	}

	[HarmonyPatch(typeof(CharacterItems), "DoSwitching")]
	private static class CharacterItems_DoSwitching_BlockDuringRescueHook
	{
		private static bool Prefix(CharacterItems __instance)
		{
			try
			{
				if ((Object)(object)__instance == (Object)null)
				{
					return true;
				}
				Character val = f_ci_character.Invoke(__instance);
				if ((Object)(object)val == (Object)null || !val.IsLocal)
				{
					return true;
				}
				Item val2 = (((Object)(object)val.data != (Object)null) ? val.data.currentItem : null);
				if ((Object)(object)val2 == (Object)null)
				{
					return true;
				}
				RescueHook component = ((Component)val2).GetComponent<RescueHook>();
				if ((Object)(object)component == (Object)null)
				{
					return true;
				}
				bool flag = f_isPulling.Invoke(component) && (Object)(object)f_targetPlayer.Invoke(component) == (Object)null;
				bool flag2 = val2.progress > 0f || val2.isUsingPrimary || val2.isUsingSecondary || Time.time < val2.lastFinishedCast + 0.2f;
				bool flag3 = _reelUntil.ContainsKey(component) && Time.time <= _reelUntil[component];
				if (flag || flag2 || flag3)
				{
					return false;
				}
				return true;
			}
			catch (Exception ex)
			{
				LogCritical("[URH] DoSwitching Prefix exception: " + ex);
				return true;
			}
		}
	}

	private static class Notifier
	{
		private static Canvas _canvas;

		private static TextMeshProUGUI _text;

		private static void Ensure()
		{
			//IL_0038: 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_016c: 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_019a: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b1: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)_canvas != (Object)null) || !((Object)(object)_text != (Object)null))
			{
				GameObject val = (GameObject)(((object)GameObject.Find("RescueHookNotifierCanvas")) ?? ((object)new GameObject("RescueHookNotifierCanvas")));
				_canvas = val.GetComponent<Canvas>();
				if ((Object)(object)_canvas == (Object)null)
				{
					_canvas = val.AddComponent<Canvas>();
					_canvas.renderMode = (RenderMode)0;
					_canvas.sortingOrder = 9999;
					val.AddComponent<CanvasScaler>();
					val.AddComponent<GraphicRaycaster>();
					Object.DontDestroyOnLoad((Object)(object)val);
				}
				GameObject val2 = (GameObject)(((object)GameObject.Find("RescueHookNotifierText")) ?? ((object)new GameObject("RescueHookNotifierText")));
				if ((Object)(object)val2.transform.parent != (Object)(object)((Component)_canvas).transform)
				{
					val2.transform.SetParent(((Component)_canvas).transform);
				}
				_text = val2.GetComponent<TextMeshProUGUI>();
				if ((Object)(object)_text == (Object)null)
				{
					_text = val2.AddComponent<TextMeshProUGUI>();
					((TMP_Text)_text).fontSize = 30f;
					((TMP_Text)_text).alignment = (TextAlignmentOptions)514;
					((Graphic)_text).raycastTarget = false;
					((TMP_Text)_text).enableWordWrapping = false;
					((TMP_Text)_text).fontStyle = (FontStyles)1;
					RectTransform component = ((Component)_text).GetComponent<RectTransform>();
					component.sizeDelta = new Vector2(800f, 120f);
					component.anchorMin = new Vector2(0.5f, 0.5f);
					component.anchorMax = new Vector2(0.5f, 0.5f);
					component.pivot = new Vector2(0.5f, 0.5f);
				}
			}
		}

		public static void ShowMode(bool autoRelease)
		{
			//IL_004a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0064: 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)
			Ensure();
			if (!((Object)(object)_text == (Object)null))
			{
				((TMP_Text)_text).text = (autoRelease ? "Rescue Hook: Auto-Release" : "Rescue Hook: Hang");
				RectTransform component = ((Component)_text).GetComponent<RectTransform>();
				component.anchoredPosition = new Vector2((float)NotifyPosX, (float)NotifyPosY);
				((Graphic)_text).color = (autoRelease ? NotifyColorAuto : NotifyColorHang);
				((Component)_text).gameObject.SetActive(true);
			}
		}

		public static void Hide()
		{
			if ((Object)(object)_text != (Object)null)
			{
				((Component)_text).gameObject.SetActive(false);
			}
		}
	}

	[CompilerGenerated]
	private sealed class <ClearCurrentItemNextFrame>d__49 : IEnumerator<object>, IDisposable, IEnumerator
	{
		private int <>1__state;

		private object <>2__current;

		public Character ch;

		private CharacterData <data>5__1;

		private Exception <e>5__2;

		object IEnumerator<object>.Current
		{
			[DebuggerHidden]
			get
			{
				return <>2__current;
			}
		}

		object IEnumerator.Current
		{
			[DebuggerHidden]
			get
			{
				return <>2__current;
			}
		}

		[DebuggerHidden]
		public <ClearCurrentItemNextFrame>d__49(int <>1__state)
		{
			this.<>1__state = <>1__state;
		}

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

		private bool MoveNext()
		{
			switch (<>1__state)
			{
			default:
				return false;
			case 0:
				<>1__state = -1;
				<>2__current = null;
				<>1__state = 1;
				return true;
			case 1:
				<>1__state = -1;
				try
				{
					<data>5__1 = (((Object)(object)ch != (Object)null) ? ch.data : null);
					if ((Object)(object)<data>5__1 != (Object)null && (Object)(object)<data>5__1.currentItem != (Object)null && IsRescueHookInstance(<data>5__1.currentItem))
					{
						<data>5__1.currentItem = null;
					}
					<data>5__1 = null;
				}
				catch (Exception ex)
				{
					<e>5__2 = ex;
					LogCritical("[URH] ClearCurrentItemNextFrame exception: " + <e>5__2);
				}
				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();
		}
	}

	[CompilerGenerated]
	private sealed class <RenameExistingHookInstancesNextFrame>d__62 : IEnumerator<object>, IDisposable, IEnumerator
	{
		private int <>1__state;

		private object <>2__current;

		public UseableRescueHooksPlugin <>4__this;

		private Item[] <all>5__1;

		private Item[] <>s__2;

		private int <>s__3;

		private Item <it>5__4;

		private Exception <e>5__5;

		object IEnumerator<object>.Current
		{
			[DebuggerHidden]
			get
			{
				return <>2__current;
			}
		}

		object IEnumerator.Current
		{
			[DebuggerHidden]
			get
			{
				return <>2__current;
			}
		}

		[DebuggerHidden]
		public <RenameExistingHookInstancesNextFrame>d__62(int <>1__state)
		{
			this.<>1__state = <>1__state;
		}

		[DebuggerHidden]
		void IDisposable.Dispose()
		{
			<all>5__1 = null;
			<>s__2 = null;
			<it>5__4 = null;
			<e>5__5 = null;
			<>1__state = -2;
		}

		private bool MoveNext()
		{
			switch (<>1__state)
			{
			default:
				return false;
			case 0:
				<>1__state = -1;
				<>2__current = null;
				<>1__state = 1;
				return true;
			case 1:
				<>1__state = -1;
				<>2__current = null;
				<>1__state = 2;
				return true;
			case 2:
				<>1__state = -1;
				try
				{
					<all>5__1 = Object.FindObjectsOfType<Item>(true);
					<>s__2 = <all>5__1;
					for (<>s__3 = 0; <>s__3 < <>s__2.Length; <>s__3++)
					{
						<it>5__4 = <>s__2[<>s__3];
						if (IsRescueHookPrefab(<it>5__4))
						{
							TrySetItemUIName(<it>5__4, "Rescue Hook");
						}
						<it>5__4 = null;
					}
					<>s__2 = null;
					<all>5__1 = null;
				}
				catch (Exception ex)
				{
					<e>5__5 = ex;
					LogCritical("[URH] RenameExistingHookInstancesNextFrame exception: " + <e>5__5);
				}
				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();
		}
	}

	private static Harmony _harmony;

	internal static UseableRescueHooksPlugin Instance;

	private static ConfigEntry<KeyCode> CFG_ModeToggleKey;

	private static ConfigEntry<KeyCode> CFG_ManualLetGoKey;

	private static ConfigEntry<int> CFG_NotifyPosX;

	private static ConfigEntry<int> CFG_NotifyPosY;

	private static ConfigEntry<string> CFG_NotifyColorHang;

	private static ConfigEntry<string> CFG_NotifyColorAuto;

	private const float DEFAULT_HANG = 2f;

	private const float MIN_HANG = 0.05f;

	private const float MAX_HANG = 40f;

	private const float SCROLL_STEP = 3f;

	private static readonly Dictionary<RescueHook, float> _reelUntil = new Dictionary<RescueHook, float>();

	private static readonly Dictionary<RescueHook, float> _reelOrigHang = new Dictionary<RescueHook, float>();

	private const float REEL_DURATION = 0.65f;

	private const float REEL_TARGET = 0.2f;

	private const float REEL_SPEED = 30f;

	private static readonly Dictionary<RescueHook, float> _dynHang = new Dictionary<RescueHook, float>();

	private static readonly Dictionary<RescueHook, Vector3> _pullStartPos = new Dictionary<RescueHook, Vector3>();

	private static readonly Dictionary<RescueHook, float> _pullStartTime = new Dictionary<RescueHook, float>();

	private static bool _activeRagdoll;

	private static bool _activeAutoLetGo;

	private static bool _modeAutoRelease;

	private static readonly HashSet<Character> _hangNoFall = new HashSet<Character>();

	private static readonly Dictionary<Character, float> _hangNoFallGraceUntil = new Dictionary<Character, float>();

	private static readonly Dictionary<Character, Item> _lastEquippedHook = new Dictionary<Character, Item>();

	private static readonly Dictionary<Character, Optionable<byte>> _capturedSlotOnEquip = new Dictionary<Character, Optionable<byte>>();

	internal static readonly FieldRef<RescueHook, float> f_launchForce = AccessTools.FieldRefAccess<RescueHook, float>("launchForce");

	internal static readonly FieldRef<RescueHook, Character> f_targetPlayer = AccessTools.FieldRefAccess<RescueHook, Character>("targetPlayer");

	internal static readonly FieldRef<RescueHook, bool> f_isPulling = AccessTools.FieldRefAccess<RescueHook, bool>("isPulling");

	internal static readonly FieldRef<RescueHook, Vector3> f_targetPos = AccessTools.FieldRefAccess<RescueHook, Vector3>("targetPos");

	internal static readonly FieldRef<RescueHook, float> f_range = AccessTools.FieldRefAccess<RescueHook, float>("range");

	internal static readonly FieldRef<CharacterData, Character> f_cd_character = AccessTools.FieldRefAccess<CharacterData, Character>("character");

	internal static readonly FieldRef<CharacterItems, Character> f_ci_character = AccessTools.FieldRefAccess<CharacterItems, Character>("character");

	internal static readonly FieldRef<CharacterItems, float> f_ci_throwChargeLevel = AccessTools.FieldRefAccess<CharacterItems, float>("throwChargeLevel");

	private const string RESCUE_HOOK_DISPLAY = "Rescue Hook";

	internal static KeyCode ModeToggleKey => CFG_ModeToggleKey.Value;

	internal static KeyCode ManualLetGoKey => CFG_ManualLetGoKey.Value;

	internal static int NotifyPosX => CFG_NotifyPosX.Value;

	internal static int NotifyPosY => CFG_NotifyPosY.Value;

	internal static Color NotifyColorHang => ParseHtmlColor(CFG_NotifyColorHang.Value, new Color(0.62f, 0.49f, 1f));

	internal static Color NotifyColorAuto => ParseHtmlColor(CFG_NotifyColorAuto.Value, new Color(0.77f, 0.29f, 1f));

	private static Color ParseHtmlColor(string html, Color fallback)
	{
		//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_0018: 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_0020: Unknown result type (might be due to invalid IL or missing references)
		Color result = default(Color);
		if (!string.IsNullOrEmpty(html) && ColorUtility.TryParseHtmlString(html, ref result))
		{
			return result;
		}
		return fallback;
	}

	internal static void LogCritical(string msg)
	{
		if ((Object)(object)Instance != (Object)null)
		{
			((BaseUnityPlugin)Instance).Logger.LogInfo((object)msg);
		}
		else
		{
			Debug.Log((object)msg);
		}
	}

	private static float GetHang(RescueHook inst)
	{
		float value;
		return _dynHang.TryGetValue(inst, out value) ? value : 2f;
	}

	private static void SetHang(RescueHook inst, float v)
	{
		_dynHang[inst] = Mathf.Clamp(v, 0.05f, 40f);
	}

	private static void StartNoFallGrace(Character ch, float seconds)
	{
		if (!((Object)(object)ch == (Object)null))
		{
			_hangNoFallGraceUntil[ch] = Time.time + seconds;
		}
	}

	private static bool IsNoFallActive(Character ch)
	{
		if ((Object)(object)ch == (Object)null)
		{
			return false;
		}
		if (_hangNoFall.Contains(ch))
		{
			return true;
		}
		if (_hangNoFallGraceUntil.TryGetValue(ch, out var value))
		{
			if (Time.time <= value)
			{
				return true;
			}
			_hangNoFallGraceUntil.Remove(ch);
		}
		return false;
	}

	private static bool WasHangingRecently(Character ch)
	{
		if ((Object)(object)ch == (Object)null)
		{
			return false;
		}
		if (_hangNoFall.Contains(ch))
		{
			return true;
		}
		if (_hangNoFallGraceUntil.TryGetValue(ch, out var value) && Time.time <= value)
		{
			return true;
		}
		return false;
	}

	private static bool IsRescueHookInstance(Item it)
	{
		if (!Object.op_Implicit((Object)(object)it))
		{
			return false;
		}
		if (it.itemID == 100)
		{
			return true;
		}
		string text = ((Object)it).name ?? string.Empty;
		return text == "RescueHook" || text == "RescueHook(Clone)";
	}

	private static bool IsRescueHookPrefab(Item it)
	{
		if (!Object.op_Implicit((Object)(object)it))
		{
			return false;
		}
		if (it.itemID == 100)
		{
			return true;
		}
		string text = ((Object)it).name ?? string.Empty;
		return text == "RescueHook" || text == "RescueHook(Clone)";
	}

	private static void TryRemoveFromInventory(Item hookItem, Optionable<byte> preferredSlot, string reason, bool allowScan)
	{
		//IL_00e2: 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_019c: 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)
		try
		{
			if (!Object.op_Implicit((Object)(object)hookItem))
			{
				return;
			}
			Character val = hookItem.holderCharacter ?? hookItem.trueHolderCharacter;
			if (!Object.op_Implicit((Object)(object)val) || !val.IsLocal)
			{
				return;
			}
			CharacterItems val2 = ((val.refs != null) ? val.refs.items : null);
			Player player = val.player;
			if ((Object)(object)val2 == (Object)null || (Object)(object)player == (Object)null)
			{
				return;
			}
			if ((Object)(object)((MonoBehaviourPun)val2).photonView != (Object)null)
			{
				((MonoBehaviourPun)val2).photonView.RPC("DestroyHeldItemRpc", (RpcTarget)0, new object[0]);
			}
			UseableRescueHooksPlugin instance = Instance;
			if ((Object)(object)instance != (Object)null)
			{
				((MonoBehaviour)instance).StartCoroutine(ClearCurrentItemNextFrame(val));
			}
			if (preferredSlot.IsSome)
			{
				player.EmptySlot(Optionable<byte>.Some(preferredSlot.Value));
				return;
			}
			if (val2.currentSelectedSlot.IsSome)
			{
				player.EmptySlot(val2.currentSelectedSlot);
				return;
			}
			if (allowScan)
			{
				for (byte b = 0; b < player.itemSlots.Length; b++)
				{
					ItemSlot val3 = player.itemSlots[b];
					if (!val3.IsEmpty() && (Object)(object)val3.prefab != (Object)null && IsRescueHookPrefab(val3.prefab))
					{
						player.EmptySlot(Optionable<byte>.Some(b));
						return;
					}
				}
			}
			if (val2.lastSelectedSlot.IsSome)
			{
				player.EmptySlot(val2.lastSelectedSlot);
			}
		}
		catch (Exception ex)
		{
			LogCritical("[URH] Remove exception: " + ex);
		}
	}

	[IteratorStateMachine(typeof(<ClearCurrentItemNextFrame>d__49))]
	private static IEnumerator ClearCurrentItemNextFrame(Character ch)
	{
		//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
		return new <ClearCurrentItemNextFrame>d__49(0)
		{
			ch = ch
		};
	}

	private void Awake()
	{
		//IL_00da: Unknown result type (might be due to invalid IL or missing references)
		//IL_00e4: Expected O, but got Unknown
		Instance = this;
		CFG_ModeToggleKey = ((BaseUnityPlugin)this).Config.Bind<KeyCode>("LetGo", "ModeToggleKey", (KeyCode)53, "Toggle Hang <-> Auto-Release.");
		CFG_ManualLetGoKey = ((BaseUnityPlugin)this).Config.Bind<KeyCode>("LetGo", "ManualLetGoKey", (KeyCode)32, "Manual 'Let Go' while wall-hanging.");
		CFG_NotifyPosX = ((BaseUnityPlugin)this).Config.Bind<int>("UI", "NotifyPosX", 0, "Notifier X offset (pixels).");
		CFG_NotifyPosY = ((BaseUnityPlugin)this).Config.Bind<int>("UI", "NotifyPosY", -600, "Notifier Y offset (pixels).");
		CFG_NotifyColorHang = ((BaseUnityPlugin)this).Config.Bind<string>("UI", "NotifyColorHang", "#9D7CFF", "Notifier color in Hang mode (HTML color).");
		CFG_NotifyColorAuto = ((BaseUnityPlugin)this).Config.Bind<string>("UI", "NotifyColorAuto", "#C54BFF", "Notifier color in Auto-Release mode (HTML color).");
		_harmony = new Harmony("tony4twentys.Useable_Rescue_Hooks");
		_harmony.PatchAll();
		TryRenameHookPrefabs();
		((MonoBehaviour)this).StartCoroutine(RenameExistingHookInstancesNextFrame());
		AttachFireBlockPatches();
		LogCritical("[URH] Loaded v2.0.1 (configs restored, logger fixed).");
	}

	private void OnDestroy()
	{
		if (_harmony != null)
		{
			_harmony.UnpatchSelf();
		}
	}

	private void TryRenameHookPrefabs()
	{
		try
		{
			Item item = default(Item);
			if (ItemDatabase.TryGetItem((ushort)100, ref item))
			{
				TrySetItemUIName(item, "Rescue Hook");
			}
		}
		catch (Exception ex)
		{
			LogCritical("[URH] TryRenameHookPrefabs exception: " + ex);
		}
	}

	[IteratorStateMachine(typeof(<RenameExistingHookInstancesNextFrame>d__62))]
	private IEnumerator RenameExistingHookInstancesNextFrame()
	{
		//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
		return new <RenameExistingHookInstancesNextFrame>d__62(0)
		{
			<>4__this = this
		};
	}

	private static void TrySetItemUIName(Item item, string name)
	{
		if (!Object.op_Implicit((Object)(object)item))
		{
			return;
		}
		try
		{
			Type type = AccessTools.Inner(typeof(Item), "ItemUIData");
			if (type == null)
			{
				return;
			}
			FieldInfo fieldInfo = null;
			foreach (FieldInfo declaredField in AccessTools.GetDeclaredFields(typeof(Item)))
			{
				if (declaredField.FieldType == type)
				{
					fieldInfo = declaredField;
					break;
				}
			}
			if (fieldInfo == null)
			{
				return;
			}
			object obj = fieldInfo.GetValue(item);
			if (obj == null)
			{
				obj = Activator.CreateInstance(type);
			}
			FieldInfo fieldInfo2 = AccessTools.Field(type, "itemName");
			if (!(fieldInfo2 == null))
			{
				if (type.IsValueType)
				{
					object obj2 = obj;
					fieldInfo2.SetValue(obj2, name);
					fieldInfo.SetValue(item, obj2);
				}
				else
				{
					fieldInfo2.SetValue(obj, name);
					fieldInfo.SetValue(item, obj);
				}
			}
		}
		catch (Exception ex)
		{
			LogCritical("[URH] TrySetItemUIName exception: " + ex);
		}
	}

	private static void ConsumeHookFromInventory_Held(Item item, string reason)
	{
		try
		{
			if (!((Object)(object)item == (Object)null))
			{
				Character val = item.holderCharacter ?? item.trueHolderCharacter;
				if (!((Object)(object)val == (Object)null) && val.IsLocal)
				{
					((MonoBehaviour)item).StartCoroutine(item.ConsumeDelayed(false));
				}
			}
		}
		catch (Exception ex)
		{
			LogCritical("[URH] Consume exception: " + ex);
		}
	}

	public static void GuardedFall(Character character, float seconds, float force)
	{
		if ((Object)(object)character == (Object)null)
		{
			return;
		}
		if (_activeRagdoll)
		{
			MethodInfo method = ((object)character).GetType().GetMethod("Fall", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
			if (method != null)
			{
				method.Invoke(character, new object[2] { seconds, force });
			}
		}
		else
		{
			character.data.fallSeconds = 0f;
		}
	}

	public static void GuardLetGoWallOnly(RescueHook inst)
	{
		if (!((Object)(object)inst == (Object)null) && _activeAutoLetGo)
		{
			MethodInfo methodInfo = AccessTools.Method(typeof(RescueHook), "RPCA_LetGo", (Type[])null, (Type[])null);
			if (methodInfo != null)
			{
				methodInfo.Invoke(inst, new object[0]);
			}
		}
	}

	private static void DoLetGo(RescueHook inst)
	{
		if (!((Object)(object)inst == (Object)null))
		{
			MethodInfo methodInfo = AccessTools.Method(typeof(RescueHook), "RPCA_LetGo", (Type[])null, (Type[])null);
			if ((Object)(object)((MonoBehaviourPun)inst).photonView != (Object)null && ((MonoBehaviourPun)inst).photonView.IsMine)
			{
				((MonoBehaviourPun)inst).photonView.RPC("RPCA_LetGo", (RpcTarget)0, new object[0]);
			}
			else if (methodInfo != null)
			{
				methodInfo.Invoke(inst, new object[0]);
			}
			Character playerHoldingItem = inst.playerHoldingItem;
			if ((Object)(object)playerHoldingItem != (Object)null && _hangNoFall.Remove(playerHoldingItem))
			{
				StartNoFallGrace(playerHoldingItem, 2f);
			}
		}
	}

	private static void AttachFireBlockPatches()
	{
		//IL_00b7: Unknown result type (might be due to invalid IL or missing references)
		//IL_00c5: Expected O, but got Unknown
		try
		{
			string[] array = new string[12]
			{
				"OnPrimaryStartCast", "OnPrimaryPerformedCast", "OnPrimaryFinishedCast", "OnPrimaryInput", "OnPrimary", "Primary", "Fire", "RPCA_Fire", "RPC_Fire", "StartCast",
				"TryFire", "Shoot"
			};
			int num = 0;
			string[] array2 = array;
			foreach (string text in array2)
			{
				MethodInfo methodInfo = AccessTools.Method(typeof(RescueHook), text, (Type[])null, (Type[])null);
				if (methodInfo != null)
				{
					_harmony.Patch((MethodBase)methodInfo, new HarmonyMethod(typeof(UseableRescueHooksPlugin), "FireGuardPrefix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
					num++;
				}
			}
			LogCritical("[URH] Fire block patched on " + num + " entrypoints");
		}
		catch (Exception ex)
		{
			LogCritical("[URH] AttachFireBlockPatches exception: " + ex);
		}
	}

	private static bool FireGuardPrefix(RescueHook __instance)
	{
		Character val = (((Object)(object)__instance != (Object)null && (Object)(object)((ItemComponent)__instance).item != (Object)null) ? ((ItemComponent)__instance).item.holderCharacter : null);
		if ((Object)(object)val != (Object)null && val.IsLocal && _hangNoFall.Contains(val))
		{
			return false;
		}
		return true;
	}
}