Decompiled source of PlayerHealthRegen v1.0.1

build/PlayerHealthRegen.dll

Decompiled a week ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Configuration;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using Photon.Pun;
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("PlayerHealthRegen")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0")]
[assembly: AssemblyProduct("PlayerHealthRegen")]
[assembly: AssemblyTitle("PlayerHealthRegen")]
[assembly: AssemblyVersion("1.0.0.0")]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[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 BridgeGPT.PlayerHealthRegen
{
	[BepInPlugin("com.bridgegpt.repo.playerhealthregen", "Player Health Regen", "1.0.1")]
	public sealed class Plugin : BaseUnityPlugin
	{
		public const string PluginGuid = "com.bridgegpt.repo.playerhealthregen";

		public const string PluginName = "Player Health Regen";

		public const string PluginVersion = "1.0.1";

		private ConfigEntry<bool> _enabled;

		private ConfigEntry<int> _healAmount;

		private ConfigEntry<float> _interval;

		private ConfigEntry<bool> _hostOnly;

		private readonly Dictionary<int, float> _nextHealAt = new Dictionary<int, float>();

		private float _nextScanAt;

		private float _nextErrorLogAt;

		private static readonly FieldInfo HealthField = AccessTools.Field(typeof(PlayerHealth), "health");

		private static readonly FieldInfo MaxHealthField = AccessTools.Field(typeof(PlayerHealth), "maxHealth");

		private static readonly FieldInfo PlayerAvatarField = AccessTools.Field(typeof(PlayerHealth), "playerAvatar");

		private static readonly FieldInfo AvatarDisabledField = AccessTools.Field(typeof(PlayerAvatar), "isDisabled");

		private void Awake()
		{
			//IL_0045: Unknown result type (might be due to invalid IL or missing references)
			//IL_004f: Expected O, but got Unknown
			//IL_0083: Unknown result type (might be due to invalid IL or missing references)
			//IL_008d: Expected O, but got Unknown
			_enabled = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "Enabled", true, "Enable gradual health regeneration.");
			_healAmount = ((BaseUnityPlugin)this).Config.Bind<int>("General", "HealAmount", 1, new ConfigDescription("Health restored per tick.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 25), Array.Empty<object>()));
			_interval = ((BaseUnityPlugin)this).Config.Bind<float>("General", "IntervalSeconds", 5f, new ConfigDescription("Seconds between regeneration ticks.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.5f, 120f), Array.Empty<object>()));
			_hostOnly = ((BaseUnityPlugin)this).Config.Bind<bool>("Multiplayer", "HostOnly", true, "Only the host performs the regeneration scan in multiplayer.");
			((BaseUnityPlugin)this).Logger.LogInfo((object)"Player Health Regen 1.0.1 loaded. Safe gameplay-state and avatar checks enabled.");
		}

		private void Update()
		{
			//IL_005a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0060: Invalid comparison between Unknown and I4
			if (!_enabled.Value || Time.unscaledTime < _nextScanAt)
			{
				return;
			}
			_nextScanAt = Time.unscaledTime + 0.25f;
			if ((PhotonNetwork.InRoom && _hostOnly.Value && !PhotonNetwork.IsMasterClient) || (Object)(object)GameDirector.instance == (Object)null || (int)GameDirector.instance.currentState != 2 || (Object)(object)StatsManager.instance == (Object)null)
			{
				return;
			}
			try
			{
				PlayerHealth[] array = Object.FindObjectsByType<PlayerHealth>((FindObjectsSortMode)0);
				HashSet<int> hashSet = new HashSet<int>();
				PlayerHealth[] array2 = array;
				foreach (PlayerHealth val in array2)
				{
					if (IsReadyForHealing(val))
					{
						int instanceID = ((Object)val).GetInstanceID();
						hashSet.Add(instanceID);
						int num = ReadInt(HealthField, val);
						int num2 = ReadInt(MaxHealthField, val);
						float value;
						if (num <= 0 || num2 <= 0 || num >= num2)
						{
							_nextHealAt.Remove(instanceID);
						}
						else if (!_nextHealAt.TryGetValue(instanceID, out value) || !(Time.unscaledTime < value))
						{
							val.HealOther(_healAmount.Value, false);
							_nextHealAt[instanceID] = Time.unscaledTime + _interval.Value;
						}
					}
				}
				if (_nextHealAt.Count <= hashSet.Count + 8)
				{
					return;
				}
				List<int> list = new List<int>();
				foreach (int key in _nextHealAt.Keys)
				{
					if (!hashSet.Contains(key))
					{
						list.Add(key);
					}
				}
				foreach (int item in list)
				{
					_nextHealAt.Remove(item);
				}
			}
			catch (Exception ex)
			{
				if (Time.unscaledTime >= _nextErrorLogAt)
				{
					((BaseUnityPlugin)this).Logger.LogError((object)("Regeneration scan failed (logging throttled to once per 10 seconds): " + ex));
					_nextErrorLogAt = Time.unscaledTime + 10f;
				}
			}
		}

		private static bool IsReadyForHealing(PlayerHealth health)
		{
			if ((Object)(object)health == (Object)null || !((Component)health).gameObject.activeInHierarchy || health.isMenuAvatar)
			{
				return false;
			}
			if (PlayerAvatarField == null)
			{
				return false;
			}
			object? value = PlayerAvatarField.GetValue(health);
			PlayerAvatar val = (PlayerAvatar)((value is PlayerAvatar) ? value : null);
			if ((Object)(object)val == (Object)null || !((Component)val).gameObject.activeInHierarchy || (Object)(object)val.playerCosmetics == (Object)null)
			{
				return false;
			}
			if (AvatarDisabledField != null && (bool)AvatarDisabledField.GetValue(val))
			{
				return false;
			}
			if (GameManager.Multiplayer())
			{
				PhotonView component = ((Component)health).GetComponent<PhotonView>();
				if ((Object)(object)component == (Object)null || component.ViewID == 0)
				{
					return false;
				}
			}
			return true;
		}

		private static int ReadInt(FieldInfo field, object instance)
		{
			if (field == null || instance == null)
			{
				return 0;
			}
			object value = field.GetValue(instance);
			if (value is int)
			{
				return (int)value;
			}
			return 0;
		}
	}
}

package/PlayerHealthRegen.dll

Decompiled a week ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Configuration;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using Photon.Pun;
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("PlayerHealthRegen")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0")]
[assembly: AssemblyProduct("PlayerHealthRegen")]
[assembly: AssemblyTitle("PlayerHealthRegen")]
[assembly: AssemblyVersion("1.0.0.0")]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[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 BridgeGPT.PlayerHealthRegen
{
	[BepInPlugin("com.bridgegpt.repo.playerhealthregen", "Player Health Regen", "1.0.1")]
	public sealed class Plugin : BaseUnityPlugin
	{
		public const string PluginGuid = "com.bridgegpt.repo.playerhealthregen";

		public const string PluginName = "Player Health Regen";

		public const string PluginVersion = "1.0.1";

		private ConfigEntry<bool> _enabled;

		private ConfigEntry<int> _healAmount;

		private ConfigEntry<float> _interval;

		private ConfigEntry<bool> _hostOnly;

		private readonly Dictionary<int, float> _nextHealAt = new Dictionary<int, float>();

		private float _nextScanAt;

		private float _nextErrorLogAt;

		private static readonly FieldInfo HealthField = AccessTools.Field(typeof(PlayerHealth), "health");

		private static readonly FieldInfo MaxHealthField = AccessTools.Field(typeof(PlayerHealth), "maxHealth");

		private static readonly FieldInfo PlayerAvatarField = AccessTools.Field(typeof(PlayerHealth), "playerAvatar");

		private static readonly FieldInfo AvatarDisabledField = AccessTools.Field(typeof(PlayerAvatar), "isDisabled");

		private void Awake()
		{
			//IL_0045: Unknown result type (might be due to invalid IL or missing references)
			//IL_004f: Expected O, but got Unknown
			//IL_0083: Unknown result type (might be due to invalid IL or missing references)
			//IL_008d: Expected O, but got Unknown
			_enabled = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "Enabled", true, "Enable gradual health regeneration.");
			_healAmount = ((BaseUnityPlugin)this).Config.Bind<int>("General", "HealAmount", 1, new ConfigDescription("Health restored per tick.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 25), Array.Empty<object>()));
			_interval = ((BaseUnityPlugin)this).Config.Bind<float>("General", "IntervalSeconds", 5f, new ConfigDescription("Seconds between regeneration ticks.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.5f, 120f), Array.Empty<object>()));
			_hostOnly = ((BaseUnityPlugin)this).Config.Bind<bool>("Multiplayer", "HostOnly", true, "Only the host performs the regeneration scan in multiplayer.");
			((BaseUnityPlugin)this).Logger.LogInfo((object)"Player Health Regen 1.0.1 loaded. Safe gameplay-state and avatar checks enabled.");
		}

		private void Update()
		{
			//IL_005a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0060: Invalid comparison between Unknown and I4
			if (!_enabled.Value || Time.unscaledTime < _nextScanAt)
			{
				return;
			}
			_nextScanAt = Time.unscaledTime + 0.25f;
			if ((PhotonNetwork.InRoom && _hostOnly.Value && !PhotonNetwork.IsMasterClient) || (Object)(object)GameDirector.instance == (Object)null || (int)GameDirector.instance.currentState != 2 || (Object)(object)StatsManager.instance == (Object)null)
			{
				return;
			}
			try
			{
				PlayerHealth[] array = Object.FindObjectsByType<PlayerHealth>((FindObjectsSortMode)0);
				HashSet<int> hashSet = new HashSet<int>();
				PlayerHealth[] array2 = array;
				foreach (PlayerHealth val in array2)
				{
					if (IsReadyForHealing(val))
					{
						int instanceID = ((Object)val).GetInstanceID();
						hashSet.Add(instanceID);
						int num = ReadInt(HealthField, val);
						int num2 = ReadInt(MaxHealthField, val);
						float value;
						if (num <= 0 || num2 <= 0 || num >= num2)
						{
							_nextHealAt.Remove(instanceID);
						}
						else if (!_nextHealAt.TryGetValue(instanceID, out value) || !(Time.unscaledTime < value))
						{
							val.HealOther(_healAmount.Value, false);
							_nextHealAt[instanceID] = Time.unscaledTime + _interval.Value;
						}
					}
				}
				if (_nextHealAt.Count <= hashSet.Count + 8)
				{
					return;
				}
				List<int> list = new List<int>();
				foreach (int key in _nextHealAt.Keys)
				{
					if (!hashSet.Contains(key))
					{
						list.Add(key);
					}
				}
				foreach (int item in list)
				{
					_nextHealAt.Remove(item);
				}
			}
			catch (Exception ex)
			{
				if (Time.unscaledTime >= _nextErrorLogAt)
				{
					((BaseUnityPlugin)this).Logger.LogError((object)("Regeneration scan failed (logging throttled to once per 10 seconds): " + ex));
					_nextErrorLogAt = Time.unscaledTime + 10f;
				}
			}
		}

		private static bool IsReadyForHealing(PlayerHealth health)
		{
			if ((Object)(object)health == (Object)null || !((Component)health).gameObject.activeInHierarchy || health.isMenuAvatar)
			{
				return false;
			}
			if (PlayerAvatarField == null)
			{
				return false;
			}
			object? value = PlayerAvatarField.GetValue(health);
			PlayerAvatar val = (PlayerAvatar)((value is PlayerAvatar) ? value : null);
			if ((Object)(object)val == (Object)null || !((Component)val).gameObject.activeInHierarchy || (Object)(object)val.playerCosmetics == (Object)null)
			{
				return false;
			}
			if (AvatarDisabledField != null && (bool)AvatarDisabledField.GetValue(val))
			{
				return false;
			}
			if (GameManager.Multiplayer())
			{
				PhotonView component = ((Component)health).GetComponent<PhotonView>();
				if ((Object)(object)component == (Object)null || component.ViewID == 0)
				{
					return false;
				}
			}
			return true;
		}

		private static int ReadInt(FieldInfo field, object instance)
		{
			if (field == null || instance == null)
			{
				return 0;
			}
			object value = field.GetValue(instance);
			if (value is int)
			{
				return (int)value;
			}
			return 0;
		}
	}
}

PlayerHealthRegen.dll

Decompiled a week ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Configuration;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using Photon.Pun;
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("PlayerHealthRegen")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0")]
[assembly: AssemblyProduct("PlayerHealthRegen")]
[assembly: AssemblyTitle("PlayerHealthRegen")]
[assembly: AssemblyVersion("1.0.0.0")]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[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 BridgeGPT.PlayerHealthRegen
{
	[BepInPlugin("com.bridgegpt.repo.playerhealthregen", "Player Health Regen", "1.0.1")]
	public sealed class Plugin : BaseUnityPlugin
	{
		public const string PluginGuid = "com.bridgegpt.repo.playerhealthregen";

		public const string PluginName = "Player Health Regen";

		public const string PluginVersion = "1.0.1";

		private ConfigEntry<bool> _enabled;

		private ConfigEntry<int> _healAmount;

		private ConfigEntry<float> _interval;

		private ConfigEntry<bool> _hostOnly;

		private readonly Dictionary<int, float> _nextHealAt = new Dictionary<int, float>();

		private float _nextScanAt;

		private float _nextErrorLogAt;

		private static readonly FieldInfo HealthField = AccessTools.Field(typeof(PlayerHealth), "health");

		private static readonly FieldInfo MaxHealthField = AccessTools.Field(typeof(PlayerHealth), "maxHealth");

		private static readonly FieldInfo PlayerAvatarField = AccessTools.Field(typeof(PlayerHealth), "playerAvatar");

		private static readonly FieldInfo AvatarDisabledField = AccessTools.Field(typeof(PlayerAvatar), "isDisabled");

		private void Awake()
		{
			//IL_0045: Unknown result type (might be due to invalid IL or missing references)
			//IL_004f: Expected O, but got Unknown
			//IL_0083: Unknown result type (might be due to invalid IL or missing references)
			//IL_008d: Expected O, but got Unknown
			_enabled = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "Enabled", true, "Enable gradual health regeneration.");
			_healAmount = ((BaseUnityPlugin)this).Config.Bind<int>("General", "HealAmount", 1, new ConfigDescription("Health restored per tick.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 25), Array.Empty<object>()));
			_interval = ((BaseUnityPlugin)this).Config.Bind<float>("General", "IntervalSeconds", 5f, new ConfigDescription("Seconds between regeneration ticks.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.5f, 120f), Array.Empty<object>()));
			_hostOnly = ((BaseUnityPlugin)this).Config.Bind<bool>("Multiplayer", "HostOnly", true, "Only the host performs the regeneration scan in multiplayer.");
			((BaseUnityPlugin)this).Logger.LogInfo((object)"Player Health Regen 1.0.1 loaded. Safe gameplay-state and avatar checks enabled.");
		}

		private void Update()
		{
			//IL_005a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0060: Invalid comparison between Unknown and I4
			if (!_enabled.Value || Time.unscaledTime < _nextScanAt)
			{
				return;
			}
			_nextScanAt = Time.unscaledTime + 0.25f;
			if ((PhotonNetwork.InRoom && _hostOnly.Value && !PhotonNetwork.IsMasterClient) || (Object)(object)GameDirector.instance == (Object)null || (int)GameDirector.instance.currentState != 2 || (Object)(object)StatsManager.instance == (Object)null)
			{
				return;
			}
			try
			{
				PlayerHealth[] array = Object.FindObjectsByType<PlayerHealth>((FindObjectsSortMode)0);
				HashSet<int> hashSet = new HashSet<int>();
				PlayerHealth[] array2 = array;
				foreach (PlayerHealth val in array2)
				{
					if (IsReadyForHealing(val))
					{
						int instanceID = ((Object)val).GetInstanceID();
						hashSet.Add(instanceID);
						int num = ReadInt(HealthField, val);
						int num2 = ReadInt(MaxHealthField, val);
						float value;
						if (num <= 0 || num2 <= 0 || num >= num2)
						{
							_nextHealAt.Remove(instanceID);
						}
						else if (!_nextHealAt.TryGetValue(instanceID, out value) || !(Time.unscaledTime < value))
						{
							val.HealOther(_healAmount.Value, false);
							_nextHealAt[instanceID] = Time.unscaledTime + _interval.Value;
						}
					}
				}
				if (_nextHealAt.Count <= hashSet.Count + 8)
				{
					return;
				}
				List<int> list = new List<int>();
				foreach (int key in _nextHealAt.Keys)
				{
					if (!hashSet.Contains(key))
					{
						list.Add(key);
					}
				}
				foreach (int item in list)
				{
					_nextHealAt.Remove(item);
				}
			}
			catch (Exception ex)
			{
				if (Time.unscaledTime >= _nextErrorLogAt)
				{
					((BaseUnityPlugin)this).Logger.LogError((object)("Regeneration scan failed (logging throttled to once per 10 seconds): " + ex));
					_nextErrorLogAt = Time.unscaledTime + 10f;
				}
			}
		}

		private static bool IsReadyForHealing(PlayerHealth health)
		{
			if ((Object)(object)health == (Object)null || !((Component)health).gameObject.activeInHierarchy || health.isMenuAvatar)
			{
				return false;
			}
			if (PlayerAvatarField == null)
			{
				return false;
			}
			object? value = PlayerAvatarField.GetValue(health);
			PlayerAvatar val = (PlayerAvatar)((value is PlayerAvatar) ? value : null);
			if ((Object)(object)val == (Object)null || !((Component)val).gameObject.activeInHierarchy || (Object)(object)val.playerCosmetics == (Object)null)
			{
				return false;
			}
			if (AvatarDisabledField != null && (bool)AvatarDisabledField.GetValue(val))
			{
				return false;
			}
			if (GameManager.Multiplayer())
			{
				PhotonView component = ((Component)health).GetComponent<PhotonView>();
				if ((Object)(object)component == (Object)null || component.ViewID == 0)
				{
					return false;
				}
			}
			return true;
		}

		private static int ReadInt(FieldInfo field, object instance)
		{
			if (field == null || instance == null)
			{
				return 0;
			}
			object value = field.GetValue(instance);
			if (value is int)
			{
				return (int)value;
			}
			return 0;
		}
	}
}

src/obj/Release/netstandard2.1/PlayerHealthRegen.dll

Decompiled a week ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Configuration;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using Photon.Pun;
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("PlayerHealthRegen")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0")]
[assembly: AssemblyProduct("PlayerHealthRegen")]
[assembly: AssemblyTitle("PlayerHealthRegen")]
[assembly: AssemblyVersion("1.0.0.0")]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[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 BridgeGPT.PlayerHealthRegen
{
	[BepInPlugin("com.bridgegpt.repo.playerhealthregen", "Player Health Regen", "1.0.1")]
	public sealed class Plugin : BaseUnityPlugin
	{
		public const string PluginGuid = "com.bridgegpt.repo.playerhealthregen";

		public const string PluginName = "Player Health Regen";

		public const string PluginVersion = "1.0.1";

		private ConfigEntry<bool> _enabled;

		private ConfigEntry<int> _healAmount;

		private ConfigEntry<float> _interval;

		private ConfigEntry<bool> _hostOnly;

		private readonly Dictionary<int, float> _nextHealAt = new Dictionary<int, float>();

		private float _nextScanAt;

		private float _nextErrorLogAt;

		private static readonly FieldInfo HealthField = AccessTools.Field(typeof(PlayerHealth), "health");

		private static readonly FieldInfo MaxHealthField = AccessTools.Field(typeof(PlayerHealth), "maxHealth");

		private static readonly FieldInfo PlayerAvatarField = AccessTools.Field(typeof(PlayerHealth), "playerAvatar");

		private static readonly FieldInfo AvatarDisabledField = AccessTools.Field(typeof(PlayerAvatar), "isDisabled");

		private void Awake()
		{
			//IL_0045: Unknown result type (might be due to invalid IL or missing references)
			//IL_004f: Expected O, but got Unknown
			//IL_0083: Unknown result type (might be due to invalid IL or missing references)
			//IL_008d: Expected O, but got Unknown
			_enabled = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "Enabled", true, "Enable gradual health regeneration.");
			_healAmount = ((BaseUnityPlugin)this).Config.Bind<int>("General", "HealAmount", 1, new ConfigDescription("Health restored per tick.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 25), Array.Empty<object>()));
			_interval = ((BaseUnityPlugin)this).Config.Bind<float>("General", "IntervalSeconds", 5f, new ConfigDescription("Seconds between regeneration ticks.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.5f, 120f), Array.Empty<object>()));
			_hostOnly = ((BaseUnityPlugin)this).Config.Bind<bool>("Multiplayer", "HostOnly", true, "Only the host performs the regeneration scan in multiplayer.");
			((BaseUnityPlugin)this).Logger.LogInfo((object)"Player Health Regen 1.0.1 loaded. Safe gameplay-state and avatar checks enabled.");
		}

		private void Update()
		{
			//IL_005a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0060: Invalid comparison between Unknown and I4
			if (!_enabled.Value || Time.unscaledTime < _nextScanAt)
			{
				return;
			}
			_nextScanAt = Time.unscaledTime + 0.25f;
			if ((PhotonNetwork.InRoom && _hostOnly.Value && !PhotonNetwork.IsMasterClient) || (Object)(object)GameDirector.instance == (Object)null || (int)GameDirector.instance.currentState != 2 || (Object)(object)StatsManager.instance == (Object)null)
			{
				return;
			}
			try
			{
				PlayerHealth[] array = Object.FindObjectsByType<PlayerHealth>((FindObjectsSortMode)0);
				HashSet<int> hashSet = new HashSet<int>();
				PlayerHealth[] array2 = array;
				foreach (PlayerHealth val in array2)
				{
					if (IsReadyForHealing(val))
					{
						int instanceID = ((Object)val).GetInstanceID();
						hashSet.Add(instanceID);
						int num = ReadInt(HealthField, val);
						int num2 = ReadInt(MaxHealthField, val);
						float value;
						if (num <= 0 || num2 <= 0 || num >= num2)
						{
							_nextHealAt.Remove(instanceID);
						}
						else if (!_nextHealAt.TryGetValue(instanceID, out value) || !(Time.unscaledTime < value))
						{
							val.HealOther(_healAmount.Value, false);
							_nextHealAt[instanceID] = Time.unscaledTime + _interval.Value;
						}
					}
				}
				if (_nextHealAt.Count <= hashSet.Count + 8)
				{
					return;
				}
				List<int> list = new List<int>();
				foreach (int key in _nextHealAt.Keys)
				{
					if (!hashSet.Contains(key))
					{
						list.Add(key);
					}
				}
				foreach (int item in list)
				{
					_nextHealAt.Remove(item);
				}
			}
			catch (Exception ex)
			{
				if (Time.unscaledTime >= _nextErrorLogAt)
				{
					((BaseUnityPlugin)this).Logger.LogError((object)("Regeneration scan failed (logging throttled to once per 10 seconds): " + ex));
					_nextErrorLogAt = Time.unscaledTime + 10f;
				}
			}
		}

		private static bool IsReadyForHealing(PlayerHealth health)
		{
			if ((Object)(object)health == (Object)null || !((Component)health).gameObject.activeInHierarchy || health.isMenuAvatar)
			{
				return false;
			}
			if (PlayerAvatarField == null)
			{
				return false;
			}
			object? value = PlayerAvatarField.GetValue(health);
			PlayerAvatar val = (PlayerAvatar)((value is PlayerAvatar) ? value : null);
			if ((Object)(object)val == (Object)null || !((Component)val).gameObject.activeInHierarchy || (Object)(object)val.playerCosmetics == (Object)null)
			{
				return false;
			}
			if (AvatarDisabledField != null && (bool)AvatarDisabledField.GetValue(val))
			{
				return false;
			}
			if (GameManager.Multiplayer())
			{
				PhotonView component = ((Component)health).GetComponent<PhotonView>();
				if ((Object)(object)component == (Object)null || component.ViewID == 0)
				{
					return false;
				}
			}
			return true;
		}

		private static int ReadInt(FieldInfo field, object instance)
		{
			if (field == null || instance == null)
			{
				return 0;
			}
			object value = field.GetValue(instance);
			if (value is int)
			{
				return (int)value;
			}
			return 0;
		}
	}
}