Decompiled source of Garrys Mod Hear Display v1.0.1

GMHearDisplay.dll

Decompiled 2 days ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using GMHearDisplay.Patches;
using GameNetcodeStuff;
using HarmonyLib;
using LethalConfig.ConfigItems;
using LethalConfig.ConfigItems.Options;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: AssemblyTitle("GMHearDisplay")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("GMHearDisplay")]
[assembly: AssemblyCopyright("Copyright ©  2026")]
[assembly: AssemblyTrademark("")]
[assembly: ComVisible(false)]
[assembly: Guid("be13cb0f-c894-4d78-b9c2-2c9bb103c566")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")]
[assembly: AssemblyVersion("1.0.0.0")]
namespace GMHearDisplay
{
	[BepInPlugin("dev.closeraven783.gmheardisplay", "GM Hear Display", "1.0.1")]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	public class GMHearDisplayMain : BaseUnityPlugin
	{
		internal static class PluginInfo
		{
			public const string GUID = "dev.closeraven783.gmheardisplay";

			public const string NAME = "GM Hear Display";

			public const string VERSION = "1.0.1";
		}

		internal static ManualLogSource Log;

		private readonly Harmony _harmony = new Harmony("dev.closeraven783.gmheardisplay");

		private static GMHearDisplayMain Instance;

		public static ConfigEntry<bool> ShowVoiceUI { get; private set; }

		public static ConfigEntry<float> MaxDistance { get; private set; }

		public static ConfigEntry<float> BarelyHearThreshold { get; private set; }

		public static ConfigEntry<string> TextColor { get; private set; }

		private void Awake()
		{
			//IL_0046: Unknown result type (might be due to invalid IL or missing references)
			//IL_004c: Expected O, but got Unknown
			if ((Object)(object)Instance == (Object)null)
			{
				Instance = this;
			}
			Log = ((BaseUnityPlugin)this).Logger;
			SetupBaseConfig();
			SetupLethalConfig();
			Log.LogInfo((object)"Plugin [dev.closeraven783.gmheardisplay (GM Hear Display) v1.0.1] is loaded!");
			GameObject val = new GameObject("GMHearDisplay");
			Object.DontDestroyOnLoad((Object)(object)val);
			((Object)val).hideFlags = (HideFlags)61;
			val.AddComponent<VoiceDisplayRunner>();
		}

		private void SetupBaseConfig()
		{
			//IL_0050: Unknown result type (might be due to invalid IL or missing references)
			//IL_005a: Expected O, but got Unknown
			//IL_008e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0098: Expected O, but got Unknown
			ShowVoiceUI = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "Show Voice UI", true, "Enable or disable the voice UI display");
			MaxDistance = ((BaseUnityPlugin)this).Config.Bind<float>("Distances", "Max Distance", 45f, new ConfigDescription("Maximum distance players can (probably) hear you normally", (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 100f), Array.Empty<object>()));
			BarelyHearThreshold = ((BaseUnityPlugin)this).Config.Bind<float>("Distances", "Barely Hear Threshold", 47f, new ConfigDescription("Distance threshold for barely hearing", (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 120f), Array.Empty<object>()));
			TextColor = ((BaseUnityPlugin)this).Config.Bind<string>("UI", "Text Color", "#FFFFFF", "Hex color of the UI text (e.g., #FF0000 for red)");
		}

		private void SetupLethalConfig()
		{
			try
			{
				Type type = Type.GetType("LethalConfig.LethalConfigManager, LethalConfig");
				if (type != null)
				{
					Log.LogInfo((object)"LethalConfig found, adding config entries...");
					AddLethalConfigEntries(type);
				}
			}
			catch (Exception ex)
			{
				Log.LogWarning((object)("Could not initialize LethalConfig: " + ex.Message));
			}
		}

		private void AddLethalConfigEntries(Type lethalConfigManager)
		{
			//IL_00c1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c7: Expected O, but got Unknown
			//IL_00cc: 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_00d9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e4: Expected O, but got Unknown
			//IL_00e5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f0: Expected O, but got Unknown
			//IL_00f6: Expected O, but got Unknown
			//IL_00f1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f8: Expected O, but got Unknown
			//IL_00fd: Unknown result type (might be due to invalid IL or missing references)
			//IL_0102: Unknown result type (might be due to invalid IL or missing references)
			//IL_010a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0115: Expected O, but got Unknown
			//IL_0116: Unknown result type (might be due to invalid IL or missing references)
			//IL_0121: Expected O, but got Unknown
			//IL_0127: Expected O, but got Unknown
			//IL_0122: Unknown result type (might be due to invalid IL or missing references)
			//IL_0129: Expected O, but got Unknown
			//IL_012f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0136: Expected O, but got Unknown
			try
			{
				Assembly assembly = null;
				Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies();
				foreach (Assembly assembly2 in assemblies)
				{
					if (assembly2.GetName().Name == "LethalConfig")
					{
						assembly = assembly2;
						break;
					}
				}
				if (assembly == null)
				{
					Log.LogError((object)"Could not find LethalConfig assembly!");
					return;
				}
				Type type = assembly.GetType("LethalConfig.ConfigItems.BaseConfigItem");
				if (type == null)
				{
					Log.LogError((object)"Could not find BaseConfigItem type!");
					return;
				}
				MethodInfo method = lethalConfigManager.GetMethod("AddConfigItem", BindingFlags.Static | BindingFlags.Public, null, new Type[1] { type }, null);
				BoolCheckBoxConfigItem val = new BoolCheckBoxConfigItem(ShowVoiceUI, false);
				ConfigEntry<float> maxDistance = MaxDistance;
				FloatSliderOptions val2 = new FloatSliderOptions
				{
					RequiresRestart = false
				};
				((BaseRangeOptions<float>)val2).Min = 0f;
				((BaseRangeOptions<float>)val2).Max = 100f;
				FloatSliderConfigItem val3 = new FloatSliderConfigItem(maxDistance, val2);
				ConfigEntry<float> barelyHearThreshold = BarelyHearThreshold;
				FloatSliderOptions val4 = new FloatSliderOptions
				{
					RequiresRestart = false
				};
				((BaseRangeOptions<float>)val4).Min = 100f;
				((BaseRangeOptions<float>)val4).Max = 120f;
				FloatSliderConfigItem val5 = new FloatSliderConfigItem(barelyHearThreshold, val4);
				HexColorInputFieldConfigItem val6 = new HexColorInputFieldConfigItem(TextColor, false);
				Log.LogInfo((object)"LethalConfig entires added");
			}
			catch (Exception arg)
			{
				Log.LogError((object)$"Failed to add LethalConfig entries: {arg}");
			}
		}
	}
}
namespace GMHearDisplay.Patches
{
	public class VoiceDisplayUI
	{
		private static readonly Dictionary<PlayerControllerB, AudioSource> playerVoiceAudios = new Dictionary<PlayerControllerB, AudioSource>();

