using System; using System.Globalization; using System.Reflection; using System.Runtime.CompilerServices; using BepInEx; using BepInEx.Configuration; using TMPro; using UnityEngine; using UnityEngine.UI; [assembly: AssemblyDescription("Shows the active boss's exact synchronized HP beside the native health bar.")] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: AssemblyCompany("evansvl")] [assembly: CompilationRelaxations(8)] [assembly: AssemblyVersion("0.0.0.0")] namespace HowToFish.BossHP; [BepInPlugin("community.howtofish.bosshp", "Boss HP", "0.1.2")] public sealed class Plugin : BaseUnityPlugin { public const string PluginGuid = "community.howtofish.bosshp"; public const string PluginName = "Boss HP"; public const string PluginVersion = "0.1.2"; private static readonly FieldInfo BossHealthField = typeof(BossUI).GetField("_bossHealth", BindingFlags.Instance | BindingFlags.NonPublic); private static readonly FieldInfo BossNameField = typeof(BossUI).GetField("_bossNameText", BindingFlags.Instance | BindingFlags.NonPublic); private static readonly FieldInfo BossHpRotateField = typeof(BossUI).GetField("_bossHpToRotate", BindingFlags.Instance | BindingFlags.NonPublic); private ConfigEntry _enabled; private ConfigEntry _showMaximum; private ConfigEntry _scale; private ConfigEntry _opacity; private ConfigEntry _horizontalOffset; private ConfigEntry _verticalOffset; private BossUI _nativeBossUi; private Image _nativeHealth; private RectTransform _nativeHudRoot; private TextMeshProUGUI _text; private readonly Vector3[] _healthCorners = (Vector3[])(object)new Vector3[4]; private void Awake() { //IL_0072: Unknown result type (might be due to invalid IL or missing references) //IL_007c: Expected O, but got Unknown //IL_00b1: Unknown result type (might be due to invalid IL or missing references) //IL_00bb: Expected O, but got Unknown //IL_00f0: Unknown result type (might be due to invalid IL or missing references) //IL_00fa: Expected O, but got Unknown //IL_012f: Unknown result type (might be due to invalid IL or missing references) //IL_0139: Expected O, but got Unknown _enabled = ((BaseUnityPlugin)this).Config.Bind("HUD", "Enabled", true, "Show exact boss HP beside the native boss health bar."); _showMaximum = ((BaseUnityPlugin)this).Config.Bind("HUD", "ShowMaximum", true, "Show current and maximum HP instead of current HP only."); _scale = ((BaseUnityPlugin)this).Config.Bind("HUD", "Scale", 1f, new ConfigDescription("Boss HP text scale.", (AcceptableValueBase)(object)new AcceptableValueRange(0.6f, 1.8f), new object[0])); _opacity = ((BaseUnityPlugin)this).Config.Bind("HUD", "Opacity", 1f, new ConfigDescription("Boss HP text opacity.", (AcceptableValueBase)(object)new AcceptableValueRange(0.2f, 1f), new object[0])); _horizontalOffset = ((BaseUnityPlugin)this).Config.Bind("Position", "HorizontalOffset", 18f, new ConfigDescription("Distance to the left of the native health bar.", (AcceptableValueBase)(object)new AcceptableValueRange(0f, 180f), new object[0])); _verticalOffset = ((BaseUnityPlugin)this).Config.Bind("Position", "VerticalOffset", 0f, new ConfigDescription("Vertical adjustment relative to the native health bar.", (AcceptableValueBase)(object)new AcceptableValueRange(-80f, 80f), new object[0])); ((BaseUnityPlugin)this).Logger.LogInfo((object)"Loaded. Boss HP reads synchronized boss state and attaches text to the native boss health bar."); } private void Update() { Creature boss = BossManager.Boss; if (!_enabled.Value || (Object)(object)boss == (Object)null || boss.IsDead || !IsGameplayBossHudVisible()) { SetVisible(visible: false); return; } if (!EnsureAttached()) { SetVisible(visible: false); return; } int num = BossManager.BossMaxHp; if (num <= 0) { num = boss.MaxHp; } if (num <= 0) { SetVisible(visible: false); return; } int value = Math.Max(0, Math.Min(boss.Hp, num)); ((TMP_Text)_text).text = (_showMaximum.Value ? (FormatHp(value) + " / " + FormatHp(num)) : FormatHp(value)); ApplyLiveSettings(); SetVisible(visible: true); } private static bool IsGameplayBossHudVisible() { if (MainMenuManager.IsInMenu || PauseManager.IsPaused) { return false; } try { return PlayerUI.BossCanvasActive; } catch { return false; } } private bool EnsureAttached() { if ((Object)(object)_nativeBossUi != (Object)null && (Object)(object)_nativeHealth != (Object)null && (Object)(object)_nativeHudRoot != (Object)null && (Object)(object)_text != (Object)null) { return true; } ClearAttachment(); if (BossHealthField == null || BossHpRotateField == null) { return false; } BossUI[] array = Resources.FindObjectsOfTypeAll(); BossUI[] array2 = array; foreach (BossUI val in array2) { if (!((Object)(object)val == (Object)null) && ((Component)val).gameObject.activeInHierarchy) { object? value = BossHealthField.GetValue(val); Image val2 = (Image)((value is Image) ? value : null); object? value2 = BossHpRotateField.GetValue(val); RectTransform val3 = (RectTransform)((value2 is RectTransform) ? value2 : null); if (!((Object)(object)val2 == (Object)null) && !((Object)(object)((Graphic)val2).rectTransform == (Object)null) && !((Object)(object)val3 == (Object)null)) { _nativeBossUi = val; _nativeHealth = val2; _nativeHudRoot = val3; CreateText(val3, FindTemplate(val)); ((BaseUnityPlugin)this).Logger.LogInfo((object)"Attached numeric HP to the native boss shake-and-rotation transform."); return (Object)(object)_text != (Object)null; } } } return false; } private void CreateText(RectTransform hudRoot, TextMeshProUGUI template) { //IL_0034: Unknown result type (might be due to invalid IL or missing references) //IL_003a: Expected O, but got Unknown //IL_0076: 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_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_0093: Unknown result type (might be due to invalid IL or missing references) //IL_00a8: Unknown result type (might be due to invalid IL or missing references) //IL_015f: Unknown result type (might be due to invalid IL or missing references) GameObject val = new GameObject("BossHPText", new Type[3] { typeof(RectTransform), typeof(CanvasRenderer), typeof(TextMeshProUGUI) }); val.transform.SetParent((Transform)(object)hudRoot, false); val.transform.SetAsLastSibling(); _text = val.GetComponent(); RectTransform rectTransform = ((TMP_Text)_text).rectTransform; Vector2 anchorMin = (rectTransform.anchorMax = new Vector2(0.5f, 0.5f)); rectTransform.anchorMin = anchorMin; rectTransform.pivot = new Vector2(1f, 0.5f); rectTransform.sizeDelta = new Vector2(300f, 70f); if ((Object)(object)template != (Object)null && (Object)(object)((TMP_Text)template).font != (Object)null) { ((TMP_Text)_text).font = ((TMP_Text)template).font; if ((Object)(object)((TMP_Text)template).fontSharedMaterial != (Object)null) { ((TMP_Text)_text).fontSharedMaterial = ((TMP_Text)template).fontSharedMaterial; } ((TMP_Text)_text).characterSpacing = ((TMP_Text)template).characterSpacing; } ((TMP_Text)_text).fontSize = 30f; ((TMP_Text)_text).alignment = (TextAlignmentOptions)4100; ((TMP_Text)_text).enableWordWrapping = false; ((TMP_Text)_text).overflowMode = (TextOverflowModes)0; ((Graphic)_text).raycastTarget = false; ((TMP_Text)_text).outlineColor = new Color32((byte)20, (byte)18, (byte)18, byte.MaxValue); ((TMP_Text)_text).outlineWidth = 0.18f; ((TMP_Text)_text).text = string.Empty; } private static TextMeshProUGUI FindTemplate(BossUI bossUi) { TextMeshProUGUI val = (TextMeshProUGUI)((BossNameField == null) ? null : /*isinst with value type is only supported in some contexts*/); if ((Object)(object)val != (Object)null && (Object)(object)((TMP_Text)val).font != (Object)null) { return val; } TextMeshProUGUI[] array = Resources.FindObjectsOfTypeAll(); TextMeshProUGUI[] array2 = array; foreach (TextMeshProUGUI val2 in array2) { if ((Object)(object)val2 != (Object)null && ((TMP_Text)val2).text != null && ((TMP_Text)val2).text.IndexOf("Version", StringComparison.OrdinalIgnoreCase) >= 0) { return val2; } } return null; } private void ApplyLiveSettings() { //IL_002e: 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) //IL_0044: Unknown result type (might be due to invalid IL or missing references) //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_005a: Unknown result type (might be due to invalid IL or missing references) //IL_005b: Unknown result type (might be due to invalid IL or missing references) //IL_0060: 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_0098: Unknown result type (might be due to invalid IL or missing references) //IL_00a8: Unknown result type (might be due to invalid IL or missing references) //IL_00d2: Unknown result type (might be due to invalid IL or missing references) RectTransform rectTransform = ((TMP_Text)_text).rectTransform; ((Graphic)_nativeHealth).rectTransform.GetWorldCorners(_healthCorners); Vector3 val = (_healthCorners[0] + _healthCorners[1]) * 0.5f; Vector3 val2 = ((Transform)_nativeHudRoot).InverseTransformPoint(val); ((Transform)rectTransform).localPosition = new Vector3(val2.x - _horizontalOffset.Value, val2.y + _verticalOffset.Value, 0f); ((Transform)rectTransform).localScale = Vector3.one * _scale.Value; ((Graphic)_text).color = new Color(1f, 1f, 1f, _opacity.Value); } private static string FormatHp(int value) { return value.ToString("N0", CultureInfo.InvariantCulture); } private void SetVisible(bool visible) { if ((Object)(object)_text != (Object)null && ((Behaviour)_text).enabled != visible) { ((Behaviour)_text).enabled = visible; } } private void ClearAttachment() { if ((Object)(object)_text != (Object)null) { Object.Destroy((Object)(object)((Component)_text).gameObject); } _text = null; _nativeHealth = null; _nativeHudRoot = null; _nativeBossUi = null; } private void OnDestroy() { ClearAttachment(); } }