Please disclose if any significant portion of your mod was created using AI tools by adding the 'AI Generated' category. Failing to do so may result in the mod being removed from Thunderstore.
Decompiled source of EnemyHealthBar v1.0.0
EnemyHealthBar.dll
Decompiled a day agousing 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 BepInEx.Logging; using EnemyHealthBar.Config; using EnemyHealthBar.Services; using EnemyHealthBar.UI; using EnemyHealthBar.Utilities; using HarmonyLib; using Microsoft.CodeAnalysis; using TMPro; using UnityEngine; 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: AssemblyVersion("0.0.0.0")] [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 EnemyHealthBar { [BepInPlugin("DarkSpider90.EnemyHealthBar", "EnemyHealthBar", "1.0.0")] public sealed class Plugin : BaseUnityPlugin { public const string ModGuid = "DarkSpider90.EnemyHealthBar"; public const string ModName = "EnemyHealthBar"; public const string ModVersion = "1.0.0"; private readonly Harmony _harmony = new Harmony("DarkSpider90.EnemyHealthBar"); internal static ManualLogSource Log { get; private set; } internal static ModConfig Settings { get; private set; } private void Awake() { Log = ((BaseUnityPlugin)this).Logger; Settings = new ModConfig(((BaseUnityPlugin)this).Config); _harmony.PatchAll(); Log.LogInfo((object)"EnemyHealthBar by DarkSpider90 loaded. v1.0.0"); } private void OnDestroy() { _harmony.UnpatchSelf(); } } } namespace EnemyHealthBar.Utilities { internal static class ColorUtils { internal static Color Parse(string htmlColor, Color fallback) { //IL_000e: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_000f: Unknown result type (might be due to invalid IL or missing references) //IL_0012: Unknown result type (might be due to invalid IL or missing references) Color val = default(Color); return ColorUtility.TryParseHtmlString(htmlColor, ref val) ? val : fallback; } internal static Color WithAlpha(Color color, float alpha) { //IL_000e: Unknown result type (might be due to invalid IL or missing references) //IL_000f: Unknown result type (might be due to invalid IL or missing references) //IL_0012: Unknown result type (might be due to invalid IL or missing references) color.a = Mathf.Clamp01(alpha); return color; } } } namespace EnemyHealthBar.UI { internal sealed class EnemyHealthBarDisplay : MonoBehaviour { private const float BoundsRefreshInterval = 0.65f; private EnemyHealth _enemyHealth; private GameObject _root; private RectTransform _canvasRect; private Image _foreground; private Image _background; private TextMeshProUGUI _healthText; private int _displayedCurrent; private int _displayedMax; private bool _hasHealthState; private float _targetFill = 1f; private float _smoothedFill = 1f; private float _lastRevealTime = -999f; private float _verticalBarOffset = 1.7f; private float _nextBoundsRefreshTime; private static Sprite _whiteSprite; private void Awake() { _enemyHealth = ((Component)this).GetComponent<EnemyHealth>(); } private void Start() { if (Plugin.Settings.HealthBarEnabled.Value && !((Object)(object)_enemyHealth == (Object)null)) { SetHealth(_enemyHealth.health, _enemyHealth.health, silent: true); } } private void LateUpdate() { //IL_00d4: Unknown result type (might be due to invalid IL or missing references) //IL_00d9: Unknown result type (might be due to invalid IL or missing references) //IL_00e5: Unknown result type (might be due to invalid IL or missing references) //IL_011c: Unknown result type (might be due to invalid IL or missing references) //IL_0110: Unknown result type (might be due to invalid IL or missing references) //IL_0166: Unknown result type (might be due to invalid IL or missing references) //IL_0184: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)_enemyHealth == (Object)null) { DestroyRoot(); Object.Destroy((Object)(object)this); return; } if (!Plugin.Settings.HealthBarEnabled.Value || !_hasHealthState || _displayedCurrent <= 0) { HideRoot(); return; } if (!Plugin.Settings.AlwaysVisible.Value && Time.time - _lastRevealTime > Plugin.Settings.HideAfterSeconds.Value) { HideRoot(); return; } EnsureCanvas(); if ((Object)(object)_root == (Object)null || (Object)(object)_canvasRect == (Object)null) { return; } Vector3 val = CalculateTargetPosition(); _root.transform.position = val; Camera main = Camera.main; if ((Object)(object)main != (Object)null) { _root.transform.rotation = ((Component)main).transform.rotation; } float num = CalculateVisibilityAlpha(val, main); if (num <= 0f) { HideRoot(); return; } if (!_root.activeSelf) { _root.SetActive(true); } ((Transform)_canvasRect).localScale = Vector3.one * Mathf.Max(0.001f, Plugin.Settings.BarScale.Value); RefreshVisuals(num); } internal void SetHealth(int current, int max, bool silent) { _displayedMax = Mathf.Max(1, max); _displayedCurrent = Mathf.Clamp(current, 0, _displayedMax); _hasHealthState = true; _targetFill = Mathf.Clamp01((float)_displayedCurrent / (float)_displayedMax); if (silent) { _smoothedFill = _targetFill; } else { Reveal(); } } internal void ApplyClientDamage(int damage, int max) { int num = Mathf.Max(1, max); if (!_hasHealthState || _displayedMax != num) { _displayedMax = num; _displayedCurrent = num; _hasHealthState = true; _smoothedFill = 1f; } _displayedCurrent = Mathf.Clamp(_displayedCurrent - Mathf.Max(0, damage), 0, _displayedMax); _targetFill = Mathf.Clamp01((float)_displayedCurrent / (float)_displayedMax); Reveal(); } internal void Reveal() { _lastRevealTime = Time.time; if ((Object)(object)_root != (Object)null && !_root.activeSelf) { _root.SetActive(true); } } internal void KillImmediately() { DestroyRoot(); Object.Destroy((Object)(object)this); } private float CalculateVisibilityAlpha(Vector3 barPosition, Camera camera) { //IL_00c6: Unknown result type (might be due to invalid IL or missing references) //IL_00cb: Unknown result type (might be due to invalid IL or missing references) float num = 1f; if (!Plugin.Settings.AlwaysVisible.Value) { float num2 = _lastRevealTime + Mathf.Max(0.1f, Plugin.Settings.HideAfterSeconds.Value); float num3 = num2 - Time.time; if (num3 <= 0f) { return 0f; } float num4 = Mathf.Max(0.01f, Plugin.Settings.HideFadeDuration.Value); if (num3 < num4) { num *= Mathf.Clamp01(num3 / num4); } } if ((Object)(object)camera != (Object)null) { float num5 = Mathf.Max(1f, Plugin.Settings.FadeDistance.Value); float num6 = Vector3.Distance(((Component)camera).transform.position, barPosition); num *= Mathf.Clamp01(1f - num6 / num5); } return num; } private Vector3 CalculateTargetPosition() { //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_0016: Unknown result type (might be due to invalid IL or missing references) //IL_003b: Unknown result type (might be due to invalid IL or missing references) //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) Transform val = ResolveFollowAnchor(); RefreshVerticalOffset(val); return val.position + Vector3.up * (_verticalBarOffset + Mathf.Max(0f, Plugin.Settings.ExtraHeightOffset.Value)); } private Transform ResolveFollowAnchor() { Transform val = ResolveEnemyRootForBounds(); if ((Object)(object)val != (Object)null) { EnemyRigidbody componentInChildren = ((Component)val).GetComponentInChildren<EnemyRigidbody>(true); if ((Object)(object)componentInChildren != (Object)null) { return ((Component)componentInChildren).transform; } Transform val2 = FindNamedDescendant(val, "Center"); if ((Object)(object)val2 != (Object)null) { return val2; } } return ((Component)this).transform; } private void RefreshVerticalOffset(Transform anchor) { //IL_0058: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)anchor == (Object)null) && !(Time.time < _nextBoundsRefreshTime)) { _nextBoundsRefreshTime = Time.time + 0.65f; Transform val = ResolveEnemyRootForBounds(); if (!((Object)(object)val == (Object)null) && TryResolveTopY(val, out var topY)) { _verticalBarOffset = Mathf.Clamp(topY - anchor.position.y + 0.2f, 0.4f, 16f); } } } private Transform ResolveEnemyRootForBounds() { if ((Object)(object)_enemyHealth != (Object)null && (Object)(object)((Component)_enemyHealth).transform != (Object)null && (Object)(object)((Component)_enemyHealth).transform.parent != (Object)null) { return ((Component)_enemyHealth).transform.parent; } return ((Component)this).transform; } private void EnsureCanvas() { //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_0026: Expected O, but got Unknown //IL_006a: Unknown result type (might be due to invalid IL or missing references) //IL_007b: 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) if (!((Object)(object)_root != (Object)null)) { _root = new GameObject("EnemyHealthBar_View"); Canvas val = _root.AddComponent<Canvas>(); val.renderMode = (RenderMode)2; _canvasRect = ((Component)val).GetComponent<RectTransform>(); _canvasRect.sizeDelta = new Vector2(Plugin.Settings.BarWidth.Value, Plugin.Settings.BarHeight.Value); ((Transform)_canvasRect).localScale = Vector3.one * Mathf.Max(0.001f, Plugin.Settings.BarScale.Value); _background = CreateImage((Transform)(object)_canvasRect, "Background"); Stretch(((Graphic)_background).rectTransform, 0f); _foreground = CreateImage((Transform)(object)_canvasRect, "Foreground"); Stretch(((Graphic)_foreground).rectTransform, 3f); _foreground.type = (Type)3; _foreground.fillMethod = (FillMethod)0; _foreground.fillOrigin = 0; _foreground.fillAmount = _smoothedFill; CreateHealthText((Transform)(object)_canvasRect); } } private static Image CreateImage(Transform parent, string name) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0008: Expected O, but got Unknown GameObject val = new GameObject(name); val.transform.SetParent(parent, false); Image val2 = val.AddComponent<Image>(); val2.sprite = GetWhiteSprite(); ((Graphic)val2).raycastTarget = false; return val2; } private void CreateHealthText(Transform parent) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Expected O, but got Unknown GameObject val = new GameObject("HealthText"); val.transform.SetParent(parent, false); _healthText = val.AddComponent<TextMeshProUGUI>(); ((TMP_Text)_healthText).alignment = (TextAlignmentOptions)514; ((TMP_Text)_healthText).enableAutoSizing = false; ((Graphic)_healthText).raycastTarget = false; RectTransform rectTransform = ((TMP_Text)_healthText).rectTransform; Stretch(rectTransform, 0f); } private static void Stretch(RectTransform rect, float inset) { //IL_0002: 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_001c: Unknown result type (might be due to invalid IL or missing references) //IL_002c: Unknown result type (might be due to invalid IL or missing references) rect.anchorMin = Vector2.zero; rect.anchorMax = Vector2.one; rect.offsetMin = new Vector2(inset, inset); rect.offsetMax = new Vector2(0f - inset, 0f - inset); } private void RefreshVisuals(float alpha) { //IL_00d9: Unknown result type (might be due to invalid IL or missing references) //IL_00de: Unknown result type (might be due to invalid IL or missing references) //IL_00be: Unknown result type (might be due to invalid IL or missing references) //IL_00c3: Unknown result type (might be due to invalid IL or missing references) //IL_00e3: Unknown result type (might be due to invalid IL or missing references) //IL_0107: Unknown result type (might be due to invalid IL or missing references) //IL_010c: 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_013f: Unknown result type (might be due to invalid IL or missing references) //IL_0144: Unknown result type (might be due to invalid IL or missing references) //IL_0124: Unknown result type (might be due to invalid IL or missing references) //IL_0129: Unknown result type (might be due to invalid IL or missing references) //IL_0149: Unknown result type (might be due to invalid IL or missing references) //IL_0151: Unknown result type (might be due to invalid IL or missing references) //IL_0153: Unknown result type (might be due to invalid IL or missing references) //IL_0164: Unknown result type (might be due to invalid IL or missing references) //IL_0165: Unknown result type (might be due to invalid IL or missing references) //IL_016d: Unknown result type (might be due to invalid IL or missing references) //IL_01d0: Unknown result type (might be due to invalid IL or missing references) //IL_01d2: Unknown result type (might be due to invalid IL or missing references) //IL_01db: Unknown result type (might be due to invalid IL or missing references) //IL_0205: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)_foreground == (Object)null) && !((Object)(object)_background == (Object)null)) { _smoothedFill = Mathf.Lerp(_smoothedFill, _targetFill, Time.deltaTime * Mathf.Max(0.01f, Plugin.Settings.BarLerpSpeed.Value)); _foreground.fillAmount = _smoothedFill; float num = ((_displayedMax > 0) ? Mathf.Clamp01((float)_displayedCurrent / (float)_displayedMax) : 0f); bool flag = num <= Plugin.Settings.LowHealthThreshold.Value; Color color = (flag ? ColorUtils.Parse(Plugin.Settings.LowHealthBarColor.Value, Color.yellow) : ColorUtils.Parse(Plugin.Settings.BarColor.Value, Color.red)); Color val = ColorUtils.Parse(Plugin.Settings.BackgroundColor.Value, new Color(0f, 0f, 0f, 0.65f)); Color val2 = (flag ? ColorUtils.Parse(Plugin.Settings.LowHealthTextColor.Value, Color.yellow) : ColorUtils.Parse(Plugin.Settings.TextColor.Value, Color.white)); ((Graphic)_foreground).color = ColorUtils.WithAlpha(color, alpha); ((Graphic)_background).color = ColorUtils.WithAlpha(val, val.a * alpha); if (!((Object)(object)_healthText == (Object)null)) { ((Component)_healthText).gameObject.SetActive(Plugin.Settings.ShowHealthText.Value); ((TMP_Text)_healthText).fontSize = Plugin.Settings.TextSize.Value; ((Graphic)_healthText).color = ColorUtils.WithAlpha(val2, val2.a * alpha); ((TMP_Text)_healthText).rectTransform.anchoredPosition = new Vector2(0f, Plugin.Settings.TextOffsetY.Value); ((TMP_Text)_healthText).text = (Plugin.Settings.ShowMaxHealth.Value ? $"{_displayedCurrent} / {_displayedMax}" : _displayedCurrent.ToString()); } } } private static Sprite GetWhiteSprite() { //IL_0037: Unknown result type (might be due to invalid IL or missing references) //IL_0046: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)_whiteSprite != (Object)null) { return _whiteSprite; } Texture2D whiteTexture = Texture2D.whiteTexture; _whiteSprite = Sprite.Create(whiteTexture, new Rect(0f, 0f, (float)((Texture)whiteTexture).width, (float)((Texture)whiteTexture).height), new Vector2(0.5f, 0.5f), 100f); return _whiteSprite; } private static bool TryResolveTopY(Transform root, out float topY) { //IL_004e: Unknown result type (might be due to invalid IL or missing references) //IL_0053: Unknown result type (might be due to invalid IL or missing references) //IL_0057: Unknown result type (might be due to invalid IL or missing references) //IL_00ce: 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) //IL_00d7: Unknown result type (might be due to invalid IL or missing references) topY = 0f; bool flag = false; Renderer[] componentsInChildren = ((Component)root).GetComponentsInChildren<Renderer>(false); Renderer[] array = componentsInChildren; Bounds bounds; foreach (Renderer val in array) { if (!((Object)(object)val == (Object)null) && !(((object)val).GetType().Name == "ParticleSystemRenderer")) { bounds = val.bounds; float y = ((Bounds)(ref bounds)).max.y; if (!flag || y > topY) { topY = y; flag = true; } } } if (flag) { return true; } Collider[] componentsInChildren2 = ((Component)root).GetComponentsInChildren<Collider>(false); Collider[] array2 = componentsInChildren2; foreach (Collider val2 in array2) { if (!((Object)(object)val2 == (Object)null) && !val2.isTrigger) { bounds = val2.bounds; float y2 = ((Bounds)(ref bounds)).max.y; if (!flag || y2 > topY) { topY = y2; flag = true; } } } return flag; } private static Transform FindNamedDescendant(Transform root, string namePart) { if ((Object)(object)root == (Object)null) { return null; } string value = namePart.ToLowerInvariant(); Transform[] componentsInChildren = ((Component)root).GetComponentsInChildren<Transform>(true); foreach (Transform val in componentsInChildren) { if ((Object)(object)val != (Object)null && ((Object)val).name.ToLowerInvariant().Contains(value)) { return val; } } return null; } private void HideRoot() { if ((Object)(object)_root != (Object)null && _root.activeSelf) { _root.SetActive(false); } } private void DestroyRoot() { if ((Object)(object)_root != (Object)null) { Object.Destroy((Object)(object)_root); _root = null; } } private void OnDisable() { DestroyRoot(); } private void OnDestroy() { DestroyRoot(); } } internal sealed class FloatingDamageText : MonoBehaviour { private TextMeshProUGUI _text; private Vector3 _startWorldPosition; private float _age; private float _lifetime; private float _riseDistance; private float _fadeMultiplier; internal void Initialize(int damage, Vector3 position, DamageTextStyle style) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0003: Unknown result type (might be due to invalid IL or missing references) //IL_0017: Unknown result type (might be due to invalid IL or missing references) //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_0021: Unknown result type (might be due to invalid IL or missing references) //IL_0084: Unknown result type (might be due to invalid IL or missing references) //IL_0090: Unknown result type (might be due to invalid IL or missing references) //IL_009b: Unknown result type (might be due to invalid IL or missing references) //IL_00ab: Unknown result type (might be due to invalid IL or missing references) //IL_00b1: Expected O, but got Unknown //IL_0122: Unknown result type (might be due to invalid IL or missing references) //IL_014c: Unknown result type (might be due to invalid IL or missing references) //IL_0158: Unknown result type (might be due to invalid IL or missing references) //IL_0164: Unknown result type (might be due to invalid IL or missing references) //IL_0170: Unknown result type (might be due to invalid IL or missing references) //IL_0182: Unknown result type (might be due to invalid IL or missing references) _startWorldPosition = position + Random.insideUnitSphere * Plugin.Settings.DamageTextRandomOffset.Value; _lifetime = Mathf.Max(0.05f, style.Lifetime); _riseDistance = style.FloatSpeed; _fadeMultiplier = Mathf.Max(0.01f, style.FadeMultiplier); Canvas val = ((Component)this).gameObject.AddComponent<Canvas>(); val.renderMode = (RenderMode)2; RectTransform component = ((Component)val).GetComponent<RectTransform>(); component.sizeDelta = new Vector2(150f, 72f); ((Transform)component).localScale = Vector3.one * style.CanvasScale; GameObject val2 = new GameObject("Text"); val2.transform.SetParent((Transform)(object)component, false); _text = val2.AddComponent<TextMeshProUGUI>(); ((TMP_Text)_text).alignment = (TextAlignmentOptions)514; ((TMP_Text)_text).enableAutoSizing = false; ((TMP_Text)_text).fontStyle = (FontStyles)1; ((Graphic)_text).raycastTarget = false; ((TMP_Text)_text).text = FormatDamage(style.Format, damage); ((Graphic)_text).color = style.Color; ((TMP_Text)_text).fontSize = style.Size; RectTransform rectTransform = ((TMP_Text)_text).rectTransform; rectTransform.anchorMin = Vector2.zero; rectTransform.anchorMax = Vector2.one; rectTransform.offsetMin = Vector2.zero; rectTransform.offsetMax = Vector2.zero; ((Component)this).transform.position = _startWorldPosition; FaceMainCamera(); } private void LateUpdate() { //IL_004b: Unknown result type (might be due to invalid IL or missing references) //IL_0050: Unknown result type (might be due to invalid IL or missing references) //IL_005d: Unknown result type (might be due to invalid IL or missing references) //IL_0062: Unknown result type (might be due to invalid IL or missing references) _age += Time.deltaTime; float num = Mathf.Clamp01(_age / _lifetime); if (num >= 1f) { Object.Destroy((Object)(object)((Component)this).gameObject); return; } ((Component)this).transform.position = _startWorldPosition + Vector3.up * (num * _riseDistance); FaceMainCamera(); if ((Object)(object)_text != (Object)null) { ((TMP_Text)_text).alpha = Mathf.Clamp01((1f - num * num) * _fadeMultiplier); } } private static string FormatDamage(string format, int damage) { if (string.IsNullOrWhiteSpace(format)) { format = "-{damage}"; } return format.Replace("{damage}", damage.ToString()); } private void FaceMainCamera() { //IL_001e: Unknown result type (might be due to invalid IL or missing references) Camera main = Camera.main; if ((Object)(object)main != (Object)null) { ((Component)this).transform.rotation = ((Component)main).transform.rotation; } } } } namespace EnemyHealthBar.Services { internal static class DamageTextSpawner { internal static void Spawn(Vector3 worldPosition, int damage) { //IL_0025: Unknown result type (might be due to invalid IL or missing references) //IL_002b: Expected O, but got Unknown //IL_0032: Unknown result type (might be due to invalid IL or missing references) if (Plugin.Settings.DamageTextEnabled.Value) { DamageTextStyle style = DamageTextStyle.FromDamage(damage); GameObject val = new GameObject("EnemyHealthBar_DamageText"); val.AddComponent<FloatingDamageText>().Initialize(damage, worldPosition, style); } } } internal readonly struct DamageTextStyle { internal readonly Color Color; internal readonly float Size; internal readonly float Lifetime; internal readonly float FloatSpeed; internal readonly float FadeMultiplier; internal readonly float CanvasScale; internal readonly string Format; private DamageTextStyle(Color color, float size, float lifetime, float floatSpeed, float fadeMultiplier, float canvasScale, string format) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0003: Unknown result type (might be due to invalid IL or missing references) Color = color; Size = size; Lifetime = lifetime; FloatSpeed = floatSpeed; FadeMultiplier = fadeMultiplier; CanvasScale = canvasScale; Format = format; } internal static DamageTextStyle FromDamage(int damage) { //IL_0021: Unknown result type (might be due to invalid IL or missing references) //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_002b: Unknown result type (might be due to invalid IL or missing references) //IL_00e2: Unknown result type (might be due to invalid IL or missing references) //IL_007d: 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_0087: Unknown result type (might be due to invalid IL or missing references) //IL_00c9: Unknown result type (might be due to invalid IL or missing references) //IL_00ce: 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) ModConfig settings = Plugin.Settings; Color color = ColorUtils.Parse(settings.DamageTextColor.Value, new Color(1f, 0.6f, 0.18f)); float value = settings.DamageTextSize.Value; if (settings.UseDamageTiers.Value) { if (damage >= settings.CriticalDamageThreshold.Value) { color = ColorUtils.Parse(settings.CriticalDamageTextColor.Value, new Color(1f, 0.31f, 0.27f)); value = settings.CriticalDamageTextSize.Value; } else if (damage >= settings.MediumDamageThreshold.Value) { color = ColorUtils.Parse(settings.MediumDamageTextColor.Value, new Color(1f, 0.83f, 0.35f)); value = settings.MediumDamageTextSize.Value; } } return new DamageTextStyle(color, value, Mathf.Max(0.05f, settings.DamageTextLifetime.Value), settings.DamageTextFloatSpeed.Value, settings.DamageTextFadeMultiplier.Value, Mathf.Max(0.001f, settings.DamageTextScale.Value), settings.DamageTextFormat.Value); } } } namespace EnemyHealthBar.Patches { [HarmonyPatch] internal static class EnemyHealthPatches { private static readonly Dictionary<int, float> LastDamageTextTimeByEnemy = new Dictionary<int, float>(); private static readonly FieldRef<EnemyHealth, int> HealthCurrentRef = AccessTools.FieldRefAccess<EnemyHealth, int>("healthCurrent"); [HarmonyPostfix] [HarmonyPatch(typeof(EnemyHealth), "Awake")] private static void EnemyHealthAwakePostfix(EnemyHealth __instance) { try { EnsureHealthBar(__instance); if (Plugin.Settings.VerboseLogging.Value) { Plugin.Log.LogInfo((object)("Initialized health bar for " + ((Object)__instance).name)); } } catch (Exception arg) { Plugin.Log.LogError((object)$"EnemyHealthBar Awake patch failed: {arg}"); } } [HarmonyPostfix] [HarmonyPatch(typeof(EnemyHealth), "OnSpawn")] private static void EnemyHealthOnSpawnPostfix(EnemyHealth __instance) { EnemyHealthBarDisplay enemyHealthBarDisplay = EnsureHealthBar(__instance); enemyHealthBarDisplay.SetHealth(__instance.health, __instance.health, silent: true); } [HarmonyPostfix] [HarmonyPatch(typeof(EnemyHealth), "HurtRPC")] private static void EnemyHealthHurtRpcPostfix(EnemyHealth __instance, int _damage, Vector3 _hurtDirection) { if ((Object)(object)__instance == (Object)null || _damage <= 0) { return; } try { EnemyHealthBarDisplay enemyHealthBarDisplay = EnsureHealthBar(__instance); if (SemiFunc.IsMasterClientOrSingleplayer()) { enemyHealthBarDisplay.SetHealth(HealthCurrentRef.Invoke(__instance), __instance.health, silent: false); } else { enemyHealthBarDisplay.ApplyClientDamage(_damage, __instance.health); } SpawnDamageText(__instance, _damage); } catch (Exception arg) { Plugin.Log.LogError((object)$"EnemyHealthBar HurtRPC patch failed: {arg}"); } } [HarmonyPostfix] [HarmonyPatch(typeof(EnemyHealth), "DeathRPC")] private static void EnemyHealthDeathRpcPostfix(EnemyHealth __instance) { DestroyHealthBar(__instance); } [HarmonyPostfix] [HarmonyPatch(typeof(EnemyHealth), "Death")] private static void EnemyHealthDeathPostfix(EnemyHealth __instance) { DestroyHealthBar(__instance); } private static EnemyHealthBarDisplay EnsureHealthBar(EnemyHealth enemyHealth) { EnemyHealthBarDisplay enemyHealthBarDisplay = ((Component)enemyHealth).GetComponent<EnemyHealthBarDisplay>(); if ((Object)(object)enemyHealthBarDisplay == (Object)null) { enemyHealthBarDisplay = ((Component)enemyHealth).gameObject.AddComponent<EnemyHealthBarDisplay>(); } return enemyHealthBarDisplay; } private static void DestroyHealthBar(EnemyHealth enemyHealth) { if (!((Object)(object)enemyHealth == (Object)null)) { LastDamageTextTimeByEnemy.Remove(((Object)enemyHealth).GetInstanceID()); EnemyHealthBarDisplay component = ((Component)enemyHealth).GetComponent<EnemyHealthBarDisplay>(); if ((Object)(object)component != (Object)null) { component.KillImmediately(); } } } private static void SpawnDamageText(EnemyHealth enemyHealth, int damage) { //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_0065: Unknown result type (might be due to invalid IL or missing references) //IL_0066: Unknown result type (might be due to invalid IL or missing references) //IL_007a: Unknown result type (might be due to invalid IL or missing references) //IL_007f: Unknown result type (might be due to invalid IL or missing references) //IL_0084: Unknown result type (might be due to invalid IL or missing references) //IL_0086: Unknown result type (might be due to invalid IL or missing references) if (Plugin.Settings.DamageTextEnabled.Value) { int instanceID = ((Object)enemyHealth).GetInstanceID(); float time = Time.time; if (!LastDamageTextTimeByEnemy.TryGetValue(instanceID, out var value) || !(time - value < 0.05f)) { LastDamageTextTimeByEnemy[instanceID] = time; Vector3 position = ((Component)enemyHealth).transform.position; Vector3 worldPosition = position + Vector3.up * Plugin.Settings.DamageTextHeightOffset.Value; DamageTextSpawner.Spawn(worldPosition, Mathf.Clamp(damage, 1, 9999)); } } } } } namespace EnemyHealthBar.Config { internal sealed class ModConfig { internal readonly ConfigEntry<bool> HealthBarEnabled; internal readonly ConfigEntry<bool> AlwaysVisible; internal readonly ConfigEntry<bool> ShowHealthText; internal readonly ConfigEntry<bool> ShowMaxHealth; internal readonly ConfigEntry<float> BarWidth; internal readonly ConfigEntry<float> BarHeight; internal readonly ConfigEntry<float> BarScale; internal readonly ConfigEntry<float> BarLerpSpeed; internal readonly ConfigEntry<float> ExtraHeightOffset; internal readonly ConfigEntry<float> HideAfterSeconds; internal readonly ConfigEntry<float> HideFadeDuration; internal readonly ConfigEntry<float> FadeDistance; internal readonly ConfigEntry<string> BarColor; internal readonly ConfigEntry<string> LowHealthBarColor; internal readonly ConfigEntry<string> BackgroundColor; internal readonly ConfigEntry<string> TextColor; internal readonly ConfigEntry<string> LowHealthTextColor; internal readonly ConfigEntry<float> LowHealthThreshold; internal readonly ConfigEntry<float> TextSize; internal readonly ConfigEntry<float> TextOffsetY; internal readonly ConfigEntry<bool> DamageTextEnabled; internal readonly ConfigEntry<string> DamageTextFormat; internal readonly ConfigEntry<bool> UseDamageTiers; internal readonly ConfigEntry<float> DamageTextHeightOffset; internal readonly ConfigEntry<float> DamageTextRandomOffset; internal readonly ConfigEntry<float> DamageTextLifetime; internal readonly ConfigEntry<float> DamageTextFloatSpeed; internal readonly ConfigEntry<float> DamageTextFadeMultiplier; internal readonly ConfigEntry<float> DamageTextScale; internal readonly ConfigEntry<string> DamageTextColor; internal readonly ConfigEntry<float> DamageTextSize; internal readonly ConfigEntry<int> MediumDamageThreshold; internal readonly ConfigEntry<string> MediumDamageTextColor; internal readonly ConfigEntry<float> MediumDamageTextSize; internal readonly ConfigEntry<int> CriticalDamageThreshold; internal readonly ConfigEntry<string> CriticalDamageTextColor; internal readonly ConfigEntry<float> CriticalDamageTextSize; internal readonly ConfigEntry<bool> VerboseLogging; internal ModConfig(ConfigFile config) { HealthBarEnabled = config.Bind<bool>("Health Bar", "Enabled", true, "Show enemy health bars."); AlwaysVisible = config.Bind<bool>("Health Bar", "AlwaysVisible", false, "Always show health bars, even without recent damage."); ShowHealthText = config.Bind<bool>("Health Bar", "ShowHealthText", true, "Show health numbers above the bar."); ShowMaxHealth = config.Bind<bool>("Health Bar", "ShowMaxHealth", true, "Show current/max health instead of current health only."); BarWidth = config.Bind<float>("Health Bar", "BarWidth", 210f, "World-space health bar canvas width."); BarHeight = config.Bind<float>("Health Bar", "BarHeight", 28f, "World-space health bar canvas height."); BarScale = config.Bind<float>("Health Bar", "BarScale", 0.0068f, "World-space health bar scale."); BarLerpSpeed = config.Bind<float>("Health Bar", "BarLerpSpeed", 11f, "Health bar fill smoothing speed."); ExtraHeightOffset = config.Bind<float>("Health Bar", "ExtraHeightOffset", 0.62f, "Extra height above enemy after automatic height calculation."); HideAfterSeconds = config.Bind<float>("Health Bar", "HideAfterSeconds", 8f, "Hide health bar after this many seconds without damage."); HideFadeDuration = config.Bind<float>("Health Bar", "HideFadeDuration", 0.45f, "Fade-out duration before the bar disappears."); FadeDistance = config.Bind<float>("Health Bar", "FadeDistance", 48f, "Distance where health bar fully fades out."); BarColor = config.Bind<string>("Health Bar", "BarColor", "#E2372F", "Health bar color in HTML format."); LowHealthBarColor = config.Bind<string>("Health Bar", "LowHealthBarColor", "#FFD447", "Health bar color below low health threshold."); BackgroundColor = config.Bind<string>("Health Bar", "BackgroundColor", "#16191ECC", "Health bar background color in HTML format."); TextColor = config.Bind<string>("Health Bar", "TextColor", "#F7F8FA", "Health text color in HTML format."); LowHealthTextColor = config.Bind<string>("Health Bar", "LowHealthTextColor", "#FFD447", "Health text color below low health threshold."); LowHealthThreshold = config.Bind<float>("Health Bar", "LowHealthThreshold", 0.3f, "Low health threshold from 0 to 1."); TextSize = config.Bind<float>("Health Bar", "TextSize", 14f, "Health text size."); TextOffsetY = config.Bind<float>("Health Bar", "TextOffsetY", 0f, "Health text vertical offset."); DamageTextEnabled = config.Bind<bool>("Damage Text", "Enabled", true, "Show floating damage numbers."); DamageTextFormat = config.Bind<string>("Damage Text", "TextFormat", "-{damage}", "Damage text format. Use {damage} as placeholder."); UseDamageTiers = config.Bind<bool>("Damage Text", "UseDamageTiers", true, "Use separate colors/sizes for medium and critical damage."); DamageTextHeightOffset = config.Bind<float>("Damage Text", "HeightOffset", 1.65f, "Damage text height above enemy transform."); DamageTextRandomOffset = config.Bind<float>("Damage Text", "RandomOffsetRadius", 0.28f, "Random offset radius for damage text."); DamageTextLifetime = config.Bind<float>("Damage Text", "Lifetime", 1.05f, "Damage text lifetime."); DamageTextFloatSpeed = config.Bind<float>("Damage Text", "FloatSpeed", 1.25f, "Damage text upward movement distance."); DamageTextFadeMultiplier = config.Bind<float>("Damage Text", "FadeMultiplier", 1f, "Damage text fade multiplier."); DamageTextScale = config.Bind<float>("Damage Text", "Scale", 0.0105f, "World-space damage text canvas scale."); DamageTextColor = config.Bind<string>("Damage Text", "Color", "#FF9A2F", "Default damage text color."); DamageTextSize = config.Bind<float>("Damage Text", "Size", 30f, "Default damage text size."); MediumDamageThreshold = config.Bind<int>("Damage Text", "MediumDamageThreshold", 30, "Minimum damage for medium damage text style."); MediumDamageTextColor = config.Bind<string>("Damage Text", "MediumColor", "#FFD35A", "Medium damage text color."); MediumDamageTextSize = config.Bind<float>("Damage Text", "MediumSize", 35f, "Medium damage text size."); CriticalDamageThreshold = config.Bind<int>("Damage Text", "CriticalDamageThreshold", 60, "Minimum damage for critical damage text style."); CriticalDamageTextColor = config.Bind<string>("Damage Text", "CriticalColor", "#FF4E45", "Critical damage text color."); CriticalDamageTextSize = config.Bind<float>("Damage Text", "CriticalSize", 42f, "Critical damage text size."); VerboseLogging = config.Bind<bool>("Debug", "VerboseLogging", false, "Enable verbose logs."); } } }