Decompiled source of NilsHUD v1.0.3

plugins/NilsHUD.dll

Decompiled 8 hours ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Configuration;
using GameNetcodeStuff;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using NilsHUD;
using UnityEngine;
using UnityEngine.SceneManagement;
using UnityEngine.UI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("NilsHUD")]
[assembly: AssemblyConfiguration("Debug")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0")]
[assembly: AssemblyProduct("NilsHUD")]
[assembly: AssemblyTitle("NilsHUD")]
[assembly: AssemblyVersion("1.0.0.0")]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableAttribute : Attribute
	{
		public readonly byte[] NullableFlags;

		public NullableAttribute(byte P_0)
		{
			NullableFlags = new byte[1] { P_0 };
		}

		public NullableAttribute(byte[] P_0)
		{
			NullableFlags = P_0;
		}
	}
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableContextAttribute : Attribute
	{
		public readonly byte Flag;

		public NullableContextAttribute(byte P_0)
		{
			Flag = P_0;
		}
	}
}
[HarmonyPatch(typeof(PlayerControllerB), "LateUpdate")]
public static class HealthBarPatch
{
	private static Dictionary<PlayerControllerB, Vector3> lastPlayerPositions = new Dictionary<PlayerControllerB, Vector3>();

	private const float POSITION_THRESHOLD = 0.1f;

	public static void Postfix(PlayerControllerB __instance)
	{
		//IL_002e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0033: Unknown result type (might be due to invalid IL or missing references)
		//IL_0041: Unknown result type (might be due to invalid IL or missing references)
		//IL_0048: Unknown result type (might be due to invalid IL or missing references)
		//IL_0070: Unknown result type (might be due to invalid IL or missing references)
		if (!PluginConfig.ConfigEnableHealthBar.Value)
		{
			return;
		}
		HealthBar healthBar = HealthBar.GetHealthBar(__instance);
		if ((Object)(object)healthBar != (Object)null)
		{
			Vector3 position = ((Component)__instance).transform.position;
			if (!lastPlayerPositions.ContainsKey(__instance) || Vector3.Distance(position, lastPlayerPositions[__instance]) > 0.1f)
			{
				healthBar.UpdateHealthBarPosition();
				lastPlayerPositions[__instance] = position;
			}
		}
	}
}
public class HealthChangeHelper : MonoBehaviour
{
	private void Awake()
	{
		Object.DontDestroyOnLoad((Object)(object)((Component)this).gameObject);
	}

	public void HandleHealthChange(Image healthBarImage, Image redHealthBarImage, float currentHealth, float maxHealth, float previousHealth)
	{
		Debug.Log((object)$"HandleHealthChange called, healthBarImage: {healthBarImage}, redHealthBarImage: {redHealthBarImage}");
		float num3 = (redHealthBarImage.fillAmount = (healthBarImage.fillAmount = currentHealth / maxHealth));
		if (currentHealth < previousHealth)
		{
			Debug.Log((object)$"Player is being damaged, fillAmount: {num3}");
		}
		else if (currentHealth > previousHealth)
		{
			Debug.Log((object)$"Player is being healed, fillAmount: {num3}");
		}
	}
}
public class HealthBar : MonoBehaviour
{
	[HarmonyPatch(typeof(PlayerControllerB), "Start")]
	public static class AddHealthBarPatch
	{
		public static void Postfix(PlayerControllerB __instance)
		{
			if ((Object)(object)__instance != (Object)(object)PlayerUtils.GetPlayerControllerB() && healthBarList.Count < initialHealthBarCount)
			{
				GetHealthBar(__instance);
			}
		}
	}

	private PlayerControllerB player;

	public Image healthBarImage;

	public Image redHealthBarImage;

	private CanvasGroup healthBarAlpha;

	private CanvasGroup redHealthBarAlpha;

	private bool isLocalPlayer;

	private GameObject healthBarObject;

	private float lastHealth;

	private float fadeOutDelay;

	private float fadeOutTimer = 0f;

	private RectTransform healthBarTransform;

	private RectTransform redHealthBarTransform;

	private RectTransform healthBarFillTransform;

	private static PlayerControllerB localPlayerController;

	private static Queue<HealthBar> healthBarPool = new Queue<HealthBar>();

	private float previousHealth;

	private Transform usernameBillboard;

	private Transform playerGlobalHead;

	private CanvasGroup usernameAlpha;

	private float fadeInRate;

	private float fadeOutRate;

	private HealthChangeHelper healthChangeHelper;

	private static int initialHealthBarCount = 4;

	private static List<HealthBar> healthBarList = new List<HealthBar>();

