Decompiled source of HealthDisplayWithFont v0.4.2

Mods/HealthDisplayWithFont.dll

Decompiled 21 hours ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using HarmonyLib;
using HealthDisplayWithFont;
using Il2CppRUMBLE.Managers;
using Il2CppRUMBLE.Players;
using Il2CppRUMBLE.Players.Subsystems;
using Il2CppRUMBLE.Utilities;
using Il2CppSystem.Collections.Generic;
using Il2CppTMPro;
using MelonLoader;
using Microsoft.CodeAnalysis;
using RumbleModdingAPI.RMAPI;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: MelonInfo(typeof(HealthDisplayWithFontClass), "HealthDisplayWithFont", "0.4.2", "ninjaguardian", "https://thunderstore.io/c/rumble/p/ninjaguardian/HealthDisplayWithFont")]
[assembly: MelonGame("Buckethead Entertainment", "RUMBLE")]
[assembly: MelonColor(255, 0, 160, 230)]
[assembly: MelonAuthorColor(255, 0, 160, 230)]
[assembly: MelonPlatformDomain(/*Could not decode attribute arguments.*/)]
[assembly: VerifyLoaderVersion("0.7.2", true)]
[assembly: TargetFramework(".NETCoreApp,Version=v6.0", FrameworkDisplayName = "")]
[assembly: AssemblyCompany("ninjaguardian (github)")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyCopyright("Copyright © 2025 ninjaguardian (github), This work is dedicated to the public domain under CC0 1.0.")]
[assembly: AssemblyDescription("Shows health above healthbar with a chosen font")]
[assembly: AssemblyFileVersion("0.4.2.0")]
[assembly: AssemblyInformationalVersion("0.4.2")]
[assembly: AssemblyProduct("HealthDisplayWithFont")]
[assembly: AssemblyTitle("HealthDisplayWithFont")]
[assembly: AssemblyMetadata("RepositoryUrl", "https://github.com/ninjaguardian/HealthDisplayWithFont")]
[assembly: AssemblyVersion("0.4.2.0")]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableAttribute : Attribute
	{
		public readonly byte[] NullableFlags;

		public NullableAttribute(byte P_0)
		{
			NullableFlags = new byte[1] { P_0 };
		}

		public NullableAttribute(byte[] P_0)
		{
			NullableFlags = P_0;
		}
	}
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableContextAttribute : Attribute
	{
		public readonly byte Flag;

		public NullableContextAttribute(byte P_0)
		{
			Flag = P_0;
		}
	}
}
namespace HealthDisplayWithFont
{
	public static class HealthDisplayWithFontModInfo
	{
		public const string ModName = "HealthDisplayWithFont";

		public const string ModVersion = "0.4.2";

		public const string MLVersion = "0.7.2";

		public const string HealthbarTextName = "HealthText";
	}
	public class HealthDisplayWithFontClass : MelonMod
	{
		[HarmonyPatch(typeof(PlayerHealth), "Initialize")]
		private static class PlayerHealthInitPatch
		{
			private static void Postfix(PlayerHealth __instance, PlayerController controller)
			{
				//IL_0007: Unknown result type (might be due to invalid IL or missing references)
				AddHealthbarText(GetHealthbar(((Component)__instance).transform, controller.controllerType), controller);
			}
		}

		[HarmonyPatch(typeof(PlayerHealth), "SetHealthBarPercentage")]
		private static class SetHealthBarPercentagePatch
		{
			private static void Postfix(PlayerHealth __instance, float currentHealth)
			{
				Transform? healthbarText = GetHealthbarText(((Component)__instance).transform, ((PlayerControllerSubsystem)__instance).parentController);
				if (healthbarText != null)
				{
					TextMeshPro component = ((Component)healthbarText).GetComponent<TextMeshPro>();
					if (component != null)
					{
						((TMP_Text)component).SetText("{0}", currentHealth);
					}
				}
			}
		}