		private static PlayerControllerB localPlayer;

		private static AudioSource localVoiceAudio;

		private static float nextSearchTime = 0f;

		private static Texture2D voiceIconTexture;

		private static Color ParseHexColor(string hex)
		{
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			//IL_000e: 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)
			Color result = default(Color);
			if (ColorUtility.TryParseHtmlString(hex, ref result))
			{
				return result;
			}
			return Color.white;
		}

		public static void LoadVoiceIcon()
		{
			//IL_009c: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a6: Expected O, but got Unknown
			try
			{
				string directoryName = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
				string text = Path.Combine(directoryName, "Assets", "voice_icon.png");
				if (!File.Exists(text))
				{
					text = Path.Combine(directoryName, "voice_icon.png");
					if (!File.Exists(text))
					{
						GMHearDisplayMain.Log.LogError((object)("Voice icon not found at either:\n" + Path.Combine(directoryName, "Assets", "voice_icon.png") + "\nor\n" + text));
						return;
					}
					GMHearDisplayMain.Log.LogInfo((object)("Voice icon found at root: " + text));
				}
				byte[] array = File.ReadAllBytes(text);
				voiceIconTexture = new Texture2D(3, 2);
				if (ImageConversion.LoadImage(voiceIconTexture, array))
				{
					((Texture)voiceIconTexture).filterMode = (FilterMode)0;
				}
				else
				{
					GMHearDisplayMain.Log.LogError((object)"Failed to load image data into texture");
				}
			}
			catch (Exception arg)
			{
				GMHearDisplayMain.Log.LogError((object)$"Failed to load voice icon: {arg}");
			}
		}

