using System; using System.Collections.Generic; using System.Diagnostics; using System.IO; 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 Sparroh.UI; using TMPro; using UnityEngine; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")] [assembly: AssemblyCompany("ShowBossHealth")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0")] [assembly: AssemblyProduct("ShowBossHealth")] [assembly: AssemblyTitle("ShowBossHealth")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("1.0.0.0")] [module: UnverifiableCode] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [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; } } } public class EnemyHealthValueMod { internal static class BossHealthbarPatches { [HarmonyPostfix] [HarmonyPatch(typeof(BossHealthbar), "Initialize")] private static void PostfixInitialize(BossHealthbar prefab, EnemyBrain target) { if (Instance == null) { return; } try { List instances = BossHealthbar.instances; if (instances == null || instances.Count == 0) { return; } BossHealthbar val = instances[instances.Count - 1]; if ((Object)(object)val != (Object)null && val.targetMatches(target)) { Instance.AttachToBar(val); return; } for (int num = instances.Count - 1; num >= 0; num--) { BossHealthbar val2 = instances[num]; if ((Object)(object)val2 != (Object)null && val2.targetMatches(target)) { Instance.AttachToBar(val2); break; } } } catch (Exception ex) { SparrohPlugin.Logger.LogError((object)("Failed to attach enemy health label: " + ex.Message)); } } } private readonly ConfigEntry enableHealthValues; private readonly ConfigEntry fontSize; private readonly ConfigEntry yOffset; private readonly ConfigColor valueColor; private readonly FieldInfo targetField; private readonly FieldInfo healthbarParentField; private readonly Dictionary labels = new Dictionary(); private readonly List removeBuffer = new List(); public static EnemyHealthValueMod Instance { get; private set; } public EnemyHealthValueMod(ConfigFile configFile, Harmony harmony) { //IL_008a: Unknown result type (might be due to invalid IL or missing references) Instance = this; enableHealthValues = configFile.Bind("General", "EnableEnemyHealthValues", true, "Show current / max health under enemy HUD health bars."); fontSize = configFile.Bind("Display", "FontSize", 14f, "Font size for health value text (reference 1080p pixels)."); yOffset = configFile.Bind("Display", "YOffset", -4f, "Vertical offset below the health bar (reference pixels; negative is further down)."); valueColor = ConfigColor.Bind(configFile, "Colors", "ValueColor", UIColors.TextPrimary, "Health value text color (hex RRGGBB or #RRGGBB)."); targetField = AccessTools.Field(typeof(BossHealthbar), "target"); healthbarParentField = AccessTools.Field(typeof(BossHealthbar), "healthbarParent"); if (targetField == null) { SparrohPlugin.Logger.LogError((object)"Could not find BossHealthbar.target field."); } if (healthbarParentField == null) { SparrohPlugin.Logger.LogWarning((object)"Could not find BossHealthbar.healthbarParent field; using bar root for layout."); } } public void AttachToBar(BossHealthbar bar) { if (!((Object)(object)bar == (Object)null) && !labels.ContainsKey(bar) && enableHealthValues.Value) { CreateLabel(bar); } } private void CreateLabel(BossHealthbar bar) { //IL_0059: Unknown result type (might be due to invalid IL or missing references) //IL_0085: Unknown result type (might be due to invalid IL or missing references) //IL_009a: Unknown result type (might be due to invalid IL or missing references) //IL_00af: Unknown result type (might be due to invalid IL or missing references) //IL_0174: Unknown result type (might be due to invalid IL or missing references) //IL_0186: Unknown result type (might be due to invalid IL or missing references) //IL_00e7: Unknown result type (might be due to invalid IL or missing references) //IL_00ec: Unknown result type (might be due to invalid IL or missing references) //IL_00f9: Unknown result type (might be due to invalid IL or missing references) //IL_0114: Unknown result type (might be due to invalid IL or missing references) //IL_0119: Unknown result type (might be due to invalid IL or missing references) //IL_0147: Unknown result type (might be due to invalid IL or missing references) //IL_0134: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)bar == (Object)null || labels.ContainsKey(bar)) { return; } Transform transform = ((Component)bar).transform; object? obj = healthbarParentField?.GetValue(bar); RectTransform val = (RectTransform)((obj is RectTransform) ? obj : null); float num = UITheme.S(fontSize.Value); UIText val2 = UIText.Create(transform, "EnemyHealthValue", "", num, (Color?)valueColor.Value, (TextAlignmentOptions)514, false); if (val2 == null) { return; } RectTransform rect = val2.Rect; rect.anchorMin = new Vector2(0.5f, 0.5f); rect.anchorMax = new Vector2(0.5f, 0.5f); rect.pivot = new Vector2(0.5f, 1f); float num2 = 400f; float num3 = UITheme.S(yOffset.Value); if ((Object)(object)val != (Object)null) { float[] array = new float[3]; Rect rect2 = val.rect; array[0] = ((Rect)(ref rect2)).width; array[1] = val.sizeDelta.x; array[2] = 200f; num2 = Mathf.Max(array); rect2 = val.rect; float num4 = ((Rect)(ref rect2)).height * 0.5f; if (num4 <= 0f) { num4 = val.sizeDelta.y * 0.5f; } num3 = val.anchoredPosition.y - num4 + UITheme.S(yOffset.Value); } rect.sizeDelta = new Vector2(num2, UITheme.S(22f)); rect.anchoredPosition = new Vector2(0f, num3); labels[bar] = val2; UpdateLabel(bar, val2); } public void Update() { if (!enableHealthValues.Value) { if (labels.Count > 0) { ClearAllLabels(); } return; } List instances = BossHealthbar.instances; if (instances != null) { for (int i = 0; i < instances.Count; i++) { BossHealthbar val = instances[i]; if ((Object)(object)val != (Object)null && !labels.ContainsKey(val)) { CreateLabel(val); } } } removeBuffer.Clear(); foreach (KeyValuePair label in labels) { BossHealthbar key = label.Key; UIText value = label.Value; if ((Object)(object)key == (Object)null || value == null || (Object)(object)value.GameObject == (Object)null) { removeBuffer.Add(key); } else { UpdateLabel(key, value); } } for (int j = 0; j < removeBuffer.Count; j++) { BossHealthbar val2 = removeBuffer[j]; if (labels.TryGetValue(val2, out var value2)) { value2?.DestroySafe(); labels.Remove(val2); } else if ((Object)(object)val2 == (Object)null) { labels.Remove(val2); } } } private void UpdateLabel(BossHealthbar bar, UIText text) { //IL_0036: 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_003d: Unknown result type (might be due to invalid IL or missing references) object? obj = targetField?.GetValue(bar); EnemyBrain val = (EnemyBrain)((obj is EnemyBrain) ? obj : null); if (!((Object)(object)val == (Object)null) && TryGetHealthValues(val, out var current, out var max)) { Color value = valueColor.Value; text.Color = value; text.FontSize = UITheme.S(fontSize.Value); int num = Mathf.Max(0, Mathf.RoundToInt(current)); int num2 = Mathf.Max(0, Mathf.RoundToInt(max)); text.Text = $"{num} / {num2}"; } } internal static bool TryGetHealthValues(EnemyBrain brain, out float current, out float max) { current = 0f; max = 0f; if ((Object)(object)brain == (Object)null || (Object)(object)brain.Core == (Object)null) { return false; } bool flag = false; try { if ((Object)(object)brain.EnemyClass != (Object)null) { flag = brain.EnemyClass.config.onlyUseCoreHealthForHealthbar; } } catch { flag = false; } if (flag) { current = ((EnemyPart)brain.Core).Health; max = ((EnemyPart)brain.Core).MaxHealth; return max > 0f; } SumShellHealth((IEnemyComponent)(object)brain.Core, ref current, ref max); if (max <= 0f) { current = ((EnemyPart)brain.Core).Health; max = ((EnemyPart)brain.Core).MaxHealth; } return max > 0f; } private static void SumShellHealth(IEnemyComponent component, ref float current, ref float max) { //IL_000f: Unknown result type (might be due to invalid IL or missing references) //IL_0015: Unknown result type (might be due to invalid IL or missing references) if (component == null) { return; } EnemyPart val = (EnemyPart)(object)((component is EnemyPart) ? component : null); if (val != null && (val.ComponentType & 4) != 0) { max += val.MaxHealth; if (val.IsAlive) { current += val.Health; } } List childComponents = component.ChildComponents; if (childComponents != null) { for (int i = 0; i < childComponents.Count; i++) { SumShellHealth(childComponents[i], ref current, ref max); } } } private void ClearAllLabels() { foreach (KeyValuePair label in labels) { label.Value?.DestroySafe(); } labels.Clear(); } public void OnDestroy() { ClearAllLabels(); Instance = null; } } internal static class BossHealthbarExtensions { private static readonly FieldInfo TargetField = AccessTools.Field(typeof(BossHealthbar), "target"); public static bool targetMatches(this BossHealthbar bar, EnemyBrain brain) { if ((Object)(object)bar == (Object)null || (Object)(object)brain == (Object)null || TargetField == null) { return false; } return TargetField.GetValue(bar) == brain; } public static void DestroySafe(this UIText text) { if (text != null) { UIHelpers.DestroySafe((Object)(object)text.GameObject); } } } [BepInPlugin("sparroh.showbosshealth", "ShowBossHealth", "1.0.0")] [BepInDependency(/*Could not decode attribute arguments.*/)] [MycoMod(/*Could not decode attribute arguments.*/)] public class SparrohPlugin : BaseUnityPlugin { public const string PluginGUID = "sparroh.showbosshealth"; public const string PluginName = "ShowBossHealth"; public const string PluginVersion = "1.0.0"; internal static ManualLogSource Logger; private Harmony harmony; private EnemyHealthValueMod mod; private void Awake() { //IL_0017: Unknown result type (might be due to invalid IL or missing references) //IL_0021: Expected O, but got Unknown Logger = ((BaseUnityPlugin)this).Logger; try { harmony = new Harmony("sparroh.showbosshealth"); } catch (Exception ex) { Logger.LogError((object)("Failed to create Harmony instance: " + ex.Message)); return; } ConfigFile configFile = ((BaseUnityPlugin)this).Config; try { FileSystemWatcher fileSystemWatcher = new FileSystemWatcher(Paths.ConfigPath, "sparroh.showbosshealth.cfg"); fileSystemWatcher.Changed += delegate { configFile.Reload(); }; fileSystemWatcher.EnableRaisingEvents = true; } catch (Exception ex2) { Logger.LogWarning((object)("Failed to set up config watcher: " + ex2.Message)); } try { mod = new EnemyHealthValueMod(configFile, harmony); } catch (Exception ex3) { Logger.LogError((object)("Failed to initialize ShowBossHealth: " + ex3.Message)); } try { harmony.PatchAll(); } catch (Exception ex4) { Logger.LogError((object)("Failed to apply Harmony patches: " + ex4.Message)); } Logger.LogInfo((object)"ShowBossHealth loaded successfully."); } private void Update() { try { if (mod != null) { mod.Update(); } } catch (Exception ex) { Logger.LogError((object)("Error in ShowBossHealth.Update(): " + ex.Message)); } } private void OnDestroy() { try { if (mod != null) { mod.OnDestroy(); } } catch (Exception ex) { Logger.LogError((object)("Error in ShowBossHealth.OnDestroy(): " + ex.Message)); } try { if (harmony != null) { harmony.UnpatchSelf(); } } catch (Exception ex2) { Logger.LogError((object)("Error unpatching Harmony: " + ex2.Message)); } } } namespace ShowBossHealth { public static class MyPluginInfo { public const string PLUGIN_GUID = "ShowBossHealth"; public const string PLUGIN_NAME = "ShowBossHealth"; public const string PLUGIN_VERSION = "1.0.0"; } } namespace System.Runtime.CompilerServices { [AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)] internal sealed class IgnoresAccessChecksToAttribute : Attribute { public IgnoresAccessChecksToAttribute(string assemblyName) { } } }