using System; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Security; using System.Security.Permissions; using System.Text; using BepInEx; using BepInEx.Bootstrap; using BepInEx.Configuration; using HarmonyLib; using Microsoft.CodeAnalysis; using TMPro; using UnityEngine; using UnityEngine.UI; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETFramework,Version=v4.7.1", FrameworkDisplayName = ".NET Framework 4.7.1")] [assembly: AssemblyCompany("MoreLoadingQuotes")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyDescription("More loading quotes for Gamble With Your Friends")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0")] [assembly: AssemblyProduct("MoreLoadingQuotes")] [assembly: AssemblyTitle("MoreLoadingQuotes")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("1.0.0.0")] [module: UnverifiableCode] [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 MoreLoadingQuotes { [BepInPlugin("com.ananas1k.gwyf.moreloadingquotes", "More Loading Quotes", "1.0.0")] public class MoreLoadingQuotesPlugin : BaseUnityPlugin { private sealed class QuoteParts { public readonly string Quote; public readonly string Author; public readonly string Formatted; public QuoteParts(string quote, string author, string formatted) { Quote = quote; Author = author; Formatted = formatted; } } private const string PluginGuid = "com.ananas1k.gwyf.moreloadingquotes"; private const string PluginName = "More Loading Quotes"; private const string PluginVersion = "1.0.0"; private const string PluginFolderName = "MoreLoadingQuotes"; private const string QuotesFileName = "quotes.txt"; private const string EnglishQuotesFileName = "en_quotes.txt"; private const string RussianQuotesFileName = "ru_quotes.txt"; private const string RussianTranslationPackageName = "RTLC-GWYF_Russian_Translation"; private static readonly HashSet PatchedInstances = new HashSet(); private static readonly Dictionary VanillaQuotesByInstance = new Dictionary(); private static readonly Dictionary QuotePartsByDisplayedText = new Dictionary(StringComparer.Ordinal); private static readonly Dictionary QuotePartsByQuoteText = new Dictionary(StringComparer.Ordinal); private static readonly object QuoteLock = new object(); private static readonly string[] EmptyQuotes = new string[0]; private static MoreLoadingQuotesPlugin Instance; private static ConfigEntry EnableCustomQuotes; private static ConfigEntry ReplaceVanillaQuotes; private static ConfigEntry LiveReload; private static ConfigEntry QuoteFilePath; private static ConfigEntry QuoteAuthorFormat; private static ConfigEntry ConfigLocalizationLanguage; private static ConfigEntry ConfigLineSpacing; private static ConfigEntry ConfigTextBoxMinHeight; private static ConfigEntry ConfigAuthorVerticalOffset; private static ConfigEntry ConfigAuthorFontScale; private static string activeQuoteFilePath; private static string[] cachedQuotes = EmptyQuotes; private static DateTime cachedQuoteFileWriteTimeUtc = DateTime.MinValue; private static bool useRussianQuotes; private static FieldInfo targetTextField; private Harmony harmony; private void Awake() { //IL_0050: Unknown result type (might be due to invalid IL or missing references) //IL_005a: Expected O, but got Unknown //IL_0086: Unknown result type (might be due to invalid IL or missing references) //IL_009b: Unknown result type (might be due to invalid IL or missing references) //IL_00a8: Expected O, but got Unknown //IL_00a8: Expected O, but got Unknown Instance = this; BindConfig(); useRussianQuotes = ShouldUseRussianQuotes(); activeQuoteFilePath = ResolveQuoteFilePath(); EnsureQuoteFileExists(activeQuoteFilePath); LoadQuotes(force: true); targetTextField = AccessTools.Field(typeof(LoadingQuotes), "targetText"); harmony = new Harmony("com.ananas1k.gwyf.moreloadingquotes"); harmony.Patch((MethodBase)AccessTools.Method(typeof(LoadingQuotes), "ShowRandomQuote", (Type[])null, (Type[])null), new HarmonyMethod(typeof(MoreLoadingQuotesPlugin), "PatchShowRandomQuote", (Type[])null), new HarmonyMethod(typeof(MoreLoadingQuotesPlugin), "PatchShowRandomQuotePostfix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); ((BaseUnityPlugin)this).Logger.LogInfo((object)("More Loading Quotes 1.0.0 loaded. " + (useRussianQuotes ? "Russian" : "English") + " quote file: " + activeQuoteFilePath)); } private void OnDestroy() { if (harmony != null) { harmony.UnpatchSelf(); } } private void BindConfig() { //IL_00ca: Unknown result type (might be due to invalid IL or missing references) //IL_00d4: Expected O, but got Unknown //IL_0107: Unknown result type (might be due to invalid IL or missing references) //IL_0111: Expected O, but got Unknown //IL_0144: Unknown result type (might be due to invalid IL or missing references) //IL_014e: Expected O, but got Unknown //IL_0181: Unknown result type (might be due to invalid IL or missing references) //IL_018b: Expected O, but got Unknown //IL_01be: Unknown result type (might be due to invalid IL or missing references) //IL_01c8: Expected O, but got Unknown EnableCustomQuotes = ((BaseUnityPlugin)this).Config.Bind("General", "EnableCustomQuotes", true, "If true, loads extra loading quotes from en_quotes.txt or ru_quotes.txt."); ReplaceVanillaQuotes = ((BaseUnityPlugin)this).Config.Bind("General", "ReplaceVanillaQuotes", false, "If true, only custom quotes from quotes.txt will be used. If false, custom quotes are added to the vanilla quote pool."); LiveReload = ((BaseUnityPlugin)this).Config.Bind("General", "LiveReload", true, "If true, quotes.txt is re-read when it changes, so testing new quotes does not require restarting the game."); QuoteFilePath = ((BaseUnityPlugin)this).Config.Bind("General", "QuoteFilePath", string.Empty, "Optional custom quote file path. Relative paths are resolved from the BepInEx plugins folder. Leave empty to use automatic en_quotes.txt/ru_quotes.txt selection."); QuoteAuthorFormat = ((BaseUnityPlugin)this).Config.Bind("General", "QuoteAuthorFormat", "{0}\\n- {1}", "Format used for quote lines written as: quote | author. {0}=quote, {1}=author. Use \\n for line breaks."); ConfigLocalizationLanguage = ((BaseUnityPlugin)this).Config.Bind("Localization", "Language", 0, new ConfigDescription("0=Auto, 1=English, 2=Russian. Auto uses Russian quotes when RTLC-GWYF_Russian_Translation is enabled.", (AcceptableValueBase)(object)new AcceptableValueRange(0, 2), Array.Empty())); ConfigLineSpacing = ((BaseUnityPlugin)this).Config.Bind("Layout", "LineSpacing", 35f, new ConfigDescription("Extra TextMeshPro line spacing for loading quotes. Increase if wrapped quote lines overlap.", (AcceptableValueBase)(object)new AcceptableValueRange(0f, 120f), Array.Empty())); ConfigTextBoxMinHeight = ((BaseUnityPlugin)this).Config.Bind("Layout", "TextBoxMinHeight", 260f, new ConfigDescription("Minimum height for the loading quote text box. Increase if the quote author is clipped.", (AcceptableValueBase)(object)new AcceptableValueRange(0f, 600f), Array.Empty())); ConfigAuthorVerticalOffset = ((BaseUnityPlugin)this).Config.Bind("Layout", "AuthorVerticalOffset", -125f, new ConfigDescription("Vertical offset for the separate quote author text. Negative values move it down.", (AcceptableValueBase)(object)new AcceptableValueRange(-300f, 100f), Array.Empty())); ConfigAuthorFontScale = ((BaseUnityPlugin)this).Config.Bind("Layout", "AuthorFontScale", 0.55f, new ConfigDescription("Author font size as a multiplier of the quote font size.", (AcceptableValueBase)(object)new AcceptableValueRange(0.2f, 1f), Array.Empty())); } private static void PatchShowRandomQuote(LoadingQuotes __instance) { try { if ((Object)(object)__instance == (Object)null || EnableCustomQuotes == null || !EnableCustomQuotes.Value) { return; } if (LiveReload != null && LiveReload.Value && (Object)(object)Instance != (Object)null) { Instance.LoadQuotes(force: false); } string[] array = GetCachedQuotes(); if (array.Length == 0) { return; } int instanceID = ((Object)__instance).GetInstanceID(); if (!PatchedInstances.Contains(instanceID)) { string[] source = (AccessTools.Field(typeof(LoadingQuotes), "quotes").GetValue(__instance) as string[]) ?? EmptyQuotes; if (!VanillaQuotesByInstance.TryGetValue(instanceID, out var value)) { value = CopyQuotes(source); VanillaQuotesByInstance[instanceID] = value; } string[] value2 = ((ReplaceVanillaQuotes != null && ReplaceVanillaQuotes.Value) ? NormalizeQuotes(array) : MergeQuotes(value, array)); AccessTools.Field(typeof(LoadingQuotes), "quotes").SetValue(__instance, value2); ApplyTextLayout(__instance); PatchedInstances.Add(instanceID); } } catch (Exception ex) { LogWarning("Failed to add custom loading quotes: " + ex.Message); } } private static void PatchShowRandomQuotePostfix(LoadingQuotes __instance) { try { ApplyTextLayout(__instance); } catch (Exception ex) { LogWarning("Failed to adjust loading quote layout: " + ex.Message); } } private static void ApplyTextLayout(LoadingQuotes loadingQuotes) { //IL_009d: Unknown result type (might be due to invalid IL or missing references) //IL_00a2: Unknown result type (might be due to invalid IL or missing references) TextMeshProUGUI targetText = GetTargetText(loadingQuotes); if ((Object)(object)targetText == (Object)null) { return; } ((TMP_Text)targetText).richText = true; EnableTextWrapping(targetText); ((TMP_Text)targetText).overflowMode = (TextOverflowModes)0; ((TMP_Text)targetText).lineSpacing = ((ConfigLineSpacing == null) ? 35f : ConfigLineSpacing.Value); ((TMP_Text)targetText).maxVisibleCharacters = 99999; ((TMP_Text)targetText).maxVisibleWords = 99999; ((TMP_Text)targetText).maxVisibleLines = 99999; ((TMP_Text)targetText).extraPadding = true; float num = ((ConfigTextBoxMinHeight == null) ? 260f : ConfigTextBoxMinHeight.Value); RectTransform rectTransform = ((TMP_Text)targetText).rectTransform; if ((Object)(object)rectTransform != (Object)null && num > 0f) { Rect rect = rectTransform.rect; if (((Rect)(ref rect)).height < num) { rectTransform.SetSizeWithCurrentAnchors((Axis)1, num); } } ApplyAuthorText(targetText); ((TMP_Text)targetText).ForceMeshUpdate(false, false); } private static void ApplyAuthorText(TextMeshProUGUI targetText) { if (!TryGetQuoteParts(((TMP_Text)targetText).text, out var parts)) { SetAuthorObjectActive(targetText, active: false, null); return; } if (!string.Equals(((TMP_Text)targetText).text, parts.Quote, StringComparison.Ordinal)) { ((TMP_Text)targetText).text = parts.Quote; } SetAuthorObjectActive(targetText, active: true, parts.Author); } private static bool TryGetQuoteParts(string displayedText, out QuoteParts parts) { parts = null; string text = NormalizeRuntimeText(displayedText); if (string.IsNullOrEmpty(text)) { return false; } if (QuotePartsByDisplayedText.TryGetValue(text, out parts)) { return true; } if (QuotePartsByQuoteText.TryGetValue(text, out parts)) { return true; } return TrySplitFormattedQuote(text, out parts); } private static void SetAuthorObjectActive(TextMeshProUGUI targetText, bool active, string author) { //IL_010e: Unknown result type (might be due to invalid IL or missing references) //IL_0049: Unknown result type (might be due to invalid IL or missing references) //IL_0055: Unknown result type (might be due to invalid IL or missing references) //IL_0061: 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) //IL_0072: Unknown result type (might be due to invalid IL or missing references) //IL_008f: Unknown result type (might be due to invalid IL or missing references) //IL_0094: Unknown result type (might be due to invalid IL or missing references) //IL_0082: Unknown result type (might be due to invalid IL or missing references) //IL_00a1: Unknown result type (might be due to invalid IL or missing references) //IL_00ad: Unknown result type (might be due to invalid IL or missing references) //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_00df: Unknown result type (might be due to invalid IL or missing references) //IL_00ea: Unknown result type (might be due to invalid IL or missing references) TextMeshProUGUI orCreateAuthorText = GetOrCreateAuthorText(targetText); if ((Object)(object)orCreateAuthorText == (Object)null) { return; } ((Component)orCreateAuthorText).gameObject.SetActive(active); if (!active) { return; } RectTransform rectTransform = ((TMP_Text)targetText).rectTransform; RectTransform rectTransform2 = ((TMP_Text)orCreateAuthorText).rectTransform; if ((Object)(object)rectTransform != (Object)null && (Object)(object)rectTransform2 != (Object)null) { rectTransform2.anchorMin = rectTransform.anchorMin; rectTransform2.anchorMax = rectTransform.anchorMax; rectTransform2.pivot = rectTransform.pivot; Rect rect = rectTransform.rect; float num; if (!(((Rect)(ref rect)).width > 0f)) { num = rectTransform.sizeDelta.x; } else { rect = rectTransform.rect; num = ((Rect)(ref rect)).width; } rectTransform2.sizeDelta = new Vector2(num, 90f); rectTransform2.anchoredPosition = rectTransform.anchoredPosition + new Vector2(0f, (ConfigAuthorVerticalOffset == null) ? (-125f) : ConfigAuthorVerticalOffset.Value); ((Transform)rectTransform2).localScale = Vector3.one; ((Transform)rectTransform2).localRotation = Quaternion.identity; } ((TMP_Text)orCreateAuthorText).font = ((TMP_Text)targetText).font; ((TMP_Text)orCreateAuthorText).fontSharedMaterial = ((TMP_Text)targetText).fontSharedMaterial; ((Graphic)orCreateAuthorText).color = ((Graphic)targetText).color; ((TMP_Text)orCreateAuthorText).alignment = (TextAlignmentOptions)514; ((TMP_Text)orCreateAuthorText).richText = true; ((TMP_Text)orCreateAuthorText).overflowMode = (TextOverflowModes)0; ((TMP_Text)orCreateAuthorText).enableAutoSizing = false; ((TMP_Text)orCreateAuthorText).fontSize = ((TMP_Text)targetText).fontSize * ((ConfigAuthorFontScale == null) ? 0.55f : ConfigAuthorFontScale.Value); ((TMP_Text)orCreateAuthorText).lineSpacing = ((TMP_Text)targetText).lineSpacing; ((TMP_Text)orCreateAuthorText).maxVisibleCharacters = 99999; ((TMP_Text)orCreateAuthorText).maxVisibleWords = 99999; ((TMP_Text)orCreateAuthorText).maxVisibleLines = 99999; ((TMP_Text)orCreateAuthorText).extraPadding = true; ((Graphic)orCreateAuthorText).raycastTarget = false; ((TMP_Text)orCreateAuthorText).text = "- " + author; ((TMP_Text)orCreateAuthorText).ForceMeshUpdate(false, false); } private static TextMeshProUGUI GetOrCreateAuthorText(TextMeshProUGUI targetText) { //IL_004b: Unknown result type (might be due to invalid IL or missing references) //IL_0050: Unknown result type (might be due to invalid IL or missing references) //IL_005d: Unknown result type (might be due to invalid IL or missing references) Transform parent = ((TMP_Text)targetText).transform.parent; if ((Object)(object)parent == (Object)null) { return null; } Transform val = parent.Find("MoreLoadingQuotes_Author"); if ((Object)(object)val != (Object)null) { return ((Component)val).GetComponent(); } GameObject val2 = new GameObject("MoreLoadingQuotes_Author", new Type[1] { typeof(RectTransform) }); val2.transform.SetParent(parent, false); val2.transform.SetSiblingIndex(((TMP_Text)targetText).transform.GetSiblingIndex() + 1); return val2.AddComponent(); } private static void EnableTextWrapping(TextMeshProUGUI targetText) { try { PropertyInfo property = typeof(TMP_Text).GetProperty("textWrappingMode", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); if (property != null && property.PropertyType.IsEnum) { object value = Enum.Parse(property.PropertyType, "Normal"); property.SetValue(targetText, value, null); return; } PropertyInfo property2 = typeof(TMP_Text).GetProperty("enableWordWrapping", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); if (property2 != null) { property2.SetValue(targetText, true, null); } } catch { } } private static TextMeshProUGUI GetTargetText(LoadingQuotes loadingQuotes) { if ((Object)(object)loadingQuotes == (Object)null || targetTextField == null) { return null; } try { object? value = targetTextField.GetValue(loadingQuotes); return (TextMeshProUGUI)((value is TextMeshProUGUI) ? value : null); } catch { return null; } } private static string ResolveQuoteFilePath() { string text = ((QuoteFilePath.Value == null) ? string.Empty : QuoteFilePath.Value.Trim()); if (!string.IsNullOrEmpty(text)) { if (!Path.IsPathRooted(text)) { return Path.Combine(Paths.PluginPath, text); } return text; } string text2 = (useRussianQuotes ? "ru_quotes.txt" : "en_quotes.txt"); string text3 = Path.Combine(Paths.PluginPath, "MoreLoadingQuotes", text2); if (File.Exists(text3)) { return text3; } string directoryName = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location); if (!string.IsNullOrEmpty(directoryName)) { string text4 = Path.Combine(directoryName, text2); if (File.Exists(text4)) { return text4; } } string text5 = Path.Combine(Paths.PluginPath, "MoreLoadingQuotes", "quotes.txt"); if (File.Exists(text5)) { return text5; } return text3; } private static bool ShouldUseRussianQuotes() { if (ConfigLocalizationLanguage != null) { if (ConfigLocalizationLanguage.Value == 1) { return false; } if (ConfigLocalizationLanguage.Value == 2) { return true; } } return IsRussianLocalizationDetected(); } private static bool IsRussianLocalizationDetected() { if (TryGetManagedRussianTranslationEnabled(out var enabled)) { return enabled; } if (IsManagedThunderstoreProfile()) { return false; } if (HasRussianTranslationPackageFiles()) { return true; } try { foreach (KeyValuePair pluginInfo in Chainloader.PluginInfos) { string text = pluginInfo.Key ?? string.Empty; string text2 = ((pluginInfo.Value != null && pluginInfo.Value.Metadata != null) ? (pluginInfo.Value.Metadata.Name ?? string.Empty) : string.Empty); string text3 = ((pluginInfo.Value != null && pluginInfo.Value.Metadata != null) ? (pluginInfo.Value.Metadata.GUID ?? string.Empty) : string.Empty); if (IsRussianTranslationPluginText((text + " " + text2 + " " + text3).ToLowerInvariant())) { return true; } } } catch { } return false; } private static bool TryGetManagedRussianTranslationEnabled(out bool enabled) { enabled = false; try { string managedModsFilePath = GetManagedModsFilePath(); if (string.IsNullOrEmpty(managedModsFilePath) || !File.Exists(managedModsFilePath)) { return false; } string[] array = File.ReadAllLines(managedModsFilePath); bool flag = false; for (int i = 0; i < array.Length; i++) { string text = array[i].Trim(); if (array[i].StartsWith("- ", StringComparison.Ordinal)) { if (flag) { return true; } flag = false; } bool result; if (text.StartsWith("name:", StringComparison.OrdinalIgnoreCase) && text.IndexOf("RTLC-GWYF_Russian_Translation", StringComparison.OrdinalIgnoreCase) >= 0) { flag = true; } else if (flag && text.StartsWith("enabled:", StringComparison.OrdinalIgnoreCase) && bool.TryParse(text.Substring("enabled:".Length).Trim(), out result)) { enabled = result; return true; } } return flag; } catch { return false; } } private static bool IsManagedThunderstoreProfile() { string managedModsFilePath = GetManagedModsFilePath(); if (!string.IsNullOrEmpty(managedModsFilePath)) { return File.Exists(managedModsFilePath); } return false; } private static string GetManagedModsFilePath() { try { DirectoryInfo directoryInfo = Directory.GetParent(Paths.PluginPath)?.Parent; return (directoryInfo == null) ? null : Path.Combine(directoryInfo.FullName, "mods.yml"); } catch { return null; } } private static bool HasRussianTranslationPackageFiles() { try { string text = Path.Combine(Paths.PluginPath, "RTLC-GWYF_Russian_Translation"); if (!Directory.Exists(text)) { return false; } if (File.Exists(Path.Combine(text, "RTLC.GWYF", "RTLC.GWYF.Text.dll"))) { return true; } return Directory.GetFiles(text, "RTLC.GWYF.Text.dll", SearchOption.AllDirectories).Length != 0; } catch { return false; } } private static bool IsRussianTranslationPluginText(string text) { if (!text.Contains("rtlc.gwyf.text") && !text.Contains("gwyf_russian_translation") && !text.Contains("gwyf russian translation")) { return text.Contains("rtlc-gwyf_russian_translation"); } return true; } private static void EnsureQuoteFileExists(string filePath) { try { string directoryName = Path.GetDirectoryName(filePath); if (!string.IsNullOrEmpty(directoryName)) { Directory.CreateDirectory(directoryName); } if (!File.Exists(filePath)) { File.WriteAllText(filePath, GetQuoteFileTemplate(useRussianQuotes), Encoding.UTF8); } } catch (Exception ex) { LogWarning("Failed to create quote file '" + filePath + "': " + ex.Message); } } private static string GetQuoteFileTemplate(bool russian) { if (russian) { return "# More Loading Quotes\n# Recommended format: Quote text | Author\n# Example: Gambling is just math with dramatic lighting. | A broke statistician\n# Already formatted lines are also accepted. Use \\n for manual line breaks.\n# Empty lines and lines starting with # or // are ignored.\n# Put your Russian quotes below this line.\n"; } return "# More Loading Quotes\n# Recommended format: Quote text | Author\n# Example: Gambling is just math with dramatic lighting. | A broke statistician\n# Already formatted lines are also accepted. Use \\n for manual line breaks.\n# Empty lines and lines starting with # or // are ignored.\n# Put your English quotes below this line.\n"; } private void LoadQuotes(bool force) { lock (QuoteLock) { try { useRussianQuotes = ShouldUseRussianQuotes(); string b = ResolveQuoteFilePath(); if (!string.Equals(activeQuoteFilePath, b, StringComparison.OrdinalIgnoreCase)) { activeQuoteFilePath = b; cachedQuoteFileWriteTimeUtc = DateTime.MinValue; PatchedInstances.Clear(); force = true; } EnsureQuoteFileExists(activeQuoteFilePath); if (string.IsNullOrEmpty(activeQuoteFilePath) || !File.Exists(activeQuoteFilePath)) { cachedQuotes = EmptyQuotes; cachedQuoteFileWriteTimeUtc = DateTime.MinValue; PatchedInstances.Clear(); return; } DateTime lastWriteTimeUtc = File.GetLastWriteTimeUtc(activeQuoteFilePath); if (!force && lastWriteTimeUtc == cachedQuoteFileWriteTimeUtc) { return; } Dictionary dictionary = new Dictionary(StringComparer.Ordinal); Dictionary dictionary2 = new Dictionary(StringComparer.Ordinal); List list = new List(); string[] array = File.ReadAllLines(activeQuoteFilePath, Encoding.UTF8); for (int i = 0; i < array.Length; i++) { string text = array[i].Trim(); if (!string.IsNullOrEmpty(text) && !text.StartsWith("#", StringComparison.Ordinal) && !text.StartsWith("//", StringComparison.Ordinal)) { list.Add(ParseQuoteLine(text, dictionary, dictionary2)); } } cachedQuotes = NormalizeQuotes(list.ToArray()); QuotePartsByDisplayedText.Clear(); QuotePartsByQuoteText.Clear(); foreach (KeyValuePair item in dictionary) { QuotePartsByDisplayedText[item.Key] = item.Value; } foreach (KeyValuePair item2 in dictionary2) { QuotePartsByQuoteText[item2.Key] = item2.Value; } cachedQuoteFileWriteTimeUtc = lastWriteTimeUtc; PatchedInstances.Clear(); ((BaseUnityPlugin)this).Logger.LogInfo((object)string.Format("Loaded {0} custom {1} loading quote(s).", cachedQuotes.Length, useRussianQuotes ? "Russian" : "English")); } catch (Exception ex) { cachedQuotes = EmptyQuotes; cachedQuoteFileWriteTimeUtc = DateTime.MinValue; PatchedInstances.Clear(); ((BaseUnityPlugin)this).Logger.LogWarning((object)("Failed to load custom loading quotes: " + ex.Message)); } } } private static string ParseQuoteLine(string line, Dictionary displayedParts, Dictionary quoteParts) { string text = line.Replace("\\n", "\n").Trim(); int num = text.IndexOf('|'); if (num < 0) { return text; } string text2 = text.Substring(0, num).Trim(); string text3 = text.Substring(num + 1).Trim().TrimStart(new char[1] { '|' }) .Trim(); if (string.IsNullOrEmpty(text2) || string.IsNullOrEmpty(text3)) { return text; } string text4 = FormatQuoteWithAuthor(text2, text3); QuoteParts value = new QuoteParts(text2, text3, text4); displayedParts[NormalizeRuntimeText(text4)] = value; quoteParts[NormalizeRuntimeText(text2)] = value; return text4; } private static bool TrySplitFormattedQuote(string text, out QuoteParts parts) { parts = null; int num = text.LastIndexOf("\n- ", StringComparison.Ordinal); if (num < 0) { return false; } string text2 = text.Substring(0, num).Trim(); string text3 = text.Substring(num + 3).Trim(); if (string.IsNullOrEmpty(text2) || string.IsNullOrEmpty(text3)) { return false; } parts = new QuoteParts(text2, text3, text); return true; } private static string NormalizeRuntimeText(string text) { if (text == null) { return string.Empty; } return text.Replace("\r\n", "\n").Replace("\r", "\n").Trim(); } private static string FormatQuoteWithAuthor(string quote, string author) { string text = ((QuoteAuthorFormat == null || string.IsNullOrEmpty(QuoteAuthorFormat.Value)) ? "{0}\\n- {1}" : QuoteAuthorFormat.Value); text = text.Replace("\\n", "\n"); try { return string.Format(text, quote, author); } catch { return quote + "\n- " + author; } } private static string[] GetCachedQuotes() { lock (QuoteLock) { if (cachedQuotes.Length == 0) { return EmptyQuotes; } string[] array = new string[cachedQuotes.Length]; Array.Copy(cachedQuotes, array, cachedQuotes.Length); return array; } } private static string[] CopyQuotes(string[] source) { if (source == null || source.Length == 0) { return EmptyQuotes; } string[] array = new string[source.Length]; Array.Copy(source, array, source.Length); return array; } private static string[] MergeQuotes(string[] vanillaQuotes, string[] customQuotes) { List list = new List(); AddUniqueQuotes(list, vanillaQuotes); AddUniqueQuotes(list, customQuotes); return list.ToArray(); } private static string[] NormalizeQuotes(string[] quotes) { List list = new List(); AddUniqueQuotes(list, quotes); return list.ToArray(); } private static void AddUniqueQuotes(List target, string[] source) { if (source == null) { return; } HashSet hashSet = new HashSet(target, StringComparer.Ordinal); for (int i = 0; i < source.Length; i++) { string text = ((source[i] == null) ? string.Empty : source[i].Trim()); if (!string.IsNullOrEmpty(text) && !hashSet.Contains(text)) { target.Add(text); hashSet.Add(text); } } } private static void LogWarning(string message) { if ((Object)(object)Instance != (Object)null) { ((BaseUnityPlugin)Instance).Logger.LogWarning((object)message); } } } }