	private static Dictionary<PlayerControllerB, HealthBar> playerHealthBarMap = new Dictionary<PlayerControllerB, HealthBar>();

	public static HealthBar GetHealthBar(PlayerControllerB player)
	{
		//IL_00e1: Unknown result type (might be due to invalid IL or missing references)
		//IL_00e8: Expected O, but got Unknown
		if ((Object)(object)localPlayerController == (Object)null)
		{
			localPlayerController = PlayerUtils.GetPlayerControllerB();
		}
		if ((Object)(object)player == (Object)(object)localPlayerController)
		{
			return null;
		}
		if (playerHealthBarMap.TryGetValue(player, out HealthBar value))
		{
			if ((Object)(object)value != (Object)null && ((Component)value).gameObject.activeSelf)
			{
				return value;
			}
			playerHealthBarMap.Remove(player);
		}
		HealthBar healthBar = healthBarList.Find((HealthBar hb) => !((Component)hb).gameObject.activeSelf);
		if ((Object)(object)healthBar != (Object)null)
		{
			healthBar.player = player;
			((Component)healthBar).gameObject.SetActive(true);
			playerHealthBarMap[player] = healthBar;
			return healthBar;
		}
		GameObject val = new GameObject("HealthBar");
		val.SetActive(false);
		HealthBar healthBar2 = val.AddComponent<HealthBar>();
		healthBar2.player = player;
		healthBar2.InitializeHealthBar();
		val.SetActive(true);
		healthBarList.Add(healthBar2);
		playerHealthBarMap[player] = healthBar2;
		return healthBar2;
	}

	private void Awake()
	{
		//IL_00ea: Unknown result type (might be due to invalid IL or missing references)
		//IL_00f0: Expected O, but got Unknown
		if (!PluginConfig.ConfigEnableHealthBar.Value)
		{
			((Component)this).gameObject.SetActive(false);
			return;
		}
		isLocalPlayer = (Object)(object)player == (Object)(object)localPlayerController;
		lastHealth = player.health;
		fadeOutDelay = PluginConfig.ConfigFadeOutDelay.Value;
		usernameBillboard = player.usernameBillboard;
		playerGlobalHead = player.playerGlobalHead;
		usernameAlpha = player.usernameAlpha;
		fadeInRate = 1f / PluginConfig.ConfigFadeInDuration.Value;
		fadeOutRate = 1f / PluginConfig.ConfigFadeOutDuration.Value;
		previousHealth = player.health;
		GameObject val = GameObject.Find("HealthChangeHelper");
		if ((Object)(object)val == (Object)null)
		{
			val = new GameObject("HealthChangeHelper");
			healthChangeHelper = val.AddComponent<HealthChangeHelper>();
			Debug.Log((object)"Created new HealthChangeHelper instance");
		}
		else
		{
			healthChangeHelper = val.GetComponent<HealthChangeHelper>();
			Debug.Log((object)"Found existing HealthChangeHelper instance");
		}
	}

