Please disclose if your mod was created primarily using AI tools by adding the 'AI Generated' category. Failing to do so may result in the mod being removed from Thunderstore.
Decompiled source of espeakTTS v0.2.4
espeakTTS.dll
Decompiled 6 months agousing System; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.Versioning; using System.Security; using System.Security.Permissions; using System.Text; using System.Text.RegularExpressions; using System.Threading; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using ExitGames.Client.Photon; using HarmonyLib; using Microsoft.CodeAnalysis; using Photon.Pun; using Photon.Realtime; using Unity.VisualScripting; using UnityEngine; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)] [assembly: IgnoresAccessChecksTo("Assembly-CSharp-firstpass")] [assembly: IgnoresAccessChecksTo("Assembly-CSharp")] [assembly: IgnoresAccessChecksTo("Autodesk.Fbx")] [assembly: IgnoresAccessChecksTo("Discord.Sdk")] [assembly: IgnoresAccessChecksTo("Domain_Reload")] [assembly: IgnoresAccessChecksTo("Facepunch.Steamworks.Win64")] [assembly: IgnoresAccessChecksTo("FbxBuildTestAssets")] [assembly: IgnoresAccessChecksTo("Klattersynth")] [assembly: IgnoresAccessChecksTo("Photon3Unity3D")] [assembly: IgnoresAccessChecksTo("PhotonChat")] [assembly: IgnoresAccessChecksTo("PhotonRealtime")] [assembly: IgnoresAccessChecksTo("PhotonUnityNetworking")] [assembly: IgnoresAccessChecksTo("PhotonUnityNetworking.Utilities")] [assembly: IgnoresAccessChecksTo("PhotonVoice.API")] [assembly: IgnoresAccessChecksTo("PhotonVoice")] [assembly: IgnoresAccessChecksTo("PhotonVoice.PUN")] [assembly: IgnoresAccessChecksTo("SingularityGroup.HotReload.Runtime")] [assembly: IgnoresAccessChecksTo("SingularityGroup.HotReload.Runtime.Public")] [assembly: IgnoresAccessChecksTo("Sirenix.OdinInspector.Attributes")] [assembly: IgnoresAccessChecksTo("Sirenix.Serialization.Config")] [assembly: IgnoresAccessChecksTo("Sirenix.Serialization")] [assembly: IgnoresAccessChecksTo("Sirenix.Utilities")] [assembly: IgnoresAccessChecksTo("Unity.AI.Navigation")] [assembly: IgnoresAccessChecksTo("Unity.Burst")] [assembly: IgnoresAccessChecksTo("Unity.Burst.Unsafe")] [assembly: IgnoresAccessChecksTo("Unity.Collections")] [assembly: IgnoresAccessChecksTo("Unity.Collections.LowLevel.ILSupport")] [assembly: IgnoresAccessChecksTo("Unity.Formats.Fbx.Runtime")] [assembly: IgnoresAccessChecksTo("Unity.InputSystem")] [assembly: IgnoresAccessChecksTo("Unity.InputSystem.ForUI")] [assembly: IgnoresAccessChecksTo("Unity.Mathematics")] [assembly: IgnoresAccessChecksTo("Unity.MemoryProfiler")] [assembly: IgnoresAccessChecksTo("Unity.Postprocessing.Runtime")] [assembly: IgnoresAccessChecksTo("Unity.Profiling.Core")] [assembly: IgnoresAccessChecksTo("Unity.RenderPipelines.Core.Runtime")] [assembly: IgnoresAccessChecksTo("Unity.RenderPipelines.Core.ShaderLibrary")] [assembly: IgnoresAccessChecksTo("Unity.RenderPipelines.ShaderGraph.ShaderGraphLibrary")] [assembly: IgnoresAccessChecksTo("Unity.Splines")] [assembly: IgnoresAccessChecksTo("Unity.TextMeshPro")] [assembly: IgnoresAccessChecksTo("Unity.Timeline")] [assembly: IgnoresAccessChecksTo("Unity.VisualScripting.Antlr3.Runtime")] [assembly: IgnoresAccessChecksTo("Unity.VisualScripting.Core")] [assembly: IgnoresAccessChecksTo("Unity.VisualScripting.Flow")] [assembly: IgnoresAccessChecksTo("Unity.VisualScripting.State")] [assembly: IgnoresAccessChecksTo("UnityEngine.ARModule")] [assembly: IgnoresAccessChecksTo("UnityEngine.NVIDIAModule")] [assembly: IgnoresAccessChecksTo("UnityEngine.UI")] [assembly: IgnoresAccessChecksTo("websocket-sharp")] [assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")] [assembly: AssemblyCompany("Lavighju")] [assembly: AssemblyConfiguration("Debug")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0")] [assembly: AssemblyProduct("espeakTTS")] [assembly: AssemblyTitle("espeakTTS")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("1.0.0.0")] [module: UnverifiableCode] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)] internal sealed class NullableAttribute : Attribute { public readonly byte[] NullableFlags; public NullableAttribute(byte P_0) { NullableFlags = new byte[1] { P_0 }; } public NullableAttribute(byte[] P_0) { NullableFlags = P_0; } } [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)] internal sealed class NullableContextAttribute : Attribute { public readonly byte Flag; public NullableContextAttribute(byte P_0) { Flag = P_0; } } [CompilerGenerated] [Microsoft.CodeAnalysis.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 repo_espeak { public class Client { private enum AudioOutput { Playback, Retrieval, Synchronous, SynchronousPlayback } private enum Error { EE_OK = 0, EE_INTERNAL_ERROR = -1, EE_BUFFER_FULL = 1, EE_NOT_FOUND = 2 } private enum PositionType { Character = 1, Word, Sentence } private enum Parameter { Rate = 1, Volume = 2, Pitch = 3, Range = 4, Punctuation = 5, Capitals = 6, WordGap = 7, Intonation = 9 } private enum ParameterType { Absolute, Relative } [Flags] private enum SpeechFlags { CharsUtf8 = 1, SSML = 0x10 } private static bool Initialized; public static int sampleRate; public static void Initialize(string path) { try { byte[] bytes = Encoding.UTF8.GetBytes(path + "\0"); IntPtr intPtr = Marshal.AllocHGlobal(bytes.Length); Marshal.Copy(bytes, 0, intPtr, bytes.Length); int num = espeak_Initialize(AudioOutput.Retrieval, 0, intPtr, 0); Marshal.FreeHGlobal(intPtr); if (num == -1) { Debug.LogError((object)$"Could not initialize ESpeak. Maybe there is no espeak data at {path}?"); } else { sampleRate = num; } } catch (Exception ex) { Debug.LogError((object)ex); } espeak_SetSynthCallback(EventHandler.Handle); Initialized = true; } public static int SetRate(int rate) { if (rate < 80 && rate > 450) { Debug.LogError((object)"The rate must be between 80 and 450."); } Error result = espeak_SetParameter(Parameter.Rate, rate, ParameterType.Absolute); return CheckResult(result); } public static int SetWordgap(int wordgap) { if (wordgap < 0) { wordgap = 0; } Error result = espeak_SetParameter(Parameter.WordGap, wordgap, ParameterType.Absolute); return CheckResult(result); } public static bool VoiceFinished() { bool result = false; EventHandler.audio_files_mutex.WaitOne(); if (EventHandler.audio_files.Count > 0) { result = true; } EventHandler.audio_files_mutex.ReleaseMutex(); return result; } public static int SetPitch(int pitch) { if (pitch < 0) { pitch = 0; } if (pitch > 100) { pitch = 100; } Error result = espeak_SetParameter(Parameter.Pitch, pitch, ParameterType.Absolute); return CheckResult(result); } private static int CheckResult(Error result) { return (int)result; } public static int Speak(TTSWord text) { EventHandler.audio_files_mutex.WaitOne(); EventHandler.audio_files.Add(text); SetVoiceByName(text.parameters.Language + "+" + text.parameters.Variant); SetPitch(text.parameters.Pitch); SetRate(text.parameters.Speed); SetWordgap(text.parameters.Gap / 10); Error result = espeak_Synth(text.word, text.word.Length * Marshal.SystemDefaultCharSize, 0u, PositionType.Character, 0u, SpeechFlags.CharsUtf8, (UIntPtr)0u, (IntPtr)0); EventHandler.audio_files_mutex.ReleaseMutex(); return CheckResult(result); } public static int SetVoiceByName(string name) { Error result = espeak_SetVoiceByName(name); return CheckResult(result); } [DllImport("libespeak-ng.dll", CallingConvention = CallingConvention.Cdecl)] private static extern Error espeak_SetVoiceByName([MarshalAs(UnmanagedType.LPUTF8Str)] string name); [DllImport("libespeak-ng.dll", CallingConvention = CallingConvention.Cdecl)] private static extern Error espeak_SetParameter(Parameter parameter, int value, ParameterType type); [DllImport("libespeak-ng.dll", CallingConvention = CallingConvention.Cdecl)] private static extern Error espeak_Synth([MarshalAs(UnmanagedType.LPUTF8Str)] string text, int size, uint startPosition = 0u, PositionType positionType = PositionType.Character, uint endPosition = 0u, SpeechFlags flags = SpeechFlags.CharsUtf8, UIntPtr uniqueIdentifier = default(UIntPtr), IntPtr userData = default(IntPtr)); [DllImport("libespeak-ng.dll", CallingConvention = CallingConvention.Cdecl)] private static extern int espeak_Initialize(AudioOutput output, int bufferLength, IntPtr path, int options); [DllImport("libespeak-ng.dll", CallingConvention = CallingConvention.Cdecl)] private static extern void espeak_SetSynthCallback(EventHandler.SynthCallback callback); } internal struct Event { public enum EventType { ListTerminated, Word, Sentence, Mark, Play, End, MessageTerminated, Phoneme, SetSampleRate } public EventType Type; public uint UniqueIdentifier; public int TextPosition; public int Length; public int AudioPosition; public int Sample; public IntPtr UserData; public int Id; } internal class EventHandler { public delegate int SynthCallback(IntPtr wavePtr, int bufferLength, IntPtr eventsPtr); private static MemoryStream Stream; public static Mutex audio_files_mutex = new Mutex(); public static List<TTSWord> audio_files = new List<TTSWord>(); public static int Handle(IntPtr wavePtr, int bufferLength, IntPtr eventsPtr) { if (bufferLength == 0) { if (Stream != null) { Stream.Flush(); audio_files_mutex.WaitOne(); byte[] array = Stream.ToArray(); float[] array2 = new float[array.Length / 2]; for (int i = 0; i < array2.Length; i++) { if (i < 20 || i > array2.Length - 11) { array2[i] = 0f; } else { array2[i] = (float)BitConverter.ToInt16(array, i * 2) / 32767f; } } if (audio_files.Count > 0 && audio_files[0] != null) { audio_files[0].audio_buffer = array2; } audio_files.RemoveAt(0); audio_files_mutex.ReleaseMutex(); Stream.Dispose(); Stream = null; } return 0; } WriteAudioToStream(wavePtr, bufferLength); List<Event> list = MarshalEvents(eventsPtr); foreach (Event item in list) { } return 0; } private static List<Event> MarshalEvents(IntPtr eventsPtr) { List<Event> list = new List<Event>(); int num = Marshal.SizeOf(typeof(Event)); int num2 = 0; while (true) { IntPtr ptr = new IntPtr(eventsPtr.ToInt64() + num * num2); Event item = (Event)Marshal.PtrToStructure(ptr, typeof(Event)); if (item.Type == Event.EventType.ListTerminated) { break; } list.Add(item); num2++; } return list; } private static int WriteAudioToStream(IntPtr wavePtr, int bufferLength) { if (wavePtr == IntPtr.Zero) { return 0; } if (Stream == null) { Stream = new MemoryStream(); InitializeStream(); } byte[] array = new byte[bufferLength * 2]; Marshal.Copy(wavePtr, array, 0, array.Length); Stream.Write(array, 0, array.Length); return 0; } private static void InitializeStream() { Encoding aSCII = Encoding.ASCII; Stream.Write(aSCII.GetBytes("RIFF"), 0, 4); Stream.Write(BitConverter.GetBytes(0), 0, 4); Stream.Write(aSCII.GetBytes("WAVEfmt "), 0, 8); Stream.Write(BitConverter.GetBytes(16), 0, 4); Stream.Write(BitConverter.GetBytes((short)1), 0, 2); Stream.Write(BitConverter.GetBytes((short)1), 0, 2); Stream.Write(BitConverter.GetBytes(22050), 0, 4); Stream.Write(BitConverter.GetBytes(44100), 0, 4); Stream.Write(BitConverter.GetBytes((short)2), 0, 2); Stream.Write(BitConverter.GetBytes((short)16), 0, 2); Stream.Write(aSCII.GetBytes("DATA"), 0, 4); Stream.Write(BitConverter.GetBytes(0), 0, 4); } private static string PrintBytes(byte[] byteArray) { StringBuilder stringBuilder = new StringBuilder("new byte[] { "); for (int i = 0; i < byteArray.Length; i++) { byte value = byteArray[i]; stringBuilder.Append(value); if (i < byteArray.Length - 1) { stringBuilder.Append(", "); } } stringBuilder.Append(" }"); return stringBuilder.ToString(); } private static string ConvertHeadersToString(byte[] buffer) { StringBuilder stringBuilder = new StringBuilder(); stringBuilder.AppendFormat("The stream length is {0}.\n", Stream.Length); stringBuilder.Append(Encoding.ASCII.GetChars(buffer, 0, 4)); stringBuilder.Append(BitConverter.ToInt32(buffer, 4)); stringBuilder.Append(Encoding.ASCII.GetChars(buffer, 8, 8)); stringBuilder.Append(BitConverter.ToInt32(buffer, 16)); stringBuilder.Append(BitConverter.ToInt16(buffer, 20)); stringBuilder.Append(BitConverter.ToInt16(buffer, 22)); stringBuilder.Append(BitConverter.ToInt32(buffer, 24)); stringBuilder.Append(BitConverter.ToInt32(buffer, 28)); stringBuilder.Append(BitConverter.ToInt16(buffer, 32)); stringBuilder.Append(BitConverter.ToInt16(buffer, 34)); stringBuilder.Append(Encoding.ASCII.GetChars(buffer, 36, 4)); stringBuilder.Append(BitConverter.ToInt32(buffer, 40)); return stringBuilder.ToString(); } } public struct eSpeakParameters { public string Language; public string Variant; public int Pitch; public int Speed; public int Gap; public eSpeakParameters(string language, string variant, int pitch, int speed, int gap) { Language = language; Variant = variant; Pitch = pitch; Speed = speed; Gap = gap; } } internal class playerEspeak : MonoBehaviour { public TTSVoice ttsvoice; public static eSpeakParameters TTSParameters; public long end_timestamp = 0L; public List<TTSWord> words = new List<TTSWord>(); public static void init(string language, string variant, int pitch, int speed, int gap, string espeak_data_path) { TTSParameters = new eSpeakParameters(language, variant, pitch, speed, gap); try { espeak_data_path += "\\espeak-ng-data"; Client.Initialize(espeak_data_path); } catch (Exception ex) { repo_espeak.Logger.LogError((object)ex); } } public void Update() { if (words.Count > 0 && words[0] != null) { bool flag = false; long num = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds(); if (num <= end_timestamp) { flag = true; } if (words[0].audio_buffer != null && !flag) { repo_espeak.Logger.LogDebug((object)$"{((Object)ttsvoice).GetInstanceID()}: Playing word: {words[0].word}"); AudioClip val = AudioClip.Create("espeakTTS" + ((Object)ttsvoice).GetInstanceID(), words[0].audio_buffer.Length, 1, Client.sampleRate, false); val.SetData(words[0].audio_buffer, 0); end_timestamp = num + (long)(val.length * 1000f); words[0].TTSInstance.VoiceText(words[0].word, val.length); words[0].TTSInstance.audioSource.PlayOneShot(val); words.RemoveAt(0); } } } public void stopSentence() { repo_espeak.Logger.LogDebug((object)$"{((Object)ttsvoice).GetInstanceID()}: Stopping all current words..."); words.RemoveAll((TTSWord word) => word != null); words.Clear(); end_timestamp = 0L; } public void speakSentence(string text, bool crouch, eSpeakParameters parameters, TTSVoice instance, bool natural) { instance.StopAndClearVoice(); stopSentence(); instance.setVoice(0); if (!Object.op_Implicit((Object)(object)instance.activeVoice)) { repo_espeak.Logger.LogError((object)"Active voice is not set."); } text = instance.TranslateSpecialLetters(text); if (natural) { instance.words = new List<string> { text }; } else { instance.words = new List<string>(text.Split(' ')); } schedule_play(instance.words, instance, crouch, parameters); } private void schedule_play(List<string> word_list, TTSVoice TTSInstance, bool whisper = false, eSpeakParameters? parameters = null) { if (!parameters.HasValue) { parameters = TTSParameters; } foreach (string item in word_list) { TTSWord tTSWord = new TTSWord(item, TTSInstance, parameters.Value, whisper); words.Add(tTSWord); repo_espeak.Logger.LogDebug((object)$"{((Object)ttsvoice).GetInstanceID()}: Generating audio for word: {tTSWord.word}"); Client.Speak(tTSWord); } } } internal class punEspeak : MonoBehaviour { public PlayerAvatar playerAvatar; public const int mod_version = 1; public void sendVersion() { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_0017: Expected O, but got Unknown //IL_0019: Expected O, but got Unknown Hashtable val = new Hashtable(); ((Dictionary<object, object>)val).Add((object)"espeakVersion", (object)1); Hashtable val2 = val; playerAvatar.photonView.Owner.SetCustomProperties(val2, (Hashtable)null, (WebFlags)null); } [PunRPC] public void eSpeakChatMessageSendRPC(string _message, bool crouching, string lang, string variant, int speed, int pitch, bool natural, int gap) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Invalid comparison between Unknown and I4 if ((int)GameDirector.instance.currentState != 2) { return; } ((Dictionary<object, object>)(object)playerAvatar.photonView.Owner.CustomProperties).TryGetValue((object)"espeakVersion", out object value); if (!(value is int)) { return; } int num = (int)value; if (num == 1) { if (variant.ToLower() == "whisper" || variant.ToLower() == "whisperf") { variant = ""; } if (pitch < 0 || pitch > 99) { pitch = 25; } if (speed < 80 || speed > 500) { speed = 100; } if (!repo_espeak.natural_voice.Value || gap < 10 || gap > 1000) { gap = 10; } variant = (crouching ? "whisper" : variant); string[] array = repo_espeak.blacklist.Value.Split(","); for (int i = 0; i < array.Length; i++) { _message = Regex.Replace(_message, Regex.Escape(array[i].Trim()), " ", RegexOptions.IgnoreCase); } repo_espeak.Logger.LogDebug((object)$"{((Object)playerAvatar).GetInstanceID()}: Received espeak TTS RPC"); playerEspeak component = ((Component)playerAvatar.voiceChat.ttsVoice).GetComponent<playerEspeak>(); component.speakSentence(_message, crouching, new eSpeakParameters(lang, variant, pitch, speed, gap), playerAvatar.voiceChat.ttsVoice, natural); } } } [BepInPlugin("Lavighju.espeakTTS", "espeakTTS", "0.2.3")] public class repo_espeak : BaseUnityPlugin { private class HarmonyPatches { [HarmonyPatch(typeof(TTSVoice), "StartSpeakingWithHighlight")] [HarmonyPrefix] private static bool StartSpeakingWithHighlightPrefix(ref string text, bool crouch, TTSVoice __instance) { playerEspeak component = ((Component)__instance).GetComponent<playerEspeak>(); if (Object.op_Implicit((Object)(object)__instance.playerAvatar)) { ((Dictionary<object, object>)(object)__instance.playerAvatar.photonView.Owner.CustomProperties).TryGetValue((object)"espeakVersion", out object value); if (value is int num) { if (num == 1) { return false; } Logger.LogDebug((object)$"{((Object)__instance.playerAvatar).GetInstanceID()} has an incompatible mod version. You won't be able to hear their custom voice."); } else { Logger.LogDebug((object)$"{((Object)__instance.playerAvatar).GetInstanceID()} does not have the mod installed."); } } Logger.LogDebug((object)$"{((Object)__instance).GetInstanceID()}: Received vanilla RPC"); component.speakSentence(text, crouch, new eSpeakParameters(default_language.Value, default_variant.Value, default_pitch.Value, default_speed.Value, natural_gap.Value), __instance, natural_voice.Value); return false; } public static bool ChatMessageSendPrefix(ref string _message, object[] __args, PlayerAvatar __instance) { bool flag = false; if (__args.Length > 1 && __args[1] is bool flag2) { flag = flag2; } string value = language.Value; string pattern = "^\\[(.*?)\\]\\s*"; Match match = Regex.Match(_message, pattern); if (match.Success) { value = match.Groups[1].Value; _message = Regex.Replace(_message, pattern, ""); } bool flag3 = __instance.isCrouching; if (!SemiFunc.IsMultiplayer()) { return true; } if (__instance.isDisabled) { flag3 = true; } Logger.LogDebug((object)("Sending espeak message RPC: " + _message)); __instance.photonView.RPC("eSpeakChatMessageSendRPC", (RpcTarget)0, new object[8] { _message, flag3, value, variant.Value, speed.Value, pitch.Value, natural_voice.Value, natural_gap.Value }); return true; } [HarmonyPatch(typeof(TTSVoice), "Start")] [HarmonyPostfix] private static void AwakeSpeechPost(TTSVoice __instance) { if (SemiFunc.IsMultiplayer()) { playerEspeak playerEspeak2 = ComponentHolderProtocol.AddComponent<playerEspeak>((Object)(object)__instance); playerEspeak2.ttsvoice = __instance; Logger.LogDebug((object)$"Created espeak player for TTSVoice {((Object)__instance).GetInstanceID()}"); } } [HarmonyPatch(typeof(PlayerAvatar), "Awake")] [HarmonyPostfix] private static void AwakePlayerAvatarPost(PlayerAvatar __instance) { if (SemiFunc.IsMultiplayer()) { punEspeak punEspeak2 = ComponentHolderProtocol.AddComponent<punEspeak>((Object)(object)__instance); punEspeak2.playerAvatar = __instance; if (__instance.photonView.IsMine) { punEspeak2.sendVersion(); } Logger.LogDebug((object)$"Created espeak pun for player Avatar {((Object)__instance).GetInstanceID()}"); } } } public static readonly string[] language_list = new string[128] { "af", "sq", "am", "ar", "an", "hy", "hyw", "as", "az", "ba", "cu", "eu", "be", "bn", "bpy", "bs", "bg", "my", "ca", "chr", "yue", "hak", "haw", "cmn", "hr", "cs", "da", "nl", "en-us", "en", "en-029", "en-gb-x-gbclan", "en-gb-x-rp", "en-gb-scotland", "en-gb-x-gbcwmd", "eo", "et", "fa", "fa-latn", "fi", "fr-be", "fr", "fr-ch", "ga", "gd", "ka", "de", "grc", "el", "kl", "gn", "gu", "ht", "he", "hi", "hu", "is", "id", "ia", "io", "it", "ja", "kn", "kok", "ko", "ku", "kk", "ky", "la", "lb", "ltg", "lv", "lfn", "lt", "jbo", "mi", "mk", "ms", "ml", "mt", "mr", "nci", "ne", "nb", "nog", "or", "om", "pap", "py", "pl", "pt-br", "qdb", "qu", "quc", "qya", "pt", "pa", "piqd", "ro", "ru", "ru-lv", "uk", "sjn", "sr", "tn", "sd", "shn", "si", "sk", "sl", "smj", "es", "es-419", "sw", "sv", "ta", "th", "tk", "tt", "te", "tr", "ug", "ur", "uz", "vi-vn-x-central", "vi", "vi-vn-x-south", "cy" }; public static readonly string[] variant_list = new string[101] { "", "semibot", "adam", "Alex", "Alicia", "Andrea", "Andy", "anika", "anikaRobot", "Annie", "announcer", "antonio", "AnxiousAndy", "aunty", "belinda", "benjamin", "boris", "caleb", "croak", "david", "Demonic", "Denis", "Diogo", "ed", "edward", "edward2", "f1", "f2", "f3", "f4", "f5", "fast", "Gene", "Gene2", "grandma", "grandpa", "gustave", "Henrique", "Hugo", "iven", "iven2", "iven3", "iven4", "Jacky", "john", "kaukovalta", "klatt", "klatt2", "klatt3", "klatt4", "klatt5", "klatt6", "Lee", "linda", "m1", "m2", "m3", "m4", "m5", "m6", "m7", "m8", "marcelo", "Marco", "Mario", "max", "Michael", "michel", "miguel", "Mike", "Mr serious", "Nguyen", "norbert", "pablo", "paul", "pedro", "quincy", "RicishayMax", "RicishayMax2", "RicishayMax3", "rob", "robert", "robosoft", "robosoft2", "robosoft3", "robosoft4", "robosoft5", "robosoft6", "robosoft7", "robosoft8", "sandro", "shelby", "steph", "steph2", "steph3", "Storm", "travis", "Tweaky", "UniRobot", "victor", "zac" }; public static ConfigEntry<string> language; public static ConfigEntry<string> variant; public static ConfigEntry<int> pitch; public static ConfigEntry<int> speed; public static ConfigEntry<string> default_language; public static ConfigEntry<string> default_variant; public static ConfigEntry<int> default_pitch; public static ConfigEntry<int> default_speed; public static ConfigEntry<bool> natural_voice; public static ConfigEntry<int> natural_gap; public static ConfigEntry<string> blacklist; internal static repo_espeak Instance { get; private set; } = null; public static ManualLogSource Logger => Instance._logger; private ManualLogSource _logger => ((BaseUnityPlugin)this).Logger; internal Harmony? Harmony { get; set; } private void Awake() { //IL_002a: Unknown result type (might be due to invalid IL or missing references) //IL_0034: Expected O, but got Unknown //IL_0062: Unknown result type (might be due to invalid IL or missing references) //IL_006c: Expected O, but got Unknown //IL_0095: Unknown result type (might be due to invalid IL or missing references) //IL_009f: Expected O, but got Unknown //IL_00cf: Unknown result type (might be due to invalid IL or missing references) //IL_00d9: Expected O, but got Unknown //IL_0107: Unknown result type (might be due to invalid IL or missing references) //IL_0111: Expected O, but got Unknown //IL_013f: Unknown result type (might be due to invalid IL or missing references) //IL_0149: Expected O, but got Unknown //IL_0172: Unknown result type (might be due to invalid IL or missing references) //IL_017c: Expected O, but got Unknown //IL_01ac: Unknown result type (might be due to invalid IL or missing references) //IL_01b6: Expected O, but got Unknown //IL_01d7: Unknown result type (might be due to invalid IL or missing references) //IL_01e1: Expected O, but got Unknown //IL_020e: Unknown result type (might be due to invalid IL or missing references) //IL_0218: Expected O, but got Unknown //IL_0246: Unknown result type (might be due to invalid IL or missing references) //IL_0250: Expected O, but got Unknown language = ((BaseUnityPlugin)this).Config.Bind<string>("General", "Language", "en", new ConfigDescription("Language set for the TTS. You can find the identifier for your language here: https://github.com/espeak-ng/espeak-ng/blob/59823f30e3edbd01e87002c04a49ebfd63edaaa7/docs/languages.md", (AcceptableValueBase)(object)new AcceptableValueList<string>(language_list), Array.Empty<object>())); variant = ((BaseUnityPlugin)this).Config.Bind<string>("General", "Variant", "semibot", new ConfigDescription("Variant of the voice", (AcceptableValueBase)(object)new AcceptableValueList<string>(variant_list), Array.Empty<object>())); pitch = ((BaseUnityPlugin)this).Config.Bind<int>("General", "Pitch", 50, new ConfigDescription("Pitch of the voice, 0-99", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 99), Array.Empty<object>())); speed = ((BaseUnityPlugin)this).Config.Bind<int>("General", "Speed", 175, new ConfigDescription("Speed of the voice, 80-500", (AcceptableValueBase)(object)new AcceptableValueRange<int>(80, 500), Array.Empty<object>())); default_language = ((BaseUnityPlugin)this).Config.Bind<string>("TTS for players without the mod installed", "Language", "en", new ConfigDescription("Language set for the TTS for players without the mod installed", (AcceptableValueBase)(object)new AcceptableValueList<string>(language_list), Array.Empty<object>())); default_variant = ((BaseUnityPlugin)this).Config.Bind<string>("TTS for players without the mod installed", "Variant", "semibot", new ConfigDescription("Variant of the voice", (AcceptableValueBase)(object)new AcceptableValueList<string>(variant_list), Array.Empty<object>())); default_pitch = ((BaseUnityPlugin)this).Config.Bind<int>("TTS for players without the mod installed", "Pitch", 50, new ConfigDescription("Pitch of the voice, 0-99", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 99), Array.Empty<object>())); default_speed = ((BaseUnityPlugin)this).Config.Bind<int>("TTS for players without the mod installed", "Speed", 175, new ConfigDescription("Speed of the voice, 80-500", (AcceptableValueBase)(object)new AcceptableValueRange<int>(80, 500), Array.Empty<object>())); natural_voice = ((BaseUnityPlugin)this).Config.Bind<bool>("Full sentences settings", "Enable full sentences", false, new ConfigDescription("Enable or disable full sentences (whole sentences spoken instead of word by word)", (AcceptableValueBase)null, Array.Empty<object>())); natural_gap = ((BaseUnityPlugin)this).Config.Bind<int>("Full sentences settings", "Gap", 10, new ConfigDescription("Word gap in sentences, in milliseconds", (AcceptableValueBase)(object)new AcceptableValueRange<int>(10, 1000), Array.Empty<object>())); blacklist = ((BaseUnityPlugin)this).Config.Bind<string>("Words blacklist", "Blacklist", "...", new ConfigDescription("Word list that will be skipped by TTS. Separated by commas (e.g. \"...,test,etc\")", (AcceptableValueBase)null, new object[1] { "HideFromREPOConfig" })); Instance = this; ((Component)this).gameObject.transform.parent = null; ((Object)((Component)this).gameObject).hideFlags = (HideFlags)61; string text = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location); if (Directory.Exists(text + "\\plugins\\espeak-ng-data")) { text += "\\plugins"; } else if (!Directory.Exists(text + "\\espeak-ng-data")) { Logger.LogError((object)("Could not find the folder espeak-ng-data. Are you sure it is present in the plugin's folder " + text + " ?")); return; } Logger.LogInfo((object)("Trying to initialize the dictionnary from this location: " + text)); try { playerEspeak.init(language.Value, variant.Value, pitch.Value, speed.Value, natural_gap.Value, text); Patch(); } catch (Exception ex) { Logger.LogError((object)"An error occured during initialization:"); Logger.LogError((object)ex); } Logger.LogInfo((object)$"{((BaseUnityPlugin)this).Info.Metadata.GUID} v{((BaseUnityPlugin)this).Info.Metadata.Version} has successfully loaded"); } internal void Patch() { //IL_001a: 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) //IL_0021: Expected O, but got Unknown //IL_0026: Expected O, but got Unknown //IL_00d4: Unknown result type (might be due to invalid IL or missing references) //IL_00e2: Expected O, but got Unknown if (Harmony == null) { Harmony val = new Harmony(((BaseUnityPlugin)this).Info.Metadata.GUID); Harmony val2 = val; Harmony = val; } Harmony.PatchAll(typeof(HarmonyPatches)); MethodInfo methodInfo = null; methodInfo = typeof(PlayerAvatar).GetMethod("ChatMessageSend", new Type[2] { typeof(string), typeof(bool) }); if (methodInfo == null) { methodInfo = typeof(PlayerAvatar).GetMethod("ChatMessageSend", new Type[1] { typeof(string) }); } if (methodInfo != null) { MethodInfo method = typeof(HarmonyPatches).GetMethod("ChatMessageSendPrefix"); Harmony.Patch((MethodBase)methodInfo, new HarmonyMethod(method), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); } } internal void Unpatch() { Harmony? harmony = Harmony; if (harmony != null) { harmony.UnpatchSelf(); } } } public class TTSWord { public string word { get; } public TTSVoice TTSInstance { get; } public eSpeakParameters parameters { get; } public float[] audio_buffer { get; set; } public bool whisper { get; } public TTSWord(string w, TTSVoice a, eSpeakParameters p, bool c = false, float[] ab = null) { word = w; TTSInstance = a; parameters = p; audio_buffer = ab; whisper = c; } } }