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.Text.RegularExpressions; using BepInEx; using HarmonyLib; using Microsoft.CodeAnalysis; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETStandard,Version=v2.0", FrameworkDisplayName = ".NET Standard 2.0")] [assembly: AssemblyCompany("Aethelgard.LocalizationPatcher")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyDescription("Dynamic translation fallback patcher for hardcoded mod strings")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0+dd5fceaa2ed10d400056cd50fd7fe64c3015bff5")] [assembly: AssemblyProduct("Aethelgard.LocalizationPatcher")] [assembly: AssemblyTitle("Aethelgard.LocalizationPatcher")] [assembly: AssemblyVersion("1.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 Aethelgard.LocalizationPatcher { [BepInPlugin("net.gmloc.aethelgard.localizationpatcher", "Aethelgard Localization Patcher", "1.0.3")] public class LocalizationPatcherPlugin : BaseUnityPlugin { public const string PluginGUID = "net.gmloc.aethelgard.localizationpatcher"; public const string PluginName = "Aethelgard Localization Patcher"; public const string PluginVersion = "1.0.3"; public static readonly Dictionary ExactDictionary = new Dictionary(StringComparer.OrdinalIgnoreCase); public static readonly List> PhraseReplacements = new List>(); private static readonly Regex JsonPairRegex = new Regex("\"((?:\\\\\"|[^\"])*)\"\\s*:\\s*\"((?:\\\\\"|[^\"])*)\"", RegexOptions.Compiled); private Harmony _harmony; private void Awake() { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_0010: Expected O, but got Unknown //IL_006a: Unknown result type (might be due to invalid IL or missing references) //IL_0078: Expected O, but got Unknown //IL_00d0: Unknown result type (might be due to invalid IL or missing references) //IL_00de: Expected O, but got Unknown //IL_0138: Unknown result type (might be due to invalid IL or missing references) //IL_0146: Expected O, but got Unknown _harmony = new Harmony("net.gmloc.aethelgard.localizationpatcher"); LoadLocalizations(); Type type = AccessTools.TypeByName("UnityEngine.UI.Text"); if (type != null) { MethodInfo methodInfo = AccessTools.PropertySetter(type, "text"); MethodInfo methodInfo2 = AccessTools.Method(typeof(LocalizationPatcherPlugin), "Prefix_SetText", (Type[])null, (Type[])null); if (methodInfo != null && methodInfo2 != null) { _harmony.Patch((MethodBase)methodInfo, new HarmonyMethod(methodInfo2), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); } } Type type2 = AccessTools.TypeByName("TMPro.TMP_Text"); if (type2 != null) { MethodInfo methodInfo3 = AccessTools.PropertySetter(type2, "text"); MethodInfo methodInfo4 = AccessTools.Method(typeof(LocalizationPatcherPlugin), "Prefix_SetText", (Type[])null, (Type[])null); if (methodInfo3 != null && methodInfo4 != null) { _harmony.Patch((MethodBase)methodInfo3, new HarmonyMethod(methodInfo4), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); } } Type type3 = AccessTools.TypeByName("TextsDialog"); if (type3 != null) { MethodInfo methodInfo5 = AccessTools.Method(type3, "AddText", (Type[])null, (Type[])null); MethodInfo methodInfo6 = AccessTools.Method(typeof(LocalizationPatcherPlugin), "Prefix_AddText", (Type[])null, (Type[])null); if (methodInfo5 != null && methodInfo6 != null) { _harmony.Patch((MethodBase)methodInfo5, new HarmonyMethod(methodInfo6), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); } } ((BaseUnityPlugin)this).Logger.LogInfo((object)$"[Aethelgard] Патчер 1.0.3 активен! Точных ключей: {ExactDictionary.Count}, фразовых шаблонов: {PhraseReplacements.Count}"); } private void OnDestroy() { Harmony harmony = _harmony; if (harmony != null) { harmony.UnpatchSelf(); } } private void LoadLocalizations() { try { string path = Path.Combine(Paths.ConfigPath, "Translation", "Russian"); if (Directory.Exists(path)) { string[] files = Directory.GetFiles(path, "*.json"); for (int i = 0; i < files.Length; i++) { ParseJsonFile(File.ReadAllText(files[i])); } } } catch (Exception ex) { ((BaseUnityPlugin)this).Logger.LogError((object)("[Aethelgard] Ошибка загрузки словарей: " + ex.Message)); } } private static void ParseJsonFile(string json) { foreach (Match item in JsonPairRegex.Matches(json)) { string text = item.Groups[1].Value.Replace("\\\"", "\"").Replace("\\n", "\n").Trim(); string value = item.Groups[2].Value.Replace("\\\"", "\"").Replace("\\n", "\n").Trim(); if (!string.Equals(text, "language", StringComparison.OrdinalIgnoreCase) && !string.Equals(text, "words", StringComparison.OrdinalIgnoreCase) && !string.IsNullOrEmpty(text) && !string.IsNullOrEmpty(value)) { ExactDictionary[text] = value; if (text.Length > 5 && (text.Contains(" ") || text.Contains(":"))) { PhraseReplacements.Add(new KeyValuePair(text, value)); } } } PhraseReplacements.Sort((KeyValuePair a, KeyValuePair b) => b.Key.Length.CompareTo(a.Key.Length)); } public static void Prefix_AddText(ref string topic, ref string text) { if (!string.IsNullOrEmpty(topic)) { topic = TranslateString(topic); } if (!string.IsNullOrEmpty(text)) { text = TranslateString(text); } } public static void Prefix_SetText(ref string value) { if (!string.IsNullOrEmpty(value)) { value = TranslateString(value); } } public static string TranslateString(string input) { string text = input.Trim(); if (ExactDictionary.TryGetValue(text, out var value)) { return value; } if (text.StartsWith("$") && ExactDictionary.TryGetValue(text.Substring(1), out var value2)) { return value2; } if (input.Length > 15) { string text2 = input; bool flag = false; foreach (KeyValuePair phraseReplacement in PhraseReplacements) { if (text2.Contains(phraseReplacement.Key)) { text2 = text2.Replace(phraseReplacement.Key, phraseReplacement.Value); flag = true; } } if (flag) { return text2; } } return input; } } }