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;
}
}
}
}