Decompiled source of VoiceMaster v1.0.0

Mods/VoiceMaster.dll

Decompiled 13 hours ago
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Net.WebSockets;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using System.Text;
using System.Text.Json.Nodes;
using System.Text.RegularExpressions;
using System.Threading;
using System.Threading.Tasks;
using BoneLib;
using BoneLib.BoneMenu;
using BoneLib.Notifications;
using Il2CppSLZ.Marrow;
using MelonLoader;
using MelonLoader.Preferences;
using Microsoft.CodeAnalysis;
using UnityEngine;
using VoiceMaster;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: MelonInfo(typeof(MainMod), "VoiceMaster", "1.0.1", "dimastv", null)]
[assembly: MelonGame("Stress Level Zero", "BONELAB")]
[assembly: MelonOptionalDependencies(new string[] { "BoneLib" })]
[assembly: MelonColor(255, 114, 137, 218)]
[assembly: MelonAuthorColor(255, 0, 230, 255)]
[assembly: TargetFramework(".NETCoreApp,Version=v6.0", FrameworkDisplayName = ".NET 6.0")]
[assembly: AssemblyCompany("VoiceMaster")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0")]
[assembly: AssemblyProduct("VoiceMaster")]
[assembly: AssemblyTitle("VoiceMaster")]
[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.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableAttribute : Attribute
	{
		public readonly byte[] NullableFlags;

		public NullableAttribute(byte P_0)
		{
			NullableFlags = new byte[1] { P_0 };
		}

		public NullableAttribute(byte[] P_0)
		{
			NullableFlags = P_0;
		}
	}
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableContextAttribute : Attribute
	{
		public readonly byte Flag;

		public NullableContextAttribute(byte P_0)
		{
			Flag = P_0;
		}
	}
	[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 VoiceMaster
{
	internal static class BoneMenuIntegration
	{
		private static Page? _mainPage;

		private static Page? _voicesPage;

		private static Page? _favoritesPage;

		private static Page? _discordSettingsPage;

		private static Page? _pcKeyPage;

		private static Page? _vrTriggerPage;

		private static FunctionElement? _voicemodStatusBtn;

		private static FunctionElement? _currentVoiceBtn;

		private static FunctionElement? _discordMuteBtn;

		private static FunctionElement? _discordDeafenBtn;

		private static BoolElement? _voiceChangerBool;

		private static BoolElement? _hearMyselfBool;

		private static BoolElement? _voicemodMuteBool;

		private static readonly List<(FunctionElement Element, string VoiceId)> _voiceElements = new List<(FunctionElement, string)>();

		private static readonly (string KeyId, string Label)[] _pcKeys = new(string, string)[10]
		{
			("PAUSE", "PAUSE / BREAK"),
			("F14", "F14 (Recommended - No Conflict)"),
			("F13", "F13"),
			("F15", "F15"),
			("F16", "F16"),
			("F24", "F24"),
			("SCROLLLOCK", "SCROLL LOCK"),
			("INSERT", "INSERT"),
			("M", "M"),
			("SPACE", "SPACE")
		};

		private static readonly (string TriggerId, string Label)[] _vrTriggers = new(string, string)[9]
		{
			("LeftStickTriple", "Left Stick: Triple-Click (3x) [Default]"),
			("LeftStickDouble", "Left Stick: Double-Click (2x)"),
			("LeftStickSingle", "Left Stick: Single-Click (1x)"),
			("RightStickTriple", "Right Stick: Triple-Click (3x)"),
			("RightStickDouble", "Right Stick: Double-Click (2x)"),
			("RightStickSingle", "Right Stick: Single-Click (1x)"),
			("LeftSecondary", "Left Controller: Y Button (Secondary)"),
			("RightSecondary", "Right Controller: B Button (Secondary)"),
			("Disabled", "Disabled (BoneMenu Only)")
		};

		[MethodImpl(MethodImplOptions.NoInlining)]
		internal static void SetupMenu()
		{
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			_mainPage = Page.Root.CreatePage("Voice Master", new Color(0.35f, 0.45f, 0.95f), 0, true);
			BuildMainPageOnce();
			VoicemodClient.Instance.OnStatusChanged += UpdateStatusUI;
			VoicemodClient.Instance.OnVoicesUpdated += RebuildVoicesPage;
		}

		[MethodImpl(MethodImplOptions.NoInlining)]
		private static void BuildMainPageOnce()
		{
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			//IL_0059: 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_00d4: Unknown result type (might be due to invalid IL or missing references)
			//IL_010c: 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_0173: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a7: 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_020a: Unknown result type (might be due to invalid IL or missing references)
			//IL_023e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0280: Unknown result type (might be due to invalid IL or missing references)
			//IL_02d1: Unknown result type (might be due to invalid IL or missing references)
			//IL_0322: Unknown result type (might be due to invalid IL or missing references)
			if (_mainPage == null)
			{
				return;
			}
			_voicemodStatusBtn = _mainPage.CreateFunction("Voicemod: [OFFLINE - Click to Connect]", new Color(1f, 0.35f, 0.35f), (Action)delegate
			{
				if (!VoicemodClient.Instance.IsConnected)
				{
					VoicemodClient.Instance.ConnectAsync();
				}
				UpdateStatusUI();
			});
			_currentVoiceBtn = _mainPage.CreateFunction("Current Voice: [Clean]", Color.cyan, (Action)delegate
			{
			});
			_mainPage.CreateFunction("--- DISCORD CONTROLS ---", Color.gray, (Action)delegate
			{
			});
			_discordMuteBtn = _mainPage.CreateFunction("[ ] Discord Mute: [ACTIVE]", new Color(0.25f, 0.95f, 0.4f), (Action)delegate
			{
				DiscordController.ToggleMute();
				UpdateStatusUI();
			});
			_discordDeafenBtn = _mainPage.CreateFunction("[ ] Discord Deafen: [OFF]", Color.white, (Action)delegate
			{
				DiscordController.ToggleDeafen();
				UpdateStatusUI();
			});
			_discordSettingsPage = _mainPage.CreatePage("Discord & Hotkey Settings >", new Color(0.4f, 0.6f, 1f), 0, true);
			BuildSettingsPage();
			_mainPage.CreateFunction("--- VOICEMOD CONTROLS ---", Color.gray, (Action)delegate
			{
			});
			_voicesPage = _mainPage.CreatePage("★ Choose Voice >", Color.cyan, 0, true);
			RebuildVoicesPage();
			_mainPage.CreateFunction("✦ Clean Mic (Normal)", Color.green, (Action)delegate
			{
				VoicemodClient.Instance.SelectVoice("df6454f1-8eb2-4092-9ccc-fb51219f6291", "Clean Mic");
				UpdateStatusUI();
			});
			_mainPage.CreateFunction("\ud83c\udfb2 Random Voice", new Color(1f, 0.85f, 0.2f), (Action)delegate
			{
				VoicemodClient.Instance.SelectRandomVoice();
				UpdateStatusUI();
			});
			_voiceChangerBool = _mainPage.CreateBool("Voice Changer Active", Color.white, VoicemodClient.Instance.IsVoiceChangerActive, (Action<bool>)delegate
			{
				VoicemodClient.Instance.ToggleVoiceChanger();
			});
			_hearMyselfBool = _mainPage.CreateBool("Hear Myself (Monitor)", Color.white, VoicemodClient.Instance.IsHearMyselfActive, (Action<bool>)delegate
			{
				VoicemodClient.Instance.ToggleHearMyself();
			});
			_voicemodMuteBool = _mainPage.CreateBool("Voicemod Mic Mute", new Color(1f, 0.4f, 0.4f), VoicemodClient.Instance.IsMuteMicActive, (Action<bool>)delegate
			{
				VoicemodClient.Instance.ToggleMute();
			});
			_favoritesPage = _mainPage.CreatePage("Quick Voice Favorites >", new Color(0.9f, 0.5f, 1f), 0, true);
			BuildFavoritesPage();
			UpdateStatusUI();
		}

		public static void UpdateStatusUI()
		{
			//IL_0067: 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_007d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0051: Unknown result type (might be due to invalid IL or missing references)
			//IL_004a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0103: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ed: Unknown result type (might be due to invalid IL or missing references)
			//IL_0154: 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_01a9: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a2: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				if (_voicemodStatusBtn != null)
				{
					bool isConnected = VoicemodClient.Instance.IsConnected;
					bool isConnecting = VoicemodClient.Instance.IsConnecting;
					string elementName = (isConnected ? "Voicemod: [CONNECTED]" : (isConnecting ? "Voicemod: [CONNECTING...]" : "Voicemod: [OFFLINE - Click to Connect]"));
					Color elementColor = (Color)(isConnected ? new Color(0.2f, 0.9f, 0.3f) : (isConnecting ? Color.yellow : new Color(1f, 0.35f, 0.35f)));
					((Element)_voicemodStatusBtn).ElementName = elementName;
					((Element)_voicemodStatusBtn).ElementColor = elementColor;
				}
				if (_currentVoiceBtn != null)
				{
					((Element)_currentVoiceBtn).ElementName = "Current Voice: [" + VoicemodClient.Instance.CurrentVoiceName + "]";
				}
				if (_discordMuteBtn != null)
				{
					bool isDiscordMutedEstimate = DiscordController.IsDiscordMutedEstimate;
					((Element)_discordMuteBtn).ElementName = (isDiscordMutedEstimate ? "[X] Discord Mute: [MUTED]" : "[ ] Discord Mute: [ACTIVE]");
					((Element)_discordMuteBtn).ElementColor = (isDiscordMutedEstimate ? new Color(1f, 0.25f, 0.25f) : new Color(0.25f, 0.95f, 0.4f));
				}
				if (_discordDeafenBtn != null)
				{
					bool isDiscordDeafenedEstimate = DiscordController.IsDiscordDeafenedEstimate;
					((Element)_discordDeafenBtn).ElementName = (isDiscordDeafenedEstimate ? "[X] Discord Deafen: [ON]" : "[ ] Discord Deafen: [OFF]");
					((Element)_discordDeafenBtn).ElementColor = (Color)(isDiscordDeafenedEstimate ? new Color(1f, 0.55f, 0.15f) : Color.white);
				}
				string currentVoiceId = VoicemodClient.Instance.CurrentVoiceId;
				foreach (var (val, text) in _voiceElements)
				{
					if (val != null)
					{
						bool flag = text.Equals(currentVoiceId, StringComparison.OrdinalIgnoreCase);
						((Element)val).ElementColor = (flag ? Color.green : Color.white);
					}
				}
			}
			catch
			{
			}
		}

		[MethodImpl(MethodImplOptions.NoInlining)]
		private static void RebuildVoicesPage()
		{
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_005a: Unknown result type (might be due to invalid IL or missing references)
			//IL_009d: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e0: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a2: Unknown result type (might be due to invalid IL or missing references)
			//IL_02ad: Unknown result type (might be due to invalid IL or missing references)
			//IL_021e: Unknown result type (might be due to invalid IL or missing references)
			//IL_030a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0303: Unknown result type (might be due to invalid IL or missing references)
			//IL_0223: Unknown result type (might be due to invalid IL or missing references)
			//IL_024d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0217: Unknown result type (might be due to invalid IL or missing references)
			//IL_0201: Unknown result type (might be due to invalid IL or missing references)
			//IL_030f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0339: Unknown result type (might be due to invalid IL or missing references)
			if (_voicesPage == null)
			{
				return;
			}
			_voicesPage.RemoveAll();
			_voiceElements.Clear();
			_voicesPage.CreateFunction("--- VOICEMOD COLLECTION ---", Color.gray, (Action)delegate
			{
			});
			_voicesPage.CreateFunction("⟳ Sync Collection from Voicemod", Color.green, (Action)delegate
			{
				VoicemodClient.Instance.SyncVoicesFromDisk();
				if (VoicemodClient.Instance.IsConnected)
				{
					VoicemodClient.Instance.ConnectAsync();
				}
			});
			_voicesPage.CreateFunction("✦ Clean Mic (Normal)", new Color(0.3f, 1f, 0.5f), (Action)delegate
			{
				VoicemodClient.Instance.SelectVoice("df6454f1-8eb2-4092-9ccc-fb51219f6291", "Clean Mic");
				UpdateStatusUI();
			});
			_voicesPage.CreateFunction("\ud83c\udfb2 Random Voice", new Color(1f, 0.85f, 0.2f), (Action)delegate
			{
				VoicemodClient.Instance.SelectRandomVoice();
				UpdateStatusUI();
			});
			string currentVoiceId = VoicemodClient.Instance.CurrentVoiceId;
			List<VoiceInfo> list = VoicemodClient.Instance.Voices.Where((VoiceInfo v) => v.Id.Contains("-")).ToList();
			List<VoiceInfo> list2 = VoicemodClient.Instance.Voices.Where((VoiceInfo v) => !v.Id.Contains("-")).ToList();
			if (list.Count > 0)
			{
				_voicesPage.CreateFunction("--- YOUR VOICES ---", new Color(0.35f, 0.65f, 1f), (Action)delegate
				{
				});
				foreach (VoiceInfo item3 in list)
				{
					Color val = (Color)(item3.Id.Equals(currentVoiceId, StringComparison.OrdinalIgnoreCase) ? Color.green : (item3.IsFavorite ? new Color(1f, 0.85f, 0.3f) : Color.white));
					string vId = item3.Id;
					string vName = item3.Name;
					FunctionElement item = _voicesPage.CreateFunction(vName, val, (Action)delegate
					{
						VoicemodClient.Instance.SelectVoice(vId, vName);
						UpdateStatusUI();
					});
					_voiceElements.Add((item, vId));
				}
			}
			if (list2.Count <= 0)
			{
				return;
			}
			_voicesPage.CreateFunction("--- CLASSIC PRESETS ---", Color.gray, (Action)delegate
			{
			});
			foreach (VoiceInfo item4 in list2)
			{
				Color val2 = (item4.Id.Equals(currentVoiceId, StringComparison.OrdinalIgnoreCase) ? Color.green : Color.white);
				string vId2 = item4.Id;
				string vName2 = item4.Name;
				FunctionElement item2 = _voicesPage.CreateFunction(vName2, val2, (Action)delegate
				{
					VoicemodClient.Instance.SelectVoice(vId2, vName2);
					UpdateStatusUI();
				});
				_voiceElements.Add((item2, vId2));
			}
		}

		[MethodImpl(MethodImplOptions.NoInlining)]
		private static void BuildFavoritesPage()
		{
			//IL_001c: Unknown result type (might be due to invalid IL or missing references)
			//IL_017d: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b1: 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_01e5: Unknown result type (might be due to invalid IL or missing references)
			//IL_0219: Unknown result type (might be due to invalid IL or missing references)
			if (_favoritesPage == null)
			{
				return;
			}
			_favoritesPage.RemoveAll();
			_favoritesPage.CreateFunction("--- QUICK FAVORITE SLOTS ---", Color.gray, (Action)delegate
			{
			});
			(string, MelonPreferences_Entry<string>)[] array = new(string, MelonPreferences_Entry<string>)[5]
			{
				("Slot 1", ModConfig.FavoriteVoice1),
				("Slot 2", ModConfig.FavoriteVoice2),
				("Slot 3", ModConfig.FavoriteVoice3),
				("Slot 4", ModConfig.FavoriteVoice4),
				("Slot 5", ModConfig.FavoriteVoice5)
			};
			for (int num = 0; num < array.Length; num++)
			{
				(string, MelonPreferences_Entry<string>) tuple = array[num];
				string item = tuple.Item1;
				MelonPreferences_Entry<string> item2 = tuple.Item2;
				string voiceId = item2.Value;
				VoiceInfo voiceInfo = VoicemodClient.Instance.Voices.FirstOrDefault((VoiceInfo v) => v.Id.Equals(voiceId, StringComparison.OrdinalIgnoreCase));
				string voiceName = ((voiceInfo != null) ? voiceInfo.Name : voiceId);
				_favoritesPage.CreateFunction(item + ": [" + voiceName + "]", new Color(0.9f, 0.6f, 1f), (Action)delegate
				{
					VoicemodClient.Instance.SelectVoice(voiceId, voiceName);
					UpdateStatusUI();
				});
			}
			_favoritesPage.CreateFunction("--- SAVE CURRENT TO SLOT ---", Color.gray, (Action)delegate
			{
			});
			_favoritesPage.CreateFunction("Save Current Voice to Slot 1", Color.yellow, (Action)delegate
			{
				ModConfig.FavoriteVoice1.Value = VoicemodClient.Instance.CurrentVoiceId;
				ModConfig.PrefCategory.SaveToFile(true);
				BuildFavoritesPage();
				NotificationHelper.ShowSuccess("Favorites", "Saved to Slot 1: " + VoicemodClient.Instance.CurrentVoiceName);
			});
			_favoritesPage.CreateFunction("Save Current Voice to Slot 2", Color.yellow, (Action)delegate
			{
				ModConfig.FavoriteVoice2.Value = VoicemodClient.Instance.CurrentVoiceId;
				ModConfig.PrefCategory.SaveToFile(true);
				BuildFavoritesPage();
				NotificationHelper.ShowSuccess("Favorites", "Saved to Slot 2: " + VoicemodClient.Instance.CurrentVoiceName);
			});
			_favoritesPage.CreateFunction("Save Current Voice to Slot 3", Color.yellow, (Action)delegate
			{
				ModConfig.FavoriteVoice3.Value = VoicemodClient.Instance.CurrentVoiceId;
				ModConfig.PrefCategory.SaveToFile(true);
				BuildFavoritesPage();
				NotificationHelper.ShowSuccess("Favorites", "Saved to Slot 3: " + VoicemodClient.Instance.CurrentVoiceName);
			});
		}

		[MethodImpl(MethodImplOptions.NoInlining)]
		private static void BuildSettingsPage()
		{
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00dc: Unknown result type (might be due to invalid IL or missing references)
			//IL_010b: Unknown result type (might be due to invalid IL or missing references)
			//IL_013f: 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_01b1: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ef: Unknown result type (might be due to invalid IL or missing references)
			//IL_024c: Unknown result type (might be due to invalid IL or missing references)
			//IL_02ae: Unknown result type (might be due to invalid IL or missing references)
			//IL_02e2: Unknown result type (might be due to invalid IL or missing references)
			if (_discordSettingsPage != null)
			{
				_discordSettingsPage.RemoveAll();
				_discordSettingsPage.CreateFunction("--- DISCORD MUTE CONFIGURATION ---", Color.gray, (Action)delegate
				{
				});
				string value = ModConfig.DiscordMuteKey.Value;
				string curTrigger = ModConfig.VRMuteTrigger.Value;
				string text = _vrTriggers.FirstOrDefault(((string TriggerId, string Label) t) => t.TriggerId.Equals(curTrigger, StringComparison.OrdinalIgnoreCase)).Label ?? curTrigger;
				_pcKeyPage = _discordSettingsPage.CreatePage("⌨ PC Mute Key: [" + value + "] >", Color.cyan, 0, true);
				BuildPcKeyPage();
				_vrTriggerPage = _discordSettingsPage.CreatePage("\ud83c\udfae VR Button: [" + text + "] >", new Color(1f, 0.85f, 0.3f), 0, true);
				BuildVrTriggerPage();
				_discordSettingsPage.CreateFunction("⚡ Auto-bind in Discord (sends key in 3s)", new Color(0.3f, 0.9f, 1f), (Action)delegate
				{
					DiscordController.TriggerBindingSimulation();
				});
				_discordSettingsPage.CreateFunction("--- PREFERENCES ---", Color.gray, (Action)delegate
				{
				});
				_discordSettingsPage.CreateBool("Sync Voicemod Mic with Discord", Color.white, ModConfig.SyncVoicemodMuteWithDiscord.Value, (Action<bool>)delegate(bool val)
				{
					ModConfig.SyncVoicemodMuteWithDiscord.Value = val;
					ModConfig.PrefCategory.SaveToFile(true);
				});
				_discordSettingsPage.CreateBool("Show BoneLib Notifications", Color.white, ModConfig.ShowNotifications.Value, (Action<bool>)delegate(bool val)
				{
					ModConfig.ShowNotifications.Value = val;
					ModConfig.PrefCategory.SaveToFile(true);
				});
				_discordSettingsPage.CreateFunction("--- DIAGNOSTICS ---", Color.gray, (Action)delegate
				{
				});
				_discordSettingsPage.CreateFunction($"Configured Port: {ModConfig.VoicemodPort.Value}", Color.gray, (Action)delegate
				{
				});
				_discordSettingsPage.CreateFunction($"Loaded Voices: {VoicemodClient.Instance.Voices.Count}", Color.white, (Action)delegate
				{
				});
				_discordSettingsPage.CreateFunction("⟳ Reconnect Voicemod", Color.green, (Action)delegate
				{
					VoicemodClient.Instance.ConnectAsync();
					UpdateStatusUI();
				});
			}
		}

		[MethodImpl(MethodImplOptions.NoInlining)]
		private static void BuildPcKeyPage()
		{
			//IL_001c: 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_00dc: 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_00e1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f9: Unknown result type (might be due to invalid IL or missing references)
			if (_pcKeyPage == null)
			{
				return;
			}
			_pcKeyPage.RemoveAll();
			_pcKeyPage.CreateFunction("--- SELECT KEYBOARD KEY FOR DISCORD ---", Color.gray, (Action)delegate
			{
			});
			_pcKeyPage.CreateFunction("⚡ Send Selected Key in 3s (Bind in Discord)", new Color(0.3f, 0.9f, 1f), (Action)delegate
			{
				DiscordController.TriggerBindingSimulation();
			});
			string value = ModConfig.DiscordMuteKey.Value;
			(string, string)[] pcKeys = _pcKeys;
			for (int num = 0; num < pcKeys.Length; num++)
			{
				(string, string) tuple = pcKeys[num];
				string item = tuple.Item1;
				string item2 = tuple.Item2;
				bool num2 = item.Equals(value, StringComparison.OrdinalIgnoreCase);
				string text = (num2 ? "[✓] " : "     ");
				Color val = (num2 ? Color.green : Color.white);
				string selectedKey = item;
				_pcKeyPage.CreateFunction(text + item2, val, (Action)delegate
				{
					ModConfig.DiscordMuteKey.Value = selectedKey;
					ModConfig.PrefCategory.SaveToFile(true);
					BuildPcKeyPage();
					BuildSettingsPage();
					NotificationHelper.ShowSuccess("Discord Key", "Discord Mute Key set to: " + selectedKey);
				});
			}
		}

		[MethodImpl(MethodImplOptions.NoInlining)]
		private static void BuildVrTriggerPage()
		{
			//IL_001c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0099: Unknown result type (might be due to invalid IL or missing references)
			//IL_0092: Unknown result type (might be due to invalid IL or missing references)
			//IL_009e: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bf: Unknown result type (might be due to invalid IL or missing references)
			if (_vrTriggerPage == null)
			{
				return;
			}
			_vrTriggerPage.RemoveAll();
			_vrTriggerPage.CreateFunction("--- SELECT VR CONTROLLER BUTTON / GESTURE ---", Color.gray, (Action)delegate
			{
			});
			string value = ModConfig.VRMuteTrigger.Value;
			(string, string)[] vrTriggers = _vrTriggers;
			for (int num = 0; num < vrTriggers.Length; num++)
			{
				(string, string) tuple = vrTriggers[num];
				string item = tuple.Item1;
				string item2 = tuple.Item2;
				bool num2 = item.Equals(value, StringComparison.OrdinalIgnoreCase);
				string text = (num2 ? "[✓] " : "     ");
				Color val = (num2 ? Color.green : Color.white);
				string selectedTrigger = item;
				string selectedLabel = item2;
				_vrTriggerPage.CreateFunction(text + item2, val, (Action)delegate
				{
					ModConfig.VRMuteTrigger.Value = selectedTrigger;
					ModConfig.PrefCategory.SaveToFile(true);
					BuildVrTriggerPage();
					BuildSettingsPage();
					NotificationHelper.ShowSuccess("VR Trigger", "Mute Button set to:\n" + selectedLabel);
				});
			}
		}
	}
	public static class ConsoleSafety
	{
		private const int STD_INPUT_HANDLE = -10;

		private const uint ENABLE_QUICK_EDIT_MODE = 64u;

		private const uint ENABLE_EXTENDED_FLAGS = 128u;

		private const uint WM_KEYDOWN = 256u;

		private const uint WM_KEYUP = 257u;

		private const int VK_RETURN = 13;

		[DllImport("kernel32.dll", SetLastError = true)]
		private static extern IntPtr GetStdHandle(int nStdHandle);

		[DllImport("kernel32.dll", SetLastError = true)]
		private static extern bool GetConsoleMode(IntPtr hConsoleHandle, out uint lpMode);

		[DllImport("kernel32.dll", SetLastError = true)]
		private static extern bool SetConsoleMode(IntPtr hConsoleHandle, uint dwMode);

		[DllImport("kernel32.dll")]
		private static extern IntPtr GetConsoleWindow();

		[DllImport("user32.dll")]
		private static extern bool PostMessage(IntPtr hWnd, uint msg, IntPtr wParam, IntPtr lParam);

		public static void DisableConsoleFreezing()
		{
			try
			{
				IntPtr stdHandle = GetStdHandle(-10);
				if (stdHandle != IntPtr.Zero && stdHandle != new IntPtr(-1) && GetConsoleMode(stdHandle, out var lpMode))
				{
					lpMode &= 0xFFFFFFBFu;
					lpMode |= 0x80;
					SetConsoleMode(stdHandle, lpMode);
				}
			}
			catch
			{
			}
		}

		public static void EnsureConsoleNotPaused()
		{
			try
			{
				IntPtr consoleWindow = GetConsoleWindow();
				if (consoleWindow != IntPtr.Zero)
				{
					PostMessage(consoleWindow, 256u, (IntPtr)13, IntPtr.Zero);
					PostMessage(consoleWindow, 257u, (IntPtr)13, IntPtr.Zero);
				}
			}
			catch
			{
			}
		}
	}
	public static class DiscordController
	{
		private const uint KEYEVENTF_KEYDOWN = 0u;

		private const uint KEYEVENTF_KEYUP = 2u;

		private const byte VK_PAUSE = 19;

		private const byte SCAN_PAUSE = 69;

		private const byte VK_F14 = 125;

		private static readonly Stopwatch _muteStopwatch = Stopwatch.StartNew();

		private static readonly Stopwatch _deafenStopwatch = Stopwatch.StartNew();

		private const long MinToggleIntervalMs = 350L;

		public static bool IsDiscordMutedEstimate { get; private set; }

		public static bool IsDiscordDeafenedEstimate { get; private set; }

		[DllImport("user32.dll")]
		private static extern void keybd_event(byte bVk, byte bScan, uint dwFlags, UIntPtr dwExtraInfo);

		[DllImport("user32.dll")]
		private static extern uint MapVirtualKey(uint uCode, uint uMapType);

		public static void ToggleMute()
		{
			if (_muteStopwatch.ElapsedMilliseconds < 350)
			{
				return;
			}
			_muteStopwatch.Restart();
			IsDiscordMutedEstimate = !IsDiscordMutedEstimate;
			string statusMsg = (IsDiscordMutedEstimate ? "Discord: [MUTED]" : "Discord: [UNMUTED]");
			NotificationHelper.Show("Discord", statusMsg, (NotificationType)(IsDiscordMutedEstimate ? 1 : 3));
			Task.Run(delegate
			{
				try
				{
					byte num = ResolveVirtualKey(ModConfig.DiscordMuteKey.Value, 125);
					bool value = ModConfig.DiscordMuteCtrl.Value;
					bool value2 = ModConfig.DiscordMuteShift.Value;
					bool value3 = ModConfig.DiscordMuteAlt.Value;
					SendKeyWithModifiers(num, value, value2, value3);
					if (num == 19)
					{
						ConsoleSafety.EnsureConsoleNotPaused();
					}
					MelonLogger.Msg(statusMsg);
				}
				catch (Exception ex)
				{
					MelonLogger.Warning("Failed to trigger Discord mute key: " + ex.Message);
				}
			});
			if (ModConfig.SyncVoicemodMuteWithDiscord.Value)
			{
				VoicemodClient.Instance.ToggleMute();
			}
		}

		public static void ToggleDeafen()
		{
			if (_deafenStopwatch.ElapsedMilliseconds < 350)
			{
				return;
			}
			_deafenStopwatch.Restart();
			IsDiscordDeafenedEstimate = !IsDiscordDeafenedEstimate;
			string statusMsg = (IsDiscordDeafenedEstimate ? "Discord: [DEAFENED]" : "Discord: [NORMAL]");
			NotificationHelper.Show("Discord", statusMsg, (NotificationType)(IsDiscordDeafenedEstimate ? 1 : 3));
			Task.Run(delegate
			{
				try
				{
					byte vkCode = ResolveVirtualKey(ModConfig.DiscordDeafenKey.Value, 68);
					bool value = ModConfig.DiscordDeafenCtrl.Value;
					bool value2 = ModConfig.DiscordDeafenShift.Value;
					bool value3 = ModConfig.DiscordDeafenAlt.Value;
					SendKeyWithModifiers(vkCode, value, value2, value3);
					MelonLogger.Msg(statusMsg);
				}
				catch (Exception ex)
				{
					MelonLogger.Warning("Failed to trigger Discord deafen key: " + ex.Message);
				}
			});
		}

		public static void TriggerBindingSimulation(int delaySeconds = 3)
		{
			Task.Run(async delegate
			{
				try
				{
					NotificationHelper.ShowWarning("Discord Bind", $"Press Discord 'Record Keybind' now! Sending in {delaySeconds}s...", delaySeconds);
					await Task.Delay(delaySeconds * 1000);
					byte num = ResolveVirtualKey(ModConfig.DiscordMuteKey.Value, 125);
					bool value = ModConfig.DiscordMuteCtrl.Value;
					bool value2 = ModConfig.DiscordMuteShift.Value;
					bool value3 = ModConfig.DiscordMuteAlt.Value;
					SendKeyWithModifiers(num, value, value2, value3);
					if (num == 19)
					{
						ConsoleSafety.EnsureConsoleNotPaused();
					}
					NotificationHelper.ShowSuccess("Discord Bind", "Key [" + ModConfig.DiscordMuteKey.Value + "] sent to Discord!");
				}
				catch (Exception ex)
				{
					MelonLogger.Warning("Simulation failed: " + ex.Message);
				}
			});
		}

		private static void SendKeyWithModifiers(byte vkCode, bool ctrl, bool shift, bool alt)
		{
			byte bScan = (byte)((vkCode == 19) ? 69 : ((byte)MapVirtualKey(vkCode, 0u)));
			if (ctrl)
			{
				keybd_event(17, 29, 0u, UIntPtr.Zero);
			}
			if (shift)
			{
				keybd_event(16, 42, 0u, UIntPtr.Zero);
			}
			if (alt)
			{
				keybd_event(18, 56, 0u, UIntPtr.Zero);
			}
			keybd_event(vkCode, bScan, 0u, UIntPtr.Zero);
			Thread.Sleep(30);
			keybd_event(vkCode, bScan, 2u, UIntPtr.Zero);
			if (alt)
			{
				keybd_event(18, 56, 2u, UIntPtr.Zero);
			}
			if (shift)
			{
				keybd_event(16, 42, 2u, UIntPtr.Zero);
			}
			if (ctrl)
			{
				keybd_event(17, 29, 2u, UIntPtr.Zero);
			}
		}

		public static byte ResolveVirtualKey(string keyStr, byte fallback)
		{
			if (string.IsNullOrWhiteSpace(keyStr))
			{
				return fallback;
			}
			string text = keyStr.Trim().ToUpperInvariant();
			switch (text)
			{
			case "PAUSE":
			case "BREAK":
				return 19;
			case "SCROLLLOCK":
			case "SCROLL_LOCK":
			case "SCROLL":
				return 145;
			case "INSERT":
			case "INS":
				return 45;
			case "DELETE":
			case "DEL":
				return 46;
			case "HOME":
				return 36;
			case "END":
				return 35;
			case "NUMPAD*":
			case "MULTIPLY":
				return 106;
			case "NUMPAD+":
			case "ADD":
				return 107;
			case "NUMPAD-":
			case "SUBTRACT":
				return 109;
			case "NUMPAD/":
			case "DIVIDE":
				return 111;
			default:
			{
				if (text.StartsWith("F") && int.TryParse(text.Substring(1), out var result) && result >= 1 && result <= 24)
				{
					return (byte)(112 + (result - 1));
				}
				if (text.Length == 1)
				{
					char c = text[0];
					if (c >= 'A' && c <= 'Z')
					{
						return (byte)c;
					}
					if (c >= '0' && c <= '9')
					{
						return (byte)c;
					}
				}
				return text switch
				{
					"M" => 77, 
					"D" => 68, 
					"SPACE" => 32, 
					_ => fallback, 
				};
			}
			}
		}
	}
	public class MainMod : MelonMod
	{
		private static bool _boneLibLoaded;

		private static int _multiClickCount;

		private static float _lastClickTime;

		private const float MultiClickWindow = 0.5f;

		public override void OnInitializeMelon()
		{
			ConsoleSafety.DisableConsoleFreezing();
			ModConfig.Initialize();
			MelonLogger.Msg("VoiceMaster mod initializing...");
			if (ModConfig.VoicemodAutoConnect.Value)
			{
				VoicemodClient.Instance.ConnectAsync();
			}
			MelonLogger.Msg("VoiceMaster initialized successfully!");
		}

		public override void OnLateInitializeMelon()
		{
			TryInitBoneLib();
		}

		public override void OnSceneWasLoaded(int buildIndex, string sceneName)
		{
			if (_boneLibLoaded)
			{
				MainThreadDispatcher.Enqueue(delegate
				{
					BoneMenuIntegration.UpdateStatusUI();
				});
			}
		}

		public override void OnUpdate()
		{
			MainThreadDispatcher.ProcessQueue();
			if (_boneLibLoaded)
			{
				CheckVRControllerInput();
			}
			if (Input.GetKeyDown((KeyCode)289))
			{
				DiscordController.ToggleMute();
				if (_boneLibLoaded)
				{
					BoneMenuIntegration.UpdateStatusUI();
				}
			}
			else if (Input.GetKeyDown((KeyCode)290))
			{
				VoicemodClient.Instance.SelectVoice("clean", "Clean");
				if (_boneLibLoaded)
				{
					BoneMenuIntegration.UpdateStatusUI();
				}
			}
			else if (Input.GetKeyDown((KeyCode)291))
			{
				VoicemodClient.Instance.SelectRandomVoice();
				if (_boneLibLoaded)
				{
					BoneMenuIntegration.UpdateStatusUI();
				}
			}
		}

		private static void CheckVRControllerInput()
		{
			string value = ModConfig.VRMuteTrigger.Value;
			if (string.Equals(value, "Disabled", StringComparison.OrdinalIgnoreCase))
			{
				return;
			}
			try
			{
				BaseController leftController = Player.LeftController;
				BaseController rightController = Player.RightController;
				bool flag = false;
				switch (value)
				{
				case "LeftStickTriple":
					if ((Object)(object)leftController != (Object)null && leftController.GetThumbStickDown())
					{
						flag = HandleMultiClick(3);
					}
					break;
				case "LeftStickDouble":
					if ((Object)(object)leftController != (Object)null && leftController.GetThumbStickDown())
					{
						flag = HandleMultiClick(2);
					}
					break;
				case "LeftStickSingle":
					if ((Object)(object)leftController != (Object)null && leftController.GetThumbStickDown())
					{
						flag = true;
					}
					break;
				case "RightStickTriple":
					if ((Object)(object)rightController != (Object)null && rightController.GetThumbStickDown())
					{
						flag = HandleMultiClick(3);
					}
					break;
				case "RightStickDouble":
					if ((Object)(object)rightController != (Object)null && rightController.GetThumbStickDown())
					{
						flag = HandleMultiClick(2);
					}
					break;
				case "RightStickSingle":
					if ((Object)(object)rightController != (Object)null && rightController.GetThumbStickDown())
					{
						flag = true;
					}
					break;
				case "LeftSecondary":
					if ((Object)(object)leftController != (Object)null && leftController.GetSecondaryInteractionButtonDown())
					{
						flag = true;
					}
					break;
				case "RightSecondary":
					if ((Object)(object)rightController != (Object)null && rightController.GetSecondaryInteractionButtonDown())
					{
						flag = true;
					}
					break;
				default:
					if (ModConfig.TripleClickLeftStickMute.Value && (Object)(object)leftController != (Object)null && leftController.GetThumbStickDown())
					{
						flag = HandleMultiClick(3);
					}
					break;
				}
				if (flag)
				{
					DiscordController.ToggleMute();
					BoneMenuIntegration.UpdateStatusUI();
				}
			}
			catch
			{
			}
		}

		private static bool HandleMultiClick(int targetCount)
		{
			float realtimeSinceStartup = Time.realtimeSinceStartup;
			if (realtimeSinceStartup - _lastClickTime <= 0.5f)
			{
				_multiClickCount++;
			}
			else
			{
				_multiClickCount = 1;
			}
			_lastClickTime = realtimeSinceStartup;
			if (_multiClickCount >= targetCount)
			{
				_multiClickCount = 0;
				_lastClickTime = 0f;
				return true;
			}
			return false;
		}

		public override void OnApplicationQuit()
		{
			VoicemodClient.Instance.Disconnect();
		}

		private void TryInitBoneLib()
		{
			try
			{
				if (AppDomain.CurrentDomain.GetAssemblies().Any((Assembly a) => a.GetName().Name == "BoneLib"))
				{
					HookBoneLibEvents();
					BoneMenuIntegration.SetupMenu();
					_boneLibLoaded = true;
					MelonLogger.Msg("BoneLib integration & BoneMenu initialized successfully for VoiceMaster!");
				}
				else
				{
					MelonLogger.Warning("BoneLib not detected. VoiceMaster will run in background mode without BoneMenu.");
				}
			}
			catch (Exception ex)
			{
				MelonLogger.Warning("BoneLib integration failed to load: " + ex.Message);
			}
		}

		private void HookBoneLibEvents()
		{
			Hooking.OnLevelLoaded += delegate
			{
				try
				{
					MainThreadDispatcher.Enqueue(delegate
					{
						BoneMenuIntegration.UpdateStatusUI();
					});
				}
				catch
				{
				}
			};
		}
	}
	public static class MainThreadDispatcher
	{
		private static readonly ConcurrentQueue<Action> _queue = new ConcurrentQueue<Action>();

		public static void Enqueue(Action action)
		{
			if (action != null)
			{
				_queue.Enqueue(action);
			}
		}

		public static void ProcessQueue()
		{
			Action result;
			while (_queue.TryDequeue(out result))
			{
				try
				{
					result();
				}
				catch (Exception ex)
				{
					MelonLogger.Warning("Error executing dispatcher action: " + ex.Message);
				}
			}
		}
	}
	public static class ModConfig
	{
		public static MelonPreferences_Category PrefCategory { get; private set; }

		public static MelonPreferences_Entry<bool> Enabled { get; private set; }

		public static MelonPreferences_Entry<bool> ShowNotifications { get; private set; }

		public static MelonPreferences_Entry<int> VoicemodPort { get; private set; }

		public static MelonPreferences_Entry<bool> VoicemodAutoConnect { get; private set; }

		public static MelonPreferences_Entry<string> LastSelectedVoice { get; private set; }

		public static MelonPreferences_Entry<string> DiscordMuteKey { get; private set; }

		public static MelonPreferences_Entry<bool> DiscordMuteCtrl { get; private set; }

		public static MelonPreferences_Entry<bool> DiscordMuteShift { get; private set; }

		public static MelonPreferences_Entry<bool> DiscordMuteAlt { get; private set; }

		public static MelonPreferences_Entry<string> DiscordDeafenKey { get; private set; }

		public static MelonPreferences_Entry<bool> DiscordDeafenCtrl { get; private set; }

		public static MelonPreferences_Entry<bool> DiscordDeafenShift { get; private set; }

		public static MelonPreferences_Entry<bool> DiscordDeafenAlt { get; private set; }

		public static MelonPreferences_Entry<bool> SyncVoicemodMuteWithDiscord { get; private set; }

		public static MelonPreferences_Entry<string> VRMuteTrigger { get; private set; }

		public static MelonPreferences_Entry<bool> TripleClickLeftStickMute { get; private set; }

		public static MelonPreferences_Entry<string> FavoriteVoice1 { get; private set; }

		public static MelonPreferences_Entry<string> FavoriteVoice2 { get; private set; }

		public static MelonPreferences_Entry<string> FavoriteVoice3 { get; private set; }

		public static MelonPreferences_Entry<string> FavoriteVoice4 { get; private set; }

		public static MelonPreferences_Entry<string> FavoriteVoice5 { get; private set; }

		public static void Initialize()
		{
			PrefCategory = MelonPreferences.CreateCategory("VoiceMaster", "VoiceMaster (Voicemod & Discord)");
			Enabled = PrefCategory.CreateEntry<bool>("Enabled", true, "Master Mod Enabled", (string)null, false, false, (ValueValidator)null, (string)null);
			ShowNotifications = PrefCategory.CreateEntry<bool>("ShowNotifications", true, "Show BoneLib In-Game Notifications", (string)null, false, false, (ValueValidator)null, (string)null);
			VoicemodPort = PrefCategory.CreateEntry<int>("VoicemodPort", 59125, "Voicemod WebSocket Port", (string)null, false, false, (ValueValidator)null, (string)null);
			VoicemodAutoConnect = PrefCategory.CreateEntry<bool>("VoicemodAutoConnect", true, "Auto-connect to Voicemod on start", (string)null, false, false, (ValueValidator)null, (string)null);
			LastSelectedVoice = PrefCategory.CreateEntry<string>("LastSelectedVoice", "df6454f1-8eb2-4092-9ccc-fb51219f6291", "Last Selected Voice ID", (string)null, false, false, (ValueValidator)null, (string)null);
			DiscordMuteKey = PrefCategory.CreateEntry<string>("DiscordMuteKey", "PAUSE", "Discord Mute Key (e.g. PAUSE, F14, F13, F15, INSERT, M)", (string)null, false, false, (ValueValidator)null, (string)null);
			DiscordMuteCtrl = PrefCategory.CreateEntry<bool>("DiscordMuteCtrl", false, "Discord Mute: Require Ctrl", (string)null, false, false, (ValueValidator)null, (string)null);
			DiscordMuteShift = PrefCategory.CreateEntry<bool>("DiscordMuteShift", false, "Discord Mute: Require Shift", (string)null, false, false, (ValueValidator)null, (string)null);
			DiscordMuteAlt = PrefCategory.CreateEntry<bool>("DiscordMuteAlt", false, "Discord Mute: Require Alt", (string)null, false, false, (ValueValidator)null, (string)null);
			DiscordDeafenKey = PrefCategory.CreateEntry<string>("DiscordDeafenKey", "D", "Discord Deafen Key (e.g. D, F15)", (string)null, false, false, (ValueValidator)null, (string)null);
			DiscordDeafenCtrl = PrefCategory.CreateEntry<bool>("DiscordDeafenCtrl", true, "Discord Deafen: Require Ctrl", (string)null, false, false, (ValueValidator)null, (string)null);
			DiscordDeafenShift = PrefCategory.CreateEntry<bool>("DiscordDeafenShift", true, "Discord Deafen: Require Shift", (string)null, false, false, (ValueValidator)null, (string)null);
			DiscordDeafenAlt = PrefCategory.CreateEntry<bool>("DiscordDeafenAlt", false, "Discord Deafen: Require Alt", (string)null, false, false, (ValueValidator)null, (string)null);
			SyncVoicemodMuteWithDiscord = PrefCategory.CreateEntry<bool>("SyncVoicemodMuteWithDiscord", false, "Mute Voicemod when Muting Discord", (string)null, false, false, (ValueValidator)null, (string)null);
			VRMuteTrigger = PrefCategory.CreateEntry<string>("VRMuteTrigger", "LeftStickTriple", "VR Controller Mute Trigger (LeftStickTriple, LeftStickDouble, LeftStickSingle, RightStickTriple, RightStickDouble, RightStickSingle, LeftSecondary, RightSecondary, Disabled)", (string)null, false, false, (ValueValidator)null, (string)null);
			TripleClickLeftStickMute = PrefCategory.CreateEntry<bool>("TripleClickLeftStickMute", true, "Legacy toggle for Left Stick Triple Click", (string)null, false, false, (ValueValidator)null, (string)null);
			FavoriteVoice1 = PrefCategory.CreateEntry<string>("FavoriteVoice1", "df6454f1-8eb2-4092-9ccc-fb51219f6291", "Favorite Voice Slot 1 (Clean Mic)", (string)null, false, false, (ValueValidator)null, (string)null);
			FavoriteVoice2 = PrefCategory.CreateEntry<string>("FavoriteVoice2", "372d1db4-9b06-4e48-a3d2-bfd9138fc838", "Favorite Voice Slot 2 (Golden Bunny)", (string)null, false, false, (ValueValidator)null, (string)null);
			FavoriteVoice3 = PrefCategory.CreateEntry<string>("FavoriteVoice3", "63db9115-a6c0-4de3-9494-827022d481ed", "Favorite Voice Slot 3 (Scary Teddy)", (string)null, false, false, (ValueValidator)null, (string)null);
			FavoriteVoice4 = PrefCategory.CreateEntry<string>("FavoriteVoice4", "6d3b8cf4-6b81-4f12-a4ba-64c8ba52e115", "Favorite Voice Slot 4 (Rockstar Wolf)", (string)null, false, false, (ValueValidator)null, (string)null);
			FavoriteVoice5 = PrefCategory.CreateEntry<string>("FavoriteVoice5", "f604c108-6348-44df-91cb-48cfce3ec8a3", "Favorite Voice Slot 5 (Better Mic 4K)", (string)null, false, false, (ValueValidator)null, (string)null);
			PrefCategory.SaveToFile(true);
		}
	}
	public static class NotificationHelper
	{
		private static float _lastNotificationTime;

		private const float MinNotificationInterval = 0.3f;

		public static void Show(string title, string message, NotificationType type = (NotificationType)0, float duration = 2f)
		{
			//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)
			if (!ModConfig.ShowNotifications.Value)
			{
				return;
			}
			MainThreadDispatcher.Enqueue(delegate
			{
				//IL_0020: Unknown result type (might be due to invalid IL or missing references)
				//IL_0025: 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_0028: Unknown result type (might be due to invalid IL or missing references)
				//IL_003a: Expected I4, but got Unknown
				//IL_0062: 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_0079: Unknown result type (might be due to invalid IL or missing references)
				//IL_007e: Unknown result type (might be due to invalid IL or missing references)
				//IL_004b: 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_0096: Unknown result type (might be due to invalid IL or missing references)
				//IL_0097: Unknown result type (might be due to invalid IL or missing references)
				//IL_0098: Unknown result type (might be due to invalid IL or missing references)
				//IL_009d: Unknown result type (might be due to invalid IL or missing references)
				//IL_00a4: 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_00ab: Unknown result type (might be due to invalid IL or missing references)
				//IL_00b0: Unknown result type (might be due to invalid IL or missing references)
				//IL_00b7: Unknown result type (might be due to invalid IL or missing references)
				//IL_00bd: Unknown result type (might be due to invalid IL or missing references)
				//IL_00c2: Unknown result type (might be due to invalid IL or missing references)
				//IL_00c7: Unknown result type (might be due to invalid IL or missing references)
				//IL_00c9: Unknown result type (might be due to invalid IL or missing references)
				//IL_00ce: Unknown result type (might be due to invalid IL or missing references)
				//IL_00d3: 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_00eb: Expected O, but got Unknown
				//IL_0090: Unknown result type (might be due to invalid IL or missing references)
				//IL_0095: Unknown result type (might be due to invalid IL or missing references)
				try
				{
					float realtimeSinceStartup = Time.realtimeSinceStartup;
					if (!(realtimeSinceStartup - _lastNotificationTime < 0.3f))
					{
						_lastNotificationTime = realtimeSinceStartup;
						NotificationType val = type;
						Color val2 = (Color)((val - 1) switch
						{
							2 => new Color(0.3f, 0.95f, 0.4f), 
							0 => new Color(1f, 0.75f, 0.2f), 
							1 => new Color(1f, 0.3f, 0.3f), 
							_ => new Color(0.45f, 0.6f, 1f), 
						});
						Notifier.Send(new Notification
						{
							Title = new NotificationText(title, val2, false),
							Message = new NotificationText(message, Color.white, false),
							Type = type,
							PopupLength = duration,
							ShowTitleOnPopup = true
						});
					}
				}
				catch
				{
				}
			});
		}

		public static void ShowSuccess(string title, string message, float duration = 2f)
		{
			Show(title, message, (NotificationType)3, duration);
		}

		public static void ShowWarning(string title, string message, float duration = 2.5f)
		{
			Show(title, message, (NotificationType)1, duration);
		}

		public static void ShowError(string title, string message, float duration = 3f)
		{
			Show(title, message, (NotificationType)2, duration);
		}
	}
	public class VoiceInfo
	{
		public string Id { get; set; } = "";

		public string Name { get; set; } = "";

		public bool IsFavorite { get; set; }

		public VoiceInfo(string id, string name, bool isFavorite = false)
		{
			Id = id;
			Name = name;
			IsFavorite = isFavorite;
		}
	}
	public class VoicemodClient
	{
		private static VoicemodClient? _instance;

		private ClientWebSocket? _webSocket;

		private CancellationTokenSource? _cts;

		private readonly object _lock = new object();

		public static VoicemodClient Instance => _instance ?? (_instance = new VoicemodClient());

		public bool IsConnected
		{
			get
			{
				if (_webSocket != null)
				{
					return _webSocket.State == WebSocketState.Open;
				}
				return false;
			}
		}

		public bool IsConnecting { get; private set; }

		public string CurrentVoiceId { get; private set; } = "df6454f1-8eb2-4092-9ccc-fb51219f6291";

		public string CurrentVoiceName { get; private set; } = "Clean Mic";

		public bool IsVoiceChangerActive { get; private set; } = true;

		public bool IsHearMyselfActive { get; private set; }

		public bool IsMuteMicActive { get; private set; }

		public List<VoiceInfo> Voices { get; private set; } = new List<VoiceInfo>();

		public event Action? OnStatusChanged;

		public event Action? OnVoicesUpdated;

		public VoicemodClient()
		{
			Voices = VoicemodCollectionSync.LoadSyncedCollection();
			VoiceInfo voiceInfo = Voices.FirstOrDefault((VoiceInfo v) => v.Id.Equals(CurrentVoiceId, StringComparison.OrdinalIgnoreCase));
			if (voiceInfo != null)
			{
				CurrentVoiceName = voiceInfo.Name;
			}
		}

		public void SyncVoicesFromDisk()
		{
			Voices = VoicemodCollectionSync.LoadSyncedCollection();
			MainThreadDispatcher.Enqueue(delegate
			{
				this.OnVoicesUpdated?.Invoke();
				NotificationHelper.ShowSuccess("Voicemod", $"Synced {Voices.Count} voices!");
			});
		}

		public void ConnectAsync()
		{
			if (IsConnected || IsConnecting)
			{
				return;
			}
			Task.Run(async delegate
			{
				IsConnecting = true;
				NotifyStatusChanged();
				int value = ModConfig.VoicemodPort.Value;
				int[] obj = new int[4] { 0, 59125, 59126, 59127 };
				obj[0] = value;
				int[] source = obj;
				string[] pathsToTry = new string[3] { "/v1", "/vmsd", "" };
				int[] array = source.Distinct().ToArray();
				int[] array2 = array;
				foreach (int port in array2)
				{
					string[] array3 = pathsToTry;
					foreach (string value2 in array3)
					{
						try
						{
							Uri uri = new Uri($"ws://127.0.0.1:{port}{value2}");
							ClientWebSocket ws = new ClientWebSocket();
							using CancellationTokenSource timeoutCts = new CancellationTokenSource(TimeSpan.FromSeconds(2.0));
							await ws.ConnectAsync(uri, timeoutCts.Token);
							if (ws.State == WebSocketState.Open)
							{
								lock (_lock)
								{
									_webSocket = ws;
									_cts = new CancellationTokenSource();
								}
								IsConnecting = false;
								MelonLogger.Msg($"Connected successfully to Voicemod ({uri})!");
								MainThreadDispatcher.Enqueue(delegate
								{
									NotificationHelper.ShowSuccess("Voicemod", "Connected to Voicemod!");
								});
								NotifyStatusChanged();
								Task.Run(() => ReceiveLoopAsync(_cts.Token));
								await SendRawAsync("{\"action\":\"registerClient\",\"id\":\"init-client\",\"payload\":{\"clientKey\":\"bonelab-voicemaster\"}}");
								await SendRawAsync("{\"action\":\"registerPlugin\",\"id\":\"init-plugin\",\"payload\":{\"clientKey\":\"bonelab-voicemaster\"}}");
								await SendActionAsync("getVoices", "init-voices");
								await SendActionAsync("getCurrentVoice");
								await SendActionAsync("getVoiceChangerStatus");
								await SendActionAsync("getHearMyselfStatus");
								await SendActionAsync("getMuteMicStatus");
								return;
							}
						}
						catch
						{
						}
					}
				}
				IsConnecting = false;
				NotifyStatusChanged();
			});
		}

		public void Disconnect()
		{
			lock (_lock)
			{
				try
				{
					_cts?.Cancel();
					_webSocket?.Dispose();
				}
				catch
				{
				}
				finally
				{
					_webSocket = null;
					_cts = null;
					IsConnecting = false;
				}
			}
			NotifyStatusChanged();
		}

		private async Task ReceiveLoopAsync(CancellationToken token)
		{
			byte[] buffer = new byte[65536];
			while (!token.IsCancellationRequested && IsConnected)
			{
				try
				{
					WebSocketReceiveResult webSocketReceiveResult = await _webSocket.ReceiveAsync(new ArraySegment<byte>(buffer), token);
					if (webSocketReceiveResult.MessageType == WebSocketMessageType.Close)
					{
						break;
					}
					if (webSocketReceiveResult.MessageType == WebSocketMessageType.Text)
					{
						string json = Encoding.UTF8.GetString(buffer, 0, webSocketReceiveResult.Count);
						ProcessMessage(json);
					}
					continue;
				}
				catch
				{
				}
				break;
			}
			Disconnect();
			MainThreadDispatcher.Enqueue(delegate
			{
				NotificationHelper.ShowWarning("Voicemod", "Disconnected from Voicemod");
			});
		}

		private void ProcessMessage(string json)
		{
			try
			{
				JsonNode jsonNode = JsonNode.Parse(json);
				if (jsonNode == null)
				{
					return;
				}
				string text = jsonNode["action"]?.ToString() ?? jsonNode["actionId"]?.ToString() ?? "";
				if (text.Equals("getVoices", StringComparison.OrdinalIgnoreCase))
				{
					JsonArray jsonArray = jsonNode["payload"]?["voices"]?.AsArray() ?? jsonNode["payload"]?["items"]?.AsArray();
					if (jsonArray == null || jsonArray.Count <= 0)
					{
						return;
					}
					Dictionary<string, VoiceInfo> dictionary = new Dictionary<string, VoiceInfo>(StringComparer.OrdinalIgnoreCase);
					foreach (VoiceInfo voice in Voices)
					{
						dictionary[voice.Id] = voice;
					}
					foreach (JsonNode item in jsonArray)
					{
						string text2 = item?["id"]?.ToString() ?? item?["voiceID"]?.ToString() ?? "";
						string name = item?["friendlyName"]?.ToString() ?? item?["name"]?.ToString() ?? text2;
						bool valueOrDefault = item?["favorited"]?.GetValue<bool>() == true;
						if (!string.IsNullOrEmpty(text2))
						{
							dictionary[text2] = new VoiceInfo(text2, name, valueOrDefault);
						}
					}
					Voices = dictionary.Values.ToList();
					MelonLogger.Msg($"Voicemod WebSocket synced {Voices.Count} voices!");
					MainThreadDispatcher.Enqueue(delegate
					{
						this.OnVoicesUpdated?.Invoke();
					});
				}
				else if (text.Equals("voiceLoaded", StringComparison.OrdinalIgnoreCase) || text.Equals("voiceSelected", StringComparison.OrdinalIgnoreCase) || text.Equals("onVoiceChanged", StringComparison.OrdinalIgnoreCase) || text.Equals("voiceChangedEvent", StringComparison.OrdinalIgnoreCase) || text.Equals("getCurrentVoice", StringComparison.OrdinalIgnoreCase))
				{
					string text3 = jsonNode["payload"]?["voiceID"]?.ToString() ?? jsonNode["payload"]?["voiceId"]?.ToString() ?? jsonNode["payload"]?["id"]?.ToString() ?? jsonNode["payload"]?["currentVoice"]?.ToString() ?? "";
					if (!string.IsNullOrEmpty(text3))
					{
						string name2 = jsonNode["payload"]?["friendlyName"]?.ToString() ?? jsonNode["payload"]?["name"]?.ToString();
						SetCurrentVoiceLocal(text3, name2);
					}
				}
				else if (text.Equals("voiceChangerStatus", StringComparison.OrdinalIgnoreCase) || text.Equals("getVoiceChangerStatus", StringComparison.OrdinalIgnoreCase) || text.Equals("voiceChangerDisabledEvent", StringComparison.OrdinalIgnoreCase) || text.Equals("voiceChangerEnabledEvent", StringComparison.OrdinalIgnoreCase))
				{
					if (jsonNode["payload"]?["value"] != null)
					{
						IsVoiceChangerActive = jsonNode["payload"]["value"].GetValue<bool>();
					}
					else if (text.Contains("Enabled", StringComparison.OrdinalIgnoreCase))
					{
						IsVoiceChangerActive = true;
					}
					else if (text.Contains("Disabled", StringComparison.OrdinalIgnoreCase))
					{
						IsVoiceChangerActive = false;
					}
					NotifyStatusChanged();
				}
				else if (text.Equals("hearMySelfStatus", StringComparison.OrdinalIgnoreCase) || text.Equals("hearMyselfStatus", StringComparison.OrdinalIgnoreCase) || text.Equals("getHearMyselfStatus", StringComparison.OrdinalIgnoreCase) || text.Equals("hearMySelfDisabledEvent", StringComparison.OrdinalIgnoreCase) || text.Equals("hearMySelfEnabledEvent", StringComparison.OrdinalIgnoreCase))
				{
					if (jsonNode["payload"]?["value"] != null)
					{
						IsHearMyselfActive = jsonNode["payload"]["value"].GetValue<bool>();
					}
					else if (text.Contains("Enabled", StringComparison.OrdinalIgnoreCase))
					{
						IsHearMyselfActive = true;
					}
					else if (text.Contains("Disabled", StringComparison.OrdinalIgnoreCase))
					{
						IsHearMyselfActive = false;
					}
					NotifyStatusChanged();
				}
				else if (text.Equals("micMutedStatus", StringComparison.OrdinalIgnoreCase) || text.Equals("muteMicStatus", StringComparison.OrdinalIgnoreCase) || text.Equals("getMuteMicStatus", StringComparison.OrdinalIgnoreCase) || text.Equals("muteMicDisabledEvent", StringComparison.OrdinalIgnoreCase) || text.Equals("muteMicEnabledEvent", StringComparison.OrdinalIgnoreCase))
				{
					if (jsonNode["payload"]?["value"] != null)
					{
						IsMuteMicActive = jsonNode["payload"]["value"].GetValue<bool>();
					}
					else if (text.Contains("Enabled", StringComparison.OrdinalIgnoreCase))
					{
						IsMuteMicActive = true;
					}
					else if (text.Contains("Disabled", StringComparison.OrdinalIgnoreCase))
					{
						IsMuteMicActive = false;
					}
					NotifyStatusChanged();
				}
			}
			catch
			{
			}
		}

		public void SelectVoice(string voiceId, string? voiceName = null)
		{
			SetCurrentVoiceLocal(voiceId, voiceName);
			ModConfig.LastSelectedVoice.Value = voiceId;
			ModConfig.PrefCategory.SaveToFile(true);
			string currentVoiceName = CurrentVoiceName;
			MelonLogger.Msg($"Voicemod: Selected voice '{currentVoiceName}' ({voiceId})");
			NotificationHelper.ShowSuccess("Voicemod Voice", "Voice: " + currentVoiceName);
			if (!IsConnected)
			{
				ConnectAsync();
				return;
			}
			Task.Run(async delegate
			{
				await SendRawAsync("{\"action\":\"loadVoice\",\"payload\":{\"voiceID\":\"" + voiceId + "\"}}");
				await SendRawAsync("{\"action\":\"selectVoice\",\"payload\":{\"voiceId\":\"" + voiceId + "\"}}");
				await SendRawAsync("{\"actionId\":\"selectVoice\",\"resourceId\":\"" + voiceId + "\"}");
				if (voiceId.Equals("clean", StringComparison.OrdinalIgnoreCase) || voiceId.Equals("df6454f1-8eb2-4092-9ccc-fb51219f6291", StringComparison.OrdinalIgnoreCase))
				{
					await SendRawAsync("{\"action\":\"loadVoice\",\"payload\":{\"voiceID\":\"df6454f1-8eb2-4092-9ccc-fb51219f6291\"}}");
				}
			});
		}

		public void SelectRandomVoice()
		{
			if (Voices.Count != 0)
			{
				Random random = new Random();
				VoiceInfo voiceInfo = Voices[random.Next(Voices.Count)];
				SelectVoice(voiceInfo.Id, voiceInfo.Name);
			}
		}

		public void ToggleVoiceChanger()
		{
			IsVoiceChangerActive = !IsVoiceChangerActive;
			NotifyStatusChanged();
			NotificationHelper.Show("Voicemod", "Voice Changer: " + (IsVoiceChangerActive ? "ENABLED" : "DISABLED"), (NotificationType)0);
			Task.Run(async delegate
			{
				await SendActionAsync("toggleVoiceChanger");
				await SendRawAsync("{\"action\":\"toggleVoiceChanger\",\"payload\":{\"value\":" + IsVoiceChangerActive.ToString().ToLower() + "}}");
			});
		}

		public void ToggleHearMyself()
		{
			IsHearMyselfActive = !IsHearMyselfActive;
			NotifyStatusChanged();
			NotificationHelper.Show("Voicemod", "Hear Myself: " + (IsHearMyselfActive ? "ON" : "OFF"), (NotificationType)0);
			Task.Run(async delegate
			{
				await SendActionAsync("toggleHearMySelf");
				await SendActionAsync("toggleHearMyself");
			});
		}

		public void ToggleMute()
		{
			IsMuteMicActive = !IsMuteMicActive;
			NotifyStatusChanged();
			NotificationHelper.Show("Voicemod", "Voicemod Mic: " + (IsMuteMicActive ? "MUTED" : "UNMUTED"), (NotificationType)(IsMuteMicActive ? 1 : 3));
			Task.Run(async delegate
			{
				await SendActionAsync("toggleMuteMic");
				await SendActionAsync("toggleMute");
			});
		}

		private void SetCurrentVoiceLocal(string id, string? name = null)
		{
			CurrentVoiceId = id;
			VoiceInfo voiceInfo = Voices.FirstOrDefault((VoiceInfo v) => v.Id.Equals(id, StringComparison.OrdinalIgnoreCase));
			if (voiceInfo != null)
			{
				CurrentVoiceName = voiceInfo.Name;
			}
			else if (!string.IsNullOrEmpty(name))
			{
				CurrentVoiceName = name;
			}
			else
			{
				CurrentVoiceName = char.ToUpperInvariant(id[0]) + ((id.Length > 1) ? id.Substring(1) : "");
			}
			NotifyStatusChanged();
		}

		private void NotifyStatusChanged()
		{
			MainThreadDispatcher.Enqueue(delegate
			{
				this.OnStatusChanged?.Invoke();
			});
		}

		private async Task SendActionAsync(string action, string? id = null)
		{
			string value = id ?? Guid.NewGuid().ToString("N");
			string json = $"{{\"action\":\"{action}\",\"id\":\"{value}\"}}";
			await SendRawAsync(json);
		}

		private async Task SendRawAsync(string json)
		{
			if (!IsConnected)
			{
				return;
			}
			try
			{
				byte[] bytes = Encoding.UTF8.GetBytes(json);
				await _webSocket.SendAsync(new ArraySegment<byte>(bytes), WebSocketMessageType.Text, endOfMessage: true, CancellationToken.None);
			}
			catch
			{
			}
		}
	}
	public static class VoicemodCollectionSync
	{
		public static readonly (string Id, string Name, bool Fav)[] KnownV3Voices = new(string, string, bool)[11]
		{
			("df6454f1-8eb2-4092-9ccc-fb51219f6291", "Clean Mic", true),
			("372d1db4-9b06-4e48-a3d2-bfd9138fc838", "Golden Bunny", true),
			("63db9115-a6c0-4de3-9494-827022d481ed", "Scary Teddy", true),
			("6d3b8cf4-6b81-4f12-a4ba-64c8ba52e115", "Rockstar Wolf", true),
			("7423ae58-089e-43b6-848d-92596a042a95", "Mei", false),
			("0bc99416-c142-4617-b081-51b34b4bf859", "Airi", false),
			("80fa04a9-ac43-4526-a120-45aa8bf006dc", "Florie", false),
			("610ecfdd-e030-4ebf-8cfb-28b3420e294d", "Rune", false),
			("7a680449-69ce-4056-bc31-020a656e8658", "Streamer Mic", false),
			("f604c108-6348-44df-91cb-48cfce3ec8a3", "Better Mic 4K", true),
			("cce9c495-a29b-44de-ad9a-b9147bd37636", "Voice Enhancer", false)
		};

		public static List<VoiceInfo> LoadSyncedCollection()
		{
			Dictionary<string, VoiceInfo> dictionary = new Dictionary<string, VoiceInfo>(StringComparer.OrdinalIgnoreCase);
			(string, string, bool)[] knownV3Voices = KnownV3Voices;
			for (int i = 0; i < knownV3Voices.Length; i++)
			{
				(string, string, bool) tuple = knownV3Voices[i];
				string item = tuple.Item1;
				string item2 = tuple.Item2;
				bool item3 = tuple.Item3;
				dictionary[item] = new VoiceInfo(item, item2, item3);
			}
			try
			{
				string path = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "VoicemodV3", "logs", "voicemod-desktop.log");
				if (File.Exists(path))
				{
					using FileStream stream = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
					using StreamReader streamReader = new StreamReader(stream);
					string text = null;
					string text2;
					while ((text2 = streamReader.ReadLine()) != null)
					{
						if (text2.Contains("Loading a voice, voice_id="))
						{
							Match match = Regex.Match(text2, "voice_id=([a-f0-9-]{36}),\\s*last_voice_id=([a-f0-9-]{36})");
							if (match.Success)
							{
								text = match.Groups[2].Value;
							}
						}
						else
						{
							if (text == null || !text2.Contains("Voice Unselected event enqueued for voice '"))
							{
								continue;
							}
							Match match2 = Regex.Match(text2, "Voice Unselected event enqueued for voice '([^']+)'");
							if (match2.Success)
							{
								string value = match2.Groups[1].Value;
								if (!dictionary.ContainsKey(text))
								{
									dictionary[text] = new VoiceInfo(text, value);
									MelonLogger.Msg($"[VoicemodSync] Discovered voice from log: '{value}' ({text})");
								}
							}
							text = null;
						}
					}
				}
			}
			catch (Exception ex)
			{
				MelonLogger.Warning("[VoicemodSync] Log scan notice: " + ex.Message);
			}
			(string, string)[] array = new(string, string)[14]
			{
				("clean", "Clean (Normal)"),
				("robot", "Robot"),
				("cave", "Cave"),
				("titan", "Titan"),
				("magic-chords", "Magic Chords"),
				("baby", "Baby"),
				("alien", "Alien"),
				("chipmunk", "Chipmunk"),
				("demon", "Demon"),
				("cyberpunk", "Cyberpunk"),
				("spaceman", "Spaceman"),
				("radio", "Radio"),
				("megaphone", "Megaphone"),
				("autotune", "Voicetune / Autotune")
			};
			for (int i = 0; i < array.Length; i++)
			{
				var (text3, name) = array[i];
				if (!dictionary.ContainsKey(text3))
				{
					dictionary[text3] = new VoiceInfo(text3, name);
				}
			}
			List<VoiceInfo> list = new List<VoiceInfo>(dictionary.Values);
			MelonLogger.Msg($"[VoicemodSync] Synchronized {list.Count} voices for Voicemod collection.");
			return list;
		}
	}
}