using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using System.Text;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using MycopunkShared;
using Pigeon.Movement;
using TMPro;
using Unity.Collections;
using Unity.Netcode;
using UnityEngine;
using UnityEngine.InputSystem;
using UnityEngine.InputSystem.Controls;
using UnityEngine.UI;
[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: IgnoresAccessChecksTo("Assembly-CSharp")]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("MycopunkHealthNumbers")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("0.4.4.0")]
[assembly: AssemblyInformationalVersion("0.4.4+fe8cef1291afd0a7f7ea8a9ddfd28d3607c4cdd5")]
[assembly: AssemblyProduct("MycopunkHealthNumbers")]
[assembly: AssemblyTitle("MycopunkHealthNumbers")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("0.4.4.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;
}
}
}
namespace MycopunkHealthNumbers
{
internal sealed class BossHealthLabel : MonoBehaviour
{
[HarmonyPatch(typeof(BossHealthbar), "Update")]
private static class BossBarPatch
{
[HarmonyPostfix]
private static void Postfix(BossHealthbar __instance)
{
Attach((MonoBehaviour)(object)__instance);
}
}
[HarmonyPatch(typeof(RhombominationHealthbar), "Update")]
private static class RhomboBarPatch
{
[HarmonyPostfix]
private static void Postfix(RhombominationHealthbar __instance)
{
Attach((MonoBehaviour)(object)__instance);
}
}
private readonly HealthText _text = new HealthText();
private TextMeshProUGUI _label;
private RectTransform _parent;
private string _lastApproxSource;
private string _lastApproxText;
private bool _failed;
internal static void Install(Harmony harmony)
{
Install(harmony, typeof(BossBarPatch), typeof(BossHealthbar));
Install(harmony, typeof(RhomboBarPatch), typeof(RhombominationHealthbar));
}
private static void Install(Harmony harmony, Type patch, Type type)
{
try
{
harmony.CreateClassProcessor(patch).Patch();
}
catch (Exception ex)
{
Plugin.Log.LogWarning((object)("Boss health unavailable for " + type.Name + ": " + ex.Message));
}
}
private static void Attach(MonoBehaviour __instance)
{
if ((Object)(object)__instance != (Object)null && (Object)(object)((Component)__instance).GetComponent<BossHealthLabel>() == (Object)null)
{
((Component)__instance).gameObject.AddComponent<BossHealthLabel>();
}
}
private void LateUpdate()
{
if (_failed)
{
return;
}
try
{
Refresh();
}
catch (Exception ex)
{
_failed = true;
if ((Object)(object)_label != (Object)null)
{
((Component)_label).gameObject.SetActive(false);
}
Plugin.Log.LogWarning((object)("Boss health label disabled: " + ex.Message));
}
}
private void Refresh()
{
//IL_0169: Unknown result type (might be due to invalid IL or missing references)
//IL_0380: Unknown result type (might be due to invalid IL or missing references)
//IL_03b0: Unknown result type (might be due to invalid IL or missing references)
//IL_03c5: Unknown result type (might be due to invalid IL or missing references)
//IL_03da: Unknown result type (might be due to invalid IL or missing references)
//IL_03e5: Unknown result type (might be due to invalid IL or missing references)
//IL_03f9: Unknown result type (might be due to invalid IL or missing references)
//IL_042e: Unknown result type (might be due to invalid IL or missing references)
Settings settings = Plugin.Settings;
if (settings == null || !settings.Enabled || !settings.Boss || HudVisibility.ResultsOpen())
{
Hide();
return;
}
Graphic val = null;
TextMeshProUGUI val2 = null;
float num = 0f;
float num2 = 0f;
bool flag = false;
bool flag2 = false;
BossHealthbar component = ((Component)this).GetComponent<BossHealthbar>();
if ((Object)(object)component != (Object)null)
{
EnemyBrain target = component.target;
if ((Object)(object)target == (Object)null)
{
Hide();
return;
}
val = component.healthbar;
val2 = component.nameText;
AmalgamationHealthbar val3 = (AmalgamationHealthbar)(object)((component is AmalgamationHealthbar) ? component : null);
if (val3 != null)
{
bool canBeKilled = val3.canBeKilled;
if (canBeKilled)
{
val = val3.totalHealthbar;
}
if (!canBeKilled)
{
AmalgamationBehaviour component2 = ((Component)target).GetComponent<AmalgamationBehaviour>();
if ((Object)(object)component2 == (Object)null)
{
Hide();
return;
}
AmalgamationGlobalEvent val4 = (AmalgamationGlobalEvent)(((Object)(object)Global.Instance != (Object)null) ? /*isinst with value type is only supported in some contexts*/: null);
num2 = (((Object)(object)val4 != (Object)null) ? ((float)val4.CurrentMaxInstanceDamage) : 1000f);
num = Mathf.Max(0f, num2 - component2.DamageTaken);
}
}
if (num2 <= 0f)
{
EnemyCore core = target.Core;
if ((Object)(object)core == (Object)null)
{
Hide();
return;
}
if ((Object)(object)target.EnemyClass != (Object)null && !target.EnemyClass.config.onlyUseCoreHealthForHealthbar && (Object)(object)val != (Object)null)
{
float num3 = Mathf.Clamp01(((Transform)val.rectTransform).localScale.x);
float num4 = (((NetworkBehaviour)target).IsServer ? target.totalMaxHealth : 0f);
if (!((NetworkBehaviour)target).IsServer && Plugin.BossNetwork != null && Plugin.BossNetwork.TryGet(target, out var max, out var ratio))
{
num4 = max;
num3 = ratio;
}
if (num4 > 0f && !float.IsNaN(num4) && !float.IsInfinity(num4))
{
num2 = num4;
num = num3 * num2;
flag = true;
}
else
{
num2 = 100f;
num = num3 * num2;
flag2 = true;
}
}
else
{
num = ((EnemyPart)core).Health;
num2 = ((EnemyPart)core).MaxHealth;
}
}
}
else
{
RhombominationHealthbar component3 = ((Component)this).GetComponent<RhombominationHealthbar>();
if ((Object)(object)component3 == (Object)null)
{
Hide();
return;
}
Rhombomination source = component3.source;
ObjectTarget val5 = (((Object)(object)source != (Object)null) ? source.Core : null);
if ((Object)(object)val5 == (Object)null)
{
Hide();
return;
}
val = component3.healthbar;
num = val5.Health;
num2 = val5.MaxHealth;
}
if (!((Object)(object)val == (Object)null) && ((Behaviour)val).isActiveAndEnabled)
{
Transform parent = ((Transform)val.rectTransform).parent;
RectTransform val6 = (RectTransform)(object)((parent is RectTransform) ? parent : null);
if (val6 != null && !(num2 <= 0f) && !float.IsNaN(num) && !float.IsNaN(num2) && !float.IsInfinity(num) && !float.IsInfinity(num2))
{
if ((Object)(object)_label == (Object)null || (Object)(object)_parent != (Object)(object)val6)
{
if ((Object)(object)_label != (Object)null)
{
Object.Destroy((Object)(object)((Component)_label).gameObject);
}
if ((Object)(object)val2 == (Object)null && (Object)(object)PlayerLook.Instance != (Object)null)
{
val2 = PlayerLook.Instance.PlayerTitleText;
}
if ((Object)(object)val2 == (Object)null)
{
return;
}
_parent = val6;
_label = GameText.Create(val2, (Transform)(object)val6, "Boss Health Numbers");
((TMP_Text)_label).alignment = (TextAlignmentOptions)514;
((TMP_Text)_label).fontSize = 16f;
((TMP_Text)_label).fontStyle = (FontStyles)1;
((Graphic)_label).color = Color.white;
((TMP_Text)_label).maxVisibleCharacters = int.MaxValue;
RectTransform rectTransform = ((TMP_Text)_label).rectTransform;
rectTransform.anchorMin = new Vector2(0f, 0.5f);
rectTransform.anchorMax = new Vector2(1f, 0.5f);
rectTransform.pivot = new Vector2(0.5f, 0.5f);
rectTransform.anchoredPosition = Vector2.zero;
rectTransform.sizeDelta = new Vector2(0f, 24f);
((TMP_Text)_label).transform.SetAsLastSibling();
GameText.SetShadow(_label, on: true, new Color(0f, 0f, 0f, 0.9f));
}
string text = _text.Get(num, num2, 1f, 0, flag2 ? "{0}%" : "{0} / {1}", "");
if (flag)
{
if ((object)text != _lastApproxSource)
{
_lastApproxSource = text;
_lastApproxText = "~" + text;
}
text = _lastApproxText;
}
GameHudText.SetText(_label, text);
GameHudText.SetActive(_label, true);
return;
}
}
Hide();
}
private void Hide()
{
if ((Object)(object)_label != (Object)null)
{
GameHudText.SetActive(_label, false);
}
}
private void OnDestroy()
{
if ((Object)(object)_label != (Object)null)
{
Object.Destroy((Object)(object)((Component)_label).gameObject);
}
}
}
internal sealed class BossHealthNetwork : IDisposable
{
private sealed class Entry
{
public NetworkObject Object;
public ulong Nonce;
public float Max;
public float Ratio;
public float ReceivedAt = float.NegativeInfinity;
public float NextRequest;
public float LastUsed;
}
private const string Request = "mycopunk.healthnumbers.boss.v1.request";
private const string Response = "mycopunk.healthnumbers.boss.v1.response";
private const float RequestInterval = 0.5f;
private const float ValueLifetime = 3f;
private readonly ManualLogSource _log;
private readonly Dictionary<ulong, Entry> _values = new Dictionary<ulong, Entry>();
private readonly List<ulong> _stale = new List<ulong>();
private NetworkManager _manager;
private bool _registered;
private bool _serverHandler;
private bool _failed;
private ulong _nextNonce = (ulong)DateTime.UtcNow.Ticks;
private float _nextCleanup;
public BossHealthNetwork(ManualLogSource log)
{
_log = log;
}
public void Tick()
{
//IL_00f1: Unknown result type (might be due to invalid IL or missing references)
//IL_00fb: Expected O, but got Unknown
//IL_00d8: Unknown result type (might be due to invalid IL or missing references)
//IL_00e2: Expected O, but got Unknown
NetworkManager singleton = NetworkManager.Singleton;
if ((Object)(object)singleton != (Object)(object)_manager || ((Object)(object)_manager != (Object)null && !_manager.IsListening))
{
Dispose();
_manager = (((Object)(object)singleton != (Object)null && singleton.IsListening) ? singleton : null);
_failed = false;
}
if ((Object)(object)_manager == (Object)null || _failed || !_manager.IsListening || (!_manager.IsServer && !_manager.IsConnectedClient))
{
return;
}
try
{
CustomMessagingManager customMessagingManager = _manager.CustomMessagingManager;
if (customMessagingManager == null)
{
return;
}
if (!_registered)
{
_serverHandler = _manager.IsServer;
if (_serverHandler)
{
customMessagingManager.RegisterNamedMessageHandler("mycopunk.healthnumbers.boss.v1.request", new HandleNamedMessageDelegate(OnRequest));
}
else
{
customMessagingManager.RegisterNamedMessageHandler("mycopunk.healthnumbers.boss.v1.response", new HandleNamedMessageDelegate(OnResponse));
}
_registered = true;
_log.LogInfo((object)("Boss health sharing ready (" + (_serverHandler ? "host" : "client") + ")."));
}
float unscaledTime = Time.unscaledTime;
if (unscaledTime < _nextCleanup)
{
return;
}
_nextCleanup = unscaledTime + 15f;
foreach (KeyValuePair<ulong, Entry> value in _values)
{
if ((Object)(object)value.Value.Object == (Object)null || !value.Value.Object.IsSpawned || unscaledTime - value.Value.LastUsed > 10f)
{
_stale.Add(value.Key);
}
}
foreach (ulong item in _stale)
{
_values.Remove(item);
}
_stale.Clear();
}
catch (Exception ex)
{
_failed = true;
_log.LogWarning((object)("Boss health sharing unavailable; using local values: " + ex.Message));
}
}
public unsafe bool TryGet(EnemyBrain brain, out float max, out float ratio)
{
//IL_0103: Unknown result type (might be due to invalid IL or missing references)
//IL_0109: Unknown result type (might be due to invalid IL or missing references)
//IL_011a: Unknown result type (might be due to invalid IL or missing references)
//IL_0120: Unknown result type (might be due to invalid IL or missing references)
//IL_0139: Unknown result type (might be due to invalid IL or missing references)
max = 0f;
ratio = 0f;
if ((Object)(object)_manager == (Object)null || _failed || !_registered || _manager.IsServer || !_manager.IsConnectedClient || (Object)(object)brain == (Object)null)
{
return false;
}
try
{
NetworkObject networkObject = ((NetworkBehaviour)brain).NetworkObject;
if ((Object)(object)networkObject == (Object)null || !networkObject.IsSpawned)
{
return false;
}
ulong networkObjectId = networkObject.NetworkObjectId;
float unscaledTime = Time.unscaledTime;
if (!_values.TryGetValue(networkObjectId, out var value) || (Object)(object)value.Object != (Object)(object)networkObject)
{
Dictionary<ulong, Entry> values = _values;
ulong key = networkObjectId;
Entry obj = new Entry
{
Object = networkObject
};
value = obj;
values[key] = obj;
}
value.LastUsed = unscaledTime;
if (unscaledTime >= value.NextRequest)
{
value.NextRequest = unscaledTime + 3f;
value.Nonce = ++_nextNonce;
FastBufferWriter val = default(FastBufferWriter);
((FastBufferWriter)(ref val))..ctor(16, (Allocator)2, -1);
try
{
((FastBufferWriter)(ref val)).WriteValueSafe<ulong>(ref networkObjectId, default(ForPrimitives));
((FastBufferWriter)(ref val)).WriteValueSafe<ulong>(ref value.Nonce, default(ForPrimitives));
_manager.CustomMessagingManager.SendNamedMessage("mycopunk.healthnumbers.boss.v1.request", 0uL, val, (NetworkDelivery)2);
}
finally
{
((IDisposable)(*(FastBufferWriter*)(&val))/*cast due to .constrained prefix*/).Dispose();
}
}
if (unscaledTime - value.ReceivedAt >= 3f)
{
return false;
}
max = value.Max;
ratio = value.Ratio;
return max > 0f;
}
catch (Exception ex)
{
_failed = true;
_log.LogWarning((object)("Boss health request failed; using percentage: " + ex.Message));
return false;
}
}
private unsafe void OnRequest(ulong sender, FastBufferReader reader)
{
//IL_0047: Unknown result type (might be due to invalid IL or missing references)
//IL_004d: Unknown result type (might be due to invalid IL or missing references)
//IL_005a: Unknown result type (might be due to invalid IL or missing references)
//IL_0060: 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)
//IL_0182: Unknown result type (might be due to invalid IL or missing references)
//IL_018f: Unknown result type (might be due to invalid IL or missing references)
//IL_0195: Unknown result type (might be due to invalid IL or missing references)
//IL_01a2: Unknown result type (might be due to invalid IL or missing references)
//IL_01a8: Unknown result type (might be due to invalid IL or missing references)
//IL_01b5: Unknown result type (might be due to invalid IL or missing references)
//IL_01bb: 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)
try
{
if ((Object)(object)_manager == (Object)null || !_manager.IsServer || sender == _manager.LocalClientId || !_manager.ConnectedClients.ContainsKey(sender))
{
return;
}
ulong key = default(ulong);
((FastBufferReader)(ref reader)).ReadValueSafe<ulong>(ref key, default(ForPrimitives));
ulong num = default(ulong);
((FastBufferReader)(ref reader)).ReadValueSafe<ulong>(ref num, default(ForPrimitives));
if (_manager.SpawnManager == null || !_manager.SpawnManager.SpawnedObjects.TryGetValue(key, out var value) || (Object)(object)value == (Object)null || !value.IsSpawned)
{
return;
}
EnemyBrain val = ((Component)value).GetComponent<EnemyBrain>();
if ((Object)(object)val == (Object)null)
{
val = ((Component)value).GetComponentInChildren<EnemyBrain>(true);
}
if ((Object)(object)val == (Object)null || (Object)(object)((NetworkBehaviour)val).NetworkObject != (Object)(object)value)
{
return;
}
float totalMaxHealth = val.totalMaxHealth;
if (totalMaxHealth <= 0f || float.IsNaN(totalMaxHealth) || float.IsInfinity(totalMaxHealth))
{
return;
}
EnemyCore core = val.Core;
if ((Object)(object)core == (Object)null || (Object)(object)val.EnemyClass == (Object)null)
{
return;
}
float num2 = ((EnemyPart)core).NormalizedHealth;
if (!val.EnemyClass.config.onlyUseCoreHealthForHealthbar)
{
num2 *= val.NormalizedHealth;
}
if (float.IsNaN(num2) || float.IsInfinity(num2))
{
return;
}
num2 = Mathf.Clamp01(num2);
FastBufferWriter val2 = default(FastBufferWriter);
((FastBufferWriter)(ref val2))..ctor(24, (Allocator)2, -1);
try
{
((FastBufferWriter)(ref val2)).WriteValueSafe<ulong>(ref key, default(ForPrimitives));
((FastBufferWriter)(ref val2)).WriteValueSafe<ulong>(ref num, default(ForPrimitives));
((FastBufferWriter)(ref val2)).WriteValueSafe<float>(ref totalMaxHealth, default(ForPrimitives));
((FastBufferWriter)(ref val2)).WriteValueSafe<float>(ref num2, default(ForPrimitives));
_manager.CustomMessagingManager.SendNamedMessage("mycopunk.healthnumbers.boss.v1.response", sender, val2, (NetworkDelivery)2);
}
finally
{
((IDisposable)(*(FastBufferWriter*)(&val2))/*cast due to .constrained prefix*/).Dispose();
}
}
catch (Exception ex)
{
_log.LogWarning((object)("Invalid boss health request: " + ex.Message));
}
}
private void OnResponse(ulong sender, FastBufferReader reader)
{
//IL_0029: Unknown result type (might be due to invalid IL or missing references)
//IL_002f: 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_0042: Unknown result type (might be due to invalid IL or missing references)
//IL_004f: Unknown result type (might be due to invalid IL or missing references)
//IL_0055: Unknown result type (might be due to invalid IL or missing references)
//IL_0062: Unknown result type (might be due to invalid IL or missing references)
//IL_0068: Unknown result type (might be due to invalid IL or missing references)
try
{
if (!((Object)(object)_manager == (Object)null) && !_manager.IsServer && sender == 0L)
{
ulong key = default(ulong);
((FastBufferReader)(ref reader)).ReadValueSafe<ulong>(ref key, default(ForPrimitives));
ulong num = default(ulong);
((FastBufferReader)(ref reader)).ReadValueSafe<ulong>(ref num, default(ForPrimitives));
float num2 = default(float);
((FastBufferReader)(ref reader)).ReadValueSafe<float>(ref num2, default(ForPrimitives));
float num3 = default(float);
((FastBufferReader)(ref reader)).ReadValueSafe<float>(ref num3, default(ForPrimitives));
if (!(num2 <= 0f) && !float.IsNaN(num2) && !float.IsInfinity(num2) && !(num3 < 0f) && !(num3 > 1f) && !float.IsNaN(num3) && !float.IsInfinity(num3) && _values.TryGetValue(key, out var value) && value.Nonce == num && !((Object)(object)value.Object == (Object)null) && value.Object.IsSpawned && _manager.SpawnManager != null && _manager.SpawnManager.SpawnedObjects.TryGetValue(key, out var value2) && !((Object)(object)value2 != (Object)(object)value.Object))
{
value.Max = num2;
value.Ratio = num3;
value.ReceivedAt = Time.unscaledTime;
value.NextRequest = value.ReceivedAt + 0.5f;
}
}
}
catch (Exception ex)
{
_log.LogWarning((object)("Invalid boss health response: " + ex.Message));
}
}
public void Dispose()
{
try
{
if ((Object)(object)_manager != (Object)null && _registered && _manager.CustomMessagingManager != null)
{
if (_serverHandler)
{
_manager.CustomMessagingManager.UnregisterNamedMessageHandler("mycopunk.healthnumbers.boss.v1.request");
}
else
{
_manager.CustomMessagingManager.UnregisterNamedMessageHandler("mycopunk.healthnumbers.boss.v1.response");
}
}
}
catch (Exception ex)
{
_log.LogWarning((object)("Boss health sharing cleanup failed: " + ex.Message));
}
_registered = false;
_values.Clear();
_stale.Clear();
_manager = null;
_nextCleanup = 0f;
}
}
internal static class CapTracker
{
[HarmonyPatch(typeof(Player), "UpdateTarget")]
private static class UpdateTargetPatch
{
[HarmonyPrefix]
private static void Prefix(Player __instance)
{
if (__instance == Player.LocalPlayer)
{
_cap = __instance.tempMaxHealthCap;
_frame = Time.frameCount;
}
}
}
private static float _cap = 1f;
private static int _frame = -1;
public static bool Installed { get; private set; }
public static float Current
{
get
{
if (!Installed || Time.frameCount - _frame > 2)
{
return 1f;
}
return _cap;
}
}
public static void Install(Harmony harmony)
{
try
{
harmony.CreateClassProcessor(typeof(UpdateTargetPatch)).Patch();
Installed = true;
}
catch (Exception arg)
{
Plugin.Log.LogWarning((object)$"Could not hook Player.UpdateTarget; the max-health cap is not shown. {arg}");
}
}
}
internal static class DamageLog
{
[HarmonyPatch(typeof(Player), "ApplyDamage_Owner")]
private static class ApplyDamagePatch
{
[HarmonyPrefix]
private static void Prefix(Player __instance, ref DamageData data, IDamageSource source, out float __state)
{
//IL_004a: Unknown result type (might be due to invalid IL or missing references)
//IL_004f: 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_0056: Unknown result type (might be due to invalid IL or missing references)
//IL_0058: Invalid comparison between Unknown and I4
//IL_0096: Unknown result type (might be due to invalid IL or missing references)
//IL_00c8: Unknown result type (might be due to invalid IL or missing references)
__state = float.NaN;
if (Enabled() && __instance == Player.LocalPlayer && __instance.IsAlive)
{
__state = __instance.Health;
_inDamage = true;
_healthSet = false;
_guardBefore = Guard(__instance);
LogHandlers(__instance);
DamageFlags damageFlags = data.damageFlags;
bool flag = (damageFlags & 0x220) > 0;
Plugin.Log.LogInfo((object)($"[damage] t={Time.time:0.00} raw={F(data.damage)} " + $"effect={data.effect} effectAmount={F(data.effectAmount)} " + $"dot={((DamageData)(ref data)).IsDOT} flags={damageFlags} " + "source=" + DescribeSource(source) + " hp=" + F(__state) + "/" + F(__instance.MaxHealth) + " guard=" + (_guardBefore ? "on" : "off") + (flag ? " (this hit ignores the guard)" : "")));
}
}
[HarmonyFinalizer]
private static void Finalizer(Player __instance, float __state)
{
if (!float.IsNaN(__state))
{
_inDamage = false;
bool flag = Guard(__instance);
string text = " guard " + (_guardBefore ? "on" : "off") + " -> " + (flag ? "on" : "off");
if (_healthSet)
{
Plugin.Log.LogInfo((object)("[damage] lost=" + F(__state - _newHealth) + " hp " + F(__state) + " -> " + F(_newHealth) + text));
}
else
{
Plugin.Log.LogInfo((object)("[damage] no health change (blocked, mitigated or deferred)" + text));
}
if (_guardBefore && !flag)
{
Plugin.Log.LogInfo((object)$"[guard] t={Time.time:0.00} used: the hit left {F(_newHealth)}");
}
if (_healthSet && _newHealth <= 0f)
{
Plugin.Log.LogInfo((object)string.Format("[guard] t={0:0.00} killed (guard was {1} before the hit)", Time.time, _guardBefore ? "on" : "off"));
}
}
}
}
[HarmonyPatch(typeof(Player), "SetHealth_Owner")]
private static class SetHealthPatch
{
[HarmonyPrefix]
private static void Prefix(Player __instance, float value)
{
if (_inDamage && __instance == Player.LocalPlayer)
{
_newHealth = value;
_healthSet = true;
}
}
}
[HarmonyPatch(typeof(Player), "ApplyHeal_Owner")]
private static class HealPatch
{
[HarmonyPrefix]
private static void Prefix(Player __instance, out bool __state)
{
__state = Enabled() && __instance == Player.LocalPlayer && Guard(__instance);
}
[HarmonyPostfix]
private static void Postfix(Player __instance, bool __state)
{
if (Enabled() && __instance == Player.LocalPlayer && !__state && Guard(__instance))
{
Plugin.Log.LogInfo((object)$"[guard] t={Time.time:0.00} back on (health {F(__instance.Health)}/{F(__instance.MaxHealth)})");
}
}
}
public static Func<bool> Enabled = () => false;
private static readonly FieldInfo BeforeTakeDamage = AccessTools.Field(typeof(Player), "OnBeforeTakeDamage");
private static string _lastHandlers;
private const int IgnoresGuardFlags = 544;
private static bool _inDamage;
private static float _newHealth;
private static bool _healthSet;
private static bool _guardBefore;
public static void Install(Harmony harmony)
{
try
{
ModSetup.PatchTogether(harmony, new Type[3]
{
typeof(ApplyDamagePatch),
typeof(SetHealthPatch),
typeof(HealPatch)
});
}
catch (Exception arg)
{
Plugin.Log.LogWarning((object)$"Could not hook the damage path; the damage log is off. {arg}");
}
}
private static bool Guard(Player p)
{
return p.hasDeathProtection;
}
private static void LogHandlers(Player p)
{
if (BeforeTakeDamage == null)
{
return;
}
Delegate obj = BeforeTakeDamage.GetValue(p) as Delegate;
string text = "none";
if ((object)obj != null)
{
List<string> list = new List<string>();
Delegate[] invocationList = obj.GetInvocationList();
foreach (Delegate obj2 in invocationList)
{
list.Add(((obj2.Method.DeclaringType != null) ? (obj2.Method.DeclaringType.Name + ".") : "") + obj2.Method.Name);
}
text = string.Join(", ", list);
}
if (!(text == _lastHandlers))
{
_lastHandlers = text;
Plugin.Log.LogInfo((object)("[damage] OnBeforeTakeDamage handlers: " + text));
}
}
private static string DescribeSource(IDamageSource source)
{
if (source == null)
{
return "null";
}
string text = ((object)source).GetType().Name;
Component val = (Component)(object)((source is Component) ? source : null);
if (val != null && (Object)(object)val != (Object)null)
{
text = text + "(" + ((Object)val.gameObject).name + ")";
}
try
{
IDamageSource val2 = source.GetBase();
if (val2 != null && val2 != source)
{
text = text + " base=" + ((object)val2).GetType().Name;
}
}
catch
{
}
return text;
}
private static string F(object v)
{
if (!(v is float num))
{
return Convert.ToString(v, CultureInfo.InvariantCulture);
}
return num.ToString("0.###", CultureInfo.InvariantCulture);
}
}
internal static class GameText
{
public static TextMeshProUGUI Create(TextMeshProUGUI template, Transform parent, string name)
{
//IL_002c: Unknown result type (might be due to invalid IL or missing references)
//IL_0032: Unknown result type (might be due to invalid IL or missing references)
//IL_0043: 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_0058: Unknown result type (might be due to invalid IL or missing references)
TextMeshProUGUI obj = GameHudText.Create(template, parent, name);
((TMP_Text)obj).alignment = (TextAlignmentOptions)4097;
RectTransform rectTransform = ((TMP_Text)obj).rectTransform;
Vector2 val = default(Vector2);
((Vector2)(ref val))..ctor(0.5f, 0.5f);
rectTransform.anchorMax = val;
rectTransform.anchorMin = val;
rectTransform.pivot = new Vector2(0f, 0.5f);
((Transform)rectTransform).localRotation = Quaternion.identity;
((Transform)rectTransform).localScale = Vector3.one;
((TMP_Text)obj).text = "";
((Component)obj).gameObject.SetActive(true);
return obj;
}
public static void SetShadow(TextMeshProUGUI label, bool on, Color color)
{
//IL_0025: Unknown result type (might be due to invalid IL or missing references)
Material fontMaterial = ((TMP_Text)label).fontMaterial;
if (!((Object)(object)fontMaterial == (Object)null))
{
if (on)
{
fontMaterial.EnableKeyword(ShaderUtilities.Keyword_Underlay);
fontMaterial.SetColor(ShaderUtilities.ID_UnderlayColor, color);
fontMaterial.SetFloat(ShaderUtilities.ID_UnderlayOffsetX, 0.6f);
fontMaterial.SetFloat(ShaderUtilities.ID_UnderlayOffsetY, -0.6f);
fontMaterial.SetFloat(ShaderUtilities.ID_UnderlaySoftness, 0.3f);
}
else
{
fontMaterial.DisableKeyword(ShaderUtilities.Keyword_Underlay);
}
}
}
}
internal sealed class HealthText
{
private string _text;
private float _health = float.NaN;
private float _max = float.NaN;
private float _cap = float.NaN;
private int _decimals = -1;
private string _format;
private string _capFormat;
public string Get(float health, float max, float cap, int decimals, string format, string capFormat)
{
if (cap >= 1f || string.IsNullOrEmpty(capFormat))
{
cap = 1f;
}
if (_text != null && health == _health && max == _max && cap == _cap && decimals == _decimals && format == _format && capFormat == _capFormat)
{
return _text;
}
_health = health;
_max = max;
_cap = cap;
_decimals = decimals;
_format = format;
_capFormat = capFormat;
string text = "F" + decimals;
string text2 = health.ToString(text, CultureInfo.InvariantCulture);
string text3 = max.ToString(text, CultureInfo.InvariantCulture);
if (cap < 1f)
{
string text4 = (max * cap).ToString(text, CultureInfo.InvariantCulture);
_text = SafeFormat(format, text2 + " / " + text4, text2, text4) + SafeFormat(capFormat, " (" + text3 + ")", text3);
}
else
{
_text = SafeFormat(format, text2 + " / " + text3, text2, text3);
}
return _text;
}
private static string SafeFormat(string format, string fallback, params object[] args)
{
try
{
return string.Format(CultureInfo.InvariantCulture, format, args);
}
catch (FormatException)
{
return fallback;
}
}
}
internal static class MenuText
{
private static readonly Dictionary<string, Dictionary<string, string>> Names = new Dictionary<string, Dictionary<string, string>>
{
["en"] = new Dictionary<string, string>
{
["health.enabled"] = "Show health numbers",
["health.dead"] = "Hide while dead",
["health.bar"] = "Hide with the health bar",
["health.bold"] = "Bold",
["health.color"] = "Text color",
["health.shadow"] = "Shadow",
["health.teammates"] = "Teammates' health",
["health.boss"] = "Show boss health numbers",
["health.name_color"] = "Teammates' health in their name color",
["health.damage_log"] = "Damage log (debug)"
},
["ja"] = new Dictionary<string, string>
{
["health.enabled"] = "体力を数値で表示",
["health.dead"] = "死亡中は非表示",
["health.bar"] = "体力バーと一緒に非表示にする",
["health.bold"] = "太字",
["health.color"] = "文字の色",
["health.shadow"] = "文字の影",
["health.teammates"] = "味方の体力を表示",
["health.boss"] = "ボスの体力を数値で表示",
["health.name_color"] = "味方の名前と同じ色",
["health.damage_log"] = "被ダメージログ(デバッグ)"
}
};
private static readonly Dictionary<string, Dictionary<string, string>> Descriptions = new Dictionary<string, Dictionary<string, string>> { ["ja"] = new Dictionary<string, string>
{
["health.enabled"] = "体力を数値で表示します。",
["health.dead"] = "死亡している間は数値を表示しません。",
["health.bar"] = "Anchor が HealthBar のとき、メニューや HUD 非表示などで体力バーが隠れる間は数値も隠します。",
["health.bold"] = "文字を太字にします。",
["health.color"] = "数値の文字の色です。不透明度は設定ファイルの値のままです。",
["health.shadow"] = "文字の後ろに影を付け、読みやすくします。",
["health.teammates"] = "味方 HUD の名前の下に現在の体力と最大体力を表示します。自分だけがこの Mod を入れれば使えます。",
["health.boss"] = "ボスの体力バーに数値を表示します。複数パーツのボスはバーから換算した概算値を表示し、参加側は Mod を導入したホストから最大値を取得します。",
["health.name_color"] = "味方の名前と同じ色で数値を表示します。オフの場合は Style.Color を使います。",
["health.damage_log"] = "受けた攻撃の元のダメージ、属性、継続ダメージ、攻撃元、実際に減った体力、ワンパンガード(即死を防ぐ仕組み)の状態を BepInEx のログに記録します。"
} };
public static object[] Label(string key)
{
return ModsMenuTag.Label(key, (IDictionary<string, Dictionary<string, string>>)Names, (IDictionary<string, Dictionary<string, string>>)Descriptions);
}
}
public enum AnchorMode
{
HealthBar,
Screen
}
public enum RendererMode
{
Game,
OnGUI
}
internal sealed class Settings
{
internal ConfigEntry<bool> EnabledEntry;
internal ConfigEntry<string> FormatEntry;
internal ConfigEntry<int> DecimalsEntry;
internal ConfigEntry<string> CapFormatEntry;
internal ConfigEntry<bool> HideWhenDeadEntry;
internal ConfigEntry<Color> ColorEntry;
internal ConfigEntry<bool> TeammatesEntry;
internal ConfigEntry<float> TeammateOffsetXEntry;
internal ConfigEntry<float> TeammateOffsetYEntry;
internal ConfigEntry<float> TeammateFontScaleEntry;
internal ConfigEntry<bool> TeammateNameColorEntry;
internal ConfigEntry<bool> BossEntry;
public bool Enabled => EnabledEntry.Value;
public string Format => FormatEntry.Value;
public int Decimals => DecimalsEntry.Value;
public string CapFormat => CapFormatEntry.Value;
public bool HideWhenDead => HideWhenDeadEntry.Value;
public Color Color => ColorEntry.Value;
public bool Teammates => TeammatesEntry.Value;
public float TeammateOffsetX => TeammateOffsetXEntry.Value;
public float TeammateOffsetY => TeammateOffsetYEntry.Value;
public float TeammateFontScale => TeammateFontScaleEntry.Value;
public bool TeammateNameColor => TeammateNameColorEntry.Value;
public bool Boss => BossEntry.Value;
}
[BepInPlugin("t4t5u0.mycopunk.healthnumbers", "Mycopunk Health Numbers", "0.4.4")]
[BepInDependency("doku_macaron.mycopunk.macaroncore", "1.1.0")]
[MycoMod(/*Could not decode attribute arguments.*/)]
public class Plugin : BaseUnityPlugin
{
public const string Guid = "t4t5u0.mycopunk.healthnumbers";
public const string Name = "Mycopunk Health Numbers";
public const string Version = "0.4.4";
internal static ManualLogSource Log;
internal static Settings Settings;
internal static BossHealthNetwork BossNetwork;
private ConfigEntry<AnchorMode> _anchor;
private ConfigEntry<RendererMode> _renderer;
private ConfigEntry<bool> _hideWithHealthBar;
private ConfigEntry<float> _offsetX;
private ConfigEntry<float> _offsetY;
private ConfigEntry<float> _screenX;
private ConfigEntry<float> _screenY;
private ConfigEntry<int> _fontSize;
private ConfigEntry<bool> _bold;
private ConfigEntry<bool> _shadow;
private ConfigEntry<Color> _shadowColor;
private ConfigEntry<Key> _statDumpKey;
private ConfigEntry<bool> _damageLog;
private Harmony _harmony;
private HealthBarLocator _locator;
private readonly HealthText _localText = new HealthText();
private TextMeshProUGUI _label;
private Transform _labelParent;
private bool _labelShadow;
private Color _labelShadowColor;
private bool _gameLabelFailed;
private GUIStyle _style;
private GUIStyle _shadowStyle;
private readonly GUIContent _content = new GUIContent();
private bool UseGameRenderer
{
get
{
if (_renderer.Value == RendererMode.Game)
{
return !_gameLabelFailed;
}
return false;
}
}
private static Color TextColor => Settings.Color;
private void Awake()
{
//IL_0032: Unknown result type (might be due to invalid IL or missing references)
//IL_003c: Expected O, but got Unknown
//IL_0089: Unknown result type (might be due to invalid IL or missing references)
//IL_0093: Expected O, but got Unknown
//IL_00df: Unknown result type (might be due to invalid IL or missing references)
//IL_00e9: Expected O, but got Unknown
//IL_0131: Unknown result type (might be due to invalid IL or missing references)
//IL_013b: Expected O, but got Unknown
//IL_01b9: Unknown result type (might be due to invalid IL or missing references)
//IL_01c3: Expected O, but got Unknown
//IL_01f7: Unknown result type (might be due to invalid IL or missing references)
//IL_0201: Expected O, but got Unknown
//IL_024f: Unknown result type (might be due to invalid IL or missing references)
//IL_0259: Expected O, but got Unknown
//IL_0280: Unknown result type (might be due to invalid IL or missing references)
//IL_028a: Expected O, but got Unknown
//IL_02a0: Unknown result type (might be due to invalid IL or missing references)
//IL_02b5: Unknown result type (might be due to invalid IL or missing references)
//IL_02bf: Expected O, but got Unknown
//IL_02e6: Unknown result type (might be due to invalid IL or missing references)
//IL_02f0: Expected O, but got Unknown
//IL_031a: Unknown result type (might be due to invalid IL or missing references)
//IL_0350: Unknown result type (might be due to invalid IL or missing references)
//IL_035a: Expected O, but got Unknown
//IL_03d8: Unknown result type (might be due to invalid IL or missing references)
//IL_03e2: Expected O, but got Unknown
//IL_0409: Unknown result type (might be due to invalid IL or missing references)
//IL_0413: Expected O, but got Unknown
//IL_043a: Unknown result type (might be due to invalid IL or missing references)
//IL_0444: Expected O, but got Unknown
//IL_04ab: Unknown result type (might be due to invalid IL or missing references)
//IL_04b5: Expected O, but got Unknown
//IL_04c0: Unknown result type (might be due to invalid IL or missing references)
//IL_04ca: Expected O, but got Unknown
Log = ((BaseUnityPlugin)this).Logger;
Settings obj = new Settings
{
EnabledEntry = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "Enabled", true, new ConfigDescription("Show the health numbers.", (AcceptableValueBase)null, MenuText.Label("health.enabled"))),
FormatEntry = ((BaseUnityPlugin)this).Config.Bind<string>("Display", "Format", "{0} / {1}", "Text to show. {0} is the current health, {1} is the max health (the capped max while capped)."),
DecimalsEntry = ((BaseUnityPlugin)this).Config.Bind<int>("Display", "Decimals", 1, new ConfigDescription("Digits after the decimal point. Values are rounded.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 2), Array.Empty<object>())),
CapFormatEntry = ((BaseUnityPlugin)this).Config.Bind<string>("Display", "CapFormat", " ({0})", "Appended while max health is temporarily capped (Mycologist's consumed max health, some objectives). Format then shows the capped max as {1}, and {0} here is the original max health. Leave empty to ignore the cap. Only for yourself: teammates' caps are not known on your machine."),
HideWhenDeadEntry = ((BaseUnityPlugin)this).Config.Bind<bool>("Display", "HideWhenDead", true, new ConfigDescription("Hide the text while the player is dead.", (AcceptableValueBase)null, MenuText.Label("health.dead")))
};
_anchor = ((BaseUnityPlugin)this).Config.Bind<AnchorMode>("Position", "Anchor", AnchorMode.HealthBar, "HealthBar: place the text to the right of the game's health bar (falls back to Screen if the bar is not found). Screen: place the text at ScreenX / ScreenY.");
_hideWithHealthBar = ((BaseUnityPlugin)this).Config.Bind<bool>("Position", "HideWithHealthBar", true, new ConfigDescription("With Anchor = HealthBar, hide the text while the game's health bar is hidden (menus, HUD off, and so on).", (AcceptableValueBase)null, MenuText.Label("health.bar")));
_offsetX = ((BaseUnityPlugin)this).Config.Bind<float>("Position", "OffsetX", 12f, "With Anchor = HealthBar: horizontal offset from the right end of the bar, in pixels at 1080p (scaled with the screen height).");
_offsetY = ((BaseUnityPlugin)this).Config.Bind<float>("Position", "OffsetY", 0f, "With Anchor = HealthBar: vertical offset from the middle of the bar, in pixels at 1080p. Positive moves down.");
_screenX = ((BaseUnityPlugin)this).Config.Bind<float>("Position", "ScreenX", 0.02f, new ConfigDescription("With Anchor = Screen (or as the fallback): left edge of the text, as a fraction of the screen width from the left.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 1f), Array.Empty<object>()));
_screenY = ((BaseUnityPlugin)this).Config.Bind<float>("Position", "ScreenY", 0.93f, new ConfigDescription("With Anchor = Screen (or as the fallback): vertical middle of the text, as a fraction of the screen height from the top.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 1f), Array.Empty<object>()));
_renderer = ((BaseUnityPlugin)this).Config.Bind<RendererMode>("Style", "Renderer", RendererMode.Game, "Game: draw with a copy of the game's own HUD text (same font, behind menus like the rest of the HUD). OnGUI: draw with Unity IMGUI on top of everything (the look of 0.1.0). Game falls back to OnGUI if the HUD text is not found.");
_fontSize = ((BaseUnityPlugin)this).Config.Bind<int>("Style", "FontSize", 22, new ConfigDescription("Font size in pixels at 1080p (scaled with the screen height).", (AcceptableValueBase)(object)new AcceptableValueRange<int>(6, 200), Array.Empty<object>()));
_bold = ((BaseUnityPlugin)this).Config.Bind<bool>("Style", "Bold", true, new ConfigDescription("Use a bold font.", (AcceptableValueBase)null, MenuText.Label("health.bold")));
obj.ColorEntry = ((BaseUnityPlugin)this).Config.Bind<Color>("Style", "Color", Color.white, new ConfigDescription("Text color (RRGGBBAA).", (AcceptableValueBase)null, MenuText.Label("health.color")));
_shadow = ((BaseUnityPlugin)this).Config.Bind<bool>("Style", "Shadow", true, new ConfigDescription("Draw a drop shadow behind the text so it stays readable.", (AcceptableValueBase)null, MenuText.Label("health.shadow")));
_shadowColor = ((BaseUnityPlugin)this).Config.Bind<Color>("Style", "ShadowColor", new Color(0f, 0f, 0f, 0.8f), "Shadow color (RRGGBBAA).");
obj.TeammatesEntry = ((BaseUnityPlugin)this).Config.Bind<bool>("Teammates", "Enabled", true, new ConfigDescription("Also show each teammate's health / max health on a line under their name in the teammate HUD. Needs only this mod on your side; the game already sends teammates' health to everyone.", (AcceptableValueBase)null, MenuText.Label("health.teammates")));
obj.TeammateOffsetXEntry = ((BaseUnityPlugin)this).Config.Bind<float>("Teammates", "OffsetX", 6f, "Not used since 0.4.0 (the teammate number is on its own line under the name now). Kept so old cfg files stay valid.");
obj.TeammateOffsetYEntry = ((BaseUnityPlugin)this).Config.Bind<float>("Teammates", "OffsetY", 0f, "Not used since 0.4.0 (the teammate number is on its own line under the name now). Kept so old cfg files stay valid.");
obj.TeammateFontScaleEntry = ((BaseUnityPlugin)this).Config.Bind<float>("Teammates", "FontScale", 0.9f, new ConfigDescription("Font size relative to the teammate's name.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.3f, 3f), Array.Empty<object>()));
obj.TeammateNameColorEntry = ((BaseUnityPlugin)this).Config.Bind<bool>("Teammates", "UseNameColor", true, new ConfigDescription("Use the color of the teammate's name. Off: use Style.Color.", (AcceptableValueBase)null, MenuText.Label("health.name_color")));
obj.BossEntry = ((BaseUnityPlugin)this).Config.Bind<bool>("Boss", "Enabled", true, new ConfigDescription("Show boss health over the health bar. Composite bosses use an approximate bar-based value; clients can request the maximum from a host with this mod.", (AcceptableValueBase)null, MenuText.Label("health.boss")));
Settings = obj;
BossNetwork = new BossHealthNetwork(Log);
_locator = new HealthBarLocator();
_statDumpKey = ((BaseUnityPlugin)this).Config.Bind<Key>("Debug", "StatDumpKey", (Key)0, "Key that writes the Player prefab's base stats and your current stats to BepInEx/HealthNumbers/stats-*.md. None = off.");
_damageLog = ((BaseUnityPlugin)this).Config.Bind<bool>("Debug", "DamageLog", false, new ConfigDescription("Log every hit you take (raw damage, element, DoT, source, health lost, the one-hit guard) to the BepInEx log.", (AcceptableValueBase)null, MenuText.Label("health.damage_log")));
_harmony = new Harmony("t4t5u0.mycopunk.healthnumbers");
ModsMenu.Install(_harmony, (BaseUnityPlugin)(object)this);
CapTracker.Install(_harmony);
BossHealthLabel.Install(_harmony);
DamageLog.Enabled = () => _damageLog.Value;
DamageLog.Install(_harmony);
try
{
TeammateHealthLabel.Install(_harmony);
}
catch (Exception ex)
{
Log.LogWarning((object)("Teammate health numbers could not be hooked: " + ex));
}
Hotkeys.ReportConflicts((BaseUnityPlugin)(object)this);
Log.LogInfo((object)"Mycopunk Health Numbers 0.4.4 loaded");
}
private void OnDestroy()
{
Harmony harmony = _harmony;
if (harmony != null)
{
harmony.UnpatchSelf();
}
BossNetwork?.Dispose();
BossNetwork = null;
if ((Object)(object)_label != (Object)null)
{
Object.Destroy((Object)(object)((Component)_label).gameObject);
}
}
private void Update()
{
//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_0022: Unknown result type (might be due to invalid IL or missing references)
//IL_002b: Unknown result type (might be due to invalid IL or missing references)
BossNetwork?.Tick();
Key value = _statDumpKey.Value;
Keyboard current = Keyboard.current;
if ((int)value == 0 || current == null)
{
return;
}
try
{
if (((ButtonControl)current[value]).wasPressedThisFrame)
{
StatDump.Write();
}
}
catch (Exception arg)
{
Log.LogWarning((object)$"Stat dump failed: {arg}");
}
}
private bool TryGetPlacement(out Player player, out float x, out float yMid)
{
//IL_00b1: Unknown result type (might be due to invalid IL or missing references)
x = (yMid = 0f);
player = Player.LocalPlayer;
if (!Settings.Enabled || (Object)(object)player == (Object)null)
{
return false;
}
if (Settings.HideWhenDead && !player.IsAlive)
{
return false;
}
if (_anchor.Value == AnchorMode.HealthBar && _hideWithHealthBar.Value && HudVisibility.ResultsOpen())
{
return false;
}
float num = (float)Screen.height / 1080f;
if (_anchor.Value == AnchorMode.HealthBar)
{
Rect screenRect;
switch (_locator.TryGetScreenRect(player, out screenRect))
{
case HealthBarLocator.Result.Found:
x = ((Rect)(ref screenRect)).xMax + _offsetX.Value * num;
yMid = ((Rect)(ref screenRect)).center.y + _offsetY.Value * num;
return true;
case HealthBarLocator.Result.Hidden:
if (_hideWithHealthBar.Value)
{
return false;
}
break;
}
}
x = _screenX.Value * (float)Screen.width;
yMid = _screenY.Value * (float)Screen.height;
return true;
}
private string LocalText(Player player)
{
return _localText.Get(player.Health, player.MaxHealth, CapTracker.Current, Settings.Decimals, Settings.Format, Settings.CapFormat);
}
private void LateUpdate()
{
//IL_00c6: Unknown result type (might be due to invalid IL or missing references)
//IL_00ce: Unknown result type (might be due to invalid IL or missing references)
//IL_00d3: Unknown result type (might be due to invalid IL or missing references)
//IL_00ea: Unknown result type (might be due to invalid IL or missing references)
//IL_00ef: Unknown result type (might be due to invalid IL or missing references)
//IL_00dd: Unknown result type (might be due to invalid IL or missing references)
//IL_0101: Unknown result type (might be due to invalid IL or missing references)
//IL_014e: Unknown result type (might be due to invalid IL or missing references)
//IL_0153: Unknown result type (might be due to invalid IL or missing references)
//IL_0165: Unknown result type (might be due to invalid IL or missing references)
//IL_011f: Unknown result type (might be due to invalid IL or missing references)
//IL_012a: Unknown result type (might be due to invalid IL or missing references)
//IL_018d: Unknown result type (might be due to invalid IL or missing references)
//IL_0192: Unknown result type (might be due to invalid IL or missing references)
//IL_019d: Expected O, but got Unknown
//IL_01aa: Unknown result type (might be due to invalid IL or missing references)
//IL_01b1: Unknown result type (might be due to invalid IL or missing references)
//IL_01bd: Unknown result type (might be due to invalid IL or missing references)
if (!UseGameRenderer)
{
if ((Object)(object)_label != (Object)null)
{
GameHudText.SetActive(_label, false);
}
return;
}
try
{
if (!TryGetPlacement(out var player, out var x, out var yMid) || !EnsureLabel(out var root))
{
if ((Object)(object)_label != (Object)null)
{
GameHudText.SetActive(_label, false);
}
return;
}
GameHudText.SetText(_label, LocalText(player));
float num = (float)_fontSize.Value * ((float)Screen.height / 1080f) / Mathf.Max(0.0001f, root.scaleFactor);
if (((TMP_Text)_label).fontSize != num)
{
((TMP_Text)_label).fontSize = num;
}
FontStyles val = (FontStyles)(_bold.Value ? 1 : 0);
if (((TMP_Text)_label).fontStyle != val)
{
((TMP_Text)_label).fontStyle = val;
}
if (((Graphic)_label).color != TextColor)
{
((Graphic)_label).color = TextColor;
}
if (_labelShadow != _shadow.Value || _labelShadowColor != _shadowColor.Value)
{
_labelShadow = _shadow.Value;
_labelShadowColor = _shadowColor.Value;
GameText.SetShadow(_label, _labelShadow, _labelShadowColor);
}
Camera val2 = HudCoordinates.CameraFor(root);
Vector2 val3 = default(Vector2);
((Vector2)(ref val3))..ctor(x, (float)Screen.height - yMid);
Vector2 val4 = default(Vector2);
if (RectTransformUtility.ScreenPointToLocalPointInRectangle((RectTransform)_labelParent, val3, val2, ref val4))
{
((Transform)((TMP_Text)_label).rectTransform).localPosition = new Vector3(val4.x, val4.y, 0f);
}
GameHudText.SetActive(_label, true);
}
catch (Exception ex)
{
_gameLabelFailed = true;
if ((Object)(object)_label != (Object)null)
{
Object.Destroy((Object)(object)((Component)_label).gameObject);
}
_label = null;
Log.LogWarning((object)("Game-style health label failed; using OnGUI instead: " + ex));
}
}
private bool EnsureLabel(out Canvas root)
{
//IL_00e0: Unknown result type (might be due to invalid IL or missing references)
root = null;
PlayerLook instance = PlayerLook.Instance;
TextMeshProUGUI val = (((Object)(object)instance != (Object)null) ? instance.PlayerTitleText : null);
if ((Object)(object)val == (Object)null)
{
return false;
}
Canvas canvas = ((Graphic)val).canvas;
if ((Object)(object)canvas == (Object)null)
{
return false;
}
root = canvas.rootCanvas;
Transform transform = ((Component)root).transform;
if ((Object)(object)_label != (Object)null && (Object)(object)_labelParent == (Object)(object)transform)
{
return true;
}
if ((Object)(object)_label != (Object)null)
{
Object.Destroy((Object)(object)((Component)_label).gameObject);
}
_labelParent = transform;
_label = GameText.Create(val, _labelParent, "Health Numbers (local)");
((TMP_Text)_label).transform.SetAsLastSibling();
_labelShadow = !_shadow.Value;
Log.LogInfo((object)$"Health label: copied {((Object)val).name} onto canvas {((Object)root).name} ({root.renderMode})");
return true;
}
private void OnGUI()
{
//IL_000d: Unknown result type (might be due to invalid IL or missing references)
//IL_0013: Invalid comparison between Unknown and I4
//IL_0087: 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_00b4: Unknown result type (might be due to invalid IL or missing references)
//IL_00bf: 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_00d9: 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_010e: Unknown result type (might be due to invalid IL or missing references)
//IL_0129: Unknown result type (might be due to invalid IL or missing references)
//IL_016d: Unknown result type (might be due to invalid IL or missing references)
if (!UseGameRenderer && (int)Event.current.type == 7 && TryGetPlacement(out var player, out var x, out var yMid))
{
float num = (float)Screen.height / 1080f;
EnsureStyles();
int fontSize = Mathf.Max(1, Mathf.RoundToInt((float)_fontSize.Value * num));
_style.fontSize = fontSize;
_style.fontStyle = (FontStyle)(_bold.Value ? 1 : 0);
_style.normal.textColor = TextColor;
_content.text = LocalText(player);
Vector2 val = _style.CalcSize(_content);
Rect val2 = default(Rect);
((Rect)(ref val2))..ctor(Mathf.Round(x), Mathf.Round(yMid - val.y / 2f), val.x, val.y);
if (_shadow.Value)
{
_shadowStyle.fontSize = fontSize;
_shadowStyle.fontStyle = _style.fontStyle;
_shadowStyle.normal.textColor = _shadowColor.Value;
float num2 = Mathf.Max(1f, Mathf.Round(2f * num));
GUI.Label(new Rect(((Rect)(ref val2)).x + num2, ((Rect)(ref val2)).y + num2, ((Rect)(ref val2)).width, ((Rect)(ref val2)).height), _content, _shadowStyle);
}
GUI.Label(val2, _content, _style);
}
}
private void EnsureStyles()
{
//IL_0014: 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_0020: Unknown result type (might be due to invalid IL or missing references)
//IL_0027: Unknown result type (might be due to invalid IL or missing references)
//IL_002e: Unknown result type (might be due to invalid IL or missing references)
//IL_0033: Unknown result type (might be due to invalid IL or missing references)
//IL_003d: Expected O, but got Unknown
//IL_003d: Unknown result type (might be due to invalid IL or missing references)
//IL_0042: Unknown result type (might be due to invalid IL or missing references)
//IL_004c: Expected O, but got Unknown
//IL_0051: Expected O, but got Unknown
//IL_0058: Unknown result type (might be due to invalid IL or missing references)
//IL_0062: Expected O, but got Unknown
if (_style == null)
{
_style = new GUIStyle(GUI.skin.label)
{
alignment = (TextAnchor)3,
wordWrap = false,
clipping = (TextClipping)0,
padding = new RectOffset(0, 0, 0, 0),
margin = new RectOffset(0, 0, 0, 0)
};
_shadowStyle = new GUIStyle(_style);
}
}
}
internal sealed class HealthBarLocator
{
public enum Result
{
NotFound,
Hidden,
Found
}
private readonly Vector3[] _corners = (Vector3[])(object)new Vector3[4];
private Player _player;
private RectTransform _bar;
private Canvas _canvas;
private bool _found;
public Result TryGetScreenRect(Player player, out Rect screenRect)
{
//IL_0001: 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_0112: 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_01b1: Unknown result type (might be due to invalid IL or missing references)
//IL_01b6: 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_01c9: 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_01da: Unknown result type (might be due to invalid IL or missing references)
//IL_01e1: Unknown result type (might be due to invalid IL or missing references)
//IL_01e6: Unknown result type (might be due to invalid IL or missing references)
//IL_01eb: Unknown result type (might be due to invalid IL or missing references)
//IL_01fb: Unknown result type (might be due to invalid IL or missing references)
//IL_0200: Unknown result type (might be due to invalid IL or missing references)
//IL_0202: 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_0207: Unknown result type (might be due to invalid IL or missing references)
//IL_020f: Unknown result type (might be due to invalid IL or missing references)
//IL_0214: Unknown result type (might be due to invalid IL or missing references)
//IL_0232: Unknown result type (might be due to invalid IL or missing references)
//IL_0237: Unknown result type (might be due to invalid IL or missing references)
//IL_023c: Unknown result type (might be due to invalid IL or missing references)
//IL_025d: Unknown result type (might be due to invalid IL or missing references)
//IL_0262: Unknown result type (might be due to invalid IL or missing references)
//IL_0267: Unknown result type (might be due to invalid IL or missing references)
//IL_0288: Unknown result type (might be due to invalid IL or missing references)
//IL_028d: Unknown result type (might be due to invalid IL or missing references)
//IL_0292: Unknown result type (might be due to invalid IL or missing references)
//IL_02b3: Unknown result type (might be due to invalid IL or missing references)
//IL_02b8: Unknown result type (might be due to invalid IL or missing references)
//IL_02bd: Unknown result type (might be due to invalid IL or missing references)
//IL_0391: Unknown result type (might be due to invalid IL or missing references)
//IL_0396: Unknown result type (might be due to invalid IL or missing references)
//IL_030c: Unknown result type (might be due to invalid IL or missing references)
//IL_02f8: Unknown result type (might be due to invalid IL or missing references)
//IL_02fd: Unknown result type (might be due to invalid IL or missing references)
//IL_0311: Unknown result type (might be due to invalid IL or missing references)
//IL_032e: Unknown result type (might be due to invalid IL or missing references)
//IL_033e: Unknown result type (might be due to invalid IL or missing references)
//IL_034e: Unknown result type (might be due to invalid IL or missing references)
//IL_035e: Unknown result type (might be due to invalid IL or missing references)
//IL_031c: Unknown result type (might be due to invalid IL or missing references)
screenRect = default(Rect);
bool flag = _found && ((Object)(object)_bar == (Object)null || (Object)(object)_canvas == (Object)null);
if (player != _player || flag)
{
_found = false;
_player = player;
_bar = null;
_canvas = null;
Component healthbar = (Component)(object)player.healthbar;
if (healthbar != null && (Object)(object)healthbar != (Object)null)
{
ref RectTransform bar = ref _bar;
Transform transform = healthbar.transform;
bar = (RectTransform)(object)((transform is RectTransform) ? transform : null);
if ((Object)(object)_bar != (Object)null)
{
_canvas = ((Component)_bar).GetComponentInParent<Canvas>(true);
}
}
_found = (Object)(object)_canvas != (Object)null;
if (_found)
{
Plugin.Log.LogInfo((object)$"Health bar: {((Object)_bar).name}, canvas {((Object)_canvas.rootCanvas).name} ({_canvas.rootCanvas.renderMode}), rect {_bar.rect}");
}
else
{
Plugin.Log.LogInfo((object)"Health bar not found for the local player; using the Screen position.");
}
}
if ((Object)(object)_bar == (Object)null || (Object)(object)_canvas == (Object)null)
{
return Result.NotFound;
}
if (!((Component)_bar).gameObject.activeInHierarchy || !((Behaviour)_canvas).isActiveAndEnabled)
{
return Result.Hidden;
}
Canvas rootCanvas = _canvas.rootCanvas;
Camera val = null;
if ((int)rootCanvas.renderMode != 0)
{
val = HudCoordinates.CameraFor(rootCanvas);
if ((Object)(object)val == (Object)null)
{
return Result.NotFound;
}
}
Transform parent = ((Transform)_bar).parent;
Vector3 localScale = ((Transform)_bar).localScale;
Matrix4x4 val2 = Matrix4x4.TRS(((Transform)_bar).localPosition, ((Transform)_bar).localRotation, new Vector3(1f, localScale.y, localScale.z));
Matrix4x4 val3 = (((Object)(object)parent != (Object)null) ? (parent.localToWorldMatrix * val2) : val2);
Rect rect = _bar.rect;
_corners[0] = ((Matrix4x4)(ref val3)).MultiplyPoint3x4(new Vector3(((Rect)(ref rect)).xMin, ((Rect)(ref rect)).yMin, 0f));
_corners[1] = ((Matrix4x4)(ref val3)).MultiplyPoint3x4(new Vector3(((Rect)(ref rect)).xMin, ((Rect)(ref rect)).yMax, 0f));
_corners[2] = ((Matrix4x4)(ref val3)).MultiplyPoint3x4(new Vector3(((Rect)(ref rect)).xMax, ((Rect)(ref rect)).yMax, 0f));
_corners[3] = ((Matrix4x4)(ref val3)).MultiplyPoint3x4(new Vector3(((Rect)(ref rect)).xMax, ((Rect)(ref rect)).yMin, 0f));
float num = float.MaxValue;
float num2 = float.MinValue;
float num3 = float.MaxValue;
float num4 = float.MinValue;
for (int i = 0; i < 4; i++)
{
Vector3 val4 = (((Object)(object)val == (Object)null) ? _corners[i] : val.WorldToScreenPoint(_corners[i]));
if ((Object)(object)val != (Object)null && val4.z < 0f)
{
return Result.Hidden;
}
num = Mathf.Min(num, val4.x);
num2 = Mathf.Max(num2, val4.x);
num3 = Mathf.Min(num3, val4.y);
num4 = Mathf.Max(num4, val4.y);
}
screenRect = Rect.MinMaxRect(num, (float)Screen.height - num4, num2, (float)Screen.height - num3);
return Result.Found;
}
}
internal static class StatDump
{
private const BindingFlags InstanceFields = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic;
public static void Write()
{
//IL_00d6: Unknown result type (might be due to invalid IL or missing references)
//IL_00ee: Unknown result type (might be due to invalid IL or missing references)
Player localPlayer = Player.LocalPlayer;
Player prefab = GetPrefab();
if ((Object)(object)prefab == (Object)null && (Object)(object)localPlayer == (Object)null)
{
Plugin.Log.LogWarning((object)"Stat dump: neither the Player prefab nor the local player is available.");
return;
}
StringBuilder stringBuilder = new StringBuilder();
stringBuilder.AppendLine("# Mycopunk player stats");
stringBuilder.AppendLine();
stringBuilder.AppendLine($"- Time: {DateTime.Now:yyyy-MM-dd HH:mm:ss}");
stringBuilder.AppendLine("- Game version: " + Application.version);
stringBuilder.AppendLine("- Class: " + (((Object)(object)localPlayer != (Object)null) ? DescribeCharacter(localPlayer) : "(no local player)"));
stringBuilder.AppendLine("- base = Player prefab (NetworkConfig.PlayerPrefab), current = local player after upgrades. Rows marked * differ.");
stringBuilder.AppendLine();
AppendTable(stringBuilder, "Player", typeof(Player), prefab, localPlayer);
object baseObj = (((Object)(object)prefab != (Object)null) ? ((object)prefab.upgradeVariables) : null);
object curObj = (((Object)(object)localPlayer != (Object)null) ? ((object)localPlayer.upgradeVariables) : null);
AppendTable(stringBuilder, "Player.upgradeVariables", typeof(UpgradeVariableData), baseObj, curObj);
if ((Object)(object)localPlayer != (Object)null)
{
AppendGear(stringBuilder, localPlayer);
}
string text = Path.Combine(Paths.BepInExRootPath, "HealthNumbers");
Directory.CreateDirectory(text);
string text2 = Path.Combine(text, $"stats-{DateTime.Now:yyyyMMdd-HHmmss}.md");
File.WriteAllText(text2, stringBuilder.ToString().Replace("\r\n", "\n"));
Plugin.Log.LogInfo((object)("Stat dump written to " + text2));
}
private static Player GetPrefab()
{
try
{
GameObject val = ((!((Object)(object)NetworkManager.Singleton != (Object)null)) ? null : NetworkManager.Singleton.NetworkConfig?.PlayerPrefab);
return ((Object)(object)val != (Object)null) ? val.GetComponent<Player>() : null;
}
catch (Exception ex)
{
Plugin.Log.LogWarning((object)("Stat dump: could not read the Player prefab. " + ex.Message));
return null;
}
}
private static string DescribeCharacter(Player player)
{
try
{
object character = player.Character;
Object val = (Object)((character is Object) ? character : null);
if (val != null && val != (Object)null)
{
return val.name;
}
return character?.ToString() ?? "(unknown)";
}
catch
{
return "(unknown)";
}
}
private static void AppendTable(StringBuilder sb, string title, Type type, object baseObj, object curObj)
{
sb.AppendLine("## " + title);
sb.AppendLine();
sb.AppendLine("| Field | Base | Current | |");
sb.AppendLine("|---|---|---|---|");
foreach (FieldInfo item in SerializedSimpleFields(type))
{
string text = ((baseObj != null) ? Format(item.GetValue(baseObj)) : "");
string text2 = ((curObj != null) ? Format(item.GetValue(curObj)) : "");
string text3 = ((baseObj != null && curObj != null && text != text2) ? "*" : "");
sb.AppendLine("| `" + item.Name + "` | " + text + " | " + text2 + " | " + text3 + " |");
}
sb.AppendLine();
}
private static void AppendGear(StringBuilder sb, Player player)
{
IEnumerable gear = player.Gear;
if (gear == null)
{
return;
}
int num = 0;
foreach (object item in gear)
{
int num2 = num++;
if (item != null)
{
Object val = (Object)((item is Object) ? item : null);
if (val == null || !(val == (Object)null))
{
Object val2 = (Object)((item is Object) ? item : null);
string arg = ((val2 != null) ? val2.name : item.ToString());
sb.AppendLine($"## Gear {num2}: {arg} ({item.GetType().Name})");
sb.AppendLine();
sb.AppendLine("| Field | Value |");
sb.AppendLine("|---|---|");
AppendFieldsRecursive(sb, item, item.GetType(), "", 0);
sb.AppendLine();
}
}
}
}
private static void AppendFieldsRecursive(StringBuilder sb, object obj, Type type, string prefix, int depth)
{
Assembly assembly = typeof(Player).Assembly;
List<Type> list = new List<Type>();
Type type2 = type;
while (type2 != null && type2.Assembly == assembly)
{
list.Insert(0, type2);
type2 = type2.BaseType;
}
foreach (Type item in list)
{
FieldInfo[] fields = item.GetFields(BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
foreach (FieldInfo fieldInfo in fields)
{
Type fieldType = fieldInfo.FieldType;
object value;
try
{
value = fieldInfo.GetValue(obj);
}
catch
{
continue;
}
string text = prefix + CleanName(fieldInfo.Name);
if (IsSimple(fieldType))
{
sb.AppendLine("| `" + text + "` | " + Format(value) + " |");
}
else if (depth < 2 && fieldType.IsValueType && !fieldType.IsPrimitive && fieldType.Assembly == assembly && value != null)
{
AppendFieldsRecursive(sb, value, fieldType, text + ".", depth + 1);
}
}
}
}
private static string CleanName(string n)
{
if (n.StartsWith("<") && n.Contains(">"))
{
return n.Substring(1, n.IndexOf('>') - 1);
}
return n;
}
private static IEnumerable<FieldInfo> SerializedSimpleFields(Type type)
{
List<Type> list = new List<Type>();
Type type2 = type;
while (type2 != null && type2.Assembly == type.Assembly)
{
list.Insert(0, type2);
type2 = type2.BaseType;
}
foreach (Type item in list)
{
FieldInfo[] fields = item.GetFields(BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
foreach (FieldInfo fieldInfo in fields)
{
if (((fieldInfo.IsPublic && !fieldInfo.IsNotSerialized) || fieldInfo.IsDefined(typeof(SerializeField), inherit: false)) && IsSimple(fieldInfo.FieldType))
{
yield return fieldInfo;
}
}
}
}
private static bool IsSimple(Type t)
{
if (!(t == typeof(float)) && !(t == typeof(int)) && !(t == typeof(bool)) && !t.IsEnum && !(t == typeof(Vector2)))
{
return t == typeof(Vector3);
}
return true;
}
private static string Format(object v)
{
//IL_001a: Unknown result type (might be due to invalid IL or missing references)
//IL_001f: Unknown result type (might be due to invalid IL or missing references)
//IL_002b: Unknown result type (might be due to invalid IL or missing references)
//IL_0030: Unknown result type (might be due to invalid IL or missing references)
//IL_0060: Unknown result type (might be due to invalid IL or missing references)
//IL_007b: 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_00c5: Unknown result type (might be due to invalid IL or missing references)
//IL_00e0: Unknown result type (might be due to invalid IL or missing references)
if (!(v is float num))
{
if (!(v is Vector2 val))
{
if (!(v is Vector3 val2))
{
if (v == null)
{
return "null";
}
return Convert.ToString(v, CultureInfo.InvariantCulture);
}
return "(" + Format(val2.x) + ", " + Format(val2.y) + ", " + Format(val2.z) + ")";
}
return "(" + Format(val.x) + ", " + Format(val.y) + ")";
}
return num.ToString("0.#####", CultureInfo.InvariantCulture);
}
}
internal sealed class TeammateHealthLabel : MonoBehaviour
{
[HarmonyPatch(typeof(TeammateHUD), "Initialize")]
private static class InitializePatch
{
[HarmonyPostfix]
private static void Postfix(TeammateHUD __instance, Player player)
{
Initialize_Postfix(__instance, player);
}
}
internal const string LineId = "t4t5u0.healthnumbers";
internal const int LineOrder = 50;
private TeammateHUD _hud;
private Player _player;
private TextMeshProUGUI _nameText;
private TextMeshProUGUI _label;
private readonly HealthText _text = new HealthText();
private string _shown;
public static void Install(Harmony harmony)
{
if (!UnityTeammateHud.Available)
{
Plugin.Log.LogWarning((object)"TeammateHUD.Initialize or its fields not found; teammate health numbers are off.");
return;
}
harmony.CreateClassProcessor(typeof(InitializePatch)).Patch();
TeammateHUD[] array = Object.FindObjectsByType<TeammateHUD>((FindObjectsInactive)1);
foreach (TeammateHUD val in array)
{
Player player = val.player;
if (player != null)
{
Initialize_Postfix(val, player);
}
}
}
private static void Initialize_Postfix(TeammateHUD __instance, Player player)
{
try
{
TeammateHealthLabel teammateHealthLabel = ((Component)__instance).GetComponent<TeammateHealthLabel>();
if ((Object)(object)teammateHealthLabel == (Object)null)
{
teammateHealthLabel = ((Component)__instance).gameObject.AddComponent<TeammateHealthLabel>();
}
teammateHealthLabel._hud = __instance;
teammateHealthLabel._player = player;
teammateHealthLabel._nameText = __instance.nameText;
teammateHealthLabel._label = null;
teammateHealthLabel._shown = null;
}
catch (Exception ex)
{
Plugin.Log.LogWarning((object)("Teammate health label could not be created: " + ex));
}
}
private void LateUpdate()
{
//IL_01ac: Unknown result type (might be due to invalid IL or missing references)
//IL_019f: Unknown result type (might be due to invalid IL or missing references)
//IL_01b1: Unknown result type (might be due to invalid IL or missing references)
//IL_01b8: Unknown result type (might be due to invalid IL or missing references)
//IL_01bd: Unknown result type (might be due to invalid IL or missing references)
//IL_01cb: Unknown result type (might be due to invalid IL or missing references)
if ((Object)(object)_hud == (Object)null || (Object)(object)_nameText == (Object)null)
{
return;
}
try
{
Settings settings = Plugin.Settings;
if (settings == null || !settings.Enabled || !settings.Teammates || !((Object)(object)_player != (Object)null))
{
if ((Object)(object)_label != (Object)null)
{
UnityTeammateHud.Remove(_hud, "t4t5u0.healthnumbers");
_label = null;
_shown = null;
}
return;
}
if ((Object)(object)_label == (Object)null)
{
_label = UnityTeammateHud.AddText(_hud, "t4t5u0.healthnumbers", 50);
if ((Object)(object)_label == (Object)null)
{
Plugin.Log.LogWarning((object)"Teammate health line could not be added; teammate health numbers are off for this HUD.");
((Behaviour)this).enabled = false;
return;
}
}
string text = ((settings.HideWhenDead && !_player.IsAlive) ? "" : _text.Get(_player.Health, _player.MaxHealth, 1f, settings.Decimals, settings.Format, ""));
if ((object)text != _shown)
{
_shown = text;
string text2 = ((text.Length == 0) ? "" : ("HP " + text));
if (((TMP_Text)_label).text != text2)
{
((TMP_Text)_label).text = text2;
}
}
float num = ((TMP_Text)_nameText).fontSize * settings.TeammateFontScale;
if (((TMP_Text)_label).fontSize != num)
{
((TMP_Text)_label).fontSize = num;
}
Color val = (settings.TeammateNameColor ? ((Graphic)_nameText).color : settings.Color);
if (((Graphic)_label).color != val)
{
((Graphic)_label).color = val;
}
}
catch (Exception ex)
{
Plugin.Log.LogWarning((object)("Teammate health label failed and is turned off: " + ex));
((Behaviour)this).enabled = false;
}
}
private void OnDestroy()
{
if ((Object)(object)_hud != (Object)null && (Object)(object)_label != (Object)null)
{
UnityTeammateHud.Remove(_hud, "t4t5u0.healthnumbers");
}
}
}
}
namespace System.Runtime.CompilerServices
{
[AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)]
internal sealed class IgnoresAccessChecksToAttribute : Attribute
{
public IgnoresAccessChecksToAttribute(string assemblyName)
{
}
}
}