Decompiled source of YapYapMoreLanguages v1.0.9

YapYapMoreLanguages/YapYapLanguageAPI.dll

Decompiled 2 days ago
using 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 BepInEx;
using HarmonyLib;
using UnityEngine;
using YAPYAP;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: AssemblyTitle("YapYapLanguageAPI")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("YapYapLanguageAPI")]
[assembly: AssemblyCopyright("Copyright ©  2026")]
[assembly: AssemblyTrademark("")]
[assembly: ComVisible(false)]
[assembly: Guid("ca946b50-9be9-4768-972b-51f7ff669496")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: TargetFramework(".NETFramework,Version=v4.8.1", FrameworkDisplayName = ".NET Framework 4.8.1")]
[assembly: AssemblyVersion("1.0.0.0")]
[Serializable]
public class LanguageDef
{
	public string id;

	public string displayName;

	public string systemLanguage;

	public string modelFolder;

	public string localisationFile;

	public string fallback;

	[NonSerialized]
	public string sourcePluginPath;
}
[Serializable]
public class LanguageDefList
{
	public List<LanguageDef> languages;
}
public static class LanguageRegistry
{
	public static List<LanguageDef> Languages = new List<LanguageDef>();

	public static Dictionary<string, Dictionary<string, string[]>> GrammarById = new Dictionary<string, Dictionary<string, string[]>>();

	public static Dictionary<string, string> ModelPathById = new Dictionary<string, string>();

