Decompiled source of Teammate HUD v1.0.0

plugins/TeammateHUD.dll

Decompiled 8 hours ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Configuration;
using Microsoft.CodeAnalysis;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("TeammateHUD")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0")]
[assembly: AssemblyProduct("TeammateHUD")]
[assembly: AssemblyTitle("TeammateHUD")]
[assembly: AssemblyVersion("1.0.0.0")]
[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 Codex.TeammateHUD
{
	[BepInPlugin("codex.teammatehud", "Teammate HUD", "1.0.0")]
	public sealed class TeammateHUDPlugin : BaseUnityPlugin
	{
		private sealed class TeammateInfo
		{
			public string Name;

			public float Distance;

			public bool Downed;

			public bool HasHealth;

			public float Health;

			public float MaxHealth;

			public bool HasEnergy;

			public float Energy;

			public float MaxEnergy;
		}

		private readonly List<TeammateInfo> _visibleTeammates = new List<TeammateInfo>();

		private ConfigEntry<bool> _enabled;

		private ConfigEntry<KeyCode> _toggleKey;

		private ConfigEntry<float> _maxDistance;

		private ConfigEntry<int> _maxTeammates;

		private Texture2D _pixel;

		private GUIStyle _titleStyle;

		private GUIStyle _nameStyle;

		private GUIStyle _detailStyle;

		private float _nextRefresh;

		private void Awake()
		{
			//IL_0075: Unknown result type (might be due to invalid IL or missing references)
			//IL_007f: Expected O, but got Unknown
			//IL_00a7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b1: Expected O, but got Unknown
			//IL_00bb: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c5: Expected O, but got Unknown
			//IL_00cd: Unknown result type (might be due to invalid IL or missing references)
			_enabled = ((BaseUnityPlugin)this).Config.Bind<bool>("HUD", "Enabled", true, "Show nearby teammate status cards.");
			_toggleKey = ((BaseUnityPlugin)this).Config.Bind<KeyCode>("HUD", "ToggleKey", (KeyCode)291, "Show or hide the teammate HUD.");
			_maxDistance = ((BaseUnityPlugin)this).Config.Bind<float>("HUD", "MaxDistance", 24f, new ConfigDescription("Only show teammates within this distance.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(5f, 60f), Array.Empty<object>()));
			_maxTeammates = ((BaseUnityPlugin)this).Config.Bind<int>("HUD", "MaxTeammates", 4, new ConfigDescription("Maximum number of teammate cards.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 8), Array.Empty<object>()));
			_pixel = new Texture2D(1, 1, (TextureFormat)4, false);
			_pixel.SetPixel(0, 0, Color.white);
			_pixel.Apply();
			((BaseUnityPlugin)this).Logger.LogInfo((object)"Teammate HUD loaded. Press F10 to show or hide the status panel.");
		}

		private void Update()
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			if (Input.GetKeyDown(_toggleKey.Value))
			{
				_enabled.Value = !_enabled.Value;
			}
			if (_enabled.Value && !(Time.unscaledTime < _nextRefresh))
			{
				_nextRefresh = Time.unscaledTime + 0.25f;
				RefreshVisibleTeammates();
			}
		}

		private void RefreshVisibleTeammates()
		{
			//IL_006e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0073: Unknown result type (might be due to invalid IL or missing references)
			//IL_007d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0082: 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_008f: Unknown result type (might be due to invalid IL or missing references)
			//IL_009b: 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_00bc: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00df: 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)
			//IL_00fc: Unknown result type (might be due to invalid IL or missing references)
			//IL_0111: Unknown result type (might be due to invalid IL or missing references)
			//IL_0116: Unknown result type (might be due to invalid IL or missing references)
			_visibleTeammates.Clear();
			PlayerAvatar val = SemiFunc.PlayerGetLocal();
			Camera main = Camera.main;
			if ((Object)(object)val == (Object)null || (Object)(object)main == (Object)null)
			{
				return;
			}
			PlayerAvatar[] array = Object.FindObjectsOfType<PlayerAvatar>();
			foreach (PlayerAvatar val2 in array)
			{
				if ((Object)(object)val2 == (Object)null || (Object)(object)val2 == (Object)(object)val || !((Component)val2).gameObject.activeInHierarchy)
				{
					continue;
				}
				Vector3 val3 = ((Component)val2).transform.position + Vector3.up * 0.85f;
				float num = Vector3.Distance(((Component)val).transform.position, ((Component)val2).transform.position);
				if (!(num > _maxDistance.Value))
				{
					Vector3 val4 = main.WorldToScreenPoint(val3);
					if (!(val4.z <= 0f) && !(val4.x < 0f) && !(val4.x > (float)Screen.width) && !(val4.y < 0f) && !(val4.y > (float)Screen.height) && HasLineOfSight(((Component)main).transform.position, val3, ((Component)val).transform, ((Component)val2).transform))
					{
						TeammateInfo item = ReadTeammate(val2, num);
						_visibleTeammates.Add(item);
					}
				}
			}
			_visibleTeammates.Sort((TeammateInfo a, TeammateInfo b) => a.Distance.CompareTo(b.Distance));
			if (_visibleTeammates.Count > _maxTeammates.Value)
			{
				_visibleTeammates.RemoveRange(_maxTeammates.Value, _visibleTeammates.Count - _maxTeammates.Value);
			}
		}

		private static bool HasLineOfSight(Vector3 origin, Vector3 target, Transform localTransform, Transform teammateTransform)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_001a: 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_001d: Unknown result type (might be due to invalid IL or missing references)
			Vector3 val = target - origin;
			float magnitude = ((Vector3)(ref val)).magnitude;
			if (magnitude <= 0.01f)
			{
				return true;
			}
			RaycastHit[] array = Physics.RaycastAll(origin, val / magnitude, magnitude, -5, (QueryTriggerInteraction)1);
			Array.Sort(array, (RaycastHit a, RaycastHit b) => ((RaycastHit)(ref a)).distance.CompareTo(((RaycastHit)(ref b)).distance));
			for (int num = 0; num < array.Length; num++)
			{
				Transform transform = ((RaycastHit)(ref array[num])).transform;
				if (!((Object)(object)transform == (Object)null) && !((Object)(object)transform == (Object)(object)localTransform) && !transform.IsChildOf(localTransform))
				{
					if (!((Object)(object)transform == (Object)(object)teammateTransform))
					{
						return transform.IsChildOf(teammateTransform);
					}
					return true;
				}
			}
			return true;
		}

		private static TeammateInfo ReadTeammate(PlayerAvatar player, float distance)
		{
			Component[] componentsInChildren = ((Component)player).GetComponentsInChildren<Component>(true);
			TeammateInfo teammateInfo = new TeammateInfo();
			teammateInfo.Name = ReadString(componentsInChildren, new string[5] { "playername", "displayname", "nickname", "username", "steamname" }) ?? "Teammate";
			teammateInfo.Distance = distance;
			TeammateInfo teammateInfo2 = teammateInfo;
			teammateInfo2.HasHealth = TryReadNumber(componentsInChildren, new string[4] { "syncedhealth", "playerhealthvalue", "currenthealth", "health" }, out teammateInfo2.Health);
			teammateInfo2.HasHealth = teammateInfo2.HasHealth && TryReadNumber(componentsInChildren, new string[1] { "maxhealth" }, out teammateInfo2.MaxHealth);
			if (teammateInfo2.HasHealth && teammateInfo2.MaxHealth <= 0f)
			{
				teammateInfo2.HasHealth = false;
			}
			bool flag = TryReadNumber(componentsInChildren, new string[4] { "energycurrent", "currentenergy", "stamina", "energy" }, out teammateInfo2.Energy);
			bool flag2 = TryReadNumber(componentsInChildren, new string[3] { "maxenergy", "maxstamina", "energymax" }, out teammateInfo2.MaxEnergy);
			teammateInfo2.HasEnergy = flag && flag2 && teammateInfo2.MaxEnergy > 0f;
			if (TryReadBoolean(componentsInChildren, new string[5] { "isdead", "dead", "isdowned", "downed", "playerdead" }, out var result))
			{
				teammateInfo2.Downed = result;
			}
			if (teammateInfo2.HasHealth && teammateInfo2.Health <= 0f)
			{
				teammateInfo2.Downed = true;
			}
			return teammateInfo2;
		}

		private static string ReadString(Component[] components, string[] names)
		{
			foreach (Component val in components)
			{
				if ((Object)(object)val == (Object)null)
				{
					continue;
				}
				foreach (MemberInfo member in GetMembers(((object)val).GetType()))
				{
					if (Matches(member.Name, names))
					{
						string text = ReadMember(val, member) as string;
						if (!string.IsNullOrWhiteSpace(text))
						{
							return text;
						}
					}
				}
			}
			return null;
		}

		private static bool TryReadNumber(Component[] components, string[] names, out float result)
		{
			foreach (Component val in components)
			{
				if ((Object)(object)val == (Object)null)
				{
					continue;
				}
				foreach (MemberInfo member in GetMembers(((object)val).GetType()))
				{
					if (!Matches(member.Name, names))
					{
						continue;
					}
					object obj = ReadMember(val, member);
					if (obj == null)
					{
						continue;
					}
					try
					{
						if (obj is float || obj is double || obj is int || obj is short || obj is long || obj is byte)
						{
							result = Convert.ToSingle(obj);
							return true;
						}
					}
					catch
					{
					}
				}
			}
			result = 0f;
			return false;
		}

		private static bool TryReadBoolean(Component[] components, string[] names, out bool result)
		{
			foreach (Component val in components)
			{
				if ((Object)(object)val == (Object)null)
				{
					continue;
				}
				foreach (MemberInfo member in GetMembers(((object)val).GetType()))
				{
					if (Matches(member.Name, names))
					{
						object obj = ReadMember(val, member);
						if (obj is bool)
						{
							result = (bool)obj;
							return true;
						}
					}
				}
			}
			result = false;
			return false;
		}

		private static List<MemberInfo> GetMembers(Type type)
		{
			List<MemberInfo> list = new List<MemberInfo>();
			Type type2 = type;
			while (type2 != null)
			{
				list.AddRange(type2.GetFields(BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic));
				PropertyInfo[] properties = type2.GetProperties(BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
				foreach (PropertyInfo propertyInfo in properties)
				{
					if (propertyInfo.GetIndexParameters().Length == 0 && propertyInfo.CanRead)
					{
						list.Add(propertyInfo);
					}
				}
				type2 = type2.BaseType;
			}
			return list;
		}

		private static object ReadMember(object target, MemberInfo member)
		{
			try
			{
				FieldInfo fieldInfo = member as FieldInfo;
				if (fieldInfo != null)
				{
					return fieldInfo.GetValue(target);
				}
				PropertyInfo propertyInfo = member as PropertyInfo;
				if (propertyInfo != null)
				{
					return propertyInfo.GetValue(target, null);
				}
			}
			catch
			{
			}
			return null;
		}

		private static bool Matches(string name, string[] hints)
		{
			string text = name.Replace("_", string.Empty).ToLowerInvariant();
			for (int i = 0; i < hints.Length; i++)
			{
				if (text == hints[i] || text.EndsWith(hints[i]))
				{
					return true;
				}
			}
			return false;
		}

		private void OnGUI()
		{
			//IL_0056: Unknown result type (might be due to invalid IL or missing references)
			//IL_006b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0090: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c7: 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_0112: Unknown result type (might be due to invalid IL or missing references)
			if (_enabled.Value && _visibleTeammates.Count != 0)
			{
				EnsureStyles();
				float num = 300f;
				float num2 = 64f;
				float num3 = 38f + num2 * (float)_visibleTeammates.Count;
				Rect rect = default(Rect);
				((Rect)(ref rect))..ctor(16f, 16f, num, num3);
				DrawRect(rect, new Color(0.025f, 0.035f, 0.045f, 0.88f));
				DrawRect(new Rect(((Rect)(ref rect)).x, ((Rect)(ref rect)).y, ((Rect)(ref rect)).width, 3f), new Color(0.38f, 0.92f, 0.74f, 1f));
				GUI.color = new Color(0.73f, 0.9f, 0.91f, 1f);
				GUI.Label(new Rect(((Rect)(ref rect)).x + 12f, ((Rect)(ref rect)).y + 8f, ((Rect)(ref rect)).width - 24f, 22f), "TEAM STATUS   ·   F10 TOGGLE", _titleStyle);
				GUI.color = Color.white;
				for (int i = 0; i < _visibleTeammates.Count; i++)
				{
					DrawTeammate(((Rect)(ref rect)).x + 10f, ((Rect)(ref rect)).y + 34f + num2 * (float)i, _visibleTeammates[i]);
				}
			}
		}

		private void DrawTeammate(float x, float y, TeammateInfo info)
		{
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0026: 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_0052: Unknown result type (might be due to invalid IL or missing references)
			//IL_007c: Unknown result type (might be due to invalid IL or missing references)
			//IL_009e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0119: Unknown result type (might be due to invalid IL or missing references)
			//IL_015d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0167: Unknown result type (might be due to invalid IL or missing references)
			DrawRect(new Rect(x, y, 280f, 58f), new Color(0.07f, 0.09f, 0.11f, 0.88f));
			GUI.color = Color.white;
			GUI.Label(new Rect(x + 9f, y + 4f, 158f, 20f), info.Name, _nameStyle);
			GUI.color = new Color(0.68f, 0.77f, 0.81f, 1f);
			GUI.Label(new Rect(x + 167f, y + 5f, 104f, 18f), Mathf.RoundToInt(info.Distance) + " m  ·  " + (info.Downed ? "DOWN" : "ACTIVE"), _detailStyle);
			DrawStat(x + 9f, y + 29f, "HP", info.HasHealth, info.Health, info.MaxHealth, new Color(0.35f, 0.86f, 0.57f, 1f));
			DrawStat(x + 145f, y + 29f, "STA", info.HasEnergy, info.Energy, info.MaxEnergy, new Color(0.35f, 0.72f, 1f, 1f));
			GUI.color = Color.white;
		}

		private void DrawStat(float x, float y, string label, bool available, float value, float maximum, Color color)
		{
			//IL_0055: 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_0068: Unknown result type (might be due to invalid IL or missing references)
			//IL_008b: Unknown result type (might be due to invalid IL or missing references)
			//IL_010c: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b9: 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_0100: Unknown result type (might be due to invalid IL or missing references)
			//IL_0105: Unknown result type (might be due to invalid IL or missing references)
			string text = (available ? (Mathf.Clamp(Mathf.RoundToInt(value / maximum * 100f), 0, 100) + "%") : "—");
			GUI.color = (Color)(available ? color : new Color(0.55f, 0.58f, 0.6f, 1f));
			GUI.Label(new Rect(x, y, 43f, 18f), label, _detailStyle);
			GUI.Label(new Rect(x + 43f, y, 42f, 18f), text, _detailStyle);
			if (available)
			{
				DrawRect(new Rect(x + 86f, y + 5f, 42f, 7f), new Color(0.18f, 0.21f, 0.23f, 1f));
				DrawRect(new Rect(x + 86f, y + 5f, 42f * Mathf.Clamp01(value / maximum), 7f), color);
			}
			GUI.color = Color.white;
		}

		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_0021: Unknown result type (might be due to invalid IL or missing references)
			//IL_0028: Unknown result type (might be due to invalid IL or missing references)
			//IL_0034: Expected O, but got Unknown
			//IL_003f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0044: Unknown result type (might be due to invalid IL or missing references)
			//IL_004c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0053: 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_0066: Expected O, but got Unknown
			//IL_0071: Unknown result type (might be due to invalid IL or missing references)
			//IL_0076: 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_0085: Unknown result type (might be due to invalid IL or missing references)
			//IL_008c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0098: Expected O, but got Unknown
			if (_titleStyle == null)
			{
				_titleStyle = new GUIStyle(GUI.skin.label)
				{
					fontSize = 11,
					fontStyle = (FontStyle)1,
					alignment = (TextAnchor)3
				};
				_nameStyle = new GUIStyle(GUI.skin.label)
				{
					fontSize = 14,
					fontStyle = (FontStyle)1,
					alignment = (TextAnchor)3,
					clipping = (TextClipping)1
				};
				_detailStyle = new GUIStyle(GUI.skin.label)
				{
					fontSize = 11,
					fontStyle = (FontStyle)1,
					alignment = (TextAnchor)3,
					clipping = (TextClipping)1
				};
			}
		}

		private void DrawRect(Rect rect, Color color)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			Color color2 = GUI.color;
			GUI.color = color;
			GUI.DrawTexture(rect, (Texture)(object)_pixel);
			GUI.color = color2;
		}

		private void OnDestroy()
		{
			if ((Object)(object)_pixel != (Object)null)
			{
				Object.Destroy((Object)(object)_pixel);
			}
		}
	}
}