	private void InitializeHealthBar()
	{
		//IL_0032: Unknown result type (might be due to invalid IL or missing references)
		//IL_003c: Expected O, but got Unknown
		//IL_0064: Unknown result type (might be due to invalid IL or missing references)
		//IL_00bd: Unknown result type (might be due to invalid IL or missing references)
		//IL_015e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0179: Unknown result type (might be due to invalid IL or missing references)
		//IL_019e: Unknown result type (might be due to invalid IL or missing references)
		//IL_01c3: Unknown result type (might be due to invalid IL or missing references)
		//IL_01de: Unknown result type (might be due to invalid IL or missing references)
		//IL_01f9: Unknown result type (might be due to invalid IL or missing references)
		//IL_021e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0243: Unknown result type (might be due to invalid IL or missing references)
		//IL_0278: Unknown result type (might be due to invalid IL or missing references)
		//IL_02ac: Unknown result type (might be due to invalid IL or missing references)
		if (PluginConfig.ConfigEnableHealthBar.Value && (Object)(object)healthBarObject == (Object)null)
		{
			healthBarObject = new GameObject("HealthBarObject");
			healthBarObject.transform.SetParent(((Component)player.usernameBillboard).transform, false);
			redHealthBarImage = new GameObject("RedHealthBar").AddComponent<Image>();
			((Component)redHealthBarImage).transform.SetParent(healthBarObject.transform, false);
			redHealthBarAlpha = ((Component)redHealthBarImage).gameObject.AddComponent<CanvasGroup>();
			redHealthBarAlpha.alpha = 0f;
			healthBarImage = new GameObject("HealthBar").AddComponent<Image>();
			((Component)healthBarImage).transform.SetParent(healthBarObject.transform, false);
			healthBarAlpha = ((Component)healthBarImage).gameObject.AddComponent<CanvasGroup>();
			healthBarAlpha.alpha = 0f;
			Debug.Log((object)$"Initialized health bar: healthBarImage={healthBarImage}, redHealthBarImage={redHealthBarImage}");
			redHealthBarTransform = ((Component)redHealthBarImage).GetComponent<RectTransform>();
			healthBarTransform = ((Component)healthBarImage).GetComponent<RectTransform>();
			redHealthBarTransform.anchorMin = new Vector2(0.5f, 0f);
			redHealthBarTransform.anchorMax = new Vector2(0.5f, 0f);
			redHealthBarTransform.sizeDelta = new Vector2(PluginConfig.ConfigRedHealthBarWidth.Value, PluginConfig.ConfigRedHealthBarHeight.Value);
			redHealthBarTransform.anchoredPosition = new Vector2(PluginConfig.ConfigHealthBarPositionX.Value, PluginConfig.ConfigHealthBarPositionY.Value);
			healthBarTransform.anchorMin = new Vector2(0f, 0f);
			healthBarTransform.anchorMax = new Vector2(1f, 0f);
			healthBarTransform.sizeDelta = new Vector2(PluginConfig.ConfigHealthBarWidth.Value, PluginConfig.ConfigHealthBarHeight.Value);
			healthBarTransform.anchoredPosition = new Vector2(PluginConfig.ConfigHealthBarPositionX.Value, PluginConfig.ConfigHealthBarPositionY.Value);
			string value = PluginConfig.ConfigHealthBarColorHex.Value;
			Color color = default(Color);
			if (ColorUtility.TryParseHtmlString("#" + value, ref color))
			{
				((Graphic)healthBarImage).color = color;
			}
			string value2 = PluginConfig.ConfigRedHealthBarColorHex.Value;
			Color color2 = default(Color);
			if (ColorUtility.TryParseHtmlString("#" + value2, ref color2))
			{
				((Graphic)redHealthBarImage).color = color2;
			}
		}
	}

	private void LateUpdate()
	{
		if (PluginConfig.ConfigEnableHealthBar.Value)
		{
			UpdateHealthBarFade();
			if ((float)player.health != lastHealth)
			{
				OnHealthChanged();
			}
		}
	}

	private void OnHealthChanged()
	{
		//IL_00af: Unknown result type (might be due to invalid IL or missing references)
		//IL_00b9: Unknown result type (might be due to invalid IL or missing references)
		//IL_00e1: Unknown result type (might be due to invalid IL or missing references)
		//IL_00eb: Unknown result type (might be due to invalid IL or missing references)
		if (PluginConfig.ConfigEnableHealthBar.Value)
		{
			float num = player.health;
			float num2 = 100f;
			float num3 = lastHealth;
			Debug.Log((object)$"OnHealthChanged called for player: {((Object)player).name}, currentHealth: {num}, previousHealth: {num3}");
			if ((Object)(object)player != (Object)(object)localPlayerController && num != num3)
			{
				healthChangeHelper.HandleHealthChange(healthBarImage, redHealthBarImage, num, num2, num3);
				float num4 = num / num2;
				healthBarTransform.anchorMax = new Vector2(num4, healthBarTransform.anchorMax.y);
				float num5 = num4 * PluginConfig.ConfigHealthBarWidth.Value;
				healthBarTransform.sizeDelta = new Vector2(num5, healthBarTransform.sizeDelta.y);
				lastHealth = num;
			}
		}
	}

	private void UpdateHealthBarFade()
	{
		if (isLocalPlayer)
		{
			healthBarAlpha.alpha = 0f;
			redHealthBarAlpha.alpha = 0f;
			return;
		}
		if (usernameAlpha.alpha > 0f)
		{
			fadeOutTimer = 0f;
			if (healthBarAlpha.alpha < 1f)
			{
				CanvasGroup obj = healthBarAlpha;
				obj.alpha += Time.deltaTime * fadeInRate;
				healthBarAlpha.alpha = Mathf.Clamp01(healthBarAlpha.alpha);
			}
			if (redHealthBarAlpha.alpha < 1f)
			{
				CanvasGroup obj2 = redHealthBarAlpha;
				obj2.alpha += Time.deltaTime * fadeInRate;
				redHealthBarAlpha.alpha = Mathf.Clamp01(redHealthBarAlpha.alpha);
			}
			return;
		}
		fadeOutTimer += Time.deltaTime;
		if (fadeOutTimer >= fadeOutDelay)
		{
			CanvasGroup obj3 = healthBarAlpha;
			obj3.alpha -= Time.deltaTime * fadeOutRate;
			healthBarAlpha.alpha = Mathf.Clamp01(healthBarAlpha.alpha);
			CanvasGroup obj4 = redHealthBarAlpha;
			obj4.alpha -= Time.deltaTime * fadeOutRate;
			redHealthBarAlpha.alpha = Mathf.Clamp01(redHealthBarAlpha.alpha);
			if (healthBarAlpha.alpha <= 0f && redHealthBarAlpha.alpha <= 0f)
			{
				healthBarPool.Enqueue(this);
				((Component)this).gameObject.SetActive(false);
			}
		}
	}