		private static void UpdateVoiceInfo()
		{
			if (Time.time < nextSearchTime)
			{
				return;
			}
			nextSearchTime = Time.time + 1.5f;
			playerVoiceAudios.Clear();
			PlayerControllerB[] array = Object.FindObjectsOfType<PlayerControllerB>();
			localPlayer = StartOfRound.Instance?.localPlayerController;
			PlayerControllerB[] array2 = array;
			foreach (PlayerControllerB val in array2)
			{
				if ((Object)(object)val == (Object)null)
				{
					continue;
				}
				AudioSource[] componentsInChildren = ((Component)val).GetComponentsInChildren<AudioSource>();
				AudioSource[] array3 = componentsInChildren;
				foreach (AudioSource val2 in array3)
				{
					if ((Object)(object)val2 != (Object)null && val2.spatialBlend > 0.5f)
					{
						playerVoiceAudios[val] = val2;
						if ((Object)(object)val == (Object)(object)localPlayer)
						{
							localVoiceAudio = val2;
						}
						break;
					}
				}
			}
		}

		public static void OnGUI()
		{
			//IL_00c6: 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_00d5: Expected O, but got Unknown
			//IL_00f0: 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_0106: Unknown result type (might be due to invalid IL or missing references)
			//IL_0137: Unknown result type (might be due to invalid IL or missing references)
			//IL_013c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0071: Unknown result type (might be due to invalid IL or missing references)
			//IL_0076: Unknown result type (might be due to invalid IL or missing references)
			//IL_0081: Expected O, but got Unknown
			//IL_0095: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a6: Unknown result type (might be due to invalid IL or missing references)
			//IL_019b: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a0: Unknown result type (might be due to invalid IL or missing references)
			//IL_0440: Unknown result type (might be due to invalid IL or missing references)
			//IL_041e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0429: 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)
			//IL_01e3: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e8: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f2: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f7: Unknown result type (might be due to invalid IL or missing references)
			//IL_027c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0281: Unknown result type (might be due to invalid IL or missing references)
			//IL_028c: Expected O, but got Unknown
			//IL_02aa: Unknown result type (might be due to invalid IL or missing references)
			//IL_02b0: Unknown result type (might be due to invalid IL or missing references)
			//IL_02b2: Unknown result type (might be due to invalid IL or missing references)
			//IL_0240: Unknown result type (might be due to invalid IL or missing references)
			//IL_036b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0372: Expected O, but got Unknown
			//IL_03a0: Unknown result type (might be due to invalid IL or missing references)
			//IL_03a6: Unknown result type (might be due to invalid IL or missing references)
			//IL_03ba: Unknown result type (might be due to invalid IL or missing references)
			//IL_032f: Unknown result type (might be due to invalid IL or missing references)
			if (!GMHearDisplayMain.ShowVoiceUI.Value)
			{
				return;
			}
			UpdateVoiceInfo();
			if ((Object)(object)localPlayer != (Object)null && localPlayer.isPlayerDead)
			{
				return;
			}
			if ((Object)(object)localPlayer == (Object)null || (Object)(object)localVoiceAudio == (Object)null)
			{
				GUIStyle style = new GUIStyle(GUI.skin.label)
				{
					fontSize = 16
				};
				DrawTextWithStroke(new Rect(20f, 20f, 250f, 30f), "waiting for voice :3", style, Color.white, Color.black, 1f);
				return;
			}
			GUIStyle style2 = new GUIStyle(GUI.skin.label)
			{
				fontSize = 20
			};
			Rect rect = default(Rect);
			((Rect)(ref rect))..ctor(20f, 500f, 300f, 50f);
			DrawTextWithStroke(rect, "Who can hear you:", style2, ParseHexColor(GMHearDisplayMain.TextColor.Value), Color.black, 1.5f);
			float value = GMHearDisplayMain.MaxDistance.Value;
			float value2 = GMHearDisplayMain.BarelyHearThreshold.Value;
			Vector3 position = ((Component)localPlayer).transform.position;
			float num = 550f;
			bool flag = false;
			bool flag2 = false;
			Rect val = default(Rect);
			Rect rect2 = default(Rect);
			Rect val2 = default(Rect);
			Rect rect3 = default(Rect);
			foreach (KeyValuePair<PlayerControllerB, AudioSource> playerVoiceAudio in playerVoiceAudios)
			{
				PlayerControllerB key = playerVoiceAudio.Key;
				if ((Object)(object)key == (Object)null || (Object)(object)key == (Object)(object)localPlayer)
				{
					continue;
				}
				float num2 = Vector3.Distance(((Component)key).transform.position, position);
				bool flag3 = key.voicePlayerState != null && key.voicePlayerState.IsSpeaking;
				if (num2 <= value)
				{
					flag = true;
					float num3 = Mathf.Clamp01(num2 / value);
					Color textColor = Color.Lerp(Color.green, Color.red, num3 * num3);
					float num4 = 0f;
					if (flag3 && (Object)(object)voiceIconTexture != (Object)null)
					{
						float num5 = 24f;
						float num6 = 20f;
						float num7 = num + 5f;
						((Rect)(ref val))..ctor(num6, num7, num5, num5);
						GUI.DrawTexture(val, (Texture)(object)voiceIconTexture);
						num4 = num5 + 5f;
					}
					string text = $"{key.playerUsername} ({num2:F1}m)";
					GUIStyle style3 = new GUIStyle(GUI.skin.label)
					{
						fontSize = 18
					};
					((Rect)(ref rect2))..ctor(20f + num4, num, 300f - num4, 35f);
					DrawTextWithStroke(rect2, text, style3, textColor, Color.black, 1f, eightWayStroke: true);
					num += 35f;
				}
				else if (num2 <= value2)
				{
					flag2 = true;
					float num8 = 0f;
					if (flag3 && (Object)(object)voiceIconTexture != (Object)null)
					{
						float num9 = 24f;
						float num10 = 20f;
						float num11 = num + 7f;
						((Rect)(ref val2))..ctor(num10, num11, num9, num9);
						GUI.DrawTexture(val2, (Texture)(object)voiceIconTexture);
						num8 = num9 + 5f;
					}
					string text2 = $"{key.playerUsername} might be barely hearing you ({num2:F1}m)";
					GUIStyle val3 = new GUIStyle(GUI.skin.label);
					val3.fontSize = 18;
					((Rect)(ref rect3))..ctor(20f + num8, num + 2f, 300f - num8, 30f);
					DrawTextWithStroke(rect3, text2, val3, Color.yellow, new Color(0.2f, 0.2f, 0f));
					num += 35f;
				}
			}
			if (!flag && !flag2)
			{
				DrawTextWithStroke(new Rect(20f, num + 3f, 300f, 25f), "No one", style2, Color.gray, Color.black, 1f);
			}
			GUI.color = Color.white;
		}

