using System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Text; using BepInEx; using HarmonyLib; using Microsoft.CodeAnalysis; using TMPro; using UnityEngine; using UnityEngine.Localization; using UnityEngine.Localization.Settings; using UnityEngine.Localization.Tables; using UnityEngine.UI; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")] [assembly: AssemblyVersion("0.0.0.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 RepoPTBRContextual { [BepInPlugin("local.repo.ptbrcontextual", "R.E.P.O. PT-BR Contextual", "1.0.1")] public sealed class RepoPTBRContextualPlugin : BaseUnityPlugin { private Harmony harmony; public void Awake() { //IL_0010: Unknown result type (might be due to invalid IL or missing references) //IL_001a: Expected O, but got Unknown PTBRTranslator.Load(Paths.PluginPath); harmony = new Harmony("local.repo.ptbrcontextual"); harmony.PatchAll(typeof(RepoPTBRContextualPlugin).Assembly); OverrideTools.ApplyOverridesToActiveLocales(); ((MonoBehaviour)this).StartCoroutine(ApplyTranslationWhenReady()); ((BaseUnityPlugin)this).Logger.LogInfo((object)"PT-BR contextual translation loaded."); } private IEnumerator ApplyTranslationWhenReady() { for (int attempt = 0; attempt < 12; attempt++) { yield return (object)new WaitForSecondsRealtime(1f); OverrideTools.ApplyOverridesToActiveLocales(); } } public void OnDestroy() { if (harmony != null) { harmony.UnpatchSelf(); } } } internal static class PTBRTranslator { private static readonly Dictionary Exact = new Dictionary(); private static readonly HashSet Missing = new HashSet(); private static readonly object MissingLock = new object(); private static string missingPath; private static string localizationPath; private static DateTime nextOverrideApplyAt = DateTime.MinValue; internal static string LocalizationPath => localizationPath; public static void Load(string pluginPath) { string path = Path.Combine(pluginPath, "RepoPTBRContextual"); string path2 = Path.Combine(path, "runtime.tsv"); localizationPath = Path.Combine(path, "Localizations"); missingPath = Path.Combine(Paths.ConfigPath, "RepoPTBRContextual.missing.tsv"); Exact.Clear(); if (!File.Exists(path2)) { LoadOfficialLocalizationPairs(); return; } string[] array = File.ReadAllLines(path2, Encoding.UTF8); foreach (string text in array) { if (!string.IsNullOrWhiteSpace(text) && !text.StartsWith("#", StringComparison.Ordinal)) { string[] array2 = text.Split(new char[1] { '\t' }, 2); if (array2.Length == 2 && !string.IsNullOrWhiteSpace(array2[0])) { Exact[array2[0].Replace("\\n", "\n")] = array2[1].Replace("\\n", "\n"); } } } LoadOfficialLocalizationPairs(); } public static bool ShouldApplyOverridesNow() { DateTime utcNow = DateTime.UtcNow; if (utcNow < nextOverrideApplyAt) { return false; } nextOverrideApplyAt = utcNow.AddSeconds(1.0); return true; } public static string Translate(string value) { if (string.IsNullOrEmpty(value)) { return value; } string translated; if (value.StartsWith("(PT-BR) ", StringComparison.OrdinalIgnoreCase)) { string text = value.Substring("(PT-BR) ".Length); if (TryTranslate(text, out translated)) { return translated; } return text; } if (TryTranslate(value, out translated)) { return translated; } LogMissing(value); return value; } private static bool TryTranslate(string value, out string translated) { if (Exact.TryGetValue(value, out translated)) { return true; } string text = value.Trim(); if (text.Length != value.Length && Exact.TryGetValue(text, out translated)) { int length = value.Length - value.TrimStart().Length; int num = value.Length - value.TrimEnd().Length; translated = value.Substring(0, length) + translated + value.Substring(value.Length - num); return true; } return false; } private static void LoadOfficialLocalizationPairs() { try { string path = Path.Combine(Path.Combine(Application.streamingAssetsPath, "Localizations"), "Default"); string[] array = new string[3] { "HUD.tsv", "Menu.tsv", "Game.tsv" }; for (int i = 0; i < array.Length; i++) { Dictionary dictionary = ReadTsv(Path.Combine(path, array[i])); Dictionary dictionary2 = ReadTsv(Path.Combine(localizationPath, array[i])); foreach (KeyValuePair item in dictionary) { if (dictionary2.TryGetValue(item.Key, out var value) && !Exact.ContainsKey(item.Value)) { Exact[item.Value] = value; string key = item.Value.ToUpperInvariant(); if (!Exact.ContainsKey(key)) { Exact[key] = value; } } } } } catch { } } private static Dictionary ReadTsv(string path) { Dictionary dictionary = new Dictionary(); if (!File.Exists(path)) { return dictionary; } string[] array = File.ReadAllLines(path, Encoding.UTF8); foreach (string text in array) { if (!string.IsNullOrWhiteSpace(text)) { string[] array2 = text.Split(new char[1] { '\t' }, 2); if (array2.Length == 2 && !string.IsNullOrWhiteSpace(array2[0])) { dictionary[array2[0]] = array2[1].Replace("\\n", "\n"); } } } return dictionary; } private static void LogMissing(string value) { if (!LooksUserFacingEnglish(value)) { return; } lock (MissingLock) { if (Missing.Add(value)) { File.AppendAllText(missingPath, value.Replace("\r", "\\r").Replace("\n", "\\n") + "\t\r\n", Encoding.UTF8); } } } private static bool LooksUserFacingEnglish(string value) { string text = value.Trim(); if (text.Length < 2 || text.Length > 180) { return false; } if (text.Contains("/") || text.Contains("\\") || text.Contains(".dll") || text.Contains(".asset")) { return false; } bool flag = false; bool flag2 = false; foreach (char c in text) { if ((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z')) { flag = true; } else if (char.IsWhiteSpace(c) || ",.!?:;()[]{}'\"-".IndexOf(c) >= 0) { flag2 = true; } } if (!flag) { return false; } if (!flag2 && text.ToUpperInvariant() == text && text.Contains(".")) { return false; } return true; } } internal static class LocaleTools { public static void ForcePtBr(object manager) { try { if (manager == null) { return; } Type type = manager.GetType(); FieldInfo fieldInfo = AccessTools.Field(type, "AvailableLocales"); MethodInfo methodInfo = AccessTools.Method(type, "SwitchLocale", (Type[])null, (Type[])null); IEnumerable enumerable = ((fieldInfo == null) ? null : (fieldInfo.GetValue(manager) as IEnumerable)); if (enumerable == null || methodInfo == null) { return; } foreach (object item in enumerable) { if (string.Equals(GetLocaleCode(item), "pt-BR", StringComparison.OrdinalIgnoreCase)) { methodInfo.Invoke(manager, new object[2] { item, true }); break; } } } catch (Exception ex) { Debug.LogError((object)("[RepoPTBRContextual] Failed to apply localization overrides: " + ex)); } } private static string GetLocaleCode(object localeAsset) { if (localeAsset == null) { return null; } FieldInfo fieldInfo = AccessTools.Field(localeAsset.GetType(), "LocaleReference"); object obj = ((fieldInfo == null) ? null : fieldInfo.GetValue(localeAsset)); if (obj == null) { return null; } object value = AccessTools.Property(obj.GetType(), "Identifier").GetValue(obj, null); if (value != null) { return (string)AccessTools.Property(value.GetType(), "Code").GetValue(value, null); } return null; } } internal static class OverrideTools { public static void ApplyOverridesToActiveLocales() { try { string localizationPath = PTBRTranslator.LocalizationPath; if (string.IsNullOrEmpty(localizationPath) || !Directory.Exists(localizationPath)) { Debug.LogWarning((object)"[RepoPTBRContextual] Bundled localization tables were not found."); return; } string[] array = new string[3] { "HUD", "Menu", "Game" }; List targetLocales = GetTargetLocales(); int num = 0; foreach (string text in array) { string path = Path.Combine(localizationPath, text + ".tsv"); if (File.Exists(path)) { List> entries = ReadEntries(path); for (int j = 0; j < targetLocales.Count; j++) { num += ApplyTable(text, targetLocales[j], entries); } } } Debug.Log((object)("[RepoPTBRContextual] Applied " + num + " localization override entries to " + targetLocales.Count + " locale(s).")); } catch (Exception ex) { Debug.LogWarning((object)("[RepoPTBRContextual] Localization tables are not ready yet: " + ex.Message)); } } private static List GetTargetLocales() { List list = new List(); AddLocale(list, LocalizationSettings.SelectedLocale); AddLocale(list, LocalizationSettings.ProjectLocale); try { if (LocalizationSettings.AvailableLocales != null) { foreach (Locale locale in LocalizationSettings.AvailableLocales.Locales) { if (IsPtBr(locale)) { AddLocale(list, locale); } } } } catch { } return list; } private static void AddLocale(List locales, Locale locale) { if ((Object)(object)locale == (Object)null) { return; } for (int i = 0; i < locales.Count; i++) { if ((Object)(object)locales[i] == (Object)(object)locale) { return; } } locales.Add(locale); } private static bool IsPtBr(Locale locale) { //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)locale == (Object)null) { return false; } LocaleIdentifier identifier = locale.Identifier; return string.Equals(((LocaleIdentifier)(ref identifier)).Code, "pt-BR", StringComparison.OrdinalIgnoreCase); } private static List> ReadEntries(string path) { List> list = new List>(); string[] array = File.ReadAllLines(path, Encoding.UTF8); foreach (string text in array) { if (!string.IsNullOrWhiteSpace(text)) { string[] array2 = text.Split(new char[1] { '\t' }, 2); if (array2.Length == 2 && !string.IsNullOrWhiteSpace(array2[0])) { list.Add(new KeyValuePair(array2[0], array2[1].Replace("\\n", "\n"))); } } } return list; } private static int ApplyTable(string tableName, Locale locale, List> entries) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) StringTable table = ((LocalizedDatabase)(object)LocalizationSettings.StringDatabase).GetTable(TableReference.op_Implicit(tableName), locale); if ((Object)(object)table == (Object)null) { return 0; } int num = 0; for (int i = 0; i < entries.Count; i++) { KeyValuePair keyValuePair = entries[i]; StringTableEntry entry = ((DetailedLocalizationTable)(object)table).GetEntry(keyValuePair.Key); if (entry != null) { entry.Value = keyValuePair.Value; } else { ((DetailedLocalizationTable)(object)table).AddEntry(keyValuePair.Key, keyValuePair.Value); } num++; } return num; } } [HarmonyPatch(typeof(LocalizationManager), "Start")] internal static class LocalizationManagerStartPatch { private static void Postfix(LocalizationManager __instance) { OverrideTools.ApplyOverridesToActiveLocales(); MethodInfo methodInfo = AccessTools.Method(((object)__instance).GetType(), "NotifyLocalizationChanged", (Type[])null, (Type[])null); if (methodInfo != null) { methodInfo.Invoke(__instance, null); } } } [HarmonyPatch(typeof(LocalizationChangedEvent), "OnLocaleChange")] internal static class LocalizationChangedEventPatch { private static void Prefix() { if (PTBRTranslator.ShouldApplyOverridesNow()) { OverrideTools.ApplyOverridesToActiveLocales(); } } } [HarmonyPatch(typeof(TMP_Text), "set_text")] internal static class TMPTextPatch { private static void Prefix(ref string value) { value = PTBRTranslator.Translate(value); } } [HarmonyPatch] internal static class TMPSetTextPatch { private static IEnumerable TargetMethods() { return from method in typeof(TMP_Text).GetMethods(BindingFlags.Instance | BindingFlags.Public) where method.Name == "SetText" && method.GetParameters().Length != 0 && method.GetParameters()[0].ParameterType == typeof(string) select method; } private static void Prefix(ref string sourceText) { sourceText = PTBRTranslator.Translate(sourceText); } } [HarmonyPatch(typeof(Text), "set_text")] internal static class UITextPatch { private static void Prefix(ref string value) { value = PTBRTranslator.Translate(value); } } }