	public void UpdateHealthBarPosition()
	{
		//IL_001b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0020: Unknown result type (might be due to invalid IL or missing references)
		//IL_0027: Unknown result type (might be due to invalid IL or missing references)
		//IL_002d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0039: Unknown result type (might be due to invalid IL or missing references)
		//IL_003f: Unknown result type (might be due to invalid IL or missing references)
		if (PluginConfig.ConfigEnableHealthBar.Value)
		{
			Vector3 position = playerGlobalHead.position;
			usernameBillboard.position = new Vector3(position.x, position.y + 0.55f, position.z);
		}
	}
}
[HarmonyPatch(typeof(UnlockableSuit), "SwitchSuitForPlayer")]
public static class UnlockableSuitPatch
{
	private static readonly Dictionary<int, Color> suitColors = new Dictionary<int, Color>
	{
		{
			0,
			new Color(1f, 0.5f, 0f)
		},
		{
			1,
			Color.green
		},
		{
			2,
			Color.yellow
		},
		{
			3,
			Color.cyan
		},
		{
			24,
			new Color(0.5f, 0f, 0.5f)
		}
	};

	private const string FallbackColorHex = "#FF0000";

	[HarmonyPostfix]
	public static void SwitchSuitForPlayer_Postfix(PlayerControllerB player, int suitID)
	{
		if (PluginConfig.ConfigEnableSuitColorOverlay.Value)
		{
			UpdateHealthOverlayColor(player, suitID);
		}
	}

	public static void UpdateHealthOverlayColor(PlayerControllerB player, int suitID)
	{
		//IL_0078: Unknown result type (might be due to invalid IL or missing references)
		//IL_007c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0082: Unknown result type (might be due to invalid IL or missing references)
		//IL_005a: Unknown result type (might be due to invalid IL or missing references)
		//IL_00a4: Unknown result type (might be due to invalid IL or missing references)
		//IL_00a0: Unknown result type (might be due to invalid IL or missing references)
		//IL_0099: Unknown result type (might be due to invalid IL or missing references)
		Debug.Log((object)$"UpdateHealthOverlayColor called with player: {((Object)player).name}, suitID: {suitID}");
		HUDManager instance = HUDManager.Instance;
		object obj;
		if (instance == null)
		{
			obj = null;
		}
		else
		{
			CanvasGroup selfRedCanvasGroup = instance.selfRedCanvasGroup;
			obj = ((selfRedCanvasGroup != null) ? ((Component)selfRedCanvasGroup).GetComponent<Image>() : null);
		}
		Image val = (Image)obj;
		if ((Object)(object)val != (Object)null)
		{
			if (suitColors.TryGetValue(suitID, out var value))
			{
				((Graphic)val).color = value;
				return;
			}
			Color val2 = default(Color);
			ColorUtility.TryParseHtmlString(PluginConfig.ConfigOverlayColorHex.Value, ref val2);
			Color val3 = default(Color);
			((Graphic)val).color = ((val2 != default(Color)) ? val2 : (ColorUtility.TryParseHtmlString("#FF0000", ref val3) ? val3 : Color.red));
		}
	}
}
namespace NilsHUD
{
	public static class PlayerUtils
	{
		private static PlayerControllerB localPlayerController;

		public static PlayerControllerB GetPlayerControllerB()
		{
			if ((Object)(object)localPlayerController == (Object)null)
			{
				localPlayerController = GameNetworkManager.Instance?.localPlayerController;
				PlayerControllerB obj = localPlayerController;
				Debug.Log((object)("[NilsHUD] GetPlayerControllerB returned: " + (((obj != null) ? ((Object)obj).name : null) ?? "null")));
			}
			return localPlayerController;
		}
	}
	public static class HUDManagerPatch
	{
		private const string HealFromCriticalTrigger = "HealFromCritical";

		private const string CriticalHitTrigger = "CriticalHit";

		private const string SmallHitTrigger = "SmallHit";

		private const int CriticalHealthThreshold = 20;

		private static bool playerIsCriticallyInjured;

		private static float targetFillAmount;