		[HarmonyPatch(typeof(PlayerNameTag), "SetPlayerNameTagActive")]
		private static class SetPlayerNameTagActivePatch
		{
			private static void Prefix(PlayerNameTag __instance, bool state)
			{
				//IL_001c: Unknown result type (might be due to invalid IL or missing references)
				//IL_0022: Invalid comparison between Unknown and I4
				if (FadeActive.Contains(__instance))
				{
					return;
				}
				PlayerController parentController = ((PlayerControllerSubsystem)__instance).parentController;
				if (parentController != null && (int)parentController.controllerType == 2 && !((Object)(object)((Component)__instance).transform.parent != (Object)(object)((Component)parentController).transform) && !ControllerIsReplay(parentController))
				{
					Transform? healthbarText = GetHealthbarText(parentController);
					if (healthbarText != null)
					{
						((Component)healthbarText).gameObject.SetActive(!state);
					}
				}
			}
		}

		[HarmonyPatch(typeof(PlayerNameTag), "FadePlayerNameTag")]
		private static class FadePlayerNameTagPatch
		{
			private static void Prefix(PlayerNameTag __instance, bool on)
			{
				//IL_0020: Unknown result type (might be due to invalid IL or missing references)
				//IL_0026: Invalid comparison between Unknown and I4
				PlayerController parentController = ((PlayerControllerSubsystem)__instance).parentController;
				if (parentController == null || (int)parentController.controllerType != 2 || (Object)(object)((Component)__instance).transform.parent != (Object)(object)((Component)parentController).transform || ControllerIsReplay(parentController))
				{
					return;
				}
				Transform healthbar = GetHealthbarText(parentController);
				Transform obj = healthbar;
				if ((Object)(object)((obj != null) ? ((Component)obj).gameObject : null) == (Object)null)
				{
					return;
				}
				if (!on && !((Component)healthbar).gameObject.activeSelf)
				{
					((Component)healthbar).gameObject.SetActive(true);
					((TMP_Text)((Component)healthbar).GetComponent<TextMeshPro>()).alpha = 0f;
				}
				if (!FadeActive.Add(__instance))
				{
					return;
				}
				MelonCoroutines.Start(FadeText(((Component)healthbar).GetComponent<TextMeshPro>(), on ? 0f : 1f, __instance.playerNameFadeOutDuration, on ? ((Action)delegate
				{
					Transform obj2 = healthbar;
					if (obj2 != null)
					{
						((Component)obj2).gameObject.SetActive(false);
					}
					FadeActive.Remove(__instance);
				}) : ((Action)delegate
				{
					FadeActive.Remove(__instance);
				})));
			}
		}

		private static readonly Dictionary<TMP_FontAsset, TMP_FontAsset> FontToShaderFont = new Dictionary<TMP_FontAsset, TMP_FontAsset>();

		private static readonly HashSet<PlayerNameTag> FadeActive = new HashSet<PlayerNameTag>();

		private static Func<bool, TMP_FontAsset>? _getFont;

		private static Func<string, bool, TMP_FontAsset>? _fontFromName;

		private static Material? _healthbarMaterial;

