The BepInEx console will not appear when launching like it does for other games on Thunderstore (you can turn it back on in your BepInEx.cfg file). If your PEAK crashes on startup, add -dx12 to your launch parameters.
Decompiled source of Useable Rescue Hooks v2.0.1
tony4twentys-Useable Rescue Hooks.dll
Decompiled a day agousing 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; } }