	public static void LoadFromPlugin(string pluginDir)
	{
		string text = Path.Combine(pluginDir, "yapyap_custom_languages.json");
		Debug.Log((object)$"[YapYapLanguageAPI] LoadFromPlugin called. pluginDir='{pluginDir}', jsonPath='{text}', exists={File.Exists(text)}");
		if (!File.Exists(text))
		{
			Debug.LogWarning((object)("[YapYapLanguageAPI] yapyap_custom_languages.json not found in " + pluginDir));
			return;
		}
		string text2;
		try
		{
			text2 = File.ReadAllText(text);
			Debug.Log((object)$"[YapYapLanguageAPI] Read yapyap_custom_languages.json ({text2.Length} chars) from {pluginDir}.");
		}
		catch (Exception arg)
		{
			Debug.LogError((object)$"[YapYapLanguageAPI] Failed to read yapyap_custom_languages.json from {pluginDir}: {arg}");
			return;
		}
		LanguageDefList languageDefList = null;
		try
		{
			languageDefList = JsonUtility.FromJson<LanguageDefList>(text2);
			Debug.Log((object)("[YapYapLanguageAPI] JsonUtility.FromJson returned " + ((languageDefList == null) ? "null" : "non-null") + "."));
		}
		catch (Exception arg2)
		{
			Debug.LogError((object)$"[YapYapLanguageAPI] JSON parse exception: {arg2}");
		}
		if (languageDefList == null || languageDefList.languages == null)
		{
			Debug.LogWarning((object)"[YapYapLanguageAPI] JsonUtility didn't populate languages array — attempting fallback parse.");
			try
			{
				int num = text2.IndexOf("\"languages\"", StringComparison.OrdinalIgnoreCase);
				if (num >= 0)
				{
					int num2 = text2.IndexOf('[', num);
					int num3 = text2.IndexOf(']', num2 + 1);
					if (num2 >= 0 && num3 > num2)
					{
						string text3 = text2.Substring(num2 + 1, num3 - num2 - 1).Trim();
						if (!string.IsNullOrEmpty(text3))
						{
							string[] array = text3.Replace("},{", "}|{").Split(new char[1] { '|' }, StringSplitOptions.RemoveEmptyEntries);
							List<LanguageDef> list = new List<LanguageDef>();
							string[] array2 = array;
							foreach (string text4 in array2)
							{
								string text5 = text4.Trim();
								if (!text5.StartsWith("{"))
								{
									text5 = "{" + text5;
								}
								if (!text5.EndsWith("}"))
								{
									text5 += "}";
								}
								try
								{
									LanguageDef languageDef = JsonUtility.FromJson<LanguageDef>(text5);
									if (languageDef != null)
									{
										list.Add(languageDef);
									}
								}
								catch (Exception ex)
								{
									Debug.LogWarning((object)("[YapYapLanguageAPI] Fallback parse failed for segment: " + ex.Message));
								}
							}
							if (list.Count > 0)
							{
								languageDefList = new LanguageDefList
								{
									languages = list
								};
								Debug.Log((object)$"[YapYapLanguageAPI] Fallback parsed {list.Count} language(s).");
							}
						}
					}
				}
			}
			catch (Exception arg3)
			{
				Debug.LogError((object)$"[YapYapLanguageAPI] Exception during fallback parse: {arg3}");
				return;
			}
		}
		if (languageDefList == null || languageDefList.languages == null || languageDefList.languages.Count == 0)
		{
			Debug.LogWarning((object)("[YapYapLanguageAPI] No languages found in " + pluginDir + "/languages.json"));
			return;
		}
		foreach (LanguageDef lang in languageDefList.languages)
		{
			if (lang == null || string.IsNullOrEmpty(lang.id))
			{
				Debug.LogWarning((object)"[YapYapLanguageAPI] Skipping language with null or empty id.");
				continue;
			}
			if (Languages.Exists((LanguageDef l) => l.id == lang.id))
			{
				Debug.LogWarning((object)("[YapYapLanguageAPI] Language id '" + lang.id + "' already loaded. Skipping duplicate from " + pluginDir + "."));
				continue;
			}
			lang.sourcePluginPath = pluginDir;
			string value = Path.Combine(pluginDir, lang.modelFolder ?? string.Empty);
			ModelPathById[lang.id] = value;
			Dictionary<string, string[]> dictionary = new Dictionary<string, string[]>();
			string text6 = Path.Combine(pluginDir, lang.localisationFile ?? string.Empty);
			if (File.Exists(text6))
			{
				try
				{
					string[] array3 = File.ReadAllLines(text6);
					foreach (string text7 in array3)
					{
						if (!string.IsNullOrWhiteSpace(text7))
						{
							int num4 = text7.IndexOf("::", StringComparison.Ordinal);
							if (num4 >= 0)
							{
								string key = text7.Substring(0, num4).Trim();
								string[] value2 = text7.Substring(num4 + 2).Split(new char[2] { '-', ' ' }, StringSplitOptions.RemoveEmptyEntries);
								dictionary[key] = value2;
							}
						}
					}
					Debug.Log((object)$"[YapYapLanguageAPI] Loaded {dictionary.Count} grammar entries for '{lang.id}' from {text6}");
				}
				catch (Exception arg4)
				{
					Debug.LogError((object)$"[YapYapLanguageAPI] Failed to load localisation file {text6}: {arg4}");
				}
			}
			else
			{
				Debug.LogWarning((object)("[YapYapLanguageAPI] Localisation file not found: " + text6));
			}
			GrammarById[lang.id] = dictionary;
			Languages.Add(lang);
			Debug.Log((object)("[YapYapLanguageAPI] Registered language '" + lang.displayName + "' (id: " + lang.id + ") from plugin: " + pluginDir));
		}
		Debug.Log((object)$"[YapYapLanguageAPI] Finished loading from {pluginDir}. Total languages: {Languages.Count}");
	}
}
[HarmonyPatch(typeof(UISettings), "SetVoiceLanguage")]
internal class Patch_SetVoiceLanguage
{
	private static bool Prefix(UISettings __instance, int index)
	{
		VoiceManager val = default(VoiceManager);
		if (!Service.Get<VoiceManager>(ref val))
		{
			return true;
		}
		int num = val.VoskLocalisations?.Count ?? 0;
		if (index < num)
		{
			return true;
		}
		int num2 = index - num;
		if (num2 < 0 || num2 >= LanguageRegistry.Languages.Count)
		{
			return true;
		}
		LanguageDef languageDef = LanguageRegistry.Languages[num2];
		if (!LanguageRegistry.ModelPathById.TryGetValue(languageDef.id, out var value))
		{
			Debug.LogWarning((object)("[YapYapLanguageAPI] No model path for language '" + languageDef.id + "'. Aborting StartVosk."));
			return true;
		}
		List<string> list = new List<string>();
		if (!string.IsNullOrEmpty(value))
		{
			list.Add(value);
		}
		try
		{
			string pluginPath = Paths.PluginPath;
			if (!string.IsNullOrEmpty(pluginPath) && !Path.IsPathRooted(value))
			{
				list.Add(Path.Combine(pluginPath, value));
			}
			string text = Path.Combine(pluginPath, "GOOGNA_DEV_SQUAD-YapYapMoreLanguages", "YapYapMoreLanguages");
			if (!string.IsNullOrEmpty(text) && !Path.IsPathRooted(value))
			{
				list.Add(Path.Combine(text, value));
			}
		}
		catch
		{
		}
		try
		{
			string dataPath = Application.dataPath;
			if (!string.IsNullOrEmpty(dataPath))
			{
				list.Add(Path.Combine(dataPath, "StreamingAssets", value));
				string fileName = Path.GetFileName(value);
				if (!string.IsNullOrEmpty(fileName))
				{
					list.Add(Path.Combine(dataPath, "StreamingAssets", "Vosk", "Model", fileName));
				}
			}
		}
		catch
		{
		}
		List<string> list2 = (from p in list
			where !string.IsNullOrEmpty(p)
			select Path.GetFullPath(p)).Distinct().ToList();
		string text2 = list2.FirstOrDefault((string p) => Directory.Exists(p));
		if (text2 == null)
		{
			Debug.LogError((object)("[YapYapLanguageAPI] Model folder not found for language '" + languageDef.id + "'. Tried:\n  " + string.Join("\n  ", list2) + "\nAborting StartVosk to avoid breaking audio."));
			return true;
		}
		LanguageRegistry.GrammarById.TryGetValue(languageDef.id, out var value2);
		List<string> list3 = (value2 ?? new Dictionary<string, string[]>()).SelectMany((KeyValuePair<string, string[]> x) => x.Value).Distinct().ToList();
		Debug.Log((object)$"[YapYapLanguageAPI] Starting Vosk for '{languageDef.id}' (modelPath='{text2}') grammarWords={list3.Count}");
		try
		{
			val.Vosk.StartVosk(list3, text2, 3);
		}
		catch (Exception arg)
		{
			Debug.LogError((object)$"[YapYapLanguageAPI] StartVosk failed for '{languageDef.id}': {arg}. Aborting and falling back.");
			return true;
		}
		return false;
	}
}
[HarmonyPatch(typeof(UISettings), "Awake")]
internal static class Patch_UISettings_Awake
{
	private static readonly HashSet<string> s_addedLanguageIds = new HashSet<string>(StringComparer.OrdinalIgnoreCase);

