Please disclose if any significant portion of your mod was created using AI tools by adding the 'AI Generated' category. Failing to do so may result in the mod being removed from Thunderstore.
Decompiled source of MicSnitch v1.1.1
plugins/MicSnitch.dll
Decompiled 16 hours agousing System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.Reflection; using System.Runtime.CompilerServices; using BepInEx; using BepInEx.Logging; using HarmonyLib; using UnityEngine; [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: AssemblyVersion("0.0.0.0")] namespace SeeWhoIsTalkingFix; [BepInPlugin("MicSnitch", "Mic Snitch", "1.1.1")] public class Plugin : BaseUnityPlugin { public const string GUID = "MicSnitch"; public const string NAME = "Mic Snitch"; public const string VERSION = "1.1.1"; internal static ManualLogSource Log; internal static Harmony harmony; private void Awake() { //IL_0044: Unknown result type (might be due to invalid IL or missing references) //IL_004e: Expected O, but got Unknown //IL_0053: Unknown result type (might be due to invalid IL or missing references) //IL_0059: Expected O, but got Unknown Log = ((BaseUnityPlugin)this).Logger; Log.LogInfo((object)"[MicSnitch] Mic Snitch 1.1.1 loading..."); try { Core.ResolveTypes(); } catch (Exception ex) { Log.LogError((object)("[MicSnitch] ResolveTypes failed: " + ex)); } harmony = new Harmony("MicSnitch"); GameObject val = new GameObject("MicSnitch_Overlay"); ((Object)val).hideFlags = (HideFlags)61; Object.DontDestroyOnLoad((Object)(object)val); val.AddComponent<Overlay>(); val.AddComponent<Poller>(); Log.LogInfo((object)"[MicSnitch] components attached, Awake done"); } private void OnDestroy() { try { if (harmony != null) { harmony.UnpatchSelf(); } } catch { } } } internal class SpeakerInfo { public float lastNormal; public float lastLoud; public float peakNow; } internal static class Core { internal const float QUIET_THRESHOLD = 0.06f; internal const float LOUD_THRESHOLD = 0.3f; internal const float NORMAL_HOLD = 0.7f; internal const float LOUD_HOLD = 3f; internal static bool Visible = true; internal static readonly object lockObj = new object(); internal static readonly Dictionary<string, SpeakerInfo> activeSpeakers = new Dictionary<string, SpeakerInfo>(); private static readonly Stopwatch Clock = Stopwatch.StartNew(); internal static MethodBase mLinkOnDecodedFrame; internal static FieldInfo fiLinkPlayerId; internal static FieldInfo fiLinkVoiceInfo; internal static PropertyInfo piVoiceInfoUserData; internal static PropertyInfo piFrameOutBuf; internal static PropertyInfo piCurrentRoom; internal static MethodInfo miGetPlayer; internal static int getPlayerArgc; internal static PropertyInfo piPlayerNickName; internal static PropertyInfo piPunInstance; internal static PropertyInfo piVoiceClient; internal static PropertyInfo piLocalVoices; internal static PropertyInfo piIsTransmitting; internal static PropertyInfo piMyNickName; private const BindingFlags ANY_INSTANCE = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic; private const BindingFlags ANY_STATIC = BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic; internal static float Now => (float)Clock.Elapsed.TotalSeconds; internal static Type FindType(string shortName) { Type type = Type.GetType(shortName); if (type != null) { return type; } Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies(); foreach (Assembly assembly in assemblies) { try { Type type2 = assembly.GetType(shortName, throwOnError: false); if (type2 != null) { return type2; } } catch { } } return null; } internal static void ResolveTypes() { ManualLogSource log = Plugin.Log; Type type = FindType("Photon.Voice.Unity.RemoteVoiceLink"); Type type2 = FindType("Photon.Voice.FrameOut`1"); Type type3 = FindType("Photon.Voice.VoiceClient"); Type type4 = FindType("Photon.Realtime.Player"); Type type5 = FindType("Photon.Pun.PhotonNetwork"); Type type6 = FindType("Photon.Voice.PUN.PunVoiceClient"); Type type7 = FindType("Photon.Voice.LocalVoice"); if (type != null) { mLinkOnDecodedFrame = type.GetMethod("OnDecodedFrameFloatAction", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); fiLinkPlayerId = type.GetField("PlayerId", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); fiLinkVoiceInfo = type.GetField("VoiceInfo", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); } if (type2 != null) { Type type8 = type2.MakeGenericType(typeof(float)); piFrameOutBuf = type8.GetProperty("Buf", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); } Type type9 = FindType("Photon.Voice.VoiceInfo"); if (type9 != null) { piVoiceInfoUserData = type9.GetProperty("UserData", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); } if (type4 != null) { piPlayerNickName = type4.GetProperty("NickName", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); } if (type5 != null) { piCurrentRoom = type5.GetProperty("CurrentRoom", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); piMyNickName = type5.GetProperty("NickName", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); } if (piCurrentRoom != null) { miGetPlayer = piCurrentRoom.PropertyType.GetMethod("GetPlayer", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, new Type[2] { typeof(int), typeof(bool) }, null) ?? piCurrentRoom.PropertyType.GetMethod("GetPlayer", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, new Type[1] { typeof(int) }, null); if (miGetPlayer != null) { getPlayerArgc = miGetPlayer.GetParameters().Length; } } if (type6 != null) { piPunInstance = type6.GetProperty("Instance", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); piVoiceClient = type6.GetProperty("VoiceClient", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); } if (type3 != null) { piLocalVoices = type3.GetProperty("LocalVoices", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); } if (type7 != null) { piIsTransmitting = type7.GetProperty("IsCurrentlyTransmitting", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); } log.LogInfo((object)("[MicSnitch] Resolved: Link=" + (mLinkOnDecodedFrame != null) + ", LinkPlayerId=" + (fiLinkPlayerId != null) + ", LinkVoiceInfo=" + (fiLinkVoiceInfo != null) + ", VoiceInfo.UserData=" + (piVoiceInfoUserData != null) + ", FrameOut.Buf=" + (piFrameOutBuf != null) + ", GetPlayer(argc=" + getPlayerArgc + ")=" + (miGetPlayer != null) + ", NickName=" + (piPlayerNickName != null))); log.LogInfo((object)("[MicSnitch] LocalMic: PunInstance=" + (piPunInstance != null) + ", VoiceClient=" + (piVoiceClient != null) + ", LocalVoices=" + (piLocalVoices != null) + ", IsCurrentlyTransmitting=" + (piIsTransmitting != null) + ", MyNickName=" + (piMyNickName != null))); } internal static void ApplyPatches(Harmony harmony) { //IL_003d: Unknown result type (might be due to invalid IL or missing references) //IL_0043: Expected O, but got Unknown if (mLinkOnDecodedFrame != null && fiLinkPlayerId != null) { MethodBase methodBase = mLinkOnDecodedFrame; HarmonyMethod val = new HarmonyMethod(typeof(Core).GetMethod("OnLinkFramePostfix", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic)); harmony.Patch(methodBase, (HarmonyMethod)null, val, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); Plugin.Log.LogInfo((object)"[MicSnitch] Patched RemoteVoiceLink.OnDecodedFrameFloatAction"); } } public static void OnLinkFramePostfix(object __instance, object floats) { try { if (__instance != null) { int actor = ResolveActor(__instance); float peak = ComputePeak(floats); RecordActor(actor, peak); } } catch (Exception ex) { if (Plugin.Log != null) { Plugin.Log.LogWarning((object)("[MicSnitch] OnLinkFramePostfix: " + ex.Message)); } } } private static int ResolveActor(object link) { if (fiLinkVoiceInfo != null && piVoiceInfoUserData != null) { object value = fiLinkVoiceInfo.GetValue(link); if (value != null) { object value2 = piVoiceInfoUserData.GetValue(value); object obj = ((value2 is int) ? value2 : null); int num = default(int); if (obj != null) { num = (int)value2; } if (obj != null && num > 0) { return num / 1000; } } } return Convert.ToInt32(fiLinkPlayerId.GetValue(link)); } private static float ComputePeak(object frameOut) { if (frameOut == null || piFrameOutBuf == null) { return -1f; } if (!(piFrameOutBuf.GetValue(frameOut) is float[] array) || array.Length == 0) { return 0f; } float num = 0f; for (int i = 0; i < array.Length; i++) { float num2 = ((!(array[i] >= 0f)) ? (0f - array[i]) : array[i]); if (num2 > num) { num = num2; } } return num; } internal static void RecordActor(int actor, float peak) { if (peak >= 0f && peak < 0.06f) { return; } string text = ResolveNick(actor); if (string.IsNullOrEmpty(text)) { text = "Player " + actor; } lock (lockObj) { if (!activeSpeakers.TryGetValue(text, out var value)) { value = new SpeakerInfo(); activeSpeakers[text] = value; } value.lastNormal = Now; value.peakNow = peak; if (peak < 0f || peak >= 0.3f) { value.lastLoud = Now; } } } internal static void PollLocalVoice() { try { if (piPunInstance == null || piVoiceClient == null || piLocalVoices == null || piIsTransmitting == null) { return; } object value = piPunInstance.GetValue(null); if (value == null) { return; } object value2 = piVoiceClient.GetValue(value); if (value2 == null || !(piLocalVoices.GetValue(value2) is IEnumerable enumerable)) { return; } bool flag = false; foreach (object item in enumerable) { if (item != null && (bool)piIsTransmitting.GetValue(item)) { flag = true; break; } } if (!flag) { return; } string text = ((!(piMyNickName != null)) ? null : (piMyNickName.GetValue(null) as string)); if (string.IsNullOrEmpty(text)) { text = "You"; } lock (lockObj) { if (!activeSpeakers.TryGetValue(text, out var value3)) { value3 = new SpeakerInfo(); activeSpeakers[text] = value3; } value3.lastNormal = Now; } } catch (Exception ex) { if (Plugin.Log != null) { Plugin.Log.LogWarning((object)("[MicSnitch] PollLocalVoice: " + ex.Message)); } } } internal static string ResolveNick(int actor) { try { if (piCurrentRoom == null || miGetPlayer == null || piPlayerNickName == null) { return null; } object value = piCurrentRoom.GetValue(null); if (value == null) { return null; } object[] parameters = ((getPlayerArgc == 2) ? new object[2] { actor, false } : new object[1] { actor }); object obj = miGetPlayer.Invoke(value, parameters); if (obj == null) { return null; } return piPlayerNickName.GetValue(obj) as string; } catch { return null; } } } internal class Poller : MonoBehaviour { private float nextPoll; private bool patched; private void Update() { if (!patched) { patched = true; try { Core.ApplyPatches(Plugin.harmony); } catch (Exception ex) { if (Plugin.Log != null) { Plugin.Log.LogError((object)("[MicSnitch] ApplyPatches failed: " + ex)); } } } try { if (Input.GetKeyDown((KeyCode)289)) { Core.Visible = !Core.Visible; if (Plugin.Log != null) { Plugin.Log.LogInfo((object)("[MicSnitch] F8 -> Visible=" + Core.Visible)); } } } catch { } if (Core.Now < nextPoll) { return; } nextPoll = Core.Now + 0.15f; Core.PollLocalVoice(); float now = Core.Now; float num = now - Mathf.Max(0.7f, 3f) - 1f; lock (Core.lockObj) { if (Core.activeSpeakers.Count == 0) { return; } List<string> list = null; foreach (KeyValuePair<string, SpeakerInfo> activeSpeaker in Core.activeSpeakers) { SpeakerInfo value = activeSpeaker.Value; float num2 = ((!(value.lastLoud > value.lastNormal)) ? value.lastNormal : value.lastLoud); if (num2 < num) { (list ?? (list = new List<string>())).Add(activeSpeaker.Key); } } if (list == null) { return; } foreach (string item in list) { Core.activeSpeakers.Remove(item); } } } } internal class Overlay : MonoBehaviour { private struct Row { public string name; public bool loud; public float at; } private GUIStyle styleLoud; private GUIStyle styleNormal; private GUIStyle styleHint; private GUIStyle styleHintFaint; private Font font; private static readonly Color LOUD = new Color(1f, 0.3f, 0.3f, 0.95f); private static readonly Color NORMAL = new Color(1f, 0.94f, 0.4f, 0.55f); private static readonly Color HINT = new Color(1f, 0.94f, 0.4f, 0.55f); private static readonly Color FAINT = new Color(1f, 0.94f, 0.4f, 0.18f); private void EnsureStyles() { //IL_0092: Unknown result type (might be due to invalid IL or missing references) //IL_009c: Expected O, but got Unknown //IL_00dd: 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_00f8: Expected O, but got Unknown //IL_010f: 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_012a: Expected O, but got Unknown //IL_0142: 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_015d: Expected O, but got Unknown //IL_0168: Unknown result type (might be due to invalid IL or missing references) if (styleLoud != null) { return; } try { font = Font.CreateDynamicFontFromOSFont(new string[4] { "Arial", "Helvetica", "Liberation Sans", "Verdana" }, 22); } catch (Exception ex) { if (Plugin.Log != null) { Plugin.Log.LogWarning((object)("[MicSnitch] CreateDynamicFontFromOSFont: " + ex.Message)); } } if ((Object)(object)font == (Object)null) { font = GUI.skin.font; } styleNormal = new GUIStyle(); styleNormal.font = font; styleNormal.fontSize = 22; styleNormal.fontStyle = (FontStyle)0; styleNormal.alignment = (TextAnchor)0; styleNormal.normal.textColor = NORMAL; styleLoud = new GUIStyle(styleNormal); styleLoud.fontStyle = (FontStyle)1; styleLoud.normal.textColor = LOUD; styleHint = new GUIStyle(styleNormal); styleHint.fontSize = 14; styleHint.normal.textColor = HINT; styleHintFaint = new GUIStyle(styleHint); styleHintFaint.normal.textColor = FAINT; } private void OnGUI() { //IL_0023: Unknown result type (might be due to invalid IL or missing references) //IL_002d: Expected O, but got Unknown //IL_0028: Unknown result type (might be due to invalid IL or missing references) //IL_002d: Unknown result type (might be due to invalid IL or missing references) //IL_0061: 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) //IL_0177: Expected O, but got Unknown //IL_0172: 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_023c: Unknown result type (might be due to invalid IL or missing references) //IL_01c7: Unknown result type (might be due to invalid IL or missing references) //IL_01d1: Expected O, but got Unknown //IL_01cc: Unknown result type (might be due to invalid IL or missing references) //IL_01d1: Unknown result type (might be due to invalid IL or missing references) //IL_02cd: Unknown result type (might be due to invalid IL or missing references) //IL_02d7: Expected O, but got Unknown //IL_02d2: Unknown result type (might be due to invalid IL or missing references) //IL_02d7: Unknown result type (might be due to invalid IL or missing references) //IL_02ff: Unknown result type (might be due to invalid IL or missing references) EnsureStyles(); float now = Core.Now; if (!Core.Visible) { string text = "[F8] Mic Snitch"; Vector2 val = styleHintFaint.CalcSize(new GUIContent(text)); GUI.Label(new Rect((float)Screen.width - val.x - 24f, 24f, val.x + 4f, val.y + 4f), text, styleHintFaint); return; } List<Row> list = new List<Row>(); lock (Core.lockObj) { foreach (KeyValuePair<string, SpeakerInfo> activeSpeaker in Core.activeSpeakers) { SpeakerInfo value = activeSpeaker.Value; bool flag = now - value.lastLoud < 3f; bool flag2 = now - value.lastNormal < 0.7f; if (flag || flag2) { list.Add(new Row { name = activeSpeaker.Key, loud = flag, at = ((!flag) ? value.lastNormal : value.lastLoud) }); } } } string text2 = "Speaking [F8]"; Vector2 val2 = styleHint.CalcSize(new GUIContent(text2)); float num = 24f; float num2 = val2.x; foreach (Row item in list) { GUIStyle val3 = ((!item.loud) ? styleNormal : styleLoud); float x = val3.CalcSize(new GUIContent(item.name)).x; if (x > num2) { num2 = x; } } float num3 = (float)Screen.width - 24f; GUI.Label(new Rect(num3 - val2.x, num, val2.x + 4f, val2.y + 2f), text2, styleHint); num += val2.y + 4f; if (list.Count == 0) { return; } list.Sort((Row a, Row b) => (a.loud != b.loud) ? ((!a.loud) ? 1 : (-1)) : b.at.CompareTo(a.at)); foreach (Row item2 in list) { GUIStyle val4 = ((!item2.loud) ? styleNormal : styleLoud); Vector2 val5 = val4.CalcSize(new GUIContent(item2.name)); GUI.Label(new Rect(num3 - val5.x, num, val5.x + 4f, val5.y + 2f), item2.name, val4); num += val5.y + 1f; } } }