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;
}
}