		private static void AddHealthbarText(Transform? uiBar, PlayerController controller)
		{
			//IL_0055: Unknown result type (might be due to invalid IL or missing references)
			//IL_005b: Expected O, but got Unknown
			//IL_0070: Unknown result type (might be due to invalid IL or missing references)
			//IL_0076: Invalid comparison between Unknown and I4
			//IL_008d: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ac: 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)
			//IL_01c1: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c7: Invalid comparison between Unknown and I4
			//IL_0124: Unknown result type (might be due to invalid IL or missing references)
			//IL_0143: Unknown result type (might be due to invalid IL or missing references)
			//IL_0162: Unknown result type (might be due to invalid IL or missing references)
			//IL_017c: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)uiBar == (Object)null)
			{
				return;
			}
			if ((Object)(object)_healthbarMaterial == (Object)null)
			{
				MelonLogger.Error("Something really bad happened! (Context: HealthbarMaterial)", new Exception("Mod detected impossible state"));
				return;
			}
			Transform val = uiBar.Find("HealthText");
			if (val != null)
			{
				if (ControllerIsReplay(controller))
				{
					((Component)val).gameObject.SetActive(true);
				}
				return;
			}
			GameObject val2 = new GameObject("HealthText");
			val2.transform.SetParent(uiBar, false);
			TextMeshPro val3 = val2.AddComponent<TextMeshPro>();
			if ((int)controller.controllerType == 1)
			{
				val2.transform.localPosition = new Vector3(-1.01f, 0.01f, 0f);
				val2.transform.localRotation = Quaternion.Euler(63f, 270f, 0f);
				val2.transform.localScale = new Vector3(0.015f, 0.007f, 0.015f);
				((TMP_Text)val3).fontSize = 36f;
			}
			else
			{
				Transform obj = ((Component)controller).transform.Find("NameTag");
				if (obj != null && ((Component)obj).gameObject.activeSelf)
				{
					val2.SetActive(false);
				}
				val2.transform.localPosition = new Vector3(0f, -0.05f, 0f);
				val2.transform.localRotation = Quaternion.Euler(0f, 0f, 0f);
				val2.transform.localScale = new Vector3(-0.1f, 0.1f, 0.1f);
				val2.GetComponent<RectTransform>().pivot = new Vector2(0.5f, 0f);
				((TMP_Text)val3).fontSize = 30f;
			}
			((TMP_Text)val3).SetText("{0}", (float)controller.assignedPlayer.Data.HealthPoints);
			((TMP_Text)val3).alignment = (TextAlignmentOptions)514;
			if (_getFont == null)
			{
				return;
			}
			if ((int)controller.controllerType == 1)
			{
				((TMP_Text)val3).font = _getFont(arg: true);
				return;
			}
			TMP_FontAsset key = _getFont(arg: true);
			if (FontToShaderFont.TryGetValue(key, out TMP_FontAsset value))
			{
				((TMP_Text)val3).font = value;
				return;
			}
			TMP_FontAsset val4 = (((TMP_Text)val3).font = _getFont(arg: false));
			_healthbarMaterial.mainTexture = (Texture)(object)val4.atlasTexture;
			((TMP_Text)val3).fontMaterial = _healthbarMaterial;
			((TMP_Asset)val4).material = _healthbarMaterial;
			FontToShaderFont[key] = val4;
		}

		private static Transform? GetHealthbarText(PlayerController? controller)
		{
			return GetHealthbarText((controller != null) ? ((Component)controller).transform.Find("UI") : null, controller);
		}

		private static Transform? GetHealthbarText(Transform? ui, PlayerController? controller)
		{
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			Transform? healthbar = GetHealthbar(ui, (controller != null) ? new ControllerType?(controller.controllerType) : ((ControllerType?)null));
			if (healthbar == null)
			{
				return null;
			}
			return healthbar.Find("HealthText");
		}

		private static Transform? GetHealthbar(Transform? ui, ControllerType? controllerType)
		{
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: 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_001e: Invalid comparison between Unknown and I4
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			//IL_0022: Invalid comparison between Unknown and I4
			if ((Object)(object)ui == (Object)null)
			{
				return null;
			}
			if (controllerType.HasValue)
			{
				ControllerType valueOrDefault = controllerType.GetValueOrDefault();
				if ((int)valueOrDefault != 1)
				{
					if ((int)valueOrDefault == 2)
					{
						Transform child = ui.GetChild(1);
						if (((child != null) ? ((Object)child).name : null) == "RemoteUI")
						{
							return child;
						}
						MelonLogger.Warning("Could not get RemoteUI via GetChild");
						child = ui.Find("RemoteUI");
						if ((Object)(object)child != (Object)null)
						{
							return child;
						}
						MelonLogger.Error("Could not get RemoteUI via Find");
						return null;
					}
					MelonLogger.Warning($"Unknown controller type: {controllerType}");
					return null;
				}
				Transform child2 = ui.GetChild(0);
				Transform val = ((child2 != null) ? child2.GetChild(1) : null);
				if (((val != null) ? ((Object)val).name : null) == "Local UI Bar")
				{
					return val;
				}
				MelonLogger.Warning("Could not get Local Healthbar via GetChild");
				val = ui.Find("LocalUI/Local UI Bar");
				if ((Object)(object)val != (Object)null)
				{
					return val;
				}
				MelonLogger.Error("Could not get Local Healthbar via Find");
				return null;
			}
			return null;
		}

