using System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Linq; using System.Reflection; using System.Reflection.Emit; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Text; using BepInEx; using BepInEx.Bootstrap; using HarmonyLib; using Microsoft.CodeAnalysis; using UnityEngine; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")] [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.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)] internal sealed class NullableAttribute : Attribute { public readonly byte[] NullableFlags; public NullableAttribute(byte P_0) { NullableFlags = new byte[1] { P_0 }; } public NullableAttribute(byte[] P_0) { NullableFlags = P_0; } } [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)] internal sealed class NullableContextAttribute : Attribute { public readonly byte Flag; public NullableContextAttribute(byte P_0) { Flag = P_0; } } [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)] internal sealed class RefSafetyRulesAttribute : Attribute { public readonly int Version; public RefSafetyRulesAttribute(int P_0) { Version = P_0; } } } namespace ObeliskRU { [BepInPlugin("obelisk.ru.localization", "ObeliskRU", "0.1.0")] [BepInDependency(/*Could not decode attribute arguments.*/)] [BepInDependency(/*Could not decode attribute arguments.*/)] [BepInDependency(/*Could not decode attribute arguments.*/)] [BepInDependency(/*Could not decode attribute arguments.*/)] [BepInDependency(/*Could not decode attribute arguments.*/)] [BepInDependency(/*Could not decode attribute arguments.*/)] [BepInDependency(/*Could not decode attribute arguments.*/)] [BepInDependency(/*Could not decode attribute arguments.*/)] [BepInDependency(/*Could not decode attribute arguments.*/)] [BepInDependency(/*Could not decode attribute arguments.*/)] [BepInDependency(/*Could not decode attribute arguments.*/)] [BepInDependency(/*Could not decode attribute arguments.*/)] [BepInDependency(/*Could not decode attribute arguments.*/)] [BepInDependency(/*Could not decode attribute arguments.*/)] [BepInDependency(/*Could not decode attribute arguments.*/)] [BepInDependency(/*Could not decode attribute arguments.*/)] [BepInDependency(/*Could not decode attribute arguments.*/)] [BepInDependency(/*Could not decode attribute arguments.*/)] [BepInDependency(/*Could not decode attribute arguments.*/)] [BepInDependency(/*Could not decode attribute arguments.*/)] [BepInDependency(/*Could not decode attribute arguments.*/)] [BepInDependency(/*Could not decode attribute arguments.*/)] [BepInDependency(/*Could not decode attribute arguments.*/)] [BepInDependency(/*Could not decode attribute arguments.*/)] [BepInDependency(/*Could not decode attribute arguments.*/)] [BepInDependency(/*Could not decode attribute arguments.*/)] public sealed class ObeliskRUPlugin : BaseUnityPlugin { private static readonly HashSet AddedLocalizationWordKeys = new HashSet(StringComparer.Ordinal); private const string BlacksmithingGuid = "org.bepinex.plugins.blacksmithing"; private const string CreatureLevelControlGuid = "org.bepinex.plugins.creaturelevelcontrol"; private const string CookingGuid = "org.bepinex.plugins.cooking"; private const string FarmingGuid = "org.bepinex.plugins.farming"; private const string InventorySlotsGuid = "sighsorry.InventorySlots"; private const string ImpactfulSkillsGuid = "MidnightsFX.ImpactfulSkills"; private const string CartographySkillGuid = "advize.CartographySkill"; private const string ValheimClockGuid = "com.orfox.valheimclock"; private const string MoreWorldLocationsAioGuid = "warpalicious.More_World_Locations_AIO"; private const string BalrondAmazingNatureGuid = "balrond.astafaraios.BalrondAmazingNature"; private const string BalrondArsenalRebornGuid = "balrond.astafaraios.ZBalrondArsenalReborn"; private const string BalrondConstructionsGuid = "balrond.astafaraios.BalrondConstructions"; private const string BalrondDualMasteryGuid = "balrond.astafaraios.BalrondDualMastery"; private const string BalrondFurnitureRebornGuid = "balrond.astafaraios.BalrondFurnitureReborn"; private const string BalrondLightkeeperGuid = "balrond.astafaraios.BalrondLightkeeper"; private const string BalrondMonsterMayhemGuid = "balrond.astafaraios.BalrondMonsterMayhem"; private const string BetterArcheryGuid = "ishid4.mods.betterarchery"; private const string OdinHorseGuid = "Raelaziel.OdinHorse"; private const string ValheimArmoryGuid = "MidnightsFX.ValheimArmory"; private const string ValheimGlidersGuid = "Yggdrah.ValheimGliders"; private const string XPortalGuid = "yay.spikehimself.xportal"; private const string CraftyCartsGuid = "Azumatt.CraftyCarts"; private const string CulinaryHorizonsGuid = "Insanity.Culinary_Horizons"; private const string EternalLegendsGuid = "Dreanegade.Eternal_Legends"; private const string HunterLegacyGuid = "Dreanegade.Hunter_Legacy"; private const string MagicSupremacyGuid = "Dreanegade.Magic_Supremacy"; private void Awake() { ApplyBlacksmithingLocalization(); ApplyValheimLocalizationWords(); ApplyCreatureLevelAndLootControlLocalization(); ApplyInventorySlotsSlotLabels(); ApplyCartographySkillTranspiler(); ApplyValheimClockTranspilers(); ApplyBalrondAmazingNatureLocalization(); ApplyBalrondArsenalRebornLocalization(); ApplyBalrondConstructionsLocalization(); ApplyBalrondDualMasteryLocalization(); ApplyBalrondFurnitureRebornLocalization(); ApplyBalrondLightkeeperLocalization(); ApplyBalrondMonsterMayhemLocalization(); ApplyBetterArcheryTranspilers(); ApplyOdinHorseTranspilers(); ApplyXPortalTranspilers(); ApplyMoreWorldLocationsTranspilers(); ApplyPieceManagerCategoryNormalizers(); } private void Start() { ApplyValheimLocalizationWords(); ApplyImpactfulSkillsLocalization(); ApplyValheimArmoryLocalization(); ApplyBalrondAmazingNatureLocalizationWords(); ApplyBalrondArsenalRebornLocalizationWords(); ApplyBalrondConstructionsLocalizationWords(); ApplyBalrondDualMasteryLocalizationWords(); ApplyBalrondDualMasterySkillLocalization(); ApplyBalrondFurnitureRebornLocalizationWords(); ApplyBalrondLightkeeperLocalizationWords(); ApplyBalrondMonsterMayhemLocalizationWords(); ApplyBetterArcheryLocalizationWords(); ApplyValheimGlidersLocalizationWords(); ApplyXPortalLocalizationWords(); ApplyCraftyCartsLocalizationWords(); ApplyMoreWorldLocationsLocalization(); ApplyMoreWorldLocationsTutorials(); } private void ApplyBlacksmithingLocalization() { if (!Chainloader.PluginInfos.TryGetValue("org.bepinex.plugins.blacksmithing", out var value)) { return; } if (!((((object)value.Instance).GetType().Assembly.GetType("SkillManager.Skill")?.GetField("skillByName", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic))?.GetValue(null) is IDictionary dictionary) || !dictionary.Contains("Blacksmithing")) { ((BaseUnityPlugin)this).Logger.LogWarning((object)"Blacksmithing found, but SkillManager data was not available. Block skipped."); return; } object obj = dictionary["Blacksmithing"]; if (obj == null) { ((BaseUnityPlugin)this).Logger.LogWarning((object)"Blacksmithing skill entry was empty. Block skipped."); return; } ApplySkillLocalization(obj, "Name", "Кузнечное дело"); ApplySkillLocalization(obj, "Description", "Повышает прочность созданных доспехов и оружия."); } private void ApplyValheimLocalizationWords() { bool flag = false; if (Chainloader.PluginInfos.ContainsKey("org.bepinex.plugins.cooking")) { flag |= AddLocalizationWordVariants(new string[2] { "skill_cooking", "skill_Cooking" }, "Готовка"); flag |= AddLocalizationWordVariants(new string[2] { "skilldesc_cooking", "skilldesc_Cooking" }, "Повышает пользу приготовленной еды: здоровье, выносливость, эйтр и восстановление здоровья."); } if (Chainloader.PluginInfos.ContainsKey("org.bepinex.plugins.farming")) { flag |= AddLocalizationWordVariants(new string[2] { "skill_farming", "skill_Farming" }, "Земледелие"); flag |= AddLocalizationWordVariants(new string[2] { "skilldesc_farming", "skilldesc_Farming" }, "Ускоряет рост посевов, повышает урожайность и снижает расход выносливости при посадке и сборе."); } if (flag) { ((BaseUnityPlugin)this).Logger.LogInfo((object)"Smoothbrain skill localization words registered."); } } private bool AddLocalizationWordVariants(IEnumerable keys, string russianText) { Type type = Type.GetType("Localization, Assembly-CSharp"); object obj = type?.GetProperty("instance", BindingFlags.Static | BindingFlags.Public)?.GetValue(null) ?? type?.GetField("m_instance", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic)?.GetValue(null); MethodInfo methodInfo = type?.GetMethod("AddWord", BindingFlags.Instance | BindingFlags.Public, null, new Type[2] { typeof(string), typeof(string) }, null); if (obj == null || methodInfo == null) { return false; } foreach (string key in keys) { methodInfo.Invoke(obj, new object[2] { key, russianText }); } return true; } private void ApplyBalrondAmazingNatureLocalization() { ApplyBalrondJsonLocalization("balrond.astafaraios.BalrondAmazingNature", "BalrondNature.BalrondTranslator", "BalrondAmazingNature"); } private void ApplyBalrondAmazingNatureLocalizationWords() { ApplyBalrondJsonLocalizationWords("balrond.astafaraios.BalrondAmazingNature", "BalrondAmazingNature"); } private void ApplyBalrondArsenalRebornLocalization() { ApplyBalrondJsonLocalization("balrond.astafaraios.ZBalrondArsenalReborn", "BalrondArsenalReborn.BalrondTranslator", "BalrondArsenalReborn"); } private void ApplyBalrondArsenalRebornLocalizationWords() { ApplyBalrondJsonLocalizationWords("balrond.astafaraios.ZBalrondArsenalReborn", "BalrondArsenalReborn"); } private void ApplyBalrondConstructionsLocalization() { ApplyBalrondJsonLocalization("balrond.astafaraios.BalrondConstructions", "BalrondConstructions.BalrondTranslator", "BalrondConstructions"); } private void ApplyBalrondConstructionsLocalizationWords() { ApplyBalrondJsonLocalizationWords("balrond.astafaraios.BalrondConstructions", "BalrondConstructions"); } private void ApplyBalrondDualMasteryLocalization() { ApplyBalrondJsonLocalization("balrond.astafaraios.BalrondDualMastery", "BalrondDualWield.BalrondTranslator", "BalrondDualMastery"); } private void ApplyBalrondDualMasteryLocalizationWords() { ApplyBalrondJsonLocalizationWords("balrond.astafaraios.BalrondDualMastery", "BalrondDualMastery"); } private void ApplyBalrondDualMasterySkillLocalization() { if (Chainloader.PluginInfos.TryGetValue("balrond.astafaraios.BalrondDualMastery", out var value) && (((object)value.Instance).GetType().Assembly.GetType("BalrondDualWield.DualWieldSkills")?.GetField("SkillsById", BindingFlags.Static | BindingFlags.NonPublic))?.GetValue(null) is IDictionary dictionary && dictionary.Contains(874298)) { object obj = dictionary[874298]; if (obj != null) { Type type = obj.GetType(); type.GetField("SkillName", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)?.SetValue(obj, "Парное оружие"); object obj2 = type.GetField("SkillDef", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)?.GetValue(obj); obj2?.GetType().GetField("m_description", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)?.SetValue(obj2, "Повышает эффективность атак второй рукой при использовании двух одноручных видов оружия."); AddLocalizationWords(new Dictionary { ["skill_874298"] = "Парное оружие", ["tag_dualwield_bal"] = "Парное оружие", ["tag_dualwield_bal_tooltip"] = "Повышает эффективность атак второй рукой при использовании двух одноручных видов оружия." }); } } } private void ApplyBalrondFurnitureRebornLocalization() { ApplyBalrondJsonLocalization("balrond.astafaraios.BalrondFurnitureReborn", "BalrondFurnitureReborn.BalrondTranslator", "BalrondFurnitureReborn"); } private void ApplyBalrondFurnitureRebornLocalizationWords() { ApplyBalrondJsonLocalizationWords("balrond.astafaraios.BalrondFurnitureReborn", "BalrondFurnitureReborn"); } private void ApplyBalrondLightkeeperLocalization() { ApplyBalrondJsonLocalization("balrond.astafaraios.BalrondLightkeeper", "LightController.BalrondTranslator", "BalrondLightkeeper"); } private void ApplyBalrondLightkeeperLocalizationWords() { ApplyBalrondJsonLocalizationWords("balrond.astafaraios.BalrondLightkeeper", "BalrondLightkeeper"); } private void ApplyBalrondMonsterMayhemLocalization() { ApplyBalrondJsonLocalization("balrond.astafaraios.BalrondMonsterMayhem", "BalrondExtendedAnimals.BalrondTranslator", "BalrondMonsterMayhem"); } private void ApplyBalrondMonsterMayhemLocalizationWords() { ApplyBalrondJsonLocalizationWords("balrond.astafaraios.BalrondMonsterMayhem", "BalrondMonsterMayhem"); } private void ApplyBetterArcheryLocalizationWords() { if (Chainloader.PluginInfos.ContainsKey("ishid4.mods.betterarchery")) { string path = Path.Combine(GetPluginDirectory(), "BetterArchery", "ishid4_translations.json"); if (!File.Exists(path)) { ((BaseUnityPlugin)this).Logger.LogWarning((object)"BetterArchery Russian localization file was not found. Block skipped."); return; } Dictionary dictionary = LoadFlatJsonDictionary(path); AddLocalizationWords(dictionary); ((BaseUnityPlugin)this).Logger.LogInfo((object)$"BetterArchery Russian localization words registered: {dictionary.Count}."); } } private void ApplyBalrondJsonLocalizationWords(string pluginGuid, string folderName) { if (Chainloader.PluginInfos.ContainsKey(pluginGuid)) { string path = Path.Combine(GetPluginDirectory(), folderName, "Russian.json"); if (File.Exists(path)) { Dictionary words = LoadFlatJsonDictionary(path); AddLocalizationWords(words); } } } private void ApplyValheimGlidersLocalizationWords() { if (Chainloader.PluginInfos.ContainsKey("Yggdrah.ValheimGliders")) { string path = Path.Combine(GetPluginDirectory(), "ValheimGliders", "Russian.json"); if (!File.Exists(path)) { ((BaseUnityPlugin)this).Logger.LogWarning((object)"ValheimGliders Russian localization file was not found. Block skipped."); return; } Dictionary dictionary = LoadFlatJsonDictionary(path); AddLocalizationWords(dictionary); ((BaseUnityPlugin)this).Logger.LogInfo((object)$"ValheimGliders Russian localization words registered: {dictionary.Count}."); } } private void ApplyXPortalLocalizationWords() { if (Chainloader.PluginInfos.ContainsKey("yay.spikehimself.xportal")) { string path = Path.Combine(GetPluginDirectory(), "XPortal", "Russian.json"); if (!File.Exists(path)) { ((BaseUnityPlugin)this).Logger.LogWarning((object)"XPortal Russian localization file was not found. Block skipped."); return; } Dictionary dictionary = LoadFlatJsonDictionary(path); AddLocalizationWords(dictionary); ((BaseUnityPlugin)this).Logger.LogInfo((object)$"XPortal Russian localization words registered: {dictionary.Count}."); } } private void ApplyCraftyCartsLocalizationWords() { if (Chainloader.PluginInfos.TryGetValue("Azumatt.CraftyCarts", out var value)) { Dictionary words = new Dictionary(StringComparer.Ordinal) { ["msg_cartupgraded"] = "$1 улучшена", ["msg_cantupgrade"] = "$1 нельзя улучшить", ["msg_maxlevel"] = "$1 уже максимального уровня", ["piece_upgradecart"] = "Улучшение телеги", ["piece_upgradecart_description"] = "Улучшает телегу до более высокого уровня.", ["piecemanager_cat_craftycarts"] = "Телеги-мастерские" }; AddLocalizationWords(words); int num = ApplyPieceManagerLocalizeKeyTranslations(((object)value.Instance).GetType().Assembly, words); ((BaseUnityPlugin)this).Logger.LogInfo((object)$"CraftyCarts Russian localization words registered. LocalizeKeys updated: {num}."); } } private static int ApplyPieceManagerLocalizeKeyTranslations(Assembly assembly, Dictionary words) { Type? type = assembly.GetType("PieceManager.LocalizeKey"); FieldInfo fieldInfo = type?.GetField("keys", BindingFlags.Static | BindingFlags.NonPublic); MethodInfo methodInfo = type?.GetMethod("Russian", BindingFlags.Instance | BindingFlags.Public); FieldInfo fieldInfo2 = type?.GetField("Key", BindingFlags.Instance | BindingFlags.Public); if (!(fieldInfo?.GetValue(null) is IEnumerable enumerable) || methodInfo == null || fieldInfo2 == null) { return 0; } int num = 0; foreach (object item in enumerable) { if (fieldInfo2.GetValue(item) is string key && words.TryGetValue(key, out string value)) { methodInfo.Invoke(item, new object[1] { value }); num++; } } return num; } private void ApplyBalrondJsonLocalization(string pluginGuid, string translatorTypeName, string folderName) { if (Chainloader.PluginInfos.TryGetValue(pluginGuid, out var value)) { string path = Path.Combine(GetPluginDirectory(), folderName, "Russian.json"); if (!File.Exists(path)) { ((BaseUnityPlugin)this).Logger.LogWarning((object)(folderName + " Russian localization file was not found. Block skipped.")); return; } if (!((((object)value.Instance).GetType().Assembly.GetType(translatorTypeName)?.GetField("translations", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic))?.GetValue(null) is IDictionary dictionary)) { ((BaseUnityPlugin)this).Logger.LogWarning((object)(folderName + " translator dictionary was not recognized. Block skipped.")); return; } Dictionary dictionary2 = (Dictionary)(dictionary["Russian"] = LoadFlatJsonDictionary(path)); ((BaseUnityPlugin)this).Logger.LogInfo((object)$"{folderName} Russian localization registered: {dictionary2.Count} words."); } } private static Dictionary LoadFlatJsonDictionary(string path) { return ParseFlatJsonDictionary(File.ReadAllText(path)); } private static Dictionary ParseFlatJsonDictionary(string json) { Dictionary dictionary = new Dictionary(StringComparer.Ordinal); int index = 0; SkipJsonWhitespace(json, ref index); ExpectJsonChar(json, ref index, '{'); while (true) { SkipJsonWhitespace(json, ref index); if (TryReadJsonChar(json, ref index, '}')) { break; } string key = ReadJsonString(json, ref index); SkipJsonWhitespace(json, ref index); ExpectJsonChar(json, ref index, ':'); SkipJsonWhitespace(json, ref index); string value = ReadJsonString(json, ref index); dictionary[key] = value; SkipJsonWhitespace(json, ref index); if (!TryReadJsonChar(json, ref index, ',')) { ExpectJsonChar(json, ref index, '}'); break; } } return dictionary; } private static void SkipJsonWhitespace(string json, ref int index) { while (index < json.Length && char.IsWhiteSpace(json[index])) { index++; } } private static bool TryReadJsonChar(string json, ref int index, char expected) { if (index < json.Length && json[index] == expected) { index++; return true; } return false; } private static void ExpectJsonChar(string json, ref int index, char expected) { if (!TryReadJsonChar(json, ref index, expected)) { throw new FormatException($"Expected JSON character '{expected}' at position {index}."); } } private static string ReadJsonString(string json, ref int index) { ExpectJsonChar(json, ref index, '"'); StringBuilder stringBuilder = new StringBuilder(); while (index < json.Length) { char c = json[index++]; switch (c) { case '"': return stringBuilder.ToString(); default: stringBuilder.Append(c); break; case '\\': { if (index >= json.Length) { throw new FormatException("Unexpected end of JSON escape sequence."); } char c2 = json[index++]; switch (c2) { case '"': case '/': case '\\': stringBuilder.Append(c2); break; case 'b': stringBuilder.Append('\b'); break; case 'f': stringBuilder.Append('\f'); break; case 'n': stringBuilder.Append('\n'); break; case 'r': stringBuilder.Append('\r'); break; case 't': stringBuilder.Append('\t'); break; case 'u': { if (index + 4 > json.Length) { throw new FormatException("Unexpected end of JSON unicode escape sequence."); } string value = json.Substring(index, 4); stringBuilder.Append((char)Convert.ToInt32(value, 16)); index += 4; break; } default: throw new FormatException($"Unsupported JSON escape sequence '\\{c2}' at position {index - 1}."); } break; } } } throw new FormatException("Unterminated JSON string."); } private void AddLocalizationWords(Dictionary words) { Type type = Type.GetType("Localization, Assembly-CSharp"); object obj = type?.GetProperty("instance", BindingFlags.Static | BindingFlags.Public)?.GetValue(null) ?? type?.GetField("m_instance", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic)?.GetValue(null); if (obj == null) { return; } if ((type?.GetField("m_translations", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic))?.GetValue(obj) is IDictionary dictionary) { { foreach (KeyValuePair word in words) { dictionary[word.Key] = word.Value; AddedLocalizationWordKeys.Add(word.Key); } return; } } MethodInfo methodInfo = type?.GetMethod("AddWord", BindingFlags.Instance | BindingFlags.Public, null, new Type[2] { typeof(string), typeof(string) }, null); if (methodInfo == null) { return; } foreach (KeyValuePair word2 in words) { if (AddedLocalizationWordKeys.Add(word2.Key)) { methodInfo.Invoke(obj, new object[2] { word2.Key, word2.Value }); } } } private void ApplyBetterArcheryTranspilers() { //IL_0070: Unknown result type (might be due to invalid IL or missing references) //IL_0076: Expected O, but got Unknown if (!Chainloader.PluginInfos.TryGetValue("ishid4.mods.betterarchery", out var value)) { return; } MethodInfo method = typeof(ObeliskRUPlugin).GetMethod("TranspileBetterArcheryStrings", BindingFlags.Static | BindingFlags.NonPublic); if (method == null) { ((BaseUnityPlugin)this).Logger.LogWarning((object)"BetterArchery transpiler was not available. Hardcoded string block skipped."); return; } string[] obj = new string[4] { "BetterArchery.ModifyOnSpawned", "BetterArchery.Character_OnDamaged_Patch", "BetterArchery.Humanoid_OnDamaged_Patch", "BetterArchery.TerminalAwake_Patch" }; Harmony harmony = new Harmony("obelisk.ru.localization.betterarchery"); int num = 0; string[] array = obj; foreach (string name in array) { Type type = ((object)value.Instance).GetType().Assembly.GetType(name); if (!(type == null)) { num += PatchBetterArcheryTypeStrings(type, harmony, method); Type[] nestedTypes = type.GetNestedTypes(BindingFlags.Public | BindingFlags.NonPublic); foreach (Type type2 in nestedTypes) { num += PatchBetterArcheryTypeStrings(type2, harmony, method); } } } ((BaseUnityPlugin)this).Logger.LogInfo((object)$"BetterArchery hardcoded string transpilers applied: {num} methods."); } private static int PatchBetterArcheryTypeStrings(Type type, Harmony harmony, MethodInfo transpiler) { //IL_0030: Unknown result type (might be due to invalid IL or missing references) //IL_003c: Expected O, but got Unknown int num = 0; MethodInfo[] methods = type.GetMethods(BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); foreach (MethodInfo methodInfo in methods) { if (!methodInfo.IsAbstract && !methodInfo.ContainsGenericParameters && methodInfo.GetMethodBody() != null) { harmony.Patch((MethodBase)methodInfo, (HarmonyMethod)null, (HarmonyMethod)null, new HarmonyMethod(transpiler), (HarmonyMethod)null, (HarmonyMethod)null); num++; } } return num; } private static IEnumerable TranspileBetterArcheryStrings(IEnumerable instructions) { Dictionary replacements = new Dictionary(StringComparer.Ordinal) { ["Thank you for using this mod! Don't forget to change configurations to get your own taste!"] = "Спасибо за использование BetterArchery. Настройте мод под свой стиль игры в конфигурации.", ["Welcome to BetterArchery"] = "Добро пожаловать в BetterArchery", ["Sneak attack for {0}X ({1}) damage!"] = "Скрытая атака: {0}x ({1}) урона!", ["Syntax: ba [action]"] = "Синтаксис: ba [действие]", ["Better Archery Reloaded."] = "BetterArchery перезагружен." }; foreach (CodeInstruction instruction in instructions) { if (instruction.opcode == OpCodes.Ldstr && instruction.operand is string key && replacements.TryGetValue(key, out string value)) { instruction.operand = value; } yield return instruction; } } private void ApplyOdinHorseTranspilers() { //IL_007f: Unknown result type (might be due to invalid IL or missing references) //IL_0085: Expected O, but got Unknown if (!Chainloader.PluginInfos.TryGetValue("Raelaziel.OdinHorse", out var value)) { return; } MethodInfo method = typeof(ObeliskRUPlugin).GetMethod("TranspileOdinHorseStrings", BindingFlags.Static | BindingFlags.NonPublic); if (method == null) { ((BaseUnityPlugin)this).Logger.LogWarning((object)"OdinHorse transpiler was not available. Hardcoded string block skipped."); return; } Type type = ((object)value.Instance).GetType().Assembly.GetType("OdinHorse.OdinHorse"); if (type == null) { ((BaseUnityPlugin)this).Logger.LogWarning((object)"OdinHorse type was not recognized. Hardcoded string block skipped."); return; } Harmony harmony = new Harmony("obelisk.ru.localization.odinhorse"); int num = 0; Type[] nestedTypes = type.GetNestedTypes(BindingFlags.Public | BindingFlags.NonPublic); foreach (Type type2 in nestedTypes) { string name = type2.Name; if (name.IndexOf("AddTextForRemovalOfArmorTameableGetHoverTextPatch", StringComparison.Ordinal) >= 0 || name.IndexOf("SaddlebagHoverTextPatch", StringComparison.Ordinal) >= 0) { num += PatchDeclaredMethods(type2, harmony, method); } } ((BaseUnityPlugin)this).Logger.LogInfo((object)$"OdinHorse hardcoded string transpilers applied: {num} methods."); } private static int PatchDeclaredMethods(Type type, Harmony harmony, MethodInfo transpiler) { //IL_0030: Unknown result type (might be due to invalid IL or missing references) //IL_003c: Expected O, but got Unknown int num = 0; MethodInfo[] methods = type.GetMethods(BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); foreach (MethodInfo methodInfo in methods) { if (!methodInfo.IsAbstract && !methodInfo.ContainsGenericParameters && methodInfo.GetMethodBody() != null) { harmony.Patch((MethodBase)methodInfo, (HarmonyMethod)null, (HarmonyMethod)null, new HarmonyMethod(transpiler), (HarmonyMethod)null, (HarmonyMethod)null); num++; } } return num; } private static IEnumerable TranspileOdinHorseStrings(IEnumerable instructions) { Dictionary replacements = new Dictionary(StringComparer.Ordinal) { ["Remove Armor"] = "Снять броню", ["Wait Here"] = "Ждать здесь", ["Resume"] = "Следовать", ["Open Saddlebags"] = "Открыть седельные сумки" }; foreach (CodeInstruction instruction in instructions) { if (instruction.opcode == OpCodes.Ldstr && instruction.operand is string key && replacements.TryGetValue(key, out string value)) { instruction.operand = value; } yield return instruction; } } private void ApplyPieceManagerCategoryNormalizers() { ApplyPieceManagerCategoryNormalizer("Azumatt.CraftyCarts", "CraftyCarts"); ApplyPieceManagerCategoryNormalizer("Insanity.Culinary_Horizons", "Culinary Horizons"); ApplyPieceManagerCategoryNormalizer("Dreanegade.Eternal_Legends", "Eternal Legends"); ApplyPieceManagerCategoryNormalizer("Dreanegade.Hunter_Legacy", "Hunter Legacy"); ApplyPieceManagerCategoryNormalizer("Dreanegade.Magic_Supremacy", "Magic Supremacy"); } private void ApplyPieceManagerCategoryNormalizer(string pluginGuid, string logName) { //IL_008b: Unknown result type (might be due to invalid IL or missing references) //IL_0092: Unknown result type (might be due to invalid IL or missing references) //IL_00a0: Expected O, but got Unknown if (Chainloader.PluginInfos.TryGetValue(pluginGuid, out var value)) { Assembly assembly = ((object)value.Instance).GetType().Assembly; MethodInfo methodInfo = assembly.GetType("PieceManager.PiecePrefabManager")?.GetMethod("GetCategory", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); MethodInfo method = typeof(ObeliskRUPlugin).GetMethod("NormalizePieceManagerCategoryArgument", BindingFlags.Static | BindingFlags.NonPublic); if (methodInfo == null || method == null) { ((BaseUnityPlugin)this).Logger.LogWarning((object)(logName + " PieceManager category method was not recognized. Category block skipped.")); return; } new Harmony("obelisk.ru.localization.categories." + pluginGuid).Patch((MethodBase)methodInfo, new HarmonyMethod(method), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); int num = RewriteRegisteredBuildPieceCategoryCustoms(assembly); ((BaseUnityPlugin)this).Logger.LogInfo((object)$"{logName} build categories normalized. Registered pieces updated: {num}."); } } private static void NormalizePieceManagerCategoryArgument(ref string name) { name = NormalizePieceManagerCategoryName(name); } private static int RewriteRegisteredBuildPieceCategoryCustoms(Assembly assembly) { Type? type = assembly.GetType("PieceManager.BuildPiece"); FieldInfo fieldInfo = type?.GetField("registeredPieces", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); FieldInfo fieldInfo2 = type?.GetField("Category", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); if (!(fieldInfo?.GetValue(null) is IEnumerable enumerable) || fieldInfo2 == null) { return 0; } int num = 0; foreach (object item in enumerable) { object value = fieldInfo2.GetValue(item); FieldInfo fieldInfo3 = value?.GetType().GetField("custom", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); if (fieldInfo3?.GetValue(value) is string text) { string text2 = NormalizePieceManagerCategoryName(text); if (!(text2 == text)) { fieldInfo3.SetValue(value, text2); num++; } } } return num; } private static string NormalizePieceManagerCategoryName(string name) { return name switch { "Crafty Carts" => "Телеги-мастерские", "Distant Origins" => "Древние истоки", "Distant Origins Decor" => "Декор древних истоков", "Culinary Horizons" => "Кулинарные горизонты", _ => name, }; } private void ApplyXPortalTranspilers() { //IL_00a9: Unknown result type (might be due to invalid IL or missing references) //IL_00ae: Unknown result type (might be due to invalid IL or missing references) //IL_00b3: Unknown result type (might be due to invalid IL or missing references) //IL_00bf: Expected O, but got Unknown //IL_00c4: Unknown result type (might be due to invalid IL or missing references) //IL_00d0: Expected O, but got Unknown if (Chainloader.PluginInfos.TryGetValue("yay.spikehimself.xportal", out var value)) { Assembly assembly = ((object)value.Instance).GetType().Assembly; MethodInfo method = typeof(ObeliskRUPlugin).GetMethod("TranspileXPortalStrings", BindingFlags.Static | BindingFlags.NonPublic); MethodInfo methodInfo = assembly.GetType("XPortal.XPortal")?.GetMethod("OnPrePortalHover", BindingFlags.Static | BindingFlags.NonPublic); MethodInfo methodInfo2 = assembly.GetType("XPortal.Patches.TeleportWorld_GetHoverText")?.GetMethod("Prefix", BindingFlags.Static | BindingFlags.NonPublic); if (method == null || methodInfo == null || methodInfo2 == null) { ((BaseUnityPlugin)this).Logger.LogWarning((object)"XPortal methods were not recognized. Hardcoded string block skipped."); return; } Harmony val = new Harmony("obelisk.ru.localization.xportal"); val.Patch((MethodBase)methodInfo, (HarmonyMethod)null, (HarmonyMethod)null, new HarmonyMethod(method), (HarmonyMethod)null, (HarmonyMethod)null); val.Patch((MethodBase)methodInfo2, (HarmonyMethod)null, (HarmonyMethod)null, new HarmonyMethod(method), (HarmonyMethod)null, (HarmonyMethod)null); ((BaseUnityPlugin)this).Logger.LogInfo((object)"XPortal hardcoded string transpilers applied."); } } private static IEnumerable TranspileXPortalStrings(IEnumerable instructions) { Dictionary replacements = new Dictionary(StringComparer.Ordinal) { ["Fetching portal info..."] = "Получение сведений о портале...", ["This portal doesn't actually appear to exist. Heimdallr sees you..."] = "Похоже, этого портала на самом деле не существует. Хеймдалль видит тебя..." }; foreach (CodeInstruction instruction in instructions) { if (instruction.opcode == OpCodes.Ldstr && instruction.operand is string key && replacements.TryGetValue(key, out string value)) { instruction.operand = value; } yield return instruction; } } private void ApplyImpactfulSkillsLocalization() { ApplyJotunnJsonLocalization("MidnightsFX.ImpactfulSkills", "ImpactfulSkills", "ImpactfulSkills"); } private void ApplyValheimArmoryLocalization() { ApplyJotunnJsonLocalization("MidnightsFX.ValheimArmory", "ValheimArmory", "ValheimArmory"); } private void ApplyJotunnJsonLocalization(string pluginGuid, string folderName, string logName) { if (Chainloader.PluginInfos.ContainsKey(pluginGuid)) { string path = Path.Combine(GetPluginDirectory(), folderName, "Russian.json"); if (!File.Exists(path)) { ((BaseUnityPlugin)this).Logger.LogWarning((object)(logName + " Russian localization file was not found. Block skipped.")); return; } Dictionary dictionary = LoadFlatJsonDictionary(path); AddLocalizationWords(dictionary); ((BaseUnityPlugin)this).Logger.LogInfo((object)$"{logName} Russian localization words registered: {dictionary.Count}."); } } private void ApplyValheimClockTranspilers() { //IL_00c1: Unknown result type (might be due to invalid IL or missing references) //IL_00c6: Unknown result type (might be due to invalid IL or missing references) //IL_00cb: Unknown result type (might be due to invalid IL or missing references) //IL_00d7: Expected O, but got Unknown //IL_00dd: Unknown result type (might be due to invalid IL or missing references) //IL_00e9: Expected O, but got Unknown if (Chainloader.PluginInfos.TryGetValue("com.orfox.valheimclock", out var value)) { Type? type = ((object)value.Instance).GetType().Assembly.GetType("ClockMod.MinimapPatches"); MethodInfo methodInfo = type?.GetMethod("Update_Postfix", BindingFlags.Static | BindingFlags.Public); MethodInfo methodInfo2 = type?.GetMethod("TranslateWeather", BindingFlags.Static | BindingFlags.NonPublic); MethodInfo method = typeof(ObeliskRUPlugin).GetMethod("TranspileValheimClockDay", BindingFlags.Static | BindingFlags.NonPublic); MethodInfo method2 = typeof(ObeliskRUPlugin).GetMethod("TranspileValheimClockWeather", BindingFlags.Static | BindingFlags.NonPublic); if (methodInfo == null || methodInfo2 == null || method == null || method2 == null) { ((BaseUnityPlugin)this).Logger.LogWarning((object)"ValheimClock methods were not recognized. Clock block skipped."); return; } Harmony val = new Harmony("obelisk.ru.localization.valheimclock"); val.Patch((MethodBase)methodInfo, (HarmonyMethod)null, (HarmonyMethod)null, new HarmonyMethod(method), (HarmonyMethod)null, (HarmonyMethod)null); val.Patch((MethodBase)methodInfo2, (HarmonyMethod)null, (HarmonyMethod)null, new HarmonyMethod(method2), (HarmonyMethod)null, (HarmonyMethod)null); ((BaseUnityPlugin)this).Logger.LogInfo((object)"ValheimClock Russian clock transpilers applied."); } } private static IEnumerable TranspileValheimClockDay(IEnumerable instructions) { foreach (CodeInstruction instruction in instructions) { if (instruction.opcode == OpCodes.Ldstr && instruction.operand as string == "Day {1}{2}{3}{4}") { instruction.operand = "День {1}{2}{3}{4}"; } yield return instruction; } } private static IEnumerable TranspileValheimClockWeather(IEnumerable instructions) { Dictionary dictionary = new Dictionary(StringComparer.Ordinal) { ["Clear Skies"] = "Ясно", ["Light Rain"] = "Лёгкий дождь", ["Raining"] = "Дождь", ["Thunderstorm"] = "Гроза", ["Snowing"] = "Снег", ["Warm Snow"] = "Тёплый снег", ["Warm Snowstorm"] = "Тёплая метель", ["Blizzard"] = "Метель", ["Ash Rain"] = "Пепельный дождь", ["Ash Clear"] = "Ясно в Пепельных землях", ["Cinder Rain"] = "Дождь из углей", ["Meteor Shower"] = "Метеоритный дождь", ["Ashlands Fog"] = "Туман Пепельных земель", ["Ashlands Storm"] = "Буря Пепельных земель", ["Ashlands Seastorm"] = "Морская буря Пепельных земель", ["Mistlands Dark"] = "Тьма Туманных земель", ["Mislands Clear"] = "Ясно в Туманных землях", ["Mistlands Rain"] = "Дождь в Туманных землях", ["Mistlands Thunder"] = "Гроза в Туманных землях", ["Twilight Clear"] = "Сумеречное ясное небо", ["Twilight Snow"] = "Сумеречный снег", ["Twilight Snowstorm"] = "Сумеречная метель", ["Black Forest Fog"] = "Туман Чёрного леса", ["Swamp Rain"] = "Болотный дождь", ["Freezing"] = "Мороз", ["Sunken Crypt"] = "Затопленный склеп", ["Crypt"] = "Склеп", ["Crypt Hildir"] = "Склеп Хильдир", ["Infected Mine"] = "Заражённая шахта", ["Night Frost"] = "Ночной мороз", ["Queen's Jam"] = "Морок Королевы", ["Eikthyr's Thunderstorm"] = "Гроза Эйктюра", ["The Elder's Haze"] = "Мгла Древнего", ["Bonemass' Downpour"] = "Ливень Массы Костей", ["Moder's Vortex"] = "Вихрь Моудер", ["Yagluth's Magic Blizzard"] = "Магическая метель Яглута", ["Plains Fog"] = "Туман равнин", ["Ocean Fog"] = "Морской туман", ["Fog"] = "Туман" }; List list = instructions.ToList(); for (int i = 0; i < list.Count - 1; i++) { if (!(list[i].opcode != OpCodes.Ldstr) && !(list[i + 1].opcode != OpCodes.Ret) && list[i].operand is string key && dictionary.TryGetValue(key, out var value)) { list[i].operand = value; } } return list; } private void ApplyCartographySkillTranspiler() { //IL_0081: Unknown result type (might be due to invalid IL or missing references) //IL_008a: Unknown result type (might be due to invalid IL or missing references) //IL_0096: Expected O, but got Unknown if (Chainloader.PluginInfos.TryGetValue("advize.CartographySkill", out var value)) { MethodInfo methodInfo = ((object)value.Instance).GetType().Assembly.GetType("Advize_CartographySkill.CartographySkill")?.GetMethod("UpdateLocalization", BindingFlags.Static | BindingFlags.NonPublic); MethodInfo method = typeof(ObeliskRUPlugin).GetMethod("TranspileCartographySkillLocalization", BindingFlags.Static | BindingFlags.NonPublic); if (methodInfo == null || method == null) { ((BaseUnityPlugin)this).Logger.LogWarning((object)"CartographySkill localization method was not recognized. Cartography block skipped."); return; } new Harmony("obelisk.ru.localization.cartographyskill").Patch((MethodBase)methodInfo, (HarmonyMethod)null, (HarmonyMethod)null, new HarmonyMethod(method), (HarmonyMethod)null, (HarmonyMethod)null); ((BaseUnityPlugin)this).Logger.LogInfo((object)"CartographySkill Russian localization transpiler applied."); } } private static IEnumerable TranspileCartographySkillLocalization(IEnumerable instructions) { foreach (CodeInstruction instruction in instructions) { if ((instruction.opcode == OpCodes.Call || instruction.opcode == OpCodes.Callvirt) && instruction.operand is MethodInfo methodInfo && methodInfo.DeclaringType?.FullName == "Advize_CartographySkill.ModConfig") { if (methodInfo.Name == "get_SkillDescription") { yield return new CodeInstruction(OpCodes.Pop, (object)null); yield return new CodeInstruction(OpCodes.Ldstr, (object)"Увеличивает радиус разведки карты."); continue; } if (methodInfo.Name == "get_SkillName") { yield return new CodeInstruction(OpCodes.Pop, (object)null); yield return new CodeInstruction(OpCodes.Ldstr, (object)"Картография"); continue; } } yield return instruction; } } private void ApplyMoreWorldLocationsTranspilers() { //IL_00d3: Unknown result type (might be due to invalid IL or missing references) //IL_00da: Expected O, but got Unknown //IL_00e1: Unknown result type (might be due to invalid IL or missing references) //IL_00ed: Expected O, but got Unknown //IL_00f5: Unknown result type (might be due to invalid IL or missing references) //IL_0101: Expected O, but got Unknown Assembly loadedOrLoadPluginAssembly = GetLoadedOrLoadPluginAssembly("warpalicious.More_World_Locations_AIO", "More_World_Locations_AIO", "More_World_Locations_AIO.dll"); if (!(loadedOrLoadPluginAssembly == null)) { Type type = loadedOrLoadPluginAssembly.GetType("More_World_Locations_AIO.PortInit"); Type? type2 = loadedOrLoadPluginAssembly.GetType("More_World_Locations_AIO.MWLLocalizations"); MethodInfo methodInfo = type?.GetMethod("SetupManifests", BindingFlags.Static | BindingFlags.NonPublic); MethodInfo methodInfo2 = type2?.GetMethod("Load", BindingFlags.Static | BindingFlags.Public); MethodInfo method = typeof(ObeliskRUPlugin).GetMethod("TranspileMoreWorldLocationsManifests", BindingFlags.Static | BindingFlags.NonPublic); MethodInfo method2 = typeof(ObeliskRUPlugin).GetMethod("TranspileMoreWorldLocationsLocalizationLoad", BindingFlags.Static | BindingFlags.NonPublic); if (type == null || methodInfo == null || methodInfo2 == null || method == null || method2 == null) { ((BaseUnityPlugin)this).Logger.LogWarning((object)"More World Locations AIO localization methods were not recognized. MWL block skipped."); return; } Harmony val = new Harmony("obelisk.ru.localization.moreworldlocations"); val.Patch((MethodBase)methodInfo, (HarmonyMethod)null, (HarmonyMethod)null, new HarmonyMethod(method), (HarmonyMethod)null, (HarmonyMethod)null); val.Patch((MethodBase)methodInfo2, (HarmonyMethod)null, (HarmonyMethod)null, new HarmonyMethod(method2), (HarmonyMethod)null, (HarmonyMethod)null); int num = PatchMoreWorldLocationsManifestCreationMethods(type, val, method); ((BaseUnityPlugin)this).Logger.LogInfo((object)$"More World Locations AIO transpilers applied. Manifest methods patched: {num}."); } } private static int PatchMoreWorldLocationsManifestCreationMethods(Type portInitType, Harmony harmony, MethodInfo manifestTranspiler) { //IL_0052: Unknown result type (might be due to invalid IL or missing references) //IL_005e: Expected O, but got Unknown int num = 0; Type[] nestedTypes = portInitType.GetNestedTypes(BindingFlags.Public | BindingFlags.NonPublic); for (int i = 0; i < nestedTypes.Length; i++) { MethodInfo[] methods = nestedTypes[i].GetMethods(BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); foreach (MethodInfo methodInfo in methods) { if (!methodInfo.IsAbstract && !methodInfo.ContainsGenericParameters && methodInfo.Name.IndexOf("SetupManifests", StringComparison.Ordinal) >= 0) { harmony.Patch((MethodBase)methodInfo, (HarmonyMethod)null, (HarmonyMethod)null, new HarmonyMethod(manifestTranspiler), (HarmonyMethod)null, (HarmonyMethod)null); num++; } } } return num; } private static Assembly? GetLoadedOrLoadPluginAssembly(string pluginGuid, string assemblyName, string dllName) { Assembly loadedPluginAssembly = GetLoadedPluginAssembly(pluginGuid, assemblyName); if (loadedPluginAssembly != null) { return loadedPluginAssembly; } try { string text = Directory.GetFiles(Paths.PluginPath, dllName, SearchOption.AllDirectories).FirstOrDefault((string file) => file.IndexOf("More_World_Locations_AIO", StringComparison.OrdinalIgnoreCase) >= 0); return (text == null) ? null : Assembly.LoadFrom(text); } catch { return null; } } private static Assembly? GetLoadedPluginAssembly(string pluginGuid, string assemblyName) { if (Chainloader.PluginInfos.TryGetValue(pluginGuid, out var value) && (Object)(object)value.Instance != (Object)null) { return ((object)value.Instance).GetType().Assembly; } return AppDomain.CurrentDomain.GetAssemblies().FirstOrDefault((Assembly assembly) => string.Equals(assembly.GetName().Name, assemblyName, StringComparison.Ordinal)); } private static IEnumerable TranspileMoreWorldLocationsManifests(IEnumerable instructions) { Dictionary manifests = new Dictionary(StringComparer.Ordinal) { ["Wooden Shipment"] = "Грузовой деревянный сундук", ["Barrel Shipment"] = "Грузовая бочка", ["Fine Shipment"] = "Грузовой добротный сундук", ["Fuling Shipment"] = "Грузовой сундук фулингов", ["Dvergr Shipment"] = "Грузовой сундук двергров" }; foreach (CodeInstruction instruction in instructions) { if (instruction.opcode == OpCodes.Ldstr && instruction.operand is string key && manifests.TryGetValue(key, out string value)) { instruction.operand = value; } yield return instruction; } } private static IEnumerable TranspileMoreWorldLocationsLocalizationLoad(IEnumerable instructions) { MethodInfo addRussianLocalization = typeof(ObeliskRUPlugin).GetMethod("AddMoreWorldLocationsRussianLocalization", BindingFlags.Static | BindingFlags.NonPublic); bool inserted = false; foreach (CodeInstruction instruction in instructions) { yield return instruction; if (!inserted && !(addRussianLocalization == null) && !(instruction.opcode != OpCodes.Callvirt) && instruction.operand is MethodInfo { Name: "AddYamlFile" }) { yield return new CodeInstruction(OpCodes.Call, (object)addRussianLocalization); inserted = true; } } } private static void AddMoreWorldLocationsRussianLocalization() { string directoryName = Path.GetDirectoryName(typeof(ObeliskRUPlugin).Assembly.Location); if (directoryName == null) { return; } string path = Path.Combine(directoryName, "More_World_Locations_AIO", "warpalicious.More_World_Locations_Localization.Russian.yml"); if (!File.Exists(path)) { Console.WriteLine("[ObeliskRU] More World Locations AIO Russian localization file was not found. Block skipped."); return; } Type? type = Type.GetType("Jotunn.Managers.LocalizationManager, Jotunn"); object obj = type?.GetProperty("Instance", BindingFlags.Static | BindingFlags.Public)?.GetValue(null); object obj2 = type?.GetMethod("GetLocalization", BindingFlags.Instance | BindingFlags.Public)?.Invoke(obj, null); MethodInfo methodInfo = obj2?.GetType().GetMethod("AddYamlFile", new Type[2] { typeof(string), typeof(string) }); if (methodInfo == null) { Console.WriteLine("[ObeliskRU] Jotunn localization API was not available. More World Locations AIO block skipped."); return; } string text = File.ReadAllText(path); methodInfo.Invoke(obj2, new object[2] { "Russian", text }); Console.WriteLine("[ObeliskRU] More World Locations AIO Russian localization loaded."); } private void ApplyMoreWorldLocationsLocalization() { if (Chainloader.PluginInfos.ContainsKey("warpalicious.More_World_Locations_AIO") || !AppDomain.CurrentDomain.GetAssemblies().All((Assembly assembly) => assembly.GetName().Name != "More_World_Locations_AIO")) { AddMoreWorldLocationsRussianLocalization(); } } private void ApplySkillLocalization(object skill, string fieldName, string russianText) { object obj = skill.GetType().GetField(fieldName, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)?.GetValue(skill); MethodInfo methodInfo = obj?.GetType().GetMethod("Russian", BindingFlags.Instance | BindingFlags.Public); if (methodInfo == null) { ((BaseUnityPlugin)this).Logger.LogWarning((object)("Could not register Blacksmithing " + fieldName + " localization. Block skipped.")); return; } methodInfo.Invoke(obj, new object[1] { russianText }); } private void ApplyCreatureLevelAndLootControlLocalization() { if (!Chainloader.PluginInfos.TryGetValue("org.bepinex.plugins.creaturelevelcontrol", out var value)) { return; } string path = Path.Combine(GetPluginDirectory(), "CreatureLevelAndLootControl", "Russian.yml"); if (!File.Exists(path)) { ((BaseUnityPlugin)this).Logger.LogWarning((object)"Creature Level and Loot Control localization file was not found. Block skipped."); return; } Assembly assembly = ((object)value.Instance).GetType().Assembly; Type type = assembly.GetType("CreatureLevelControl.LocalizationWrapper"); Type type2 = assembly.GetType("YamlDotNet.Serialization.DeserializerBuilder"); if (type == null || type2 == null) { ((BaseUnityPlugin)this).Logger.LogWarning((object)"Creature Level and Loot Control localization types were not available. Block skipped."); return; } object obj = Activator.CreateInstance(type2, nonPublic: true); object obj2 = type2.GetMethod("Build", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)?.Invoke(obj, null); MethodInfo methodInfo = obj2?.GetType().GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic).FirstOrDefault(delegate(MethodInfo method) { if (method.Name != "Deserialize" || method.IsGenericMethod) { return false; } ParameterInfo[] parameters = method.GetParameters(); return parameters.Length == 2 && parameters[0].ParameterType == typeof(TextReader) && parameters[1].ParameterType == typeof(Type); }); FieldInfo field = type.GetField("instance", BindingFlags.Static | BindingFlags.NonPublic); FieldInfo field2 = type.GetField("language", BindingFlags.Instance | BindingFlags.NonPublic); if (methodInfo == null || field == null || field2 == null) { ((BaseUnityPlugin)this).Logger.LogWarning((object)"Creature Level and Loot Control localization internals were not available. Block skipped."); return; } using StreamReader streamReader = new StreamReader(path); object obj3 = methodInfo.Invoke(obj2, new object[2] { streamReader, type }); if (obj3 == null) { ((BaseUnityPlugin)this).Logger.LogWarning((object)"Creature Level and Loot Control localization file could not be read. Block skipped."); return; } field2.SetValue(obj3, "Russian"); field.SetValue(null, obj3); ((BaseUnityPlugin)this).Logger.LogInfo((object)"Creature Level and Loot Control Russian localization loaded."); } private void ApplyInventorySlotsSlotLabels() { if (!Chainloader.PluginInfos.TryGetValue("sighsorry.InventorySlots", out var value)) { return; } Assembly assembly = ((object)value.Instance).GetType().Assembly; Type type = assembly.GetType("InventorySlots.InventorySlotsPlugin"); Type type2 = assembly.GetType("InventorySlots.SlotDefinition"); Type type3 = assembly.GetType("InventorySlots.SlotKind"); if (!((type?.GetProperty("SlotDefinitions", BindingFlags.Static | BindingFlags.NonPublic))?.GetValue(null) is IList list) || type2 == null || type3 == null) { ((BaseUnityPlugin)this).Logger.LogWarning((object)"InventorySlots slot definitions were not available. Slot label block skipped."); return; } FieldInfo field = type2.GetField("_accepts", BindingFlags.Instance | BindingFlags.NonPublic); PropertyInfo property = type2.GetProperty("Id", BindingFlags.Instance | BindingFlags.Public); PropertyInfo property2 = type2.GetProperty("Name", BindingFlags.Instance | BindingFlags.Public); PropertyInfo property3 = type2.GetProperty("Kind", BindingFlags.Instance | BindingFlags.Public); PropertyInfo property4 = type2.GetProperty("QuickSlotIndex", BindingFlags.Instance | BindingFlags.Public); if (field == null || property == null || property2 == null || property3 == null || property4 == null) { ((BaseUnityPlugin)this).Logger.LogWarning((object)"InventorySlots slot definition shape was not recognized. Slot label block skipped."); return; } ConstructorInfo constructor = type2.GetConstructor(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, new Type[5] { typeof(string), typeof(string), type3, field.FieldType, typeof(int) }, null); if (constructor == null) { ((BaseUnityPlugin)this).Logger.LogWarning((object)"InventorySlots slot definition constructor was not available. Slot label block skipped."); return; } Dictionary dictionary = new Dictionary(StringComparer.OrdinalIgnoreCase) { ["helmet"] = ("Helmet", "Шлем"), ["chest"] = ("Chest", "Нагрудник"), ["legs"] = ("Legs", "Поножи"), ["cape"] = ("Cape", "Плащ"), ["utility"] = ("Utility", "Аксессуар"), ["trinket"] = ("Trinket", "Талисман"), ["circlet"] = ("Circlet", "Венец"), ["wishbone"] = ("Wishbone", "Дужка"), ["demister"] = ("Demister", "Висп"), ["jewelcrafting.necklace"] = ("Necklace", "Ожерелье"), ["jewelcrafting.ring"] = ("Ring", "Кольцо"), ["smoothbrainbackpacks.backpack"] = ("Backpack", "Рюкзак"), ["adventurebackpacks.backpack"] = ("Backpack", "Рюкзак"), ["rustybags.bag"] = ("Bag", "Сумка"), ["rustybags.quiver"] = ("Quiver", "Колчан"), ["magicsupremacy.belt"] = ("MagicBelt", "Магический пояс") }; int num = 0; for (int i = 0; i < list.Count; i++) { object obj = list[i]; if (obj == null) { continue; } string text = property.GetValue(obj) as string; string text2 = property2.GetValue(obj) as string; if (text != null && text2 != null && dictionary.TryGetValue(text, out var value2) && string.Equals(text2, value2.Item1, StringComparison.OrdinalIgnoreCase)) { object value3 = property3.GetValue(obj); object value4 = field.GetValue(obj); object value5 = property4.GetValue(obj); if (value3 != null && value4 != null && value5 != null) { list[i] = constructor.Invoke(new object[5] { text, value2.Item2, value3, value4, value5 }); num++; } } } if (num > 0) { ((BaseUnityPlugin)this).Logger.LogInfo((object)$"InventorySlots Russian slot labels applied: {num}."); } } private void ApplyMoreWorldLocationsTutorials() { Assembly loadedPluginAssembly = GetLoadedPluginAssembly("warpalicious.More_World_Locations_AIO", "More_World_Locations_AIO"); if (loadedPluginAssembly == null) { return; } Type? type = loadedPluginAssembly.GetType("More_World_Locations_AIO.tutorials.PortTutorial"); FieldInfo fieldInfo = type?.GetField("tutorials", BindingFlags.Static | BindingFlags.NonPublic); ConstructorInfo constructorInfo = type?.GetConstructor(BindingFlags.Instance | BindingFlags.NonPublic, null, new Type[2] { typeof(string), typeof(List) }, null); if (!(fieldInfo?.GetValue(null) is IList list) || constructorInfo == null) { ((BaseUnityPlugin)this).Logger.LogWarning((object)"More World Locations AIO tutorial data was not available. Tutorial block skipped."); return; } string path = Path.Combine(GetPluginDirectory(), "More_World_Locations_AIO", "Tutorials"); (string, string)[] array = new(string, string)[6] { ("Введение", "introduction.md"), ("Порт", "port.md"), ("Накладная", "manifest.md"), ("Отправка", "shipment.md"), ("Доставка", "delivery.md"), ("Телепорт", "teleport.md") }; (string, string)[] array2 = array; for (int i = 0; i < array2.Length; i++) { string item = array2[i].Item2; if (!File.Exists(Path.Combine(path, item))) { ((BaseUnityPlugin)this).Logger.LogWarning((object)"More World Locations AIO tutorial file was not found. Tutorial block skipped."); return; } } list.Clear(); array2 = array; for (int i = 0; i < array2.Length; i++) { (string, string) tuple = array2[i]; string item2 = tuple.Item1; string item3 = tuple.Item2; string path2 = Path.Combine(path, item3); constructorInfo.Invoke(new object[2] { item2, new List(File.ReadAllLines(path2)) }); } } private string GetPluginDirectory() { return Path.GetDirectoryName(((BaseUnityPlugin)this).Info.Location) ?? Paths.PluginPath; } } }