		[HarmonyPatch(typeof(HUDManager), "UpdateHealthUI")]
		[HarmonyPrefix]
		public static bool UpdateHealthUIPrefix(int health, bool hurtPlayer = true)
		{
			HUDManager instance = HUDManager.Instance;
			if ((Object)(object)instance?.selfRedCanvasGroup == (Object)null)
			{
				Debug.LogError((object)"HUDManager instance or selfRedCanvasGroup is null!");
				return true;
			}
			if (PluginConfig.ConfigOverlayColorHex.Value != null)
			{
				_ = PluginConfig.ConfigEnableCriticalHitEffect.Value;
				_ = PluginConfig.ConfigEnableSmallHitEffect.Value;
				if (0 == 0)
				{
					Image component = ((Component)instance.selfRedCanvasGroup).GetComponent<Image>();
					if ((Object)(object)component == (Object)null)
					{
						Debug.LogError((object)"Image component not found on selfRedCanvasGroup!");
						return false;
					}
					PlayerControllerB playerControllerB = PlayerUtils.GetPlayerControllerB();
					ConfigureHealthImage(component, health, playerControllerB);
					if (!Object.op_Implicit((Object)(object)((Component)instance).gameObject.GetComponent<HealthIndicatorInitializer>()))
					{
						((Component)instance).gameObject.AddComponent<HealthIndicatorInitializer>();
						component.fillAmount = 0f;
					}
					float previousFillAmount = (component.fillAmount = component.fillAmount);
					StartHealthMonitoring(instance);
					StartSmoothFillTransition(instance, component, previousFillAmount);
					if ((Object)(object)instance.HUDAnimator == (Object)null)
					{
						Debug.LogError((object)"HUDAnimator is null!");
						return false;
					}
					HandlePlayerHealthState(instance, health, hurtPlayer);
					return false;
				}
			}
			Debug.LogError((object)"PluginConfig values are not properly initialized!");
			return true;
		}

		private static void StartHealthMonitoring(HUDManager hudManager)
		{
			if (!Object.op_Implicit((Object)(object)((Component)hudManager).gameObject.GetComponent<HealthMonitorCoroutine>()))
			{
				((Component)hudManager).gameObject.AddComponent<HealthMonitorCoroutine>();
			}
		}

		private static void StartSmoothFillTransition(HUDManager hudManager, Image image, float previousFillAmount)
		{
			((MonoBehaviour)hudManager).StopAllCoroutines();
			if (PluginConfig.ConfigEnableFillAnimation.Value)
			{
				float duration = Mathf.Clamp(PluginConfig.ConfigFillTransitionDuration.Value, 0.01f, 1f);
				((MonoBehaviour)hudManager).StartCoroutine(SmoothFillTransition(image, targetFillAmount, duration));
			}
			else
			{
				image.fillAmount = targetFillAmount;
			}
			if (PluginConfig.ConfigEnableFadeOut.Value)
			{
				float fadeOutDuration = Mathf.Clamp(PluginConfig.ConfigFadeOutDuration.Value, 0f, 5f);
				((MonoBehaviour)hudManager).StartCoroutine(StartFadeOutEffect(image, fadeOutDuration));
			}
		}

		private static IEnumerator StartFadeOutEffect(Image image, float fadeOutDuration)
		{
			float elapsedTime = 0f;
			Color startColor = ((Graphic)image).color;
			float targetAlpha = Mathf.Clamp01(1f - PluginConfig.ConfigFadeOutIntensity.Value);
			Color targetColor = new Color(startColor.r, startColor.g, startColor.b, targetAlpha);
			while (elapsedTime < fadeOutDuration)
			{
				float t = elapsedTime / fadeOutDuration;
				((Graphic)image).color = Color.Lerp(startColor, targetColor, t);
				elapsedTime += Time.deltaTime;
				yield return null;
			}
			((Graphic)image).color = targetColor;
		}

		private static IEnumerator SmoothFillTransition(Image image, float targetFillAmount, float duration)
		{
			float elapsedTime = 0f;
			float startFillAmount = image.fillAmount;
			Debug.LogFormat("Start fill amount: {0}", new object[1] { startFillAmount });
			Debug.LogFormat("Target fill amount: {0}", new object[1] { targetFillAmount });
			Debug.LogFormat("Fill duration: {0}", new object[1] { duration });
			if (Mathf.Approximately(startFillAmount, targetFillAmount))
			{
				duration = Mathf.Max(duration, 0.1f);
			}
			while (elapsedTime < duration)
			{
				float t = elapsedTime / duration;
				float smoothT = Mathf.SmoothStep(0f, 1f, t);
				image.fillAmount = Mathf.Lerp(startFillAmount, targetFillAmount, smoothT);
				elapsedTime += Time.deltaTime;
				yield return null;
			}
			image.fillAmount = targetFillAmount;
		}