	private static void Postfix(UISettings __instance)
	{
		//IL_0244: Unknown result type (might be due to invalid IL or missing references)
		try
		{
			Debug.Log((object)"[YapYapLanguageAPI] Postfix UISettings.Awake running.");
			VoiceManager val = default(VoiceManager);
			if (!Service.Get<VoiceManager>(ref val))
			{
				Debug.LogWarning((object)"[YapYapLanguageAPI] VoiceManager service not found.");
				return;
			}
			FieldInfo field = typeof(VoiceManager).GetField("_voskLocalisations", BindingFlags.Instance | BindingFlags.NonPublic);
			if (field == null)
			{
				Debug.LogWarning((object)"[YapYapLanguageAPI] VoiceManager._voskLocalisations field not found.");
				return;
			}
			VoskLocalisation[] array = (VoskLocalisation[])(((object)(field.GetValue(val) as VoskLocalisation[])) ?? ((object)new VoskLocalisation[0]));
			int num = 0;
			IEnumerable<LanguageDef> languages = LanguageRegistry.Languages;
			foreach (LanguageDef def in languages ?? Enumerable.Empty<LanguageDef>())
			{
				if (!string.IsNullOrEmpty(def?.id) && s_addedLanguageIds.Contains(def.id))
				{
					Debug.Log((object)("[YapYapLanguageAPI] Skipping '" + def.displayName + "' because id '" + def.id + "' already added."));
					continue;
				}
				if (array.Any((VoskLocalisation x) => (Object)(object)x != (Object)null && IsMatch(x, def)))
				{
					Debug.Log((object)("[YapYapLanguageAPI] Skipping '" + def.displayName + "' because matching VoskLocalisation already exists."));
					continue;
				}
				string defName = def?.displayName ?? string.Empty;
				if (!string.IsNullOrEmpty(defName) && array.Any(delegate(VoskLocalisation v)
				{
					try
					{
						string text5 = ((object)v).GetType().GetProperty("Name", BindingFlags.Instance | BindingFlags.Public)?.GetValue(v) as string;
						return !string.IsNullOrEmpty(text5) && string.Equals(text5, defName, StringComparison.OrdinalIgnoreCase);
					}
					catch
					{
						return false;
					}
				}))
				{
					Debug.Log((object)("[YapYapLanguageAPI] Skipping '" + def.displayName + "' because an entry with same Name exists."));
					if (!string.IsNullOrEmpty(def?.id))
					{
						s_addedLanguageIds.Add(def.id);
					}
					continue;
				}
				VoskLocalisation val2 = ScriptableObject.CreateInstance<VoskLocalisation>();
				SetPrivate(val2, "_language", ParseSystemLanguage(def.systemLanguage));
				SetPrivate(val2, "_name", def.displayName);
				string value;
				string value2 = ((def != null && !string.IsNullOrEmpty(def.id) && LanguageRegistry.ModelPathById.TryGetValue(def.id, out value)) ? value : def?.modelFolder);
				SetPrivate(val2, "_modelPath", value2);
				string text = (string.IsNullOrEmpty(def?.localisationFile) ? string.Empty : Path.GetFileName(def.localisationFile));
				SetPrivate(val2, "_filename", text);
				Debug.Log((object)("[YapYapLanguageAPI] For language '" + def?.id + "' set _filename = '" + text + "' (source value: '" + def?.localisationFile + "')"));
				try
				{
					if (!string.IsNullOrEmpty(text) && !string.IsNullOrEmpty(def?.localisationFile) && !string.IsNullOrEmpty(def?.sourcePluginPath))
					{
						string path = NormalizePath(def.localisationFile);
						string text2 = Path.Combine(def.sourcePluginPath, path);
						string text3 = Path.Combine(Application.dataPath, "StreamingAssets", "Vosk", "Localisation");
						string text4 = Path.Combine(text3, text);
						if (File.Exists(text2))
						{
							Directory.CreateDirectory(text3);
							bool flag = true;
							if (File.Exists(text4))
							{
								FileInfo fileInfo = new FileInfo(text2);
								FileInfo fileInfo2 = new FileInfo(text4);
								flag = fileInfo.Length != fileInfo2.Length || fileInfo.LastWriteTimeUtc > fileInfo2.LastWriteTimeUtc;
							}
							if (flag)
							{
								File.Copy(text2, text4, overwrite: true);
								Debug.Log((object)("[YapYapLanguageAPI] Copied localisation '" + text + "' from '" + text2 + "' to '" + text4 + "'"));
							}
							else
							{
								Debug.Log((object)("[YapYapLanguageAPI] Localisation '" + text + "' already up-to-date at '" + text4 + "'"));
							}
						}
						else
						{
							Debug.LogWarning((object)("[YapYapLanguageAPI] Localisation source not found at: " + text2 + "\nExpected dest: " + text4));
						}
					}
				}
				catch (Exception arg)
				{
					Debug.LogWarning((object)$"[YapYapLanguageAPI] Failed to copy localisation file for '{def?.id}': {arg}");
				}
				array = array.Concat((IEnumerable<VoskLocalisation>)(object)new VoskLocalisation[1] { val2 }).ToArray();
				num++;
				if (!string.IsNullOrEmpty(def?.id))
				{
					s_addedLanguageIds.Add(def.id);
				}
				Debug.Log((object)("[YapYapLanguageAPI] Created VoskLocalisation stub: Name='" + def.displayName + "', id='" + def.id + "'"));
			}
			if (num > 0)
			{
				field.SetValue(val, array);
				Debug.Log((object)$"[YapYapLanguageAPI] Added {num} localisation(s). New count = {array.Length}");
				try
				{
					val.ReloadLocalisation();
					Debug.Log((object)"[YapYapLanguageAPI] Called VoiceManager.ReloadLocalisation()");
				}
				catch (Exception arg2)
				{
					Debug.LogError((object)$"[YapYapLanguageAPI] ReloadLocalisation threw: {arg2}");
				}
			}
			else
			{
				Debug.Log((object)"[YapYapLanguageAPI] No new localisations added.");
			}
			try
			{
				FieldInfo field2 = typeof(UISettings).GetField("voiceLanguageSetting", BindingFlags.Instance | BindingFlags.NonPublic);
				if (field2 == null)
				{
					Debug.LogWarning((object)"[YapYapLanguageAPI] UISettings.voiceLanguageSetting field not found; cannot refresh dropdown.");
					return;
				}
				object value3 = field2.GetValue(__instance);
				if (value3 == null)
				{
					Debug.LogWarning((object)"[YapYapLanguageAPI] UISettings.voiceLanguageSetting is null; cannot refresh dropdown.");
					return;
				}
				Type type = value3.GetType();
				MethodInfo[] methods = type.GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
				MethodInfo methodInfo = methods.FirstOrDefault(delegate(MethodInfo m)
				{
					if (m.GetParameters().Length != 0)
					{
						return false;
					}
					Type returnType = m.ReturnType;
					return typeof(IEnumerable<string>).IsAssignableFrom(returnType) || returnType == typeof(string[]) || returnType == typeof(List<string>);
				});
				MethodInfo methodInfo2 = methods.FirstOrDefault(delegate(MethodInfo m)
				{
					ParameterInfo[] parameters = m.GetParameters();
					if (parameters.Length != 1)
					{
						return false;
					}
					Type parameterType2 = parameters[0].ParameterType;
					return typeof(IEnumerable<string>).IsAssignableFrom(parameterType2) || parameterType2 == typeof(string[]);
				});
				List<string> list = new List<string>();
				if (methodInfo != null)
				{
					try
					{
						object obj = methodInfo.Invoke(value3, null);
						if (obj is IEnumerable<string> collection)
						{
							list.AddRange(collection);
						}
						else if (obj is string[] collection2)
						{
							list.AddRange(collection2);
						}
					}
					catch (Exception arg3)
					{
						Debug.LogWarning((object)$"[YapYapLanguageAPI] Exception calling dropdown getter: {arg3}");
					}
				}
				else
				{
					try
					{
						List<VoskLocalisation> voskLocalisations = val.VoskLocalisations;
						if (voskLocalisations != null)
						{
							foreach (VoskLocalisation item in voskLocalisations)
							{
								if (!((Object)(object)item == (Object)null))
								{
									string name = null;
									PropertyInfo property = ((object)item).GetType().GetProperty("Name", BindingFlags.Instance | BindingFlags.Public);
									if (property != null)
									{
										name = property.GetValue(item) as string;
									}
									if (string.IsNullOrEmpty(name))
									{
										name = (((object)item).GetType().GetProperty("Language", BindingFlags.Instance | BindingFlags.Public)?.GetValue(item))?.ToString();
									}
									if (string.IsNullOrEmpty(name))
									{
										name = ((object)item).ToString();
									}
									if (!list.Any((string x) => string.Equals(x, name, StringComparison.OrdinalIgnoreCase)))
									{
										list.Add(name);
									}
								}
							}
						}
					}
					catch (Exception arg4)
					{
						Debug.LogWarning((object)$"[YapYapLanguageAPI] Failed to read vm.VoskLocalisations: {arg4}");
					}
				}
				List<string> list2 = new List<string>(list);
				foreach (LanguageDef ld in LanguageRegistry.Languages)
				{
					if (!string.IsNullOrEmpty(ld?.displayName) && !list2.Any((string x) => string.Equals(x, ld.displayName, StringComparison.OrdinalIgnoreCase)))
					{
						list2.Add(ld.displayName);
					}
				}
				list2 = list2.Distinct<string>(StringComparer.OrdinalIgnoreCase).ToList();
				if (!(methodInfo2 != null))
				{
					return;
				}
				Type parameterType = methodInfo2.GetParameters()[0].ParameterType;
				object obj2 = null;
				if (parameterType == typeof(string[]))
				{
					obj2 = list2.ToArray();
				}
				else if (parameterType.IsAssignableFrom(typeof(List<string>)))
				{
					obj2 = list2;
				}
				else if (typeof(IEnumerable<string>).IsAssignableFrom(parameterType))
				{
					obj2 = list2;
				}
				if (obj2 == null)
				{
					return;
				}
				try
				{
					methodInfo2.Invoke(value3, new object[1] { obj2 });
					Debug.Log((object)"[YapYapLanguageAPI] Invoked dropdown setter to refresh options.");
				}
				catch (Exception arg5)
				{
					Debug.LogError((object)$"[YapYapLanguageAPI] Invoking dropdown setter threw: {arg5}");
				}
			}
			catch (Exception arg6)
			{
				Debug.LogError((object)$"[YapYapLanguageAPI] Exception during dropdown inspection/update: {arg6}");
			}
		}
		catch (Exception arg7)
		{
			Debug.LogError((object)$"[YapYapLanguageAPI] Patch_UISettings_Awake failed: {arg7}");
		}
	}

