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 MicVisual v1.0.0
plugins/MicVisual.dll
Decompiled 4 hours agousing System; using System.Diagnostics; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; using Microsoft.CodeAnalysis; using UnityEngine; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")] [assembly: AssemblyCompany("MicVisual")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0+bd0cc09f6f4aef4f0acc0c2dce3ddf3f84da6db9")] [assembly: AssemblyProduct("MicVisual")] [assembly: AssemblyTitle("MicVisual")] [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 MicVisual { public static class MicIndicator { private const float ReferenceHeight = 1080f; private const float PanelWidth = 132f; private const float PanelHeight = 36f; private const float IconSize = 28f; private const float BarHeight = 12f; private const float BarWidth = 92f; private const float Padding = 4f; private const float PeakWidth = 2f; private static readonly Color IconColor = new Color(0.92f, 0.95f, 0.98f, 1f); private static readonly Color BarColor = new Color(0.3f, 0.9f, 0.35f, 1f); private static readonly Color TrackColor = new Color(0f, 0f, 0f, 0.45f); private static readonly Color PeakColor = new Color(1f, 1f, 1f, 0.85f); private static readonly Color MutedColor = new Color(0.65f, 0.65f, 0.68f, 1f); private static readonly MicLevelSource Source = new MicLevelSource(); private static GameObject _host; private static Texture2D _iconTexture; private static Texture2D _barTexture; private static int _lastFrame = -1; private static float _nextHeartbeat; private static float _display; private static float _peak; private static float _alpha; private static float _silentTime; public static void Tick() { if (_lastFrame == Time.frameCount) { return; } _lastFrame = Time.frameCount; EnsureHost(); MicSettings settings = MicVisualPlugin.Settings; float num = Mathf.Max(Time.unscaledDeltaTime, 0.0001f); Source.TryResolve(); bool flag = Source.Sample(); bool muted = Source.Muted; float num2 = 0f; if (flag && !muted) { num2 = Mathf.Clamp01(Source.Level * settings.Sensitivity.Value); float value = settings.NoiseFloor.Value; num2 = ((num2 <= value) ? 0f : ((num2 - value) / Mathf.Max(1f - value, 0.0001f))); } float num3 = ((num2 > _display) ? settings.AttackSpeed.Value : settings.ReleaseSpeed.Value); _display = Mathf.Lerp(_display, num2, 1f - Mathf.Exp((0f - num3) * num)); _peak = (settings.ShowPeakMarker.Value ? Mathf.Max(_display, _peak - settings.PeakDecay.Value * num) : 0f); if (!muted && _display > 0.001f) { _silentTime = 0f; } else { _silentTime += num; } bool flag2 = settings.Enabled.Value && flag; if (settings.HideWhenSilent.Value && _silentTime > settings.SilentHideDelay.Value) { flag2 = false; } _alpha = Mathf.MoveTowards(_alpha, flag2 ? 1f : 0f, num * settings.FadeSpeed.Value); if (settings.Verbose.Value && Time.unscaledTime >= _nextHeartbeat) { _nextHeartbeat = Time.unscaledTime + 2f; ManualLogSource log = MicVisualPlugin.Log; if (log != null) { log.LogInfo((object)($"mic: raw={Source.Level:F4} bar={num2:F3} display={_display:F3} " + $"muted={muted} available={flag} resolved={Source.Resolved}")); } } } public static void Draw() { //IL_00e6: Unknown result type (might be due to invalid IL or missing references) //IL_00fb: Unknown result type (might be due to invalid IL or missing references) //IL_00f4: Unknown result type (might be due to invalid IL or missing references) //IL_014c: Unknown result type (might be due to invalid IL or missing references) //IL_014e: 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_016a: 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_01d1: Unknown result type (might be due to invalid IL or missing references) //IL_01e2: Unknown result type (might be due to invalid IL or missing references) //IL_01e7: Unknown result type (might be due to invalid IL or missing references) MicSettings settings = MicVisualPlugin.Settings; if ((Object)(object)_iconTexture == (Object)null || settings == null || _alpha <= 0.001f) { return; } int depth = GUI.depth; GUI.depth = -1000; try { float num = (float)Screen.height / 1080f * Mathf.Max(settings.Scale.Value, 0.01f); float num2 = 132f * num; float num3 = 36f * num; float num4 = settings.MarginRight.Value * num; float num5 = settings.MarginBottom.Value * num; Rect val = default(Rect); ((Rect)(ref val))..ctor((float)Screen.width - num2 - num4, (float)Screen.height - num3 - num5, num2, num3); bool muted = Source.Muted; float num6 = 28f * num; Draw(new Rect(((Rect)(ref val)).x + 4f * num, ((Rect)(ref val)).y + (((Rect)(ref val)).height - num6) * 0.5f, num6, num6), _iconTexture, muted ? MutedColor : IconColor); float num7 = 92f * num; float num8 = 12f * num; Rect rect = default(Rect); ((Rect)(ref rect))..ctor(((Rect)(ref val)).xMax - 4f * num - num7, ((Rect)(ref val)).y + (((Rect)(ref val)).height - num8) * 0.5f, num7, num8); DrawPill(rect, TrackColor, 1f); DrawPill(rect, muted ? MutedColor : BarColor, Mathf.Clamp01(_display)); if (_peak > 0.01f) { float num9 = 2f * num; GUI.DrawTexture(new Rect(((Rect)(ref rect)).x + ((Rect)(ref rect)).width * _peak - num9 * 0.5f, ((Rect)(ref rect)).y - 2f * num, num9, ((Rect)(ref rect)).height + 4f * num), (Texture)(object)Texture2D.whiteTexture, (ScaleMode)0, true, 0f, Fade(PeakColor), 0f, 0f); } } finally { GUI.depth = depth; } } private static void Draw(Rect rect, Texture2D texture, Color color) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0009: Unknown result type (might be due to invalid IL or missing references) //IL_000a: Unknown result type (might be due to invalid IL or missing references) GUI.DrawTexture(rect, (Texture)(object)texture, (ScaleMode)0, true, 0f, Fade(color), 0f, 0f); } private static void DrawPill(Rect rect, Color color, float fill) { //IL_00ab: Unknown result type (might be due to invalid IL or missing references) //IL_00b5: Unknown result type (might be due to invalid IL or missing references) //IL_00d5: 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_006f: Unknown result type (might be due to invalid IL or missing references) //IL_0080: Unknown result type (might be due to invalid IL or missing references) //IL_0081: Unknown result type (might be due to invalid IL or missing references) float height = ((Rect)(ref rect)).height; float num = ((Rect)(ref rect)).width * Mathf.Clamp01(fill); if (!(num <= 0.5f)) { float num2 = Mathf.Min(height, num); float num3 = Mathf.Min(height, Mathf.Max(0f, num - height)); float num4 = Mathf.Max(0f, num - num2 - num3); if (num4 > 0f) { GUI.DrawTexture(new Rect(((Rect)(ref rect)).x + num2, ((Rect)(ref rect)).y, num4, ((Rect)(ref rect)).height), (Texture)(object)Texture2D.whiteTexture, (ScaleMode)0, true, 0f, Fade(color), 0f, 0f); } Draw(new Rect(((Rect)(ref rect)).x, ((Rect)(ref rect)).y, num2, ((Rect)(ref rect)).height), _barTexture, color); Draw(new Rect(((Rect)(ref rect)).x + num - num3, ((Rect)(ref rect)).y, num3, ((Rect)(ref rect)).height), _barTexture, color); } } private static Color Fade(Color color) { //IL_0010: Unknown result type (might be due to invalid IL or missing references) color.a *= _alpha; return color; } private static void EnsureHost() { //IL_002d: Unknown result type (might be due to invalid IL or missing references) //IL_0037: Expected O, but got Unknown if (!((Object)(object)_host != (Object)null) || !((Object)(object)_iconTexture != (Object)null)) { if ((Object)(object)_host == (Object)null) { _host = new GameObject("MicVisualGui"); _host.AddComponent<MicIndicatorBehaviour>(); } if ((Object)(object)_iconTexture == (Object)null) { _iconTexture = UiSprites.CreateMicIcon(128); _barTexture = UiSprites.CreateRoundedRect(64, 64, 32); } } } } public sealed class MicIndicatorBehaviour : MonoBehaviour { private void OnGUI() { MicIndicator.Draw(); } } public sealed class MicLevelSource { private const string VoiceChatType = "PlayerVoiceChat"; private Type _voiceChatType; private FieldInfo _instanceField; private FieldInfo _loudnessField; private FieldInfo _muteField; private FieldInfo _micEnabledField; private FieldInfo _isTalkingField; private bool _resolved; private bool _resolveFailed; public bool Resolved => _resolved; public float Level { get; private set; } public bool Muted { get; private set; } public bool MicrophoneAvailable { get; private set; } public bool IsTalking { get; private set; } public bool TryResolve() { if (_resolved || _resolveFailed) { return _resolved; } _voiceChatType = AccessTools.TypeByName("PlayerVoiceChat"); if (_voiceChatType == null) { _resolveFailed = true; ManualLogSource log = MicVisualPlugin.Log; if (log != null) { log.LogWarning((object)"'PlayerVoiceChat' not found in Assembly-CSharp; mic indicator disabled."); } return false; } _instanceField = AccessTools.Field(_voiceChatType, "instance"); _loudnessField = AccessTools.Field(_voiceChatType, "clipLoudness"); _muteField = AccessTools.Field(_voiceChatType, "toggleMute"); _micEnabledField = AccessTools.Field(_voiceChatType, "microphoneEnabled"); _isTalkingField = AccessTools.Field(_voiceChatType, "isTalking"); if (_instanceField == null || _loudnessField == null) { _resolveFailed = true; ManualLogSource log2 = MicVisualPlugin.Log; if (log2 != null) { log2.LogError((object)"'PlayerVoiceChat' found but expected fields are missing; mic indicator disabled."); } return false; } _resolved = true; return true; } public bool Sample() { if (!TryResolve()) { return false; } object obj = _instanceField.GetValue(null); Object val = (Object)((obj is Object) ? obj : null); if (val != null && val == (Object)null) { obj = null; } if (obj == null) { Level = 0f; Muted = false; MicrophoneAvailable = false; IsTalking = false; return false; } Level = (float)_loudnessField.GetValue(obj); Muted = ReadBool(_muteField, obj); MicrophoneAvailable = ReadBool(_micEnabledField, obj); IsTalking = ReadBool(_isTalkingField, obj); return true; } private static bool ReadBool(FieldInfo field, object instance) { if (field == null) { return false; } try { object value = field.GetValue(instance); bool flag = default(bool); int num; if (value is bool) { flag = (bool)value; num = 1; } else { num = 0; } return (byte)((uint)num & (flag ? 1u : 0u)) != 0; } catch (Exception) { return false; } } } [BepInPlugin("com.repo.micvisual", "MicVisual", "1.0.0")] [BepInProcess("REPO.exe")] public class MicVisualPlugin : BaseUnityPlugin { public const string PluginGuid = "com.repo.micvisual"; public const string PluginVersion = "1.0.0"; public static ManualLogSource Log; public static MicSettings Settings; private void Awake() { //IL_002f: Unknown result type (might be due to invalid IL or missing references) //IL_0039: Expected O, but got Unknown Log = ((BaseUnityPlugin)this).Logger; Settings = new MicSettings(((BaseUnityPlugin)this).Config); Log.LogInfo((object)"MicVisual 1.0.0 loaded"); try { ApplyPatches(new Harmony("com.repo.micvisual")); } catch (Exception arg) { Log.LogError((object)$"Failed to patch the game update loop: {arg}"); } } private static void ApplyPatches(Harmony harmony) { //IL_0096: Unknown result type (might be due to invalid IL or missing references) //IL_00a3: Expected O, but got Unknown string[] obj = new string[2] { "RoundDirector", "PlayerVoiceChat" }; bool flag = false; string[] array = obj; foreach (string text in array) { Type type = AccessTools.TypeByName(text); if (type == null) { Log.LogWarning((object)(text + " not found, skipping")); continue; } MethodInfo methodInfo = AccessTools.Method(type, "Update", Type.EmptyTypes, (Type[])null); if (methodInfo == null) { Log.LogWarning((object)(text + ".Update not found, skipping")); continue; } harmony.Patch((MethodBase)methodInfo, (HarmonyMethod)null, new HarmonyMethod(typeof(MicIndicatorPatch), "Postfix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); Log.LogInfo((object)("Patched " + text + ".Update")); flag = true; break; } if (!flag) { Log.LogError((object)"No patch target found; the indicator will not update"); } } } public static class MicIndicatorPatch { public static void Postfix() { MicIndicator.Tick(); } } public class MicSettings { public readonly ConfigEntry<bool> Enabled; public readonly ConfigEntry<bool> Verbose; public readonly ConfigEntry<float> Sensitivity; public readonly ConfigEntry<float> NoiseFloor; public readonly ConfigEntry<float> AttackSpeed; public readonly ConfigEntry<float> ReleaseSpeed; public readonly ConfigEntry<float> PeakDecay; public readonly ConfigEntry<bool> ShowPeakMarker; public readonly ConfigEntry<bool> HideWhenSilent; public readonly ConfigEntry<float> SilentHideDelay; public readonly ConfigEntry<float> FadeSpeed; public readonly ConfigEntry<float> Scale; public readonly ConfigEntry<float> MarginRight; public readonly ConfigEntry<float> MarginBottom; public MicSettings(ConfigFile config) { Enabled = config.Bind<bool>("Indicator", "Enabled", true, "Show the microphone indicator."); Verbose = config.Bind<bool>("Indicator", "Verbose", false, "Log the raw microphone level and indicator state every two seconds. Useful for tuning Sensitivity."); Sensitivity = config.Bind<float>("Indicator", "Sensitivity", 4f, "How strongly the microphone level fills the bar. Raise it if the bar barely moves."); NoiseFloor = config.Bind<float>("Indicator", "NoiseFloor", 0.02f, "Levels below this fraction count as silence, so the bar does not flicker on room noise."); AttackSpeed = config.Bind<float>("Indicator", "AttackSpeed", 18f, "How fast the bar rises, in units per second."); ReleaseSpeed = config.Bind<float>("Indicator", "ReleaseSpeed", 6f, "How fast the bar falls back, in units per second."); ShowPeakMarker = config.Bind<bool>("Indicator", "ShowPeakMarker", true, "Show a thin marker at the highest recent level."); PeakDecay = config.Bind<float>("Indicator", "PeakDecay", 0.6f, "How quickly the peak marker falls back, in units per second."); HideWhenSilent = config.Bind<bool>("Indicator", "HideWhenSilent", false, "Fade the whole indicator out during silence instead of showing an empty bar."); SilentHideDelay = config.Bind<float>("Indicator", "SilentHideDelay", 0.6f, "Seconds of silence before the indicator fades out."); FadeSpeed = config.Bind<float>("Indicator", "FadeSpeed", 6f, "Fade speed of the whole indicator, in units per second."); Scale = config.Bind<float>("Layout", "Scale", 1f, "Size multiplier for the indicator."); MarginRight = config.Bind<float>("Layout", "MarginRight", 20f, "Distance from the right edge of the screen, in 1080p reference pixels."); MarginBottom = config.Bind<float>("Layout", "MarginBottom", 40f, "Distance from the bottom edge of the screen, in 1080p reference pixels."); } } public static class UiSprites { private const int Supersample = 4; public static Texture2D CreateMicIcon(int size) { //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_0026: Unknown result type (might be due to invalid IL or missing references) //IL_002b: Unknown result type (might be due to invalid IL or missing references) //IL_003b: Unknown result type (might be due to invalid IL or missing references) //IL_0040: Unknown result type (might be due to invalid IL or missing references) //IL_0050: Unknown result type (might be due to invalid IL or missing references) //IL_0055: Unknown result type (might be due to invalid IL or missing references) //IL_0065: 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_007a: 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_008f: Unknown result type (might be due to invalid IL or missing references) //IL_0094: Unknown result type (might be due to invalid IL or missing references) Vector2 bodyTop = new Vector2(0.5f, 0.72f); Vector2 bodyBottom = new Vector2(0.5f, 0.44f); Vector2 cradleCentre = new Vector2(0.5f, 0.55f); Vector2 stemTop = new Vector2(0.5f, 0.31f); Vector2 stemBottom = new Vector2(0.5f, 0.21f); Vector2 baseLeft = new Vector2(0.34f, 0.19f); Vector2 baseRight = new Vector2(0.66f, 0.19f); return Render(size, size, delegate(Vector2 p) { //IL_0000: 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_0008: 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_001b: 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_0037: Unknown result type (might be due to invalid IL or missing references) //IL_0039: Unknown result type (might be due to invalid IL or missing references) //IL_003f: Unknown result type (might be due to invalid IL or missing references) //IL_0054: Unknown result type (might be due to invalid IL or missing references) //IL_0067: 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) //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) float num = Capsule(p, bodyTop, bodyBottom, 0.115f); num = Mathf.Min(num, Capsule(p, stemTop, stemBottom, 0.028f)); num = Mathf.Min(num, Capsule(p, baseLeft, baseRight, 0.028f)); if (p.y <= cradleCentre.y) { Vector2 val = p - cradleCentre; float num2 = Mathf.Abs(((Vector2)(ref val)).magnitude - 0.215f) - 0.025f; num = Mathf.Min(num, num2); } return num; }); } public static Texture2D CreateRoundedRect(int width, int height, int radius) { //IL_0029: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Unknown result type (might be due to invalid IL or missing references) radius = Mathf.Clamp(radius, 1, Mathf.Min(width, height) / 2); Vector2 half = new Vector2((float)width * 0.5f, (float)height * 0.5f); float r = radius; return Render(width, height, delegate(Vector2 p) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0017: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Unknown result type (might be due to invalid IL or missing references) //IL_0034: Unknown result type (might be due to invalid IL or missing references) //IL_0039: Unknown result type (might be due to invalid IL or missing references) //IL_003e: Unknown result type (might be due to invalid IL or missing references) //IL_003f: Unknown result type (might be due to invalid IL or missing references) //IL_004f: Unknown result type (might be due to invalid IL or missing references) //IL_005f: Unknown result type (might be due to invalid IL or missing references) //IL_0064: Unknown result type (might be due to invalid IL or missing references) //IL_006c: Unknown result type (might be due to invalid IL or missing references) //IL_0072: Unknown result type (might be due to invalid IL or missing references) Vector2 val = new Vector2(Mathf.Abs(p.x - half.x), Mathf.Abs(p.y - half.y)) - half; Vector2 val2 = new Vector2(Mathf.Max(val.x, 0f), Mathf.Max(val.y, 0f)); return ((Vector2)(ref val2)).magnitude + Mathf.Min(Mathf.Max(val.x, val.y), 0f) - r; }); } private static float Capsule(Vector2 p, Vector2 a, Vector2 b, float radius) { //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_0008: Unknown result type (might be due to invalid IL or missing references) //IL_0009: 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_000f: Unknown result type (might be due to invalid IL or missing references) //IL_0010: 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_0017: Unknown result type (might be due to invalid IL or missing references) //IL_0024: 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_002b: 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) Vector2 val = p - a; Vector2 val2 = b - a; float num = Mathf.Clamp01(Vector2.Dot(val, val2) / Vector2.Dot(val2, val2)); Vector2 val3 = val - val2 * num; return ((Vector2)(ref val3)).magnitude - radius; } private static Texture2D Render(int width, int height, Func<Vector2, float> sdf) { //IL_0004: Unknown result type (might be due to invalid IL or missing references) //IL_0009: Unknown result type (might be due to invalid IL or missing references) //IL_0010: Unknown result type (might be due to invalid IL or missing references) //IL_0017: Unknown result type (might be due to invalid IL or missing references) //IL_0020: Expected O, but got Unknown //IL_00e4: Unknown result type (might be due to invalid IL or missing references) //IL_00e9: Unknown result type (might be due to invalid IL or missing references) //IL_008a: Unknown result type (might be due to invalid IL or missing references) Texture2D val = new Texture2D(width, height, (TextureFormat)4, false) { filterMode = (FilterMode)1, wrapMode = (TextureWrapMode)1, hideFlags = (HideFlags)61 }; Color32[] array = (Color32[])(object)new Color32[width * height]; float num = 0.25f; float num2 = num * 0.5f; float num3 = 0.0625f; Vector2 arg = default(Vector2); for (int i = 0; i < height; i++) { for (int j = 0; j < width; j++) { float num4 = 0f; for (int k = 0; k < 4; k++) { for (int l = 0; l < 4; l++) { ((Vector2)(ref arg))..ctor(((float)j + num2 + (float)l * num) / (float)width, ((float)i + num2 + (float)k * num) / (float)height); num4 += Mathf.Clamp01(0.5f - sdf(arg) * (float)width) * num3; } } byte b = (byte)Mathf.RoundToInt(Mathf.Clamp01(num4) * 255f); array[i * width + j] = new Color32(byte.MaxValue, byte.MaxValue, byte.MaxValue, b); } } val.SetPixels32(array); val.Apply(false, false); return val; } } }