		private static IEnumerator SmoothFillAndFadeTransition(Image image, float startFillAmount, float targetFillAmount, float fillDuration, float fadeOutDuration)
		{
			Debug.LogFormat("Start fill amount: {0}", new object[1] { image.fillAmount });
			Debug.LogFormat("Target fill amount: {0}", new object[1] { targetFillAmount });
			Debug.LogFormat("Fill duration: {0}", new object[1] { fillDuration });
			Debug.LogFormat("Fade-out duration: {0}", new object[1] { fadeOutDuration });
			if (Mathf.Approximately(image.fillAmount, targetFillAmount))
			{
				fillDuration = Mathf.Max(fillDuration, 0.1f);
			}
			yield return SmoothFillTransition(image, targetFillAmount, fillDuration);
			float elapsedTime = 0f;
			Color startColor = ((Graphic)image).color;
			float targetAlpha = Mathf.Clamp01(1f - PluginConfig.ConfigFadeOutIntensity.Value);
			Color targetColor = new Color(startColor.r, startColor.g, startColor.b, targetAlpha);
			Debug.Log((object)$"Starting fade-out effect. Start color: {startColor}, Target color: {targetColor}, Fade-out duration: {fadeOutDuration}");
			while (elapsedTime < fadeOutDuration)
			{
				float t = elapsedTime / fadeOutDuration;
				((Graphic)image).color = Color.Lerp(startColor, targetColor, t);
				Debug.Log((object)$"Fade-out effect progress: {t}, Current color: {((Graphic)image).color}");
				elapsedTime += Time.deltaTime;
				yield return null;
			}
			((Graphic)image).color = targetColor;
			Debug.Log((object)$"Fade-out effect completed. Final color: {((Graphic)image).color}");
		}

		private static void ConfigureHealthImage(Image image, int health, PlayerControllerB controllerInstance)
		{
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: Invalid comparison between Unknown and I4
			//IL_00e0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d3: Unknown result type (might be due to invalid IL or missing references)
			targetFillAmount = (100f - (float)health) / 100f;
			if ((int)image.type != 3)
			{
				image.type = (Type)3;
				image.fillMethod = (FillMethod)1;
			}
			if (PluginConfig.ConfigFillDirection.Value == FillDirection.TopToBottom)
			{
				image.fillOrigin = 1;
			}
			else
			{
				image.fillOrigin = 0;
			}
			Color color = default(Color);
			if (PluginConfig.ConfigEnableSuitColorOverlay.Value && (Object)(object)controllerInstance != (Object)null)
			{
				int currentSuitID = controllerInstance.currentSuitID;
				Debug.LogFormat("Current Suit ID in HealthIndicatorPatch: {0}", new object[1] { currentSuitID });
				UnlockableSuitPatch.UpdateHealthOverlayColor(controllerInstance, currentSuitID);
				Debug.Log((object)"Health overlay color updated in HealthIndicatorPatch");
			}
			else if (ColorUtility.TryParseHtmlString("#" + PluginConfig.ConfigOverlayColorHex.Value, ref color))
			{
				((Graphic)image).color = color;
			}
			else
			{
				((Graphic)image).color = Color.red;
			}
		}

		private static void HandlePlayerHealthState(HUDManager hudManager, int health, bool hurtPlayer)
		{
			hudManager.selfRedCanvasGroup.alpha = (100f - (float)health) / 100f;
			if (health >= 20 && playerIsCriticallyInjured)
			{
				playerIsCriticallyInjured = false;
				hudManager.HUDAnimator.SetTrigger("HealFromCritical");
			}
			if (hurtPlayer && health > 0)
			{
				ProcessPlayerInjury(hudManager, health);
			}
		}

		private static void ProcessPlayerInjury(HUDManager hudManager, int health)
		{
			if (health < 20)
			{
				playerIsCriticallyInjured = true;
				if (PluginConfig.ConfigEnableCriticalHitEffect.Value)
				{
					hudManager.HUDAnimator.SetTrigger("CriticalHit");
					AudioSource uIAudio = hudManager.UIAudio;
					if (uIAudio != null)
					{
						uIAudio.PlayOneShot(hudManager.criticalInjury, 1f);
					}
				}
			}
			else if (PluginConfig.ConfigEnableSmallHitEffect.Value)
			{
				hudManager.HUDAnimator.SetTrigger("SmallHit");
			}
		}
	}
	public class HealthIndicatorInitializer : MonoBehaviour
	{
	}
	public class HealthMonitorCoroutine : MonoBehaviour
	{
		private int lastHealth = -1;

