using System; using System.Collections.Generic; using System.Diagnostics; using System.Reflection; using System.Reflection.Emit; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Security; using System.Security.Permissions; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; using Microsoft.CodeAnalysis; using Photon.Pun; using UnityEngine; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)] [assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")] [assembly: AssemblyCompany("BetterFriendPull")] [assembly: AssemblyConfiguration("Debug")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0+21ed1f20f1f85c010fe6758e26953fb81c50997d")] [assembly: AssemblyProduct("BetterFriendPull")] [assembly: AssemblyTitle("BetterFriendPull")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("1.0.0.0")] [module: UnverifiableCode] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)] internal sealed class RefSafetyRulesAttribute : Attribute { public readonly int Version; public RefSafetyRulesAttribute(int P_0) { Version = P_0; } } } namespace BetterFriendPull { [HarmonyPatch(typeof(CharacterGrabbing), "Reach")] public static class PatchReachRange { [HarmonyTranspiler] private static IEnumerable Transpiler(IEnumerable instructions) { //IL_0080: Unknown result type (might be due to invalid IL or missing references) //IL_008a: Expected O, but got Unknown //IL_00fc: Unknown result type (might be due to invalid IL or missing references) //IL_0106: Expected O, but got Unknown List list = new List(instructions); for (int i = 0; i < list.Count; i++) { if (list[i].opcode == OpCodes.Ldc_R4 && Mathf.Approximately((float)list[i].operand, 4f)) { Debug.Log((object)$"[BetterFriendPull] Replacing 4f range with {Plugin.PullRange.Value}f"); list[i] = new CodeInstruction(OpCodes.Ldc_R4, (object)Plugin.PullRange.Value); } if (list[i].opcode == OpCodes.Ldc_R4 && Mathf.Approximately((float)list[i].operand, 60f)) { Debug.Log((object)$"[BetterFriendPull] Replacing 60f angle with {Plugin.PullAngle.Value}f"); list[i] = new CodeInstruction(OpCodes.Ldc_R4, (object)Plugin.PullAngle.Value); } } return list; } } [HarmonyPatch(typeof(CharacterGrabbing), "TargetCanBeHelped")] public static class PatchVerticalLimit { [HarmonyTranspiler] private static IEnumerable Transpiler(IEnumerable instructions) { //IL_00f0: Unknown result type (might be due to invalid IL or missing references) //IL_00fa: Expected O, but got Unknown List list = new List(instructions); for (int i = 0; i < list.Count; i++) { if (!(list[i].opcode == OpCodes.Ldc_R4) || !Mathf.Approximately((float)list[i].operand, 1f)) { continue; } bool flag = false; for (int j = Mathf.Max(0, i - 8); j < i; j++) { if (list[j].opcode == OpCodes.Callvirt && list[j].operand.ToString().Contains("get_isClimbing")) { flag = true; break; } } if (flag) { Debug.Log((object)$"[BetterFriendPull] Replacing vertical limit 1f with {Plugin.PullVerticalLimit.Value}f"); list[i] = new CodeInstruction(OpCodes.Ldc_R4, (object)Plugin.PullVerticalLimit.Value); } } return list; } } [HarmonyPatch(typeof(Character), "DragTowards")] public static class PatchPullForce { [HarmonyPrefix] private static void Prefix(Character __instance, Vector3 target, ref float force) { if (!Mathf.Approximately(Plugin.PullForceMultiplier.Value, 1f)) { force *= Plugin.PullForceMultiplier.Value; if (Plugin.PullForceMultiplier.Value != 1f) { Debug.Log((object)$"[BetterFriendPull] Pull force multiplied: {force / Plugin.PullForceMultiplier.Value:F0} → {force:F0}"); } } } } public static class StaminaFreezeManager { private static HashSet _protectedChars = new HashSet(); private static Dictionary _protectUntil = new Dictionary(); public static void ProtectCharacter(Character c) { if (Plugin.EnableStaminaFreeze.Value) { _protectedChars.Add(c); _protectUntil[c] = Time.time + Plugin.StaminaFreezeCooldown.Value; } } public static bool IsProtected(Character c) { if (!Plugin.EnableStaminaFreeze.Value) { return false; } float time = Time.time; List list = new List(); foreach (KeyValuePair item in _protectUntil) { if (time > item.Value) { list.Add(item.Key); } } foreach (Character item2 in list) { _protectedChars.Remove(item2); _protectUntil.Remove(item2); } return _protectedChars.Contains(c); } } [HarmonyPatch(typeof(Character), "DragTowards")] public static class PatchTrackPullSimple { [HarmonyPrefix] private static void Prefix(Character __instance) { StaminaFreezeManager.ProtectCharacter(__instance); if (((MonoBehaviourPun)__instance).photonView.IsMine && Plugin.EnableStaminaFreeze.Value) { Debug.Log((object)("[BetterFriendPull] Stamina frozen for " + __instance.characterName)); } } } [HarmonyPatch(typeof(Character), "UseStamina")] public static class PatchBlockStamina { [HarmonyPrefix] private static bool Prefix(Character __instance) { if (StaminaFreezeManager.IsProtected(__instance)) { return false; } return true; } } [BepInPlugin("jill920.BetterFriendPull", "BetterFriendPull", "1.0.1")] public class Plugin : BaseUnityPlugin { public static ManualLogSource Log; public static ConfigEntry PullRange; public static ConfigEntry PullAngle; public static ConfigEntry PullVerticalLimit; public static ConfigEntry PullForceMultiplier; public static ConfigEntry EnableStaminaFreeze; public static ConfigEntry StaminaFreezeCooldown; public static HashSet PullProtectedCharacters = new HashSet(); public static Dictionary PullProtectionEndTime = new Dictionary(); private void Awake() { //IL_00f0: Unknown result type (might be due to invalid IL or missing references) //IL_00f6: Expected O, but got Unknown Log = ((BaseUnityPlugin)this).Logger; PullRange = ((BaseUnityPlugin)this).Config.Bind("Settings", "Pull Range", 6f, "Max distance to detect climbing friends (vanilla: 4)"); PullAngle = ((BaseUnityPlugin)this).Config.Bind("Settings", "Pull Angle", 60f, "Cone angle in degrees (vanilla: 60)"); PullVerticalLimit = ((BaseUnityPlugin)this).Config.Bind("Settings", "Vertical Pull Limit", 1f, "Max height difference to pull (vanilla: 1)"); PullForceMultiplier = ((BaseUnityPlugin)this).Config.Bind("Settings", "Pull Force Multiplier", 1f, "Multiply pull force (vanilla: 1)"); EnableStaminaFreeze = ((BaseUnityPlugin)this).Config.Bind("Stamina", "Enable Stamina Freeze", true, "Prevent stamina drain while being pulled"); StaminaFreezeCooldown = ((BaseUnityPlugin)this).Config.Bind("Stamina", "Stamina Freeze Cooldown", 0.65f, "Seconds after pull ends to keep stamina frozen (prevents instant drain)"); Harmony val = new Harmony(((BaseUnityPlugin)this).Info.Metadata.GUID); val.PatchAll(); Log.LogInfo((object)$"BetterFriendPull loaded. Range: {PullRange.Value}m, Stamina Freeze: {EnableStaminaFreeze.Value}, Cooldown: {StaminaFreezeCooldown.Value}s"); } private void Update() { float time = Time.time; List list = new List(); foreach (KeyValuePair item in PullProtectionEndTime) { if (time > item.Value) { list.Add(item.Key); } } foreach (Character item2 in list) { PullProtectedCharacters.Remove(item2); PullProtectionEndTime.Remove(item2); if ((Object)(object)item2 != (Object)null && ((MonoBehaviourPun)item2).photonView.IsMine) { Log.LogDebug((object)("Stamina freeze expired for " + item2.characterName)); } } if (!Application.isFocused || (Object)(object)Character.localCharacter == (Object)null || (!Input.GetKey((KeyCode)306) && !Input.GetKey((KeyCode)305))) { return; } if (Input.GetKeyDown((KeyCode)273)) { ConfigEntry pullRange = PullRange; pullRange.Value += 0.5f; Log.LogInfo((object)$"↑ Pull Range increased to {PullRange.Value}m"); } if (Input.GetKeyDown((KeyCode)274)) { ConfigEntry pullRange2 = PullRange; pullRange2.Value -= 0.5f; Log.LogInfo((object)$"↓ Pull Range decreased to {PullRange.Value}m"); } if (Input.GetKeyDown((KeyCode)275)) { ConfigEntry pullAngle = PullAngle; pullAngle.Value += 5f; Log.LogInfo((object)$"→ Pull Angle increased to {PullAngle.Value}°"); } if (Input.GetKeyDown((KeyCode)276)) { ConfigEntry pullAngle2 = PullAngle; pullAngle2.Value -= 5f; Log.LogInfo((object)$"← Pull Angle decreased to {PullAngle.Value}°"); } if (Input.GetKeyDown((KeyCode)280)) { ConfigEntry pullVerticalLimit = PullVerticalLimit; pullVerticalLimit.Value += 0.5f; Log.LogInfo((object)$"PgUp Vertical Limit increased to {PullVerticalLimit.Value}m"); } if (Input.GetKeyDown((KeyCode)281)) { ConfigEntry pullVerticalLimit2 = PullVerticalLimit; pullVerticalLimit2.Value -= 0.5f; Log.LogInfo((object)$"PgDn Vertical Limit decreased to {PullVerticalLimit.Value}m"); } if (Input.GetKey((KeyCode)304) || Input.GetKey((KeyCode)303)) { if (Input.GetKeyDown((KeyCode)273)) { ConfigEntry pullForceMultiplier = PullForceMultiplier; pullForceMultiplier.Value += 0.25f; Log.LogInfo((object)$"↑ Pull Force increased to {PullForceMultiplier.Value}x"); } if (Input.GetKeyDown((KeyCode)274)) { ConfigEntry pullForceMultiplier2 = PullForceMultiplier; pullForceMultiplier2.Value -= 0.25f; Log.LogInfo((object)$"↓ Pull Force decreased to {PullForceMultiplier.Value}x"); } } if (Input.GetKeyDown((KeyCode)115)) { EnableStaminaFreeze.Value = !EnableStaminaFreeze.Value; Log.LogInfo((object)("Stamina Freeze: " + (EnableStaminaFreeze.Value ? "ENABLED" : "DISABLED"))); } } } }