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 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(".NETFramework,Version=v4.8", FrameworkDisplayName = "")]
[assembly: AssemblyCompany("HealthRegenMod")]
[assembly: AssemblyConfiguration("Debug")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0")]
[assembly: AssemblyProduct("HealthRegenMod")]
[assembly: AssemblyTitle("HealthRegenMod")]
[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;
}
}
}
[BepInPlugin("Xmods.healthregen", "HealthRegen", "2.8.7")]
public class HealthRegenMod : BaseUnityPlugin
{
[HarmonyPatch(typeof(PlayerHealth), "Start")]
public class RegenPatch
{
private static void Postfix(PlayerHealth __instance)
{
if ((Object)(object)__instance != (Object)null && (Object)(object)((Component)__instance).gameObject.GetComponent<RegenUpdater>() == (Object)null)
{
((Component)__instance).gameObject.AddComponent<RegenUpdater>().Init(__instance);
Log.LogInfo((object)$"[{DateTime.Now:HH:mm:ss}] [Patch] RegenUpdater attached to {((Object)__instance).name}.");
}
}
}
public class RegenUpdater : MonoBehaviour
{
private bool isRegenActive = false;
private int lastKnownLocalHealth;
private PlayerHealth playerHealth;
private FieldInfo healthField;
private FieldInfo maxHealthField;
private FieldInfo playerAvatarField;
private PhotonView playerPhotonView;
private int currentRegenInterval;
public void Init(PlayerHealth instance)
{
playerHealth = instance;
Type type = ((object)playerHealth).GetType();
healthField = type.GetField("health", BindingFlags.Instance | BindingFlags.NonPublic);
maxHealthField = type.GetField("maxHealth", BindingFlags.Instance | BindingFlags.NonPublic);
playerAvatarField = type.GetField("playerAvatar", BindingFlags.Instance | BindingFlags.NonPublic);
playerPhotonView = ((Component)playerHealth).GetComponent<PhotonView>();
if (healthField != null)
{
lastKnownLocalHealth = (int)healthField.GetValue(playerHealth);
}
currentRegenInterval = BaseRegenIntervalSeconds.Value;
LogInfo("[Init] Reflection setup complete for " + GetNickname(playerAvatarField?.GetValue(playerHealth)) + ".");
}
private void Start()
{
LogInfo("[Start] RegenUpdater Start() called for " + ((Object)playerHealth).name + ".");
}
private void Update()
{
if ((Object)(object)playerPhotonView != (Object)null && !playerPhotonView.IsMine)
{
return;
}
int num = (int)healthField.GetValue(playerHealth);
int num2 = (int)maxHealthField.GetValue(playerHealth);
if (num <= 0)
{
if (isRegenActive)
{
StopRegenCycle();
LogInfo("[Regen] " + GetNickname(playerAvatarField?.GetValue(playerHealth)) + " has 0 HP. Regen stopped.");
}
return;
}
if (num < num2 && !isRegenActive)
{
isRegenActive = true;
((MonoBehaviour)this).CancelInvoke("PerformRegenTick");
((MonoBehaviour)this).InvokeRepeating("PerformRegenTick", (float)currentRegenInterval, (float)currentRegenInterval);
LogInfo("[Regen] " + GetNickname(playerAvatarField?.GetValue(playerHealth)) + " is alive and not full HP. Starting regen.");
}
if (isRegenActive && num >= num2)
{
StopRegenCycle();
LogInfo($"[Regen] {GetNickname(playerAvatarField?.GetValue(playerHealth))} reached max HP ({num2}). Regen cycle stopped.");
}
}
private void PerformRegenTick()
{
int num = (int)healthField.GetValue(playerHealth);
int num2 = (int)maxHealthField.GetValue(playerHealth);
object avatarObj = playerAvatarField?.GetValue(playerHealth);
string nickname = GetNickname(avatarObj);
if (!isRegenActive || num == 0)
{
StopRegenCycle();
LogInfo("[Regen] Regen canceled. Reason: " + ((num == 0) ? "Health is 0" : "Regen inactive") + ".");
return;
}
if (num >= num2)
{
StopRegenCycle();
LogInfo($"[Regen] {nickname} reached max HP ({num2}). Regen cycle stopped.");
return;
}
int value = RegenAmountPerTick.Value;
int num3 = Mathf.Min(num + value, num2);
if (PhotonNetwork.IsConnected && (Object)(object)playerPhotonView != (Object)null)
{
playerPhotonView.RPC("UpdateHealthRPC", (RpcTarget)0, new object[3] { num3, num2, false });
}
else
{
healthField.SetValue(playerHealth, num3);
}
LogInfo($"[Regen] {nickname} → +{value} → {num3}/{num2}");
}
private void StopRegenCycle()
{
isRegenActive = false;
((MonoBehaviour)this).CancelInvoke("PerformRegenTick");
}
private string GetNickname(object avatarObj)
{
try
{
PlayerAvatar val = (PlayerAvatar)((avatarObj is PlayerAvatar) ? avatarObj : null);
if ((Object)(object)val != (Object)null && (Object)(object)val.photonView != (Object)null && val.photonView.Owner != null)
{
return val.photonView.Owner.NickName;
}
return "Unknown/Local";
}
catch
{
return "Unknown/Local";
}
}
private void LogInfo(string msg)
{
if (DebugLoggingEnabled.Value)
{
Log.LogInfo((object)$"[{DateTime.Now:HH:mm:ss}] {msg}");
}
}
}
public static ConfigEntry<int> BaseRegenIntervalSeconds;
public static ConfigEntry<int> RegenAmountPerTick;
public static ConfigEntry<bool> DebugLoggingEnabled;
internal static ManualLogSource Log;
private void Awake()
{
//IL_0041: Unknown result type (might be due to invalid IL or missing references)
//IL_004b: Expected O, but got Unknown
//IL_0073: Unknown result type (might be due to invalid IL or missing references)
//IL_007d: Expected O, but got Unknown
//IL_00a7: Unknown result type (might be due to invalid IL or missing references)
//IL_00ad: Expected O, but got Unknown
Log = ((BaseUnityPlugin)this).Logger;
((BaseUnityPlugin)this).Logger.LogInfo((object)"[Init] HealthRegen is loading...");
BaseRegenIntervalSeconds = ((BaseUnityPlugin)this).Config.Bind<int>("Regen Settings", "BaseRegenIntervalSeconds", 20, new ConfigDescription("Time in seconds after damage before regen starts.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 20), Array.Empty<object>()));
RegenAmountPerTick = ((BaseUnityPlugin)this).Config.Bind<int>("Regen Settings", "RegenAmountPerTick", 1, new ConfigDescription("Amount of HP restored per regen tick.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 50), Array.Empty<object>()));
DebugLoggingEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("Debug Settings", "DebugLoggingEnabled", false, "Enable debug log output.");
Harmony val = new Harmony("Xmods.healthregen");
val.PatchAll();
((BaseUnityPlugin)this).Logger.LogInfo((object)"[Init] Patching complete.");
}
}