Decompiled source of PeakChatTranslator v0.2.4

plugins/Gordoni.PeakChatTranslator.dll

Decompiled 3 days ago
using System;
using System.Collections;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
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.Text.RegularExpressions;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using ExitGames.Client.Photon;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using Newtonsoft.Json.Linq;
using PeakChatTranslator.Patches;
using PeakTextChat;
using Photon.Pun;
using Photon.Realtime;
using UnityEngine;
using UnityEngine.Networking;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: IgnoresAccessChecksTo("Assembly-CSharp")]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("Gordoni.PeakChatTranslator")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("0.2.4.0")]
[assembly: AssemblyInformationalVersion("0.2.4+70d1682804a01d781853b8b43db877afcccbdbe8")]
[assembly: AssemblyProduct("Gordoni.PeakChatTranslator")]
[assembly: AssemblyTitle("PeakChatTranslator")]
[assembly: AssemblyMetadata("RepositoryUrl", "https://github.com/gustavogordoni/PeakChatTranslator")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("0.2.4.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableAttribute : Attribute
	{
		public readonly byte[] NullableFlags;

		public NullableAttribute(byte P_0)
		{
			NullableFlags = new byte[1] { P_0 };
		}

		public NullableAttribute(byte[] P_0)
		{
			NullableFlags = P_0;
		}
	}
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableContextAttribute : Attribute
	{
		public readonly byte Flag;

		public NullableContextAttribute(byte P_0)
		{
			Flag = P_0;
		}
	}
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace BepInEx
{
	[AttributeUsage(AttributeTargets.Class, Inherited = false, AllowMultiple = false)]
	[Conditional("CodeGeneration")]
	[Embedded]
	internal sealed class BepInAutoPluginAttribute : Attribute
	{
		public BepInAutoPluginAttribute(string? id = null, string? name = null, string? version = null)
		{
		}
	}
}
namespace BepInEx.Preloader.Core.Patching
{
	[AttributeUsage(AttributeTargets.Class, Inherited = false, AllowMultiple = false)]
	[Conditional("CodeGeneration")]
	[Embedded]
	internal sealed class PatcherAutoPluginAttribute : Attribute
	{
		public PatcherAutoPluginAttribute(string? id = null, string? name = null, string? version = null)
		{
		}
	}
}
namespace Microsoft.CodeAnalysis
{
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace PeakChatTranslator
{
	public enum TranslationProvider
	{
		Google,
		MyMemory
	}
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[BepInPlugin("Gordoni.PeakChatTranslator", "PeakChatTranslator", "0.2.4")]
	public class Plugin : BaseUnityPlugin
	{
		internal static Plugin Instance = null;

		internal static ConfigEntry<bool> Enabled = null;

		internal static ConfigEntry<string> TargetLanguage = null;

		internal static ConfigEntry<string> TranslationPrefix = null;

		internal static ConfigEntry<string> TranslationColor = null;

		internal static ConfigEntry<TranslationProvider> TranslationProviderConfig = null;

		internal static ConfigEntry<string> OutgoingTargetLanguage = null;

		private static readonly Dictionary<string, string> LanguageDisplayNames = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase)
		{
			["pt-BR"] = "Português do Brasil (pt-BR)",
			["pt-PT"] = "Português de Portugal (pt-PT)",
			["en"] = "English (en)",
			["es"] = "Spanish / Español (es)",
			["fr"] = "French / Français (fr)",
			["de"] = "German / Deutsch (de)",
			["it"] = "Italian / Italiano (it)",
			["ru"] = "Russian / Русский (ru)",
			["ja"] = "Japanese / 日本語 (ja)",
			["ko"] = "Korean / 한국어 (ko)",
			["zh"] = "Chinese Simplified / 中文简体 (zh)",
			["zh-TW"] = "Chinese Traditional / 中文繁體 (zh-TW)",
			["zh-CN"] = "Chinese Simplified / 中文简体 (zh-CN)",
			["ar"] = "Arabic / العربية (ar)",
			["hi"] = "Hindi / ह\u093fन\u094dद\u0940 (hi)",
			["tr"] = "Turkish / Türkçe (tr)",
			["pl"] = "Polish / Polski (pl)",
			["nl"] = "Dutch / Nederlands (nl)",
			["sv"] = "Swedish / Svenska (sv)",
			["da"] = "Danish / Dansk (da)",
			["no"] = "Norwegian / Norsk (no)",
			["fi"] = "Finnish / Suomi (fi)",
			["cs"] = "Czech / Čeština (cs)",
			["hu"] = "Hungarian / Magyar (hu)",
			["ro"] = "Romanian / Română (ro)",
			["bg"] = "Bulgarian / Български (bg)",
			["hr"] = "Croatian / Hrvatski (hr)",
			["sk"] = "Slovak / Slovenčina (sk)",
			["sl"] = "Slovenian / Slovenščina (sl)",
			["et"] = "Estonian / Eesti (et)",
			["lv"] = "Latvian / Latviešu (lv)",
			["lt"] = "Lithuanian / Lietuvių (lt)",
			["mt"] = "Maltese / Malti (mt)",
			["ga"] = "Irish / Gaeilge (ga)",
			["cy"] = "Welsh / Cymraeg (cy)",
			["eu"] = "Basque / Euskara (eu)",
			["ca"] = "Catalan / Català (ca)",
			["gl"] = "Galician / Galego (gl)",
			["he"] = "Hebrew / עברית (he)",
			["th"] = "Thai / ไทย (th)",
			["vi"] = "Vietnamese / Tiếng Việt (vi)",
			["id"] = "Indonesian / Bahasa Indonesia (id)",
			["ms"] = "Malay / Bahasa Melayu (ms)",
			["tl"] = "Tagalog / Tagalog (tl)",
			["sw"] = "Swahili / Kiswahili (sw)",
			["af"] = "Afrikaans / Afrikaans (af)",
			["sq"] = "Albanian / Shqip (sq)",
			["mk"] = "Macedonian / Македонски (mk)",
			["sr"] = "Serbian / Српски (sr)",
			["bs"] = "Bosnian / Bosanski (bs)",
			["is"] = "Icelandic / Íslenska (is)",
			["ka"] = "Georgian / ქართული (ka)",
			["hy"] = "Armenian / Հայերեն (hy)",
			["az"] = "Azerbaijani / Azərbaycanca (az)",
			["be"] = "Belarusian / Беларуская (be)",
			["kk"] = "Kazakh / Қазақша (kk)",
			["ky"] = "Kyrgyz / Кыргызча (ky)",
			["uz"] = "Uzbek / O'zbekcha (uz)",
			["mn"] = "Mongolian / Монгол (mn)",
			["my"] = "Burmese / မ\u103cန\u103aမ\u102cဘ\u102cသ\u102c (my)",
			["km"] = "Khmer / ខ\u17d2ម\u17c2រ (km)",
			["lo"] = "Lao / ລາວ (lo)",
			["si"] = "Sinhala / ස\u0dd2\u0d82හල (si)",
			["ne"] = "Nepali / न\u0947प\u093eल\u0940 (ne)",
			["bn"] = "Bengali / ব\u09be\u0982ল\u09be (bn)",
			["gu"] = "Gujarati / ગ\u0ac1જર\u0abeત\u0ac0 (gu)",
			["pa"] = "Punjabi / ਪ\u0a70ਜ\u0a3eਬ\u0a40 (pa)",
			["ta"] = "Tamil / தம\u0bbfழ\u0bcd (ta)",
			["te"] = "Telugu / త\u0c46ల\u0c41గ\u0c41 (te)",
			["kn"] = "Kannada / ಕನ\u0ccdನಡ (kn)",
			["ml"] = "Malayalam / മലയ\u0d3eള\u0d02 (ml)",
			["or"] = "Odia / ଓଡ\u0b3c\u0b3fଆ (or)",
			["as"] = "Assamese / অসম\u09c0য\u09bc\u09be (as)",
			["mr"] = "Marathi / मर\u093eठ\u0940 (mr)",
			["sa"] = "Sanskrit / स\u0902स\u094dक\u0943तम\u094d (sa)",
			["ur"] = "Urdu / اردو (ur)",
			["fa"] = "Persian / فارسی (fa)",
			["ps"] = "Pashto / پښتو (ps)",
			["sd"] = "Sindhi / سنڌي (sd)",
			["ku"] = "Kurdish / کوردی (ku)",
			["ug"] = "Uyghur / ئۇيغۇرچە (ug)",
			["yi"] = "Yiddish / יי\u05b4דיש (yi)",
			["ji"] = "Yiddish / יי\u05b4דיש (ji)"
		};

		public const string Id = "Gordoni.PeakChatTranslator";

		internal static ManualLogSource Log { get; private set; } = null;

		public static string Name => "PeakChatTranslator";

		public static string Version => "0.2.4";

		private void Awake()
		{
			//IL_008a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0094: Expected O, but got Unknown
			//IL_0106: Unknown result type (might be due to invalid IL or missing references)
			//IL_0110: Expected O, but got Unknown
			Instance = this;
			Log = ((BaseUnityPlugin)this).Logger;
			string[] supportedLanguages = GetSupportedLanguages();
			string[] array = supportedLanguages.Select(GetLanguageDisplayName).ToArray();
			AcceptableValueList<string> val = new AcceptableValueList<string>(array);
			Enabled = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "Enabled", true, "Enable/disable chat translation");
			TargetLanguage = ((BaseUnityPlugin)this).Config.Bind<string>("General", "Target Language", GetLanguageDisplayName("en"), new ConfigDescription("Translate incoming messages into this language", (AcceptableValueBase)(object)val, Array.Empty<object>()));
			TranslationPrefix = ((BaseUnityPlugin)this).Config.Bind<string>("Display", "Translation Prefix", "TR", "Prefix shown before translated text (e.g. [TR])");
			TranslationColor = ((BaseUnityPlugin)this).Config.Bind<string>("Display", "Translation Color", "#7FC8FF", "Color (hex) for translated lines");
			OutgoingTargetLanguage = ((BaseUnityPlugin)this).Config.Bind<string>("Outgoing", "Translate My Messages To", GetLanguageDisplayName("en"), new ConfigDescription("When using /tr, translate your messages into this language", (AcceptableValueBase)(object)val, Array.Empty<object>()));
			TranslationProviderConfig = ((BaseUnityPlugin)this).Config.Bind<TranslationProvider>("General", "Translation Provider", TranslationProvider.Google, "Translation service to use. Google = better quality, MyMemory = fallback");
			Harmony.CreateAndPatchAll(typeof(TextChatDisplayPatch), "Gordoni.PeakChatTranslator");
			Harmony.CreateAndPatchAll(typeof(SendChatMessagePatch), "Gordoni.PeakChatTranslator");
			Log.LogInfo((object)("Plugin " + Name + " loaded!"));
		}

		private void OnDestroy()
		{
			Harmony.UnpatchID("Gordoni.PeakChatTranslator");
		}

		internal void HandleTranslationResult(TranslationResult result, Message messageData)
		{
			if (!Enabled.Value || string.IsNullOrWhiteSpace(result.Text))
			{
				return;
			}
			string languageCode = GetLanguageCode(TargetLanguage.Value ?? "pt");
			if (!string.IsNullOrEmpty(languageCode) && !IsSameLanguage(result.SourceLang, languageCode) && (messageData == null || !((Object)(object)messageData.character != (Object)null) || !((Object)(object)messageData.character == (Object)(object)Character.localCharacter)) && !((Object)(object)TextChatDisplay.instance == (Object)null))
			{
				string text = (string.IsNullOrWhiteSpace(TranslationPrefix.Value) ? "TR" : TranslationPrefix.Value.Trim());
				string text2 = TranslationColor.Value;
				if (string.IsNullOrWhiteSpace(text2))
				{
					text2 = "#7FC8FF";
				}
				if (!text2.StartsWith('#'))
				{
					text2 = "#" + text2;
				}
				TextChatDisplay.instance.AddMessage("<color=" + text2 + ">[" + text + "] " + result.Text + "</color>");
			}
		}

		internal static bool IsTranslationMessage(string message)
		{
			if (string.IsNullOrWhiteSpace(message))
			{
				return false;
			}
			string text = TranslationService.StripRichText(message).TrimStart();
			if (!text.StartsWith("[TR-", StringComparison.OrdinalIgnoreCase))
			{
				return text.StartsWith("[TR:", StringComparison.OrdinalIgnoreCase);
			}
			return true;
		}

		private static bool IsSameLanguage(string detected, string target)
		{
			if (string.IsNullOrWhiteSpace(detected))
			{
				return false;
			}
			string text = detected.Trim().ToLowerInvariant();
			if (text.Length > 2 && text[2] == '-')
			{
				text = text.Substring(0, 2);
			}
			string text2 = target.Trim().ToLowerInvariant();
			if (text2.Length > 2 && text2[2] == '-')
			{
				text2 = text2.Substring(0, 2);
			}
			return text == text2;
		}

		internal static bool TryExtractCommandMessage(string message, out string extracted)
		{
			extracted = null;
			string text = message.TrimStart();
			if (!text.StartsWith("/tr", StringComparison.OrdinalIgnoreCase))
			{
				return false;
			}
			string text2 = text.Substring("/tr".Length).TrimStart();
			if (string.IsNullOrWhiteSpace(text2))
			{
				return false;
			}
			extracted = text2;
			return true;
		}

		internal void SendOutgoingTranslation(string textToTranslate)
		{
			if (!Enabled.Value || IsTranslationMessage(textToTranslate) || string.IsNullOrWhiteSpace(textToTranslate))
			{
				return;
			}
			string targetLang = GetLanguageCode(OutgoingTargetLanguage.Value ?? "en");
			string languageCode = GetLanguageCode(TargetLanguage.Value ?? "pt");
			if (string.Equals(languageCode, targetLang, StringComparison.OrdinalIgnoreCase))
			{
				return;
			}
			Action<TranslationResult> onResult = delegate(TranslationResult result)
			{
				//IL_008e: Unknown result type (might be due to invalid IL or missing references)
				//IL_0093: 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_009a: Unknown result type (might be due to invalid IL or missing references)
				//IL_00a4: Expected O, but got Unknown
				if (!Enabled.Value || string.IsNullOrWhiteSpace(result.Text) || IsSameLanguage(result.SourceLang, targetLang))
				{
					return;
				}
				string text = "TR-" + targetLang.ToUpperInvariant();
				string text2 = "[" + text + "] " + result.Text;
				try
				{
					byte b = 81;
					object[] array = new object[4]
					{
						PhotonNetwork.LocalPlayer.NickName,
						text2,
						PhotonNetwork.LocalPlayer.UserId,
						false
					};
					PhotonNetwork.RaiseEvent(b, (object)array, new RaiseEventOptions
					{
						Receivers = (ReceiverGroup)1
					}, SendOptions.SendReliable);
				}
				catch (Exception ex)
				{
					Log.LogWarning((object)("Failed to send outgoing translation: " + ex.Message));
				}
			};
			Action<string> onError = delegate(string error)
			{
				Log.LogWarning((object)("Outgoing translation failed for '" + textToTranslate + "': " + error));
			};
			((MonoBehaviour)this).StartCoroutine(TranslationService.TranslateWithSourceCoroutine(textToTranslate, languageCode, targetLang, TranslationProviderConfig.Value, onResult, onError));
		}

		internal void SendWhisperTranslation(string targetName, string textToTranslate)
		{
			if (!Enabled.Value || IsTranslationMessage(textToTranslate) || string.IsNullOrWhiteSpace(textToTranslate))
			{
				return;
			}
			Player targetPlayer = FindPlayerByName(targetName);
			if (targetPlayer == null)
			{
				Log.LogWarning((object)("Whisper translation: player '" + targetName + "' not found"));
				return;
			}
			string targetLang = GetLanguageCode(OutgoingTargetLanguage.Value ?? "en");
			string languageCode = GetLanguageCode(TargetLanguage.Value ?? "pt");
			if (string.Equals(languageCode, targetLang, StringComparison.OrdinalIgnoreCase))
			{
				return;
			}
			Action<TranslationResult> onResult = delegate(TranslationResult result)
			{
				//IL_00c0: Unknown result type (might be due to invalid IL or missing references)
				//IL_00c7: Expected O, but got Unknown
				//IL_00e4: Unknown result type (might be due to invalid IL or missing references)
				if (!Enabled.Value || string.IsNullOrWhiteSpace(result.Text) || IsSameLanguage(result.SourceLang, targetLang))
				{
					return;
				}
				string text = "TR-" + targetLang.ToUpperInvariant();
				string text2 = result.Text;
				string text3 = "#8973a1";
				string text4 = "<color=" + text3 + ">[" + text + "] " + text2 + " <size=16><i>(secret msg for you)</i></size></color>";
				try
				{
					byte b = 81;
					object[] array = new object[4]
					{
						PhotonNetwork.LocalPlayer.NickName,
						text4,
						PhotonNetwork.LocalPlayer.UserId,
						false
					};
					RaiseEventOptions val = new RaiseEventOptions();
					val.TargetActors = new int[1] { targetPlayer.ActorNumber };
					PhotonNetwork.RaiseEvent(b, (object)array, val, SendOptions.SendReliable);
					if ((Object)(object)TextChatDisplay.instance != (Object)null)
					{
						TextChatDisplay.instance.AddMessage(text4);
					}
				}
				catch (Exception ex)
				{
					Log.LogWarning((object)("Failed to send whisper translation: " + ex.Message));
				}
			};
			Action<string> onError = delegate(string error)
			{
				Log.LogWarning((object)("Whisper translation failed for '" + textToTranslate + "': " + error));
			};
			((MonoBehaviour)this).StartCoroutine(TranslationService.TranslateWithSourceCoroutine(textToTranslate, languageCode, targetLang, TranslationProviderConfig.Value, onResult, onError));
		}

		private static Player FindPlayerByName(string name)
		{
			string value = Regex.Replace(name.ToLower(), "</?color(=\\w+|=[#\\w]+)?>", string.Empty, RegexOptions.IgnoreCase);
			Player[] playerList = PhotonNetwork.PlayerList;
			foreach (Player val in playerList)
			{
				string text = Regex.Replace(val.NickName.ToLower(), "</?color(=\\w+|=[#\\w]+)?>", string.Empty, RegexOptions.IgnoreCase);
				if (text.Contains(value, StringComparison.OrdinalIgnoreCase))
				{
					return val;
				}
			}
			return null;
		}

		private static string[] GetSupportedLanguages()
		{
			return LanguageDisplayNames.Keys.OrderBy((string k) => k).ToArray();
		}

		internal static string GetLanguageDisplayName(string code)
		{
			if (LanguageDisplayNames.TryGetValue(code, out string value))
			{
				return value;
			}
			return code;
		}

		internal static string GetLanguageCode(string displayName)
		{
			if (string.IsNullOrWhiteSpace(displayName))
			{
				return "en";
			}
			Match match = Regex.Match(displayName, "\\(([a-zA-Z0-9\\-]+)\\)$");
			if (match.Success)
			{
				return match.Groups[1].Value;
			}
			return LanguageDisplayNames.FirstOrDefault<KeyValuePair<string, string>>((KeyValuePair<string, string> kvp) => kvp.Value.Equals(displayName, StringComparison.OrdinalIgnoreCase)).Key ?? "en";
		}
	}
	public readonly struct TranslationResult
	{
		public readonly string Text;

		public readonly string SourceLang;

		public TranslationResult(string text, string sourceLang)
		{
			Text = text;
			SourceLang = sourceLang;
		}
	}
	internal static class TranslationService
	{
		private static readonly Regex RichTextRegex = new Regex("<.*?>", RegexOptions.Compiled);

		private static readonly ConcurrentDictionary<string, string> Cache = new ConcurrentDictionary<string, string>();

		public static string StripRichText(string text)
		{
			return RichTextRegex.Replace(text, string.Empty);
		}

		public static IEnumerator TranslateCoroutine(string text, string targetLang, TranslationProvider provider, Action<TranslationResult> onResult, Action<string> onError)
		{
			yield return TranslateWithSourceCoroutine(text, "en", targetLang, provider, onResult, onError);
		}

		public static IEnumerator TranslateWithSourceCoroutine(string text, string sourceLang, string targetLang, TranslationProvider provider, Action<TranslationResult> onResult, Action<string> onError)
		{
			yield return TryTranslate(text, sourceLang, targetLang, provider, onResult, onError);
		}

		private static IEnumerator TryTranslate(string text, string sourceLang, string targetLang, TranslationProvider provider, Action<TranslationResult> onResult, Action<string> onError)
		{
			string cacheKey = $"{provider}|{sourceLang}|{targetLang}|{text}";
			if (Cache.TryGetValue(cacheKey, out string value))
			{
				onResult(new TranslationResult(value, sourceLang));
				yield break;
			}
			UnityWebRequest request = BuildRequest(text, sourceLang, targetLang, provider);
			try
			{
				if (request == null)
				{
					onError?.Invoke($"Unknown provider: {provider}");
					yield break;
				}
				yield return request.SendWebRequest();
				if ((int)request.result != 1)
				{
					string text2 = $"HTTP {(int)request.responseCode} {request.error}";
					TranslationProvider fallbackProvider = GetFallbackProvider(provider);
					if (fallbackProvider != TranslationProvider.Google && fallbackProvider != provider)
					{
						LogDebug($"Primary provider {provider} failed: {text2}. Trying fallback: {fallbackProvider}");
						yield return TryTranslate(text, sourceLang, targetLang, fallbackProvider, onResult, onError);
					}
					else
					{
						onError?.Invoke(text2);
					}
					yield break;
				}
				TranslationResult obj = default(TranslationResult);
				Exception ex = null;
				try
				{
					obj = provider switch
					{
						TranslationProvider.Google => ParseGoogle(request.downloadHandler.text, targetLang), 
						TranslationProvider.MyMemory => ParseMyMemory(request.downloadHandler.text), 
						_ => throw new ArgumentOutOfRangeException("provider"), 
					};
				}
				catch (Exception ex2)
				{
					ex = ex2;
				}
				if (ex != null)
				{
					TranslationProvider fallbackProvider2 = GetFallbackProvider(provider);
					if (fallbackProvider2 != TranslationProvider.Google && fallbackProvider2 != provider)
					{
						LogDebug($"Primary provider {provider} parse error: {ex.Message}. Trying fallback: {fallbackProvider2}");
						yield return TryTranslate(text, sourceLang, targetLang, fallbackProvider2, onResult, onError);
					}
					else
					{
						onError?.Invoke(ex.Message);
					}
				}
				else
				{
					if (!string.IsNullOrWhiteSpace(obj.Text))
					{
						Cache[cacheKey] = obj.Text;
					}
					onResult(obj);
				}
			}
			finally
			{
				((IDisposable)request)?.Dispose();
			}
		}

		private static TranslationProvider GetFallbackProvider(TranslationProvider provider)
		{
			if (provider != TranslationProvider.Google)
			{
				return TranslationProvider.Google;
			}
			return TranslationProvider.MyMemory;
		}

		private static void LogDebug(string msg)
		{
			Debug.Log((object)("[PeakChatTranslator] " + msg));
		}

		private static UnityWebRequest BuildRequest(string text, string sourceLang, string targetLang, TranslationProvider provider)
		{
			return (UnityWebRequest)(provider switch
			{
				TranslationProvider.Google => BuildGoogleRequest(text, targetLang), 
				TranslationProvider.MyMemory => BuildMyMemoryRequest(text, sourceLang, targetLang), 
				_ => null, 
			});
		}

		private static UnityWebRequest BuildGoogleRequest(string text, string targetLang)
		{
			string text2 = "https://translate.googleapis.com/translate_a/single?client=gtx&sl=auto&tl=" + Uri.EscapeDataString(targetLang) + "&dt=t&q=" + Uri.EscapeDataString(text);
			UnityWebRequest val = UnityWebRequest.Get(text2);
			val.timeout = 10;
			val.SetRequestHeader("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36");
			return val;
		}

		private static UnityWebRequest BuildMyMemoryRequest(string text, string sourceLang, string targetLang)
		{
			string text2 = "https://api.mymemory.translated.net/get?q=" + Uri.EscapeDataString(text) + "&langpair=" + Uri.EscapeDataString(sourceLang) + "|" + Uri.EscapeDataString(targetLang);
			UnityWebRequest val = UnityWebRequest.Get(text2);
			val.timeout = 15;
			return val;
		}

		private static TranslationResult ParseGoogle(string json, string targetLang)
		{
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			JArray val = JArray.Parse(json);
			StringBuilder stringBuilder = new StringBuilder();
			foreach (JToken item in (JArray)val[0])
			{
				stringBuilder.Append(((object)item[(object)0]).ToString());
			}
			string sourceLang = ((object)val[2])?.ToString() ?? "en";
			return new TranslationResult(stringBuilder.ToString(), sourceLang);
		}

		private static TranslationResult ParseMyMemory(string json)
		{
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			//IL_0018: Expected O, but got Unknown
			JObject val = JObject.Parse(json);
			JObject val2 = (JObject)val["responseData"];
			string text = ((val2 == null) ? null : ((object)val2["translatedText"])?.ToString()) ?? string.Empty;
			string sourceLang = ((val2 == null) ? null : ((object)val2["detectedLanguage"])?.ToString()) ?? "en";
			return new TranslationResult(text, sourceLang);
		}
	}
}
namespace PeakChatTranslator.Patches
{
	[HarmonyPatch(typeof(TextChatManager), "SendChatMessage")]
	internal static class SendChatMessagePatch
	{
		private static readonly Regex WhisperTranslateRegex = new Regex("^/w\\s+(\\S+)\\s+/tr\\s+(.+)$", RegexOptions.IgnoreCase | RegexOptions.Compiled);

		private static readonly Regex TranslateCommandRegex = new Regex("^/tr\\s+(.+)$", RegexOptions.IgnoreCase | RegexOptions.Compiled);

		private static readonly Regex TranslateWhisperRegex = new Regex("^/tr\\s+/w\\s+(\\S+)\\s+(.+)$", RegexOptions.IgnoreCase | RegexOptions.Compiled);

		private static bool Prefix(string message)
		{
			if (!Plugin.Enabled.Value)
			{
				return true;
			}
			if (string.IsNullOrWhiteSpace(message))
			{
				return true;
			}
			if (Plugin.IsTranslationMessage(message))
			{
				return true;
			}
			Match match = TranslateWhisperRegex.Match(message.Trim());
			if (match.Success)
			{
				string value = match.Groups[1].Value;
				string value2 = match.Groups[2].Value;
				Plugin.Instance?.SendWhisperTranslation(value, value2);
				return false;
			}
			Match match2 = WhisperTranslateRegex.Match(message.Trim());
			if (match2.Success)
			{
				string value3 = match2.Groups[1].Value;
				string value4 = match2.Groups[2].Value;
				Plugin.Instance?.SendWhisperTranslation(value3, value4);
				return false;
			}
			Match match3 = TranslateCommandRegex.Match(message.Trim());
			if (match3.Success)
			{
				string value5 = match3.Groups[1].Value;
				Plugin.Instance?.SendOutgoingTranslation(value5);
				return false;
			}
			return true;
		}
	}
	[HarmonyPatch(typeof(TextChatDisplay), "AddMessage", new Type[] { typeof(Message) })]
	internal static class TextChatDisplayPatch
	{
		private static readonly Regex RichTextRegex = new Regex("<.*?>", RegexOptions.Compiled);

		private static void Postfix(Message messageData)
		{
			if (!Plugin.Enabled.Value || messageData == null)
			{
				return;
			}
			string languageCode = Plugin.GetLanguageCode(Plugin.TargetLanguage.Value ?? "pt");
			if (string.IsNullOrWhiteSpace(languageCode))
			{
				return;
			}
			string rawMessage = RichTextRegex.Replace(messageData.message, string.Empty).Trim();
			if (!string.IsNullOrWhiteSpace(rawMessage) && !Plugin.IsTranslationMessage(rawMessage) && !((Object)(object)Plugin.Instance == (Object)null))
			{
				((MonoBehaviour)Plugin.Instance).StartCoroutine(TranslationService.TranslateCoroutine(rawMessage, languageCode, Plugin.TranslationProviderConfig.Value, delegate(TranslationResult result)
				{
					Plugin.Instance.HandleTranslationResult(result, messageData);
				}, delegate(string error)
				{
					Plugin.Log.LogWarning((object)("Translation failed for \"" + rawMessage + "\": " + error));
				}));
			}
		}
	}
}
namespace System.Diagnostics.CodeAnalysis
{
	[AttributeUsage(AttributeTargets.Parameter, Inherited = false)]
	[ExcludeFromCodeCoverage]
	internal sealed class ConstantExpectedAttribute : Attribute
	{
		public object? Min { get; set; }

		public object? Max { get; set; }
	}
	[AttributeUsage(AttributeTargets.Assembly | AttributeTargets.Module | AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Enum | AttributeTargets.Constructor | AttributeTargets.Method | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Interface | AttributeTargets.Delegate, Inherited = false)]
	[ExcludeFromCodeCoverage]
	internal sealed class ExperimentalAttribute : Attribute
	{
		public string DiagnosticId { get; }

		public string? UrlFormat { get; set; }

		public ExperimentalAttribute(string diagnosticId)
		{
			DiagnosticId = diagnosticId;
		}
	}
	[AttributeUsage(AttributeTargets.Method | AttributeTargets.Property, Inherited = false, AllowMultiple = true)]
	[ExcludeFromCodeCoverage]
	internal sealed class MemberNotNullAttribute : Attribute
	{
		public string[] Members { get; }

		public MemberNotNullAttribute(string member)
		{
			Members = new string[1] { member };
		}

		public MemberNotNullAttribute(params string[] members)
		{
			Members = members;
		}
	}
	[AttributeUsage(AttributeTargets.Method | AttributeTargets.Property, Inherited = false, AllowMultiple = true)]
	[ExcludeFromCodeCoverage]
	internal sealed class MemberNotNullWhenAttribute : Attribute
	{
		public bool ReturnValue { get; }

		public string[] Members { get; }

		public MemberNotNullWhenAttribute(bool returnValue, string member)
		{
			ReturnValue = returnValue;
			Members = new string[1] { member };
		}

		public MemberNotNullWhenAttribute(bool returnValue, params string[] members)
		{
			ReturnValue = returnValue;
			Members = members;
		}
	}
	[AttributeUsage(AttributeTargets.Constructor, AllowMultiple = false, Inherited = false)]
	[ExcludeFromCodeCoverage]
	internal sealed class SetsRequiredMembersAttribute : Attribute
	{
	}
	[AttributeUsage(AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Parameter, AllowMultiple = false, Inherited = false)]
	[ExcludeFromCodeCoverage]
	internal sealed class StringSyntaxAttribute : Attribute
	{
		public const string CompositeFormat = "CompositeFormat";

		public const string DateOnlyFormat = "DateOnlyFormat";

		public const string DateTimeFormat = "DateTimeFormat";

		public const string EnumFormat = "EnumFormat";

		public const string GuidFormat = "GuidFormat";

		public const string Json = "Json";

		public const string NumericFormat = "NumericFormat";

		public const string Regex = "Regex";

		public const string TimeOnlyFormat = "TimeOnlyFormat";

		public const string TimeSpanFormat = "TimeSpanFormat";

		public const string Uri = "Uri";

		public const string Xml = "Xml";

		public string Syntax { get; }

		public object?[] Arguments { get; }

		public StringSyntaxAttribute(string syntax)
		{
			Syntax = syntax;
			Arguments = new object[0];
		}

		public StringSyntaxAttribute(string syntax, params object?[] arguments)
		{
			Syntax = syntax;
			Arguments = arguments;
		}
	}
	[AttributeUsage(AttributeTargets.Method | AttributeTargets.Property | AttributeTargets.Parameter, AllowMultiple = false, Inherited = false)]
	[ExcludeFromCodeCoverage]
	internal sealed class UnscopedRefAttribute : Attribute
	{
	}
}
namespace System.Runtime.Versioning
{
	[AttributeUsage(AttributeTargets.Assembly | AttributeTargets.Module | AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Enum | AttributeTargets.Constructor | AttributeTargets.Method | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Interface | AttributeTargets.Delegate, Inherited = false)]
	[ExcludeFromCodeCoverage]
	internal sealed class RequiresPreviewFeaturesAttribute : Attribute
	{
		public string? Message { get; }

		public string? Url { get; set; }

		public RequiresPreviewFeaturesAttribute()
		{
		}

		public RequiresPreviewFeaturesAttribute(string? message)
		{
			Message = message;
		}
	}
}
namespace System.Runtime.CompilerServices
{
	[AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)]
	internal sealed class IgnoresAccessChecksToAttribute : Attribute
	{
		public IgnoresAccessChecksToAttribute(string assemblyName)
		{
		}
	}
	[AttributeUsage(AttributeTargets.Parameter, AllowMultiple = false, Inherited = false)]
	[ExcludeFromCodeCoverage]
	internal sealed class CallerArgumentExpressionAttribute : Attribute
	{
		public string ParameterName { get; }

		public CallerArgumentExpressionAttribute(string parameterName)
		{
			ParameterName = parameterName;
		}
	}
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Interface, Inherited = false)]
	[ExcludeFromCodeCoverage]
	internal sealed class CollectionBuilderAttribute : Attribute
	{
		public Type BuilderType { get; }

		public string MethodName { get; }

		public CollectionBuilderAttribute(Type builderType, string methodName)
		{
			BuilderType = builderType;
			MethodName = methodName;
		}
	}
	[AttributeUsage(AttributeTargets.All, AllowMultiple = true, Inherited = false)]
	[ExcludeFromCodeCoverage]
	internal sealed class CompilerFeatureRequiredAttribute : Attribute
	{
		public const string RefStructs = "RefStructs";

		public const string RequiredMembers = "RequiredMembers";

		public string FeatureName { get; }

		public bool IsOptional { get; set; }

		public CompilerFeatureRequiredAttribute(string featureName)
		{
			FeatureName = featureName;
		}
	}
	[AttributeUsage(AttributeTargets.Parameter, AllowMultiple = false, Inherited = false)]
	[ExcludeFromCodeCoverage]
	internal sealed class InterpolatedStringHandlerArgumentAttribute : Attribute
	{
		public string[] Arguments { get; }

		public InterpolatedStringHandlerArgumentAttribute(string argument)
		{
			Arguments = new string[1] { argument };
		}

		public InterpolatedStringHandlerArgumentAttribute(params string[] arguments)
		{
			Arguments = arguments;
		}
	}
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct, AllowMultiple = false, Inherited = false)]
	[ExcludeFromCodeCoverage]
	internal sealed class InterpolatedStringHandlerAttribute : Attribute
	{
	}
	[EditorBrowsable(EditorBrowsableState.Never)]
	[ExcludeFromCodeCoverage]
	internal static class IsExternalInit
	{
	}
	[AttributeUsage(AttributeTargets.Method, Inherited = false)]
	[ExcludeFromCodeCoverage]
	internal sealed class ModuleInitializerAttribute : Attribute
	{
	}
	[AttributeUsage(AttributeTargets.Constructor | AttributeTargets.Method | AttributeTargets.Property, AllowMultiple = false, Inherited = false)]
	[ExcludeFromCodeCoverage]
	internal sealed class OverloadResolutionPriorityAttribute : Attribute
	{
		public int Priority { get; }

		public OverloadResolutionPriorityAttribute(int priority)
		{
			Priority = priority;
		}
	}
	[AttributeUsage(AttributeTargets.Parameter, Inherited = true, AllowMultiple = false)]
	[ExcludeFromCodeCoverage]
	internal sealed class ParamCollectionAttribute : Attribute
	{
	}
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Property | AttributeTargets.Field, AllowMultiple = false, Inherited = false)]
	[ExcludeFromCodeCoverage]
	internal sealed class RequiredMemberAttribute : Attribute
	{
	}
	[AttributeUsage(AttributeTargets.Parameter, Inherited = false)]
	[EditorBrowsable(EditorBrowsableState.Never)]
	[ExcludeFromCodeCoverage]
	internal sealed class RequiresLocationAttribute : Attribute
	{
	}
	[AttributeUsage(AttributeTargets.Module | AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Constructor | AttributeTargets.Method | AttributeTargets.Property | AttributeTargets.Event | AttributeTargets.Interface, Inherited = false)]
	[ExcludeFromCodeCoverage]
	internal sealed class SkipLocalsInitAttribute : Attribute
	{
	}
}