		private void Start()
		{
			((MonoBehaviour)this).StartCoroutine(MonitorHealth());
		}

		private IEnumerator MonitorHealth()
		{
			while (true)
			{
				PlayerControllerB playerController = PlayerUtils.GetPlayerControllerB();
				if ((Object)(object)playerController != (Object)null)
				{
					int currentHealth = playerController.health;
					if (currentHealth != lastHealth)
					{
						lastHealth = currentHealth;
						HUDManagerPatch.UpdateHealthUIPrefix(currentHealth, hurtPlayer: false);
					}
				}
				yield return (object)new WaitForSeconds(0.01f);
			}
		}
	}
	[BepInPlugin("Nilaier.NilsHUD", "NilsHUD", "1.0.1")]
	public class Plugin : BaseUnityPlugin
	{
		private const string AsciiLogoResourceName = "NilsHUD.Resources.ascii_logo.txt";

		private static readonly Assembly ExecutingAssembly = Assembly.GetExecutingAssembly();

		private static readonly string[] ExcludedScenes = new string[4] { "InitScene", "InitSceneLaunchOptions", "MainMenu", "InitSceneLANMode" };

		private Harmony harmonyInstance;

		private bool isPluginInitialized = false;

		private void Awake()
		{
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0018: Expected O, but got Unknown
			DisplayAsciiLogo();
			harmonyInstance = new Harmony("Nilaier.NilsHUD");
			harmonyInstance.PatchAll(typeof(HUDManagerPatch));
			harmonyInstance.PatchAll(typeof(UnlockableSuitPatch));
			harmonyInstance.PatchAll(typeof(HealthBarPatch));
			Debug.Log((object)"[NilsHUD] Harmony patches applied.");
			SceneManager.sceneLoaded += OnSceneLoaded;
		}

		private void DisplayAsciiLogo()
		{
			string text = LoadAsciiLogoFromResource();
			Debug.Log((object)(string.IsNullOrEmpty(text) ? "[NilsHUD] ASCII logo not found or empty." : text));
		}

		private string LoadAsciiLogoFromResource()
		{
			try
			{
				using Stream stream = ExecutingAssembly.GetManifestResourceStream("NilsHUD.Resources.ascii_logo.txt");
				if (stream != null)
				{
					using (StreamReader streamReader = new StreamReader(stream))
					{
						return streamReader.ReadToEnd();
					}
				}
			}
			catch (IOException ex)
			{
				Debug.LogError((object)("[NilsHUD] Error loading ASCII logo: " + ex.Message));
			}
			return string.Empty;
		}

		private void OnSceneLoaded(Scene scene, LoadSceneMode mode)
		{
			Debug.Log((object)("[NilsHUD] Loaded scene: " + ((Scene)(ref scene)).name));
			if (!isPluginInitialized && !ExcludedScenes.Contains(((Scene)(ref scene)).name))
			{
				PluginConfig.BindConfig(((BaseUnityPlugin)this).Config);
				isPluginInitialized = true;
				Debug.Log((object)("[NilsHUD] Plugin initialized in scene: " + ((Scene)(ref scene)).name));
			}
		}
	}
	public class PluginConfig
	{
		private const string DefaultOverlayColor = "FF0000";

		private const float DefaultFillTransitionDuration = 0.1f;

		private const float DefaultFadeOutDuration = 0.5f;

		private const float DefaultFadeOutIntensity = 0.5f;

		private const string DefaultHealthBarColor = "FF8000";

		private const string DefaultRedHealthBarColor = "FF0000";

		private const float DefaultHealthBarPositionX = 0f;

		private const float DefaultHealthBarPositionY = 30f;

		private const float DefaultFadeInDuration = 0.5f;

		private const float DefaultFadeOutDelay = 1f;

		private const float DefaultHealthBarWidth = 300f;

		private const float DefaultHealthBarHeight = 15f;

		private const float DefaultRedHealthBarWidth = 300f;

		private const float DefaultRedHealthBarHeight = 15f;

		public static ConfigEntry<string> ConfigOverlayColorHex;

		public static ConfigEntry<bool> ConfigEnableFillAnimation;

		public static ConfigEntry<FillDirection> ConfigFillDirection;

		public static ConfigEntry<float> ConfigFillTransitionDuration;

		public static ConfigEntry<bool> ConfigEnableSuitColorOverlay;

		public static ConfigEntry<bool> ConfigEnableFadeOut;

		public static ConfigEntry<float> ConfigFadeOutDuration;

		public static ConfigEntry<float> ConfigFadeOutIntensity;

		public static ConfigEntry<bool> ConfigEnableCriticalHitEffect;

		public static ConfigEntry<bool> ConfigEnableSmallHitEffect;

