Please disclose if any significant portion of your mod was created using AI tools by adding the 'AI Generated' category. Failing to do so may result in the mod being removed from Thunderstore.
Decompiled source of Tongue v1.0.0
tongue.dll
Decompiled a year agousing System; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Linq; 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 BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using ExitGames.Client.Photon; using HarmonyLib; using Microsoft.CodeAnalysis; using REPOLib.Modules; using Strobotnik.Klattersynth; using UnityEngine; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)] [assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")] [assembly: AssemblyCompany("tongue")] [assembly: AssemblyConfiguration("Debug")] [assembly: AssemblyFileVersion("0.1.1.0")] [assembly: AssemblyInformationalVersion("0.1.1+0616cb263e2b8da20975f29505302f335ec69195")] [assembly: AssemblyProduct("Tongue")] [assembly: AssemblyTitle("tongue")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("0.1.1.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.Module, AllowMultiple = false, Inherited = false)] internal sealed class RefSafetyRulesAttribute : Attribute { public readonly int Version; public RefSafetyRulesAttribute(int P_0) { Version = P_0; } } } namespace tongue { [BepInPlugin("sane.tongue", "Tongue", "1.0.0")] [BepInProcess("REPO.exe")] [BepInIncompatibility("Lavighju.espeakTTS")] [BepInDependency(/*Could not decode attribute arguments.*/)] [HarmonyPatch] public class Tongue : BaseUnityPlugin { internal static ManualLogSource Logger; public static NetworkedEvent LanguageChangeEvent; private ConfigEntry<string> languageSetting; private const int AUDIO_OUTPUT_SYNCHRONOUS = 0; private const int espeakCHARS_UTF8 = 1; private const int PHONEME_MODE_ASCII = 0; private string currentSpeaker = ""; private Dictionary<string, string> languagePerPlayer = new Dictionary<string, string>(); public static readonly string[] language_list = new string[128] { "af", "am", "an", "ar", "as", "az", "ba", "be", "bg", "bn", "bpy", "bs", "ca", "chr", "cmn", "cs", "cu", "cy", "da", "de", "el", "en", "en-029", "en-gb-scotland", "en-gb-x-gbclan", "en-gb-x-gbcwmd", "en-gb-x-rp", "en-us", "eo", "es", "es-419", "et", "eu", "fa", "fa-latn", "fi", "fr", "fr-be", "fr-ch", "ga", "gd", "gn", "grc", "gu", "hak", "haw", "he", "hi", "hr", "ht", "hu", "hy", "hyw", "ia", "id", "io", "is", "it", "ja", "jbo", "ka", "kk", "kl", "kn", "ko", "kok", "ku", "ky", "la", "lb", "lfn", "lt", "ltg", "lv", "mi", "mk", "ml", "mr", "ms", "mt", "my", "nb", "nci", "ne", "nl", "nog", "om", "or", "pa", "pap", "piqd", "pl", "pt", "pt-br", "py", "qdb", "qu", "quc", "qya", "ro", "ru", "ru-lv", "sd", "shn", "si", "sjn", "sk", "sl", "smj", "sq", "sr", "sv", "sw", "ta", "te", "th", "tk", "tn", "tr", "tt", "ug", "uk", "ur", "uz", "vi", "vi-vn-x-central", "vi-vn-x-south", "yue" }; public static Tongue Instance { get; private set; } [DllImport("libespeak-ng.dll", CallingConvention = CallingConvention.Cdecl)] public static extern int espeak_Initialize(int output, int buflength, string path, int options); [DllImport("libespeak-ng.dll", CallingConvention = CallingConvention.Cdecl)] public static extern int espeak_SetVoiceByName(string name); [DllImport("libespeak-ng.dll", CallingConvention = CallingConvention.Cdecl)] public static extern IntPtr espeak_TextToPhonemes(ref IntPtr textPtr, int textMode, int phonemeMode); public static string phoneticize(string text, string language) { if (language == "en") { return text; } espeak_SetVoiceByName(language); byte[] bytes = Encoding.UTF8.GetBytes(text + "\0"); IntPtr intPtr = Marshal.AllocHGlobal(bytes.Length); Marshal.Copy(bytes, 0, intPtr, bytes.Length); IntPtr textPtr = intPtr; IntPtr intPtr2 = espeak_TextToPhonemes(ref textPtr, 1, 0); if (intPtr2 != IntPtr.Zero) { string text2 = Marshal.PtrToStringAnsi(intPtr2); Marshal.FreeHGlobal(intPtr); return "[" + text2 + "]"; } Marshal.FreeHGlobal(intPtr); return ""; } private void Awake() { //IL_0045: Unknown result type (might be due to invalid IL or missing references) //IL_004f: Expected O, but got Unknown //IL_0079: Unknown result type (might be due to invalid IL or missing references) //IL_0083: Expected O, but got Unknown //IL_011d: Unknown result type (might be due to invalid IL or missing references) //IL_0123: Expected O, but got Unknown Instance = this; ((Object)((Component)Instance).gameObject).hideFlags = (HideFlags)61; Logger = ((BaseUnityPlugin)this).Logger; LanguageChangeEvent = new NetworkedEvent("LanguageChangeEvent", (Action<EventData>)HandleLanguageChangeEvent); languageSetting = ((BaseUnityPlugin)this).Config.Bind<string>("General", "Language", "de", new ConfigDescription("What language should the TTS emulate?", (AcceptableValueBase)(object)new AcceptableValueList<string>(language_list), Array.Empty<object>())); string text; try { text = Directory.GetFiles(Paths.PluginPath, "phondata-manifest", SearchOption.AllDirectories)[0].Replace("phondata-manifest", ""); } catch { Logger.LogError((object)"espeak-ng-data not found!"); return; } Logger.LogInfo((object)("Attempting to load eSpeak data from " + text)); int num = espeak_Initialize(0, 0, text, 0); if (num == -1) { Logger.LogError((object)("eSpeak failed to initialize from " + text + "! Not patching!")); return; } Logger.LogInfo((object)"eSpeak loaded successfully! Patching Speak Method..."); Harmony val = new Harmony("sane.tongue"); val.PatchAll(); } private static void HandleLanguageChangeEvent(EventData eventData) { string[] array = (string[])eventData.CustomData; string key = array[0]; string value = array[1]; Instance.languagePerPlayer[key] = value; } [HarmonyPatch(typeof(WorldSpaceUIParent), "TTS")] [HarmonyPrefix] private static void TTSPrefix(PlayerAvatar _player, string _text, float _time) { string text = (string)typeof(PlayerAvatar).GetField("steamID", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic).GetValue(_player); Logger.LogDebug((object)("Current Speaker: " + text)); Instance.currentSpeaker = text; } public void ChangeTTSLanguageForSteamID(string steamID, string language) { if (!language_list.Contains(language)) { Logger.LogError((object)("Language " + language + " is not valid. Perhaps someone is using a different version of Tongue.")); return; } PlayerAvatar val = SemiFunc.PlayerAvatarGetFromSteamID(steamID); if ((Object)(object)val == (Object)null) { Logger.LogError((object)"Someone wants to change language but provided an invalid steamID!"); } else if (languagePerPlayer.ContainsKey(steamID)) { languagePerPlayer[steamID] = language; } else { languagePerPlayer.Add(steamID, language); } } [HarmonyPatch(typeof(PlayerAvatar), "ChatMessageSend")] [HarmonyPrefix] private static void ChatMessageSendPrefix(PlayerAvatar __instance) { //IL_004b: Unknown result type (might be due to invalid IL or missing references) string text = (string)typeof(PlayerAvatar).GetField("steamID", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic).GetValue(__instance); string[] array = new string[2] { text, Instance.languageSetting.Value }; LanguageChangeEvent.RaiseEvent((object)array, NetworkingEvents.RaiseAll, SendOptions.SendReliable); } [HarmonyPatch(typeof(SpeechSynth), "speak", new Type[] { typeof(StringBuilder), typeof(int), typeof(VoicingSource), typeof(bool) })] [HarmonyPrefix] private static void SpeakPrefix(ref StringBuilder text, int voiceFundamentalFreq, VoicingSource voicingSource, ref bool bracketsAsPhonemes) { bracketsAsPhonemes = true; string text2 = text.ToString(); text.Length = 0; string valueOrDefault = Instance.languagePerPlayer.GetValueOrDefault(Instance.currentSpeaker, Instance.languageSetting.Value); text.Append(phoneticize(text2, valueOrDefault)); if (valueOrDefault == "en") { return; } while (text.ToString().IndexOf(':') != -1) { int num = text.ToString().IndexOf(':'); text[num] = text[num - 1]; } Dictionary<char, char> dictionary = new Dictionary<char, char> { { 'C', 'S' }, { 'Y', '3' }, { 'E', 'e' }, { 'a', 'A' }, { 'W', '3' } }; foreach (var (oldChar, newChar) in dictionary) { text.Replace(oldChar, newChar); } text2 = Regex.Replace(text.ToString(), "\\([^)]*\\)", "").Trim(); text.Length = 0; text.Append(text2); Logger.LogDebug((object)$"Saying word: {text}"); } } public static class MyPluginInfo { public const string PLUGIN_GUID = "tongue"; public const string PLUGIN_NAME = "Tongue"; public const string PLUGIN_VERSION = "0.1.1"; } }