Decompiled source of PeakTTS v1.2.1

PeakTTS/PeakTTS.dll

Decompiled 2 weeks ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading;
using System.Threading.Tasks;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using UnityEngine;
using UnityEngine.SceneManagement;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("PeakTTS")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.2.1.0")]
[assembly: AssemblyInformationalVersion("1.2.1")]
[assembly: AssemblyProduct("PeakTTS")]
[assembly: AssemblyTitle("PeakTTS")]
[assembly: AssemblyVersion("1.2.1.0")]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace PeakTTS
{
	internal static class ExternalTts
	{
		public static SpeechClip SynthesizePiper(string text, VoiceOption voice, string piperPath, int speakerId)
		{
			if (voice == null || voice.Backend != VoiceBackend.Piper)
			{
				throw new ArgumentException("A Piper voice is required", "voice");
			}
			if (!File.Exists(voice.ModelPath))
			{
				throw new FileNotFoundException("Piper .onnx model was not found", voice.ModelPath);
			}
			if (!File.Exists(voice.ConfigPath))
			{
				throw new FileNotFoundException("Piper model config (.onnx.json) was not found", voice.ConfigPath);
			}
			if (string.IsNullOrWhiteSpace(piperPath))
			{
				throw new InvalidOperationException("PiperPath is empty");
			}
			string text2 = TempWavPath();
			try
			{
				StringBuilder stringBuilder = new StringBuilder();
				stringBuilder.Append("--model ").Append(QuoteArg(voice.ModelPath));
				stringBuilder.Append(" --output_file ").Append(QuoteArg(text2));
				if (speakerId >= 0)
				{
					stringBuilder.Append(" --speaker ").Append(speakerId);
				}
				ProcessStartInfo processStartInfo = CreateProcess(piperPath, stringBuilder.ToString(), Path.GetDirectoryName(voice.ModelPath));
				processStartInfo.RedirectStandardInput = true;
				RunProcess(processStartInfo, text ?? string.Empty, "Piper");
				if (!File.Exists(text2))
				{
					throw new FileNotFoundException("Piper did not produce a WAV file", text2);
				}
				return WavReader.ReadMono(text2);
			}
			finally
			{
				TryDelete(text2);
			}
		}

		public static SpeechClip SynthesizeCoqui(string text, VoiceOption voice, string coquiTtsPath, string speaker, string language, string speakerWav)
		{
			if (voice == null || voice.Backend != VoiceBackend.Coqui)
			{
				throw new ArgumentException("A Coqui voice is required", "voice");
			}
			if (!File.Exists(voice.ModelPath))
			{
				throw new FileNotFoundException("Coqui .pth model was not found", voice.ModelPath);
			}
			if (!File.Exists(voice.ConfigPath))
			{
				throw new FileNotFoundException("Coqui model config (config.json) was not found", voice.ConfigPath);
			}
			if (string.IsNullOrWhiteSpace(coquiTtsPath))
			{
				throw new InvalidOperationException("CoquiTtsPath is empty");
			}
			string text2 = TempWavPath();
			try
			{
				StringBuilder stringBuilder = new StringBuilder();
				stringBuilder.Append("--text ").Append(QuoteArg(text ?? string.Empty));
				stringBuilder.Append(" --model_path ").Append(QuoteArg(voice.ModelPath));
				stringBuilder.Append(" --config_path ").Append(QuoteArg(voice.ConfigPath));
				stringBuilder.Append(" --out_path ").Append(QuoteArg(text2));
				if (!string.IsNullOrWhiteSpace(speaker))
				{
					stringBuilder.Append(" --speaker_idx ").Append(QuoteArg(speaker));
				}
				if (!string.IsNullOrWhiteSpace(language))
				{
					stringBuilder.Append(" --language_idx ").Append(QuoteArg(language));
				}
				string value = ResolveOptionalPath(speakerWav, Path.GetDirectoryName(voice.ModelPath));
				if (!string.IsNullOrWhiteSpace(value))
				{
					stringBuilder.Append(" --speaker_wav ").Append(QuoteArg(value));
				}
				RunProcess(CreateProcess(coquiTtsPath, stringBuilder.ToString(), Path.GetDirectoryName(voice.ModelPath)), null, "Coqui TTS");
				if (!File.Exists(text2))
				{
					throw new FileNotFoundException("Coqui TTS did not produce a WAV file", text2);
				}
				return WavReader.ReadMono(text2);
			}
			finally
			{
				TryDelete(text2);
			}
		}

		private static void RunProcess(ProcessStartInfo psi, string standardInput, string label)
		{
			StringBuilder stdout = new StringBuilder();
			StringBuilder stderr = new StringBuilder();
			using Process process = new Process
			{
				StartInfo = psi
			};
			process.OutputDataReceived += delegate(object _, DataReceivedEventArgs e)
			{
				if (e.Data != null)
				{
					stdout.AppendLine(e.Data);
				}
			};
			process.ErrorDataReceived += delegate(object _, DataReceivedEventArgs e)
			{
				if (e.Data != null)
				{
					stderr.AppendLine(e.Data);
				}
			};
			if (!process.Start())
			{
				throw new InvalidOperationException("Could not start " + label);
			}
			process.BeginOutputReadLine();
			process.BeginErrorReadLine();
			if (psi.RedirectStandardInput)
			{
				process.StandardInput.Write(standardInput ?? string.Empty);
				process.StandardInput.WriteLine();
				process.StandardInput.Close();
			}
			process.WaitForExit();
			process.WaitForExit();
			if (process.ExitCode != 0)
			{
				throw new InvalidOperationException($"{label} exited with code {process.ExitCode}: {stderr}\n{stdout}");
			}
		}

		private static ProcessStartInfo CreateProcess(string executable, string arguments, string workingDirectory)
		{
			return new ProcessStartInfo
			{
				FileName = executable,
				Arguments = arguments,
				UseShellExecute = false,
				CreateNoWindow = true,
				RedirectStandardOutput = true,
				RedirectStandardError = true,
				WorkingDirectory = (string.IsNullOrWhiteSpace(workingDirectory) ? Environment.CurrentDirectory : workingDirectory)
			};
		}

		private static string TempWavPath()
		{
			string text = Path.Combine(Path.GetTempPath(), "PeakTTS");
			Directory.CreateDirectory(text);
			return Path.Combine(text, Guid.NewGuid().ToString("N") + ".wav");
		}

		private static string ResolveOptionalPath(string value, string baseDirectory)
		{
			if (string.IsNullOrWhiteSpace(value))
			{
				return string.Empty;
			}
			if (Path.IsPathRooted(value))
			{
				return value;
			}
			return Path.Combine(baseDirectory ?? Environment.CurrentDirectory, value);
		}

		private static string QuoteArg(string value)
		{
			if (value == null)
			{
				return "\"\"";
			}
			if (value.Length > 0 && value.IndexOfAny(new char[5] { ' ', '\t', '\n', '\v', '"' }) < 0)
			{
				return value;
			}
			StringBuilder stringBuilder = new StringBuilder();
			stringBuilder.Append('"');
			int num = 0;
			foreach (char c in value)
			{
				switch (c)
				{
				case '\\':
					num++;
					continue;
				case '"':
					stringBuilder.Append('\\', num * 2 + 1);
					stringBuilder.Append('"');
					num = 0;
					continue;
				}
				if (num > 0)
				{
					stringBuilder.Append('\\', num);
					num = 0;
				}
				stringBuilder.Append(c);
			}
			if (num > 0)
			{
				stringBuilder.Append('\\', num * 2);
			}
			stringBuilder.Append('"');
			return stringBuilder.ToString();
		}

		private static void TryDelete(string path)
		{
			try
			{
				if (!string.IsNullOrEmpty(path) && File.Exists(path))
				{
					File.Delete(path);
				}
			}
			catch
			{
			}
		}
	}
	internal static class GameInputBridge
	{
		private static Type _guiManagerType;

		private static PropertyInfo _instanceProperty;

		private static FieldInfo _instanceField;

		private static PropertyInfo _windowBlockingInputProperty;

		public static bool InstallPatch(Harmony harmony)
		{
			//IL_00b8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00be: Expected O, but got Unknown
			try
			{
				_guiManagerType = AccessTools.TypeByName("GUIManager");
				if (_guiManagerType == null)
				{
					ManualLogSource logSource = Plugin.LogSource;
					if (logSource != null)
					{
						logSource.LogWarning((object)"GUIManager not found; the TTS box will still work, but PEAK input may not be blocked while typing");
					}
					return false;
				}
				_instanceProperty = AccessTools.Property(_guiManagerType, "instance");
				_instanceField = AccessTools.Field(_guiManagerType, "instance");
				_windowBlockingInputProperty = AccessTools.Property(_guiManagerType, "windowBlockingInput");
				MethodInfo methodInfo = AccessTools.Method(_guiManagerType, "UpdateWindowStatus", (Type[])null, (Type[])null);
				if (methodInfo == null)
				{
					ManualLogSource logSource2 = Plugin.LogSource;
					if (logSource2 != null)
					{
						logSource2.LogWarning((object)"GUIManager.UpdateWindowStatus not found; inputblock disabled");
					}
					return false;
				}
				HarmonyMethod val = new HarmonyMethod(typeof(GameInputBridge), "UpdateWindowStatusPostfix", (Type[])null);
				harmony.Patch((MethodBase)methodInfo, (HarmonyMethod)null, val, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
				return true;
			}
			catch (Exception ex)
			{
				ManualLogSource logSource3 = Plugin.LogSource;
				if (logSource3 != null)
				{
					logSource3.LogWarning((object)("Could not install PEAK inputblock: " + ex.Message));
				}
				return false;
			}
		}

		public static bool IsBlockedByGame()
		{
			try
			{
				EnsureReflection();
				object instance = GetInstance();
				if (instance == null || _windowBlockingInputProperty == null)
				{
					return false;
				}
				return Convert.ToBoolean(_windowBlockingInputProperty.GetValue(instance, null));
			}
			catch
			{
				return false;
			}
		}

		private static void UpdateWindowStatusPostfix()
		{
			if ((Object)(object)Plugin.Instance == (Object)null || !Plugin.Instance.IsInputOpen)
			{
				return;
			}
			try
			{
				EnsureReflection();
				object instance = GetInstance();
				if (instance != null && !(_windowBlockingInputProperty == null) && _windowBlockingInputProperty.CanWrite)
				{
					_windowBlockingInputProperty.SetValue(instance, true, null);
				}
			}
			catch
			{
			}
		}

		private static object GetInstance()
		{
			object obj = _instanceProperty?.GetValue(null, null);
			if (obj == null)
			{
				FieldInfo instanceField = _instanceField;
				if ((object)instanceField == null)
				{
					return null;
				}
				obj = instanceField.GetValue(null);
			}
			return obj;
		}

		private static void EnsureReflection()
		{
			if (!(_guiManagerType != null))
			{
				_guiManagerType = AccessTools.TypeByName("GUIManager");
				if (!(_guiManagerType == null))
				{
					_instanceProperty = AccessTools.Property(_guiManagerType, "instance");
					_instanceField = AccessTools.Field(_guiManagerType, "instance");
					_windowBlockingInputProperty = AccessTools.Property(_guiManagerType, "windowBlockingInput");
				}
			}
		}
	}
	internal sealed class LanguageChoice
	{
		public string Code;

		public string DisplayName;

		public override string ToString()
		{
			return DisplayName ?? Code ?? "Language";
		}
	}
	internal static class LanguageSupport
	{
		private static readonly LanguageChoice[] Choices = new LanguageChoice[25]
		{
			new LanguageChoice
			{
				Code = "auto",
				DisplayName = "Auto"
			},
			new LanguageChoice
			{
				Code = "en",
				DisplayName = "English (en)"
			},
			new LanguageChoice
			{
				Code = "ko",
				DisplayName = "Korean (ko)"
			},
			new LanguageChoice
			{
				Code = "ja",
				DisplayName = "Japanese (ja)"
			},
			new LanguageChoice
			{
				Code = "zh-cn",
				DisplayName = "Chinese (zh-cn)"
			},
			new LanguageChoice
			{
				Code = "es",
				DisplayName = "Spanish (es)"
			},
			new LanguageChoice
			{
				Code = "fr",
				DisplayName = "French (fr)"
			},
			new LanguageChoice
			{
				Code = "de",
				DisplayName = "German (de)"
			},
			new LanguageChoice
			{
				Code = "it",
				DisplayName = "Italian (it)"
			},
			new LanguageChoice
			{
				Code = "pt",
				DisplayName = "Portuguese (pt)"
			},
			new LanguageChoice
			{
				Code = "pl",
				DisplayName = "Polish (pl)"
			},
			new LanguageChoice
			{
				Code = "tr",
				DisplayName = "Turkish (tr)"
			},
			new LanguageChoice
			{
				Code = "ru",
				DisplayName = "Russian (ru)"
			},
			new LanguageChoice
			{
				Code = "nl",
				DisplayName = "Dutch (nl)"
			},
			new LanguageChoice
			{
				Code = "cs",
				DisplayName = "Czech (cs)"
			},
			new LanguageChoice
			{
				Code = "ar",
				DisplayName = "Arabic (ar)"
			},
			new LanguageChoice
			{
				Code = "hu",
				DisplayName = "Hungarian (hu)"
			},
			new LanguageChoice
			{
				Code = "hi",
				DisplayName = "Hindi (hi)"
			},
			new LanguageChoice
			{
				Code = "el",
				DisplayName = "Greek (el)"
			},
			new LanguageChoice
			{
				Code = "he",
				DisplayName = "Hebrew (he)"
			},
			new LanguageChoice
			{
				Code = "th",
				DisplayName = "Thai (th)"
			},
			new LanguageChoice
			{
				Code = "sv",
				DisplayName = "Swedish (sv)"
			},
			new LanguageChoice
			{
				Code = "da",
				DisplayName = "Danish (da)"
			},
			new LanguageChoice
			{
				Code = "no",
				DisplayName = "Norwegian (no)"
			},
			new LanguageChoice
			{
				Code = "fi",
				DisplayName = "Finnish (fi)"
			}
		};

		private static readonly Dictionary<string, string> FriendlyNames = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase)
		{
			["en"] = "English",
			["ko"] = "Korean",
			["ja"] = "Japanese",
			["zh"] = "Chinese",
			["zh-cn"] = "Chinese",
			["es"] = "Spanish",
			["fr"] = "French",
			["de"] = "German",
			["it"] = "Italian",
			["pt"] = "Portuguese",
			["pl"] = "Polish",
			["tr"] = "Turkish",
			["ru"] = "Russian",
			["nl"] = "Dutch",
			["cs"] = "Czech",
			["ar"] = "Arabic",
			["hu"] = "Hungarian",
			["hi"] = "Hindi",
			["el"] = "Greek",
			["he"] = "Hebrew",
			["th"] = "Thai",
			["sv"] = "Swedish",
			["da"] = "Danish",
			["no"] = "Norwegian",
			["fi"] = "Finnish"
		};

		public static LanguageChoice[] SnapshotChoices()
		{
			return Choices.Select((LanguageChoice c) => new LanguageChoice
			{
				Code = c.Code,
				DisplayName = c.DisplayName
			}).ToArray();
		}

		public static string Step(string current, int delta)
		{
			string normalized = NormalizeLanguageCode(current);
			if (string.IsNullOrEmpty(normalized))
			{
				normalized = "auto";
			}
			int num = Array.FindIndex(Choices, (LanguageChoice c) => string.Equals(c.Code, normalized, StringComparison.OrdinalIgnoreCase));
			if (num < 0)
			{
				num = 0;
			}
			int num2 = (num + delta) % Choices.Length;
			if (num2 < 0)
			{
				num2 += Choices.Length;
			}
			return Choices[num2].Code;
		}

		public static string GetDisplayName(string code)
		{
			string normalized = NormalizeLanguageCode(code);
			if (string.IsNullOrEmpty(normalized) || normalized == "auto")
			{
				return "Auto";
			}
			return Choices.FirstOrDefault((LanguageChoice c) => string.Equals(c.Code, normalized, StringComparison.OrdinalIgnoreCase))?.DisplayName ?? (FriendlyLanguageName(normalized) + " (" + normalized + ")");
		}

		public static string FriendlyLanguageName(string code)
		{
			string text = NormalizeLanguageCode(code);
			if (string.IsNullOrEmpty(text) || text == "auto")
			{
				return "Auto";
			}
			string key = LanguageFamily(text);
			if (FriendlyNames.TryGetValue(text, out var value))
			{
				return value;
			}
			if (FriendlyNames.TryGetValue(key, out var value2))
			{
				return value2;
			}
			return text;
		}

		public static string ResolveRequestedLanguage(string setting, string text)
		{
			return ResolveRequestedLanguage(setting, text, null);
		}

		public static string ResolveRequestedLanguage(string setting, string text, IEnumerable<string> preferredVoiceLanguages)
		{
			string text2 = NormalizeLanguageCode(setting);
			if (!string.IsNullOrEmpty(text2) && text2 != "auto")
			{
				return text2;
			}
			string text3 = DetectConfident(text);
			if (!string.IsNullOrEmpty(text3))
			{
				return text3;
			}
			string text4 = PreferredVoiceLanguage(preferredVoiceLanguages);
			if (!string.IsNullOrEmpty(text4))
			{
				return text4;
			}
			return "en";
		}

		public static string Detect(string text)
		{
			string text2 = DetectConfident(text);
			if (!string.IsNullOrEmpty(text2))
			{
				return text2;
			}
			return "en";
		}

		public static string DetectConfident(string text)
		{
			if (string.IsNullOrWhiteSpace(text))
			{
				return string.Empty;
			}
			int num = 0;
			int num2 = 0;
			int num3 = 0;
			int num4 = 0;
			int num5 = 0;
			int num6 = 0;
			int num7 = 0;
			int num8 = 0;
			int num9 = 0;
			foreach (int num10 in text)
			{
				if ((num10 >= 44032 && num10 <= 55215) || (num10 >= 4352 && num10 <= 4607) || (num10 >= 12592 && num10 <= 12687))
				{
					num++;
				}
				else if ((num10 >= 12352 && num10 <= 12543) || (num10 >= 12784 && num10 <= 12799))
				{
					num2++;
				}
				else if ((num10 >= 19968 && num10 <= 40959) || (num10 >= 13312 && num10 <= 19903))
				{
					num3++;
				}
				else if ((num10 >= 1536 && num10 <= 1791) || (num10 >= 1872 && num10 <= 1919) || (num10 >= 2208 && num10 <= 2303))
				{
					num4++;
				}
				else if (num10 >= 1024 && num10 <= 1327)
				{
					num5++;
				}
				else if (num10 >= 2304 && num10 <= 2431)
				{
					num6++;
				}
				else if (num10 >= 880 && num10 <= 1023)
				{
					num7++;
				}
				else if (num10 >= 1424 && num10 <= 1535)
				{
					num8++;
				}
				else if (num10 >= 3584 && num10 <= 3711)
				{
					num9++;
				}
			}
			if (num > 0)
			{
				return "ko";
			}
			if (num2 > 0)
			{
				return "ja";
			}
			if (num3 > 0)
			{
				return "zh-cn";
			}
			if (num4 > 0)
			{
				return "ar";
			}
			if (num5 > 0)
			{
				return "ru";
			}
			if (num6 > 0)
			{
				return "hi";
			}
			if (num7 > 0)
			{
				return "el";
			}
			if (num8 > 0)
			{
				return "he";
			}
			if (num9 > 0)
			{
				return "th";
			}
			return DetectLatinLanguage(text);
		}

		private static string PreferredVoiceLanguage(IEnumerable<string> languages)
		{
			if (languages == null)
			{
				return string.Empty;
			}
			string[] array = (from v in languages.Select(NormalizeLanguageCode)
				where !string.IsNullOrEmpty(v) && v != "auto"
				select v).ToArray();
			if (array.Length == 0)
			{
				return string.Empty;
			}
			string[] array2 = (from v in array.Select(LanguageFamily)
				where !string.IsNullOrEmpty(v)
				select v).Distinct<string>(StringComparer.OrdinalIgnoreCase).ToArray();
			if (array2.Length != 1)
			{
				return string.Empty;
			}
			return array2[0];
		}

		public static string NormalizeLanguageCode(string code)
		{
			if (string.IsNullOrWhiteSpace(code))
			{
				return string.Empty;
			}
			string text = code.Trim().Replace('_', '-').ToLowerInvariant();
			if (text == "automatic")
			{
				return "auto";
			}
			if (text == "zh" || text.StartsWith("zh-cn", StringComparison.Ordinal) || text.StartsWith("zh-hans", StringComparison.Ordinal))
			{
				return "zh-cn";
			}
			if (text.StartsWith("zh-tw", StringComparison.Ordinal) || text.StartsWith("zh-hk", StringComparison.Ordinal) || text.StartsWith("zh-hant", StringComparison.Ordinal))
			{
				return "zh";
			}
			return text;
		}

		public static string LanguageFamily(string code)
		{
			string text = NormalizeLanguageCode(code);
			if (string.IsNullOrEmpty(text) || text == "auto")
			{
				return text;
			}
			if (text.StartsWith("zh", StringComparison.Ordinal))
			{
				return "zh";
			}
			int num = text.IndexOf('-');
			if (num <= 0)
			{
				return text;
			}
			return text.Substring(0, num);
		}

		public static bool SupportsLanguage(IEnumerable<string> supportedLanguages, string requestedLanguage)
		{
			if (supportedLanguages == null)
			{
				return false;
			}
			string text = NormalizeLanguageCode(requestedLanguage);
			if (string.IsNullOrEmpty(text) || text == "auto")
			{
				return true;
			}
			string b = LanguageFamily(text);
			foreach (string supportedLanguage in supportedLanguages)
			{
				string text2 = NormalizeLanguageCode(supportedLanguage);
				if (!string.IsNullOrEmpty(text2))
				{
					if (string.Equals(text2, text, StringComparison.OrdinalIgnoreCase))
					{
						return true;
					}
					if (string.Equals(LanguageFamily(text2), b, StringComparison.OrdinalIgnoreCase))
					{
						return true;
					}
				}
			}
			return false;
		}

		public static string BestLanguageCodeForBackend(IEnumerable<string> supportedLanguages, string requestedLanguage)
		{
			if (supportedLanguages == null)
			{
				return string.Empty;
			}
			string requested = NormalizeLanguageCode(requestedLanguage);
			if (string.IsNullOrEmpty(requested) || requested == "auto")
			{
				return string.Empty;
			}
			string requestedFamily = LanguageFamily(requested);
			string[] source = (from v in supportedLanguages.Select(NormalizeLanguageCode)
				where !string.IsNullOrEmpty(v)
				select v).Distinct<string>(StringComparer.OrdinalIgnoreCase).ToArray();
			string text = source.FirstOrDefault((string v) => string.Equals(v, requested, StringComparison.OrdinalIgnoreCase));
			if (!string.IsNullOrEmpty(text))
			{
				return text;
			}
			return source.FirstOrDefault((string v) => string.Equals(LanguageFamily(v), requestedFamily, StringComparison.OrdinalIgnoreCase)) ?? string.Empty;
		}

		private static string DetectLatinLanguage(string text)
		{
			string text2 = (text ?? string.Empty).ToLowerInvariant();
			if (ContainsAny(text2, "ą", "ć", "ę", "ł", "ń", "ś", "ź", "ż"))
			{
				return "pl";
			}
			if (ContainsAny(text2, "č", "ď", "ě", "ň", "ř", "š", "ť", "ů", "ž"))
			{
				return "cs";
			}
			if (ContainsAny(text2, "ğ", "ı", "ş"))
			{
				return "tr";
			}
			if (ContainsAny(text2, "ő", "ű", "ó"))
			{
				return "hu";
			}
			if (ContainsAny(text2, "ß"))
			{
				return "de";
			}
			if (ContainsAny(text2, "ñ", "¿", "¡"))
			{
				return "es";
			}
			if (ContainsAny(text2, "ã", "õ"))
			{
				return "pt";
			}
			if (ContainsAny(text2, "œ", "æ"))
			{
				return "fr";
			}
			string[] array = Tokenize(text2);
			if (array.Length == 0)
			{
				return string.Empty;
			}
			Dictionary<string, int> dictionary = new Dictionary<string, int>(StringComparer.OrdinalIgnoreCase);
			dictionary["en"] = Score(array, "the", "and", "you", "is", "are", "this", "that", "with", "for", "not", "hello", "what");
			dictionary["es"] = Score(array, "el", "la", "los", "las", "que", "de", "y", "es", "una", "por", "para", "hola");
			dictionary["fr"] = Score(array, "le", "la", "les", "des", "que", "et", "est", "une", "pour", "pas", "bonjour", "avec");
			dictionary["de"] = Score(array, "der", "die", "das", "und", "ist", "nicht", "ich", "du", "mit", "für", "ein", "eine");
			dictionary["it"] = Score(array, "il", "lo", "la", "gli", "che", "e", "è", "non", "una", "per", "con", "ciao");
			dictionary["pt"] = Score(array, "o", "a", "os", "as", "que", "de", "e", "não", "uma", "para", "com", "olá");
			dictionary["nl"] = Score(array, "de", "het", "een", "en", "is", "niet", "ik", "je", "met", "voor", "dat", "hallo");
			dictionary["tr"] = Score(array, "ve", "bir", "bu", "de", "da", "için", "ile", "ben", "sen", "değil", "merhaba");
			dictionary["hu"] = Score(array, "és", "egy", "hogy", "nem", "az", "a", "van", "én", "te", "meg", "szia", "ez", "itt", "ott", "vagy", "vagyok", "volt", "lesz", "mert", "mint", "csak", "igen", "mit", "miért", "jó", "köszönöm", "köszi", "magyar");
			dictionary["sv"] = Score(array, "och", "det", "är", "inte", "en", "ett", "jag", "du", "med", "för", "hej");
			dictionary["da"] = Score(array, "og", "det", "er", "ikke", "en", "et", "jeg", "du", "med", "for", "hej");
			dictionary["no"] = Score(array, "og", "det", "er", "ikke", "en", "et", "jeg", "du", "med", "for", "hei");
			dictionary["fi"] = Score(array, "ja", "on", "ei", "että", "se", "minä", "sinä", "kanssa", "hei");
			KeyValuePair<string, int>[] array2 = dictionary.OrderByDescending((KeyValuePair<string, int> kv) => kv.Value).ToArray();
			if (array2.Length != 0 && array2[0].Value >= 2 && (array2.Length == 1 || array2[0].Value > array2[1].Value))
			{
				return array2[0].Key;
			}
			return string.Empty;
		}

		private static string[] Tokenize(string text)
		{
			char[] array = new char[text.Length];
			for (int i = 0; i < text.Length; i++)
			{
				char c = text[i];
				array[i] = (char.IsLetter(c) ? c : ' ');
			}
			return new string(array).Split(new char[1] { ' ' }, StringSplitOptions.RemoveEmptyEntries);
		}

		private static int Score(string[] words, params string[] markers)
		{
			if (words == null || markers == null)
			{
				return 0;
			}
			HashSet<string> hashSet = new HashSet<string>(words, StringComparer.OrdinalIgnoreCase);
			int num = 0;
			foreach (string item in markers)
			{
				if (hashSet.Contains(item))
				{
					num++;
				}
			}
			return num;
		}

		private static bool ContainsAny(string value, params string[] needles)
		{
			if (string.IsNullOrEmpty(value) || needles == null)
			{
				return false;
			}
			foreach (string value2 in needles)
			{
				if (!string.IsNullOrEmpty(value2) && value.IndexOf(value2, StringComparison.Ordinal) >= 0)
				{
					return true;
				}
			}
			return false;
		}
	}
	internal sealed class PeakNativeUiRenderer : IDisposable
	{
		private sealed class VisualSlot
		{
			public GameObject Object;

			public RectTransform RectTransform;

			public Component RawImage;
		}

		private sealed class TextSlot
		{
			public GameObject Object;

			public RectTransform RectTransform;

			public Component Text;
		}

		private readonly ManualLogSource _log;

		private readonly List<VisualSlot> _visualSlots = new List<VisualSlot>();

		private readonly List<TextSlot> _textSlots = new List<TextSlot>();

		private Type _rawImageType;

		private PropertyInfo _rawImageTextureProperty;

		private PropertyInfo _rawImageColorProperty;

		private PropertyInfo _rawImageRaycastProperty;

		private Type _tmpTextType;

		private PropertyInfo _tmpTextProperty;

		private PropertyInfo _tmpFontProperty;

		private PropertyInfo _tmpFontSharedMaterialProperty;

		private PropertyInfo _tmpFontSizeProperty;

		private PropertyInfo _tmpColorProperty;

		private PropertyInfo _tmpAlignmentProperty;

		private PropertyInfo _tmpWordWrapProperty;

		private PropertyInfo _tmpRaycastProperty;

		private PropertyInfo _tmpRichTextProperty;

		private PropertyInfo _tmpAutoSizingProperty;

		private Object _nativeFont;

		private Material _nativeMaterial;

		private bool _ownsNativeMaterial;

		private PropertyInfo _tmpMaterialForRenderingProperty;

		private GameObject _canvasObject;

		private Canvas _canvas;

		private Transform _visualRoot;

		private Transform _textRoot;

		private int _visualCursor;

		private int _textCursor;

		private float _nextFontScanAt;

		private bool _loggedFontReady;

		private bool _loggedMissingUi;

		internal bool CanRenderVisuals
		{
			get
			{
				ResolveTypes();
				if (_rawImageType != null)
				{
					return EnsureCanvas();
				}
				return false;
			}
		}

		internal bool CanRenderNativeText
		{
			get
			{
				if (CanRenderVisuals && _tmpTextType != null && _nativeFont != (Object)null)
				{
					return (Object)(object)_nativeMaterial != (Object)null;
				}
				return false;
			}
		}

		internal PeakNativeUiRenderer(ManualLogSource log)
		{
			_log = log;
			ResolveTypes();
		}

		internal void TryDiscoverNativeFont(bool allowScan)
		{
			if (CanRenderNativeText || !allowScan || Time.unscaledTime < _nextFontScanAt)
			{
				return;
			}
			_nextFontScanAt = Time.unscaledTime + 2f;
			ResolveTypes();
			if (_tmpTextType == null)
			{
				return;
			}
			try
			{
				Object[] array = Object.FindObjectsByType(_tmpTextType, (FindObjectsSortMode)0);
				if (array == null)
				{
					return;
				}
				Object[] array2 = array;
				foreach (Object obj in array2)
				{
					Component val = (Component)(object)((obj is Component) ? obj : null);
					if ((Object)(object)val == (Object)null)
					{
						continue;
					}
					object value = GetValue(_tmpFontProperty, val);
					Object val2 = (Object)((value is Object) ? value : null);
					string text = ((val2 != (Object)null) ? (val2.name ?? string.Empty) : string.Empty);
					if (text.IndexOf("DarumaDropOne", StringComparison.OrdinalIgnoreCase) >= 0 || text.IndexOf("Daruma Drop One", StringComparison.OrdinalIgnoreCase) >= 0)
					{
						Material val3 = CreateCleanFontMaterial(val2, val);
						if (!((Object)(object)val3 == (Object)null))
						{
							ReleaseNativeMaterial();
							_nativeFont = val2;
							_nativeMaterial = val3;
							_ownsNativeMaterial = true;
							break;
						}
					}
				}
				if (CanRenderNativeText && !_loggedFontReady)
				{
					_loggedFontReady = true;
					ManualLogSource log = _log;
					if (log != null)
					{
						log.LogInfo((object)("Found PEAK native font '" + _nativeFont.name + "' and created a clean SDF material"));
					}
				}
			}
			catch (Exception ex)
			{
				ManualLogSource log2 = _log;
				if (log2 != null)
				{
					log2.LogDebug((object)("PEAK native Daruma font is not available yet: " + ex.Message));
				}
			}
		}

		internal void BeginGuiFrame()
		{
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0012: Invalid comparison between Unknown and I4
			if (Event.current != null && (int)Event.current.type == 7)
			{
				_visualCursor = 0;
				_textCursor = 0;
			}
		}

		internal void EndGuiFrame()
		{
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0012: Invalid comparison between Unknown and I4
			if (Event.current == null || (int)Event.current.type != 7)
			{
				return;
			}
			for (int i = _visualCursor; i < _visualSlots.Count; i++)
			{
				VisualSlot visualSlot = _visualSlots[i];
				if ((Object)(object)visualSlot?.Object != (Object)null && visualSlot.Object.activeSelf)
				{
					visualSlot.Object.SetActive(false);
				}
			}
			for (int j = _textCursor; j < _textSlots.Count; j++)
			{
				TextSlot textSlot = _textSlots[j];
				if ((Object)(object)textSlot?.Object != (Object)null && textSlot.Object.activeSelf)
				{
					textSlot.Object.SetActive(false);
				}
			}
		}

		internal bool DrawRect(Rect rect, Color color)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			return DrawTexture(rect, (Texture)(object)Texture2D.whiteTexture, color);
		}

		internal bool DrawTexture(Rect rect, Texture texture, Color color)
		{
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_001c: Invalid comparison between Unknown and I4
			//IL_0049: Unknown result type (might be due to invalid IL or missing references)
			//IL_006d: Unknown result type (might be due to invalid IL or missing references)
			if (!CanRenderVisuals)
			{
				return false;
			}
			if (Event.current == null || (int)Event.current.type != 7)
			{
				return true;
			}
			try
			{
				VisualSlot visualSlot = GetVisualSlot(_visualCursor++);
				if (visualSlot == null)
				{
					return false;
				}
				ConfigureRect(visualSlot.RectTransform, rect);
				SetValue(_rawImageTextureProperty, visualSlot.RawImage, texture);
				SetValue(_rawImageColorProperty, visualSlot.RawImage, color);
				SetValue(_rawImageRaycastProperty, visualSlot.RawImage, false);
				if (!visualSlot.Object.activeSelf)
				{
					visualSlot.Object.SetActive(true);
				}
				return true;
			}
			catch (Exception ex)
			{
				ManualLogSource log = _log;
				if (log != null)
				{
					log.LogDebug((object)("Canvas visual draw failed: " + ex.Message));
				}
				return false;
			}
		}

		internal bool DrawText(Rect rect, string text, float fontSize, TextAnchor alignment, Color color, bool wordWrap)
		{
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_001c: Invalid comparison between Unknown and I4
			//IL_0049: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f8: Unknown result type (might be due to invalid IL or missing references)
			if (!CanRenderNativeText)
			{
				return false;
			}
			if (Event.current == null || (int)Event.current.type != 7)
			{
				return true;
			}
			try
			{
				TextSlot textSlot = GetTextSlot(_textCursor++);
				if (textSlot == null)
				{
					return false;
				}
				ConfigureRect(textSlot.RectTransform, rect);
				SetValue(_tmpTextProperty, textSlot.Text, text ?? string.Empty);
				SetValue(_tmpFontProperty, textSlot.Text, _nativeFont);
				if (_tmpFontSharedMaterialProperty != null && _tmpFontSharedMaterialProperty.CanWrite)
				{
					SetValue(_tmpFontSharedMaterialProperty, textSlot.Text, _nativeMaterial);
				}
				SetValue(_tmpFontSizeProperty, textSlot.Text, Mathf.Max(1f, fontSize));
				SetValue(_tmpColorProperty, textSlot.Text, color);
				SetEnumValue(_tmpAlignmentProperty, textSlot.Text, ToTmpAlignment(alignment));
				SetValue(_tmpWordWrapProperty, textSlot.Text, wordWrap);
				SetValue(_tmpRaycastProperty, textSlot.Text, false);
				SetValue(_tmpRichTextProperty, textSlot.Text, false);
				SetValue(_tmpAutoSizingProperty, textSlot.Text, false);
				if (!textSlot.Object.activeSelf)
				{
					textSlot.Object.SetActive(true);
				}
				return true;
			}
			catch (Exception ex)
			{
				ManualLogSource log = _log;
				if (log != null)
				{
					log.LogDebug((object)("Native TMP text draw failed: " + ex.Message));
				}
				return false;
			}
		}

		internal void ResetForScene()
		{
			DestroyCanvas();
			_nativeFont = null;
			ReleaseNativeMaterial();
			_nativeFont = null;
			_nextFontScanAt = 0f;
			_loggedFontReady = false;
		}

		public void Dispose()
		{
			DestroyCanvas();
			_nativeFont = null;
			ReleaseNativeMaterial();
			_nativeFont = null;
		}

		private void ResolveTypes()
		{
			if (_rawImageType == null)
			{
				_rawImageType = Type.GetType("UnityEngine.UI.RawImage, UnityEngine.UI", throwOnError: false);
				if (_rawImageType != null)
				{
					_rawImageTextureProperty = _rawImageType.GetProperty("texture");
					_rawImageColorProperty = _rawImageType.GetProperty("color");
					_rawImageRaycastProperty = _rawImageType.GetProperty("raycastTarget");
				}
			}
			if (_tmpTextType == null)
			{
				_tmpTextType = Type.GetType("TMPro.TextMeshProUGUI, Unity.TextMeshPro", throwOnError: false);
				if (_tmpTextType != null)
				{
					_tmpTextProperty = _tmpTextType.GetProperty("text");
					_tmpFontProperty = _tmpTextType.GetProperty("font");
					_tmpFontSharedMaterialProperty = _tmpTextType.GetProperty("fontSharedMaterial");
					_tmpFontSizeProperty = _tmpTextType.GetProperty("fontSize");
					_tmpColorProperty = _tmpTextType.GetProperty("color");
					_tmpAlignmentProperty = _tmpTextType.GetProperty("alignment");
					_tmpWordWrapProperty = _tmpTextType.GetProperty("enableWordWrapping");
					_tmpRaycastProperty = _tmpTextType.GetProperty("raycastTarget");
					_tmpRichTextProperty = _tmpTextType.GetProperty("richText");
					_tmpAutoSizingProperty = _tmpTextType.GetProperty("enableAutoSizing");
					_tmpMaterialForRenderingProperty = _tmpTextType.GetProperty("materialForRendering");
				}
			}
			if ((_rawImageType == null || _tmpTextType == null) && !_loggedMissingUi)
			{
				_loggedMissingUi = true;
				ManualLogSource log = _log;
				if (log != null)
				{
					log.LogWarning((object)"Unity UI/TextMeshPro types were not found yet. Using IMGUI fallback until they are available");
				}
			}
		}

		private bool EnsureCanvas()
		{
			//IL_0055: Unknown result type (might be due to invalid IL or missing references)
			//IL_005a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0067: Expected O, but got Unknown
			//IL_00cf: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00dd: Expected O, but got Unknown
			//IL_0123: Unknown result type (might be due to invalid IL or missing references)
			//IL_0128: Unknown result type (might be due to invalid IL or missing references)
			//IL_0131: Expected O, but got Unknown
			if ((Object)(object)_canvasObject != (Object)null && (Object)(object)_canvas != (Object)null)
			{
				return true;
			}
			if (_rawImageType == null)
			{
				return false;
			}
			try
			{
				_canvasObject = new GameObject("PeakTTS.NativeCanvas", new Type[2]
				{
					typeof(RectTransform),
					typeof(Canvas)
				})
				{
					hideFlags = (HideFlags)61
				};
				Object.DontDestroyOnLoad((Object)(object)_canvasObject);
				_canvas = _canvasObject.GetComponent<Canvas>();
				_canvas.renderMode = (RenderMode)0;
				_canvas.pixelPerfect = false;
				_canvas.overrideSorting = true;
				_canvas.sortingOrder = 32767;
				GameObject val = new GameObject("Visuals", new Type[1] { typeof(RectTransform) })
				{
					hideFlags = (HideFlags)61
				};
				val.transform.SetParent(_canvasObject.transform, false);
				StretchToParent(val.GetComponent<RectTransform>());
				_visualRoot = val.transform;
				GameObject val2 = new GameObject("Text", new Type[1] { typeof(RectTransform) })
				{
					hideFlags = (HideFlags)61
				};
				val2.transform.SetParent(_canvasObject.transform, false);
				StretchToParent(val2.GetComponent<RectTransform>());
				_textRoot = val2.transform;
				_textRoot.SetAsLastSibling();
				return true;
			}
			catch (Exception ex)
			{
				ManualLogSource log = _log;
				if (log != null)
				{
					log.LogWarning((object)("Could not create native Canvas: " + ex.Message));
				}
				DestroyCanvas();
				return false;
			}
		}

		private VisualSlot GetVisualSlot(int index)
		{
			//IL_0035: Unknown result type (might be due to invalid IL or missing references)
			//IL_003a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0043: Expected O, but got Unknown
			while (_visualSlots.Count <= index)
			{
				GameObject val = new GameObject("PeakTTS.Visual." + _visualSlots.Count, new Type[1] { typeof(RectTransform) })
				{
					hideFlags = (HideFlags)61
				};
				val.transform.SetParent(_visualRoot, false);
				Component val2 = val.AddComponent(_rawImageType);
				if ((Object)(object)val2 == (Object)null)
				{
					Object.Destroy((Object)(object)val);
					return null;
				}
				SetValue(_rawImageRaycastProperty, val2, false);
				_visualSlots.Add(new VisualSlot
				{
					Object = val,
					RectTransform = val.GetComponent<RectTransform>(),
					RawImage = val2
				});
			}
			return _visualSlots[index];
		}

		private TextSlot GetTextSlot(int index)
		{
			//IL_0035: Unknown result type (might be due to invalid IL or missing references)
			//IL_003a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0043: Expected O, but got Unknown
			while (_textSlots.Count <= index)
			{
				GameObject val = new GameObject("PeakTTS.Text." + _textSlots.Count, new Type[1] { typeof(RectTransform) })
				{
					hideFlags = (HideFlags)61
				};
				val.transform.SetParent(_textRoot, false);
				Component val2 = val.AddComponent(_tmpTextType);
				if ((Object)(object)val2 == (Object)null)
				{
					Object.Destroy((Object)(object)val);
					return null;
				}
				SetValue(_tmpRaycastProperty, val2, false);
				SetValue(_tmpRichTextProperty, val2, false);
				SetValue(_tmpAutoSizingProperty, val2, false);
				_textSlots.Add(new TextSlot
				{
					Object = val,
					RectTransform = val.GetComponent<RectTransform>(),
					Text = val2
				});
			}
			return _textSlots[index];
		}

		private Material GetMaterialForRendering(Component component)
		{
			if ((Object)(object)component == (Object)null || _tmpTextType == null)
			{
				return null;
			}
			try
			{
				object? obj = _tmpMaterialForRenderingProperty?.GetValue(component, null);
				return (Material)((obj is Material) ? obj : null);
			}
			catch
			{
				return null;
			}
		}

		private Material CreateCleanFontMaterial(Object font, Component sourceText)
		{
			//IL_0056: Unknown result type (might be due to invalid IL or missing references)
			//IL_005b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0066: Unknown result type (might be due to invalid IL or missing references)
			//IL_006f: Expected O, but got Unknown
			//IL_0122: Unknown result type (might be due to invalid IL or missing references)
			//IL_013f: Unknown result type (might be due to invalid IL or missing references)
			//IL_015c: Unknown result type (might be due to invalid IL or missing references)
			if (font == (Object)null)
			{
				return null;
			}
			Material val = null;
			try
			{
				object? obj = ((object)font).GetType().GetProperty("material", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)?.GetValue(font, null);
				val = (Material)((obj is Material) ? obj : null);
			}
			catch
			{
			}
			if ((Object)(object)val == (Object)null)
			{
				val = GetMaterialForRendering(sourceText);
			}
			if ((Object)(object)val == (Object)null)
			{
				return null;
			}
			try
			{
				Material val2 = new Material(val)
				{
					name = "PeakTTS Daruma Clean",
					hideFlags = (HideFlags)61
				};
				SetMaterialFloat(val2, "_FaceDilate", 0f);
				SetMaterialFloat(val2, "_OutlineWidth", 0f);
				SetMaterialFloat(val2, "_OutlineSoftness", 0f);
				SetMaterialFloat(val2, "_UnderlayOffsetX", 0f);
				SetMaterialFloat(val2, "_UnderlayOffsetY", 0f);
				SetMaterialFloat(val2, "_UnderlayDilate", 0f);
				SetMaterialFloat(val2, "_UnderlaySoftness", 0f);
				SetMaterialFloat(val2, "_GlowInner", 0f);
				SetMaterialFloat(val2, "_GlowOuter", 0f);
				SetMaterialFloat(val2, "_GlowPower", 0f);
				if (val2.HasProperty("_FaceColor"))
				{
					val2.SetColor("_FaceColor", Color.white);
				}
				if (val2.HasProperty("_OutlineColor"))
				{
					val2.SetColor("_OutlineColor", Color.clear);
				}
				if (val2.HasProperty("_UnderlayColor"))
				{
					val2.SetColor("_UnderlayColor", Color.clear);
				}
				val2.DisableKeyword("OUTLINE_ON");
				val2.DisableKeyword("UNDERLAY_ON");
				val2.DisableKeyword("UNDERLAY_INNER");
				val2.DisableKeyword("GLOW_ON");
				val2.DisableKeyword("BEVEL_ON");
				return val2;
			}
			catch (Exception ex)
			{
				ManualLogSource log = _log;
				if (log != null)
				{
					log.LogDebug((object)("Could not create clean Daruma SDF material: " + ex.Message));
				}
				return null;
			}
		}

		private static void SetMaterialFloat(Material material, string property, float value)
		{
			if ((Object)(object)material != (Object)null && material.HasProperty(property))
			{
				material.SetFloat(property, value);
			}
		}

		private void ReleaseNativeMaterial()
		{
			if (_ownsNativeMaterial && (Object)(object)_nativeMaterial != (Object)null)
			{
				Object.Destroy((Object)(object)_nativeMaterial);
			}
			_nativeMaterial = null;
			_ownsNativeMaterial = false;
		}

		private void DestroyCanvas()
		{
			_visualSlots.Clear();
			_textSlots.Clear();
			_visualCursor = 0;
			_textCursor = 0;
			_visualRoot = null;
			_textRoot = null;
			if ((Object)(object)_canvasObject != (Object)null)
			{
				Object.Destroy((Object)(object)_canvasObject);
			}
			_canvasObject = null;
			_canvas = null;
		}

		private static void StretchToParent(RectTransform rectTransform)
		{
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0036: Unknown result type (might be due to invalid IL or missing references)
			//IL_0041: Unknown result type (might be due to invalid IL or missing references)
			//IL_004c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0057: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)rectTransform == (Object)null))
			{
				rectTransform.anchorMin = Vector2.zero;
				rectTransform.anchorMax = Vector2.one;
				rectTransform.pivot = new Vector2(0.5f, 0.5f);
				rectTransform.offsetMin = Vector2.zero;
				rectTransform.offsetMax = Vector2.zero;
				((Transform)rectTransform).localScale = Vector3.one;
				((Transform)rectTransform).localRotation = Quaternion.identity;
			}
		}

		private static void ConfigureRect(RectTransform rectTransform, Rect rect)
		{
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			//IL_003f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0059: Unknown result type (might be due to invalid IL or missing references)
			//IL_0086: Unknown result type (might be due to invalid IL or missing references)
			//IL_0091: Unknown result type (might be due to invalid IL or missing references)
			//IL_009c: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)rectTransform == (Object)null))
			{
				rectTransform.anchorMin = new Vector2(0f, 1f);
				rectTransform.anchorMax = new Vector2(0f, 1f);
				rectTransform.pivot = new Vector2(0f, 1f);
				rectTransform.anchoredPosition = new Vector2(((Rect)(ref rect)).x, 0f - ((Rect)(ref rect)).y);
				rectTransform.sizeDelta = new Vector2(Mathf.Max(1f, ((Rect)(ref rect)).width), Mathf.Max(1f, ((Rect)(ref rect)).height));
				((Transform)rectTransform).localScale = Vector3.one;
				((Transform)rectTransform).localRotation = Quaternion.identity;
			}
		}

		private static object GetValue(PropertyInfo property, object instance)
		{
			if (property == null || instance == null)
			{
				return null;
			}
			try
			{
				return property.GetValue(instance, null);
			}
			catch
			{
				return null;
			}
		}

		private static void SetValue(PropertyInfo property, object instance, object value)
		{
			if (property == null || instance == null || !property.CanWrite)
			{
				return;
			}
			try
			{
				property.SetValue(instance, value, null);
			}
			catch
			{
			}
		}

		private static void SetEnumValue(PropertyInfo property, object instance, string name)
		{
			if (property == null || instance == null || !property.CanWrite || !property.PropertyType.IsEnum)
			{
				return;
			}
			try
			{
				object value = Enum.Parse(property.PropertyType, name, ignoreCase: true);
				property.SetValue(instance, value, null);
			}
			catch
			{
			}
		}

		private static string ToTmpAlignment(TextAnchor anchor)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_002a: Expected I4, but got Unknown
			return (int)anchor switch
			{
				0 => "TopLeft", 
				1 => "Top", 
				2 => "TopRight", 
				3 => "MidlineLeft", 
				4 => "Midline", 
				5 => "MidlineRight", 
				6 => "BottomLeft", 
				7 => "Bottom", 
				8 => "BottomRight", 
				_ => "MidlineLeft", 
			};
		}
	}
	internal static class PhotonVoiceBridge
	{
		private static readonly object Sync = new object();

		private static object _primaryVoice;

		private static int _sampleRate;

		private static int _channels;

		private static int _frameSize;

		private static int _frameDurationUs;

		private static Type _sampleType;

		private static MethodInfo _pushDataAsync;

		private static PropertyInfo _pushDataAsyncReady;

		private static object _syntheticTransmitVoice;

		private static PropertyInfo _syntheticTransmitProperty;

		private static bool _syntheticTransmitChanged;

		private static long _lastRealPush;

		private static long _queueSeenAt;

		private static double _nextSyntheticFrameAt;

		private static bool _loggedSyntheticPump;

		private static bool _loggedEffectiveRate;

		private static long _retryPumpAt;

		[ThreadStatic]
		private static bool _insideSyntheticPush;

		public static void RefreshPrimaryVoice()
		{
			object obj = null;
			int num = 0;
			int num2 = 0;
			int num3 = 0;
			int num4 = 0;
			MethodInfo pushDataAsync = null;
			PropertyInfo pushDataAsyncReady = null;
			Type type = null;
			try
			{
				object obj2 = FindExistingRecorder();
				obj = ((obj2 == null) ? null : AccessTools.Field(obj2.GetType(), "voice")?.GetValue(obj2));
				object obj3 = ((obj == null) ? null : AccessTools.Property(obj.GetType(), "Info")?.GetValue(obj, null));
				if (obj3 != null)
				{
					num = ReadIntProperty(obj3, "SamplingRate");
					num2 = ReadIntProperty(obj3, "Channels");
					num3 = ReadIntProperty(obj3, "FrameSize");
					num4 = ReadIntProperty(obj3, "FrameDurationUs");
					if (num4 <= 0)
					{
						num4 = CalculateFrameDurationUs(num, num2, num3);
					}
				}
				if (obj != null)
				{
					type = FindSampleType(obj.GetType());
					if (type == typeof(float) || type == typeof(short))
					{
						pushDataAsync = obj.GetType().GetMethod("PushDataAsync", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, new Type[1] { type.MakeArrayType() }, null);
						pushDataAsyncReady = AccessTools.Property(obj.GetType(), "PushDataAsyncReady");
					}
				}
			}
			catch (Exception ex)
			{
				ManualLogSource logSource = Plugin.LogSource;
				if (logSource != null)
				{
					logSource.LogDebug((object)("Primary voice refresh failed: " + ex.Message));
				}
			}
			bool flag = obj != null && num > 0 && num2 > 0 && num3 >= num2 && num3 % num2 == 0 && num4 > 0;
			bool flag2 = false;
			lock (Sync)
			{
				if (!flag)
				{
					return;
				}
				flag2 = _primaryVoice != obj || _sampleRate != num || _channels != num2 || _frameSize != num3 || _frameDurationUs != num4;
				bool num5 = _primaryVoice != obj;
				_primaryVoice = obj;
				_sampleRate = num;
				_channels = num2;
				_frameSize = num3;
				_frameDurationUs = num4;
				_sampleType = type;
				_pushDataAsync = pushDataAsync;
				_pushDataAsyncReady = pushDataAsyncReady;
				if (num5)
				{
					_lastRealPush = 0L;
					_queueSeenAt = 0L;
					_nextSyntheticFrameAt = 0.0;
					_loggedSyntheticPump = false;
					_loggedEffectiveRate = false;
					_retryPumpAt = 0L;
				}
			}
			if (flag2)
			{
				ManualLogSource logSource2 = Plugin.LogSource;
				if (logSource2 != null)
				{
					logSource2.LogInfo((object)($"Primary encoder format: {num} Hz, " + $"{num2} channels, {num3} values per frame, " + $"{(double)num4 / 1000.0:0.###} ms"));
				}
			}
		}

		public static void ObservePush(object voice)
		{
			if (_insideSyntheticPush)
			{
				return;
			}
			StopSyntheticTransmit();
			bool flag = false;
			lock (Sync)
			{
				if (_primaryVoice == voice)
				{
					_lastRealPush = Stopwatch.GetTimestamp();
					_nextSyntheticFrameAt = 0.0;
					flag = true;
				}
			}
			if (flag)
			{
				return;
			}
			RefreshFromObservedVoice(voice);
			lock (Sync)
			{
				if (_primaryVoice == voice)
				{
					_lastRealPush = Stopwatch.GetTimestamp();
					_nextSyntheticFrameAt = 0.0;
				}
			}
		}

		public static void ServiceQueuedSpeech()
		{
			if (!TtsMixer.HasAudio || !PhotonVoicePatches.IsInstalled)
			{
				StopSyntheticTransmit();
				lock (Sync)
				{
					_queueSeenAt = 0L;
					_nextSyntheticFrameAt = 0.0;
					_loggedSyntheticPump = false;
					return;
				}
			}
			long timestamp = Stopwatch.GetTimestamp();
			long num = Stopwatch.Frequency / 10;
			object primaryVoice;
			MethodInfo pushDataAsync;
			PropertyInfo pushDataAsyncReady;
			Type sampleType;
			int sampleRate;
			int channels;
			int frameSize;
			int frameDurationUs;
			lock (Sync)
			{
				if (_primaryVoice == null || _pushDataAsync == null || _sampleType == null)
				{
					return;
				}
				if (_queueSeenAt == 0L)
				{
					_queueSeenAt = timestamp;
				}
				if (timestamp - _queueSeenAt < num || (_lastRealPush != 0L && timestamp - _lastRealPush < num))
				{
					_nextSyntheticFrameAt = 0.0;
					return;
				}
				if (timestamp < _retryPumpAt)
				{
					return;
				}
				primaryVoice = _primaryVoice;
				pushDataAsync = _pushDataAsync;
				pushDataAsyncReady = _pushDataAsyncReady;
				sampleType = _sampleType;
				sampleRate = _sampleRate;
				channels = _channels;
				frameSize = _frameSize;
				frameDurationUs = _frameDurationUs;
			}
			if (primaryVoice == null || sampleRate <= 0 || channels <= 0 || frameSize <= 0)
			{
				return;
			}
			double num2 = (double)Stopwatch.Frequency * ((double)frameDurationUs / 1000000.0);
			if (num2 < 1.0)
			{
				num2 = (double)Stopwatch.Frequency * ((double)frameSize / (double)(sampleRate * channels));
			}
			if (num2 < 1.0)
			{
				return;
			}
			lock (Sync)
			{
				if (_nextSyntheticFrameAt <= 0.0)
				{
					_nextSyntheticFrameAt = timestamp;
				}
				if ((double)timestamp < _nextSyntheticFrameAt)
				{
					return;
				}
			}
			try
			{
				_insideSyntheticPush = true;
				if (pushDataAsyncReady != null && !Convert.ToBoolean(pushDataAsyncReady.GetValue(primaryVoice, null)))
				{
					return;
				}
				EnableSyntheticTransmit(primaryVoice);
				int num3 = 0;
				while (num3 < 2 && TtsMixer.HasAudio)
				{
					lock (Sync)
					{
						timestamp = Stopwatch.GetTimestamp();
						if (_primaryVoice != primaryVoice || (double)timestamp < _nextSyntheticFrameAt)
						{
							break;
						}
						goto IL_0238;
					}
					IL_0238:
					Array array = Array.CreateInstance(sampleType, frameSize);
					pushDataAsync.Invoke(primaryVoice, new object[1] { array });
					num3++;
					lock (Sync)
					{
						_nextSyntheticFrameAt += num2;
					}
				}
				if (num3 <= 0)
				{
					return;
				}
				lock (Sync)
				{
					timestamp = Stopwatch.GetTimestamp();
					if (_nextSyntheticFrameAt < (double)timestamp - num2)
					{
						_nextSyntheticFrameAt = (double)timestamp + num2;
					}
					_retryPumpAt = 0L;
					if (!_loggedSyntheticPump)
					{
						_loggedSyntheticPump = true;
						ManualLogSource logSource = Plugin.LogSource;
						if (logSource != null)
						{
							logSource.LogInfo((object)"Started recorder fallback because no microphone frames were arriving");
						}
					}
				}
			}
			catch (Exception ex)
			{
				lock (Sync)
				{
					_retryPumpAt = Stopwatch.GetTimestamp() + Stopwatch.Frequency * 2;
				}
				Exception arg = ((ex is TargetInvocationException && ex.InnerException != null) ? ex.InnerException : ex);
				ManualLogSource logSource2 = Plugin.LogSource;
				if (logSource2 != null)
				{
					logSource2.LogError((object)$"Recorder fallback failed: {arg}");
				}
			}
			finally
			{
				_insideSyntheticPush = false;
			}
		}

		private static void RefreshFromObservedVoice(object voice)
		{
			if (voice == null)
			{
				return;
			}
			try
			{
				object obj = AccessTools.Property(voice.GetType(), "Info")?.GetValue(voice, null);
				if (obj == null)
				{
					return;
				}
				int num = ReadIntProperty(obj, "SamplingRate");
				int num2 = ReadIntProperty(obj, "Channels");
				int num3 = ReadIntProperty(obj, "FrameSize");
				int num4 = ReadIntProperty(obj, "FrameDurationUs");
				if (num4 <= 0)
				{
					num4 = CalculateFrameDurationUs(num, num2, num3);
				}
				Type type = FindSampleType(voice.GetType());
				if ((type != typeof(float) && type != typeof(short)) || num <= 0 || num2 <= 0 || num3 < num2 || num3 % num2 != 0 || num4 <= 0)
				{
					return;
				}
				MethodInfo method = voice.GetType().GetMethod("PushDataAsync", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, new Type[1] { type.MakeArrayType() }, null);
				if (method == null)
				{
					return;
				}
				bool flag = false;
				lock (Sync)
				{
					flag = _primaryVoice != voice || _sampleRate != num || _channels != num2 || _frameSize != num3 || _frameDurationUs != num4;
					_primaryVoice = voice;
					_sampleRate = num;
					_channels = num2;
					_frameSize = num3;
					_frameDurationUs = num4;
					_sampleType = type;
					_pushDataAsync = method;
					_pushDataAsyncReady = AccessTools.Property(voice.GetType(), "PushDataAsyncReady");
					if (flag)
					{
						_queueSeenAt = 0L;
						_nextSyntheticFrameAt = 0.0;
						_loggedSyntheticPump = false;
						_loggedEffectiveRate = false;
						_retryPumpAt = 0L;
					}
				}
				if (flag)
				{
					ManualLogSource logSource = Plugin.LogSource;
					if (logSource != null)
					{
						logSource.LogInfo((object)($"Captured active Photon voice: {num} Hz, " + $"{num2} channel(s), {num3} values per frame, " + $"{(double)num4 / 1000.0:0.###} ms"));
					}
				}
			}
			catch (Exception ex)
			{
				ManualLogSource logSource2 = Plugin.LogSource;
				if (logSource2 != null)
				{
					logSource2.LogDebug((object)("Observed Photon voice capture failed: " + ex.Message));
				}
			}
		}

		private static object FindExistingRecorder()
		{
			Type type = AccessTools.TypeByName("VoiceClientHandler");
			if (type == null)
			{
				return null;
			}
			object obj = AccessTools.Field(type, "m_LocalRecorder")?.GetValue(null);
			if (obj != null)
			{
				return obj;
			}
			object obj2 = AccessTools.Field(type, "m_VoiceConnection")?.GetValue(null);
			if (obj2 != null)
			{
				return AccessTools.Property(obj2.GetType(), "PrimaryRecorder")?.GetValue(obj2, null);
			}
			return null;
		}

		private static void EnableSyntheticTransmit(object voice)
		{
			if (voice == null)
			{
				return;
			}
			lock (Sync)
			{
				if (_syntheticTransmitVoice == voice)
				{
					return;
				}
			}
			StopSyntheticTransmit();
			try
			{
				PropertyInfo propertyInfo = AccessTools.Property(voice.GetType(), "TransmitEnabled");
				if (propertyInfo == null || !propertyInfo.CanRead || !propertyInfo.CanWrite)
				{
					return;
				}
				bool flag = !Convert.ToBoolean(propertyInfo.GetValue(voice, null));
				if (flag)
				{
					propertyInfo.SetValue(voice, true, null);
				}
				lock (Sync)
				{
					_syntheticTransmitVoice = voice;
					_syntheticTransmitProperty = propertyInfo;
					_syntheticTransmitChanged = flag;
				}
			}
			catch (Exception ex)
			{
				ManualLogSource logSource = Plugin.LogSource;
				if (logSource != null)
				{
					logSource.LogDebug((object)("Transmit override failed: " + ex.Message));
				}
			}
		}

		private static void StopSyntheticTransmit()
		{
			object syntheticTransmitVoice;
			PropertyInfo syntheticTransmitProperty;
			bool syntheticTransmitChanged;
			lock (Sync)
			{
				syntheticTransmitVoice = _syntheticTransmitVoice;
				syntheticTransmitProperty = _syntheticTransmitProperty;
				syntheticTransmitChanged = _syntheticTransmitChanged;
				_syntheticTransmitVoice = null;
				_syntheticTransmitProperty = null;
				_syntheticTransmitChanged = false;
			}
			if (!syntheticTransmitChanged || syntheticTransmitVoice == null || syntheticTransmitProperty == null)
			{
				return;
			}
			try
			{
				if (Convert.ToBoolean(syntheticTransmitProperty.GetValue(syntheticTransmitVoice, null)))
				{
					syntheticTransmitProperty.SetValue(syntheticTransmitVoice, false, null);
				}
			}
			catch
			{
			}
		}

		private static Type FindSampleType(Type type)
		{
			while (type != null)
			{
				if (type.IsGenericType)
				{
					Type genericTypeDefinition = type.GetGenericTypeDefinition();
					if (genericTypeDefinition.Namespace == "Photon.Voice" && genericTypeDefinition.Name.StartsWith("LocalVoiceFramed", StringComparison.Ordinal) && genericTypeDefinition.GetGenericArguments().Length == 1)
					{
						return type.GetGenericArguments()[0];
					}
				}
				type = type.BaseType;
			}
			return null;
		}

		public static bool IsPrimaryVoice(object voice)
		{
			lock (Sync)
			{
				return _primaryVoice != null && _primaryVoice == voice;
			}
		}

		public static bool TryGetFormat(object voice, int bufferLength, out int sampleRate, out int channels, out int frameSize)
		{
			bool flag = false;
			int num = 0;
			int num2 = 0;
			bool flag2 = false;
			lock (Sync)
			{
				num = (sampleRate = _sampleRate);
				channels = _channels;
				frameSize = _frameSize;
				num2 = _frameDurationUs;
				flag2 = _primaryVoice != null && _primaryVoice == voice;
				if (flag2 && bufferLength > 0 && channels > 0 && num2 > 0)
				{
					int num3 = SnapToVoiceRate((int)Math.Round((double)bufferLength * 1000000.0 / ((double)channels * (double)num2)));
					if (num3 > 0)
					{
						sampleRate = num3;
					}
					if (!_loggedEffectiveRate && sampleRate != num)
					{
						_loggedEffectiveRate = true;
						flag = true;
					}
				}
			}
			if (flag)
			{
				ManualLogSource logSource = Plugin.LogSource;
				if (logSource != null)
				{
					logSource.LogInfo((object)("Outgoing PCM rate corrected: " + $"{bufferLength} values over {(double)num2 / 1000.0:0.###} ms to " + $"{sampleRate} Hz (VoiceInfo {num} Hz)"));
				}
			}
			return flag2;
		}

		private static int CalculateFrameDurationUs(int sampleRate, int channels, int frameSize)
		{
			if (sampleRate <= 0 || channels <= 0 || frameSize <= 0)
			{
				return 0;
			}
			return (int)Math.Round((double)frameSize * 1000000.0 / ((double)sampleRate * (double)channels));
		}

		private static int SnapToVoiceRate(int value)
		{
			int[] obj = new int[5] { 8000, 12000, 16000, 24000, 48000 };
			int num = 0;
			int num2 = int.MaxValue;
			int[] array = obj;
			foreach (int num3 in array)
			{
				int num4 = Math.Abs(value - num3);
				if (num4 < num2)
				{
					num = num3;
					num2 = num4;
				}
			}
			if (num2 <= Math.Max(500, num / 20))
			{
				return num;
			}
			if (value < 4000 || value > 96000)
			{
				return 0;
			}
			return value;
		}

		private static int ReadIntProperty(object value, string name)
		{
			PropertyInfo propertyInfo = AccessTools.Property(value.GetType(), name);
			if (!(propertyInfo == null))
			{
				return Convert.ToInt32(propertyInfo.GetValue(value, null));
			}
			return 0;
		}
	}
	internal static class PhotonVoicePatches
	{
		private struct TransmitPatchState
		{
			public bool Changed;

			public PropertyInfo Property;

			public bool PushScopeEntered;
		}

		private static int _loggedFormatMismatch;

		private static int _loggedDuplicateProcessingPass;

		private static readonly object InstallSync = new object();

		private static readonly HashSet<Type> PatchedSampleTypes = new HashSet<Type>();

		private static bool _loggedWaitingForPhoton;

		[ThreadStatic]
		private static object _activePushVoice;

		[ThreadStatic]
		private static int _activePushDepth;

		[ThreadStatic]
		private static bool _mixedInActivePush;

		public static bool IsInstalled
		{
			get
			{
				lock (InstallSync)
				{
					return PatchedSampleTypes.Count == 2;
				}
			}
		}

		public static int Install(Harmony harmony, ManualLogSource log)
		{
			lock (InstallSync)
			{
				Type type = FindOpenVoiceType();
				if (type == null)
				{
					if (!_loggedWaitingForPhoton)
					{
						_loggedWaitingForPhoton = true;
						log.LogInfo((object)"Photon Voice is not loaded yet; will retry");
					}
					return 0;
				}
				return PatchSampleType(harmony, type, typeof(float), log) + PatchSampleType(harmony, type, typeof(short), log);
			}
		}

		private static Type FindOpenVoiceType()
		{
			string name = "Photon.Voice.LocalVoiceFramed" + '`' + "1";
			Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies();
			foreach (Assembly assembly in assemblies)
			{
				try
				{
					Type type = assembly.GetType(name, throwOnError: false);
					if (type != null && type.IsGenericTypeDefinition && type.GetGenericArguments().Length == 1)
					{
						return type;
					}
				}
				catch
				{
				}
			}
			return null;
		}

		private static int PatchSampleType(Harmony harmony, Type openType, Type sampleType, ManualLogSource log)
		{
			//IL_0147: Unknown result type (might be due to invalid IL or missing references)
			//IL_0158: Unknown result type (might be due to invalid IL or missing references)
			//IL_0163: Expected O, but got Unknown
			//IL_0163: Expected O, but got Unknown
			//IL_018a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0197: Expected O, but got Unknown
			if (PatchedSampleTypes.Contains(sampleType))
			{
				return 0;
			}
			try
			{
				Type type = openType.MakeGenericType(sampleType);
				BindingFlags bindingAttr = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic;
				MethodInfo method = type.GetMethod("PushData", bindingAttr, null, new Type[1] { sampleType.MakeArrayType() }, null);
				MethodInfo methodInfo = null;
				MethodInfo[] methods = type.GetMethods(bindingAttr);
				foreach (MethodInfo methodInfo2 in methods)
				{
					if (!(methodInfo2.Name != "processFrame") && !(methodInfo2.ReturnType != sampleType.MakeArrayType()))
					{
						ParameterInfo[] parameters = methodInfo2.GetParameters();
						if ((parameters.Length == 1 || (parameters.Length == 3 && parameters[1].ParameterType == typeof(int) && parameters[2].ParameterType == typeof(int))) && parameters[0].ParameterType == sampleType.MakeArrayType() && (methodInfo == null || parameters.Length == 3))
						{
							methodInfo = methodInfo2;
						}
					}
				}
				if (method == null || methodInfo == null)
				{
					log.LogWarning((object)("No compatible PushData/processFrame method found on " + type.FullName));
					return 0;
				}
				harmony.Patch((MethodBase)method, new HarmonyMethod(PatchMethod("PushPrefix")), (HarmonyMethod)null, (HarmonyMethod)null, new HarmonyMethod(PatchMethod("PushFinalizer")), (HarmonyMethod)null);
				harmony.Patch((MethodBase)methodInfo, (HarmonyMethod)null, new HarmonyMethod(PatchMethod((sampleType == typeof(float)) ? "ProcessFramePostfixFloat" : "ProcessFramePostfixShort")), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
				log.LogInfo((object)("Patched " + type.FullName + ": TTS after final PCM processing"));
				PatchedSampleTypes.Add(sampleType);
				return 1;
			}
			catch (Exception arg)
			{
				log.LogError((object)$"Could not install safe Photon TTS hook for {sampleType.Name}: {arg}");
				return 0;
			}
		}

		private static MethodInfo PatchMethod(string name)
		{
			return typeof(PhotonVoicePatches).GetMethod(name, BindingFlags.Static | BindingFlags.NonPublic);
		}

		private static void PushPrefix(object __instance, ref TransmitPatchState __state)
		{
			__state = default(TransmitPatchState);
			EnterPushScope(__instance);
			__state.PushScopeEntered = true;
			PhotonVoiceBridge.ObservePush(__instance);
			if (!TtsMixer.HasAudio || !PhotonVoiceBridge.IsPrimaryVoice(__instance))
			{
				return;
			}
			try
			{
				PropertyInfo propertyInfo = AccessTools.Property(__instance.GetType(), "TransmitEnabled");
				if (!(propertyInfo == null) && propertyInfo.CanRead && propertyInfo.CanWrite && !Convert.ToBoolean(propertyInfo.GetValue(__instance, null)))
				{
					__state.Property = propertyInfo;
					__state.Changed = true;
					propertyInfo.SetValue(__instance, true, null);
				}
			}
			catch (Exception ex)
			{
				ManualLogSource logSource = Plugin.LogSource;
				if (logSource != null)
				{
					logSource.LogDebug((object)("Transmit override failed: " + ex.Message));
				}
			}
		}

		private static void PushFinalizer(object __instance, TransmitPatchState __state)
		{
			try
			{
				if (__state.Changed)
				{
					__state.Property.SetValue(__instance, false, null);
				}
			}
			catch
			{
			}
			finally
			{
				if (__state.PushScopeEntered)
				{
					ExitPushScope();
				}
			}
		}

		private static void ProcessFramePostfixFloat(object __instance, ref float[] __result)
		{
			if (TryGetEncoderFormat(__instance, __result, out var rate, out var channels, out var size))
			{
				if (__result == null)
				{
					__result = new float[size];
				}
				TtsMixer.Mix(__result, rate, channels);
			}
		}

		private static void ProcessFramePostfixShort(object __instance, ref short[] __result)
		{
			if (TryGetEncoderFormat(__instance, __result, out var rate, out var channels, out var size))
			{
				if (__result == null)
				{
					__result = new short[size];
				}
				TtsMixer.Mix(__result, rate, channels);
			}
		}

		private static bool TryGetEncoderFormat(object voice, Array frame, out int rate, out int channels, out int size)
		{
			rate = (channels = (size = 0));
			int bufferLength = frame?.Length ?? 0;
			if (!TtsMixer.HasAudio || !PhotonVoiceBridge.TryGetFormat(voice, bufferLength, out rate, out channels, out size))
			{
				return false;
			}
			if (frame == null || frame.Length == size)
			{
				return TryClaimMixForCurrentPush(voice);
			}
			if (Interlocked.Exchange(ref _loggedFormatMismatch, 1) == 0)
			{
				ManualLogSource logSource = Plugin.LogSource;
				if (logSource != null)
				{
					logSource.LogWarning((object)("Skipped an unexpected final Photon frame: " + $"{frame.Length} values; encoder expects {size} at {rate} Hz / {channels} channels"));
				}
			}
			return false;
		}

		private static void EnterPushScope(object voice)
		{
			if (_activePushDepth == 0)
			{
				_activePushVoice = voice;
				_mixedInActivePush = false;
			}
			_activePushDepth++;
		}

		private static void ExitPushScope()
		{
			if (_activePushDepth > 0)
			{
				_activePushDepth--;
			}
			if (_activePushDepth == 0)
			{
				_activePushVoice = null;
				_mixedInActivePush = false;
			}
		}

		private static bool TryClaimMixForCurrentPush(object voice)
		{
			if (_activePushDepth <= 0 || _activePushVoice != voice)
			{
				return true;
			}
			if (!_mixedInActivePush)
			{
				_mixedInActivePush = true;
				return true;
			}
			if (Interlocked.Exchange(ref _loggedDuplicateProcessingPass, 1) == 0)
			{
				ManualLogSource logSource = Plugin.LogSource;
				if (logSource != null)
				{
					logSource.LogInfo((object)"Suppressed duplicated Photon processing pass for outgoing frame");
				}
			}
			return false;
		}
	}
	[BepInPlugin("ahun.PeakTTS", "PeakTTS", "1.2.1")]
	public sealed class Plugin : BaseUnityPlugin
	{
		private sealed class SpeechDisplayInfo
		{
			public string Text;

			public string Voice;

			public string Language;
		}

		private enum PeakIconKind
		{
			Refresh,
			Gear
		}

		public const string PluginGuid = "ahun.PeakTTS";

		public const string PluginName = "PeakTTS";

		public const string PluginVersion = "1.2.1";

		internal static ManualLogSource LogSource;

		internal static Plugin Instance;

		private ConfigEntry<KeyCode> _openKey;

		private ConfigEntry<float> _ttsGain;

		private ConfigEntry<float> _transmitGain;

		private ConfigEntry<bool> _monitorPlayback;

		private ConfigEntry<float> _monitorVolume;

		private ConfigEntry<int> _speechRate;

		private ConfigEntry<string> _voiceName;

		private ConfigEntry<string> _languageMode;

		private ConfigEntry<int> _maxCharacters;

		private ConfigEntry<string> _powershellPath;

		private ConfigEntry<string> _modelsFolder;

		private ConfigEntry<string> _piperPath;

		private ConfigEntry<int> _piperSpeakerId;

		private ConfigEntry<string> _coquiTtsPath;

		private ConfigEntry<string> _coquiSpeaker;

		private ConfigEntry<string> _coquiLanguage;

		private ConfigEntry<string> _coquiSpeakerWav;

		private Harmony _harmony;

		private bool _inputOpen;

		private string _text = string.Empty;

		private bool _focusNextFrame;

		private volatile string _status = "Ready";

		private int _pendingJobs;

		private float _nextVoiceRefreshAt;

		private float _nextPhotonPatchRetryAt;

		private bool _photonPatchesInstalled;

		private int _keyboardHandledFrame = -1;

		private int _catalogRefreshRunning;

		private float _nextCatalogRefreshAt;

		private bool _sapi4HelperPresent;

		private bool _sapi4Ready;

		private bool _sapi4SetupLaunched;

		private ConfigEntry<string> _sapi4HelperPageUrl;

		private readonly object _monitorSync = new object();

		private readonly Queue<SpeechClip> _monitorQueue = new Queue<SpeechClip>();

		private AudioSource _monitorSource;

		private AudioClip _monitorClip;

		private volatile bool _monitorPlaying;

		private volatile bool _monitorEnabled;

		private GUIStyle _boxStyle;

		private GUIStyle _labelStyle;

		private GUIStyle _voiceStyle;

		private GUIStyle _titleStyle;

		private GUIStyle _smallStyle;

		private GUIStyle _buttonStyle;

		private GUIStyle _textAreaStyle;

		private GUIStyle _speechTextStyle;

		private GUIStyle _speechVoiceStyle;

		private Font _contentFont;

		private Texture2D _refreshIconTexture;

		private Texture2D _gearIconTexture;

		private PeakNativeUiRenderer _peakUi;

		private float _styleScale;

		private readonly object _speechUiSync = new object();

		private readonly Dictionary<SpeechClip, SpeechDisplayInfo> _speechDisplayByClip = new Dictionary<SpeechClip, SpeechDisplayInfo>();

		private SpeechDisplayInfo _activeSpeechDisplay;

		private volatile bool _speechTransmissionFinished = true;

		private int _speechBannerRevision;

		private int _observedSpeechBannerRevision;

		private float _speechBannerShownAt;

		private float _speechBannerFadeOutAt = -1f;

		private static readonly Color UiInk = Color32.op_Implicit(new Color32((byte)48, (byte)42, (byte)32, byte.MaxValue));

		private static readonly Color UiPaper = Color32.op_Implicit(new Color32((byte)238, (byte)231, (byte)199, byte.MaxValue));

		private static readonly Color UiPaperLight = Color32.op_Implicit(new Color32((byte)248, (byte)242, (byte)214, byte.MaxValue));

		private static readonly Color UiShadow = Color32.op_Implicit(new Color32((byte)21, (byte)18, (byte)15, (byte)150));

		private static readonly Color UiYellow = Color32.op_Implicit(new Color32((byte)232, (byte)191, (byte)48, byte.MaxValue));

		private static readonly Color UiGreen = Color32.op_Implicit(new Color32((byte)67, (byte)137, (byte)75, byte.MaxValue));

		private static readonly Color UiBlue = Color32.op_Implicit(new Color32((byte)77, (byte)134, (byte)162, byte.MaxValue));

		private static readonly Color UiRed = Color32.op_Implicit(new Color32((byte)171, (byte)75, (byte)63, byte.MaxValue));

		private static readonly Color UiMuted = Color32.op_Implicit(new Color32((byte)104, (byte)92, (byte)72, byte.MaxValue));

		private const string RefreshIconAlpha64 = "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAEcIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABARHwRgADAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAwB8/7oAAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQET6/z+QAADAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEBAwMDAwIBAAAAAAAAAAMAgP/4/78AAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACBAMAAAAAAAAAAAIEAwAAAAEBFuz+/v3/QgEDAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMCAAAACRQ+QUFBHQ8AAAABAwEEAHP/+//8/7UAAwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgEAAChwreHw//////XrvH85AAAABAbW/v3//v72JwECAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAwAARbH4//////39/f3//////8ViCABg//z////8/6EAAwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAmtv////v8/f7//////v78+/7//9VN0/79/////v34JwECAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAwBk8P/9/P7//////////////////fz////////////8/6EAAwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAwCY///8/////////vz8/Pz+/////////f3//////////vr0IgACAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAgCa//v+//////77/f////////77/v///////////////////7QCAwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAwCa//r///////z////wyr6+wev////8/v////////////7/n396BwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAwBw//r//////v7/8qJOFQAAAAAPOovj///9///////////9/jIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAx/Pv+/////f//nSAAAAABAgICAAAADnzy//z///z9/////P9IBAcAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQIHzv/8/////f/tVgAAAwMBAAAAAAEDBAAAMs7//P3///39/P/+KAACAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMAX//8/////v7sNQAFAgAAAAAAAAAAAAABBQARyf//vN/////5ZQACAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABBNb+/f////z9RAAGAAAAAAAAAAAAAAAAAAAEABPedQAVQUBCJwABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADAEL+/f////z/hQAFAAAAAAAAAAAAAAAAAAAAAAEABwABAAAAAAACAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAwCh//v///3+4A4CAQAAAAAAAAAAAAAAAAAAAAAAAQACAAEDAwMCAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEF2P/9///7/38ABAAAAAAAAAAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAK/n+/////vglAQIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADAEH//f///f/OAgEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABABv//z///v/nQADAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAg//7///7/3wABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEAH7/+///+/+CAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABACF//v///v/fgAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMAYP/8///8/6sAAwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADAD7//f///f/ZBgEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAf9P7+///9/TYBAwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAsz//f//+/+aAAQAAAAAAAAAAAAAAAAAAAAAAAAAAgEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABACN//v///797yEBAgAAAAAAAAAAAAAAAAAAAAAAAgAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAK/v+/////P+tAAUBAAAAAAAAAAAAAAAAAAAAAgAxAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgC+/vz////8/3AABQEAAAAAAAAAAAAAAAAABQA2/6wZAAQBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMAQf/8/////vv/ZQABAwEAAAAAAAAAAAADAwA27f3/5VYAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAwCq//z////+/f+PBgAABAMCAQEBAwQBAABk8f/9+///kg8AAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIBFuj+/f////79/9NSBwAAAAAAAAAAADm2///9///+/P/YFwEBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAwBF//z+//////z//9iLRh4RERQ/dMb///3+//////r/hwMDAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADAGX//P3//////f3////27+7w/////vz///////r/mgABAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMAZf///P///////fv8//////37/P///////fz/mgACAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABABi8v/7/v////////7+/v7////////++///jwACAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEADLI///7/f////////////////77///lVgACAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMABX3o///++/z8/v7+/vz8+/3///meGgAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAF3TR////////////////44ssAAADAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAwAAAzVvrcDr7u7uyrmAQg0AAAMBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABBAAAAAAADxEQEAAAAAAABAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAwQDAgAAAAABAwQDAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAQEBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==";

		private const string GearIconAlpha64 = "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEEAwEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAQAAAAAAAAAAAAAAAAAAAAAAAwMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADAAABAAAAAAAAAAAAAAIBJ4o4AwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAICAAoNAAEAAAAAAAAAAAADAKH//9WfTgUBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEAAEjbyAECAQAAAAAAAAADAD78+f7///oSAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEAN7r///+aAAQBAAAAAAAAAwPB//z//PvtEgABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMBX/v//f37/48ABAAAAAAAAwBe//z///3/ygQBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADAEn/+v///vv/ZQAEAAAAAQIP3P79///8/7sAAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAR7P/+///+/f9EAAQAAQUAgP/7/////P+/AAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAb7//P////397DYABAAAI/D8/v////z/vQACAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAB///v//////f/pFwAUEKT//P/////8/8EAAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMARv/9///////9/9297e///v//////+/+QAAMAAAAAAAAAAQIDAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAB30//7///////7///////////////v/ewMFAAAAAQMEAwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAECzP/9/////////fz+/v/////////7/4cABQMEAgAAAAADKk4BAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEAJH/+/////////////////////////3zcAAAAAAKNXCu1fr/QAADAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABABL//z///////////////////////////+oSYG64v/////9/cEDAwAAAAAAAAAAAAAAAAAAAAICAgIDBAQEBQYApv/8//////////////////////////79///////++/z9//z/XAADAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAcP/8//////////////////////////////z8+/z9///////9/OIPAQEAAAAAAAAAAAAAAwBWw7u+vrmEgICAh/z+/v/////////////+/v7/////////////////////////+v/GEwEBAAAAAAAAAAAAAAMBt////////////////////////////vv+/////P3////////////////////+/P+aAwABAAAAAAAAAAAAAAEAEO78+/z8/Pv7+/v7/v///////////P///+7v/P///P/////////////////9/f+AAAABAAAAAAAAAAAAAAADAEv7/P///////////////////////f/pfzYSEipl0//+///////////////9//9lAAMBAAAAAAAAAAAAAAAAAwCe//v9/////////////////////f+4GgAAAAAAAAaP/vz////////////+/+5HAAQAAAAAAAAAAAAAAAAAAAEBIZ7///z+/////////////////P+7AAAEAgEBAgQCAID//P/////////+/tk1AAQAAAAAAAAAAAAAAAAAAAAAAAAAQ8j///v//////////////v7sFwEDAAAAAAAAAQUBwf/8///////+/vIaAAQAAAAAAAAAAAAAAAAAAAAAAAABBAAFben//v3///////////z/fwAEAAAAAAAAAAADAED9/f///////v/uEgIBAAAAAAAAAAAAAAAAAAAAAAAAAAADAAAanv/////////////++y8BAwAAAAAAAAAAAQEI4f/9///////9/kECAwAAAAAAAAAAAAAAAAAAAAAAAAAAAAEDAABDx/3+///////+/+4RAAEAAAAAAAAAAAACAb3//P///////f84AAYBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEEABDv/v7//////v/tDwABAAAAAAAAAAAAAgC7//z///////7+uisAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQMT8f/+///////+9iQBAgAAAAAAAAAAAAEF1f/9/////////v/5gxYAAQIAAAAAAAAAAAAAAAAAAAAAAAAAAAAEAcb//P///////P9kAAQAAAAAAAAAAAIBKfr+///////////8///lYgAAAwEAAAAAAAAAAAAAAAAAAAAAAAAEABLY/v3///////3/1wMEAQAAAAAAAAAGAKH//P////////////77//+8NwAAAAAAAAAAAAAAAAAAAAAAAAAEADXa//7//////////P+PAAMDAQAAAQIGAFT9/P////////////////77//ueIQEBAAAAAAAAAAAAAAAAAAAEAEfu//3////////////9/4AAAAACAgAAAFfu/v7///////////////////z8/54AAwAAAAAAAAAAAAAAAAEDAGX///3///////////////7/vEULAAAELZ3///7//////////////////////PtLAAMAAAAAAAAAAAAAAAEAAID//f3//////////////////P//4r6+1v3//v7///////////z7+/v7/Pz8+/zuEAABAAAAAAAAAAAAAAEAA5r//P7////////////////////8/v///////P////////////3/////////////twEDAAAAAAAAAAAAAAEBE8b/+v/////////////////////////9/Pz9/v////////////z/nn+BgIS5vr67w1YAAwAAAAAAAAAAAAABAQ/i/P3///////38+/z8//////////////////////////////z/rAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMAXP/8//38+/7///////z///////////////////////////3+xBEDBgQEBAMCAgICAAAAAAAAAAAAAAAAAAAAAwPB/f3/////4rqBSaj////////////////////////////8/0sABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMAQP/61a5wNQoAAAAAgPr+////////////////////////+/+RAQQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFOKgMAAAAAAgQDBACT//v////////////+/v////////3/zAIBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAwQDAQAAAAUDef/7/////////v39///+///////+//QdAAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMCAQAAAAAAAAADAJH/+/////////////T0//7///////3/RgADAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgDB//z//////v7uSUIcI+n//f/////7/38ABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAvf/8//////z/awAAAAA27P39/////P++AQIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAL///P////z/wgAFAwEEAET//f7///7/7BEAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgC7//z///78+TIAAgAAAAQAZf/7/v//+v9JAAMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEEyv/9///8/4UABAAAAAAABACP//v9/f/7XwEDAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEAEu37/P/9/t0OAwEAAAAAAAEEAJr///+6NwABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABABL6///++P9UAAMAAAAAAAAAAQIByNtIAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEFTp/V//+rAAQAAAAAAAAAAAABAA0KAAICAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAziKJQECAAAAAAAAAAAAAAEAAAMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADAwAAAAAAAAAAAAAAAAAAAAAAAQEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAwQBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==";

		internal bool IsInputOpen => _inputOpen;

		private bool HasMonitorAudio
		{
			get
			{
				if (_monitorPlaying)
				{
					return true;
				}
				lock (_monitorSync)
				{
					return _monitorQueue.Count > 0;
				}
			}
		}

		private void Awake()
		{
			//IL_03ca: Unknown result type (might be due to invalid IL or missing references)
			//IL_03d4: Expected O, but got Unknown
			Instance = this;
			LogSource = ((BaseUnityPlugin)this).Logger;
			_peakUi = new PeakNativeUiRenderer(((BaseUnityPlugin)this).Logger);
			string directoryName = Path.GetDirectoryName(((BaseUnityPlugin)this).Info.Location);
			string path = ((!string.IsNullOrWhiteSpace(directoryName)) ? directoryName : Path.Combine(Paths.PluginPath, "PeakTTS"));
			string text = Path.Combine(path, "voices");
			string text2 = Path.Combine(path, "piper", "piper.exe");
			string text3 = Path.Combine(path, "coqui", "tts.exe");
			_openKey = ((BaseUnityPlugin)this).Config.Bind<KeyCode>("Input", "OpenKey", (KeyCode)289, "Key used to toggle the TTS chatbox open/close");
			_ttsGain = ((BaseUnityPlugin)this).Config.Bind<float>("Audio", "TTSGain", 0.85f, "Legacy TTS gain setting retained for compatibility. Local monitor volume is controlled separately; outgoing voice uses TransmitGain");
			_transmitGain = ((BaseUnityPlugin)this).Config.Bind<float>("Audio", "TransmitGain", 0.22f, "Outgoing TTS gain sent to other players, from 0.0 to 1.0. Lower this if the transmitted voice is too loud");
			_monitorPlayback = ((BaseUnityPlugin)this).Config.Bind<bool>("Audio", "MonitorPlayback", true, "Play your own generated TTS locally so you can hear when it starts and ends");
			_monitorVolume = ((BaseUnityPlugin)this).Config.Bind<float>("Audio", "MonitorVolume", 0.85f, "Local TTS monitoring volume, from 0.0 to 1.0");
			_speechRate = ((BaseUnityPlugin)this).Config.Bind<int>("Voice", "SpeechRate", 0, "Windows TTS speaking rate, from -10 to 10. Piper/Coqui models control their own speaking style");
			_voiceName = ((BaseUnityPlugin)this).Config.Bind<string>("Voice", "VoiceName", string.Empty, "Voice selection. Windows names are matched; the ingame picker writes exact Windows names or SAPI4/Piper/Coqui IDs");
			_languageMode = ((BaseUnityPlugin)this).Config.Bind<string>("Voice", "Language", "auto", "Speech language. Use auto to detect each message and temporarily switch to a compatible voice when needed, or set a language code such as en, hu or ko");
			_sapi4HelperPageUrl = ((BaseUnityPlugin)this).Config.Bind<string>("SAPI4", "HelperPageUrl", "https://github.com/AternosHUN/peaktts-sapi4", "(Do NOT change!) GitHub page containing the optional PeakTTS.Sapi4.exe helper download and setup instructions");
			_maxCharacters = ((BaseUnityPlugin)this).Config.Bind<int>("Input", "MaxCharacters", 220, "Maximum text length per TTS message");
			_powershellPath = ((BaseUnityPlugin)this).Config.Bind<string>("Advanced", "PowerShellPath", "powershell.exe", "PowerShell executable used for Windows System.Speech TTS");
			_modelsFolder = ((BaseUnityPlugin)this).Config.Bind<string>("Models", "ModelsFolder", text, "Folder scanned for Piper .onnx + .onnx.json voices and Coqui .pth + config.json models");
			_piperPath = ((BaseUnityPlugin)this).Config.Bind<string>("Models", "PiperPath", text2, "Path to piper.exe. Required only for Piper .onnx voices");
			_piperSpeakerId = ((BaseUnityPlugin)this).Config.Bind<int>("Models", "PiperSpeakerId", -1, "Optional Piper speaker ID for multi-speaker .onnx models. -1 uses Piper's default speaker");
			_coquiTtsPath = ((BaseUnityPlugin)this).Config.Bind<string>("Models", "CoquiTtsPath", text3, "Path to the Coqui TTS CLI executable. Required only for .pth models");
			_coquiSpeaker = ((BaseUnityPlugin)this).Config.Bind<string>("Models", "CoquiSpeaker", string.Empty, "Optional Coqui --speaker_idx value for multi-speaker .pth models");
			_coquiLanguage = ((BaseUnityPlugin)this).Config.Bind<string>("Models", "CoquiLanguage", string.Empty, "Optional Coqui --language_idx value for multilingual .pth models");
			_coquiSpeakerWav = ((BaseUnityPlugin)this).Config.Bind<string>("Models", "CoquiSpeakerWav", string.Empty, "Optional Coqui --speaker_wav path for XTTS/voice-cloning models. Relative paths are resolved next to the selected .pth model");
			try
			{
				((BaseUnityPlugin)this).Config.Save();
			}
			catch (Exception ex)
			{
				((BaseUnityPlugin)this).Logger.LogWarning((object)("Could not explicitly save config: " + ex.Message));
			}
			EnsureModelFolders();
			try
			{
				TtsMixer.SetGain(Mathf.Clamp01(_transmitGain.Value));
				_monitorEnabled = _monitorPlayback.Value;
				SetupMonitorAudio();
			}
			catch (Exception ex2)
			{
				((BaseUnityPlugin)this).Logger.LogWarning((object)("Local monitor initialization failed: " + ex2.Message));
			}
			_transmitGain.SettingChanged += delegate
			{
				TtsMixer.SetGain(Mathf.Clamp01(_transmitGain.Value));
			};
			_modelsFolder.SettingChanged += delegate
			{
				EnsureModelFolders();
				RequestVoiceCatalogRefresh(force: true);
			};
			_powershellPath.SettingChanged += delegate
			{
				RequestVoiceCatalogRefresh(force: true);
			};
			try
			{
				_harmony = new Harmony("ahun.PeakTTS");
				int num = PhotonVoicePatches.Install(_harmony, ((BaseUnityPlugin)this).Logger);
				_photonPatchesInstalled = PhotonVoicePatches.IsInstalled;
				bool flag = GameInputBridge.InstallPatch(_harmony);
				((BaseUnityPlugin)this).Logger.LogInfo((object)string.Format("{0} {1} loaded. Installed {2} Photon Voice patches. Inputblocking: {3}", "PeakTTS", "1.2.1", num, flag));
				if (!_photonPatchesInstalled)
				{
					((BaseUnityPlugin)this).Logger.LogInfo((object)"Will finish installing its Photon hooks when PEAK initializes voice");
				}
			}
			catch (Exception arg)
			{
				((BaseUnityPlugin)this).Logger.LogError((object)$"Harmony/Photon initialization failed: {arg}");
			}
			SceneManager.activeSceneChanged += OnActiveSceneChanged;
			RefreshSapi4Availability();
			RequestVoiceCatalogRefresh(force: true);
		}

		private void EnsureModelFolders()
		{
			try
			{
				string text = _modelsFolder?.Value;
				if (!string.IsNullOrWhiteSpace(text))
				{
					Directory.CreateDirectory(text);
					Directory.CreateDirectory(Path.Combine(text, "Piper"));
					Directory.CreateDirectory(Path.Combine(text, "Coqui"));
				}
				string text2 = _piperPath?.Value;
				if (!string.IsNullOrWhiteSpace(text2))
				{
					string directoryName = Path.GetDirectoryName(text2);
					if (!string.IsNullOrWhiteSpace(directoryName))
					{
						Directory.CreateDirectory(directoryName);
					}
				}
				string text3 = _coquiTtsPath?.Value;
				if (!string.IsNullOrWhiteSpace(text3))
				{
					string directoryName2 = Path.GetDirectoryName(text3);
					if (!string.IsNullOrWhiteSpace(directoryName2))
					{
						Directory.CreateDirectory(directoryName2);
					}
				}
			}
			catch (Exception ex)
			{
				((BaseUnityPlugin)this).Logger.LogWarning((object)("Could not create model folders: " + ex.Message));
			}
		}

		private void OnDestroy()
		{
			SceneManager.activeSceneChanged -= OnActiveSceneChanged;
			try
			{
				Harmony harmony = _harmony;
				if (harmony != null)
				{
					harmony.UnpatchSelf();
				}
			}
			catch
			{
			}
			try
			{
				WindowsTts.Shutdown();
			}
			catch
			{
			}
			try
			{
				_peakUi?.Dispose();
			}
			catch
			{
			}
			_peakUi = null;
			if ((Object)(object)_refreshIconTexture != (Object)null)
			{
				Object.Destroy((Object)(object)_refreshIconTexture);
			}
			if ((Object)(object)_gearIconTexture != (Object)null)
			{
				Object.Destroy((Object)(object)_gearIconTexture);
			}
			_refreshIconTexture = null;
			_gearIconTexture = null;
			ClearMonitorPlayback();
		}

		private void Update()
		{
			//IL_0104: Unknown result type (might be due to invalid IL or missing references)
			PhotonVoiceBridge.ServiceQueuedSpeech();
			UpdateMonitorPlayback();
			UpdateSpeechBannerState();
			bool flag = _inputOpen || Volatile.Read(in _pendingJobs) > 0 || _activeSpeechDisplay != null;
			_peakUi?.TryDiscoverNativeFont(!IsMainMenuScene() && flag);
			if (!_photonPatchesInstalled && Time.unscaledTime >= _nextPhotonPatchRetryAt)
			{
				_nextPhotonPatchRetryAt = Time.unscaledTime + 1f;
				try
				{
					int num = PhotonVoicePatches.Install(_harmony, ((BaseUnityPlugin)this).Logger);
					_photonPatchesInstalled = PhotonVoicePatches.IsInstalled;
					if (num > 0 && _photonPatchesInstalled)
					{
						((BaseUnityPlugin)this).Logger.LogInfo((object)"Photon Voice hooks are now ready");
					}
				}
				catch (Exception arg)
				{
					((BaseUnityPlugin)this).Logger.LogError((object)$"Delayed Photon hook failed: {arg}");
					_nextPhotonPatchRetryAt = Time.unscaledTime + 10f;
				}
			}
			if (Time.unscaledTime >= _nextVoiceRefreshAt)
			{
				_nextVoiceRefreshAt = Time.unscaledTime + 2f;
				PhotonVoiceBridge.RefreshPrimaryVoice();
			}
			if (!Input.GetKeyDown(_openKey.Value))
			{
				return;
			}
			if (IsMainMenuScene())
			{
				if (_inputOpen)
				{
					SetInputOpen(open: false);
				}
			}
			else
			{
				SetInputOpen(!_inputOpen);
				_keyboardHandledFrame = Time.frameCount;
			}
		}

		private void OnActiveSceneChanged(Scene previous, Scene next)
		{
			if (_inputOpen)
			{
				_text = string.Empty;
				SetInputOpen(open: false);
			}
			ClearSpeechDisplay();
			InvalidateStyles();
			_peakUi?.ResetForScene();
		}

		private void OnApplicationFocus(bool hasFocus)
		{
			if (hasFocus)
			{
				RefreshSapi4Availability();
				RequestVoiceCatalogRefresh(force: false);
			}
		}

		private void RefreshSapi4Availability()
		{
			string sapi4HelperPath = GetSapi4HelperPath();
			_sapi4HelperPresent = File.Exists(sapi4HelperPath);
			if (!_sapi4HelperPresent)
			{
				_sapi4Ready = false;
				_sapi4SetupLaunched = false;
			}
		}

		private string GetSapi4HelperPath()
		{
			string text = Path.GetDirectoryName(((BaseUnityPlugin)this).Info.Location);
			if (string.IsNullOrWhiteSpace(text))
			{
				text = Paths.PluginPath;
			}
			return Path.Combine(text, "PeakTTS.Sapi4.exe");
		}

		private bool OpenSapi4HelperPage(out string error)
		{
			error = null;
			try
			{
				Application.OpenURL((_sapi4HelperPageUrl?.Value ?? string.Empty).Trim());
				return true;
			}
			catch (Exception ex)
			{
				error = "Could not open the SAPI4 helper page: " + ex.Message;
				return false;
			}
		}

		private static bool IsMainMenuScene()
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			Scene activeScene = SceneManager.GetActiveScene();
			string a = (((Scene)(ref activeScene)).IsValid() ? (((Scene)(ref activeScene)).name ?? string.Empty) : string.Empty);
			if (!string.Equals(a, "MainMenu", StringComparison.OrdinalIgnoreCase) && !string.Equals(a, "Title", StringComparison.OrdinalIgnoreCase))
			{
				return string.Equals(a, "Pretitle", StringComparison.OrdinalIgnoreCase);
			}
			return true;
		}

		private bool OpenConfigFile(out string error)
		{
			error = null;
			try
			{
				((BaseUnityPlugin)this).Config.Save();
				string configFilePath = ((BaseUnityPlugin)this).Config.ConfigFilePath;
				if (string.IsNullOrWhiteSpace(configFilePath))
				{
					throw new InvalidOperationException("BepInEx did not provide a config file path");
				}
				Process.Start(new ProcessStartInfo
				{
					FileName = configFilePath,
					UseShellExecute = true
				});
				return true;
			}
			catch (Exception ex)
			{
				error = "Could not open config: " + ex.Message;
				ManualLogSource logSource = LogSource;
				if (logSource != null)
				{
					logSource.LogWarning((object)error);
				}
				return false;
			}
		}

		private void ReloadConfigFromDisk()
		{
			try
			{
				((BaseUnityPlugin)this).Config.Reload();
				TtsMixer.SetGain(Mathf.Clamp01(_transmitGain.Value));
				_monitorEnabled = _monitorPlayback.Value;
				if ((Object)(object)_monitorSource != (Object)null)
				{
					_monitorSource.volume = Mathf.Clamp01(_monitorVolume.Value);
				}
				if (!_monitorEnabled)
				{
					ClearMonitorPlayback();
				}
				EnsureModelFolders();
				RefreshSapi4Availability();
				RequestVoiceCatalogRefresh(force: true);
				_status = "Config reloaded";
				_focusNextFrame = true;
				ManualLogSource logSource = LogSource;
				if (logSource != null)
				{
					logSource.LogInfo((object)"Config reloaded from disk");
				}
			}
			catch (Exception ex)
			{
				_status = "Config reload failed - check LogOutput.log";
				ManualLogSource logSource2 = LogSource;
				if (logSource2 != null)
				{
					logSource2.LogWarning((object)("Could not reload config: " + ex));
				}
			}
		}

		private void SetInputOpen(bool open)
		{
			if ((!open || !IsMainMenuScene()) && _inputOpen != open)
			{
				_inputOpen = open;
				_focusNextFrame = open;
				ManualLogSource logSource = LogSource;
				if (logSource != null)
				{
					logSource.LogInfo((object)("TTS input overlay " + (open ? "opened" : "closed")));
				}
				if (open)
				{
					RefreshSapi4Availability();
				}
				if (open && Time.unscaledTime >= _nextCatalogRefreshAt)
				{
					_nextCatalogRefreshAt = Time.unscaledTime + 10f;
					RequestVoiceCatalogRefresh(force: false);
				}
			}
		}

		private void OnGUI()
		{
			//IL_003b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0041: Invalid comparison between Unknown and I4
			//IL_0044: Unknown result type (might be due to invalid IL or missing references)
			//IL_004f: Unknown result type (might be due to invalid IL or missing references)
			//IL_012e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0183: Unknown result type (might be due to invalid IL or missing references)
			//IL_0185: Unknown result type (might be due to invalid IL or missing references)
			//IL_0190: Unknown result type (might be due to invalid IL or missing references)
			//IL_020c: Unknown result type (might be due to invalid IL or missing references)
			//IL_020f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0222: Unknown result type (might be due to invalid IL or missing references)
			//IL_0225: Unknown result type (might be due to invalid IL or missing references)
			//IL_0266: Unknown result type (might be due to invalid IL or missing references)
			//IL_02d2: Unknown result type (might be due to invalid IL or missing references)
			//IL_0337: Unknown result type (might be due to invalid IL or missing references)
			//IL_0388: Unknown result type (might be due to invalid IL or missing references)
			//IL_0483: Unknown result type (might be due to invalid IL or missing references)
			//IL_03bd: Unknown result type (might be due to invalid IL or missing references)
			//IL_03e5: Unknown result type (might be due to invalid IL or missing references)
			//IL_0428: Unknown result type (might be due to invalid IL or missing references)
			//IL_059e: Unknown result type (might be due to invalid IL or missing references)
			//IL_05ae: Unknown result type (might be due to invalid IL or missing references)
			//IL_05f1: Unknown result type (might be due to invalid IL or missing references)
			//IL_0601: Unknown result type (might be due to invalid IL or missing references)
			//IL_0656: Unknown result type (might be due to invalid IL or missing references)
			//IL_0658: Unknown result type (might be due to invalid IL or missing references)
			//IL_075d: Unknown result type (might be due to invalid IL or missing references)
			//IL_075f: Unknown result type (might be due to invalid IL or missing references)
			//IL_07a2: Unknown result type (might be due to invalid IL or missing references)
			//IL_07f0: Unknown result type (might be due to invalid IL or missing references)
			//IL_07fa: Unknown result type (might be due to invalid IL or missing references)
			//IL_0901: Unknown result type (might be due to invalid IL or missing references)
			//IL_085f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0861: Unknown result type (might be due to invalid IL or missing references)
			//IL_08a4: Unknown result type (might be due to invalid IL or missing references)
			//IL_06a8: Unknown result type (might be due to invalid IL or missing references)
			//IL_06f5: Unknown result type (might be due to invalid IL or missing references)
			//IL_06ff: Unknown result type (might be due to invalid IL or missing references)
			EnsureStyles();
			_peakUi?.BeginGuiFrame();
			try
			{
				DrawSpeechOverlay();
				if (!_inputOpen)
				{
					DrawCompactStatusToast();
					return;
				}
				Event current = Event.current;
				if (current != null && (int)current.type == 4 && current.keyCode == _openKe