using System; using System.Diagnostics; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Security; using System.Security.Permissions; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using ExitGames.Client.Photon; using HarmonyLib; using Microsoft.CodeAnalysis; using Photon.Pun; using Photon.Realtime; using TMPro; using UnityEngine; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")] [assembly: AssemblyCompany("PlayerGrabRecharge")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("3.2.0.0")] [assembly: AssemblyInformationalVersion("3.2.0")] [assembly: AssemblyProduct("PlayerGrabRecharge")] [assembly: AssemblyTitle("PlayerGrabRecharge")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("3.2.0.0")] [module: UnverifiableCode] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)] internal sealed class NullableAttribute : Attribute { public readonly byte[] NullableFlags; public NullableAttribute(byte P_0) { NullableFlags = new byte[1] { P_0 }; } public NullableAttribute(byte[] P_0) { NullableFlags = P_0; } } [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)] internal sealed class NullableContextAttribute : Attribute { public readonly byte Flag; public NullableContextAttribute(byte P_0) { Flag = P_0; } } } namespace PlayerGrabRecharge { [BepInPlugin("aolion.grabrechargemp", "Player Grab Recharge MP", "3.2.1")] public class PlayerGrabRechargePlugin : BaseUnityPlugin, IOnEventCallback { public const string PLUGIN_GUID = "aolion.grabrechargemp"; public const string PLUGIN_NAME = "Player Grab Recharge MP"; public const string PLUGIN_VERSION = "3.2.1"; private const byte EVENT_CHARGE = 143; private const float MAX_POWER = 100f; private const float COOLDOWN_TIME = 3f; private const float REGEN_RATE = 5f; internal static ManualLogSource Logger = null; private Harmony _harmony; internal static bool IsRecharging = false; internal static float ModPower = 100f; internal static float Cooldown = 0f; private static float _chargeAccum = 0f; private static ItemBattery? _lastBattery = null; private static FieldInfo? _chargeTimerField; private static FieldInfo? _isChargingField; private static FieldInfo? _goalUITextField; private static FieldInfo? _energyUITextField; public static ConfigEntry RechargeKey { get; private set; } = null; public static ConfigEntry ToggleMode { get; private set; } = null; public static ConfigEntry RechargeRate { get; private set; } = null; public static ConfigEntry ShowUI { get; private set; } = null; public static ConfigEntry DebugLog { get; private set; } = null; public static PlayerGrabRechargePlugin? Instance { get; private set; } private void Awake() { //IL_0071: Unknown result type (might be due to invalid IL or missing references) //IL_0080: Expected O, but got Unknown //IL_007b: Unknown result type (might be due to invalid IL or missing references) //IL_0085: Expected O, but got Unknown //IL_00d0: Unknown result type (might be due to invalid IL or missing references) //IL_00da: Expected O, but got Unknown //IL_010e: Unknown result type (might be due to invalid IL or missing references) Instance = this; Logger = ((BaseUnityPlugin)this).Logger; RechargeKey = ((BaseUnityPlugin)this).Config.Bind("Settings", "RechargeKey", (KeyCode)122, "Key to hold (or tap in toggle mode) to recharge the grabbed item."); ToggleMode = ((BaseUnityPlugin)this).Config.Bind("Settings", "ToggleMode", false, "False = hold to charge. True = tap to toggle."); RechargeRate = ((BaseUnityPlugin)this).Config.Bind("Settings", "RechargeRate", 10, new ConfigDescription("Battery % restored per second.", (AcceptableValueBase)new AcceptableValueRange(1, 100), Array.Empty())); ShowUI = ((BaseUnityPlugin)this).Config.Bind("UI", "ShowChargeBar", true, "Show the mod power bar on the HUD."); DebugLog = ((BaseUnityPlugin)this).Config.Bind("Debug", "DebugLogging", false, "Verbose logging — set true to diagnose issues."); _harmony = new Harmony("aolion.grabrechargemp"); _harmony.PatchAll(typeof(PlayerGrabRechargePlugin)); Logger.LogInfo((object)string.Format("[PGR] v{0} loaded. Key={1} ToggleMode={2} RatePerSec={3}", "3.2.1", RechargeKey.Value, ToggleMode.Value, RechargeRate.Value)); } private void OnDestroy() { _harmony.UnpatchSelf(); PhotonNetwork.RemoveCallbackTarget((object)this); } private static ItemBattery? GetGrabbedBattery(PlayerController pc) { GameObject physGrabObject = pc.physGrabObject; if ((Object)(object)physGrabObject == (Object)null) { return null; } Transform val = physGrabObject.transform; while ((Object)(object)val.parent != (Object)null && (Object)(object)((Component)val.parent).GetComponent() != (Object)null) { val = val.parent; } ItemBattery componentInChildren = ((Component)val).GetComponentInChildren(true); if (DebugLog.Value && (Object)(object)componentInChildren == (Object)null && (Object)(object)physGrabObject != (Object)null) { Logger.LogInfo((object)("[PGR] No ItemBattery found under " + ((Object)val).name + " (grabbed=" + ((Object)physGrabObject).name + ")")); } return componentInChildren; } private static void EnsureVisualFields() { if (_chargeTimerField == null) { _chargeTimerField = typeof(ItemBattery).GetField("chargeTimer", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); } if (_isChargingField == null) { _isChargingField = typeof(ItemBattery).GetField("isCharging", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); } } private static void SetChargingVisual(ItemBattery battery) { EnsureVisualFields(); _chargeTimerField?.SetValue(battery, 0.3f); _isChargingField?.SetValue(battery, true); } private static void StopChargingVisual(ItemBattery? battery) { if (!((Object)(object)battery == (Object)null)) { EnsureVisualFields(); _isChargingField?.SetValue(battery, false); _chargeTimerField?.SetValue(battery, 0f); _chargeAccum = 0f; _lastBattery = null; } } private static void ApplyCharge(ItemBattery battery, float amount) { if ((Object)(object)_lastBattery != (Object)(object)battery) { _chargeAccum = 0f; _lastBattery = battery; } float num = ((battery.batteryBars > 0) ? (100f / (float)battery.batteryBars) : 100f); _chargeAccum += amount; if (_chargeAccum >= num) { _chargeAccum -= num; float batteryLife = battery.batteryLife; float num2 = Mathf.Clamp(batteryLife + num, num, 100f); if (battery.batteryLife <= 0f) { battery.batteryLife = 0.001f; } battery.SetBatteryLife(Mathf.RoundToInt(num2)); if (DebugLog.Value) { Logger.LogInfo((object)$"[PGR] Bar +1: {batteryLife:F0}→{num2:F0} bars={battery.batteryBars} barSize={num:F0}"); } } } public void OnEvent(EventData photonEvent) { if (photonEvent.Code != 143 || !PhotonNetwork.IsMasterClient) { return; } try { object[] obj = (object[])photonEvent.CustomData; int num = (int)obj[0]; float num2 = (float)obj[1]; PhotonView val = PhotonView.Find(num); if ((Object)(object)val == (Object)null) { return; } ItemBattery val2 = ((Component)val).GetComponentInChildren(true) ?? ((Component)val).GetComponentInParent(); if (!((Object)(object)val2 == (Object)null)) { ApplyCharge(val2, num2); if (DebugLog.Value) { Logger.LogInfo((object)$"[PGR:HOST] Remote charge +{num2:F3} on viewID={num} ({((Object)val).name})"); } } } catch (Exception ex) { Logger.LogWarning((object)("[PGR] OnEvent error: " + ex.Message)); } } private static void DrawPowerBar(TextMeshProUGUI? tmp) { if (!ShowUI.Value || (Object)(object)tmp == (Object)null) { return; } float num = Mathf.Clamp01(ModPower / 100f); string text = $"{Mathf.RoundToInt(num * 100f)}%"; if (Cooldown > 0f) { text += $" (CD {Cooldown:F1}s)"; } string text2 = ((num < 0.25f) ? "#ff3333" : ((num < 0.6f) ? "#ffaa00" : "#00ff66")); string text3 = "\nCharge: " + text + ""; if (!((TMP_Text)tmp).text.Contains("Charge:")) { ((TMP_Text)tmp).text = ((TMP_Text)tmp).text + text3; return; } int num2 = ((TMP_Text)tmp).text.IndexOf("Charge:", StringComparison.Ordinal); int num3 = ((TMP_Text)tmp).text.IndexOf('\n', num2 + 1); if (num3 < 0) { num3 = ((TMP_Text)tmp).text.Length; } string text4 = ((TMP_Text)tmp).text.Substring(0, num2); string text5 = ((TMP_Text)tmp).text; int num4 = num3; ((TMP_Text)tmp).text = text4 + text3 + text5.Substring(num4, text5.Length - num4); } [HarmonyPatch(typeof(PlayerController), "Update")] [HarmonyPostfix] private static void PlayerControllerUpdate_Postfix(PlayerController __instance) { //IL_007f: Unknown result type (might be due to invalid IL or missing references) //IL_0069: Unknown result type (might be due to invalid IL or missing references) //IL_011c: Unknown result type (might be due to invalid IL or missing references) //IL_0273: Unknown result type (might be due to invalid IL or missing references) //IL_0278: Unknown result type (might be due to invalid IL or missing references) //IL_027a: Unknown result type (might be due to invalid IL or missing references) //IL_0281: Expected O, but got Unknown //IL_02a6: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)__instance != (Object)(object)PlayerController.instance) { return; } if (Cooldown > 0f) { Cooldown -= Time.deltaTime; } else if (ModPower < 100f) { ModPower = Mathf.Min(ModPower + 5f * Time.deltaTime, 100f); } if (!ToggleMode.Value) { IsRecharging = Input.GetKey(RechargeKey.Value); } else if (Input.GetKeyDown(RechargeKey.Value)) { IsRecharging = !IsRecharging; if (IsRecharging && ModPower <= 0.01f) { IsRecharging = false; } } if (IsRecharging && ModPower <= 0.01f) { Cooldown = 3f; ModPower = 0f; IsRecharging = false; } bool flag = IsRecharging && Cooldown <= 0f && ModPower > 0.01f; ItemBattery grabbedBattery = GetGrabbedBattery(__instance); if (DebugLog.Value && Input.GetKey(RechargeKey.Value)) { GameObject physGrabObject = __instance.physGrabObject; Logger.LogInfo((object)string.Format("[PGR] Z held: grabbed={0} battery={1} life={2:F1} canCharge={3} power={4:F2} cd={5:F2}", ((physGrabObject != null) ? ((Object)physGrabObject).name : null) ?? "null", ((grabbedBattery != null) ? ((Object)grabbedBattery).name : null) ?? "null", grabbedBattery?.batteryLife, flag, ModPower, Cooldown)); } if (!flag) { StopChargingVisual(grabbedBattery); return; } if ((Object)(object)grabbedBattery == (Object)null || grabbedBattery.isUnchargable || grabbedBattery.batteryLife >= 100f) { StopChargingVisual(grabbedBattery); return; } SetChargingVisual(grabbedBattery); float num = (float)RechargeRate.Value * Time.deltaTime; ModPower -= num; if (PhotonNetwork.IsMasterClient || !PhotonNetwork.IsConnectedAndReady) { ApplyCharge(grabbedBattery, num); return; } PhotonView val = ((Component)grabbedBattery).GetComponent() ?? ((Component)grabbedBattery).GetComponentInParent() ?? ((Component)grabbedBattery).GetComponentInChildren(); if ((Object)(object)val == (Object)null) { ApplyCharge(grabbedBattery, num); if (DebugLog.Value) { Logger.LogInfo((object)"[PGR] No PhotonView on battery — charged locally"); } return; } RaiseEventOptions val2 = new RaiseEventOptions { Receivers = (ReceiverGroup)2 }; PhotonNetwork.RaiseEvent((byte)143, (object)new object[2] { val.ViewID, num }, val2, SendOptions.SendUnreliable); if (DebugLog.Value) { Logger.LogInfo((object)$"[PGR] Sent charge event viewID={val.ViewID} amount={num:F4}"); } } [HarmonyPatch(typeof(LevelGenerator), "Generate")] [HarmonyPostfix] private static void LevelGenerator_Generate_Postfix() { IsRecharging = false; ModPower = 100f; Cooldown = 0f; _chargeAccum = 0f; _lastBattery = null; PhotonNetwork.AddCallbackTarget((object)Instance); if (DebugLog.Value) { Logger.LogInfo((object)"[PGR] Level generated — state reset, Photon callbacks registered"); } } [HarmonyPatch(typeof(PlayerController), "Start")] [HarmonyPostfix] private static void PlayerControllerStart_Postfix(PlayerController __instance) { if (!((Object)(object)__instance != (Object)(object)PlayerController.instance)) { PhotonNetwork.AddCallbackTarget((object)Instance); if (DebugLog.Value) { Logger.LogInfo((object)"[PGR] PlayerController.Start — Photon callbacks registered"); } } } [HarmonyPatch(typeof(GoalUI), "Update")] [HarmonyPostfix] private static void GoalUI_Update_Postfix(GoalUI __instance) { if (SemiFunc.RunIsLevel()) { if (_goalUITextField == null) { _goalUITextField = typeof(GoalUI).GetField("Text", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); } object? obj = _goalUITextField?.GetValue(__instance); DrawPowerBar((TextMeshProUGUI?)((obj is TextMeshProUGUI) ? obj : null)); } } [HarmonyPatch(typeof(EnergyUI), "Update")] [HarmonyPostfix] private static void EnergyUI_Update_Postfix(EnergyUI __instance) { if (SemiFunc.RunIsShop()) { if (_energyUITextField == null) { _energyUITextField = typeof(EnergyUI).GetField("Text", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); } object? obj = _energyUITextField?.GetValue(__instance); DrawPowerBar((TextMeshProUGUI?)((obj is TextMeshProUGUI) ? obj : null)); } } [HarmonyPatch(typeof(ItemEquippable), "StateIdle")] [HarmonyPrefix] private static bool ItemEquippable_StateIdle_Prefix(ItemEquippable __instance) { if (!IsRecharging) { return true; } PlayerController instance = PlayerController.instance; if ((Object)(object)instance == (Object)null) { return true; } GameObject physGrabObject = instance.physGrabObject; if ((Object)(object)physGrabObject == (Object)null) { return true; } Transform val = physGrabObject.transform; while ((Object)(object)val.parent != (Object)null && (Object)(object)((Component)val.parent).GetComponent() != (Object)null) { val = val.parent; } if ((Object)(object)((Component)val).GetComponentInChildren(true) == (Object)(object)__instance) { if (DebugLog.Value) { Logger.LogInfo((object)"[PGR] ItemEquippable.StateIdle suppressed (recharging)"); } return false; } return true; } } }