Decompiled source of Enemy Health Bars v1.0.5

EnemyHealthBars.dll

Decompiled a month ago
using System;
using System.Collections;
using System.Collections.Generic;
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;
using UnityEngine.Events;
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("Omniscye")]
[assembly: AssemblyConfiguration("Debug")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0")]
[assembly: AssemblyProduct("EnemyHealthBars")]
[assembly: AssemblyTitle("EnemyHealthBars")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.0.0.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.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;
		}
	}
	[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 Empress.EnemyHealthBars
{
	[BepInPlugin("Empress.EnemyHealthBars", "Enemy Health Bars", "1.0.1")]
	public class EnemyHealthBarsPlugin : BaseUnityPlugin
	{
		internal static ConfigEntry<bool> AlwaysShow;

		internal static ConfigEntry<float> ShowOnDamageSeconds;

		internal static ConfigEntry<float> BarWidth;

		internal static ConfigEntry<float> BarHeight;

		internal static ConfigEntry<float> OffsetPercentOfHeight;

		internal static ConfigEntry<float> ExtraOffsetMeters;

		internal static ConfigEntry<float> DistanceScaleFactor;

		internal static ConfigEntry<float> MinScale;

		internal static ConfigEntry<float> MaxScale;

		internal static ConfigEntry<bool> OnlyWhenVisible;

		internal static ConfigEntry<float> LerpSpeed;

		internal static ConfigEntry<bool> UseMeshParentIfAvailable;

		internal static ConfigEntry<float> ChipDropSpeed;

		internal static ConfigEntry<float> HealCatchupSpeed;

		internal static EnemyHealthBarsPlugin Instance { get; private set; }

		internal static ManualLogSource Logger => Instance._logger;

		private ManualLogSource _logger => ((BaseUnityPlugin)this).Logger;

		internal Harmony? Harmony { get; private set; }

		private void Awake()
		{
			Instance = this;
			((Component)this).gameObject.transform.parent = null;
			((Object)((Component)this).gameObject).hideFlags = (HideFlags)61;
			AlwaysShow = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "AlwaysShow", true, "If true, health bars are always visible. If false, they show for a short time after damage.");
			ShowOnDamageSeconds = ((BaseUnityPlugin)this).Config.Bind<float>("General", "ShowOnDamageSeconds", 2.5f, "Seconds to keep the bar visible after damage when AlwaysShow is false.");
			BarWidth = ((BaseUnityPlugin)this).Config.Bind<float>("Style", "BarWidth", 1f, "Base width before distance scaling.");
			BarHeight = ((BaseUnityPlugin)this).Config.Bind<float>("Style", "BarHeight", 0.1f, "Bar height.");
			OffsetPercentOfHeight = ((BaseUnityPlugin)this).Config.Bind<float>("Position", "OffsetPercentOfHeight", 0.2f, "How far above the top of the model to place the bar as a percentage of the model height.");
			ExtraOffsetMeters = ((BaseUnityPlugin)this).Config.Bind<float>("Position", "ExtraOffsetMeters", 0.15f, "Extra vertical meters to add above the top.");
			DistanceScaleFactor = ((BaseUnityPlugin)this).Config.Bind<float>("Style", "DistanceScaleFactor", 0.015f, "Scale per meter.");
			MinScale = ((BaseUnityPlugin)this).Config.Bind<float>("Style", "MinScale", 0.3f, "Min scale.");
			MaxScale = ((BaseUnityPlugin)this).Config.Bind<float>("Style", "MaxScale", 2f, "Max scale.");
			OnlyWhenVisible = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "OnlyWhenVisible", true, "Hide the bar when the enemy renderers are not visible to the camera.");
			LerpSpeed = ((BaseUnityPlugin)this).Config.Bind<float>("Style", "LerpSpeed", 12f, "Front bar heal smoothing speed.");
			UseMeshParentIfAvailable = ((BaseUnityPlugin)this).Config.Bind<bool>("Position", "UseMeshParentIfAvailable", true, "Anchor bar to EnemyHealth.meshParent if it's set; otherwise use the enemy root.");
			ChipDropSpeed = ((BaseUnityPlugin)this).Config.Bind<float>("Style", "ChipDropSpeed", 6f, "Speed the dark-red damage chip falls toward the current health after damage.");
			HealCatchupSpeed = ((BaseUnityPlugin)this).Config.Bind<float>("Style", "HealCatchupSpeed", 16f, "Speed the damage chip catches up when healing.");
			Patch();
			Logger.LogInfo((object)$"{((BaseUnityPlugin)this).Info.Metadata.GUID} v{((BaseUnityPlugin)this).Info.Metadata.Version} loaded. Painting them red.");
			try
			{
				Type type = AccessTools.TypeByName("EnemyHealth");
				MethodInfo methodInfo = AccessTools.Method(type, "Awake", (Type[])null, (Type[])null);
				if (methodInfo != null)
				{
					Logger.LogInfo((object)"Harmony: EnemyHealth.Awake patched OK");
				}
				else
				{
					Logger.LogWarning((object)"Harmony: EnemyHealth.Awake not found - bars will not attach to new spawns");
				}
			}
			catch (Exception ex)
			{
				Logger.LogWarning((object)("Harmony check failed: " + ex.Message));
			}
			TryAttachToExisting();
		}

		internal void Patch()
		{
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0021: Expected O, but got Unknown
			//IL_0026: Expected O, but got Unknown
			if (Harmony == null)
			{
				Harmony val = new Harmony(((BaseUnityPlugin)this).Info.Metadata.GUID);
				Harmony val2 = val;
				Harmony = val;
			}
			Harmony.PatchAll();
		}

		internal void Unpatch()
		{
			Harmony? harmony = Harmony;
			if (harmony != null)
			{
				harmony.UnpatchSelf();
			}
		}

		private void TryAttachToExisting()
		{
			try
			{
				MonoBehaviour[] array = Object.FindObjectsOfType<MonoBehaviour>();
				MonoBehaviour[] array2 = array;
				foreach (MonoBehaviour val in array2)
				{
					if (!((Object)(object)val == (Object)null))
					{
						Type type = ((object)val).GetType();
						if (type.Name == "EnemyHealth")
						{
							HealthBarAttacher.AttachTo(val);
						}
					}
				}
			}
			catch (Exception arg)
			{
				Logger.LogWarning((object)$"Scan failed: {arg}");
			}
		}
	}
	[HarmonyPatch]
	internal static class EnemyHealthPatches
	{
		private static MethodBase TargetMethod()
		{
			return AccessTools.Method(AccessTools.TypeByName("EnemyHealth"), "Awake", (Type[])null, (Type[])null);
		}

		[HarmonyPostfix]
		private static void Post_Awake(MonoBehaviour __instance)
		{
			HealthBarAttacher.AttachTo(__instance);
		}
	}
	[HarmonyPatch]
	internal static class EnemyHealthAttachFallbackPatches
	{
		[CompilerGenerated]
		private sealed class <TargetMethods>d__0 : IEnumerable<MethodBase>, IEnumerable, IEnumerator<MethodBase>, IEnumerator, IDisposable
		{
			private int <>1__state;

			private MethodBase <>2__current;

			private int <>l__initialThreadId;

			private Type <t>5__1;

			private string[] <names>5__2;

			private string[] <>s__3;

			private int <>s__4;

			private string <n>5__5;

			private MethodInfo <m>5__6;

			MethodBase IEnumerator<MethodBase>.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			object IEnumerator.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			[DebuggerHidden]
			public <TargetMethods>d__0(int <>1__state)
			{
				this.<>1__state = <>1__state;
				<>l__initialThreadId = Environment.CurrentManagedThreadId;
			}

			[DebuggerHidden]
			void IDisposable.Dispose()
			{
				<t>5__1 = null;
				<names>5__2 = null;
				<>s__3 = null;
				<n>5__5 = null;
				<m>5__6 = null;
				<>1__state = -2;
			}

			private bool MoveNext()
			{
				int num = <>1__state;
				if (num != 0)
				{
					if (num != 1)
					{
						return false;
					}
					<>1__state = -1;
					goto IL_00be;
				}
				<>1__state = -1;
				<t>5__1 = AccessTools.TypeByName("EnemyHealth");
				<names>5__2 = new string[2] { "Start", "OnEnable" };
				<>s__3 = <names>5__2;
				<>s__4 = 0;
				goto IL_00db;
				IL_00be:
				<m>5__6 = null;
				<n>5__5 = null;
				<>s__4++;
				goto IL_00db;
				IL_00db:
				if (<>s__4 < <>s__3.Length)
				{
					<n>5__5 = <>s__3[<>s__4];
					<m>5__6 = AccessTools.Method(<t>5__1, <n>5__5, (Type[])null, (Type[])null);
					if (<m>5__6 != null)
					{
						<>2__current = <m>5__6;
						<>1__state = 1;
						return true;
					}
					goto IL_00be;
				}
				<>s__3 = null;
				return false;
			}

			bool IEnumerator.MoveNext()
			{
				//ILSpy generated this explicit interface implementation from .override directive in MoveNext
				return this.MoveNext();
			}

			[DebuggerHidden]
			void IEnumerator.Reset()
			{
				throw new NotSupportedException();
			}

			[DebuggerHidden]
			IEnumerator<MethodBase> IEnumerable<MethodBase>.GetEnumerator()
			{
				if (<>1__state == -2 && <>l__initialThreadId == Environment.CurrentManagedThreadId)
				{
					<>1__state = 0;
					return this;
				}
				return new <TargetMethods>d__0(0);
			}

			[DebuggerHidden]
			IEnumerator IEnumerable.GetEnumerator()
			{
				return ((IEnumerable<MethodBase>)this).GetEnumerator();
			}
		}

		[IteratorStateMachine(typeof(<TargetMethods>d__0))]
		private static IEnumerable<MethodBase> TargetMethods()
		{
			//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
			return new <TargetMethods>d__0(-2);
		}

		[HarmonyPostfix]
		private static void Post_AttachFallback(MonoBehaviour __instance)
		{
			HealthBarAttacher.AttachTo(__instance);
		}
	}
	[HarmonyPatch]
	internal static class EnemyHealthEventPatches
	{
		[CompilerGenerated]
		private sealed class <TargetMethods>d__2 : IEnumerable<MethodBase>, IEnumerable, IEnumerator<MethodBase>, IEnumerator, IDisposable
		{
			private int <>1__state;

			private MethodBase <>2__current;

			private int <>l__initialThreadId;

			private string[] <names>5__1;

			private string[] <>s__2;

			private int <>s__3;

			private string <n>5__4;

			private MethodInfo <m>5__5;

			MethodBase IEnumerator<MethodBase>.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			object IEnumerator.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			[DebuggerHidden]
			public <TargetMethods>d__2(int <>1__state)
			{
				this.<>1__state = <>1__state;
				<>l__initialThreadId = Environment.CurrentManagedThreadId;
			}

			[DebuggerHidden]
			void IDisposable.Dispose()
			{
				<names>5__1 = null;
				<>s__2 = null;
				<n>5__4 = null;
				<m>5__5 = null;
				<>1__state = -2;
			}

			private bool MoveNext()
			{
				int num = <>1__state;
				if (num != 0)
				{
					if (num != 1)
					{
						return false;
					}
					<>1__state = -1;
					goto IL_00d5;
				}
				<>1__state = -1;
				<names>5__1 = new string[7] { "Hurt", "HurtRPC", "Heal", "HealRPC", "Death", "DeathRPC", "DeathImpulseRPC" };
				<>s__2 = <names>5__1;
				<>s__3 = 0;
				goto IL_00f2;
				IL_00d5:
				<m>5__5 = null;
				<n>5__4 = null;
				<>s__3++;
				goto IL_00f2;
				IL_00f2:
				if (<>s__3 < <>s__2.Length)
				{
					<n>5__4 = <>s__2[<>s__3];
					<m>5__5 = AccessTools.Method(EH, <n>5__4, (Type[])null, (Type[])null);
					if (<m>5__5 != null)
					{
						<>2__current = <m>5__5;
						<>1__state = 1;
						return true;
					}
					goto IL_00d5;
				}
				<>s__2 = null;
				return false;
			}

			bool IEnumerator.MoveNext()
			{
				//ILSpy generated this explicit interface implementation from .override directive in MoveNext
				return this.MoveNext();
			}

			[DebuggerHidden]
			void IEnumerator.Reset()
			{
				throw new NotSupportedException();
			}

			[DebuggerHidden]
			IEnumerator<MethodBase> IEnumerable<MethodBase>.GetEnumerator()
			{
				if (<>1__state == -2 && <>l__initialThreadId == Environment.CurrentManagedThreadId)
				{
					<>1__state = 0;
					return this;
				}
				return new <TargetMethods>d__2(0);
			}

			[DebuggerHidden]
			IEnumerator IEnumerable.GetEnumerator()
			{
				return ((IEnumerable<MethodBase>)this).GetEnumerator();
			}
		}

		private static Type EH => AccessTools.TypeByName("EnemyHealth");

		[IteratorStateMachine(typeof(<TargetMethods>d__2))]
		private static IEnumerable<MethodBase> TargetMethods()
		{
			//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
			return new <TargetMethods>d__2(-2);
		}

		[HarmonyPostfix]
		private static void Post_HPEvents(MonoBehaviour __instance)
		{
			EnemyHealthBar component = ((Component)__instance).GetComponent<EnemyHealthBar>();
			if ((Object)(object)component != (Object)null)
			{
				component.OnHealthTouched();
			}
		}
	}
	internal static class HealthBarAttacher
	{
		internal static void AttachTo(MonoBehaviour enemyHealth)
		{
			if ((Object)(object)enemyHealth == (Object)null)
			{
				return;
			}
			Type type = ((object)enemyHealth).GetType();
			if (type.Name != "EnemyHealth" || (Object)(object)((Component)enemyHealth).GetComponent<EnemyHealthBar>() != (Object)null)
			{
				return;
			}
			try
			{
				EnemyHealthBar enemyHealthBar = ((Component)enemyHealth).gameObject.AddComponent<EnemyHealthBar>();
				enemyHealthBar.Initialize(enemyHealth);
			}
			catch (Exception arg)
			{
				EnemyHealthBarsPlugin.Logger.LogWarning((object)$"Failed to attach health bar: {arg}");
			}
		}
	}
	public class EnemyHealthBar : MonoBehaviour
	{
		private static readonly Type EH = AccessTools.TypeByName("EnemyHealth");

		private static readonly FieldInfo F_health = AccessTools.Field(EH, "health");

		private static readonly FieldInfo F_healthCurrent = AccessTools.Field(EH, "healthCurrent");

		private static readonly FieldInfo F_dead = AccessTools.Field(EH, "dead");

		private static readonly FieldInfo F_meshParent = AccessTools.Field(EH, "meshParent");

		private static readonly FieldInfo F_onHurt = AccessTools.Field(EH, "onHurt");

		private static readonly FieldInfo F_onDeath = AccessTools.Field(EH, "onDeath");

		private MonoBehaviour enemyHealth = null;

		private int maxHealth;

		private int lastHealth;

		private bool dead;

		private Transform anchor = null;

		private readonly List<Renderer> renderers = new List<Renderer>();

		private GameObject rootGO = null;

		private Canvas canvas = null;

		private RectTransform rect = null;

		private Image imgFill = null;

		private Image imgChip = null;

		private Image imgBack = null;

		private Text textComp = null;

		private float showTimer;

		private float currentFill = 1f;

		private float chipFill = 1f;

		private Camera cachedCam;

		private static Sprite whiteSprite;

		private bool initialized;

		public void Initialize(MonoBehaviour eh)
		{
			enemyHealth = eh;
			maxHealth = SafeGet(F_health, enemyHealth, 100);
			lastHealth = SafeGet(F_healthCurrent, enemyHealth, maxHealth);
			dead = SafeGet(F_dead, enemyHealth, fallback: false);
			Transform val = SafeGet<Transform>(F_meshParent, enemyHealth, null);
			anchor = ((EnemyHealthBarsPlugin.UseMeshParentIfAvailable.Value && (Object)(object)val != (Object)null) ? val : ((Component)enemyHealth).transform);
			((Component)anchor).GetComponentsInChildren<Renderer>(true, renderers);
			if (renderers.Count == 0)
			{
				((Component)enemyHealth).GetComponentsInChildren<Renderer>(true, renderers);
			}
			BuildUI();
			HookUnityEventsIfPresent();
			initialized = true;
		}

		private void HookUnityEventsIfPresent()
		{
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0036: Expected O, but got Unknown
			//IL_0061: Unknown result type (might be due to invalid IL or missing references)
			//IL_006b: Expected O, but got Unknown
			try
			{
				object? obj = F_onHurt?.GetValue(enemyHealth);
				UnityEvent val = (UnityEvent)((obj is UnityEvent) ? obj : null);
				if (val != null)
				{
					val.AddListener(new UnityAction(OnHealthTouched));
				}
				object? obj2 = F_onDeath?.GetValue(enemyHealth);
				UnityEvent val2 = (UnityEvent)((obj2 is UnityEvent) ? obj2 : null);
				if (val2 != null)
				{
					val2.AddListener(new UnityAction(OnDeath));
				}
			}
			catch (Exception ex)
			{
				EnemyHealthBarsPlugin.Logger.LogDebug((object)("UnityEvent hook skipped: " + ex.Message));
			}
		}

		private void BuildUI()
		{
			//IL_0088: Unknown result type (might be due to invalid IL or missing references)
			//IL_0092: Expected O, but got Unknown
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_001e: Expected O, but got Unknown
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			//IL_004b: 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_013b: 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_0164: Expected O, but got Unknown
			//IL_0184: Unknown result type (might be due to invalid IL or missing references)
			//IL_0190: Unknown result type (might be due to invalid IL or missing references)
			//IL_019c: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a8: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e7: Unknown result type (might be due to invalid IL or missing references)
			//IL_020a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0211: Expected O, but got Unknown
			//IL_0230: Unknown result type (might be due to invalid IL or missing references)
			//IL_023d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0255: Unknown result type (might be due to invalid IL or missing references)
			//IL_0268: Unknown result type (might be due to invalid IL or missing references)
			//IL_02b8: Unknown result type (might be due to invalid IL or missing references)
			//IL_02db: Unknown result type (might be due to invalid IL or missing references)
			//IL_02e2: Expected O, but got Unknown
			//IL_0301: Unknown result type (might be due to invalid IL or missing references)
			//IL_030e: Unknown result type (might be due to invalid IL or missing references)
			//IL_031f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0332: Unknown result type (might be due to invalid IL or missing references)
			//IL_039c: Unknown result type (might be due to invalid IL or missing references)
			//IL_03d0: Unknown result type (might be due to invalid IL or missing references)
			//IL_03d7: Expected O, but got Unknown
			//IL_03f6: Unknown result type (might be due to invalid IL or missing references)
			//IL_0403: Unknown result type (might be due to invalid IL or missing references)
			//IL_0414: Unknown result type (might be due to invalid IL or missing references)
			//IL_0427: Unknown result type (might be due to invalid IL or missing references)
			//IL_0491: Unknown result type (might be due to invalid IL or missing references)
			//IL_04c5: Unknown result type (might be due to invalid IL or missing references)
			//IL_04cc: Expected O, but got Unknown
			//IL_04f5: Unknown result type (might be due to invalid IL or missing references)
			//IL_050c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0519: Unknown result type (might be due to invalid IL or missing references)
			//IL_0526: Unknown result type (might be due to invalid IL or missing references)
			//IL_0581: Unknown result type (might be due to invalid IL or missing references)
			//IL_05a5: Unknown result type (might be due to invalid IL or missing references)
			//IL_05bc: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)whiteSprite == (Object)null)
			{
				Texture2D val = new Texture2D(1, 1, (TextureFormat)4, false);
				val.SetPixel(0, 0, Color.white);
				val.Apply();
				whiteSprite = Sprite.Create(val, new Rect(0f, 0f, 1f, 1f), new Vector2(0.5f, 0.5f), 100f);
			}
			rootGO = new GameObject("EmpressHealthBar", new Type[1] { typeof(RectTransform) });
			((Object)rootGO).hideFlags = (HideFlags)52;
			rootGO.layer = (((Object)(object)anchor != (Object)null) ? ((Component)anchor).gameObject.layer : 0);
			Canvas val2 = rootGO.AddComponent<Canvas>();
			val2.renderMode = (RenderMode)2;
			val2.sortingOrder = 5000;
			canvas = val2;
			CanvasGroup val3 = rootGO.AddComponent<CanvasGroup>();
			val3.interactable = false;
			val3.blocksRaycasts = false;
			rect = rootGO.GetComponent<RectTransform>();
			rect.sizeDelta = new Vector2(EnemyHealthBarsPlugin.BarWidth.Value, EnemyHealthBarsPlugin.BarHeight.Value);
			GameObject val4 = new GameObject("Frame", new Type[1] { typeof(RectTransform) });
			val4.transform.SetParent(rootGO.transform, false);
			RectTransform component = val4.GetComponent<RectTransform>();
			component.anchorMin = Vector2.zero;
			component.anchorMax = Vector2.one;
			component.offsetMin = Vector2.zero;
			component.offsetMax = Vector2.zero;
			Image val5 = val4.AddComponent<Image>();
			val5.sprite = whiteSprite;
			val5.type = (Type)0;
			((Graphic)val5).color = new Color(0.1f, 0.1f, 0.1f, 1f);
			GameObject val6 = new GameObject("Back", new Type[1] { typeof(RectTransform) });
			val6.transform.SetParent(val4.transform, false);
			RectTransform component2 = val6.GetComponent<RectTransform>();
			component2.anchorMin = Vector2.zero;
			component2.anchorMax = Vector2.one;
			float num = 0.015f;
			component2.offsetMin = new Vector2(num, num);
			component2.offsetMax = new Vector2(0f - num, 0f - num);
			imgBack = val6.AddComponent<Image>();
			imgBack.sprite = whiteSprite;
			imgBack.type = (Type)0;
			((Graphic)imgBack).color = new Color(0.8f, 0.8f, 0.8f, 0.25f);
			GameObject val7 = new GameObject("Chip", new Type[1] { typeof(RectTransform) });
			val7.transform.SetParent(val4.transform, false);
			RectTransform component3 = val7.GetComponent<RectTransform>();
			component3.anchorMin = Vector2.zero;
			component3.anchorMax = Vector2.one;
			component3.offsetMin = new Vector2(num, num);
			component3.offsetMax = new Vector2(0f - num, 0f - num);
			imgChip = val7.AddComponent<Image>();
			imgChip.sprite = whiteSprite;
			imgChip.type = (Type)3;
			imgChip.fillMethod = (FillMethod)0;
			imgChip.fillOrigin = 0;
			((Graphic)imgChip).color = new Color(0.9f, 0.7f, 0.1f, 0.95f);
			imgChip.fillAmount = 1f;
			GameObject val8 = new GameObject("Fill", new Type[1] { typeof(RectTransform) });
			val8.transform.SetParent(val4.transform, false);
			RectTransform component4 = val8.GetComponent<RectTransform>();
			component4.anchorMin = Vector2.zero;
			component4.anchorMax = Vector2.one;
			component4.offsetMin = new Vector2(num, num);
			component4.offsetMax = new Vector2(0f - num, 0f - num);
			imgFill = val8.AddComponent<Image>();
			imgFill.sprite = whiteSprite;
			imgFill.type = (Type)3;
			imgFill.fillMethod = (FillMethod)0;
			imgFill.fillOrigin = 0;
			((Graphic)imgFill).color = new Color(0.9f, 0.1f, 0.1f, 1f);
			imgFill.fillAmount = 1f;
			GameObject val9 = new GameObject("Text", new Type[1] { typeof(RectTransform) });
			val9.transform.SetParent(val4.transform, false);
			RectTransform component5 = val9.GetComponent<RectTransform>();
			component5.anchorMin = new Vector2(0f, 0f);
			component5.anchorMax = new Vector2(1f, 1f);
			component5.offsetMin = Vector2.zero;
			component5.offsetMax = Vector2.zero;
			textComp = val9.AddComponent<Text>();
			textComp.font = Resources.GetBuiltinResource<Font>("Arial.ttf");
			textComp.alignment = (TextAnchor)4;
			textComp.horizontalOverflow = (HorizontalWrapMode)1;
			textComp.verticalOverflow = (VerticalWrapMode)0;
			((Graphic)textComp).color = Color.white;
			textComp.fontSize = 9;
			Shadow val10 = val9.AddComponent<Shadow>();
			val10.effectColor = Color.black;
			val10.effectDistance = new Vector2(1f, -1f);
			rootGO.transform.SetParent(((Component)enemyHealth).transform, false);
		}

		private void OnDestroy()
		{
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0036: Expected O, but got Unknown
			//IL_0061: Unknown result type (might be due to invalid IL or missing references)
			//IL_006b: Expected O, but got Unknown
			try
			{
				object? obj = F_onHurt?.GetValue(enemyHealth);
				UnityEvent val = (UnityEvent)((obj is UnityEvent) ? obj : null);
				if (val != null)
				{
					val.RemoveListener(new UnityAction(OnHealthTouched));
				}
				object? obj2 = F_onDeath?.GetValue(enemyHealth);
				UnityEvent val2 = (UnityEvent)((obj2 is UnityEvent) ? obj2 : null);
				if (val2 != null)
				{
					val2.RemoveListener(new UnityAction(OnDeath));
				}
			}
			catch
			{
			}
		}

		public void OnHealthTouched()
		{
			maxHealth = SafeGet(F_health, enemyHealth, maxHealth);
			int num = SafeGet(F_healthCurrent, enemyHealth, lastHealth);
			lastHealth = num;
			showTimer = Mathf.Max(showTimer, EnemyHealthBarsPlugin.ShowOnDamageSeconds.Value);
		}

		private void OnDeath()
		{
			dead = true;
			if ((Object)(object)rootGO != (Object)null)
			{
				rootGO.SetActive(false);
			}
		}

		private void Update()
		{
			if (!initialized || (Object)(object)enemyHealth == (Object)null)
			{
				return;
			}
			if ((Object)(object)cachedCam == (Object)null || !((Behaviour)cachedCam).isActiveAndEnabled)
			{
				cachedCam = FindCamera();
			}
			if ((Object)(object)cachedCam == (Object)null)
			{
				if ((Object)(object)rootGO != (Object)null)
				{
					rootGO.SetActive(false);
				}
				return;
			}
			int num = SafeGet(F_healthCurrent, enemyHealth, lastHealth);
			int num2 = SafeGet(F_health, enemyHealth, maxHealth);
			if (num2 <= 0)
			{
				num2 = 1;
			}
			float num3 = Mathf.Clamp01((float)num / (float)num2);
			if ((Object)(object)textComp != (Object)null)
			{
				textComp.text = $"{num} / {num2}";
			}
			float num4 = currentFill;
			bool flag = num3 < num4 - 0.0001f;
			bool flag2 = num3 > num4 + 0.0001f;
			if (flag)
			{
				currentFill = num3;
				chipFill = Mathf.Max(chipFill, num4);
			}
			else if (flag2)
			{
				currentFill = Mathf.Lerp(num4, num3, EnemyHealthBarsPlugin.LerpSpeed.Value * Time.deltaTime);
			}
			else
			{
				currentFill = Mathf.Lerp(num4, num3, EnemyHealthBarsPlugin.LerpSpeed.Value * Time.deltaTime);
			}
			float num5 = currentFill;
			float num6 = ((chipFill > num5) ? EnemyHealthBarsPlugin.ChipDropSpeed.Value : EnemyHealthBarsPlugin.HealCatchupSpeed.Value);
			chipFill = Mathf.Lerp(chipFill, num5, num6 * Time.deltaTime);
			if ((Object)(object)imgFill != (Object)null)
			{
				imgFill.fillAmount = currentFill;
			}
			if ((Object)(object)imgChip != (Object)null)
			{
				imgChip.fillAmount = chipFill;
			}
			bool flag3 = EnemyHealthBarsPlugin.AlwaysShow.Value;
			if (!flag3)
			{
				showTimer -= Time.deltaTime;
				if (showTimer > 0f)
				{
					flag3 = true;
				}
			}
			if (EnemyHealthBarsPlugin.OnlyWhenVisible.Value && !AnyRendererVisible())
			{
				flag3 = false;
			}
			if ((Object)(object)rootGO != (Object)null)
			{
				rootGO.SetActive(flag3 && !dead);
			}
		}

		private void LateUpdate()
		{
			//IL_0040: Unknown result type (might be due to invalid IL or missing references)
			//IL_0045: 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_004d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0054: Unknown result type (might be due to invalid IL or missing references)
			//IL_005e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0063: Unknown result type (might be due to invalid IL or missing references)
			//IL_0068: Unknown result type (might be due to invalid IL or missing references)
			//IL_0075: Unknown result type (might be due to invalid IL or missing references)
			//IL_008c: Unknown result type (might be due to invalid IL or missing references)
			//IL_008d: Unknown result type (might be due to invalid IL or missing references)
			//IL_009d: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00da: Unknown result type (might be due to invalid IL or missing references)
			//IL_00df: Unknown result type (might be due to invalid IL or missing references)
			//IL_011d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0122: Unknown result type (might be due to invalid IL or missing references)
			//IL_0168: Unknown result type (might be due to invalid IL or missing references)
			//IL_016f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0102: Unknown result type (might be due to invalid IL or missing references)
			if (initialized && !((Object)(object)rootGO == (Object)null) && !((Object)(object)anchor == (Object)null) && !((Object)(object)cachedCam == (Object)null))
			{
				Bounds val = ComputeBounds();
				Vector3 val2 = ((Bounds)(ref val)).center + Vector3.up * ((Bounds)(ref val)).extents.y;
				float num = EnemyHealthBarsPlugin.ExtraOffsetMeters.Value + ((Bounds)(ref val)).size.y * EnemyHealthBarsPlugin.OffsetPercentOfHeight.Value;
				Vector3 val3 = val2 + Vector3.up * Mathf.Max(0.01f, num);
				rootGO.transform.position = val3;
				Vector3 val4 = rootGO.transform.position - ((Component)cachedCam).transform.position;
				if (((Vector3)(ref val4)).sqrMagnitude > 0.0001f)
				{
					rootGO.transform.forward = ((Vector3)(ref val4)).normalized;
				}
				float num2 = Mathf.Max(0.01f, Vector3.Distance(((Component)cachedCam).transform.position, val3));
				float num3 = Mathf.Clamp(1f + num2 * EnemyHealthBarsPlugin.DistanceScaleFactor.Value, EnemyHealthBarsPlugin.MinScale.Value, EnemyHealthBarsPlugin.MaxScale.Value);
				rootGO.transform.localScale = Vector3.one * num3;
			}
		}

		private Bounds ComputeBounds()
		{
			//IL_0009: Unknown result type (might be due to invalid IL or missing references)
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_0180: Unknown result type (might be due to invalid IL or missing references)
			//IL_0181: Unknown result type (might be due to invalid IL or missing references)
			//IL_014d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0152: Unknown result type (might be due to invalid IL or missing references)
			//IL_015c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0161: Unknown result type (might be due to invalid IL or missing references)
			//IL_0175: Unknown result type (might be due to invalid IL or missing references)
			//IL_0185: Unknown result type (might be due to invalid IL or missing references)
			//IL_006e: Unknown result type (might be due to invalid IL or missing references)
			//IL_005f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0064: Unknown result type (might be due to invalid IL or missing references)
			//IL_0111: Unknown result type (might be due to invalid IL or missing references)
			//IL_0101: Unknown result type (might be due to invalid IL or missing references)
			//IL_0106: Unknown result type (might be due to invalid IL or missing references)
			Bounds bounds = default(Bounds);
			((Bounds)(ref bounds))..ctor(anchor.position, Vector3.one * 0.5f);
			bool flag = false;
			for (int i = 0; i < renderers.Count; i++)
			{
				Renderer val = renderers[i];
				if (!((Object)(object)val == (Object)null) && val.enabled)
				{
					if (!flag)
					{
						bounds = val.bounds;
						flag = true;
					}
					else
					{
						((Bounds)(ref bounds)).Encapsulate(val.bounds);
					}
				}
			}
			if (!flag)
			{
				renderers.Clear();
				((Component)anchor).GetComponentsInChildren<Renderer>(true, renderers);
				for (int j = 0; j < renderers.Count; j++)
				{
					Renderer val2 = renderers[j];
					if (!((Object)(object)val2 == (Object)null) && val2.enabled)
					{
						if (!flag)
						{
							bounds = val2.bounds;
							flag = true;
						}
						else
						{
							((Bounds)(ref bounds)).Encapsulate(val2.bounds);
						}
					}
				}
			}
			if (!flag)
			{
				((Bounds)(ref bounds))..ctor(anchor.position + Vector3.up * 1f, new Vector3(1f, 2f, 1f));
			}
			return bounds;
		}

		private bool AnyRendererVisible()
		{
			for (int i = 0; i < renderers.Count; i++)
			{
				Renderer val = renderers[i];
				if ((Object)(object)val != (Object)null && val.enabled && val.isVisible)
				{
					return true;
				}
			}
			return false;
		}

		private Camera FindCamera()
		{
			Camera main = Camera.main;
			if ((Object)(object)main != (Object)null && ((Behaviour)main).isActiveAndEnabled)
			{
				return main;
			}
			Camera[] array = Object.FindObjectsOfType<Camera>();
			Camera[] array2 = array;
			foreach (Camera val in array2)
			{
				if ((Object)(object)val != (Object)null && ((Behaviour)val).isActiveAndEnabled)
				{
					return val;
				}
			}
			return null;
		}

		private static T SafeGet<T>(FieldInfo fi, object inst, T fallback)
		{
			try
			{
				if (fi == null || inst == null)
				{
					return fallback;
				}
				object value = fi.GetValue(inst);
				if (value is T result)
				{
					return result;
				}
				if (value == null)
				{
					return fallback;
				}
				return (T)Convert.ChangeType(value, typeof(T));
			}
			catch
			{
				return fallback;
			}
		}
	}
}