Decompiled source of KikisAudioMenu v1.2.2

plugins/KikisAudioMenu.dll

Decompiled a week ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Text;
using System.Text.RegularExpressions;
using BepInEx;
using BepInEx.Bootstrap;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using Photon.Pun;
using Photon.Realtime;
using TMPro;
using UnityEngine;
using UnityEngine.UI;

[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("KikisAudioMenu")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.2.2.0")]
[assembly: AssemblyInformationalVersion("1.2.2")]
[assembly: AssemblyProduct("KikisAudioMenu")]
[assembly: AssemblyTitle("KikisAudioMenu")]
[assembly: AssemblyVersion("1.2.2.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 KAM
{
	[BepInPlugin("kikisaudiomenu.peak.kam", "Kikis Audio Menu", "1.2.2")]
	public class Plugin : BaseUnityPlugin
	{
		public const string GUID = "kikisaudiomenu.peak.kam";

		public const string NAME = "Kikis Audio Menu";

		public const string VERSION = "1.2.2";

		internal static ManualLogSource Log;

		internal static ConfigEntry<float> Spacing;

		internal static ConfigEntry<bool> SpeakingColors;

		internal static ConfigEntry<bool> OverheadIconColors;

		private void Awake()
		{
			//IL_0074: Unknown result type (might be due to invalid IL or missing references)
			Log = ((BaseUnityPlugin)this).Logger;
			Spacing = ((BaseUnityPlugin)this).Config.Bind<float>("General", "Spacing", 80f, "Vertical distance between two player rows in the audio menu (UI units, 1080p reference). 0 = keep the game's own layout.");
			SpeakingColors = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "SpeakingColors", true, "Color a player's name in the audio menu while they talk: green = quiet, yellow = medium, red = loud. Off = game colors only.");
			OverheadIconColors = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "OverheadIconColors", true, "Color the small speaker icon next to a player's name above their head while they talk: green = quiet, yellow = medium, red = loud.");
			try
			{
				new Harmony("kikisaudiomenu.peak.kam").PatchAll(typeof(Plugin).Assembly);
				bool flag = HasPostfix(AccessTools.Method(typeof(AudioLevels), "Update", (Type[])null, (Type[])null));
				bool flag2 = HasPostfix(AccessTools.Method(typeof(UIPlayerNames), "UpdateName", (Type[])null, (Type[])null));
				string text = "(spacing " + Spacing.Value.ToString("0.#") + ", speaking colors " + (SpeakingColors.Value ? "on" : "off") + ", overhead icon colors " + (OverheadIconColors.Value ? "on" : "off") + ")";
				if (flag && flag2)
				{
					Log.LogInfo((object)("[KAM] Kikis Audio Menu 1.2.2 loaded - 2 of 2 hooks ok " + text));
					return;
				}
				Log.LogError((object)("[KAM] Kikis Audio Menu 1.2.2: hooks MISSING - AudioLevels.Update " + (flag ? "ok" : "MISSING") + ", UIPlayerNames.UpdateName " + (flag2 ? "ok" : "MISSING") + " " + text));
			}
			catch (Exception ex)
			{
				Log.LogError((object)("[KAM] Kikis Audio Menu 1.2.2 failed to patch: " + ex.Message));
			}
		}

		private static bool HasPostfix(MethodInfo target)
		{
			Patches val = ((target != null) ? Harmony.GetPatchInfo((MethodBase)target) : null);
			if (val != null)
			{
				return val.Postfixes.Count > 0;
			}
			return false;
		}
	}
	internal static class Mouths
	{
		private static readonly Dictionary<Character, AnimatedMouth> _mouths = new Dictionary<Character, AnimatedMouth>();

		private static readonly List<Character> _stale = new List<Character>();

		internal static bool Speaking(Character c, out Color color)
		{
			//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_006a: Unknown result type (might be due to invalid IL or missing references)
			//IL_006f: 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_0091: Unknown result type (might be due to invalid IL or missing references)
			//IL_007f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0084: Unknown result type (might be due to invalid IL or missing references)
			color = Color.white;
			if ((Object)(object)c == (Object)null)
			{
				return false;
			}
			AnimatedMouth val = MouthOf(c);
			if ((Object)(object)val == (Object)null || !val.isSpeaking)
			{
				return false;
			}
			if ((Object)(object)c.data == (Object)null || c.data.dead || c.data.passedOut)
			{
				return false;
			}
			float volume = val.volume;
			if (volume > 0.8f)
			{
				color = Color.red;
			}
			else if (volume > 0.5f)
			{
				color = Color.yellow;
			}
			else
			{
				color = Color.green;
			}
			return true;
		}

		internal static Character ByActor(List<Character> all, int actor)
		{
			for (int i = 0; i < all.Count; i++)
			{
				Character val = all[i];
				if (!((Object)(object)val == (Object)null) && !((Object)(object)((MonoBehaviourPun)val).photonView == (Object)null) && ((MonoBehaviourPun)val).photonView.OwnerActorNr == actor)
				{
					return val;
				}
			}
			return null;
		}

		private static AnimatedMouth MouthOf(Character c)
		{
			if (_mouths.TryGetValue(c, out var value) && (Object)(object)value != (Object)null)
			{
				return value;
			}
			value = ((Component)c).GetComponent<AnimatedMouth>();
			if ((Object)(object)value == (Object)null || value.isGhost)
			{
				value = null;
				AnimatedMouth[] componentsInChildren = ((Component)c).GetComponentsInChildren<AnimatedMouth>(true);
				foreach (AnimatedMouth val in componentsInChildren)
				{
					if ((Object)(object)val != (Object)null && !val.isGhost)
					{
						value = val;
						break;
					}
				}
			}
			if ((Object)(object)value != (Object)null)
			{
				_mouths[c] = value;
				if (_mouths.Count > 64)
				{
					Prune();
				}
			}
			return value;
		}

		private static void Prune()
		{
			_stale.Clear();
			foreach (KeyValuePair<Character, AnimatedMouth> mouth in _mouths)
			{
				if ((Object)(object)mouth.Key == (Object)null || (Object)(object)mouth.Value == (Object)null)
				{
					_stale.Add(mouth.Key);
				}
			}
			foreach (Character item in _stale)
			{
				_mouths.Remove(item);
			}
		}
	}
	[HarmonyPatch(typeof(AudioLevels), "Update")]
	internal static class MenuPatch
	{
		private const float INTERVAL = 0.05f;

		private static float _nextAt;

		private static bool _errorShown;

		private static bool _layoutLogged;

		private static readonly Dictionary<AudioLevelSlider, string> _origText = new Dictionary<AudioLevelSlider, string>();

		private static readonly Dictionary<AudioLevelSlider, string> _plainText = new Dictionary<AudioLevelSlider, string>();

		private static readonly Regex Tags = new Regex("<[^>]*>", RegexOptions.Compiled);

		private const string PROFILE_CARDS_GUID = "com.atomic.profileviewer";

		private static HorizontalOrVerticalLayoutGroup _group;

		private static Transform _rowsParent;

		private static bool _groupSearched;

		private static bool _profileCardsChecked;

		private static bool _profileCardsSeen;

		private static bool _spacingLogged;

		private static void Postfix(AudioLevels __instance)
		{
			try
			{
				float unscaledTime = Time.unscaledTime;
				if (!(unscaledTime < _nextAt))
				{
					_nextAt = unscaledTime + 0.05f;
					if (!((Object)(object)__instance == (Object)null) && __instance.sliders != null && __instance.sliders.Count != 0)
					{
						ApplySpacing(__instance.sliders);
						ApplyColors(__instance.sliders);
					}
				}
			}
			catch (Exception ex)
			{
				if (!_errorShown)
				{
					_errorShown = true;
					Plugin.Log.LogWarning((object)("[KAM] menu update failed, giving up for this session: " + ex));
				}
			}
		}

		private static void ApplySpacing(List<AudioLevelSlider> sliders)
		{
			//IL_03bd: Unknown result type (might be due to invalid IL or missing references)
			//IL_0270: Unknown result type (might be due to invalid IL or missing references)
			//IL_0275: Unknown result type (might be due to invalid IL or missing references)
			//IL_04cb: Unknown result type (might be due to invalid IL or missing references)
			//IL_04d0: Unknown result type (might be due to invalid IL or missing references)
			//IL_04db: Unknown result type (might be due to invalid IL or missing references)
			//IL_04fc: Unknown result type (might be due to invalid IL or missing references)
			float value = Plugin.Spacing.Value;
			if (value <= 0f)
			{
				return;
			}
			if (!_profileCardsChecked)
			{
				_profileCardsChecked = true;
				try
				{
					_profileCardsSeen = Chainloader.PluginInfos != null && Chainloader.PluginInfos.ContainsKey("com.atomic.profileviewer");
				}
				catch
				{
				}
				if (_profileCardsSeen)
				{
					Plugin.Log.LogInfo((object)"[KAM] Profile Cards is loaded - leaving the row spacing to it (its cards need their own room)");
				}
			}
			if (_profileCardsSeen)
			{
				return;
			}
			AudioLevelSlider val = null;
			foreach (AudioLevelSlider slider in sliders)
			{
				if ((Object)(object)slider != (Object)null)
				{
					val = slider;
					break;
				}
			}
			Transform val2 = (((Object)(object)val != (Object)null) ? ((Component)val).transform.parent : null);
			if ((Object)(object)val2 == (Object)null)
			{
				return;
			}
			if ((Object)(object)_rowsParent != (Object)(object)val2)
			{
				if (_groupSearched)
				{
					Plugin.Log.LogInfo((object)"[KAM] the audio menu was rebuilt (scene change) - looking for its layout group again");
				}
				_rowsParent = val2;
				_group = null;
				_groupSearched = false;
				_spacingLogged = false;
				_layoutLogged = false;
			}
			if (!_groupSearched)
			{
				HorizontalOrVerticalLayoutGroup val3 = null;
				Transform val4 = val2;
				while ((Object)(object)val4 != (Object)null && (Object)(object)val3 == (Object)null)
				{
					val3 = ((Component)val4).GetComponent<HorizontalOrVerticalLayoutGroup>();
					val4 = val4.parent;
				}
				if ((Object)(object)val3 != (Object)null)
				{
					_group = val3;
					_groupSearched = true;
					Plugin.Log.LogInfo((object)("[KAM] layout group: " + ((object)val3).GetType().Name + " on '" + ((Object)((Component)val3).gameObject).name + "'" + (((Object)(object)((Component)val3).transform == (Object)(object)val2) ? " (the rows' parent)" : (" (" + Steps(val2, ((Component)val3).transform) + " above the rows' parent)"))));
				}
				else
				{
					if (!((Component)val2).gameObject.activeInHierarchy)
					{
						return;
					}
					_groupSearched = true;
					Plugin.Log.LogInfo((object)("[KAM] no layout group above the rows while the menu was open - moving the rows myself (old way) | " + Describe(val2) + " | above that " + Describe(val2.parent)));
				}
			}
			if ((Object)(object)_group != (Object)null)
			{
				float num = 0f;
				foreach (AudioLevelSlider slider2 in sliders)
				{
					if ((Object)(object)slider2 == (Object)null || !((Component)slider2).gameObject.activeSelf)
					{
						continue;
					}
					Transform transform = ((Component)slider2).transform;
					RectTransform val5 = (RectTransform)(object)((transform is RectTransform) ? transform : null);
					if (!((Object)(object)val5 == (Object)null))
					{
						Rect rect = val5.rect;
						num = ((Rect)(ref rect)).height;
						if (num <= 0f)
						{
							num = LayoutUtility.GetPreferredHeight(val5);
						}
						break;
					}
				}
				if (!(num <= 0f))
				{
					float num2 = value - num;
					if (!_spacingLogged)
					{
						_spacingLogged = true;
						Plugin.Log.LogInfo((object)("[KAM] layout group found: row height " + num.ToString("0.#") + ", game spacing " + _group.spacing.ToString("0.#") + " -> spacing " + num2.ToString("0.#") + " (rows " + value.ToString("0.#") + " apart, top to top)"));
					}
					if (Mathf.Abs(_group.spacing - num2) > 0.01f)
					{
						_group.spacing = num2;
					}
				}
				return;
			}
			float num3 = float.NegativeInfinity;
			float num4 = float.NegativeInfinity;
			foreach (AudioLevelSlider slider3 in sliders)
			{
				if ((Object)(object)slider3 == (Object)null)
				{
					continue;
				}
				Transform transform2 = ((Component)slider3).transform;
				RectTransform val6 = (RectTransform)(object)((transform2 is RectTransform) ? transform2 : null);
				if (!((Object)(object)val6 == (Object)null))
				{
					float y = val6.anchoredPosition.y;
					if (y > num3)
					{
						num4 = num3;
						num3 = y;
					}
					else if (y > num4)
					{
						num4 = y;
					}
				}
			}
			if (float.IsNegativeInfinity(num3))
			{
				return;
			}
			if (!_layoutLogged)
			{
				_layoutLogged = true;
				string text = (float.IsNegativeInfinity(num4) ? "n/a" : (num3 - num4).ToString("0.#"));
				Plugin.Log.LogInfo((object)("[KAM] game row spacing " + text + " -> using " + value.ToString("0.#") + " (" + sliders.Count + " rows in the prefab)"));
			}
			int num5 = 0;
			foreach (AudioLevelSlider slider4 in sliders)
			{
				if ((Object)(object)slider4 == (Object)null)
				{
					continue;
				}
				Transform transform3 = ((Component)slider4).transform;
				RectTransform val7 = (RectTransform)(object)((transform3 is RectTransform) ? transform3 : null);
				if (!((Object)(object)val7 == (Object)null))
				{
					Vector2 anchoredPosition = val7.anchoredPosition;
					float num6 = num3 - (float)num5 * value;
					if (Mathf.Abs(anchoredPosition.y - num6) > 0.01f)
					{
						anchoredPosition.y = num6;
						val7.anchoredPosition = anchoredPosition;
					}
					if (((Component)slider4).gameObject.activeSelf)
					{
						num5++;
					}
				}
			}
		}

		private static string Steps(Transform from, Transform to)
		{
			int num = 0;
			Transform val = from;
			while ((Object)(object)val != (Object)null && (Object)(object)val != (Object)(object)to)
			{
				num++;
				val = val.parent;
			}
			return num + ((num == 1) ? " step" : " steps");
		}

		private static string Describe(Transform t)
		{
			if ((Object)(object)t == (Object)null)
			{
				return "no object";
			}
			StringBuilder stringBuilder = new StringBuilder();
			stringBuilder.Append('\'').Append(((Object)((Component)t).gameObject).name).Append("': ");
			Component[] components = ((Component)t).GetComponents<Component>();
			for (int i = 0; i < components.Length; i++)
			{
				if (i > 0)
				{
					stringBuilder.Append(", ");
				}
				stringBuilder.Append(((Object)(object)components[i] == (Object)null) ? "missing script" : ((object)components[i]).GetType().Name);
			}
			return stringBuilder.ToString();
		}

		private static void ApplyColors(List<AudioLevelSlider> sliders)
		{
			//IL_008c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0084: Unknown result type (might be due to invalid IL or missing references)
			//IL_0177: 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_0091: Unknown result type (might be due to invalid IL or missing references)
			//IL_018b: Unknown result type (might be due to invalid IL or missing references)
			if (!Plugin.SpeakingColors.Value)
			{
				return;
			}
			List<Character> allCharacters = Character.AllCharacters;
			if (allCharacters == null)
			{
				return;
			}
			foreach (AudioLevelSlider slider in sliders)
			{
				if ((Object)(object)slider == (Object)null || (Object)(object)slider.playerName == (Object)null)
				{
					continue;
				}
				Player player = slider.player;
				if (player == null || !((Component)slider).gameObject.activeSelf)
				{
					continue;
				}
				Color color;
				bool num = Mouths.Speaking(Mouths.ByActor(allCharacters, player.ActorNumber), out color);
				if (!num)
				{
					color = (player.IsMasterClient ? slider.playerColorGold : slider.playerColorDefault);
				}
				string text = ((TMP_Text)slider.playerName).text;
				string value;
				bool flag = _origText.TryGetValue(slider, out value);
				if (num)
				{
					if (!flag || (text != value && text != _plainText[slider]))
					{
						value = text ?? "";
						_origText[slider] = value;
						_plainText[slider] = Tags.Replace(value, "");
					}
					string text2 = _plainText[slider];
					if (text != text2)
					{
						((TMP_Text)slider.playerName).text = text2;
					}
				}
				else if (flag)
				{
					if (text == _plainText[slider])
					{
						((TMP_Text)slider.playerName).text = value;
					}
					_origText.Remove(slider);
					_plainText.Remove(slider);
				}
				if (((Graphic)slider.playerName).color != color)
				{
					((Graphic)slider.playerName).color = color;
				}
			}
		}
	}
	[HarmonyPatch(typeof(UIPlayerNames), "UpdateName")]
	internal static class OverheadPatch
	{
		private static bool _errorShown;

		private static readonly Dictionary<PlayerName, Color> _defaultColor = new Dictionary<PlayerName, Color>();

		private static readonly Dictionary<PlayerName, Color> _lastColor = new Dictionary<PlayerName, Color>();

		private static void Postfix(UIPlayerNames __instance, int index, bool visible)
		{
			//IL_0082: Unknown result type (might be due to invalid IL or missing references)
			//IL_0083: Unknown result type (might be due to invalid IL or missing references)
			//IL_0070: Unknown result type (might be due to invalid IL or missing references)
			//IL_0075: 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_013e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0143: Unknown result type (might be due to invalid IL or missing references)
			//IL_0151: Unknown result type (might be due to invalid IL or missing references)
			//IL_00da: Unknown result type (might be due to invalid IL or missing references)
			//IL_00db: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e2: Unknown result type (might be due to invalid IL or missing references)
			//IL_0127: 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)
			try
			{
				if (!Plugin.OverheadIconColors.Value || (Object)(object)__instance == (Object)null || __instance.playerNameText == null || index < 0 || index >= __instance.playerNameText.Length)
				{
					return;
				}
				PlayerName val = __instance.playerNameText[index];
				if ((Object)(object)val == (Object)null || (Object)(object)val.audioImage == (Object)null)
				{
					return;
				}
				if (!_defaultColor.TryGetValue(val, out var value))
				{
					value = ((Graphic)val.audioImage).color;
					_defaultColor[val] = value;
				}
				Color val2 = value;
				if (visible && ((Component)val).gameObject.activeSelf && (Object)(object)val.audioImage.sprite != (Object)(object)__instance.mutedAudioSprite)
				{
					Color value2;
					if (Mouths.Speaking(((Object)(object)val.characterInteractable != (Object)null) ? val.characterInteractable.character : null, out var color))
					{
						val2 = color;
						_lastColor[val] = color;
					}
					else if (__instance.audioSprites != null && __instance.audioSprites.Length != 0 && !((Object)(object)val.audioImage.sprite == (Object)(object)__instance.audioSprites[0]) && _lastColor.TryGetValue(val, out value2))
					{
						val2 = value2;
					}
					else
					{
						_lastColor.Remove(val);
					}
				}
				if (((Graphic)val.audioImage).color != val2)
				{
					((Graphic)val.audioImage).color = val2;
				}
			}
			catch (Exception ex)
			{
				if (!_errorShown)
				{
					_errorShown = true;
					Plugin.Log.LogWarning((object)("[KAM] overhead icon update failed, giving up for this session: " + ex));
				}
			}
		}
	}
}