		private static bool ControllerIsReplay(PlayerController controller)
		{
			Transform parent = ((Component)controller).transform.parent;
			return ((parent != null) ? ((Object)parent).name : null) == "Replay Players";
		}

		private static IEnumerator FadeText(TextMeshPro text, float endAlpha, float playerNameFadeOutDuration, Action? onEnd = null)
		{
			if ((Object)(object)text == (Object)null)
			{
				onEnd?.Invoke();
				yield break;
			}
			float startAlpha = ((TMP_Text)text).alpha;
			if (playerNameFadeOutDuration <= 0f || Mathf.Approximately(startAlpha, endAlpha))
			{
				((TMP_Text)text).alpha = endAlpha;
				onEnd?.Invoke();
				yield break;
			}
			float elapsed = 0f;
			while (elapsed < playerNameFadeOutDuration)
			{
				elapsed += Time.deltaTime;
				((TMP_Text)text).alpha = Mathf.Lerp(startAlpha, endAlpha, Mathf.Clamp01(elapsed / playerNameFadeOutDuration));
				yield return null;
			}
			((TMP_Text)text).alpha = endAlpha;
			onEnd?.Invoke();
		}

		public override void OnInitializeMelon()
		{
			_healthbarMaterial = AssetBundles.LoadAssetFromStream<Material>((MelonMod)(object)this, "HealthDisplayWithFont.healthbartextshader", "healthbartext");
			((Object)_healthbarMaterial).hideFlags = (HideFlags)61;
			((Object)_healthbarMaterial.shader).hideFlags = (HideFlags)61;
			Type type = ((object)MelonBase.FindMelon("Fontifier", "ninjaguardian"))?.GetType();
			if ((object)type != null)
			{
				MethodInfo method = type.GetMethod("RegisterModCopy", BindingFlags.Static | BindingFlags.Public);
				object[] parameters = new object[2]
				{
					((MelonBase)this).Info.Name,
					new EventHandler<EventArgs>(FontChanged)
				};
				object obj = method?.Invoke(null, parameters);
				if (obj == null)
				{
					MelonLogger.Error("Something really bad happened! (Context: Fontifier installed, cannot invoke)", new Exception("Mod detected impossible state"));
					return;
				}
				(_getFont, _fontFromName) = ((Func<bool, TMP_FontAsset>, Func<string, bool, TMP_FontAsset>))obj;
			}
		}

		private static void FontChanged(object? sender, EventArgs args)
		{
			//IL_02cc: Unknown result type (might be due to invalid IL or missing references)
			//IL_02d2: Invalid comparison between Unknown and I4
			if (_fontFromName == null || (Object)(object)_healthbarMaterial == (Object)null)
			{
				MelonLogger.Error($"Something really bad happened! (Context: FontFromName {_fontFromName != null}, HealthbarMaterial {(Object)(object)_healthbarMaterial != (Object)null})", new Exception("Mod detected impossible state"));
				return;
			}
			TMP_FontAsset val = (TMP_FontAsset)_fontFromName(((dynamic)args).Value, true);
			TMP_FontAsset val2;
			if (FontToShaderFont.TryGetValue(val, out TMP_FontAsset value))
			{
				val2 = value;
			}
			else
			{
				val2 = (TMP_FontAsset)_fontFromName(((dynamic)args).Value, false);
				_healthbarMaterial.mainTexture = (Texture)(object)val2.atlasTexture;
				((TMP_Asset)val2).material = _healthbarMaterial;
				FontToShaderFont[val] = val2;
			}
			Enumerator<Player> enumerator = Singleton<PlayerManager>.instance.AllPlayers.GetEnumerator();
			while (enumerator.MoveNext())
			{
				Player current = enumerator.Current;
				Transform? healthbarText = GetHealthbarText(current.Controller);
				TextMeshPro val3 = ((healthbarText != null) ? ((Component)healthbarText).GetComponent<TextMeshPro>() : null);
				if (val3 != null)
				{
					if ((int)current.Controller.controllerType == 1)
					{
						((TMP_Text)val3).font = val;
						continue;
					}
					((TMP_Text)val3).font = val2;
					((TMP_Text)val3).fontMaterial = _healthbarMaterial;
				}
			}
		}
	}
}