Decompiled source of HealthRegenMod v1.1.4

HealthRegenMod.dll

Decompiled 17 hours 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 UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: AssemblyTitle("HealthRegenMod")]
[assembly: AssemblyDescription("Health regeneration mod with god mode and one-shot protection")]
[assembly: AssemblyCompany("hyy")]
[assembly: AssemblyProduct("HealthRegenMod")]
[assembly: AssemblyFileVersion("1.1.4.0")]
[assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.1.4.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 HealthRegenMod
{
	public static class HealthRegenAPI
	{
		public static bool SetMaxHealth(int maxHealth)
		{
			try
			{
				if (maxHealth < 1 || maxHealth > 10000000)
				{
					if (PluginConfig.EnableLogging.Value)
					{
						Plugin.ModLog.LogError((object)$"SetMaxHealth: Value {maxHealth} out of range (1-10000000)");
					}
					return false;
				}
				PluginConfig.MaxHealth.Value = maxHealth;
				if (PluginConfig.EnableLogging.Value)
				{
					Plugin.ModLog.LogInfo((object)$"API: MaxHealth set to {maxHealth}");
				}
				return true;
			}
			catch (Exception ex)
			{
				if (PluginConfig.EnableLogging.Value)
				{
					Plugin.ModLog.LogError((object)("API: SetMaxHealth error: " + ex.Message));
				}
				return false;
			}
		}

		public static int GetMaxHealth()
		{
			return PluginConfig.MaxHealth.Value;
		}

		public static bool SetGodMode(bool enabled)
		{
			try
			{
				PluginConfig.EnableGodMode.Value = enabled;
				if (PluginConfig.EnableLogging.Value)
				{
					Plugin.ModLog.LogInfo((object)$"API: GodMode set to {enabled}");
				}
				return true;
			}
			catch (Exception ex)
			{
				if (PluginConfig.EnableLogging.Value)
				{
					Plugin.ModLog.LogError((object)("API: SetGodMode error: " + ex.Message));
				}
				return false;
			}
		}

		public static bool GetGodMode()
		{
			return PluginConfig.EnableGodMode.Value;
		}

		public static bool SetHealthRegenRate(int regenAmount)
		{
			try
			{
				if (regenAmount < 0 || regenAmount > 1000)
				{
					if (PluginConfig.EnableLogging.Value)
					{
						Plugin.ModLog.LogError((object)$"SetHealthRegenRate: Value {regenAmount} out of range (0-1000)");
					}
					return false;
				}
				PluginConfig.HealthRegenPerFrame.Value = regenAmount;
				if (PluginConfig.EnableLogging.Value)
				{
					Plugin.ModLog.LogInfo((object)$"API: HealthRegenRate set to {regenAmount}");
				}
				return true;
			}
			catch (Exception ex)
			{
				if (PluginConfig.EnableLogging.Value)
				{
					Plugin.ModLog.LogError((object)("API: SetHealthRegenRate error: " + ex.Message));
				}
				return false;
			}
		}

		public static int GetHealthRegenRate()
		{
			return PluginConfig.HealthRegenPerFrame.Value;
		}

		public static bool SetPlayerHealth(int health)
		{
			try
			{
				Type type = Type.GetType("PlayerHealth, Assembly-CSharp");
				if (type == null)
				{
					if (PluginConfig.EnableLogging.Value)
					{
						Plugin.ModLog.LogError((object)"API: PlayerHealth type not found");
					}
					return false;
				}
				Object val = Object.FindObjectOfType(type);
				if (val == (Object)null)
				{
					if (PluginConfig.EnableLogging.Value)
					{
						Plugin.ModLog.LogError((object)"API: PlayerHealth instance not found");
					}
					return false;
				}
				FieldInfo field = type.GetField("health", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
				if (field == null)
				{
					if (PluginConfig.EnableLogging.Value)
					{
						Plugin.ModLog.LogError((object)"API: health field not found");
					}
					return false;
				}
				field.SetValue(val, health);
				if (PluginConfig.EnableLogging.Value)
				{
					Plugin.ModLog.LogInfo((object)$"API: Player health set to {health}");
				}
				return true;
			}
			catch (Exception ex)
			{
				if (PluginConfig.EnableLogging.Value)
				{
					Plugin.ModLog.LogError((object)("API: SetPlayerHealth error: " + ex.Message));
				}
				return false;
			}
		}

		public static int GetPlayerHealth()
		{
			try
			{
				Type type = Type.GetType("PlayerHealth, Assembly-CSharp");
				if (type == null)
				{
					return -1;
				}
				Object val = Object.FindObjectOfType(type);
				if (val == (Object)null)
				{
					return -1;
				}
				FieldInfo field = type.GetField("health", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
				if (field == null)
				{
					return -1;
				}
				return (int)field.GetValue(val);
			}
			catch
			{
				return -1;
			}
		}

		public static bool SaveConfig()
		{
			try
			{
				if (PluginConfig.EnableLogging.Value)
				{
					Plugin.ModLog.LogInfo((object)"API: Configuration saved");
				}
				return true;
			}
			catch (Exception ex)
			{
				if (PluginConfig.EnableLogging.Value)
				{
					Plugin.ModLog.LogError((object)("API: SaveConfig error: " + ex.Message));
				}
				return false;
			}
		}
	}
	public static class PluginConfig
	{
		public static ConfigEntry<bool> EnableLogging { get; private set; }

		public static ConfigEntry<bool> EnableGodMode { get; private set; }

		public static ConfigEntry<int> MaxHealth { get; private set; }

		public static ConfigEntry<int> HealthRegenPerFrame { get; private set; }

		public static ConfigEntry<bool> ShowDebugInfo { get; private set; }

		public static ConfigEntry<bool> EnableOneShotProtection { get; private set; }

		public static ConfigEntry<int> OneShotMinHealth { get; private set; }

		public static ConfigEntry<int> MaxSingleDamage { get; private set; }

		public static void InitConfig(ConfigFile config)
		{
			//IL_005f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0069: Expected O, but got Unknown
			//IL_0090: Unknown result type (might be due to invalid IL or missing references)
			//IL_009a: Expected O, but got Unknown
			//IL_00f9: Unknown result type (might be due to invalid IL or missing references)
			//IL_0103: Expected O, but got Unknown
			//IL_012e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0138: Expected O, but got Unknown
			try
			{
				EnableLogging = config.Bind<bool>("General", "EnableLogging", false, "Enable logging to the console for debugging purposes");
				EnableGodMode = config.Bind<bool>("Gameplay", "EnableGodMode", true, "Enable god mode - health never decreases below max value");
				MaxHealth = config.Bind<int>("Gameplay", "MaxHealth", 10000, new ConfigDescription("Maximum health value for the player", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 10000000), Array.Empty<object>()));
				HealthRegenPerFrame = config.Bind<int>("Gameplay", "HealthRegenPerFrame", 0, new ConfigDescription("Amount of health regenerated per frame. Set to 0 for instant full heal when god mode is enabled", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 1000), Array.Empty<object>()));
				ShowDebugInfo = config.Bind<bool>("UI", "ShowDebugInfo", false, "Show debug information on screen (if supported by the game)");
				EnableOneShotProtection = config.Bind<bool>("Protection", "EnableOneShotProtection", true, "Prevent instant death from one-shot kills by limiting maximum damage taken");
				OneShotMinHealth = config.Bind<int>("Protection", "OneShotMinHealth", 1, new ConfigDescription("Minimum health to remain after taking massive damage (only works when one-shot protection is enabled)", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 1000), Array.Empty<object>()));
				MaxSingleDamage = config.Bind<int>("Protection", "MaxSingleDamage", 500, new ConfigDescription("Maximum damage that can be taken in a single hit. Damage exceeding this will be reduced (0 = unlimited)", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 10000), Array.Empty<object>()));
				if (EnableLogging.Value)
				{
					Plugin.ModLog.LogInfo((object)"Configuration initialized successfully");
				}
			}
			catch (Exception ex)
			{
				Plugin.ModLog.LogError((object)("Failed to initialize configuration: " + ex.Message));
				throw;
			}
		}
	}
	[BepInPlugin("hyy.HealthRegenMod", "HealthRegenMod", "1.1.4")]
	[BepInProcess("REPO.exe")]
	public class Plugin : BaseUnityPlugin
	{
		internal static ManualLogSource ModLog;

		private static Harmony _harmony;

		private void Awake()
		{
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0028: Expected O, but got Unknown
			ModLog = ((BaseUnityPlugin)this).Logger;
			try
			{
				PluginConfig.InitConfig(((BaseUnityPlugin)this).Config);
				_harmony = new Harmony("hyy.HealthRegenMod");
				_harmony.PatchAll(Assembly.GetExecutingAssembly());
				if (PluginConfig.EnableLogging.Value)
				{
					ModLog.LogInfo((object)"HealthRegenMod loaded successfully!");
					ModLog.LogInfo((object)$"Configuration loaded - MaxHealth: {PluginConfig.MaxHealth.Value}, GodMode: {PluginConfig.EnableGodMode.Value}, RegenPerFrame: {PluginConfig.HealthRegenPerFrame.Value}");
					ModLog.LogInfo((object)$"OneShotProtection: {PluginConfig.EnableOneShotProtection.Value}, MinHealth: {PluginConfig.OneShotMinHealth.Value}, MaxDamage: {PluginConfig.MaxSingleDamage.Value}");
					ModLog.LogInfo((object)"author: lingzhu");
					ModLog.LogInfo((object)"version: 1.1.4");
					ModLog.LogInfo((object)"==========================================");
				}
			}
			catch (Exception ex)
			{
				ModLog.LogError((object)("Load error: " + ex.Message));
			}
		}
	}
	[HarmonyPatch(typeof(PlayerHealth), "Start")]
	public class SetMaxHealthPatch
	{
		private static FieldInfo maxHealthField;

		[HarmonyPostfix]
		private static void Postfix(PlayerHealth __instance)
		{
			try
			{
				if (!PluginConfig.EnableGodMode.Value)
				{
					return;
				}
				if (maxHealthField == null)
				{
					maxHealthField = typeof(PlayerHealth).GetField("maxHealth", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
				}
				if (!((Object)(object)__instance != (Object)null) || !(maxHealthField != null))
				{
					return;
				}
				int value = PluginConfig.MaxHealth.Value;
				int num = (int)maxHealthField.GetValue(__instance);
				if (num != value)
				{
					maxHealthField.SetValue(__instance, value);
					if (PluginConfig.EnableLogging.Value)
					{
						Plugin.ModLog.LogInfo((object)$"Set max health to {value}");
					}
				}
			}
			catch (Exception ex)
			{
				if (PluginConfig.EnableLogging.Value)
				{
					Plugin.ModLog.LogError((object)("Error in SetMaxHealthPatch: " + ex.Message));
				}
			}
		}
	}
	[HarmonyPatch(typeof(PlayerHealth), "Update")]
	public class KeepHealthAtMaxPatch
	{
		private static FieldInfo healthField;

		private static FieldInfo maxHealthField;

		[HarmonyPrefix]
		private static void Prefix(PlayerHealth __instance)
		{
			try
			{
				if (healthField == null)
				{
					healthField = typeof(PlayerHealth).GetField("health", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
				}
				if (maxHealthField == null)
				{
					maxHealthField = typeof(PlayerHealth).GetField("maxHealth", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
				}
				if (!((Object)(object)__instance != (Object)null) || !(healthField != null) || !(maxHealthField != null))
				{
					return;
				}
				int num = (int)healthField.GetValue(__instance);
				int num2 = (int)maxHealthField.GetValue(__instance);
				int value = PluginConfig.MaxHealth.Value;
				if (num2 != value)
				{
					maxHealthField.SetValue(__instance, value);
					num2 = value;
				}
				if (PluginConfig.EnableGodMode.Value)
				{
					if (num < num2)
					{
						healthField.SetValue(__instance, num2);
						if (PluginConfig.EnableLogging.Value)
						{
							Plugin.ModLog.LogDebug((object)$"God mode active: Health restored to {num2}");
						}
					}
				}
				else
				{
					if (PluginConfig.HealthRegenPerFrame.Value <= 0)
					{
						return;
					}
					int value2 = PluginConfig.HealthRegenPerFrame.Value;
					int num3 = Mathf.Min(num + value2, num2);
					if (num3 != num)
					{
						healthField.SetValue(__instance, num3);
						if (PluginConfig.EnableLogging.Value)
						{
							Plugin.ModLog.LogDebug((object)$"Health regen: {num} -> {num3} (+{value2})");
						}
					}
				}
			}
			catch (Exception ex)
			{
				if (PluginConfig.EnableLogging.Value)
				{
					Plugin.ModLog.LogError((object)("Error in KeepHealthAtMaxPatch: " + ex.Message));
				}
			}
		}
	}
	[HarmonyPatch]
	public class OneShotProtectionPatch
	{
		private static MethodBase TargetMethod()
		{
			try
			{
				Type typeFromHandle = typeof(PlayerHealth);
				string[] array = new string[6] { "TakeDamage", "Damage", "ApplyDamage", "OnDamage", "ReceiveDamage", "Hit" };
				string[] array2 = array;
				foreach (string value in array2)
				{
					MethodInfo[] methods = typeFromHandle.GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
					MethodInfo[] array3 = methods;
					foreach (MethodInfo methodInfo in array3)
					{
						if (!methodInfo.Name.Equals(value, StringComparison.OrdinalIgnoreCase))
						{
							continue;
						}
						ParameterInfo[] parameters = methodInfo.GetParameters();
						ParameterInfo[] array4 = parameters;
						foreach (ParameterInfo parameterInfo in array4)
						{
							if (parameterInfo.ParameterType == typeof(int) || parameterInfo.ParameterType == typeof(float))
							{
								if (PluginConfig.EnableLogging.Value)
								{
									Plugin.ModLog.LogInfo((object)("Found damage method: " + methodInfo.Name));
								}
								return methodInfo;
							}
						}
					}
				}
				if (PluginConfig.EnableLogging.Value)
				{
					Plugin.ModLog.LogWarning((object)"No damage method found in PlayerHealth class");
				}
				return null;
			}
			catch (Exception ex)
			{
				if (PluginConfig.EnableLogging.Value)
				{
					Plugin.ModLog.LogError((object)("Error finding damage method: " + ex.Message));
				}
				return null;
			}
		}

		[HarmonyPrefix]
		private static bool Prefix(object __instance, ref object __0, ref object __1, ref object __2, ref object __3)
		{
			try
			{
				if (PluginConfig.EnableGodMode.Value)
				{
					return false;
				}
				if (!PluginConfig.EnableOneShotProtection.Value)
				{
					return true;
				}
				int num = 0;
				object[] array = new object[4] { __0, __1, __2, __3 };
				for (int i = 0; i < array.Length; i++)
				{
					if (array[i] != null)
					{
						if (array[i] is int num2)
						{
							num = num2;
							break;
						}
						if (array[i] is float num3)
						{
							num = (int)num3;
							break;
						}
					}
				}
				if (num <= 0)
				{
					return true;
				}
				int num4 = num;
				int value = PluginConfig.MaxSingleDamage.Value;
				int value2 = PluginConfig.OneShotMinHealth.Value;
				if (value > 0 && num > value)
				{
					num = value;
					if (PluginConfig.EnableLogging.Value)
					{
						Plugin.ModLog.LogInfo((object)$"One-shot protection: Reduced damage from {num4} to {value}");
					}
				}
				FieldInfo field = typeof(PlayerHealth).GetField("health", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
				FieldInfo field2 = typeof(PlayerHealth).GetField("maxHealth", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
				if (field != null && __instance != null)
				{
					int num5 = (int)field.GetValue(__instance);
					int value3 = PluginConfig.MaxHealth.Value;
					if (field2 != null)
					{
						value3 = (int)field2.GetValue(__instance);
					}
					int num6 = num5 - num;
					if (num6 < value2 && num6 > 0)
					{
						num = num5 - value2;
						if (PluginConfig.EnableLogging.Value)
						{
							Plugin.ModLog.LogInfo((object)$"One-shot protection: Adjusted damage to keep minimum {value2} health");
						}
					}
					else if (num6 <= 0)
					{
						num = 0;
						if (PluginConfig.EnableLogging.Value)
						{
							Plugin.ModLog.LogInfo((object)$"One-shot protection: Prevented fatal damage, kept {num5} health");
						}
					}
				}
				if (__0 is int)
				{
					__0 = num;
				}
				else if (__0 is float)
				{
					__0 = (float)num;
				}
				else if (__1 is int)
				{
					__1 = num;
				}
				else if (__1 is float)
				{
					__1 = (float)num;
				}
				else if (__2 is int)
				{
					__2 = num;
				}
				else if (__2 is float)
				{
					__2 = (float)num;
				}
				else if (__3 is int)
				{
					__3 = num;
				}
				else if (__3 is float)
				{
					__3 = (float)num;
				}
				return true;
			}
			catch (Exception ex)
			{
				if (PluginConfig.EnableLogging.Value)
				{
					Plugin.ModLog.LogError((object)("Error in OneShotProtectionPatch: " + ex.Message));
				}
				return true;
			}
		}
	}
}