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