	private static void SetPrivate(object obj, string field, object value)
	{
		FieldInfo field2 = obj.GetType().GetField(field, BindingFlags.Instance | BindingFlags.NonPublic);
		if (field2 != null)
		{
			field2.SetValue(obj, value);
		}
	}

	private static SystemLanguage ParseSystemLanguage(string value)
	{
		//IL_0014: Unknown result type (might be due to invalid IL or missing references)
		//IL_000e: Unknown result type (might be due to invalid IL or missing references)
		//IL_000f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0017: Unknown result type (might be due to invalid IL or missing references)
		if (Enum.TryParse<SystemLanguage>(value, ignoreCase: true, out SystemLanguage result))
		{
			return result;
		}
		return (SystemLanguage)10;
	}

	private static bool IsMatch(VoskLocalisation loc, LanguageDef def)
	{
		//IL_0032: Unknown result type (might be due to invalid IL or missing references)
		//IL_0037: Unknown result type (might be due to invalid IL or missing references)
		try
		{
			PropertyInfo property = ((object)loc).GetType().GetProperty("Language", BindingFlags.Instance | BindingFlags.Public);
			if (property != null && property.GetValue(loc) is SystemLanguage val)
			{
				return string.Equals(((object)(SystemLanguage)(ref val)).ToString(), def.systemLanguage, StringComparison.OrdinalIgnoreCase);
			}
			PropertyInfo property2 = ((object)loc).GetType().GetProperty("Name", BindingFlags.Instance | BindingFlags.Public);
			if (property2 != null)
			{
				string text = property2.GetValue(loc) as string;
				if (!string.IsNullOrEmpty(text) && string.Equals(text, def.displayName, StringComparison.OrdinalIgnoreCase))
				{
					return true;
				}
			}
		}
		catch
		{
		}
		return false;
	}

