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));
}
}
}
}
}