		public static ConfigEntry<bool> ConfigEnableHealthBar;

		public static ConfigEntry<string> ConfigHealthBarColorHex;

		public static ConfigEntry<string> ConfigRedHealthBarColorHex;

		public static ConfigEntry<float> ConfigHealthBarPositionX;

		public static ConfigEntry<float> ConfigHealthBarPositionY;

		public static ConfigEntry<float> ConfigFadeInDuration;

		public static ConfigEntry<float> ConfigFadeOutDelay;

		public static ConfigEntry<float> ConfigHealthBarWidth;

		public static ConfigEntry<float> ConfigHealthBarHeight;

		public static ConfigEntry<float> ConfigRedHealthBarWidth;

		public static ConfigEntry<float> ConfigRedHealthBarHeight;

		public static void BindConfig(ConfigFile config)
		{
			ConfigOverlayColorHex = config.Bind<string>("Overlay", "OverlayColorHex", "FF0000", "The color of the overlay image in hexadecimal format (e.g., FF0000 for red).");
			ConfigEnableFillAnimation = config.Bind<bool>("Overlay", "EnableFillAnimation", true, "Enables the fill animation. If false, the fill amount is set instantly.");
			ConfigFillDirection = config.Bind<FillDirection>("Overlay", "FillDirection", FillDirection.BottomToTop, "The fill direction of the health indicator.");
			ConfigFillTransitionDuration = config.Bind<float>("Overlay", "FillTransitionDuration", 0.1f, "The duration over which the health indicator's fill amount changes. Lower values make the transition faster, higher values make it smoother.");
			ConfigEnableSuitColorOverlay = config.Bind<bool>("Overlay", "EnableSuitColorOverlay", false, "Enables the feature where the player's suit changes the color of the damage overlay.");
			ConfigEnableFadeOut = config.Bind<bool>("FadeOut", "EnableFadeOut", true, "Enables the fade-out effect for the filling overlay.");
			ConfigFadeOutDuration = config.Bind<float>("FadeOut", "FadeOutDuration", 0.5f, "The duration of the fade-out effect for the filling overlay (in seconds).");
			ConfigFadeOutIntensity = config.Bind<float>("FadeOut", "FadeOutIntensity", 0.5f, "The intensity of the fade-out effect (0 for no fade-out, 1 for full fade-out).");
			ConfigEnableCriticalHitEffect = config.Bind<bool>("Effects", "EnableCriticalHitEffect", true, "Enables the critical hit animation and sound effect.");
			ConfigEnableSmallHitEffect = config.Bind<bool>("Effects", "EnableSmallHitEffect", true, "Enables the small hit effect.");
			ConfigEnableHealthBar = config.Bind<bool>("Experimental", "EnableHealthBar", false, "Enables the health bar.");
			ConfigHealthBarColorHex = config.Bind<string>("Experimental", "HealthBarColorHex", "FF8000", "The color of the health bar in hexadecimal format (e.g., FF8000 for orange).");
			ConfigRedHealthBarColorHex = config.Bind<string>("Experimental", "RedHealthBarColorHex", "FF0000", "The color of the red health bar in hexadecimal format (e.g., FF0000 for red).");
			ConfigHealthBarPositionX = config.Bind<float>("Experimental", "HealthBarPositionX", 0f, "The X position of the health bar.");
			ConfigHealthBarPositionY = config.Bind<float>("Experimental", "HealthBarPositionY", 30f, "The Y position of the health bar.");
			ConfigFadeInDuration = config.Bind<float>("Experimental", "FadeInDuration", 0.5f, "The duration of the fade-in effect for the health bar (in seconds).");
			ConfigFadeOutDelay = config.Bind<float>("Experimental", "FadeOutDelay", 1f, "The delay before the health bar starts fading out (in seconds).");
			ConfigHealthBarWidth = config.Bind<float>("Experimental", "HealthBarWidth", 300f, "The width of the health bar.");
			ConfigHealthBarHeight = config.Bind<float>("Experimental", "HealthBarHeight", 15f, "The height of the health bar.");
			ConfigRedHealthBarWidth = config.Bind<float>("Experimental", "RedHealthBarWidth", 300f, "The width of the red health bar.");
			ConfigRedHealthBarHeight = config.Bind<float>("Experimental", "RedHealthBarHeight", 15f, "The height of the red health bar.");
		}
	}
	public enum FillDirection
	{
		BottomToTop,
		TopToBottom
	}
	internal static class PluginInfo
	{
		public const string PLUGIN_GUID = "Nilaier.NilsHUD";

		public const string PLUGIN_NAME = "NilsHUD";

		public const string PLUGIN_VERSION = "1.0.1";
	}
}