	private static string NormalizePath(string path)
	{
		if (string.IsNullOrEmpty(path))
		{
			return path;
		}
		return path.Replace('/', Path.DirectorySeparatorChar).Replace('\\', Path.DirectorySeparatorChar);
	}
}
[BepInPlugin("yapyap.language.api", "YapYap Language API", "0.1.0")]
public class Plugin : BaseUnityPlugin
{
	private const string LANGUAGE_CONFIG_FILE = "yapyap_custom_languages.json";

	private void Awake()
	{
		//IL_016d: Unknown result type (might be due to invalid IL or missing references)
		((BaseUnityPlugin)this).Logger.LogInfo((object)"YapYap Language API initializing...");
		string pluginPath = Paths.PluginPath;
		if (!Directory.Exists(pluginPath))
		{
			((BaseUnityPlugin)this).Logger.LogError((object)("Plugin path does not exist: " + pluginPath));
			return;
		}
		int num = 0;
		string[] directories = Directory.GetDirectories(pluginPath);
		foreach (string text in directories)
		{
			string path = Path.Combine(text);
			if (File.Exists(path))
			{
				((BaseUnityPlugin)this).Logger.LogInfo((object)("Found yapyap_custom_languages.json in: " + text));
				LanguageRegistry.LoadFromPlugin(text);
				num++;
				continue;
			}
			string[] directories2 = Directory.GetDirectories(text);
			foreach (string text2 in directories2)
			{
				string path2 = Path.Combine(text2, "yapyap_custom_languages.json");
				if (File.Exists(path2))
				{
					((BaseUnityPlugin)this).Logger.LogInfo((object)("Found yapyap_custom_languages.json in: " + text2));
					LanguageRegistry.LoadFromPlugin(text2);
					num++;
				}
			}
		}
		if (num == 0)
		{
			((BaseUnityPlugin)this).Logger.LogWarning((object)"No language packs discovered. Modders should create plugins with yapyap_custom_languages.json files.");
		}
		else
		{
			((BaseUnityPlugin)this).Logger.LogInfo((object)$"Discovered {num} language pack(s). Total languages loaded: {LanguageRegistry.Languages.Count}");
		}
		new Harmony("yapyap.language.api").PatchAll();
		((BaseUnityPlugin)this).Logger.LogInfo((object)"YapYap Language API loaded");
	}
}