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<BossHealthbar> 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<bool> enablePlayerNotches;
private readonly ConfigEntry<bool> enableEnemyBossNotches;
private readonly ConfigEntry<bool> enableFloatingEnemyNotches;
private readonly ConfigEntry<float> playerInterval;
private readonly ConfigEntry<float> enemyInterval;
private readonly ConfigEntry<float> notchThickness;
private readonly ConfigEntry<float> notchHeightFraction;
private readonly ConfigEntry<string> notchColorHex;
private readonly FieldInfo bossTargetField;
private readonly FieldInfo bossHealthbarField;
private readonly FieldInfo bossHealthbarParentField;
private readonly FieldInfo floatingHealthbarField;
private readonly Dictionary<BossHealthbar, HealthbarNotches> bossNotches = new Dictionary<BossHealthbar, HealthbarNotches>();
private readonly Dictionary<Healthbar, HealthbarNotches> floatingNotches = new Dictionary<Healthbar, HealthbarNotches>();
private readonly List<BossHealthbar> bossRemoveBuffer = new List<BossHealthbar>();
private readonly List<Healthbar> floatingRemoveBuffer = new List<Healthbar>();
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<bool>("General", "EnablePlayerNotches", true, "Add graduation notches to the local player health bar.");
enableEnemyBossNotches = config.Bind<bool>("General", "EnableEnemyBossNotches", true, "Add graduation notches to boss / abomination health bars.");
enableFloatingEnemyNotches = config.Bind<bool>("General", "EnableFloatingEnemyNotches", true, "Add graduation notches to floating world-space enemy health bars.");
playerInterval = config.Bind<float>("Intervals", "PlayerHealthPerNotch", 5f, "Player health bar: one notch every N max HP.");
enemyInterval = config.Bind<float>("Intervals", "EnemyHealthPerNotch", 500f, "Enemy health bars (boss + floating): one notch every N max HP.");
notchThickness = config.Bind<float>("Display", "NotchThickness", 2f, "Width of each notch line in UI pixels.");
notchHeightFraction = config.Bind<float>("Display", "NotchHeightFraction", 1f, "Notch height as a fraction of the bar height (0-1).");
notchColorHex = config.Bind<string>("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<Graphic>(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<Graphic>() ?? val3.GetComponentInChildren<Graphic>(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<Transform> list = new List<Transform>();
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<Graphic>();
}
if ((Object)(object)val2 == (Object)null)
{
val2 = ((Component)item).GetComponentInChildren<Graphic>(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<Transform> 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<BossHealthbar> 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<BossHealthbar, HealthbarNotches> 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<BossHealthbar>(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<IEnemyComponent> 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<BossHealthbar, HealthbarNotches> 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<Healthbar>();
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<Healthbar, HealthbarNotches> 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<Healthbar, HealthbarNotches> 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<Image> ticks = new List<Image>(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<Image>();
((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)
{
}
}
}