using System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.Globalization; using System.IO; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Security; using System.Security.Permissions; using System.Text; using System.Threading.Tasks; using BepInEx; using BepInEx.Bootstrap; using BepInEx.Configuration; using BepInEx.Logging; using ConcentusUnity; using ConcentusUnity.Enums; using GameNetcodeStuff; using HarmonyLib; using LethalConfig; using LethalConfig.ConfigItems; using LethalConfig.ConfigItems.Options; using LethalConfig.Mods; using Microsoft.CodeAnalysis; using Mirage.Domain.Audio; using NAudio.Wave; using NAudio.Wave.SampleProviders; using Newtonsoft.Json; using Newtonsoft.Json.Linq; using Unity.Netcode; using UnityEngine; using UnityEngine.Networking; using com.github.zehsteam.MelaniesVoice.Dependencies; using com.github.zehsteam.MelaniesVoice.Extensions; using com.github.zehsteam.MelaniesVoice.Helpers; using com.github.zehsteam.MelaniesVoice.Managers; using com.github.zehsteam.MelaniesVoice.MonoBehaviours; using com.github.zehsteam.MelaniesVoice.NetcodePatcher; using com.github.zehsteam.MelaniesVoice.Objects; using com.github.zehsteam.MelaniesVoice.Objects.Config; using com.github.zehsteam.MelaniesVoice.Objects.Voices; using com.github.zehsteam.MelaniesVoice.Patches; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: IgnoresAccessChecksTo("LethalConfig")] [assembly: IgnoresAccessChecksTo("Mirage.Plugin")] [assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")] [assembly: AssemblyCompany("com.github.zehsteam.MelaniesVoice")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyCopyright("Copyright © 2026 Zehs")] [assembly: AssemblyDescription("Allows players to talk through Text-To-Speech (TTS) by using the in-game chat.")] [assembly: AssemblyFileVersion("1.8.0.0")] [assembly: AssemblyInformationalVersion("1.8.0+25468e206f88204920e29374219961e1373e71ba")] [assembly: AssemblyProduct("MelaniesVoice")] [assembly: AssemblyTitle("com.github.zehsteam.MelaniesVoice")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("1.8.0.0")] [module: UnverifiableCode] [module: RefSafetyRules(11)] [module: NetcodePatchedAssembly] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)] internal sealed class RefSafetyRulesAttribute : Attribute { public readonly int Version; public RefSafetyRulesAttribute(int P_0) { Version = P_0; } } } namespace com.github.zehsteam.MelaniesVoice { internal static class Assets { public static readonly string AssetBundleFileName = "melaniesvoice_assets"; public static AssetBundle AssetBundle { get; private set; } public static bool IsLoaded { get; private set; } public static GameObject VoiceControllerPrefab { get; private set; } public static void Load() { string directoryName = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location); string text = Path.Combine(directoryName, AssetBundleFileName); if (!File.Exists(text)) { Logger.LogFatal("Failed to load assets. AssetBundle file could not be found at path \"" + text + "\". Make sure the \"" + AssetBundleFileName + "\" file is in the same folder as the mod's DLL file."); } else { AssetBundle = AssetBundle.LoadFromFile(text); if ((Object)(object)AssetBundle == (Object)null) { Logger.LogFatal("Failed to load assets. AssetBundle is null."); return; } OnAssetBundleLoaded(AssetBundle); IsLoaded = true; } } private static void OnAssetBundleLoaded(AssetBundle assetBundle) { VoiceControllerPrefab = LoadAsset("VoiceController", assetBundle); } private static T LoadAsset(string name, AssetBundle assetBundle) where T : Object { if (string.IsNullOrWhiteSpace(name)) { Logger.LogError("Failed to load asset of type \"" + typeof(T).Name + "\" from AssetBundle. Name is null or whitespace."); return default(T); } if ((Object)(object)assetBundle == (Object)null) { Logger.LogError("Failed to load asset of type \"" + typeof(T).Name + "\" with name \"" + name + "\" from AssetBundle. AssetBundle is null."); return default(T); } T val = assetBundle.LoadAsset(name); if ((Object)(object)val == (Object)null) { Logger.LogError("Failed to load asset of type \"" + typeof(T).Name + "\" with name \"" + name + "\" from AssetBundle. No asset found with that type and name."); return default(T); } return val; } private static bool TryLoadAsset(string name, AssetBundle assetBundle, out T asset) where T : Object { asset = LoadAsset(name, assetBundle); return (Object)(object)asset != (Object)null; } } internal static class Utils { public static string GetPluginPersistentDataPath() { return Path.Combine(Application.persistentDataPath, "MelaniesVoice"); } public static ConfigFile CreateConfigFile(BaseUnityPlugin plugin, string path, string name = null, bool saveOnInit = false) { //IL_0028: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Expected O, but got Unknown BepInPlugin metadata = MetadataHelper.GetMetadata((object)plugin); if (name == null) { name = metadata.GUID; } name += ".cfg"; return new ConfigFile(Path.Combine(path, name), saveOnInit, metadata); } public static ConfigFile CreateLocalConfigFile(BaseUnityPlugin plugin, string name = null, bool saveOnInit = false) { return CreateConfigFile(plugin, Paths.ConfigPath, name, saveOnInit); } public static ConfigFile CreateGlobalConfigFile(BaseUnityPlugin plugin, string name = null, bool saveOnInit = false) { string pluginPersistentDataPath = GetPluginPersistentDataPath(); if (name == null) { name = "global"; } return CreateConfigFile(plugin, pluginPersistentDataPath, name, saveOnInit); } public static IEnumerator WaitForTask(Task task, Action result) { while (!task.IsCompleted) { yield return null; } if (task.IsFaulted) { throw task.Exception; } result?.Invoke(task.Result); } public static string SanitizeFileName(string input) { char[] invalidChars = Path.GetInvalidFileNameChars(); return string.Concat(input.Where((char c) => !invalidChars.Contains(c))); } public static void DisplayMessage(string text, bool isError = false) { string text2 = "MelaniesVoice"; if (isError) { text2 += " - ERROR"; } HUDManager instance = HUDManager.Instance; if (instance != null) { instance.DisplayTip(text2, text, isError, false, "LC_Tip1"); } } } internal static class Logger { public static ManualLogSource ManualLogSource { get; private set; } public static bool IsExtendedLoggingEnabled => ConfigManager.Misc_ExtendedLogging?.Value ?? false; public static void Initialize(ManualLogSource manualLogSource) { ManualLogSource = manualLogSource; } public static void LogDebug(object data) { Log((LogLevel)32, data); } public static void LogInfo(object data, bool extended = false) { Log((LogLevel)16, data, extended); } public static void LogMessage(object data, bool extended = false) { Log((LogLevel)8, data, extended); } public static void LogWarning(object data, bool extended = false) { Log((LogLevel)4, data, extended); } public static void LogError(object data, bool extended = false) { Log((LogLevel)2, data, extended); } public static void LogFatal(object data, bool extended = false) { Log((LogLevel)1, data, extended); } public static void Log(LogLevel logLevel, object data, bool extended = false) { //IL_0015: Unknown result type (might be due to invalid IL or missing references) if (!extended || IsExtendedLoggingEnabled) { ManualLogSource manualLogSource = ManualLogSource; if (manualLogSource != null) { manualLogSource.Log(logLevel, data); } } } } [BepInPlugin("com.github.zehsteam.MelaniesVoice", "MelaniesVoice", "1.8.0")] [BepInDependency(/*Could not decode attribute arguments.*/)] [BepInDependency(/*Could not decode attribute arguments.*/)] internal class Plugin : BaseUnityPlugin { private readonly Harmony _harmony = new Harmony("com.github.zehsteam.MelaniesVoice"); public static Plugin Instance { get; private set; } public ConfigFile Config { get; private set; } private void Awake() { Instance = this; Logger.Initialize(Logger.CreateLogSource("com.github.zehsteam.MelaniesVoice")); Logger.LogInfo("MelaniesVoice has awoken!"); Config = Utils.CreateGlobalConfigFile((BaseUnityPlugin)(object)this); ConfigManager.Initialize(Config); _harmony.PatchAll(typeof(GameNetworkManager_Patches)); _harmony.PatchAll(typeof(StartOfRound_Patches)); _harmony.PatchAll(typeof(HUDManager_Patches)); _harmony.PatchAll(typeof(PlayerControllerB_Patches)); Assets.Load(); NetworkUtils.NetcodePatcherAwake(); } } public static class MyPluginInfo { public const string PLUGIN_GUID = "com.github.zehsteam.MelaniesVoice"; public const string PLUGIN_NAME = "MelaniesVoice"; public const string PLUGIN_VERSION = "1.8.0"; } } namespace com.github.zehsteam.MelaniesVoice.Patches { [HarmonyPatch(typeof(GameNetworkManager))] internal static class GameNetworkManager_Patches { [HarmonyPatch("Start")] [HarmonyPostfix] private static void Start_Patch() { AddNetworkPrefabs(); TTSVoice_TTSMonster.FetchVoices(); } private static void AddNetworkPrefabs() { AddNetworkPrefab(Assets.VoiceControllerPrefab); } private static void AddNetworkPrefab(GameObject prefab) { if ((Object)(object)prefab == (Object)null) { Logger.LogError("Failed to register network prefab. GameObject is null."); return; } NetworkManager.Singleton.AddNetworkPrefab(prefab); Logger.LogInfo("Registered \"" + ((Object)prefab).name + "\" network prefab."); } } [HarmonyPatch(typeof(HUDManager))] internal static class HUDManager_Patches { [HarmonyPatch("AddTextToChatOnServer")] [HarmonyPostfix] private static void AddTextToChatOnServer_Patch(string chatMessage, int playerId) { //IL_004a: 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) if (playerId != -1 && !ConfigManager.TTS_DisableMyVoice.Value && !chatMessage.StartsWithAny(ConfigManager.TTS_IgnorePefixesArray) && PlayerUtils.TryGetLocalPlayerScript(out var playerScript)) { VoiceController componentInChildren = ((Component)playerScript).GetComponentInChildren(); if (!((Object)(object)componentInChildren == (Object)null)) { componentInChildren.CreateVoiceMessage_ServerRpc(ConfigManager.TTS_Voice.Value, chatMessage); } } } } [HarmonyPatch(typeof(PlayerControllerB))] internal static class PlayerControllerB_Patches { [HarmonyPatch("Start")] [HarmonyPostfix] private static void Start_Patch(PlayerControllerB __instance) { if (NetworkUtils.IsServer) { GameObject val = Object.Instantiate(Assets.VoiceControllerPrefab, ((Component)__instance).transform); NetworkObject component = val.GetComponent(); component.DontDestroyWithOwner = true; component.SpawnWithOwnership(__instance.actualClientId, false); component.TrySetParent(((Component)__instance).transform, true); } } [HarmonyPatch("OnDestroy")] [HarmonyPrefix] private static void OnDestroy_Patch(PlayerControllerB __instance) { if (NetworkUtils.IsServer) { VoiceController componentInChildren = ((Component)__instance).GetComponentInChildren(); NetworkObject val = default(NetworkObject); if (!((Object)(object)componentInChildren == (Object)null) && ((Component)componentInChildren).TryGetComponent(ref val) && val.IsSpawned) { val.Despawn(true); } } } } [HarmonyPatch(typeof(StartOfRound))] internal static class StartOfRound_Patches { [HarmonyPatch("OnClientConnect")] [HarmonyPostfix] private static void OnClientConnect_Patch(ulong clientId) { PlayerControllerB playerScriptByClientId = PlayerUtils.GetPlayerScriptByClientId(clientId); if (!((Object)(object)playerScriptByClientId == (Object)null)) { VoiceController componentInChildren = ((Component)playerScriptByClientId).GetComponentInChildren(); NetworkObject val = default(NetworkObject); if (!((Object)(object)componentInChildren == (Object)null) && ((Component)componentInChildren).TryGetComponent(ref val) && val.IsSpawned) { val.ChangeOwnership(playerScriptByClientId.actualClientId); } } } } } namespace com.github.zehsteam.MelaniesVoice.Objects { public class OpusCodec { private readonly IOpusEncoder _encoder; private readonly IOpusDecoder _decoder; private readonly int _channels; private readonly int _sampleRate; public OpusCodec(int sampleRate, int channels) { _sampleRate = sampleRate; _channels = channels; _encoder = OpusCodecFactory.CreateEncoder(sampleRate, channels, (OpusApplication)2048, (TextWriter)null); _encoder.Bitrate = 24000; _decoder = OpusCodecFactory.CreateDecoder(sampleRate, channels, (TextWriter)null); } public byte[] Encode(float[] pcmChunk) { int num = pcmChunk.Length / _channels; byte[] array = new byte[4000]; int num2 = _encoder.Encode((ReadOnlySpan)pcmChunk.AsSpan(0, pcmChunk.Length), num, array.AsSpan(), array.Length); byte[] array2 = new byte[num2]; Array.Copy(array, array2, num2); return array2; } public float[] Decode(byte[] opusPacket) { float[] array = new float[5760 * _channels]; int num = _decoder.Decode((ReadOnlySpan)opusPacket.AsSpan(), array.AsSpan(), 5760, false); float[] array2 = new float[num * _channels]; Array.Copy(array, array2, array2.Length); return array2; } } public class PlayerAudioGroup { public AudioSource VoiceAudio { get; private set; } public AudioSource DeadAudio { get; private set; } public bool IsPlaying => VoiceAudio.isPlaying; public float Volume { get { return VoiceAudio.volume; } set { VoiceAudio.volume = value; DeadAudio.volume = value; } } public float MaxDistance { get { return VoiceAudio.maxDistance; } set { VoiceAudio.maxDistance = value; DeadAudio.maxDistance = value; } } public AudioClip Clip { get { return VoiceAudio.clip; } set { VoiceAudio.clip = value; DeadAudio.clip = value; } } public bool Mute { get { if (VoiceAudio.mute) { return DeadAudio.mute; } return false; } set { VoiceAudio.mute = value; DeadAudio.mute = value; } } public PlayerAudioGroup(AudioSource voiceAudio, AudioSource deadAudio) { VoiceAudio = voiceAudio; DeadAudio = deadAudio; } public void Play() { AudioSource voiceAudio = VoiceAudio; if (voiceAudio != null) { voiceAudio.Play(); } AudioSource deadAudio = DeadAudio; if (deadAudio != null) { deadAudio.Play(); } } public void Pause() { AudioSource voiceAudio = VoiceAudio; if (voiceAudio != null) { voiceAudio.Pause(); } AudioSource deadAudio = DeadAudio; if (deadAudio != null) { deadAudio.Pause(); } } public void Stop() { AudioSource voiceAudio = VoiceAudio; if (voiceAudio != null) { voiceAudio.Stop(); } AudioSource deadAudio = DeadAudio; if (deadAudio != null) { deadAudio.Stop(); } } } public struct RequestHeader { public string Name { get; set; } public string Value { get; set; } public RequestHeader(string name, string value) { Name = name; Value = value; } } public class VoiceMessage { public int Channels = 1; public int SampleRate = 48000; private float _timer; public int Id { get; private set; } public string VoiceName { get; private set; } public string Message { get; private set; } public AudioClip AudioClip { get; set; } public List ClientsReceivedAudioClip { get; private set; } = new List(); public OpusCodec Codec { get; private set; } public List BufferedSamples { get; private set; } = new List(); public bool IsClipBuilt { get; private set; } public bool HasBufferedAudio => BufferedSamples.Count > 0; public bool IsReady { get { if (!ClientsReceivedAudioClip.Contains(NetworkUtils.LocalClientId)) { return false; } return ClientsReceivedAudioClip.Count >= NetworkUtils.ConnectedPlayerCount; } } public bool IsTimedout => _timer >= ConfigManager.TTS_RequestTimeoutDuration.Value; public VoiceMessage(int id, string voiceName, string message) { Id = id; VoiceName = voiceName; Message = message; } public void InitCodec(int sampleRate, int channels) { SampleRate = sampleRate; Channels = channels; Codec = new OpusCodec(sampleRate, channels); } public void Tick() { _timer += Time.deltaTime; } public void AddOpusPacket(byte[] opusPacket) { float[] collection = Codec.Decode(opusPacket); BufferedSamples.AddRange(collection); } public void BuildClipIfNeeded() { if (!IsClipBuilt && BufferedSamples.Count != 0) { AudioClip = AudioClip.Create(string.Format("{0}_{1}", "VoiceMessage", Id), BufferedSamples.Count / Channels, Channels, SampleRate, false); AudioClip.SetData(BufferedSamples.ToArray(), 0); IsClipBuilt = true; } } public override string ToString() { return string.Format("({0}: {1}, {2}: \"{3}\", {4}: \"{5}\")", "Id", Id, "VoiceName", VoiceName, "Message", Message); } } } namespace com.github.zehsteam.MelaniesVoice.Objects.Voices { public enum VoiceService { Unknown = -1, Streamlabs, LazyPy, TTSMonster } public abstract class TTSVoice { protected const int DEFAULT_VOLUME = 100; protected static string UserAgent = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/139.0.0.0 Safari/537.36 OPR/123.0.0.0"; public string Name { get; protected set; } public string VoiceId { get; protected set; } public int DefaultVolume { get; protected set; } = 100; public abstract VoiceService Service { get; } protected TTSVoice(string name, string voiceId, int defaultVolume = 100) { Name = name; VoiceId = voiceId; DefaultVolume = defaultVolume; } public virtual void RequestAudio(string text, Action onClipReady) { CoroutineRunner.Start(RequestAudioCoroutine(text, onClipReady)); } public abstract IEnumerator RequestAudioCoroutine(string text, Action onClipReady); protected async Task FetchJsonAsync(string url, WWWForm form, List requestHeaders = null) { LogInfo("Sending POST request to \"" + url + "\"", extended: true); UnityWebRequest www = UnityWebRequest.Post(url, form); try { www.SetRequestHeader("User-Agent", UserAgent); if (requestHeaders != null) { foreach (RequestHeader requestHeader in requestHeaders) { www.SetRequestHeader(requestHeader.Name, requestHeader.Value); } } UnityWebRequestAsyncOperation operation = www.SendWebRequest(); while (!((AsyncOperation)operation).isDone) { await Task.Yield(); } if ((int)www.result == 4) { LogError("Failed to process data: " + www.error, extended: false, displayMessage: true); return null; } if ((int)www.result != 1) { LogError("Failed to fetch audio: " + www.error, extended: false, displayMessage: true); return null; } string text = www.downloadHandler.text; try { JObject val = JObject.Parse(text); LogInfo("Response data:\n" + JsonConvert.SerializeObject((object)val, (Formatting)1), extended: true); return val; } catch (Exception arg) { LogError($"Failed to parse response as JSON:\n\nResponse:\n\"{text}\"\n\nError:\n{arg}"); DisplayMessage("Failed to parse response. Check logs", isError: true); return null; } } finally { ((IDisposable)www)?.Dispose(); } } protected async Task FetchJsonAsync(string url, JObject body, List requestHeaders = null) { LogInfo("Sending POST request to \"" + url + "\"", extended: true); string s = ((body != null) ? ((JToken)body).ToString((Formatting)0, Array.Empty()) : "{}"); byte[] bytes = Encoding.UTF8.GetBytes(s); UnityWebRequest www = new UnityWebRequest(url, "POST"); try { www.uploadHandler = (UploadHandler)new UploadHandlerRaw(bytes); www.downloadHandler = (DownloadHandler)new DownloadHandlerBuffer(); www.SetRequestHeader("Content-Type", "application/json"); www.SetRequestHeader("User-Agent", UserAgent); if (requestHeaders != null) { foreach (RequestHeader requestHeader in requestHeaders) { www.SetRequestHeader(requestHeader.Name, requestHeader.Value); } } UnityWebRequestAsyncOperation operation = www.SendWebRequest(); while (!((AsyncOperation)operation).isDone) { await Task.Yield(); } if ((int)www.result == 4) { LogError("Failed to process data: " + www.error, extended: false, displayMessage: true); return null; } if ((int)www.result != 1) { LogError("Failed to fetch audio: " + www.error, extended: false, displayMessage: true); LogError(www.downloadHandler.text, extended: true); return null; } string text = www.downloadHandler.text; try { JObject val = JObject.Parse(text); LogInfo("Response data:\n" + JsonConvert.SerializeObject((object)val, (Formatting)1), extended: true); return val; } catch (Exception arg) { LogError($"Failed to parse response as JSON:\n\nResponse:\n\"{text}\"\n\nError:\n{arg}"); DisplayMessage("Failed to parse response. Check logs", isError: true); return null; } } finally { ((IDisposable)www)?.Dispose(); } } protected async Task DownloadAudioClipAsync(string url, AudioType audioType = (AudioType)13) { //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_001f: Unknown result type (might be due to invalid IL or missing references) LogInfo("Sending GET request to \"" + url + "\"", extended: true); UnityWebRequest www = UnityWebRequestMultimedia.GetAudioClip(url, audioType); try { www.SetRequestHeader("User-Agent", UserAgent); UnityWebRequestAsyncOperation operation = www.SendWebRequest(); while (!((AsyncOperation)operation).isDone) { await Task.Yield(); } if ((int)www.result != 1) { LogError("Failed to download audio: " + www.error, extended: false, displayMessage: true); return null; } try { AudioClip content = DownloadHandlerAudioClip.GetContent(www); ((Object)content).name = string.Format("{0}_{1}_{2}", "MelaniesVoice", Utils.SanitizeFileName(Name), Guid.NewGuid()); return content; } catch (Exception ex) { LogError("Failed to download audio: " + ex.Message, extended: false, displayMessage: true); return null; } } finally { ((IDisposable)www)?.Dispose(); } } protected void DisplayMessage(string text, bool isError = false) { Utils.DisplayMessage(text, isError); } public override string ToString() { return $"(Name: \"{Name}\", Service: {Service}, VoiceId: \"{VoiceId}\")"; } protected void Log(LogLevel logLevel, object data, bool extended = false, bool displayMessage = false) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Unknown result type (might be due to invalid IL or missing references) //IL_0030: Invalid comparison between Unknown and I4 Logger.Log(logLevel, $"[{GetType().Name}] [{Name}] {data}", extended); if (displayMessage) { DisplayMessage(data.ToString(), (int)logLevel == 2); } } protected void LogInfo(object data, bool extended = false, bool displayMessage = false) { Log((LogLevel)16, data, extended, displayMessage); } protected void LogWarning(object data, bool extended = false, bool displayMessage = false) { Log((LogLevel)4, data, extended, displayMessage); } protected void LogError(object data, bool extended = false, bool displayMessage = false) { Log((LogLevel)2, data, extended, displayMessage); } } public class TTSVoice_LazyPy : TTSVoice { public override VoiceService Service => VoiceService.LazyPy; public string RedirectService { get; protected set; } public TTSVoice_LazyPy(string name, string redirectService, string voiceId, int defaultVolume = 100) : base(name, voiceId, defaultVolume) { RedirectService = redirectService; } public override IEnumerator RequestAudioCoroutine(string text, Action onClipReady) { string url = "https://lazypy.ro/tts/request_tts.php"; WWWForm val = new WWWForm(); val.AddField("service", RedirectService); val.AddField("voice", base.VoiceId); val.AddField("text", text); Task task = FetchJsonAsync(url, val); JObject responseJson = null; yield return Utils.WaitForTask(task, delegate(JObject result) { responseJson = result; }); if (responseJson == null) { LogError("Failed to request audio. Response from server is invalid."); onClipReady?.Invoke(null); yield break; } JToken obj = responseJson["success"]; if (obj == null || !obj.ToObject()) { string text2 = ((object)responseJson["error_msg"])?.ToString(); LogError("Failed to fetch audio: " + text2); DisplayMessage(text2, isError: true); onClipReady?.Invoke(null); yield break; } string text3 = ((object)responseJson["audio_url"])?.ToString(); if (string.IsNullOrEmpty(text3)) { LogError("Failed to fetch audio: 'audio_url' is missing.", extended: false, displayMessage: true); onClipReady?.Invoke(null); yield break; } Task task2 = DownloadAudioClipAsync(text3, (AudioType)13); yield return Utils.WaitForTask(task2, delegate(AudioClip clip) { onClipReady?.Invoke(clip); }); } } public class TTSVoice_Streamlabs : TTSVoice { public override VoiceService Service => VoiceService.Streamlabs; public TTSVoice_Streamlabs(string name, string voiceId, int defaultVolume = 100) : base(name, voiceId, defaultVolume) { } public override IEnumerator RequestAudioCoroutine(string text, Action onClipReady) { string url = "https://streamlabs.com/tts/polly/speak"; WWWForm val = new WWWForm(); val.AddField("voice", base.VoiceId); val.AddField("text", text); Task task = FetchJsonAsync(url, val); JObject responseJson = null; yield return Utils.WaitForTask(task, delegate(JObject result) { responseJson = result; }); if (responseJson == null) { LogError("Failed to request audio. Response from server is invalid."); onClipReady?.Invoke(null); yield break; } JToken obj = responseJson["success"]; if (obj == null || !obj.ToObject()) { string text2 = ((object)responseJson["message"])?.ToString(); LogError("Failed to fetch audio: " + (object)responseJson["message"]); DisplayMessage(text2, isError: true); onClipReady?.Invoke(null); yield break; } string text3 = ((object)responseJson["speak_url"])?.ToString(); if (string.IsNullOrEmpty(text3)) { LogError("Failed to fetch audio: 'speak_url' is missing.", extended: false, displayMessage: true); onClipReady?.Invoke(null); yield break; } Task task2 = DownloadAudioClipAsync(text3, (AudioType)13); yield return Utils.WaitForTask(task2, delegate(AudioClip clip) { onClipReady?.Invoke(clip); }); } } public class TTSVoice_TTSMonster : TTSVoice { private static readonly Dictionary _voiceNameProxies; public override VoiceService Service => VoiceService.TTSMonster; static TTSVoice_TTSMonster() { _voiceNameProxies = new Dictionary(); _voiceNameProxies.Add("Chef", "Gordon Ramsay"); _voiceNameProxies.Add("Circuit", "Linus Tech Tips"); _voiceNameProxies.Add("Dash", "Sonic"); _voiceNameProxies.Add("Diplomat", "Joe Biden"); _voiceNameProxies.Add("Elder", "Morgan Freeman"); _voiceNameProxies.Add("Frogman", "Kermit"); _voiceNameProxies.Add("Gravel", "MoistCr1TiKaL"); _voiceNameProxies.Add("Leader", "Obama"); _voiceNameProxies.Add("Micro", "Plankton"); _voiceNameProxies.Add("Oracle", "GLaDOS"); _voiceNameProxies.Add("Phantom", "Vega"); _voiceNameProxies.Add("Scout", "Bart Simpson"); _voiceNameProxies.Add("Spongey", "Sponge Bob"); _voiceNameProxies.Add("Star", "Patrick Star"); _voiceNameProxies.Add("Tentacle", "Squidward"); _voiceNameProxies.Add("Tycoon", "Donald Trump"); } public TTSVoice_TTSMonster(string name, string voiceId, int defaultVolume = 100) : base(name, voiceId, defaultVolume) { } public override IEnumerator RequestAudioCoroutine(string text, Action onClipReady) { string url = "https://api.console.tts.monster/generate"; string value = ConfigManager.TTSMonster_APIKey.Value; if (string.IsNullOrEmpty(value)) { LogError("TTS.Monster API key required. Set in config file.", extended: false, displayMessage: true); onClipReady?.Invoke(null); yield break; } List requestHeaders = new List(1) { new RequestHeader("Authorization", value) }; JObject body = new JObject { ["voice_id"] = JToken.op_Implicit(base.VoiceId), ["message"] = JToken.op_Implicit(text) }; Task task = FetchJsonAsync(url, body, requestHeaders); JObject responseJson = null; yield return Utils.WaitForTask(task, delegate(JObject result) { responseJson = result; }); if (responseJson == null) { LogError("Failed to request audio. Response from server is invalid."); onClipReady?.Invoke(null); yield break; } JToken obj = responseJson["status"]; int num = ((obj != null) ? obj.ToObject() : 0); if (num != 200) { string text2 = num switch { 401 => "Unauthorized: Invalid API key", 402 => "Character quota exceeded. Upgrade your account or turn on usage-based-billing", 429 => "Too many requests. Try again later", 500 => "Internal server error", _ => $"Unknown error. Code {num}", }; LogError("Failed to fetch audio: " + text2); DisplayMessage(text2, isError: true); onClipReady?.Invoke(null); yield break; } string text3 = ((object)responseJson["url"])?.ToString(); if (string.IsNullOrEmpty(text3)) { LogError("Failed to fetch audio: 'url' is missing.", extended: false, displayMessage: true); onClipReady?.Invoke(null); yield break; } Task task2 = DownloadAudioClipAsync(text3, (AudioType)20); yield return Utils.WaitForTask(task2, delegate(AudioClip clip) { onClipReady?.Invoke(clip); }); } public static List CreateDefaultVoices() { try { JObject val = PluginResourceHelper.ReadJObject("Data/TTSMonsterVoicesDefault.json"); if (val == null) { return new List(); } return ConvertToTTSVoices(ParseVoicesJson(val)); } catch (Exception arg) { StaticLogError($"Failed to load default voices. {arg}"); return new List(); } } public static void FetchVoices() { CoroutineRunner.Start(FetchVoicesCoroutine()); } public static IEnumerator FetchVoicesCoroutine() { string value = ConfigManager.TTSMonster_APIKey.Value; if (string.IsNullOrEmpty(value)) { StaticLogError("Failed to fetch voices. TTS.Monster API key required. Set in config file."); yield break; } Task task = FetchVoicesJsonAsync(value); JObject responseJson = null; yield return Utils.WaitForTask(task, delegate(JObject result) { responseJson = result; }); if (responseJson == null) { StaticLogError("Failed to fetch voices. Response from server is invalid."); yield break; } List list = ParseVoicesJson(responseJson); if (list.Count == 0) { StaticLogError("Failed to fetch voices. No voices found from response data."); yield break; } List list2 = ConvertToTTSVoices(list); if (list2.Count == 0) { StaticLogError("Failed to fetch voices. Could not convert TTSMonsterVoice(s) to TTSVoice_TTSMonster(s)"); yield break; } UpdateExistingVoicesData(list2); List list3 = TextToSpeech.AddVoices(list2, logErrors: false); if (list3.Count > 0) { VoiceConfigManager.BindConfigs(list3); ConfigManager.UpdateTTSVoiceAcceptableValues(); } StaticLogInfo($"Found {list.Count} voices. Registered {list3.Count} new voices."); } protected static async Task FetchVoicesJsonAsync(string apiKey) { string text = "https://api.console.tts.monster/voices"; StaticLogInfo("Sending POST request to \"" + text + "\"", extended: true); UnityWebRequest www = UnityWebRequest.Post(text, new WWWForm()); try { www.SetRequestHeader("User-Agent", TTSVoice.UserAgent); www.SetRequestHeader("Authorization", apiKey); UnityWebRequestAsyncOperation operation = www.SendWebRequest(); while (!((AsyncOperation)operation).isDone) { await Task.Yield(); } if ((int)www.result == 4) { StaticLogError("Failed to process voices data: " + www.error); return null; } if ((int)www.result != 1) { StaticLogError("Failed to fetch voices: " + www.error); return null; } string text2 = www.downloadHandler.text; try { JObject val = JObject.Parse(text2); StaticLogInfo("Response data:\n" + JsonConvert.SerializeObject((object)val, (Formatting)1), extended: true); return val; } catch (Exception arg) { StaticLogError($"Failed to parse response as JSON:\n\nResponse:\n\"{text2}\"\n\nError:\n{arg}"); return null; } } finally { ((IDisposable)www)?.Dispose(); } } protected static void UpdateExistingVoicesData(List voices) { List list = (from x in TextToSpeech.GetVoicesByService(VoiceService.TTSMonster) select x as TTSVoice_TTSMonster into x where x != null select x).ToList(); foreach (TTSVoice_TTSMonster existingVoice in list) { TTSVoice_TTSMonster tTSVoice_TTSMonster = voices.FirstOrDefault((TTSVoice_TTSMonster x) => x.Name == existingVoice.Name); if (tTSVoice_TTSMonster != null && existingVoice.VoiceId != tTSVoice_TTSMonster.VoiceId) { existingVoice.VoiceId = tTSVoice_TTSMonster.VoiceId; StaticLogInfo("Updated already registerd voice \"" + existingVoice.Name + "\" VoiceId to \"" + tTSVoice_TTSMonster.VoiceId + "\"", extended: true); } } } protected static string GetProxyName(string name) { return _voiceNameProxies.GetValueOrDefault(name, name); } protected static List ParseVoicesJson(string text) { try { JObject data = JObject.Parse(text); return ParseVoicesJson(data); } catch (Exception arg) { StaticLogError($"Failed to parse text as JSON:\n\nResponse:\n\"{text}\"\n\nError:\n{arg}"); return new List(); } } protected static List ParseVoicesJson(JObject data) { //IL_003f: Unknown result type (might be due to invalid IL or missing references) //IL_0046: Expected O, but got Unknown //IL_00ca: Unknown result type (might be due to invalid IL or missing references) //IL_00d1: Expected O, but got Unknown List list = new List(); string text = "TTSM - "; JToken obj = data["customVoices"]; JArray val = (JArray)(object)((obj is JArray) ? obj : null); JToken obj2 = data["voices"]; JArray val2 = (JArray)(object)((obj2 is JArray) ? obj2 : null); foreach (JObject item in val) { JObject val3 = item; string text2 = ((object)val3["name"])?.ToString(); string text3 = ((object)val3["voice_id"])?.ToString(); if (!string.IsNullOrEmpty(text2) && !string.IsNullOrEmpty(text3)) { list.Add(new TTSMonsterVoice(text + text2, text3, isCustom: true)); } } foreach (JObject item2 in val2) { JObject val4 = item2; string text4 = ((object)val4["name"])?.ToString(); string text5 = ((object)val4["voice_id"])?.ToString(); if (!string.IsNullOrEmpty(text4) && !string.IsNullOrEmpty(text5)) { list.Add(new TTSMonsterVoice(text + GetProxyName(text4), text5)); } } return list; } protected static List ConvertToTTSVoices(List ttsMonsterVoices) { List list = new List(); foreach (TTSMonsterVoice ttsMonsterVoice in ttsMonsterVoices) { TTSVoice_TTSMonster tTSVoice_TTSMonster = ConvertToTTSVoice(ttsMonsterVoice); if (tTSVoice_TTSMonster != null) { list.Add(tTSVoice_TTSMonster); } } return list; } protected static TTSVoice_TTSMonster ConvertToTTSVoice(TTSMonsterVoice ttsMonsterVoice) { if (!ttsMonsterVoice.IsValid()) { return null; } return new TTSVoice_TTSMonster(ttsMonsterVoice.Name, ttsMonsterVoice.VoiceId); } public static void OpenLoginWebpage() { Application.OpenURL("https://console.tts.monster/login"); } protected static void StaticLog(LogLevel logLevel, object data, bool extended = false) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) Logger.Log(logLevel, string.Format("[{0}] {1}", "TTSVoice_TTSMonster", data), extended); } protected static void StaticLogInfo(object data, bool extended = false) { StaticLog((LogLevel)16, data, extended); } protected static void StaticLogWarning(object data, bool extended = false) { StaticLog((LogLevel)4, data, extended); } protected static void StaticLogError(object data, bool extended = false) { StaticLog((LogLevel)2, data, extended); } } public struct TTSMonsterVoice { public string Name { get; set; } public string VoiceId { get; set; } public bool IsCustom { get; set; } public TTSMonsterVoice(string name, string voiceId, bool isCustom = false) { Name = name; VoiceId = voiceId; IsCustom = isCustom; } public bool IsValid() { if (!string.IsNullOrEmpty(Name)) { return !string.IsNullOrEmpty(VoiceId); } return false; } public override string ToString() { return $"(Name: \"{Name}\", IsCustom: {IsCustom}, VoiceId: \"{VoiceId}\")"; } } } namespace com.github.zehsteam.MelaniesVoice.Objects.Config { public class VoiceConfigEntry { public TTSVoice Voice { get; private set; } public ConfigEntry Volume { get; private set; } public VoiceConfigEntry(TTSVoice voice, int defaultVolume) { Bind(voice, defaultVolume); } private void Bind(TTSVoice voice, int defaultVolume) { Voice = voice; string section = "Voice: " + Voice.Name; Volume = ConfigHelper.Bind(section, "Volume", defaultVolume, "The volume of the voice.", requiresRestart: false, (AcceptableValueBase)(object)new AcceptableValueRange(0, 200)); } } } namespace com.github.zehsteam.MelaniesVoice.MonoBehaviours { internal class CoroutineRunner : MonoBehaviour { public static CoroutineRunner Instance { get; private set; } public static CoroutineRunner Spawn() { //IL_002b: Unknown result type (might be due to invalid IL or missing references) //IL_0030: Unknown result type (might be due to invalid IL or missing references) //IL_0039: Expected O, but got Unknown if ((Object)(object)Instance != (Object)null) { return Instance; } GameObject val = new GameObject("MelaniesVoice CoroutineRunner", new Type[1] { typeof(CoroutineRunner) }) { hideFlags = (HideFlags)61 }; Object.DontDestroyOnLoad((Object)(object)val); return val.GetComponent(); } private void Awake() { if ((Object)(object)Instance != (Object)null && (Object)(object)Instance != (Object)(object)this) { Object.Destroy((Object)(object)((Component)this).gameObject); } else { Instance = this; } } public static Coroutine Start(IEnumerator routine) { if ((Object)(object)Instance == (Object)null) { CoroutineRunner coroutineRunner = Spawn(); return ((coroutineRunner != null) ? ((MonoBehaviour)coroutineRunner).StartCoroutine(routine) : null) ?? null; } CoroutineRunner instance = Instance; return ((instance != null) ? ((MonoBehaviour)instance).StartCoroutine(routine) : null) ?? null; } public static void Stop(IEnumerator routine) { CoroutineRunner instance = Instance; if (instance != null) { ((MonoBehaviour)instance).StopCoroutine(routine); } } public static void Stop(Coroutine routine) { CoroutineRunner instance = Instance; if (instance != null) { ((MonoBehaviour)instance).StopCoroutine(routine); } } } public class VoiceController : NetworkBehaviour { private static readonly List _instances = new List(); [SerializeField] private AudioSource _voiceAudio; [SerializeField] private AudioSource _deadAudio; private List _voiceMessageQueue = new List(); private float _noiseRange = 30f; private float _noiseLoudness = 0.7f; private float _noiseTimer; private float _noiseCooldown = 0.2f; private const int OpusFrameSize = 960; public static IReadOnlyList Instances => _instances; public PlayerAudioGroup PlayerAudioGroup { get; private set; } public PlayerControllerB PlayerScript { get; private set; } public bool IsLocal => PlayerUtils.IsLocalPlayer(PlayerScript); private int FramesPerBatch => Mathf.Clamp(ConfigManager.TTS_OpusFrameBatchSize.Value, 1, 255); private void OnEnable() { if (!_instances.Contains(this)) { _instances.Add(this); } } private void OnDisable() { _instances.Remove(this); } private void Start() { //IL_0074: 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) PlayerControllerB playerScript = default(PlayerControllerB); if ((Object)(object)((Component)this).transform.parent == (Object)null) { LogError("Failed to initialize. Transform parent is null."); if (NetworkUtils.IsServer) { ((Component)this).GetComponent().Despawn(true); } } else if (!((Component)((Component)this).transform.parent).TryGetComponent(ref playerScript)) { LogError("Failed to initialize. PlayerControllerB is null."); if (NetworkUtils.IsServer) { ((Component)this).GetComponent().Despawn(true); } } else { PlayerScript = playerScript; ((Component)this).transform.SetLocalPositionAndRotation(Vector3.zero, Quaternion.identity); PlayerAudioGroup = new PlayerAudioGroup(_voiceAudio, _deadAudio); PlayerAudioGroup.Volume = 1f; ApplySettings(); LogInfo("Initialized.", extended: true); } } private void Update() { VoiceMessageTick(); NoiseTick(); } private void VoiceMessageTick() { if (!NetworkUtils.IsServer || PlayerAudioGroup == null || IsPlayingVoiceMessage() || _voiceMessageQueue.Count == 0) { return; } VoiceMessage voiceMessage = _voiceMessageQueue[0]; if (voiceMessage == null) { _voiceMessageQueue.RemoveAt(0); return; } if (voiceMessage.IsReady) { PlayVoiceMessage_ClientRpc(voiceMessage.Id); return; } voiceMessage.Tick(); if (voiceMessage.IsTimedout) { VoiceMessageTimedout_Server(voiceMessage.Id); } } private void NoiseTick() { //IL_0056: Unknown result type (might be due to invalid IL or missing references) if (NetworkUtils.IsServer && PlayerAudioGroup != null && PlayerAudioGroup.IsPlaying && !((Object)(object)PlayerScript == (Object)null)) { if (_noiseTimer >= _noiseCooldown) { _noiseTimer = 0f; RoundManager.Instance.PlayAudibleNoise(((Component)PlayerScript).transform.position, _noiseRange, _noiseLoudness, 0, PlayerScript.isInHangarShipRoom && StartOfRound.Instance.hangarDoorsClosed, 75); } else { _noiseTimer += Time.deltaTime; } } } private void UpdateVoiceMute() { if ((Object)(object)PlayerScript == (Object)null || PlayerAudioGroup == null) { return; } if (IsLocal) { PlayerAudioGroup.Mute = !ConfigManager.TTS_HearMyself.Value; if (!PlayerAudioGroup.Mute) { PlayerAudioGroup.VoiceAudio.mute = PlayerScript.isPlayerDead; PlayerAudioGroup.DeadAudio.mute = !PlayerScript.isPlayerDead; } } else { PlayerAudioGroup.VoiceAudio.mute = PlayerScript.isPlayerDead; PlayerControllerB localPlayerScript = PlayerUtils.LocalPlayerScript; if ((Object)(object)localPlayerScript == (Object)null || !localPlayerScript.isPlayerDead) { PlayerAudioGroup.DeadAudio.mute = true; } else { PlayerAudioGroup.DeadAudio.mute = !PlayerScript.isPlayerDead; } } } private bool IsPlayingVoiceMessage() { return PlayerAudioGroup.IsPlaying; } private VoiceMessage GetVoiceMessage(int id) { return _voiceMessageQueue.FirstOrDefault((VoiceMessage x) => x.Id == id); } [ServerRpc] public void CreateVoiceMessage_ServerRpc(string voiceName, string message, ServerRpcParams serverRpcParams = default(ServerRpcParams)) { //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Invalid comparison between Unknown and I4 //IL_014e: Unknown result type (might be due to invalid IL or missing references) //IL_0158: Invalid comparison between Unknown and I4 //IL_0183: Unknown result type (might be due to invalid IL or missing references) //IL_0188: Unknown result type (might be due to invalid IL or missing references) //IL_0189: Unknown result type (might be due to invalid IL or missing references) //IL_00a5: Unknown result type (might be due to invalid IL or missing references) //IL_00ae: Unknown result type (might be due to invalid IL or missing references) //IL_00b3: 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_00d4: Unknown result type (might be due to invalid IL or missing references) //IL_007a: Unknown result type (might be due to invalid IL or missing references) //IL_0084: Invalid comparison between Unknown and I4 //IL_010c: Unknown result type (might be due to invalid IL or missing references) //IL_0112: 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) NetworkManager networkManager = ((NetworkBehaviour)this).NetworkManager; if (networkManager == null || !networkManager.IsListening) { return; } if ((int)base.__rpc_exec_stage != 1 && (networkManager.IsClient || networkManager.IsHost)) { if (((NetworkBehaviour)this).OwnerClientId != networkManager.LocalClientId) { if ((int)networkManager.LogLevel <= 1) { Debug.LogError((object)"Only the owner can invoke a ServerRpc that requires ownership!"); } return; } FastBufferWriter val = ((NetworkBehaviour)this).__beginSendServerRpc(2160464779u, serverRpcParams, (RpcDelivery)0); bool flag = voiceName != null; ((FastBufferWriter)(ref val)).WriteValueSafe(ref flag, default(ForPrimitives)); if (flag) { ((FastBufferWriter)(ref val)).WriteValueSafe(voiceName, false); } bool flag2 = message != null; ((FastBufferWriter)(ref val)).WriteValueSafe(ref flag2, default(ForPrimitives)); if (flag2) { ((FastBufferWriter)(ref val)).WriteValueSafe(message, false); } ((NetworkBehaviour)this).__endSendServerRpc(ref val, 2160464779u, serverRpcParams, (RpcDelivery)0); } if ((int)base.__rpc_exec_stage == 1 && (networkManager.IsServer || networkManager.IsHost)) { base.__rpc_exec_stage = (__RpcExecStage)0; ulong senderClientId = serverRpcParams.Receive.SenderClientId; if (((NetworkBehaviour)this).NetworkManager.ConnectedClients.ContainsKey(senderClientId) && !((Object)(object)PlayerScript == (Object)null) && PlayerScript.actualClientId == senderClientId) { int id = Random.Range(0, 1000000); CreateVoiceMessage_ClientRpc(id, voiceName, message); } } } [ClientRpc] private void CreateVoiceMessage_ClientRpc(int id, string voiceName, string message) { //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Invalid comparison between Unknown and I4 //IL_0115: Unknown result type (might be due to invalid IL or missing references) //IL_011f: Invalid comparison between Unknown and I4 //IL_005f: Unknown result type (might be due to invalid IL or missing references) //IL_0068: Unknown result type (might be due to invalid IL or missing references) //IL_006d: Unknown result type (might be due to invalid IL or missing references) //IL_0071: 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) //IL_009b: Unknown result type (might be due to invalid IL or missing references) //IL_014a: 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_00d9: Unknown result type (might be due to invalid IL or missing references) //IL_0105: Unknown result type (might be due to invalid IL or missing references) NetworkManager networkManager = ((NetworkBehaviour)this).NetworkManager; if (networkManager == null || !networkManager.IsListening) { return; } if ((int)base.__rpc_exec_stage != 1 && (networkManager.IsServer || networkManager.IsHost)) { ClientRpcParams val2 = default(ClientRpcParams); FastBufferWriter val = ((NetworkBehaviour)this).__beginSendClientRpc(1380029231u, val2, (RpcDelivery)0); BytePacker.WriteValueBitPacked(val, id); bool flag = voiceName != null; ((FastBufferWriter)(ref val)).WriteValueSafe(ref flag, default(ForPrimitives)); if (flag) { ((FastBufferWriter)(ref val)).WriteValueSafe(voiceName, false); } bool flag2 = message != null; ((FastBufferWriter)(ref val)).WriteValueSafe(ref flag2, default(ForPrimitives)); if (flag2) { ((FastBufferWriter)(ref val)).WriteValueSafe(message, false); } ((NetworkBehaviour)this).__endSendClientRpc(ref val, 1380029231u, val2, (RpcDelivery)0); } if ((int)base.__rpc_exec_stage != 1 || (!networkManager.IsClient && !networkManager.IsHost)) { return; } base.__rpc_exec_stage = (__RpcExecStage)0; int id2 = id; string voiceName2 = voiceName; VoiceMessage voiceMessage = new VoiceMessage(id2, voiceName2, message); _voiceMessageQueue.Add(voiceMessage); LogInfo($"Created VoiceMessage. {voiceMessage}", extended: true); if (!IsLocal) { return; } TextToSpeech.RequestAudio(voiceMessage.VoiceName, voiceMessage.Message, delegate(AudioClip clip) { if ((Object)(object)clip == (Object)null) { DeleteVoiceMessage_ServerRpc(id2); } else { ((Object)clip).name = string.Format("{0}_{1}_{2}", "MelaniesVoice", Utils.SanitizeFileName(voiceName2), id2); ((MonoBehaviour)this).StartCoroutine(StreamAudio_Local(voiceMessage, clip)); if (MirageProxy.Enabled) { MirageProxy.SaveAudioClip(clip); } } }); } [ServerRpc] private void DeleteVoiceMessage_ServerRpc(int id) { //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Invalid comparison between Unknown and I4 //IL_00df: Unknown result type (might be due to invalid IL or missing references) //IL_00e9: Invalid comparison between Unknown and I4 //IL_0114: Unknown result type (might be due to invalid IL or missing references) //IL_00a5: Unknown result type (might be due to invalid IL or missing references) //IL_00ae: Unknown result type (might be due to invalid IL or missing references) //IL_00b3: 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_00cf: Unknown result type (might be due to invalid IL or missing references) //IL_007a: Unknown result type (might be due to invalid IL or missing references) //IL_0084: Invalid comparison between Unknown and I4 NetworkManager networkManager = ((NetworkBehaviour)this).NetworkManager; if (networkManager == null || !networkManager.IsListening) { return; } if ((int)base.__rpc_exec_stage != 1 && (networkManager.IsClient || networkManager.IsHost)) { if (((NetworkBehaviour)this).OwnerClientId != networkManager.LocalClientId) { if ((int)networkManager.LogLevel <= 1) { Debug.LogError((object)"Only the owner can invoke a ServerRpc that requires ownership!"); } return; } ServerRpcParams val2 = default(ServerRpcParams); FastBufferWriter val = ((NetworkBehaviour)this).__beginSendServerRpc(4045068609u, val2, (RpcDelivery)0); BytePacker.WriteValueBitPacked(val, id); ((NetworkBehaviour)this).__endSendServerRpc(ref val, 4045068609u, val2, (RpcDelivery)0); } if ((int)base.__rpc_exec_stage == 1 && (networkManager.IsServer || networkManager.IsHost)) { base.__rpc_exec_stage = (__RpcExecStage)0; DeleteVoiceMessage_ClientRpc(id); DeleteVoiceMessage_Local(id); } } [ClientRpc] private void DeleteVoiceMessage_ClientRpc(int id) { //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Invalid comparison between Unknown and I4 //IL_0099: Unknown result type (might be due to invalid IL or missing references) //IL_00a3: Invalid comparison between Unknown and I4 //IL_005f: Unknown result type (might be due to invalid IL or missing references) //IL_0068: Unknown result type (might be due to invalid IL or missing references) //IL_006d: Unknown result type (might be due to invalid IL or missing references) //IL_0071: Unknown result type (might be due to invalid IL or missing references) //IL_0089: 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) NetworkManager networkManager = ((NetworkBehaviour)this).NetworkManager; if (networkManager == null || !networkManager.IsListening) { return; } if ((int)base.__rpc_exec_stage != 1 && (networkManager.IsServer || networkManager.IsHost)) { ClientRpcParams val2 = default(ClientRpcParams); FastBufferWriter val = ((NetworkBehaviour)this).__beginSendClientRpc(2880339731u, val2, (RpcDelivery)0); BytePacker.WriteValueBitPacked(val, id); ((NetworkBehaviour)this).__endSendClientRpc(ref val, 2880339731u, val2, (RpcDelivery)0); } if ((int)base.__rpc_exec_stage == 1 && (networkManager.IsClient || networkManager.IsHost)) { base.__rpc_exec_stage = (__RpcExecStage)0; if (!NetworkUtils.IsServer) { DeleteVoiceMessage_Local(id); } } } private void DeleteVoiceMessage_Local(int id) { VoiceMessage voiceMessage = GetVoiceMessage(id); if (voiceMessage != null) { _voiceMessageQueue.Remove(voiceMessage); } } private IEnumerator StreamAudio_Local(VoiceMessage voiceMessage, AudioClip clip) { if ((Object)(object)clip == (Object)null) { yield break; } voiceMessage.AudioClip = clip; if (NetworkUtils.ConnectedPlayerCount == 1) { ReceivedVoiceMessageAudioClip_ServerRpc(voiceMessage.Id); yield break; } float[] data = new float[clip.samples * clip.channels]; clip.GetData(data, 0); int num = 48000; if (clip.frequency != num) { data = AudioUtils.ResampleTo48k(data, clip.frequency, clip.channels); } OpusCodec codec = new OpusCodec(num, clip.channels); StreamAudioStart_ServerRpc(voiceMessage.Id, clip.channels, num); int frameLength = 960 * clip.channels; int pos = 0; List batch = new List(FramesPerBatch); while (pos < data.Length) { int length = Mathf.Min(frameLength, data.Length - pos); float[] array = new float[frameLength]; Array.Copy(data, pos, array, 0, length); byte[] item = codec.Encode(array); batch.Add(item); pos += frameLength; if (batch.Count >= FramesPerBatch || pos >= data.Length) { StreamAudioChunk_ServerRpc(voiceMessage.Id, PackOpusFrames(batch)); batch.Clear(); yield return null; } } StreamAudioComplete_ServerRpc(voiceMessage.Id); ReceivedVoiceMessageAudioClip_ServerRpc(voiceMessage.Id); } private byte[] PackOpusFrames(List frames) { using MemoryStream memoryStream = new MemoryStream(); using BinaryWriter binaryWriter = new BinaryWriter(memoryStream); binaryWriter.Write((byte)frames.Count); foreach (byte[] frame in frames) { binaryWriter.Write((ushort)frame.Length); binaryWriter.Write(frame); } return memoryStream.ToArray(); } private List UnpackOpusFrames(byte[] packed) { List list = new List(); using MemoryStream input = new MemoryStream(packed); using BinaryReader binaryReader = new BinaryReader(input); byte b = binaryReader.ReadByte(); for (int i = 0; i < b; i++) { ushort count = binaryReader.ReadUInt16(); list.Add(binaryReader.ReadBytes(count)); } return list; } [ServerRpc] private void StreamAudioStart_ServerRpc(int id, int channels, int sampleRate) { //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Invalid comparison between Unknown and I4 //IL_00f9: Unknown result type (might be due to invalid IL or missing references) //IL_0103: Invalid comparison between Unknown and I4 //IL_012e: Unknown result type (might be due to invalid IL or missing references) //IL_00a5: Unknown result type (might be due to invalid IL or missing references) //IL_00ae: Unknown result type (might be due to invalid IL or missing references) //IL_00b3: 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_00c4: Unknown result type (might be due to invalid IL or missing references) //IL_00d1: Unknown result type (might be due to invalid IL or missing references) //IL_00e9: Unknown result type (might be due to invalid IL or missing references) //IL_007a: Unknown result type (might be due to invalid IL or missing references) //IL_0084: Invalid comparison between Unknown and I4 NetworkManager networkManager = ((NetworkBehaviour)this).NetworkManager; if (networkManager == null || !networkManager.IsListening) { return; } if ((int)base.__rpc_exec_stage != 1 && (networkManager.IsClient || networkManager.IsHost)) { if (((NetworkBehaviour)this).OwnerClientId != networkManager.LocalClientId) { if ((int)networkManager.LogLevel <= 1) { Debug.LogError((object)"Only the owner can invoke a ServerRpc that requires ownership!"); } return; } ServerRpcParams val2 = default(ServerRpcParams); FastBufferWriter val = ((NetworkBehaviour)this).__beginSendServerRpc(1307672002u, val2, (RpcDelivery)0); BytePacker.WriteValueBitPacked(val, id); BytePacker.WriteValueBitPacked(val, channels); BytePacker.WriteValueBitPacked(val, sampleRate); ((NetworkBehaviour)this).__endSendServerRpc(ref val, 1307672002u, val2, (RpcDelivery)0); } if ((int)base.__rpc_exec_stage == 1 && (networkManager.IsServer || networkManager.IsHost)) { base.__rpc_exec_stage = (__RpcExecStage)0; StreamAudioStart_ClientRpc(id, channels, sampleRate); } } [ClientRpc] private void StreamAudioStart_ClientRpc(int id, int channels, int sampleRate) { //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Invalid comparison between Unknown and I4 //IL_00b3: Unknown result type (might be due to invalid IL or missing references) //IL_00bd: Invalid comparison between Unknown and I4 //IL_005f: Unknown result type (might be due to invalid IL or missing references) //IL_0068: Unknown result type (might be due to invalid IL or missing references) //IL_006d: Unknown result type (might be due to invalid IL or missing references) //IL_0071: 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_008b: Unknown result type (might be due to invalid IL or missing references) //IL_00a3: Unknown result type (might be due to invalid IL or missing references) //IL_00e8: Unknown result type (might be due to invalid IL or missing references) NetworkManager networkManager = ((NetworkBehaviour)this).NetworkManager; if (networkManager == null || !networkManager.IsListening) { return; } if ((int)base.__rpc_exec_stage != 1 && (networkManager.IsServer || networkManager.IsHost)) { ClientRpcParams val2 = default(ClientRpcParams); FastBufferWriter val = ((NetworkBehaviour)this).__beginSendClientRpc(721908506u, val2, (RpcDelivery)0); BytePacker.WriteValueBitPacked(val, id); BytePacker.WriteValueBitPacked(val, channels); BytePacker.WriteValueBitPacked(val, sampleRate); ((NetworkBehaviour)this).__endSendClientRpc(ref val, 721908506u, val2, (RpcDelivery)0); } if ((int)base.__rpc_exec_stage == 1 && (networkManager.IsClient || networkManager.IsHost)) { base.__rpc_exec_stage = (__RpcExecStage)0; if (!IsLocal) { GetVoiceMessage(id)?.InitCodec(sampleRate, channels); } } } [ServerRpc] private void StreamAudioChunk_ServerRpc(int id, byte[] packedFrames) { //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Invalid comparison between Unknown and I4 //IL_012a: Unknown result type (might be due to invalid IL or missing references) //IL_0134: Invalid comparison between Unknown and I4 //IL_015f: Unknown result type (might be due to invalid IL or missing references) //IL_00a5: Unknown result type (might be due to invalid IL or missing references) //IL_00ae: Unknown result type (might be due to invalid IL or missing references) //IL_00b3: 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_00db: 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_007a: Unknown result type (might be due to invalid IL or missing references) //IL_0084: Invalid comparison between Unknown and I4 //IL_011a: Unknown result type (might be due to invalid IL or missing references) //IL_00ff: Unknown result type (might be due to invalid IL or missing references) //IL_0105: Unknown result type (might be due to invalid IL or missing references) NetworkManager networkManager = ((NetworkBehaviour)this).NetworkManager; if (networkManager == null || !networkManager.IsListening) { return; } if ((int)base.__rpc_exec_stage != 1 && (networkManager.IsClient || networkManager.IsHost)) { if (((NetworkBehaviour)this).OwnerClientId != networkManager.LocalClientId) { if ((int)networkManager.LogLevel <= 1) { Debug.LogError((object)"Only the owner can invoke a ServerRpc that requires ownership!"); } return; } ServerRpcParams val2 = default(ServerRpcParams); FastBufferWriter val = ((NetworkBehaviour)this).__beginSendServerRpc(3554871174u, val2, (RpcDelivery)0); BytePacker.WriteValueBitPacked(val, id); bool flag = packedFrames != null; ((FastBufferWriter)(ref val)).WriteValueSafe(ref flag, default(ForPrimitives)); if (flag) { ((FastBufferWriter)(ref val)).WriteValueSafe(packedFrames, default(ForPrimitives)); } ((NetworkBehaviour)this).__endSendServerRpc(ref val, 3554871174u, val2, (RpcDelivery)0); } if ((int)base.__rpc_exec_stage == 1 && (networkManager.IsServer || networkManager.IsHost)) { base.__rpc_exec_stage = (__RpcExecStage)0; StreamAudioChunk_ClientRpc(id, packedFrames); } } [ClientRpc] private void StreamAudioChunk_ClientRpc(int id, byte[] packedFrames) { //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Invalid comparison between Unknown and I4 //IL_00e4: Unknown result type (might be due to invalid IL or missing references) //IL_00ee: Invalid comparison between Unknown and I4 //IL_005f: Unknown result type (might be due to invalid IL or missing references) //IL_0068: Unknown result type (might be due to invalid IL or missing references) //IL_006d: Unknown result type (might be due to invalid IL or missing references) //IL_0071: 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) //IL_009b: Unknown result type (might be due to invalid IL or missing references) //IL_0119: 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_00b9: 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) NetworkManager networkManager = ((NetworkBehaviour)this).NetworkManager; if (networkManager == null || !networkManager.IsListening) { return; } if ((int)base.__rpc_exec_stage != 1 && (networkManager.IsServer || networkManager.IsHost)) { ClientRpcParams val2 = default(ClientRpcParams); FastBufferWriter val = ((NetworkBehaviour)this).__beginSendClientRpc(431399283u, val2, (RpcDelivery)0); BytePacker.WriteValueBitPacked(val, id); bool flag = packedFrames != null; ((FastBufferWriter)(ref val)).WriteValueSafe(ref flag, default(ForPrimitives)); if (flag) { ((FastBufferWriter)(ref val)).WriteValueSafe(packedFrames, default(ForPrimitives)); } ((NetworkBehaviour)this).__endSendClientRpc(ref val, 431399283u, val2, (RpcDelivery)0); } if ((int)base.__rpc_exec_stage != 1 || (!networkManager.IsClient && !networkManager.IsHost)) { return; } base.__rpc_exec_stage = (__RpcExecStage)0; if (IsLocal) { return; } VoiceMessage voiceMessage = GetVoiceMessage(id); if (voiceMessage == null) { return; } foreach (byte[] item in UnpackOpusFrames(packedFrames)) { voiceMessage.AddOpusPacket(item); } } [ServerRpc] private void StreamAudioComplete_ServerRpc(int id, ServerRpcParams serverRpcParams = default(ServerRpcParams)) { //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Invalid comparison between Unknown and I4 //IL_00df: Unknown result type (might be due to invalid IL or missing references) //IL_00e9: Invalid comparison between Unknown and I4 //IL_0114: Unknown result type (might be due to invalid IL or missing references) //IL_00a5: Unknown result type (might be due to invalid IL or missing references) //IL_00ae: Unknown result type (might be due to invalid IL or missing references) //IL_00b3: 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_00cf: Unknown result type (might be due to invalid IL or missing references) //IL_007a: Unknown result type (might be due to invalid IL or missing references) //IL_0084: Invalid comparison between Unknown and I4 NetworkManager networkManager = ((NetworkBehaviour)this).NetworkManager; if (networkManager == null || !networkManager.IsListening) { return; } if ((int)base.__rpc_exec_stage != 1 && (networkManager.IsClient || networkManager.IsHost)) { if (((NetworkBehaviour)this).OwnerClientId != networkManager.LocalClientId) { if ((int)networkManager.LogLevel <= 1) { Debug.LogError((object)"Only the owner can invoke a ServerRpc that requires ownership!"); } return; } FastBufferWriter val = ((NetworkBehaviour)this).__beginSendServerRpc(3290872701u, serverRpcParams, (RpcDelivery)0); BytePacker.WriteValueBitPacked(val, id); ((NetworkBehaviour)this).__endSendServerRpc(ref val, 3290872701u, serverRpcParams, (RpcDelivery)0); } if ((int)base.__rpc_exec_stage == 1 && (networkManager.IsServer || networkManager.IsHost)) { base.__rpc_exec_stage = (__RpcExecStage)0; StreamAudioComplete_ClientRpc(id); } } [ClientRpc] private void StreamAudioComplete_ClientRpc(int id) { //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Invalid comparison between Unknown and I4 //IL_0099: Unknown result type (might be due to invalid IL or missing references) //IL_00a3: Invalid comparison between Unknown and I4 //IL_005f: Unknown result type (might be due to invalid IL or missing references) //IL_0068: Unknown result type (might be due to invalid IL or missing references) //IL_006d: Unknown result type (might be due to invalid IL or missing references) //IL_0071: Unknown result type (might be due to invalid IL or missing references) //IL_0089: 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_00f7: Unknown result type (might be due to invalid IL or missing references) //IL_00fd: Unknown result type (might be due to invalid IL or missing references) NetworkManager networkManager = ((NetworkBehaviour)this).NetworkManager; if (networkManager == null || !networkManager.IsListening) { return; } if ((int)base.__rpc_exec_stage != 1 && (networkManager.IsServer || networkManager.IsHost)) { ClientRpcParams val2 = default(ClientRpcParams); FastBufferWriter val = ((NetworkBehaviour)this).__beginSendClientRpc(4122899824u, val2, (RpcDelivery)0); BytePacker.WriteValueBitPacked(val, id); ((NetworkBehaviour)this).__endSendClientRpc(ref val, 4122899824u, val2, (RpcDelivery)0); } if ((int)base.__rpc_exec_stage != 1 || (!networkManager.IsClient && !networkManager.IsHost)) { return; } base.__rpc_exec_stage = (__RpcExecStage)0; if (!IsLocal) { VoiceMessage voiceMessage = GetVoiceMessage(id); if (voiceMessage != null) { voiceMessage.BuildClipIfNeeded(); ReceivedVoiceMessageAudioClip_ServerRpc(voiceMessage.Id); } } } [ServerRpc(RequireOwnership = false)] private void ReceivedVoiceMessageAudioClip_ServerRpc(int id, ServerRpcParams serverRpcParams = default(ServerRpcParams)) { //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Invalid comparison between Unknown and I4 //IL_0099: Unknown result type (might be due to invalid IL or missing references) //IL_00a3: Invalid comparison between Unknown and I4 //IL_005f: Unknown result type (might be due to invalid IL or missing references) //IL_0068: Unknown result type (might be due to invalid IL or missing references) //IL_006d: Unknown result type (might be due to invalid IL or missing references) //IL_0071: Unknown result type (might be due to invalid IL or missing references) //IL_0089: 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_00d4: Unknown result type (might be due to invalid IL or missing references) NetworkManager networkManager = ((NetworkBehaviour)this).NetworkManager; if (networkManager == null || !networkManager.IsListening) { return; } if ((int)base.__rpc_exec_stage != 1 && (networkManager.IsClient || networkManager.IsHost)) { FastBufferWriter val = ((NetworkBehaviour)this).__beginSendServerRpc(2085373701u, serverRpcParams, (RpcDelivery)0); BytePacker.WriteValueBitPacked(val, id); ((NetworkBehaviour)this).__endSendServerRpc(ref val, 2085373701u, serverRpcParams, (RpcDelivery)0); } if ((int)base.__rpc_exec_stage == 1 && (networkManager.IsServer || networkManager.IsHost)) { base.__rpc_exec_stage = (__RpcExecStage)0; ulong senderClientId = serverRpcParams.Receive.SenderClientId; VoiceMessage voiceMessage = GetVoiceMessage(id); if (voiceMessage != null && !voiceMessage.ClientsReceivedAudioClip.Contains(senderClientId)) { voiceMessage.ClientsReceivedAudioClip.Add(senderClientId); } } } private void VoiceMessageTimedout_Server(int id) { if (NetworkUtils.IsServer) { VoiceMessageTimedout_ClientRpc(id); VoiceMessageTimedout_Local(id); } } [ClientRpc] private void VoiceMessageTimedout_ClientRpc(int id) { //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Invalid comparison between Unknown and I4 //IL_0099: Unknown result type (might be due to invalid IL or missing references) //IL_00a3: Invalid comparison between Unknown and I4 //IL_005f: Unknown result type (might be due to invalid IL or missing references) //IL_0068: Unknown result type (might be due to invalid IL or missing references) //IL_006d: Unknown result type (might be due to invalid IL or missing references) //IL_0071: Unknown result type (might be due to invalid IL or missing references) //IL_0089: 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) NetworkManager networkManager = ((NetworkBehaviour)this).NetworkManager; if (networkManager == null || !networkManager.IsListening) { return; } if ((int)base.__rpc_exec_stage != 1 && (networkManager.IsServer || networkManager.IsHost)) { ClientRpcParams val2 = default(ClientRpcParams); FastBufferWriter val = ((NetworkBehaviour)this).__beginSendClientRpc(3812723390u, val2, (RpcDelivery)0); BytePacker.WriteValueBitPacked(val, id); ((NetworkBehaviour)this).__endSendClientRpc(ref val, 3812723390u, val2, (RpcDelivery)0); } if ((int)base.__rpc_exec_stage == 1 && (networkManager.IsClient || networkManager.IsHost)) { base.__rpc_exec_stage = (__RpcExecStage)0; if (!NetworkUtils.IsServer) { VoiceMessageTimedout_Local(id); } } } private void VoiceMessageTimedout_Local(int id) { VoiceMessage voiceMessage = GetVoiceMessage(id); if (voiceMessage != null) { if (IsLocal) { string text = "TTS audio for \"" + voiceMessage.VoiceName + "\" timed out"; LogError(text); Utils.DisplayMessage(text, isError: true); } _voiceMessageQueue.Remove(voiceMessage); } } [ClientRpc] private void PlayVoiceMessage_ClientRpc(int id) { //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Invalid comparison between Unknown and I4 //IL_0099: Unknown result type (might be due to invalid IL or missing references) //IL_00a3: Invalid comparison between Unknown and I4 //IL_005f: Unknown result type (might be due to invalid IL or missing references) //IL_0068: Unknown result type (might be due to invalid IL or missing references) //IL_006d: Unknown result type (might be due to invalid IL or missing references) //IL_0071: Unknown result type (might be due to invalid IL or missing references) //IL_0089: 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) NetworkManager networkManager = ((NetworkBehaviour)this).NetworkManager; if (networkManager != null && networkManager.IsListening) { if ((int)base.__rpc_exec_stage != 1 && (networkManager.IsServer || networkManager.IsHost)) { ClientRpcParams val2 = default(ClientRpcParams); FastBufferWriter val = ((NetworkBehaviour)this).__beginSendClientRpc(544932966u, val2, (RpcDelivery)0); BytePacker.WriteValueBitPacked(val, id); ((NetworkBehaviour)this).__endSendClientRpc(ref val, 544932966u, val2, (RpcDelivery)0); } if ((int)base.__rpc_exec_stage == 1 && (networkManager.IsClient || networkManager.IsHost)) { base.__rpc_exec_stage = (__RpcExecStage)0; PlayVoiceMessage_Local(id); } } } private void PlayVoiceMessage_Local(int id) { VoiceMessage voiceMessage = GetVoiceMessage(id); if (voiceMessage == null) { LogWarning($"Failed to play VoiceMessage. Could not find VoiceMessage. (Id: {id})", extended: true); return; } if ((Object)(object)voiceMessage.AudioClip == (Object)null) { LogWarning($"Failed to play VoiceMessage. AudioClip is null. {voiceMessage}", extended: true); _voiceMessageQueue.Remove(voiceMessage); return; } LogInfo($"Playing VoiceMessage. {voiceMessage}", extended: true); float num = ConfigManager.TTS_MasterVolume.Value; VoiceService service = VoiceService.Unknown; if (TextToSpeech.TryGetVoiceByName(voiceMessage.VoiceName, out var result)) { service = result.Service; } float serviceMasterVolume = ConfigManager.GetServiceMasterVolume(service); float num2 = 100f; if (VoiceConfigManager.TryGetVoiceConfigEntry(voiceMessage.VoiceName, out var voiceConfigEntry)) { num2 = voiceConfigEntry.Volume.Value; } AudioClip clip = AudioUtils.CreateAdjustedClip(voiceMessage.AudioClip, num, serviceMasterVolume, num2); UpdateVoiceMute(); PlayerAudioGroup.Clip = clip; PlayerAudioGroup.Play(); _voiceMessageQueue.Remove(voiceMessage); } private void ApplySettings() { if (PlayerAudioGroup != null) { UpdateVoiceMute(); PlayerAudioGroup.MaxDistance = ConfigManager.TTS_MaxDistance.Value; } } public static void HandleConfigSettingsChanged() { foreach (VoiceController instance in _instances) { instance.ApplySettings(); } } private void Log(LogLevel logLevel, object data, bool extended = false) { //IL_006a: Unknown result type (might be due to invalid IL or missing references) string arg = (((Object)(object)PlayerScript == (Object)null) ? ("[" + ((object)this).GetType().Name + "]") : ("[" + ((object)this).GetType().Name + " : " + PlayerScript.playerUsername + "]")); Logger.Log(logLevel, $"{arg} {data}", extended); } private void LogInfo(object data, bool extended = false) { Log((LogLevel)16, data, extended); } private void LogWarning(object data, bool extended = false) { Log((LogLevel)4, data, extended); } private void LogError(object data, bool extended = false) { Log((LogLevel)2, data, extended); } protected override void __initializeVariables() { ((NetworkBehaviour)this).__initializeVariables(); } protected override void __initializeRpcs() { //IL_000d: Unknown result type (might be due to invalid IL or missing references) //IL_001c: Expected O, but got Unknown //IL_0029: Unknown result type (might be due to invalid IL or missing references) //IL_0038: Expected O, but got Unknown //IL_0045: Unknown result type (might be due to invalid IL or missing references) //IL_0054: Expected O, but got Unknown //IL_0061: Unknown result type (might be due to invalid IL or missing references) //IL_0070: Expected O, but got Unknown //IL_007d: Unknown result type (might be due to invalid IL or missing references) //IL_008c: Expected O, but got Unknown //IL_0099: Unknown result type (might be due to invalid IL or missing references) //IL_00a8: Expected O, but got Unknown //IL_00b5: Unknown result type (might be due to invalid IL or missing references) //IL_00c4: Expected O, but got Unknown //IL_00d1: Unknown result type (might be due to invalid IL or missing references) //IL_00e0: Expected O, but got Unknown //IL_00ed: Unknown result type (might be due to invalid IL or missing references) //IL_00fc: Expected O, but got Unknown //IL_0109: Unknown result type (might be due to invalid IL or missing references) //IL_0118: Expected O, but got Unknown //IL_0125: Unknown result type (might be due to invalid IL or missing references) //IL_0134: Expected O, but got Unknown //IL_0141: Unknown result type (might be due to invalid IL or missing references) //IL_0150: Expected O, but got Unknown //IL_015d: Unknown result type (might be due to invalid IL or missing references) //IL_016c: Expected O, but got Unknown ((NetworkBehaviour)this).__registerRpc(2160464779u, new RpcReceiveHandler(__rpc_handler_2160464779), "CreateVoiceMessage_ServerRpc"); ((NetworkBehaviour)this).__registerRpc(1380029231u, new RpcReceiveHandler(__rpc_handler_1380029231), "CreateVoiceMessage_ClientRpc"); ((NetworkBehaviour)this).__registerRpc(4045068609u, new RpcReceiveHandler(__rpc_handler_4045068609), "DeleteVoiceMessage_ServerRpc"); ((NetworkBehaviour)this).__registerRpc(2880339731u, new RpcReceiveHandler(__rpc_handler_2880339731), "DeleteVoiceMessage_ClientRpc"); ((NetworkBehaviour)this).__registerRpc(1307672002u, new RpcReceiveHandler(__rpc_handler_1307672002), "StreamAudioStart_ServerRpc"); ((NetworkBehaviour)this).__registerRpc(721908506u, new RpcReceiveHandler(__rpc_handler_721908506), "StreamAudioStart_ClientRpc"); ((NetworkBehaviour)this).__registerRpc(3554871174u, new RpcReceiveHandler(__rpc_handler_3554871174), "StreamAudioChunk_ServerRpc"); ((NetworkBehaviour)this).__registerRpc(431399283u, new RpcReceiveHandler(__rpc_handler_431399283), "StreamAudioChunk_ClientRpc"); ((NetworkBehaviour)this).__registerRpc(3290872701u, new RpcReceiveHandler(__rpc_handler_3290872701), "StreamAudioComplete_ServerRpc"); ((NetworkBehaviour)this).__registerRpc(4122899824u, new RpcReceiveHandler(__rpc_handler_4122899824), "StreamAudioComplete_ClientRpc"); ((NetworkBehaviour)this).__registerRpc(2085373701u, new RpcReceiveHandler(__rpc_handler_2085373701), "ReceivedVoiceMessageAudioClip_ServerRpc"); ((NetworkBehaviour)this).__registerRpc(3812723390u, new RpcReceiveHandler(__rpc_handler_3812723390), "VoiceMessageTimedout_ClientRpc"); ((NetworkBehaviour)this).__registerRpc(544932966u, new RpcReceiveHandler(__rpc_handler_544932966), "PlayVoiceMessage_ClientRpc"); ((NetworkBehaviour)this).__initializeRpcs(); } private static void __rpc_handler_2160464779(NetworkBehaviour target, FastBufferReader reader, __RpcParams rpcParams) { //IL_0023: Unknown result type (might be due to invalid IL or missing references) //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_0029: Unknown result type (might be due to invalid IL or missing references) //IL_007c: Unknown result type (might be due to invalid IL or missing references) //IL_0082: 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_0055: Invalid comparison between Unknown and I4 //IL_00b4: Unknown result type (might be due to invalid IL or missing references) //IL_00ba: 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_00e1: Unknown result type (might be due to invalid IL or missing references) //IL_00e6: Unknown result type (might be due to invalid IL or missing references) //IL_00f0: 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_0112: Unknown result type (might be due to invalid IL or missing references) NetworkManager networkManager = target.NetworkManager; if (networkManager == null || !networkManager.IsListening) { return; } if (rpcParams.Server.Receive.SenderClientId != target.OwnerClientId) { if ((int)networkManager.LogLevel <= 1) { Debug.LogError((object)"Only the owner can invoke a ServerRpc that requires ownership!"); } return; } bool flag = default(bool); ((FastBufferReader)(ref reader)).ReadValueSafe(ref flag, default(ForPrimitives)); string voiceName = null; if (flag) { ((FastBufferReader)(ref reader)).ReadValueSafe(ref voiceName, false); } bool flag2 = default(bool); ((FastBufferReader)(ref reader)).ReadValueSafe(ref flag2, default(ForPrimitives)); string message = null; if (flag2) { ((FastBufferReader)(ref reader)).ReadValueSafe(ref message, false); } ServerRpcParams server = rpcParams.Server; target.__rpc_exec_stage = (__RpcExecStage)1; ((VoiceController)(object)target).CreateVoiceMessage_ServerRpc(voiceName, message, server); target.__rpc_exec_stage = (__RpcExecStage)0; } private static void __rpc_handler_1380029231(NetworkBehaviour target, FastBufferReader reader, __RpcParams rpcParams) { //IL_0023: Unknown result type (might be due to invalid IL or missing references) //IL_003c: Unknown result type (might be due to invalid IL or missing references) //IL_0042: Unknown result type (might be due to invalid IL or missing references) //IL_0074: Unknown result type (might be due to invalid IL or missing references) //IL_007a: Unknown result type (might be due to invalid IL or missing references) //IL_00a6: Unknown result type (might be due to invalid IL or missing references) //IL_00c8: Unknown result type (might be due to invalid IL or missing references) NetworkManager networkManager = target.NetworkManager; if (networkManager != null && networkManager.IsListening) { int id = default(int); ByteUnpacker.ReadValueBitPacked(reader, ref id); bool flag = default(bool); ((FastBufferReader)(ref reader)).ReadValueSafe(ref flag, default(ForPrimitives)); string voiceName = null; if (flag) { ((FastBufferReader)(ref reader)).ReadValueSafe(ref voiceName, false); } bool flag2 = default(bool); ((FastBufferReader)(ref reader)).ReadValueSafe(ref flag2, default(ForPrimitives)); string message = null; if (flag2) { ((FastBufferReader)(ref reader)).ReadValueSafe(ref message, false); } target.__rpc_exec_stage = (__RpcExecStage)1; ((VoiceController)(object)target).CreateVoiceMessage_ClientRpc(id, voiceName, message); target.__rpc_exec_stage = (__RpcExecStage)0; } } private static void __rpc_handler_4045068609(NetworkBehaviour target, FastBufferReader reader, __RpcParams rpcParams) { //IL_0023: Unknown result type (might be due to invalid IL or missing references) //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_0029: Unknown result type (might be due to invalid IL or missing references) //IL_0070: Unknown result type (might be due to invalid IL or missing references) //IL_0083: 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_004b: Unknown result type (might be due to invalid IL or missing references) //IL_0055: Invalid comparison between Unknown and I4 NetworkManager networkManager = target.NetworkManager; if (networkManager == null || !networkManager.IsListening) { return; } if (rpcParams.Server.Receive.SenderClientId != target.OwnerClientId) { if ((int)networkManager.LogLevel <= 1) { Debug.LogError((object)"Only the owner can invoke a ServerRpc that requires ownership!"); } } else { int id = default(int); ByteUnpacker.ReadValueBitPacked(reader, ref id); target.__rpc_exec_stage = (__RpcExecStage)1; ((VoiceController)(object)target).DeleteVoiceMessage_ServerRpc(id); target.__rpc_exec_stage = (__RpcExecStage)0; } } private static void __rpc_handler_2880339731(NetworkBehaviour target, FastBufferReader reader, __RpcParams rpcParams) { //IL_0023: Unknown result type (might be due to invalid IL or missing references) //IL_0036: 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) NetworkManager networkManager = target.NetworkManager; if (networkManager != null && networkManager.IsListening) { int id = default(int); ByteUnpacker.ReadValueBitPacked(reader, ref id); target.__rpc_exec_stage = (__RpcExecStage)1; ((VoiceController)(object)target).DeleteVoiceMessage_ClientRpc(id); target.__rpc_exec_stage = (__RpcExecStage)0; } } private static void __rpc_handler_1307672002(NetworkBehaviour target, FastBufferReader reader, __RpcParams rpcParams) { //IL_0023: Unknown result type (might be due to invalid IL or missing references) //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_0029: Unknown result type (might be due to invalid IL or missing references) //IL_0070: Unknown result type (might be due to invalid IL or missing references) //IL_007d: Unknown result type (might be due to invalid IL or missing references) //IL_008a: Unknown result type (might be due to invalid IL or missing references) //IL_009d: 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) //IL_004b: Unknown result type (might be due to invalid IL or missing references) //IL_0055: Invalid comparison between Unknown and I4 NetworkManager networkManager = target.NetworkManager; if (networkManager == null || !networkManager.IsListening) { return; } if (rpcParams.Server.Receive.SenderClientId != target.OwnerClientId) { if ((int)networkManager.LogLevel <= 1) { Debug.LogError((object)"Only the owner can invoke a ServerRpc that requires ownership!"); } return; } int id = default(int); ByteUnpacker.ReadValueBitPacked(reader, ref id); int channels = default(int); ByteUnpacker.ReadValueBitPacked(reader, ref channels); int sampleRate = default(int); ByteUnpacker.ReadValueBitPacked(reader, ref sampleRate); target.__rpc_exec_stage = (__RpcExecStage)1; ((VoiceController)(object)target).StreamAudioStart_ServerRpc(id, channels, sampleRate); target.__rpc_exec_stage = (__RpcExecStage)0; } private static void __rpc_handler_721908506(NetworkBehaviour target, FastBufferReader reader, __RpcParams rpcParams) { //IL_0023: Unknown result type (might be due to invalid IL or missing references) //IL_0030: Unknown result type (might be due to invalid IL or missing references) //IL_003d: 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_0072: Unknown result type (might be due to invalid IL or missing references) NetworkManager networkManager = target.NetworkManager; if (networkManager != null && networkManager.IsListening) { int id = default(int); ByteUnpacker.ReadValueBitPacked(reader, ref id); int channels = default(int); ByteUnpacker.ReadValueBitPacked(reader, ref channels); int sampleRate = default(int); ByteUnpacker.ReadValueBitPacked(reader, ref sampleRate); target.__rpc_exec_stage = (__RpcExecStage)1; ((VoiceController)(object)target).StreamAudioStart_ClientRpc(id, channels, sampleRate); target.__rpc_exec_stage = (__RpcExecStage)0; } } private static void __rpc_handler_3554871174(NetworkBehaviour target, FastBufferReader reader, __RpcParams rpcParams) { //IL_0023: Unknown result type (might be due to invalid IL or missing references) //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_0029: Unknown result type (might be due to invalid IL or missing references) //IL_0070: Unknown result type (might be due to invalid IL or missing references) //IL_0089: Unknown result type (might be due to invalid IL or missing references) //IL_008f: Unknown result type (might be due to invalid IL or missing references) //IL_004b: Unknown result type (might be due to invalid IL or missing references) //IL_0055: Invalid comparison between Unknown and I4 //IL_00c8: Unknown result type (might be due to invalid IL or missing references) //IL_00e6: Unknown result type (might be due to invalid IL or missing references) //IL_00b2: Unknown result type (might be due to invalid IL or missing references) //IL_00b8: Unknown result type (might be due to invalid IL or missing references) NetworkManager networkManager = target.NetworkManager; if (networkManager == null || !networkManager.IsListening) { return; } if (rpcParams.Server.Receive.SenderClientId != target.OwnerClientId) { if ((int)networkManager.LogLevel <= 1) { Debug.LogError((object)"Only the owner can invoke a ServerRpc that requires ownership!"); } return; } int id = default(int); ByteUnpacker.ReadValueBitPacked(reader, ref id); bool flag = default(bool); ((FastBufferReader)(ref reader)).ReadValueSafe(ref flag, default(ForPrimitives)); byte[] packedFrames = null; if (flag) { ((FastBufferReader)(ref reader)).ReadValueSafe(ref packedFrames, default(ForPrimitives)); } target.__rpc_exec_stage = (__RpcExecStage)1; ((VoiceController)(object)target).StreamAudioChunk_ServerRpc(id, packedFrames); target.__rpc_exec_stage = (__RpcExecStage)0; } private static void __rpc_handler_431399283(NetworkBehaviour target, FastBufferReader reader, __RpcParams rpcParams) { //IL_0023: Unknown result type (might be due to invalid IL or missing references) //IL_003c: Unknown result type (might be due to invalid IL or missing references) //IL_0042: Unknown result type (might be due to invalid IL or missing references) //IL_007b: 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_0065: Unknown result type (might be due to invalid IL or missing references) //IL_006b: Unknown result type (might be due to invalid IL or missing references) NetworkManager networkManager = target.NetworkManager; if (networkManager != null && networkManager.IsListening) { int id = default(int); ByteUnpacker.ReadValueBitPacked(reader, ref id); bool flag = default(bool); ((FastBufferReader)(ref reader)).ReadValueSafe(ref flag, default(ForPrimitives)); byte[] packedFrames = null; if (flag) { ((FastBufferReader)(ref reader)).ReadValueSafe(ref packedFrames, default(ForPrimitives)); } target.__rpc_exec_stage = (__RpcExecStage)1; ((VoiceController)(object)target).StreamAudioChunk_ClientRpc(id, packedFrames); target.__rpc_exec_stage = (__RpcExecStage)0; } } private static void __rpc_handler_3290872701(NetworkBehaviour target, FastBufferReader reader, __RpcParams rpcParams) { //IL_0023: Unknown result type (might be due to invalid IL or missing references) //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_0029: Unknown result type (might be due to invalid IL or missing references) //IL_0070: Unknown result type (might be due to invalid IL or missing references) //IL_007d: 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_0083: Unknown result type (might be due to invalid IL or missing references) //IL_008d: Unknown result type (might be due to invalid IL or missing references) //IL_009c: 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_004b: Unknown result type (might be due to invalid IL or missing references) //IL_0055: Invalid comparison between Unknown and I4 NetworkManager networkManager = target.NetworkManager; if (networkManager == null || !networkManager.IsListening) { return; } if (rpcParams.Server.Receive.SenderClientId != target.OwnerClientId) { if ((int)networkManager.LogLevel <= 1) { Debug.LogError((object)"Only the owner can invoke a ServerRpc that requires ownership!"); } } else { int id = default(int); ByteUnpacker.ReadValueBitPacked(reader, ref id); ServerRpcParams server = rpcParams.Server; target.__rpc_exec_stage = (__RpcExecStage)1; ((VoiceController)(object)target).StreamAudioComplete_ServerRpc(id, server); target.__rpc_exec_stage = (__RpcExecStage)0; } } private static void __rpc_handler_4122899824(NetworkBehaviour target, FastBufferReader reader, __RpcParams rpcParams) { //IL_0023: Unknown result type (might be due to invalid IL or missing references) //IL_0036: 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) NetworkManager networkManager = target.NetworkManager; if (networkManager != null && networkManager.IsListening) { int id = default(int); ByteUnpacker.ReadValueBitPacked(reader, ref id); target.__rpc_exec_stage = (__RpcExecStage)1; ((VoiceController)(object)target).StreamAudioComplete_ClientRpc(id); target.__rpc_exec_stage = (__RpcExecStage)0; } } private static void __rpc_handler_2085373701(NetworkBehaviour target, FastBufferReader reader, __RpcParams rpcParams) { //IL_0023: Unknown result type (might be due to invalid IL or missing references) //IL_0030: Unknown result type (might be due to invalid IL or missing references) //IL_0031: Unknown result type (might be due to invalid IL or missing references) //IL_0036: Unknown result type (might be due to invalid IL or missing references) //IL_0040: Unknown result type (might be due to invalid IL or missing references) //IL_004f: Unknown result type (might be due to invalid IL or missing references) //IL_005e: Unknown result type (might be due to invalid IL or missing references) NetworkManager networkManager = target.NetworkManager; if (networkManager != null && networkManager.IsListening) { int id = default(int); ByteUnpacker.ReadValueBitPacked(reader, ref id); ServerRpcParams server = rpcParams.Server; target.__rpc_exec_stage = (__RpcExecStage)1; ((VoiceController)(object)target).ReceivedVoiceMessageAudioClip_ServerRpc(id, server); target.__rpc_exec_stage = (__RpcExecStage)0; } } private static void __rpc_handler_3812723390(NetworkBehaviour target, FastBufferReader reader, __RpcParams rpcParams) { //IL_0023: Unknown result type (might be due to invalid IL or missing references) //IL_0036: 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) NetworkManager networkManager = target.NetworkManager; if (networkManager != null && networkManager.IsListening) { int id = default(int); ByteUnpacker.ReadValueBitPacked(reader, ref id); target.__rpc_exec_stage = (__RpcExecStage)1; ((VoiceController)(object)target).VoiceMessageTimedout_ClientRpc(id); target.__rpc_exec_stage = (__RpcExecStage)0; } } private static void __rpc_handler_544932966(NetworkBehaviour target, FastBufferReader reader, __RpcParams rpcParams) { //IL_0023: Unknown result type (might be due to invalid IL or missing references) //IL_0036: 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) NetworkManager networkManager = target.NetworkManager; if (networkManager != null && networkManager.IsListening) { int id = default(int); ByteUnpacker.ReadValueBitPacked(reader, ref id); target.__rpc_exec_stage = (__RpcExecStage)1; ((VoiceController)(object)target).PlayVoiceMessage_ClientRpc(id); target.__rpc_exec_stage = (__RpcExecStage)0; } } [MethodImpl(MethodImplOptions.NoInlining)] protected internal override string __getTypeName() { return "VoiceController"; } } } namespace com.github.zehsteam.MelaniesVoice.Managers { internal static class ConfigManager { public static ConfigFile ConfigFile { get; private set; } public static ConfigEntry Misc_ExtendedLogging { get; private set; } public static ConfigEntry TTS_Voice { get; private set; } public static ConfigEntry TTS_MasterVolume { get; private set; } public static ConfigEntry TTS_HearMyself { get; private set; } public static ConfigEntry TTS_DisableMyVoice { get; private set; } public static ConfigEntry TTS_MaxDistance { get; private set; } public static ConfigEntry TTS_IgnorePrefixes { get; private set; } public static ConfigEntry TTS_RequestTimeoutDuration { get; private set; } public static ConfigEntry TTS_OpusFrameBatchSize { get; private set; } public static ConfigEntry ServiceVolumes_Streamlabs_MasterVolume { get; private set; } public static ConfigEntry ServiceVolumes_LazyPy_MasterVolume { get; private set; } public static ConfigEntry ServiceVolumes_TTSMonster_MasterVolume { get; private set; } public static ConfigEntry ServiceVolumes_Unknown_MasterVolume { get; private set; } public static ConfigEntry TTSMonster_APIKey { get; private set; } public static ConfigEntry MirageCompatibility_Enabled { get; private set; } public static string[] TTS_IgnorePefixesArray { get { return com.github.zehsteam.MelaniesVoice.Extensions.CollectionExtensions.StringToCollection(TTS_IgnorePrefixes.Value).ToArray(); } set { TTS_IgnorePrefixes.Value = com.github.zehsteam.MelaniesVoice.Extensions.CollectionExtensions.CollectionToString(value); } } public static void Initialize(ConfigFile configFile) { ConfigFile = configFile; BindConfigs(); } private static void BindConfigs() { ConfigHelper.SkipAutoGen(); Misc_ExtendedLogging = ConfigHelper.Bind("Misc", "ExtendedLogging", defaultValue: false, "Enable extended logging."); TTS_Voice = ConfigHelper.Bind("Text-To-Speech", "Voice", TextToSpeech.VoiceNames[0], "Your text-to-speech voice.", requiresRestart: false, (AcceptableValueBase)(object)new AcceptableValueList(TextToSpeech.VoiceNames)); TTS_MasterVolume = ConfigHelper.Bind("Text-To-Speech", "MasterVolume", 100, "The master volume for all voices.", requiresRestart: false, (AcceptableValueBase)(object)new AcceptableValueRange(0, 200)); TTS_HearMyself = ConfigHelper.Bind("Text-To-Speech", "HearMyself", defaultValue: true, "If enabled, you will hear your own voice."); TTS_DisableMyVoice = ConfigHelper.Bind("Text-To-Speech", "DisableMyVoice", defaultValue: false, "If enabled, your chat messages won't trigger your text-to-speech voice."); TTS_MaxDistance = ConfigHelper.Bind("Text-To-Speech", "MaxDistance", 40f, "The max distance in meters you will hear other player voices."); TTS_IgnorePrefixes = ConfigHelper.Bind("Text-To-Speech", "IgnorePefixes", "/, !", "List of prefixes that won't trigger your text-to-speech voice.\nComma-separated values."); TTS_RequestTimeoutDuration = ConfigHelper.Bind("Text-To-Speech", "RequestTimeoutDuration", 30f, "HOST ONLY! The amount of seconds before your TTS audio API request times out."); TTS_OpusFrameBatchSize = ConfigHelper.Bind("Text-To-Speech", "OpusFrameBatchSize", 75, "The amount of encoded Opus frames to batch per stream audio RPC call.\nHigher value uses more bandwidth and has a lower latency.\n10 = 600 bytes,\n200 = 12,000 bytes", requiresRestart: false, (AcceptableValueBase)(object)new AcceptableValueRange(10, 200)); TTS_HearMyself.SettingChanged += delegate { VoiceController.HandleConfigSettingsChanged(); }; TTS_MaxDistance.SettingChanged += delegate { VoiceController.HandleConfigSettingsChanged(); }; ServiceVolumes_Streamlabs_MasterVolume = ConfigHelper.Bind("TTS Service Volumes", "SL MasterVolume", 125, "The master volume for all voices prefixed by SL.", requiresRestart: false, (AcceptableValueBase)(object)new AcceptableValueRange(0, 200)); ServiceVolumes_LazyPy_MasterVolume = ConfigHelper.Bind("TTS Service Volumes", "LP MasterVolume", 100, "The master volume for all voices prefixed by LP.", requiresRestart: false, (AcceptableValueBase)(object)new AcceptableValueRange(0, 200)); ServiceVolumes_TTSMonster_MasterVolume = ConfigHelper.Bind("TTS Service Volumes", "TTSM MasterVolume", 100, "The master volume for all voices prefixed by TTSM.", requiresRestart: false, (AcceptableValueBase)(object)new AcceptableValueRange(0, 200)); ServiceVolumes_Unknown_MasterVolume = ConfigHelper.Bind("TTS Service Volumes", "Unknown MasterVolume", 100, "The master volume for voices from unknown services.", requiresRestart: false, (AcceptableValueBase)(object)new AcceptableValueRange(0, 200)); TTSMonster_APIKey = ConfigHelper.Bind("TTS.Monster Service", "APIKey", "", "TTS.Monster API key. This is required to use TTSM voices. You can create an API key for free on the website https://tts.monster"); ConfigHelper.AddButton("TTS.Monster Service", "Get API key", "Open", "Opens the link https://console.tts.monster/login", TTSVoice_TTSMonster.OpenLoginWebpage); ConfigHelper.AddButton("TTS.Monster Service", "Refresh voices", "Refresh", "Gets all available voices for your TTS.Monster account. Requires an API key. https://tts.monster", TTSVoice_TTSMonster.FetchVoices); MirageCompatibility_Enabled = ConfigHelper.Bind("Mirage Compatibility", "Enabled", defaultValue: true, "If enabled, your TTS audio clips will be saved to be used by the Mirage mod."); VoiceConfigManager.BindInitialConfigs(); } public static void UpdateTTSVoiceAcceptableValues() { TTS_Voice.SetAcceptableValues((AcceptableValueBase)(object)new AcceptableValueList(TextToSpeech.VoiceNames)); if (LethalConfigProxy.Enabled) { LethalConfigProxy.UpdateTextDropDownConfigItem(TTS_Voice); } } public static float GetServiceMasterVolume(VoiceService service) { return service switch { VoiceService.Streamlabs => ServiceVolumes_Streamlabs_MasterVolume.Value, VoiceService.LazyPy => ServiceVolumes_LazyPy_MasterVolume.Value, VoiceService.TTSMonster => ServiceVolumes_TTSMonster_MasterVolume.Value, VoiceService.Unknown => ServiceVolumes_Unknown_MasterVolume.Value, _ => 100f, }; } } internal static class TextToSpeech { private static readonly Dictionary _voices; public static IReadOnlyDictionary Voices => _voices; public static string[] VoiceNames => Voices.Values.Select((TTSVoice v) => v.Name).ToArray(); static TextToSpeech() { _voices = new Dictionary(); AddVoice(new TTSVoice_Streamlabs("SL - Brian", "Brian")); AddVoice(new TTSVoice_Streamlabs("SL - Salli", "Salli")); AddVoice(new TTSVoice_Streamlabs("SL - Justin", "Justin")); AddVoice(new TTSVoice_Streamlabs("SL - Joey", "Joey")); AddVoice(new TTSVoice_Streamlabs("SL - Matthew", "Matthew")); AddVoice(new TTSVoice_Streamlabs("SL - Amy", "Amy")); AddVoice(new TTSVoice_Streamlabs("SL - Emma", "Emma")); AddVoice(new TTSVoice_Streamlabs("SL - Geraint", "Geraint")); AddVoice(new TTSVoice_LazyPy("LP - The Company", "Bing Translator", "en-US-ChristopherNeural")); AddVoice(new TTSVoice_LazyPy("LP - TikTok Jessie", "TikTok", "en_us_002")); AddVoice(new TTSVoice_LazyPy("LP - TikTok Joey", "TikTok", "en_us_006")); AddVoice(new TTSVoice_LazyPy("LP - C-3PO", "TikTok", "en_us_c3po")); AddVoice(new TTSVoice_LazyPy("LP - Stormtrooper", "TikTok", "en_us_stormtrooper")); AddVoice(new TTSVoice_LazyPy("LP - Ghostface", "TikTok", "en_us_ghostface")); AddVoice(new TTSVoice_LazyPy("LP - Rocket", "TikTok", "en_us_rocket")); AddVoice(new TTSVoice_LazyPy("LP - Grinch", "TikTok", "en_male_grinch")); AddVoice(new TTSVoice_LazyPy("LP - Madame Leota", "TikTok", "en_female_madam_leota")); AddVoice(new TTSVoice_LazyPy("LP - Witch", "TikTok", "en_female_witch")); AddVoice(new TTSVoice_LazyPy("LP - Wizard", "TikTok", "en_male_wizard")); AddVoice(new TTSVoice_LazyPy("LP - Zombie", "TikTok", "en_female_zombie")); AddVoice(new TTSVoice_LazyPy("LP - Werewolf", "TikTok", "en_female_werewolf")); AddVoice(new TTSVoice_LazyPy("LP - Pirate", "TikTok", "en_male_pirate")); AddVoice(new TTSVoice_LazyPy("LP - Santa", "TikTok", "en_male_santa")); AddVoice(new TTSVoice_LazyPy("LP - Santa 2", "TikTok", "en_male_santa_effect")); AddVoice(new TTSVoice_LazyPy("LP - Lord Cringe", "TikTok", "en_male_ukneighbor")); AddVoice(new TTSVoice_LazyPy("LP - Grandma", "TikTok", "en_female_grandma")); AddVoices(TTSVoice_TTSMonster.CreateDefaultVoices()); } public static List AddVoices(List voices, bool logErrors = true) where T : TTSVoice { List list = new List(); foreach (T voice in voices) { if (AddVoice(voice, logErrors)) { list.Add(voice); } } return list; } public static bool AddVoice(TTSVoice voice, bool logErrors = true) { if (_voices.ContainsKey(voice.Name)) { if (logErrors) { Logger.LogError($"[TextToSpeech] Failed to add voice. Voice with the same name already exists. {voice}"); } return false; } _voices.Add(voice.Name, voice); return true; } public static void RequestAudio(string name, string text, Action onClipReady) { if (!TryGetVoiceByName(name, out var result)) { Logger.LogError("[TextToSpeech] RequestAudio: Failed to find voice by name: \"" + name + "\""); onClipReady(null); } else { result.RequestAudio(text, onClipReady); } } public static TTSVoice GetVoiceByName(string name) { return _voices.GetValueOrDefault(name); } public static bool TryGetVoiceByName(string name, out TTSVoice result) { return _voices.TryGetValue(name, out result); } public static List GetVoicesByService(VoiceService service) { return _voices.Values.Where((TTSVoice v) => v.Service == service).ToList(); } } internal static class VoiceConfigManager { private static readonly Dictionary _entries = new Dictionary(); public static IReadOnlyDictionary Entries => _entries; public static void BindInitialConfigs() { BindConfigs(TextToSpeech.Voices.Values.ToList()); } public static List BindConfigs(List voices, bool logErrors = true) where T : TTSVoice { List list = new List(); foreach (T voice in voices) { if (BindConfig(voice, logErrors)) { list.Add(voice); } } return list; } public static bool BindConfig(TTSVoice voice, bool logErrors = true) { if (_entries.ContainsKey(voice.Name)) { if (logErrors) { Logger.LogError($"[VoiceConfigManager] Failed to bind config for voice. Voice with the same name already has already bound their config. {voice}"); } return false; } _entries.Add(voice.Name, new VoiceConfigEntry(voice, voice.DefaultVolume)); return true; } public static VoiceConfigEntry GetVoiceConfigEntry(string voiceName) { return _entries.GetValueOrDefault(voiceName); } public static bool TryGetVoiceConfigEntry(string voiceName, out VoiceConfigEntry voiceConfigEntry) { return _entries.TryGetValue(voiceName, out voiceConfigEntry); } } } namespace com.github.zehsteam.MelaniesVoice.Helpers { internal static class AudioUtils { private static float[] GetSamples(AudioClip clip) { float[] array = new float[clip.samples * clip.channels]; clip.GetData(array, 0); return array; } private static float PercentToLinear(float percent) { percent = Mathf.Clamp(percent, 0.0001f, 200f); return Mathf.Pow(percent / 100f, 2f); } private static float CombinedGain(params float[] volumes) { float num = 1f; foreach (float percent in volumes) { num *= PercentToLinear(percent); } return num; } private static float SoftClip(float x) { return x / (1f + Mathf.Abs(x)); } private static void ApplyGain(float[] samples, float gain) { for (int i = 0; i < samples.Length; i++) { samples[i] = SoftClip(samples[i] * gain); } } public static AudioClip CreateAdjustedClip(AudioClip clip, params float[] volumes) { float[] samples = GetSamples(clip); float num = CombinedGain(volumes); Logger.LogInfo($"[AudioUtils] CreateAdjustedClip: clip: \"{((Object)clip).name}\" gain: {num}", extended: true); ApplyGain(samples, num); int num2 = samples.Length / clip.channels; AudioClip val = AudioClip.Create(((Object)clip).name + "_Adjusted", num2, clip.channels, clip.frequency, false); val.SetData(samples, 0); return val; } public static float[] ResampleTo48k(float[] samples, int sourceSampleRate, int channels) { //IL_0020: Unknown result type (might be due to invalid IL or missing references) //IL_0026: Expected O, but got Unknown if (sourceSampleRate == 48000) { return samples; } WaveFormat waveFormat = WaveFormat.CreateIeeeFloatWaveFormat(sourceSampleRate, channels); FiniteSampleProvider finiteSampleProvider = new FiniteSampleProvider(samples, waveFormat); WdlResamplingSampleProvider val = new WdlResamplingSampleProvider((ISampleProvider)(object)finiteSampleProvider, 48000); long val2 = (long)samples.Length * 48000L / sourceSampleRate + 64; List list = new List((int)Math.Min(val2, 2147483647L)); float[] array = new float[4096]; int num; while ((num = val.Read(array, 0, array.Length)) > 0) { for (int i = 0; i < num; i++) { list.Add(array[i]); } } return list.ToArray(); } } public class FiniteSampleProvider : ISampleProvider { private readonly float[] _samples; private int _position; public WaveFormat WaveFormat { get; } public FiniteSampleProvider(float[] samples, WaveFormat waveFormat) { _samples = samples; WaveFormat = waveFormat; } public int Read(float[] buffer, int offset, int count) { int val = _samples.Length - _position; int num = Math.Min(val, count); if (num <= 0) { return 0; } Array.Copy(_samples, _position, buffer, offset, num); _position += num; return num; } } internal static class ConfigHelper { public static void SkipAutoGen() { if (LethalConfigProxy.Enabled) { LethalConfigProxy.SkipAutoGen(); } } public static void AddButton(string section, string name, string buttonText, string description, Action callback) { if (LethalConfigProxy.Enabled) { LethalConfigProxy.AddButton(section, name, buttonText, description, callback); } } public static ConfigEntry Bind(string section, string key, T defaultValue, string description, bool requiresRestart = false, AcceptableValueBase acceptableValues = null, Action settingChanged = null, ConfigFile configFile = null) { if (configFile == null) { configFile = ConfigManager.ConfigFile; } ConfigEntry configEntry = configFile.Bind(section, key, defaultValue, description, acceptableValues); if (settingChanged != null) { configEntry.SettingChanged += delegate { settingChanged?.Invoke(configEntry.Value); }; } if (LethalConfigProxy.Enabled) { LethalConfigProxy.AddConfig(configEntry, requiresRestart); } return configEntry; } } internal static class NetworkUtils { private static readonly FieldInfo _rpcExecStageField = AccessTools.Field(typeof(NetworkBehaviour), "__rpc_exec_stage"); public static bool IsConnected { get { NetworkManager singleton = NetworkManager.Singleton; if (singleton == null) { return false; } return singleton.IsConnectedClient; } } public static bool IsServer { get { NetworkManager singleton = NetworkManager.Singleton; if (singleton == null) { return false; } return singleton.IsServer; } } public static ulong LocalClientId { get { NetworkManager singleton = NetworkManager.Singleton; if (singleton == null) { return 0uL; } return singleton.LocalClientId; } } public static int ConnectedPlayerCount => GameNetworkManager.Instance?.connectedPlayers ?? 0; public static bool IsLocalClientId(ulong clientId) { return clientId == LocalClientId; } public static bool HasClient(ulong clientId) { if ((Object)(object)NetworkManager.Singleton == (Object)null) { return false; } return NetworkManager.Singleton.ConnectedClients.ContainsKey(clientId); } public static bool IsNetworkPrefab(GameObject prefab) { if ((Object)(object)prefab == (Object)null) { return false; } if ((Object)(object)NetworkManager.Singleton == (Object)null) { return false; } IReadOnlyList prefabs = NetworkManager.Singleton.NetworkConfig.Prefabs.Prefabs; return prefabs.Any((NetworkPrefab x) => (Object)(object)x.Prefab == (Object)(object)prefab); } public static void NetcodePatcherAwake() { try { Assembly executingAssembly = Assembly.GetExecutingAssembly(); IEnumerable loadableTypes = executingAssembly.GetLoadableTypes(); foreach (Type item in loadableTypes) { MethodInfo[] methods = item.GetMethods(BindingFlags.Instance | BindingFlags.Static | BindingFlags.NonPublic); MethodInfo[] array = methods; foreach (MethodInfo methodInfo in array) { try { object[] customAttributes = methodInfo.GetCustomAttributes(typeof(RuntimeInitializeOnLoadMethodAttribute), inherit: false); if (customAttributes.Length != 0) { try { methodInfo.Invoke(null, null); } catch (TargetInvocationException ex) { Logger.LogWarning("[NetworkUtils] Failed to invoke method " + methodInfo.Name + ": " + ex.Message); } } } catch (Exception ex2) { Logger.LogWarning("[NetworkUtils] Error processing method " + methodInfo.Name + " in type " + item.Name + ": " + ex2.Message); } } } } catch (Exception ex3) { Logger.LogError("[NetworkUtils] Failed to run NetcodePatcherAwake: " + ex3.Message); } } public static bool IsExecutingRPCMethod(NetworkBehaviour networkBehaviour) { if ((Object)(object)networkBehaviour == (Object)null) { return false; } NetworkManager networkManager = networkBehaviour.NetworkManager; if ((Object)(object)networkManager == (Object)null || !networkManager.IsListening) { return false; } if (_rpcExecStageField == null) { Logger.LogError("[NetworkUtils] IsExecutingRPCMethod: Failed to find \"__rpc_exec_stage\" field."); return false; } object value = _rpcExecStageField.GetValue(networkBehaviour); int num = (int)value; if (num != 0) { return num == 1; } return true; } } internal static class PlayerUtils { public static PlayerControllerB LocalPlayerScript => GameNetworkManager.Instance?.localPlayerController ?? null; public static PlayerControllerB[] AllPlayerScripts => StartOfRound.Instance?.allPlayerScripts ?? Array.Empty(); public static PlayerControllerB[] ConnectedPlayerScripts => AllPlayerScripts.Where(IsConnected).ToArray(); public static PlayerControllerB[] AlivePlayerScripts => ConnectedPlayerScripts.Where((PlayerControllerB x) => !x.isPlayerDead).ToArray(); public static PlayerControllerB[] DeadPlayerScripts => ConnectedPlayerScripts.Where((PlayerControllerB x) => x.isPlayerDead).ToArray(); public static bool TryGetLocalPlayerScript(out PlayerControllerB playerScript) { playerScript = LocalPlayerScript; return (Object)(object)playerScript != (Object)null; } public static bool IsLocalPlayer(PlayerControllerB playerScript) { if ((Object)(object)playerScript == (Object)null) { return false; } return (Object)(object)playerScript == (Object)(object)LocalPlayerScript; } public static bool IsConnected(PlayerControllerB playerScript) { if ((Object)(object)playerScript == (Object)null) { return false; } if (!playerScript.isPlayerControlled) { return playerScript.isPlayerDead; } return true; } public static PlayerControllerB GetPlayerScriptByClientId(ulong clientId) { return ((IEnumerable)ConnectedPlayerScripts).FirstOrDefault((Func)((PlayerControllerB playerScript) => playerScript.actualClientId == clientId)); } public static bool TryGetPlayerScriptByClientId(ulong clientId, out PlayerControllerB playerScript) { playerScript = GetPlayerScriptByClientId(clientId); return (Object)(object)playerScript != (Object)null; } public static PlayerControllerB GetPlayerScriptByPlayerId(int playerId) { if (playerId < 0 || playerId > ConnectedPlayerScripts.Length - 1) { return null; } return ConnectedPlayerScripts[playerId]; } public static bool TryGetPlayerScriptByPlayerId(int playerId, out PlayerControllerB playerScript) { playerScript = GetPlayerScriptByPlayerId(playerId); return (Object)(object)playerScript != (Object)null; } public static PlayerControllerB GetPlayerScriptByUsername(string username) { PlayerControllerB[] source = ConnectedPlayerScripts.OrderBy((PlayerControllerB x) => x.playerUsername.Length).ToArray(); PlayerControllerB val = ((IEnumerable)source).FirstOrDefault((Func)((PlayerControllerB x) => x.playerUsername.Equals(username, StringComparison.OrdinalIgnoreCase))); if (val == null) { val = ((IEnumerable)source).FirstOrDefault((Func)((PlayerControllerB x) => x.playerUsername.StartsWith(username, StringComparison.OrdinalIgnoreCase))); } if (val == null) { val = ((IEnumerable)source).FirstOrDefault((Func)((PlayerControllerB x) => x.playerUsername.Contains(username, StringComparison.OrdinalIgnoreCase))); } return val; } public static bool TryGetPlayerScriptByUsername(string username, out PlayerControllerB playerScript) { playerScript = GetPlayerScriptByUsername(username); return (Object)(object)playerScript != (Object)null; } public static PlayerControllerB GetRandomPlayerScript(PlayerControllerB[] playerScripts, bool excludeLocal = false) { if (playerScripts == null || playerScripts.Length == 0) { return null; } PlayerControllerB[] array = playerScripts.Where((PlayerControllerB playerScript) => !excludeLocal || !IsLocalPlayer(playerScript)).ToArray(); if (array.Length == 0) { return null; } return array[Random.Range(0, array.Length)]; } public static bool TryGetRandomPlayerScript(PlayerControllerB[] playerScripts, out PlayerControllerB playerScript, bool excludeLocal = false) { playerScript = GetRandomPlayerScript(playerScripts, excludeLocal); return (Object)(object)playerScript != (Object)null; } } internal static class PluginResourceHelper { private static Assembly Assembly => Assembly.GetExecutingAssembly(); public static string AssemblyName => Assembly.GetName().Name; public static string GetResourceName(string relativePath) { return AssemblyName + "." + relativePath.Replace('/', '.').Replace('\\', '.'); } public static Stream OpenResource(string relativePath) { string resourceName = GetResourceName(relativePath); return Assembly.GetManifestResourceStream(resourceName) ?? throw new InvalidOperationException("Embedded resource not found: " + resourceName); } public static string ReadString(string relativePath) { using Stream stream = OpenResource(relativePath); using StreamReader streamReader = new StreamReader(stream); return streamReader.ReadToEnd(); } public static JObject ReadJObject(string relativePath) { //IL_000f: Unknown result type (might be due to invalid IL or missing references) //IL_0015: Expected O, but got Unknown using Stream stream = OpenResource(relativePath); using StreamReader streamReader = new StreamReader(stream); JsonTextReader val = new JsonTextReader((TextReader)streamReader); try { return JObject.Load((JsonReader)(object)val); } finally { ((IDisposable)val)?.Dispose(); } } } } namespace com.github.zehsteam.MelaniesVoice.Extensions { internal static class AssemblyExtensions { public static IEnumerable GetLoadableTypes(this Assembly assembly) { if (assembly == null) { return Array.Empty(); } try { return assembly.GetTypes(); } catch (ReflectionTypeLoadException ex) { return ex.Types.Where((Type type) => type != null); } } } internal static class CollectionExtensions { public static IEnumerable StringToCollection(string s, string separator = ",") { if (string.IsNullOrEmpty(s)) { return Array.Empty(); } T result; return from x in s.Split(separator, StringSplitOptions.RemoveEmptyEntries) where !string.IsNullOrWhiteSpace(x) select x.Trim() into x select (!x.TryConvertTo(out result)) ? default(T) : result into x where x != null select x; } public static string CollectionToString(IEnumerable value, string separator = ", ") { if (value == null || !value.Any()) { return string.Empty; } return string.Join(separator, from x in value where x != null && !string.IsNullOrWhiteSpace(x.ToString()) select x.ToString().Trim()); } } internal static class ConfigEntryExtensions { public static void SetAcceptableValues(this ConfigEntry configEntry, AcceptableValueBase acceptableValues) { FieldInfo fieldInfo = AccessTools.Field(typeof(ConfigDescription), "k__BackingField"); if (fieldInfo == null) { Logger.LogError("[ConfigEntryExtensions] Failed to set acceptable values for config entry. Field is null."); } else { fieldInfo.SetValue(((ConfigEntryBase)configEntry).Description, acceptableValues); } } } internal static class ConfigFileExtensions { public static ConfigEntry Bind(this ConfigFile configFile, string section, string key, T defaultValue, string description, AcceptableValueBase acceptableValues) { //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_0027: Expected O, but got Unknown if (acceptableValues == null) { return configFile.Bind(section, key, defaultValue, description); } return configFile.Bind(section, key, defaultValue, new ConfigDescription(description, acceptableValues, Array.Empty())); } } internal static class StringExtensions { public static T ConvertTo(this string s) { Type typeFromHandle = typeof(T); if ((object)typeFromHandle != null) { Type type = typeFromHandle; object obj; if (type == typeof(int) && int.TryParse(s, NumberStyles.Any, CultureInfo.InvariantCulture, out var result)) { obj = result; } else { Type type2 = typeFromHandle; if (type2 == typeof(float) && float.TryParse(s, NumberStyles.Float, CultureInfo.InvariantCulture, out var result2)) { obj = result2; } else { Type type3 = typeFromHandle; if (type3 == typeof(double) && double.TryParse(s, NumberStyles.Float, CultureInfo.InvariantCulture, out var result3)) { obj = result3; } else { Type type4 = typeFromHandle; if (type4 == typeof(bool) && bool.TryParse(s, out var result4)) { obj = result4; } else { Type type5 = typeFromHandle; if (type5 == typeof(string)) { obj = s; } else { Type type6 = typeFromHandle; if (!type6.IsEnum || !Enum.TryParse(type6, s, ignoreCase: true, out object result5)) { goto IL_0121; } obj = result5; } } } } } object obj2 = obj; return (T)obj2; } goto IL_0121; IL_0121: throw new NotSupportedException($"Unsupported value type: {typeof(T)}"); } public static bool TryConvertTo(this string s, out T result) { try { result = s.ConvertTo(); return true; } catch { result = default(T); return false; } } public static bool EqualsAny(this string s, string[] values, StringComparison comparisonType = StringComparison.CurrentCulture) { return values.Any((string value) => s.Equals(value, comparisonType)); } public static bool ContainsAny(this string s, string[] values, StringComparison comparisonType = StringComparison.CurrentCulture) { return values.Any((string value) => s.Contains(value, comparisonType)); } public static bool StartsWithAny(this string s, string[] values, StringComparison comparisonType = StringComparison.CurrentCulture) { return values.Any((string value) => s.StartsWith(value, comparisonType)); } } } namespace com.github.zehsteam.MelaniesVoice.Dependencies { internal static class LethalConfigProxy { public const string PLUGIN_GUID = "ainavt.lc.lethalconfig"; private static bool? _enabled; public static bool Enabled { get { bool valueOrDefault = _enabled == true; if (!_enabled.HasValue) { valueOrDefault = Chainloader.PluginInfos.ContainsKey("ainavt.lc.lethalconfig"); _enabled = valueOrDefault; } return _enabled.Value; } } [MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.NoOptimization)] public static void SkipAutoGen() { LethalConfigManager.SkipAutoGen(); } [MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.NoOptimization)] public static BaseConfigItem AddConfig(ConfigEntry configEntry, bool requiresRestart = false) { //IL_0065: Unknown result type (might be due to invalid IL or missing references) //IL_006f: Expected O, but got Unknown //IL_0072: Unknown result type (might be due to invalid IL or missing references) //IL_007c: Expected O, but got Unknown //IL_007f: Unknown result type (might be due to invalid IL or missing references) //IL_0089: Expected O, but got Unknown //IL_008d: Unknown result type (might be due to invalid IL or missing references) //IL_0097: Expected O, but got Unknown AcceptableValueBase acceptableValues = ((ConfigEntryBase)configEntry).Description.AcceptableValues; if (acceptableValues != null) { if (acceptableValues is AcceptableValueRange || acceptableValues is AcceptableValueRange) { return AddConfigSlider(configEntry, requiresRestart); } if (acceptableValues is AcceptableValueList) { return AddConfigDropdown(configEntry, requiresRestart); } } if (!(configEntry is ConfigEntry val)) { if (!(configEntry is ConfigEntry val2)) { if (!(configEntry is ConfigEntry val3)) { if (configEntry is ConfigEntry val4) { return AddConfigItem((BaseConfigItem)new IntInputFieldConfigItem(val4, requiresRestart)); } throw new NotSupportedException($"Unsupported type: {typeof(T)}"); } return AddConfigItem((BaseConfigItem)new FloatInputFieldConfigItem(val3, requiresRestart)); } return AddConfigItem((BaseConfigItem)new BoolCheckBoxConfigItem(val2, requiresRestart)); } return AddConfigItem((BaseConfigItem)new TextInputFieldConfigItem(val, requiresRestart)); } [MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.NoOptimization)] public static BaseConfigItem AddConfigSlider(ConfigEntry configEntry, bool requiresRestart = false) { //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_0022: Expected O, but got Unknown //IL_0025: Unknown result type (might be due to invalid IL or missing references) //IL_002f: Expected O, but got Unknown if (!(configEntry is ConfigEntry val)) { if (configEntry is ConfigEntry val2) { return AddConfigItem((BaseConfigItem)new IntSliderConfigItem(val2, requiresRestart)); } throw new NotSupportedException($"Slider not supported for type: {typeof(T)}"); } return AddConfigItem((BaseConfigItem)new FloatSliderConfigItem(val, requiresRestart)); } [MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.NoOptimization)] public static BaseConfigItem AddConfigDropdown(ConfigEntry configEntry, bool requiresRestart = false) { //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_0016: Expected O, but got Unknown if (configEntry is ConfigEntry val) { return AddConfigItem((BaseConfigItem)new TextDropDownConfigItem(val, requiresRestart)); } throw new NotSupportedException($"Dropdown not supported for type: {typeof(T)}"); } [MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.NoOptimization)] private static BaseConfigItem AddConfigItem(BaseConfigItem configItem) { LethalConfigManager.AddConfigItem(configItem); return configItem; } [MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.NoOptimization)] public static void AddButton(string section, string name, string buttonText, string description, Action callback) { //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_0023: Expected O, but got Unknown //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_0028: Expected O, but got Unknown LethalConfigManager.AddConfigItem((BaseConfigItem)new GenericButtonConfigItem(section, name, description, buttonText, (GenericButtonHandler)delegate { callback?.Invoke(); })); } [MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.NoOptimization)] public static void UpdateTextDropDownConfigItem(ConfigEntry configEntry) { Mod val = LethalConfigManager.ModForAssembly(Assembly.GetExecutingAssembly()); if (val == null) { Logger.LogError("[LethalConfigProxy] UpdateTextDropDownConfigItem: Mod is null."); return; } if (!TryGetBaseConfigItem(val, (ConfigEntryBase)(object)configEntry, out var baseConfigItem)) { Logger.LogError("[LethalConfigProxy] UpdateTextDropDownConfigItem: Could not find BaseConfigItem for ConfigEntry."); return; } TextDropDownConfigItem val2 = (TextDropDownConfigItem)(object)((baseConfigItem is TextDropDownConfigItem) ? baseConfigItem : null); if (val2 == null) { Logger.LogError("[LethalConfigProxy] UpdateTextDropDownConfigItem: baseConfigItem is not of type TextDropDownConfigItem."); return; } AcceptableValueBase acceptableValues = ((ConfigEntryBase)configEntry).Description.AcceptableValues; if (!(acceptableValues is AcceptableValueList val3)) { Logger.LogError("[LethalConfigProxy] UpdateTextDropDownConfigItem: configEntry.Description.AcceptableValues is not of type AcceptableValueList."); } else { val2.Values = val3.AcceptableValues.ToList(); } } [MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.NoOptimization)] private static BaseConfigItem GetBaseConfigItem(Mod mod, ConfigEntryBase configEntry) { return ((IEnumerable)mod.ConfigItems).FirstOrDefault((Func)((BaseConfigItem item) => item.BaseConfigEntry == configEntry)); } [MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.NoOptimization)] private static bool TryGetBaseConfigItem(Mod mod, ConfigEntryBase configEntry, out BaseConfigItem baseConfigItem) { baseConfigItem = GetBaseConfigItem(mod, configEntry); return baseConfigItem != null; } } internal static class MirageProxy { public const string PLUGIN_GUID = "qwbarch.Mirage"; private static bool? _enabled; public static bool Enabled { get { bool valueOrDefault = _enabled == true; if (!_enabled.HasValue) { valueOrDefault = Chainloader.PluginInfos.ContainsKey("qwbarch.Mirage"); _enabled = valueOrDefault; } return _enabled.Value; } } [MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.NoOptimization)] public static void SaveAudioClip(AudioClip audioClip) { if (!ConfigManager.MirageCompatibility_Enabled.Value) { return; } try { Recording.saveAudioClipWithName(((Object)audioClip).name, audioClip); } catch (Exception arg) { Logger.LogError($"[MirageProxy] Failed to save audio clip: {arg}"); } } } } namespace System.Runtime.CompilerServices { [AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)] internal sealed class IgnoresAccessChecksToAttribute : Attribute { public IgnoresAccessChecksToAttribute(string assemblyName) { } } } namespace __GEN { internal class NetworkVariableSerializationHelper { [RuntimeInitializeOnLoadMethod] internal static void InitializeSerialization() { } } } namespace com.github.zehsteam.MelaniesVoice.NetcodePatcher { [AttributeUsage(AttributeTargets.Module)] internal class NetcodePatchedAssemblyAttribute : Attribute { } }