Decompiled source of Regen v2.8.7

HealthRegenMod.dll

Decompiled 6 months ago
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.");
	}
}