		private static void DrawTextWithStroke(Rect rect, string text, GUIStyle style, Color textColor, Color strokeColor, float strokeThickness = 2f, bool eightWayStroke = false)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: 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)
			//IL_00f8: Unknown result type (might be due to invalid IL or missing references)
			//IL_0128: Unknown result type (might be due to invalid IL or missing references)
			//IL_0158: Unknown result type (might be due to invalid IL or missing references)
			//IL_0163: Unknown result type (might be due to invalid IL or missing references)
			//IL_016a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0173: Unknown result type (might be due to invalid IL or missing references)
			//IL_0069: Unknown result type (might be due to invalid IL or missing references)
			Color color = GUI.color;
			GUI.color = strokeColor;
			if (eightWayStroke)
			{
				Rect val = default(Rect);
				for (float num = 0f - strokeThickness; num <= strokeThickness; num += strokeThickness)
				{
					for (float num2 = 0f - strokeThickness; num2 <= strokeThickness; num2 += strokeThickness)
					{
						if (num != 0f || num2 != 0f)
						{
							((Rect)(ref val))..ctor(((Rect)(ref rect)).x + num, ((Rect)(ref rect)).y + num2, ((Rect)(ref rect)).width, ((Rect)(ref rect)).height);
							GUI.Label(val, text, style);
						}
					}
				}
			}
			else
			{
				Rect val2 = default(Rect);
				((Rect)(ref val2))..ctor(((Rect)(ref rect)).x - strokeThickness, ((Rect)(ref rect)).y, ((Rect)(ref rect)).width, ((Rect)(ref rect)).height);
				GUI.Label(val2, text, style);
				((Rect)(ref val2))..ctor(((Rect)(ref rect)).x + strokeThickness, ((Rect)(ref rect)).y, ((Rect)(ref rect)).width, ((Rect)(ref rect)).height);
				GUI.Label(val2, text, style);
				((Rect)(ref val2))..ctor(((Rect)(ref rect)).x, ((Rect)(ref rect)).y - strokeThickness, ((Rect)(ref rect)).width, ((Rect)(ref rect)).height);
				GUI.Label(val2, text, style);
				((Rect)(ref val2))..ctor(((Rect)(ref rect)).x, ((Rect)(ref rect)).y + strokeThickness, ((Rect)(ref rect)).width, ((Rect)(ref rect)).height);
				GUI.Label(val2, text, style);
			}
			GUI.color = textColor;
			GUI.Label(rect, text, style);
			GUI.color = color;
		}
	}
	public class VoiceDisplayRunner : MonoBehaviour
	{
		private void Start()
		{
			VoiceDisplayUI.LoadVoiceIcon();
		}

		private void OnGUI()
		{
			VoiceDisplayUI.OnGUI();
		}
	}
}