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 Pigeon.Movement; using UnityEngine; using UnityEngine.UI; [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("GraduatedHealth")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0")] [assembly: AssemblyProduct("GraduatedHealth")] [assembly: AssemblyTitle("GraduatedHealth")] [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 GraduatedHealthMod { 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) { BossHealthbar val = instances[instances.Count - 1]; if ((Object)(object)val != (Object)null) { Instance.AttachBossBar(val); } } } catch (Exception ex) { SparrohPlugin.Logger.LogError((object)("Failed to attach boss health notches: " + ex.Message)); } } } internal static class HealthbarPatches { [HarmonyPostfix] [HarmonyPatch(typeof(Healthbar), "Activate")] private static void PostfixActivate(Healthbar __instance) { if (Instance == null || !Instance.enableFloatingEnemyNotches.Value) { return; } try { Instance.AttachFloatingBar(__instance); } catch (Exception ex) { SparrohPlugin.Logger.LogError((object)("Failed to attach floating health notches: " + ex.Message)); } } } private readonly ConfigEntry enablePlayerNotches; private readonly ConfigEntry enableEnemyBossNotches; private readonly ConfigEntry enableFloatingEnemyNotches; private readonly ConfigEntry playerInterval; private readonly ConfigEntry enemyInterval; private readonly ConfigEntry notchThickness; private readonly ConfigEntry notchHeightFraction; private readonly ConfigEntry notchColorHex; private readonly FieldInfo bossTargetField; private readonly FieldInfo bossHealthbarField; private readonly FieldInfo bossHealthbarParentField; private readonly FieldInfo floatingHealthbarField; private readonly Dictionary bossNotches = new Dictionary(); private readonly Dictionary floatingNotches = new Dictionary(); private readonly List bossRemoveBuffer = new List(); private readonly List floatingRemoveBuffer = new List(); private HealthbarNotches playerNotches; private RectTransform playerBarParent; private Graphic playerHealthGraphic; private float lastPlayerMaxHealth = -1f; private float playerDiscoverCooldown; private float floatingScanCooldown; public static GraduatedHealthMod Instance { get; private set; } public GraduatedHealthMod(ConfigFile config, Harmony harmony) { Instance = this; enablePlayerNotches = config.Bind("General", "EnablePlayerNotches", true, "Add graduation notches to the local player health bar."); enableEnemyBossNotches = config.Bind("General", "EnableEnemyBossNotches", true, "Add graduation notches to boss / abomination health bars."); enableFloatingEnemyNotches = config.Bind("General", "EnableFloatingEnemyNotches", true, "Add graduation notches to floating world-space enemy health bars."); playerInterval = config.Bind("Intervals", "PlayerHealthPerNotch", 5f, "Player health bar: one notch every N max HP."); enemyInterval = config.Bind("Intervals", "EnemyHealthPerNotch", 500f, "Enemy health bars (boss + floating): one notch every N max HP."); notchThickness = config.Bind("Display", "NotchThickness", 2f, "Width of each notch line in UI pixels."); notchHeightFraction = config.Bind("Display", "NotchHeightFraction", 1f, "Notch height as a fraction of the bar height (0-1)."); notchColorHex = config.Bind("Display", "NotchColor", "000000AA", "Notch color as hex RRGGBB or RRGGBBAA."); bossTargetField = AccessTools.Field(typeof(BossHealthbar), "target"); bossHealthbarField = AccessTools.Field(typeof(BossHealthbar), "healthbar"); bossHealthbarParentField = AccessTools.Field(typeof(BossHealthbar), "healthbarParent"); floatingHealthbarField = AccessTools.Field(typeof(Healthbar), "healthbar"); if (bossTargetField == null) { SparrohPlugin.Logger.LogError((object)"Could not find BossHealthbar.target"); } if (bossHealthbarParentField == null) { SparrohPlugin.Logger.LogWarning((object)"Could not find BossHealthbar.healthbarParent"); } if (floatingHealthbarField == null) { SparrohPlugin.Logger.LogWarning((object)"Could not find Healthbar.healthbar"); } } private Color GetNotchColor() { //IL_0075: 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) string text = notchColorHex.Value?.Trim() ?? "000000AA"; if (text.StartsWith("#")) { text = text.Substring(1); } if (text.Length == 6) { text += "AA"; } Color result = default(Color); if (ColorUtility.TryParseHtmlString("#" + text, ref result)) { return result; } return new Color(0f, 0f, 0f, 0.66f); } public void Update() { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_003c: 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_00b3: Unknown result type (might be due to invalid IL or missing references) Color notchColor = GetNotchColor(); float thickness = Mathf.Max(1f, notchThickness.Value); float heightFrac = Mathf.Clamp01(notchHeightFraction.Value); if (enablePlayerNotches.Value) { UpdatePlayerNotches(notchColor, thickness, heightFrac); } else if (playerNotches != null) { playerNotches.Destroy(); playerNotches = null; playerBarParent = null; playerHealthGraphic = null; lastPlayerMaxHealth = -1f; } if (enableEnemyBossNotches.Value) { UpdateBossNotches(notchColor, thickness, heightFrac); } else if (bossNotches.Count > 0) { ClearBossNotches(); } if (enableFloatingEnemyNotches.Value) { UpdateFloatingNotches(notchColor, thickness, heightFrac); } else if (floatingNotches.Count > 0) { ClearFloatingNotches(); } } private void UpdatePlayerNotches(Color color, float thickness, float heightFrac) { //IL_00f0: Unknown result type (might be due to invalid IL or missing references) Player localPlayer = Player.LocalPlayer; if ((Object)(object)localPlayer == (Object)null || !localPlayer.IsAlive) { return; } if ((Object)(object)playerBarParent == (Object)null || (Object)(object)playerHealthGraphic == (Object)null) { playerDiscoverCooldown -= Time.unscaledDeltaTime; if (playerDiscoverCooldown <= 0f) { playerDiscoverCooldown = 0.5f; TryDiscoverPlayerHealthBar(localPlayer); } if ((Object)(object)playerBarParent == (Object)null) { return; } } if (playerNotches == null) { playerNotches = new HealthbarNotches(); } if (!playerNotches.IsValid || (Object)(object)playerNotches.Parent != (Object)(object)playerBarParent) { playerNotches.Attach(playerBarParent); } float maxHealth = localPlayer.MaxHealth; if (!(maxHealth <= 0f)) { lastPlayerMaxHealth = maxHealth; playerNotches.Update(maxHealth, Mathf.Max(1f, playerInterval.Value), color, thickness, heightFrac); } } private void TryDiscoverPlayerHealthBar(Player player) { if (TryFindHealthGraphicOn(player, out var graphic, out var parent)) { playerHealthGraphic = graphic; playerBarParent = parent; SparrohPlugin.Logger.LogInfo((object)("Player health bar found via Player fields: " + ((Object)parent).name)); return; } PlayerLook val = null; try { val = player.PlayerLook; } catch { } if ((Object)(object)val == (Object)null) { try { val = PlayerLook.Instance; } catch { } } if ((Object)(object)val != (Object)null && TryFindHealthGraphicOn(val, out graphic, out parent)) { playerHealthGraphic = graphic; playerBarParent = parent; SparrohPlugin.Logger.LogInfo((object)("Player health bar found via PlayerLook fields: " + ((Object)parent).name)); return; } Transform val2 = null; if ((Object)(object)val != (Object)null) { val2 = ((Component)val).transform; try { object? obj3 = AccessTools.Property(typeof(PlayerLook), "DefaultHUDParent")?.GetValue(val); Transform val3 = (Transform)(((obj3 is Transform) ? obj3 : null) ?? ((object)(/*isinst with value type is only supported in some contexts*/ ?? /*isinst with value type is only supported in some contexts*/))); if ((Object)(object)val3 != (Object)null) { val2 = val3; } } catch { } } if ((Object)(object)val2 == (Object)null) { val2 = ((Component)player).transform; } if (TryFindHealthBarInHierarchy(val2, out graphic, out parent)) { playerHealthGraphic = graphic; playerBarParent = parent; SparrohPlugin.Logger.LogInfo((object)("Player health bar found via hierarchy under " + ((Object)val2).name + ": " + ((Object)parent).name)); } } private static bool TryFindHealthGraphicOn(object obj, out Graphic graphic, out RectTransform parent) { graphic = null; parent = null; if (obj == null) { return false; } Type type = obj.GetType(); FieldInfo[] fields = type.GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); foreach (FieldInfo fieldInfo in fields) { string name = fieldInfo.Name; if (name.IndexOf("health", StringComparison.OrdinalIgnoreCase) < 0 && name.IndexOf("hp", StringComparison.OrdinalIgnoreCase) < 0) { continue; } object obj2 = null; try { obj2 = fieldInfo.GetValue(obj); } catch { continue; } if (obj2 == null) { continue; } Graphic val = (Graphic)((obj2 is Graphic) ? obj2 : null); if (val != null) { graphic = val; Transform parent2 = ((Transform)val.rectTransform).parent; parent = (RectTransform)(((object)((parent2 is RectTransform) ? parent2 : null)) ?? ((object)val.rectTransform)); return true; } RectTransform val2 = (RectTransform)((obj2 is RectTransform) ? obj2 : null); if (val2 != null) { Graphic componentInChildren = ((Component)val2).GetComponentInChildren(true); if ((Object)(object)componentInChildren != (Object)null) { graphic = componentInChildren; parent = val2; return true; } } Component val3 = (Component)((obj2 is Component) ? obj2 : null); if (val3 != null) { Graphic val4 = val3.GetComponent() ?? val3.GetComponentInChildren(true); if ((Object)(object)val4 != (Object)null) { graphic = val4; Transform parent3 = ((Transform)val4.rectTransform).parent; parent = (RectTransform)(((object)((parent3 is RectTransform) ? parent3 : null)) ?? ((object)val4.rectTransform)); return true; } } } PropertyInfo[] properties = type.GetProperties(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); foreach (PropertyInfo propertyInfo in properties) { if (!propertyInfo.CanRead || propertyInfo.GetIndexParameters().Length != 0) { continue; } string name2 = propertyInfo.Name; if (name2.IndexOf("health", StringComparison.OrdinalIgnoreCase) >= 0 || name2.IndexOf("hp", StringComparison.OrdinalIgnoreCase) >= 0) { object obj4 = null; try { obj4 = propertyInfo.GetValue(obj, null); } catch { continue; } Graphic val5 = (Graphic)((obj4 is Graphic) ? obj4 : null); if (val5 != null) { graphic = val5; Transform parent4 = ((Transform)val5.rectTransform).parent; parent = (RectTransform)(((object)((parent4 is RectTransform) ? parent4 : null)) ?? ((object)val5.rectTransform)); return true; } } } return false; } private static bool TryFindHealthBarInHierarchy(Transform root, out Graphic graphic, out RectTransform parent) { //IL_00f8: Unknown result type (might be due to invalid IL or missing references) //IL_00fd: 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_010f: Unknown result type (might be due to invalid IL or missing references) graphic = null; parent = null; if ((Object)(object)root == (Object)null) { return false; } List list = new List(); CollectHealthNamed(root, list); foreach (Transform item in list) { Transform val = item.Find("Fill"); if ((Object)(object)val == (Object)null) { for (int i = 0; i < item.childCount; i++) { Transform child = item.GetChild(i); if (((Object)child).name.IndexOf("fill", StringComparison.OrdinalIgnoreCase) >= 0 || ((Object)child).name.IndexOf("health", StringComparison.OrdinalIgnoreCase) >= 0) { val = child; break; } } } Graphic val2 = null; if ((Object)(object)val != (Object)null) { val2 = ((Component)val).GetComponent(); } if ((Object)(object)val2 == (Object)null) { val2 = ((Component)item).GetComponentInChildren(true); } if (!((Object)(object)val2 == (Object)null)) { RectTransform val3 = (RectTransform)(object)((item is RectTransform) ? item : null); if ((Object)(object)val3 == (Object)null) { Transform parent2 = ((Transform)val2.rectTransform).parent; val3 = (RectTransform)(((object)((parent2 is RectTransform) ? parent2 : null)) ?? ((object)val2.rectTransform)); } Rect rect = val3.rect; float num; if (!(((Rect)(ref rect)).width > 0f)) { num = val3.sizeDelta.x; } else { rect = val3.rect; num = ((Rect)(ref rect)).width; } if (!(num < 40f)) { graphic = val2; parent = val3; return true; } } } return false; } private static void CollectHealthNamed(Transform t, List results) { string name = ((Object)t).name; if (name.IndexOf("health", StringComparison.OrdinalIgnoreCase) >= 0 || name.IndexOf("Healthbar", StringComparison.OrdinalIgnoreCase) >= 0 || name.IndexOf("HealthBar", StringComparison.OrdinalIgnoreCase) >= 0 || name.IndexOf("HPBar", StringComparison.OrdinalIgnoreCase) >= 0 || name.IndexOf("HpBar", StringComparison.OrdinalIgnoreCase) >= 0) { results.Add(t); } for (int i = 0; i < t.childCount; i++) { CollectHealthNamed(t.GetChild(i), results); } } public void AttachBossBar(BossHealthbar bar) { //IL_0055: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)bar == (Object)null) && !bossNotches.ContainsKey(bar) && enableEnemyBossNotches.Value) { RectTransform bossBarParent = GetBossBarParent(bar); if (!((Object)(object)bossBarParent == (Object)null)) { HealthbarNotches healthbarNotches = new HealthbarNotches(); healthbarNotches.Attach(bossBarParent); bossNotches[bar] = healthbarNotches; RefreshBossBar(bar, healthbarNotches, GetNotchColor(), Mathf.Max(1f, notchThickness.Value), Mathf.Clamp01(notchHeightFraction.Value)); } } } private RectTransform GetBossBarParent(BossHealthbar bar) { object? obj = bossHealthbarParentField?.GetValue(bar); RectTransform val = (RectTransform)((obj is RectTransform) ? obj : null); if ((Object)(object)val != (Object)null) { return val; } object? obj2 = bossHealthbarField?.GetValue(bar); Graphic val2 = (Graphic)((obj2 is Graphic) ? obj2 : null); if ((Object)(object)val2 != (Object)null) { Transform parent = ((Transform)val2.rectTransform).parent; return (RectTransform)(((object)((parent is RectTransform) ? parent : null)) ?? ((object)val2.rectTransform)); } Transform transform = ((Component)bar).transform; return (RectTransform)(object)((transform is RectTransform) ? transform : null); } private void UpdateBossNotches(Color color, float thickness, float heightFrac) { //IL_009f: Unknown result type (might be due to invalid IL or missing references) 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 && !bossNotches.ContainsKey(val)) { AttachBossBar(val); } } } bossRemoveBuffer.Clear(); foreach (KeyValuePair bossNotch in bossNotches) { BossHealthbar key = bossNotch.Key; HealthbarNotches value = bossNotch.Value; if ((Object)(object)key == (Object)null || value == null || !value.IsValid) { bossRemoveBuffer.Add(key); } else { RefreshBossBar(key, value, color, thickness, heightFrac); } } for (int j = 0; j < bossRemoveBuffer.Count; j++) { BossHealthbar val2 = bossRemoveBuffer[j]; if (bossNotches.TryGetValue(val2, out var value2)) { value2.Destroy(); bossNotches.Remove(val2); } else { if (!((Object)(object)val2 == (Object)null)) { continue; } foreach (BossHealthbar item in new List(bossNotches.Keys)) { if ((Object)(object)item == (Object)null) { bossNotches[item]?.Destroy(); bossNotches.Remove(item); } } } } } private void RefreshBossBar(BossHealthbar bar, HealthbarNotches notches, Color color, float thickness, float heightFrac) { //IL_0051: Unknown result type (might be due to invalid IL or missing references) if (TryGetEnemyMaxHealth(bar, out var max) && !(max <= 0f)) { RectTransform bossBarParent = GetBossBarParent(bar); if ((Object)(object)bossBarParent != (Object)null && (Object)(object)notches.Parent != (Object)(object)bossBarParent) { notches.Attach(bossBarParent); } notches.Update(max, Mathf.Max(1f, enemyInterval.Value), color, thickness, heightFrac); } } private bool TryGetEnemyMaxHealth(BossHealthbar bar, out float max) { max = 0f; object? obj = bossTargetField?.GetValue(bar); EnemyBrain val = (EnemyBrain)((obj is EnemyBrain) ? obj : null); if ((Object)(object)val == (Object)null || (Object)(object)val.Core == (Object)null) { return false; } bool flag = false; try { if ((Object)(object)val.EnemyClass != (Object)null) { flag = val.EnemyClass.config.onlyUseCoreHealthForHealthbar; } } catch { flag = false; } if (flag) { max = ((EnemyPart)val.Core).MaxHealth; return max > 0f; } float current = 0f; SumShellHealth((IEnemyComponent)(object)val.Core, ref current, ref max); if (max <= 0f) { max = ((EnemyPart)val.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 ClearBossNotches() { foreach (KeyValuePair bossNotch in bossNotches) { bossNotch.Value?.Destroy(); } bossNotches.Clear(); } private void UpdateFloatingNotches(Color color, float thickness, float heightFrac) { //IL_016a: Unknown result type (might be due to invalid IL or missing references) floatingScanCooldown -= Time.unscaledDeltaTime; if (floatingScanCooldown <= 0f) { floatingScanCooldown = 0.35f; Healthbar[] array = Object.FindObjectsOfType(); if (array != null) { foreach (Healthbar val in array) { if (!((Object)(object)val == (Object)null) && ((Component)val).gameObject.activeInHierarchy && !floatingNotches.ContainsKey(val)) { AttachFloatingBar(val); } } } } floatingRemoveBuffer.Clear(); foreach (KeyValuePair floatingNotch in floatingNotches) { Healthbar key = floatingNotch.Key; HealthbarNotches value = floatingNotch.Value; if ((Object)(object)key == (Object)null || !((Component)key).gameObject.activeInHierarchy || value == null || !value.IsValid) { floatingRemoveBuffer.Add(key); continue; } ITarget target = key.Target; if (target == null || !((ISelectable)target).Exists()) { floatingRemoveBuffer.Add(key); continue; } float maxHealth = target.MaxHealth; if (!(maxHealth <= 0f)) { _ = enemyInterval.Value; RectTransform floatingBarParent = GetFloatingBarParent(key); if ((Object)(object)floatingBarParent != (Object)null && (Object)(object)value.Parent != (Object)(object)floatingBarParent) { value.Attach(floatingBarParent); } value.Update(maxHealth, Mathf.Max(1f, enemyInterval.Value), color, thickness, heightFrac); } } for (int j = 0; j < floatingRemoveBuffer.Count; j++) { Healthbar key2 = floatingRemoveBuffer[j]; if (floatingNotches.TryGetValue(key2, out var value2)) { value2.Destroy(); floatingNotches.Remove(key2); } } } private void AttachFloatingBar(Healthbar bar) { if (!((Object)(object)bar == (Object)null) && !floatingNotches.ContainsKey(bar)) { RectTransform floatingBarParent = GetFloatingBarParent(bar); if (!((Object)(object)floatingBarParent == (Object)null)) { HealthbarNotches healthbarNotches = new HealthbarNotches(); healthbarNotches.Attach(floatingBarParent); floatingNotches[bar] = healthbarNotches; } } } private RectTransform GetFloatingBarParent(Healthbar bar) { //IL_003c: Unknown result type (might be due to invalid IL or missing references) object? obj = floatingHealthbarField?.GetValue(bar); Graphic val = (Graphic)((obj is Graphic) ? obj : null); if ((Object)(object)val != (Object)null) { Transform parent = ((Transform)val.rectTransform).parent; return (RectTransform)(((object)((parent is RectTransform) ? parent : null)) ?? ((object)(RectTransform)((Component)bar).transform)); } Transform transform = ((Component)bar).transform; return (RectTransform)(object)((transform is RectTransform) ? transform : null); } private void ClearFloatingNotches() { foreach (KeyValuePair floatingNotch in floatingNotches) { floatingNotch.Value?.Destroy(); } floatingNotches.Clear(); } public void OnDestroy() { playerNotches?.Destroy(); playerNotches = null; ClearBossNotches(); ClearFloatingNotches(); Instance = null; } } public sealed class HealthbarNotches { private static Sprite whiteSprite; private readonly List ticks = new List(32); private RectTransform parent; private GameObject root; private RectTransform rootRect; private float lastMaxHealth = -1f; private float lastInterval = -1f; private float lastWidth = -1f; private float lastHeight = -1f; private Color lastColor; private float lastThickness = -1f; private static Sprite WhiteSprite { get { //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_0019: Unknown result type (might be due to invalid IL or missing references) //IL_0023: 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_004e: Unknown result type (might be due to invalid IL or missing references) //IL_005d: Expected O, but got Unknown if ((Object)(object)whiteSprite == (Object)null) { Texture2D val = new Texture2D(1, 1, (TextureFormat)4, false); val.SetPixel(0, 0, Color.white); val.Apply(false, false); whiteSprite = Sprite.Create(val, new Rect(0f, 0f, 1f, 1f), new Vector2(0.5f, 0.5f), 100f); ((Object)whiteSprite).name = "GraduatedHealth_White"; } return whiteSprite; } } public RectTransform Parent => parent; public bool IsValid { get { if ((Object)(object)root != (Object)null) { return (Object)(object)parent != (Object)null; } return false; } } public void Attach(RectTransform barParent) { //IL_004d: Unknown result type (might be due to invalid IL or missing references) //IL_0057: Expected O, but got Unknown //IL_007a: Unknown result type (might be due to invalid IL or missing references) //IL_0084: Expected O, but got Unknown //IL_008a: 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_00aa: Unknown result type (might be due to invalid IL or missing references) //IL_00ba: Unknown result type (might be due to invalid IL or missing references) //IL_00d4: Unknown result type (might be due to invalid IL or missing references) //IL_00e4: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)barParent == (Object)null) && (!((Object)(object)parent == (Object)(object)barParent) || !((Object)(object)root != (Object)null))) { Destroy(); parent = barParent; root = new GameObject("GraduatedHealth_Notches", new Type[1] { typeof(RectTransform) }); root.transform.SetParent((Transform)(object)parent, false); rootRect = (RectTransform)root.transform; rootRect.anchorMin = Vector2.zero; rootRect.anchorMax = Vector2.one; rootRect.offsetMin = Vector2.zero; rootRect.offsetMax = Vector2.zero; rootRect.pivot = new Vector2(0.5f, 0.5f); ((Transform)rootRect).localScale = Vector3.one; ((Transform)rootRect).SetAsLastSibling(); } } public void Update(float maxHealth, float interval, Color color, float thickness, float heightFraction = 1f) { //IL_0033: Unknown result type (might be due to invalid IL or missing references) //IL_0038: Unknown result type (might be due to invalid IL or missing references) //IL_0061: 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_0050: Unknown result type (might be due to invalid IL or missing references) //IL_007e: Unknown result type (might be due to invalid IL or missing references) //IL_00ff: Unknown result type (might be due to invalid IL or missing references) //IL_0100: Unknown result type (might be due to invalid IL or missing references) //IL_00d0: 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) //IL_0183: Unknown result type (might be due to invalid IL or missing references) //IL_0199: Unknown result type (might be due to invalid IL or missing references) //IL_01af: Unknown result type (might be due to invalid IL or missing references) //IL_01be: Unknown result type (might be due to invalid IL or missing references) //IL_01d3: Unknown result type (might be due to invalid IL or missing references) //IL_01df: Unknown result type (might be due to invalid IL or missing references) //IL_0204: Unknown result type (might be due to invalid IL or missing references) //IL_01f6: Unknown result type (might be due to invalid IL or missing references) //IL_022b: Unknown result type (might be due to invalid IL or missing references) //IL_021f: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)rootRect == (Object)null || (Object)(object)parent == (Object)null || interval <= 0f || maxHealth <= 0f) { return; } Rect rect = parent.rect; float num = ((Rect)(ref rect)).width; if (num <= 0f) { num = parent.sizeDelta.x; } rect = parent.rect; float num2 = ((Rect)(ref rect)).height; if (num2 <= 0f) { num2 = parent.sizeDelta.y; } if (Mathf.Approximately(maxHealth, lastMaxHealth) && Mathf.Approximately(interval, lastInterval) && Mathf.Approximately(num, lastWidth) && Mathf.Approximately(num2, lastHeight) && Mathf.Approximately(thickness, lastThickness) && !(color != lastColor)) { return; } lastMaxHealth = maxHealth; lastInterval = interval; lastWidth = num; lastHeight = num2; lastColor = color; lastThickness = thickness; int num3 = 0; for (float num4 = interval; num4 < maxHealth - 0.001f; num4 += interval) { num3++; } EnsureTickCount(num3); float num5 = Mathf.Max(1f, num2 * Mathf.Clamp01(heightFraction)); float num6 = thickness * 0.5f; int num7 = 0; for (float num8 = interval; num8 < maxHealth - 0.001f; num8 += interval) { float num9 = num8 / maxHealth; Image val = ticks[num7]; RectTransform rectTransform = ((Graphic)val).rectTransform; rectTransform.anchorMin = new Vector2(0f, 0.5f); rectTransform.anchorMax = new Vector2(0f, 0.5f); rectTransform.pivot = new Vector2(0.5f, 0.5f); rectTransform.sizeDelta = new Vector2(thickness, num5); rectTransform.anchoredPosition = new Vector2(num9 * num, 0f); if (rectTransform.anchoredPosition.x < num6) { rectTransform.anchoredPosition = new Vector2(num6, 0f); } else if (rectTransform.anchoredPosition.x > num - num6) { rectTransform.anchoredPosition = new Vector2(num - num6, 0f); } ((Graphic)val).color = color; if (!((Component)val).gameObject.activeSelf) { ((Component)val).gameObject.SetActive(true); } num7++; } for (int i = num7; i < ticks.Count; i++) { if (((Component)ticks[i]).gameObject.activeSelf) { ((Component)ticks[i]).gameObject.SetActive(false); } } } private void EnsureTickCount(int count) { //IL_004c: Unknown result type (might be due to invalid IL or missing references) //IL_0051: Unknown result type (might be due to invalid IL or missing references) //IL_0071: Unknown result type (might be due to invalid IL or missing references) while (ticks.Count < count) { GameObject val = new GameObject($"Notch_{ticks.Count}", new Type[3] { typeof(RectTransform), typeof(CanvasRenderer), typeof(Image) }); val.transform.SetParent((Transform)(object)rootRect, false); Image component = val.GetComponent(); ((Graphic)component).raycastTarget = false; ((Graphic)component).color = Color.white; component.sprite = WhiteSprite; component.type = (Type)0; ticks.Add(component); } } public void Destroy() { if ((Object)(object)root != (Object)null) { Object.Destroy((Object)(object)root); root = null; rootRect = null; } ticks.Clear(); parent = null; lastMaxHealth = -1f; lastInterval = -1f; lastWidth = -1f; lastHeight = -1f; lastThickness = -1f; } } [BepInPlugin("sparroh.graduatedhealth", "GraduatedHealth", "1.0.0")] [MycoMod(/*Could not decode attribute arguments.*/)] public class SparrohPlugin : BaseUnityPlugin { public const string PluginGUID = "sparroh.graduatedhealth"; public const string PluginName = "GraduatedHealth"; public const string PluginVersion = "1.0.0"; internal static ManualLogSource Logger; private Harmony harmony; private GraduatedHealthMod 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.graduatedhealth"); } 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.graduatedhealth.cfg"); fileSystemWatcher.Changed += delegate { try { configFile.Reload(); } catch { } }; fileSystemWatcher.EnableRaisingEvents = true; } catch (Exception ex2) { Logger.LogWarning((object)("Failed to set up config watcher: " + ex2.Message)); } try { mod = new GraduatedHealthMod(configFile, harmony); } catch (Exception ex3) { Logger.LogError((object)("Failed to initialize GraduatedHealth: " + ex3.Message)); } try { harmony.PatchAll(); } catch (Exception ex4) { Logger.LogError((object)("Failed to apply Harmony patches: " + ex4.Message)); } Logger.LogInfo((object)"GraduatedHealth loaded successfully."); } private void Update() { try { mod?.Update(); } catch (Exception ex) { Logger.LogError((object)("Error in GraduatedHealth.Update(): " + ex.Message)); } } private void OnDestroy() { try { mod?.OnDestroy(); } catch (Exception ex) { Logger.LogError((object)("Error in GraduatedHealth.OnDestroy(): " + ex.Message)); } try { Harmony obj = harmony; if (obj != null) { obj.UnpatchSelf(); } } catch (Exception ex2) { Logger.LogError((object)("Error unpatching Harmony: " + ex2.Message)); } } } namespace GraduatedHealth { public static class MyPluginInfo { public const string PLUGIN_GUID = "GraduatedHealth"; public const string PLUGIN_NAME = "GraduatedHealth"; 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) { } } }