Decompiled source of FullHealth v1.5.2

FullHealth.dll

Decompiled a day ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using System.Threading;
using System.Threading.Tasks;
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.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("FullHealth")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.5.2.0")]
[assembly: AssemblyInformationalVersion("1.5.2+2ef5c2896593a4215c1847712611d35d8cc114f3")]
[assembly: AssemblyProduct("FullHealth")]
[assembly: AssemblyTitle("FullHealth")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.5.2.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 FullHealth
{
	public static class Configuration
	{
		public static ConfigEntry<bool> Enabled { get; set; }

		public static ConfigEntry<decimal> Percent { get; set; }

		public static ConfigEntry<WorkMode> WorkMode { get; set; }

		public static ConfigEntry<HealMode> HealMode { get; set; }

		public static ConfigEntry<PhaseMode> PhaseMode { get; set; }

		public static ConfigEntry<int> ExactValue { get; set; }

		public static ConfigEntry<HealthPackMode> HealthPackMode { get; set; }

		internal static int[] HealthPackModeValues { get; set; } = Array.Empty<int>();

	}
	public static class ConfigurationHelper
	{
		private static readonly HealthPackMode[] HealthPackModes = new HealthPackMode[3]
		{
			HealthPackMode.Small,
			HealthPackMode.Medium,
			HealthPackMode.Large
		};

		public static void Bind(ConfigFile config)
		{
			Configuration.Enabled = config.Bind<bool>("General", "Enabled", true, "Indicates whether the mod is enabled.");
			Configuration.Percent = config.Bind<decimal>("General", "Percent", 100m, "Percentage of maximum health to which the player will be healed (Min: 0, Max: 100).\r\nAttention! You must set the `PhaseMode` parameter to only one of `Level` or `Lobby`, not both. Otherwise, the healing will be done twice.\r\n");
			Configuration.WorkMode = config.Bind<WorkMode>("General", "WorkMode", WorkMode.Host, "Configures the work mode.\r\nWarning: You are using `HostAndClient` value for this parameter at your own risk.\r\nIt may stop working after future game updates.\r\nIf another lobby players do not agree with this parameter, do not use it.\r\nAlso, the `Percent` parameter may not work correctly with this parameter, since the host or other clients may also perform the heal.\r\nHost - works only on host.\r\nHostAndClient - works on host and client.\r\n");
			Configuration.HealMode = config.Bind<HealMode>("General", "HealMode", HealMode.All, "Configures the heal mode.\r\nAll - heal all.\r\nSelf - heal self.");
			Configuration.PhaseMode = config.Bind<PhaseMode>("General", "PhaseMode", PhaseMode.All, "Configures in which phases of the game health restoration will be triggered.\r\nLevel - when spawning in the level.\r\nShop - when spawning in the shop. Attention! Healing in the store does not affect the game.\r\nLobby - when spawning in the truck (not menu) before starting the next level.\r\nAll - in all phases.");
			Configuration.ExactValue = config.Bind<int>("General", "ExactValue", 0, "Sets the exact value to heal.\r\nAttention! You must set the `PhaseMode` parameter to only one of `Level` or `Lobby`, not both. Otherwise, the healing will be done twice.\r\nIf the value is `0`, then it is disabled.\r\nIt has priority over the `Percent` parameter.\r\nFor example, if you set the value to `15`, you will always receive 15 HP.");
			Configuration.HealthPackMode = config.Bind<HealthPackMode>("General", "HealthPackMode", HealthPackMode.None, "Sets healing value options to the same as in health packs, one of which will be applied randomly\r\nAttention! You must set the `PhaseMode` parameter to only one of `Level` or `Lobby`, not both. Otherwise, the healing will be done twice.\r\nIf the value is `None`, then it is disabled.\r\nIt has priority over the `Percent` and `ExactValue` parameters.\r\nFor example, if you set the value to `Medium, Large`, you will receive a random healing of 50HP or 100HP.\r\nSmall - heal 25 HP.\r\nMedium - heal 50 HP.\r\nLarge - heal 100 HP.");
			UpdateHealthPackModeValues();
			Configuration.HealthPackMode.SettingChanged += delegate
			{
				UpdateHealthPackModeValues();
			};
			decimal num = Math.Min(100m, Math.Max(0m, Configuration.Percent.Value));
			if (num != Configuration.Percent.Value)
			{
				Configuration.Percent.Value = num;
			}
			if (Configuration.ExactValue.Value < 0)
			{
				Configuration.ExactValue.Value = 0;
			}
		}

		private static void UpdateHealthPackModeValues()
		{
			List<int> list = new List<int>();
			using (IEnumerator<HealthPackMode> enumerator = HealthPackModes.Where((HealthPackMode x) => Configuration.HealthPackMode.Value.HasFlag(x)).GetEnumerator())
			{
				while (enumerator.MoveNext())
				{
					switch (enumerator.Current)
					{
					case HealthPackMode.Small:
						list.Add(25);
						break;
					case HealthPackMode.Medium:
						list.Add(50);
						break;
					case HealthPackMode.Large:
						list.Add(100);
						break;
					}
				}
			}
			Configuration.HealthPackModeValues = list.ToArray();
		}
	}
	public enum HealMode : byte
	{
		All,
		Self
	}
	[Flags]
	public enum HealthPackMode : byte
	{
		None = 0,
		Small = 1,
		Medium = 2,
		Large = 4,
		All = 7
	}
	[Flags]
	public enum PhaseMode : byte
	{
		Level = 1,
		Shop = 2,
		Lobby = 4,
		All = 7
	}
	public enum WorkMode : byte
	{
		Host,
		HostAndClient
	}
	public static class GamePhaseValidateHelper
	{
		public static bool IsValid()
		{
			PhaseMode? gamePhaseMode = GetGamePhaseMode();
			if (!gamePhaseMode.HasValue)
			{
				Plugin.Logger.LogDebug((object)"This is not a game phase");
				return false;
			}
			if (!Configuration.PhaseMode.Value.HasFlag(gamePhaseMode.Value))
			{
				Plugin.Logger.LogDebug((object)"Healing in this phase is disabled in the configuration");
				return false;
			}
			return true;
		}

		private static PhaseMode? GetGamePhaseMode()
		{
			if (SemiFunc.RunIsLevel())
			{
				return PhaseMode.Level;
			}
			if (SemiFunc.RunIsShop())
			{
				return PhaseMode.Shop;
			}
			if (SemiFunc.RunIsLobby())
			{
				return PhaseMode.Lobby;
			}
			return null;
		}
	}
	public static class HealHelper
	{
		public static async Task Heal()
		{
			if (!(await WaitHelper.Wait()))
			{
				return;
			}
			switch (Configuration.HealMode.Value)
			{
			case HealMode.All:
			{
				foreach (PlayerAvatar item in PlayersHelper.Get())
				{
					HealPlayerHelper.Heal(item);
				}
				break;
			}
			case HealMode.Self:
				if ((Object)(object)SemiFunc.PlayerAvatarLocal() == (Object)null)
				{
					Plugin.Logger.LogWarning((object)"An error occurred while retrieving data about yourself");
				}
				else
				{
					HealPlayerHelper.Heal(SemiFunc.PlayerAvatarLocal());
				}
				break;
			default:
				Plugin.Logger.LogWarning((object)"Unknown HealMode value");
				break;
			}
		}
	}
	public static class HealPlayerHelper
	{
		private static readonly Random Random = new Random();

		public static void Heal(PlayerAvatar player)
		{
			if ((Object)(object)player?.playerHealth == (Object)null)
			{
				Plugin.Logger.LogWarning((object)"Player or his health is not set");
				return;
			}
			int health = player.playerHealth.health;
			int[] healthPackModeValues = Configuration.HealthPackModeValues;
			int num2;
			if (healthPackModeValues != null && healthPackModeValues.Length > 0)
			{
				int num = ((Configuration.HealthPackModeValues.Length != 1) ? Random.Next(0, Configuration.HealthPackModeValues.Length) : 0);
				num2 = Configuration.HealthPackModeValues[num];
			}
			else if (Configuration.ExactValue.Value > 0)
			{
				num2 = Configuration.ExactValue.Value;
			}
			else
			{
				int num3 = decimal.ToInt32((decimal)player.playerHealth.maxHealth * (Configuration.Percent.Value / 100m));
				if (health >= num3)
				{
					Plugin.Logger.LogDebug((object)($"The health of the player '{player.playerName}' is '{health}' " + $"and this is is more or equal than expected '{num3}', so health is not changed"));
					return;
				}
				num2 = num3 - health;
			}
			player.playerHealth.HealOther(num2, true);
			Plugin.Logger.LogDebug((object)($"Player '{player.playerName}' with '{health}' health received '{num2}' HP. " + $"So player should have '{Math.Min(player.playerHealth.maxHealth, health + num2)}' HP"));
		}
	}
	public static class PlayersHelper
	{
		public static List<PlayerAvatar> Get()
		{
			List<PlayerAvatar> list = SemiFunc.PlayerGetList();
			if (list != null && list.Count > 0)
			{
				return list;
			}
			PlayerAvatar val = SemiFunc.PlayerAvatarLocal();
			if ((Object)(object)val != (Object)null)
			{
				return new List<PlayerAvatar>(1) { val };
			}
			return new List<PlayerAvatar>();
		}
	}
	public static class WaitHelper
	{
		public static async Task<bool> Wait()
		{
			CancellationTokenSource cts = new CancellationTokenSource(TimeSpan.FromMinutes(1.0));
			while (!cts.IsCancellationRequested)
			{
				Plugin.Logger.LogDebug((object)"Waiting for all players to load");
				await Task.Delay(1000, CancellationToken.None);
				if (SemiFunc.RunIsLobby())
				{
					return true;
				}
				if (PlayersHelper.Get().All((PlayerAvatar x) => x.levelAnimationCompleted))
				{
					return true;
				}
			}
			Plugin.Logger.LogDebug((object)"Timeout exceeded, operation cancelled");
			return false;
		}
	}
	[HarmonyPatch(typeof(RoundDirector), "StartRoundRPC")]
	public class FullHealthMultiplayerPatch
	{
		private static void Postfix()
		{
			Plugin.Logger.LogDebug((object)"StartRoundRPC patch");
			if (!Configuration.Enabled.Value)
			{
				Plugin.Logger.LogDebug((object)"The mod is disabled, so health is not changed");
			}
			else if (!SemiFunc.IsMultiplayer())
			{
				Plugin.Logger.LogDebug((object)"This is not a multiplayer");
			}
			else if (Configuration.WorkMode.Value == WorkMode.Host && !SemiFunc.IsMasterClient())
			{
				Plugin.Logger.LogDebug((object)"This is not a host");
			}
			else if (GamePhaseValidateHelper.IsValid())
			{
				Task.Run((Func<Task?>)HealHelper.Heal);
			}
		}
	}
	[HarmonyPatch(typeof(RoundDirector), "StartRound")]
	public class FullHealthSinglePlayerPatch
	{
		private static void Postfix()
		{
			Plugin.Logger.LogDebug((object)"StartRound patch");
			if (!Configuration.Enabled.Value)
			{
				Plugin.Logger.LogDebug((object)"The mod is disabled, so HP is not changed");
			}
			else if (SemiFunc.IsMultiplayer())
			{
				Plugin.Logger.LogDebug((object)"This is not a single player");
			}
			else if (GamePhaseValidateHelper.IsValid())
			{
				Task.Run((Func<Task?>)HealHelper.Heal);
			}
		}
	}
	[BepInPlugin("FullHealth", "FullHealth", "1.5.2")]
	public class Plugin : BaseUnityPlugin
	{
		public static ManualLogSource Logger;

		private void Awake()
		{
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			Logger = ((BaseUnityPlugin)this).Logger;
			ConfigurationHelper.Bind(((BaseUnityPlugin)this).Config);
			new Harmony("FullHealth").PatchAll();
			Logger.LogInfo((object)"Mod 'FullHealth' is loaded!");
			Logger.LogInfo((object)"Configuration can be changed in 'BepInEx/config/FullHealth.cfg'");
		}
	}
	public static class MyPluginInfo
	{
		public const string PLUGIN_GUID = "FullHealth";

		public const string PLUGIN_NAME = "FullHealth";

		public const string PLUGIN_VERSION = "1.5.2";
	}
}