Decompiled source of ObeliskRU v0.2.11

BepInEx\plugins\ObeliskRU.dll

Decompiled 2 weeks ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Reflection.Emit;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using System.Text;
using System.Text.RegularExpressions;
using BepInEx;
using BepInEx.Bootstrap;
using BepInEx.Logging;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: AssemblyTitle("ObeliskRU")]
[assembly: AssemblyDescription("Russian localization pack for supported Valheim mods")]
[assembly: AssemblyCompany("DragonMotion")]
[assembly: AssemblyProduct("ObeliskRU")]
[assembly: ComVisible(false)]
[assembly: Guid("b86875d4-c679-42d2-a813-23c2b953502c")]
[assembly: AssemblyFileVersion("0.2.11.0")]
[assembly: AssemblyInformationalVersion("0.2.11")]
[assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")]
[assembly: AssemblyVersion("0.2.11.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 ObeliskRU
{
	internal static class AmazingNatureTutorialLocalization
	{
		internal const string HeaderToken = "$obelisk_ban_header";

		internal const string RecipeToken = "$obelisk_ban_recipes";

		private const string TokenPrefix = "$obelisk_ban_";

		private const string RawNamePrefix = "BAN conversions:";

		private const string RawTitlePrefix = "BAN-";

		private const string PatchedTitlePrefix = "Преобразования BAN — ";

		private static readonly IReadOnlyDictionary<string, string> Titles = new Dictionary<string, string>(StringComparer.Ordinal)
		{
			["eitrrefinery"] = "Очиститель эйтра",
			["composter_bal"] = "Компостер",
			["smelter"] = "Плавильня",
			["blastfurnace"] = "Доменная печь",
			["piece_sawmill_bal"] = "Лесопилка",
			["StoneboundKiln_bal"] = "Каменная углежоговая печь",
			["fermenter"] = "Бродильная бочка",
			["piece_oven"] = "Печь",
			["piece_cookingstation"] = "Стойка для готовки",
			["piece_cookingstation_iron"] = "Железная стойка для готовки",
			["piece_singleIronRack_bal"] = "Одинарная железная стойка для готовки",
			["piece_spinningwheel"] = "Прялка",
			["charcoal_kiln"] = "Угольная печь",
			["oilpress_bal"] = "Выжиматель"
		};

		private static readonly IReadOnlyDictionary<string, string> LegacyTitles = BuildLegacyTitles();

		internal static void AddWords(IDictionary<string, string> words)
		{
			words["$obelisk_ban_header".TrimStart(new char[1] { '$' })] = "УДИВИТЕЛЬНАЯ ПРИРОДА БАЛРОНДА:";
			words["$obelisk_ban_recipes".TrimStart(new char[1] { '$' })] = "Рецепты удивительной природы Балронда";
			foreach (KeyValuePair<string, string> title in Titles)
			{
				words[GetToken(title.Key).TrimStart(new char[1] { '$' })] = title.Value;
			}
		}

		internal static bool TryGetToken(string source, out string token)
		{
			token = null;
			string text = ExtractPrefabName(source);
			if (text == null)
			{
				return false;
			}
			if (string.Equals(text, "Recipes", StringComparison.Ordinal))
			{
				token = "$obelisk_ban_recipes";
				return true;
			}
			if (!Titles.ContainsKey(text))
			{
				return false;
			}
			token = GetToken(text);
			return true;
		}

		internal static bool IsCloneAlias(string source)
		{
			if (!string.IsNullOrEmpty(source))
			{
				return source.IndexOf("(Clone)", StringComparison.Ordinal) >= 0;
			}
			return false;
		}

		internal static bool TryGetLegacyTitleToken(string source, string body, out string token)
		{
			token = null;
			string text = NormalizeBody(body);
			if (string.IsNullOrEmpty(source) || string.IsNullOrEmpty(text) || text.IndexOf("$obelisk_ban_header", StringComparison.Ordinal) < 0 || !LegacyTitles.TryGetValue(source, out var value))
			{
				return false;
			}
			token = GetToken(value);
			return true;
		}

		internal static string NormalizeBody(string source)
		{
			return source?.Replace("BALROND AMAZING NATURE:", "$obelisk_ban_header").Replace("УДИВИТЕЛЬНАЯ ПРИРОДА БАЛРОНДА:", "$obelisk_ban_header").Replace("Удивительная природа Балронда:", "$obelisk_ban_header")
				.Replace("Stonebound Kiln accepts all items that Kiln does but requires fuel", "Каменная углежоговая печь принимает всё, что принимает обычная углежоговая печь, но требует топлива.")
				.Replace("Scrap does not go into Furnace/Smelter.  Can be only converted in Smeltworks station", "Лом нельзя помещать в плавильню или доменную печь. Его можно переработать только на металлургической станции.");
		}

		private static string GetToken(string prefabName)
		{
			return "$obelisk_ban_" + prefabName;
		}

		private static IReadOnlyDictionary<string, string> BuildLegacyTitles()
		{
			Dictionary<string, string> dictionary = new Dictionary<string, string>(StringComparer.Ordinal);
			foreach (KeyValuePair<string, string> title in Titles)
			{
				dictionary[title.Value] = title.Key;
			}
			dictionary["Переработчик эйтра"] = "eitrrefinery";
			dictionary["Каменная угольная печь"] = "StoneboundKiln_bal";
			dictionary["Костровая стойка"] = "piece_cookingstation";
			dictionary["Железная стойка"] = "piece_cookingstation_iron";
			dictionary["Малая железная стойка"] = "piece_singleIronRack_bal";
			dictionary["Маслопресс"] = "oilpress_bal";
			dictionary["Ферментер BAN"] = "fermenter";
			return dictionary;
		}

		private static string ExtractPrefabName(string source)
		{
			if (string.IsNullOrEmpty(source))
			{
				return null;
			}
			string text = source;
			if (text.StartsWith("$obelisk_ban_", StringComparison.Ordinal))
			{
				text = text.Substring("$obelisk_ban_".Length);
			}
			else if (text.StartsWith("BAN conversions:", StringComparison.Ordinal))
			{
				text = text.Substring("BAN conversions:".Length);
			}
			else if (text.StartsWith("Преобразования BAN — ", StringComparison.Ordinal))
			{
				text = text.Substring("Преобразования BAN — ".Length);
			}
			else if (text.StartsWith("BAN-", StringComparison.Ordinal))
			{
				text = text.Substring("BAN-".Length);
			}
			else
			{
				if (!string.Equals(text, "BAN Recipes", StringComparison.Ordinal) && !string.Equals(text, "Рецепты BAN", StringComparison.Ordinal))
				{
					return null;
				}
				text = "Recipes";
			}
			while (text.EndsWith("(Clone)", StringComparison.Ordinal))
			{
				text = text.Substring(0, text.Length - "(Clone)".Length);
			}
			return text;
		}
	}
	internal sealed class AmazingNatureTutorialPatcher
	{
		private const string PluginGuid = "balrond.astafaraios.BalrondAmazingNature";

		private const string OptimizerHarmonyId = "dragonmotion.balrondnatureoptimizer";

		private const string HarmonyId = "obelisk.ru.localization.amazing-nature-tutorial";

		private readonly Harmony _harmony = new Harmony("obelisk.ru.localization.amazing-nature-tutorial");

		private readonly ManualLogSource _log;

		internal AmazingNatureTutorialPatcher(ManualLogSource log)
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_0010: Expected O, but got Unknown
			_log = log;
		}

		internal int Apply()
		{
			Assembly pluginAssembly = ManagerAdapters.GetPluginAssembly("balrond.astafaraios.BalrondAmazingNature");
			if (pluginAssembly == null)
			{
				return 0;
			}
			return 0 + PatchDuplicateGuard(pluginAssembly) + PatchTutorialFinalizer();
		}

		private int PatchDuplicateGuard(Assembly assembly)
		{
			//IL_0078: Unknown result type (might be due to invalid IL or missing references)
			//IL_0086: Expected O, but got Unknown
			MethodInfo methodInfo = assembly?.GetType("BalrondNature.ConversionChanges")?.GetMethods(BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic).FirstOrDefault((MethodInfo method) => method.Name == "buildConversionStationTutorialTag" && method.GetParameters().Length == 3);
			MethodInfo methodInfo2 = AccessTools.Method(typeof(AmazingNatureTutorialPatcher), "AllowTutorial", (Type[])null, (Type[])null);
			if (methodInfo == null || methodInfo2 == null)
			{
				return 0;
			}
			try
			{
				_harmony.Patch((MethodBase)methodInfo, new HarmonyMethod(methodInfo2), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
				return 1;
			}
			catch (Exception ex)
			{
				_log.LogWarning((object)("Amazing Nature duplicate-tutorial guard skipped: " + ex.GetBaseException().Message));
				return 0;
			}
		}

		private int PatchTutorialFinalizer()
		{
			//IL_0054: Unknown result type (might be due to invalid IL or missing references)
			//IL_005a: Expected O, but got Unknown
			MethodInfo methodInfo = AccessTools.Method(typeof(Tutorial), "Awake", (Type[])null, (Type[])null);
			MethodInfo methodInfo2 = AccessTools.Method(typeof(AmazingNatureTutorialPatcher), "NormalizeTutorialTexts", (Type[])null, (Type[])null);
			if (methodInfo == null || methodInfo2 == null)
			{
				_log.LogWarning((object)"Amazing Nature tutorial finalizer was not installed because Tutorial.Awake was not found.");
				return 0;
			}
			try
			{
				HarmonyMethod val = new HarmonyMethod(methodInfo2);
				val.priority = 0;
				val.after = new string[2] { "balrond.astafaraios.BalrondAmazingNature", "dragonmotion.balrondnatureoptimizer" };
				HarmonyMethod val2 = val;
				_harmony.Patch((MethodBase)methodInfo, (HarmonyMethod)null, val2, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
				return 1;
			}
			catch (Exception ex)
			{
				_log.LogWarning((object)("Amazing Nature tutorial finalizer skipped: " + ex.GetBaseException().Message));
				return 0;
			}
		}

		private static bool AllowTutorial(GameObject __0)
		{
			if (!((Object)(object)__0 == (Object)null))
			{
				return !((Object)__0).name.EndsWith("(Clone)", StringComparison.Ordinal);
			}
			return true;
		}

		private static void NormalizeTutorialTexts(Tutorial __instance)
		{
			if (__instance?.m_texts == null)
			{
				return;
			}
			for (int i = 0; i < __instance.m_texts.Count; i++)
			{
				TutorialText val = __instance.m_texts[i];
				if (val != null && AmazingNatureTutorialLocalization.TryGetToken(val.m_name, out var token))
				{
					val.m_topic = token;
					val.m_label = token;
					val.m_text = AmazingNatureTutorialLocalization.NormalizeBody(val.m_text);
				}
			}
		}
	}
	internal static class CulinaryCategoryAdapter
	{
		private static readonly IReadOnlyDictionary<string, string> Categories = new Dictionary<string, string>(StringComparer.Ordinal)
		{
			["Distant Origins"] = "Древние истоки",
			["Distant Origins Decor"] = "Декор древних истоков",
			["Culinary Horizons"] = "Кулинарные горизонты",
			["Enhanced Foods"] = "Улучшенные блюда",
			["Forgotten Recipes"] = "Забытые рецепты",
			["Banquets"] = "Пиры"
		};

		private static readonly string[] PluginGuids = new string[4] { "Insanity.Culinary_Horizons", "Dreanegade.Eternal_Legends", "Dreanegade.Hunter_Legacy", "Dreanegade.Magic_Supremacy" };

		internal static int Apply(ManualLogSource log)
		{
			int num = 0;
			string[] pluginGuids = PluginGuids;
			for (int i = 0; i < pluginGuids.Length; i++)
			{
				Assembly pluginAssembly = ManagerAdapters.GetPluginAssembly(pluginGuids[i]);
				if (pluginAssembly != null)
				{
					num += RewriteRegisteredCategories(pluginAssembly);
				}
			}
			return num + RewriteCulinaryLongCategoryHints();
		}

		private static int RewriteRegisteredCategories(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 key && Categories.TryGetValue(key, out var value2))
				{
					fieldInfo3.SetValue(value, value2);
					num++;
				}
			}
			return num;
		}

		private static int RewriteCulinaryLongCategoryHints()
		{
			if (!(((ManagerAdapters.GetPluginAssembly("Insanity.Culinary_Horizons")?.GetType("Culinary_Horizons.Culinary_HorizonsPlugin+PieceCategoryTabTextFix"))?.GetField("longCategories", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic))?.GetValue(null) is string[] array) || array.Length != 3)
			{
				return 0;
			}
			array[0] = "Забытые";
			array[1] = "рецепты";
			array[2] = "Улучшенные блюда";
			return 3;
		}
	}
	internal static class DualMasteryAdapter
	{
		private const string PluginGuid = "balrond.astafaraios.BalrondDualMastery";

		private const int DualWieldSkillId = 874298;

		internal static int Apply(TranslationCatalog catalog)
		{
			if (!catalog.Words.TryGetValue("skill_874298", out var value))
			{
				return 0;
			}
			if (!((ManagerAdapters.GetPluginAssembly("balrond.astafaraios.BalrondDualMastery")?.GetType("BalrondDualWield.DualWieldSkills"))?.GetField("SkillsById", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic)?.GetValue(null) is IDictionary dictionary) || !dictionary.Contains(874298))
			{
				return 0;
			}
			object instance = dictionary[874298];
			if (ReflectionUtil.GetMember(instance, "SkillName") is string text && text == value)
			{
				return 0;
			}
			return ReflectionUtil.SetMember(instance, "SkillName", value) ? 1 : 0;
		}
	}
	internal sealed class HumanoidRandomizerPatcher
	{
		private const string PluginGuid = "balrond.astafaraios.BalrondHumanoidRandomizer";

		private const string HarmonyId = "obelisk.ru.localization.humanoid-randomizer";

		private static readonly MethodInfo TranslateVariantMethod = AccessTools.Method(typeof(HumanoidRandomizerPatcher), "TranslateVariant", (Type[])null, (Type[])null);

		private static readonly MethodInfo StringConcatThree = AccessTools.Method(typeof(string), "Concat", new Type[3]
		{
			typeof(string),
			typeof(string),
			typeof(string)
		}, (Type[])null);

		private static readonly IReadOnlyDictionary<string, string> VariantNames = new Dictionary<string, string>(StringComparer.Ordinal)
		{
			["Guardian"] = "— страж",
			["Protector"] = "— защитник",
			["Vanguard"] = "— авангардист",
			["Defender"] = "— оборонитель",
			["Sentry"] = "— часовой",
			["Warden"] = "— хранитель",
			["Archer"] = "— лучник",
			["Firestarter"] = "— поджигатель",
			["Sharpshooter"] = "— меткий стрелок",
			["Coldblood"] = "— хладнокровный",
			["Soulpiercer"] = "— пронзатель душ",
			["Hunter"] = "— охотник",
			["Assassin"] = "— убийца",
			["Cutthroat"] = "— головорез",
			["Brute"] = "— громила",
			["Duelist"] = "— дуэлянт",
			["Berserker"] = "— берсерк",
			["Bonebreaker"] = "— костолом",
			["Swordmaster"] = "— мастер меча",
			["Executioner"] = "— палач",
			["Marauder"] = "— мародёр",
			["Mercenary"] = "— наёмник",
			["Fighter"] = "— боец",
			["Warrior"] = "— воин",
			["Bruiser"] = "— вышибала",
			["Solider"] = "— солдат",
			["Thug"] = "— бандит",
			["Scout"] = "— разведчик",
			["Savage"] = "— дикарь",
			["Pugilist"] = "— кулачный боец",
			["Corsair"] = "— корсар",
			["Sailor"] = "— моряк",
			["Stabber"] = "— ножевик",
			["Thief"] = "— вор",
			["Lightbringer"] = "— светоносец",
			["Reaper"] = "— жнец",
			["Frozenhammer"] = "— ледяной молот",
			["Icecrusher"] = "— ледокрушитель",
			["Soulshreder"] = "— терзатель душ",
			["Blackblade"] = "— чёрный клинок",
			["Soulcalibur"] = "— клинок душ",
			["Splasher"] = "— брызгун",
			["Pyromancer"] = "— пиромант",
			["Cryomancer"] = "— криомант",
			["Thundercaller"] = "— призыватель грома",
			["Venomancer"] = "— ядомант",
			["Cultist"] = "— культист",
			["Mage"] = "— маг",
			["Cleric"] = "— жрец",
			["Reaver"] = "— разоритель",
			["Arbalist"] = "— арбалетчик"
		};

		private readonly ManualLogSource _log;

		private readonly Harmony _harmony = new Harmony("obelisk.ru.localization.humanoid-randomizer");

		internal HumanoidRandomizerPatcher(ManualLogSource log)
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_0010: Expected O, but got Unknown
			_log = log;
		}

		internal int Apply()
		{
			Assembly pluginAssembly = ManagerAdapters.GetPluginAssembly("balrond.astafaraios.BalrondHumanoidRandomizer");
			if (pluginAssembly == null)
			{
				return 0;
			}
			int num = 0;
			try
			{
				num += PatchVariantName(pluginAssembly);
			}
			catch (Exception ex)
			{
				_log.LogWarning((object)("HumanoidRandomizer contextual localization was only partially installed: " + ex.GetBaseException().Message));
			}
			_log.LogInfo((object)$"HumanoidRandomizer: installed {num} constant-only localization patches.");
			return num;
		}

		private int PatchVariantName(Assembly assembly)
		{
			//IL_0078: Unknown result type (might be due to invalid IL or missing references)
			//IL_0084: Expected O, but got Unknown
			MethodInfo methodInfo = assembly.GetType("BalrondHumanoidRandomizer.Monsters.ItemSetBuilder")?.GetMethods(BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic).FirstOrDefault((MethodInfo candidate) => candidate.Name == "GeneratePrefabs" && candidate.GetParameters().Length == 3);
			if (methodInfo == null)
			{
				_log.LogWarning((object)"HumanoidRandomizer: the three-argument GeneratePrefabs method was not found.");
				return 0;
			}
			_harmony.Patch((MethodBase)methodInfo, (HarmonyMethod)null, (HarmonyMethod)null, new HarmonyMethod(AccessTools.Method(typeof(HumanoidRandomizerPatcher), "TranslateVisibleVariantName", (Type[])null, (Type[])null)), (HarmonyMethod)null, (HarmonyMethod)null);
			return 1;
		}

		private static IEnumerable<CodeInstruction> TranslateVisibleVariantName(IEnumerable<CodeInstruction> instructions)
		{
			List<CodeInstruction> source = instructions.ToList();
			for (int index = 0; index < source.Count; index++)
			{
				CodeInstruction val = source[index];
				if (val.opcode == OpCodes.Ldstr && object.Equals(val.operand, "Rancid"))
				{
					val.operand = "Гнилой";
				}
				yield return val;
				if (IsVisibleSuffixOperand(source, index))
				{
					yield return new CodeInstruction(OpCodes.Call, (object)TranslateVariantMethod);
				}
			}
		}

		private static bool IsVisibleSuffixOperand(IReadOnlyList<CodeInstruction> instructions, int index)
		{
			if (!(instructions[index].operand is FieldInfo fieldInfo) || instructions[index].opcode != OpCodes.Ldfld || fieldInfo.Name != "m_name" || fieldInfo.DeclaringType?.FullName != "Humanoid+ItemSet")
			{
				return false;
			}
			int num = index + 1;
			if (num >= instructions.Count || !CodeInstructionExtensions.Calls(instructions[num], StringConcatThree))
			{
				return false;
			}
			for (int num2 = index - 1; num2 >= Math.Max(0, index - 5); num2--)
			{
				if (!(instructions[num2].opcode != OpCodes.Ldstr))
				{
					return object.Equals(instructions[num2].operand, " ");
				}
			}
			return false;
		}

		private static string TranslateVariant(string source)
		{
			if (source == null || !VariantNames.TryGetValue(source, out var value))
			{
				return source;
			}
			return value;
		}
	}
	internal static class InventorySlotsAdapter
	{
		private sealed class SlotName
		{
			internal string Original { get; }

			internal string Russian { get; }

			internal SlotName(string original, string russian)
			{
				Original = original;
				Russian = russian;
			}
		}

		private static readonly IReadOnlyDictionary<string, SlotName> RussianNames = new Dictionary<string, SlotName>(StringComparer.OrdinalIgnoreCase)
		{
			["helmet"] = new SlotName("Helmet", "Шлем"),
			["chest"] = new SlotName("Chest", "Нагрудник"),
			["legs"] = new SlotName("Legs", "Поножи"),
			["cape"] = new SlotName("Cape", "Плащ"),
			["utility"] = new SlotName("Utility", "Аксессуар"),
			["trinket"] = new SlotName("Trinket", "Талисман"),
			["circlet"] = new SlotName("Circlet", "Венец"),
			["wishbone"] = new SlotName("Wishbone", "Дужка"),
			["demister"] = new SlotName("Demister", "Висп"),
			["jewelcrafting.necklace"] = new SlotName("Necklace", "Ожерелье"),
			["jewelcrafting.ring"] = new SlotName("Ring", "Кольцо"),
			["smoothbrainbackpacks.backpack"] = new SlotName("Backpack", "Рюкзак"),
			["adventurebackpacks.backpack"] = new SlotName("Backpack", "Рюкзак"),
			["rustybags.bag"] = new SlotName("Bag", "Сумка"),
			["rustybags.quiver"] = new SlotName("Quiver", "Колчан"),
			["magicsupremacy.belt"] = new SlotName("MagicBelt", "Магический пояс")
		};

		internal static int Apply(ManualLogSource log)
		{
			Assembly pluginAssembly = ManagerAdapters.GetPluginAssembly("sighsorry.InventorySlots");
			Type type = pluginAssembly?.GetType("InventorySlots.InventorySlotsPlugin");
			Type type2 = pluginAssembly?.GetType("InventorySlots.SlotDefinition");
			if (!(type?.GetProperty("SlotDefinitions", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic)?.GetValue(null, null) is IList list) || type2 == null)
			{
				return 0;
			}
			PropertyInfo property = type2.GetProperty("Id", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
			PropertyInfo property2 = type2.GetProperty("Name", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
			FieldInfo field = type2.GetField("_accepts", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
			PropertyInfo property3 = type2.GetProperty("Kind", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
			PropertyInfo property4 = type2.GetProperty("QuickSlotIndex", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
			if (property == null || property2 == null || field == null || property3 == null || property4 == null)
			{
				return 0;
			}
			ConstructorInfo constructor = type2.GetConstructor(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, new Type[5]
			{
				typeof(string),
				typeof(string),
				property3.PropertyType,
				field.FieldType,
				typeof(int)
			}, null);
			if (constructor == null)
			{
				return 0;
			}
			int num = 0;
			for (int i = 0; i < list.Count; i++)
			{
				object obj = list[i];
				if (property.GetValue(obj, null) is string text && RussianNames.TryGetValue(text, out var value) && string.Equals(property2.GetValue(obj, null) as string, value.Original, StringComparison.Ordinal))
				{
					object value2 = property3.GetValue(obj, null);
					object value3 = field.GetValue(obj);
					object value4 = property4.GetValue(obj, null);
					if (value2 != null && value3 != null && value4 != null)
					{
						list[i] = constructor.Invoke(new object[5] { text, value.Russian, value2, value3, value4 });
						num++;
					}
				}
			}
			return num;
		}
	}
	internal sealed class KnownTextMigrationPatcher
	{
		private const string HarmonyId = "obelisk.ru.localization.known-text-migration";

		private static readonly IReadOnlyDictionary<string, string> TitleMigrations = BuildTitleMigrations();

		private static readonly IReadOnlyDictionary<string, string> TextMigrations = new Dictionary<string, string>(StringComparer.Ordinal)
		{
			["This is your new table for all things archery. A long the way as you progress more and more recipes for arrows will show up here"] = "Это новый стол для всего, что связано со стрельбой из лука. По мере развития здесь будет появляться всё больше рецептов стрел.",
			["This is Scribe's table for creating Schematics. Those items provide information about ship upgrades"] = "Это чертёжный стол для создания схем с описанием корабельных улучшений.",
			["This Shipyard will help you improve your ships. Put schematic in to the cargo and activate the table. If there is a ship in range that can be upgraded item put in to the cargo will be used."] = "Эта верфь поможет улучшать суда. Положите чертёж в грузовой отсек и активируйте стол. Если рядом есть подходящее судно, чертёж будет использован."
		};

		private static FieldInfo _localPlayerField;

		private static FieldInfo _knownTextsField;

		private static ManualLogSource _log;

		private readonly Harmony _harmony = new Harmony("obelisk.ru.localization.known-text-migration");

		private readonly ManualLogSource _instanceLog;

		internal KnownTextMigrationPatcher(ManualLogSource log)
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_0010: Expected O, but got Unknown
			_instanceLog = log;
		}

		internal int Apply()
		{
			//IL_00dc: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e9: Expected O, but got Unknown
			Type type = AccessTools.TypeByName("Player");
			Type type2 = AccessTools.TypeByName("ZPackage");
			MethodInfo methodInfo = ((type == null || type2 == null) ? null : AccessTools.Method(type, "Load", new Type[1] { type2 }, (Type[])null));
			_localPlayerField = type?.GetField("m_localPlayer", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
			_knownTextsField = type?.GetField("m_knownTexts", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
			MethodInfo methodInfo2 = AccessTools.Method(typeof(KnownTextMigrationPatcher), "MigrateKnownTexts", (Type[])null, (Type[])null);
			if (methodInfo == null || _localPlayerField == null || _knownTextsField == null || methodInfo2 == null)
			{
				_instanceLog.LogWarning((object)"Known-text migration was not installed because the Valheim save fields were not found.");
				return 0;
			}
			try
			{
				_log = _instanceLog;
				_harmony.Patch((MethodBase)methodInfo, (HarmonyMethod)null, new HarmonyMethod(methodInfo2), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
				return 1;
			}
			catch (Exception ex)
			{
				_instanceLog.LogWarning((object)("Known-text migration was not installed: " + ex.GetBaseException().Message));
				return 0;
			}
		}

		private static void MigrateKnownTexts(object __instance)
		{
			try
			{
				MigrateKnownTextsSafely(__instance);
			}
			catch (Exception ex)
			{
				ManualLogSource log = _log;
				if (log != null)
				{
					log.LogWarning((object)("Saved Compendium text migration skipped: " + ex.GetBaseException().Message));
				}
			}
		}

		private static void MigrateKnownTextsSafely(object instance)
		{
			if (_localPlayerField?.GetValue(null) != instance || !(_knownTextsField?.GetValue(instance) is IDictionary dictionary))
			{
				return;
			}
			int num = 0;
			foreach (KeyValuePair<string, string> titleMigration in TitleMigrations)
			{
				num += MigrateTitle(dictionary, titleMigration.Key, titleMigration.Value, clone: false);
			}
			List<object> list = new List<object>();
			foreach (DictionaryEntry item in dictionary)
			{
				list.Add(item.Key);
			}
			foreach (object item2 in list)
			{
				if (item2 is string text)
				{
					string body = dictionary[item2] as string;
					if ((AmazingNatureTutorialLocalization.TryGetToken(text, out var token) || AmazingNatureTutorialLocalization.TryGetLegacyTitleToken(text, body, out token)) && !string.Equals(text, token, StringComparison.Ordinal))
					{
						num += MigrateTitle(dictionary, text, token, AmazingNatureTutorialLocalization.IsCloneAlias(text));
					}
				}
			}
			list.Clear();
			foreach (DictionaryEntry item3 in dictionary)
			{
				list.Add(item3.Key);
			}
			foreach (object item4 in list)
			{
				if (dictionary[item4] is string text2)
				{
					string text3 = NormalizeMigratedText(text2);
					if (!string.Equals(text2, text3, StringComparison.Ordinal))
					{
						dictionary[item4] = text3;
						num++;
					}
				}
			}
			if (num != 0)
			{
				ManualLogSource log = _log;
				if (log != null)
				{
					log.LogInfo((object)$"Migrated {num} saved Compendium text entries to Russian.");
				}
			}
		}

		private static string TranslateText(string source)
		{
			if (source == null || !TextMigrations.TryGetValue(source, out var value))
			{
				return source;
			}
			return value;
		}

		private static string NormalizeMigratedText(string source)
		{
			return AmazingNatureTutorialLocalization.NormalizeBody(TranslateText(source));
		}

		private static int MigrateTitle(IDictionary knownTexts, string source, string target, bool clone)
		{
			if (!knownTexts.Contains(source))
			{
				return 0;
			}
			string text = NormalizeMigratedText(knownTexts[source] as string);
			knownTexts.Remove(source);
			if (!knownTexts.Contains(target))
			{
				if (!clone || HasTutorialBody(text))
				{
					knownTexts[target] = text;
				}
			}
			else if (knownTexts[target] is string source2)
			{
				string text2 = NormalizeMigratedText(source2);
				knownTexts[target] = ((!HasTutorialBody(text2) && HasTutorialBody(text)) ? text : text2);
			}
			return 1;
		}

		private static bool HasTutorialBody(string text)
		{
			if (string.IsNullOrWhiteSpace(text))
			{
				return false;
			}
			int num = text.IndexOf("</color>", StringComparison.OrdinalIgnoreCase);
			if (num >= 0)
			{
				return !string.IsNullOrWhiteSpace(text.Substring(num + "</color>".Length));
			}
			return true;
		}

		private static IReadOnlyDictionary<string, string> BuildTitleMigrations()
		{
			return new Dictionary<string, string>(StringComparer.Ordinal)
			{
				["Fletcher's table"] = "Стол лучника",
				["Scribe's table"] = "Чертёжный стол",
				["Scribe's Table"] = "Чертёжный стол",
				["Shipyard Station"] = "Верфь"
			};
		}
	}
	internal sealed class LiteralPatchSpec
	{
		internal string PluginGuid { get; }

		internal string TypeName { get; }

		internal string MethodName { get; }

		internal IReadOnlyDictionary<string, string> Replacements { get; }

		internal LiteralPatchSpec(string pluginGuid, string typeName, string methodName, IReadOnlyDictionary<string, string> replacements)
		{
			PluginGuid = pluginGuid;
			TypeName = typeName;
			MethodName = methodName;
			Replacements = replacements;
		}
	}
	internal sealed class LiteralPatcher
	{
		private const string HarmonyId = "obelisk.ru.localization.constants";

		private static readonly Dictionary<MethodBase, IReadOnlyDictionary<string, string>> ReplacementsByMethod = new Dictionary<MethodBase, IReadOnlyDictionary<string, string>>();

		private readonly ManualLogSource _log;

		private readonly Harmony _harmony = new Harmony("obelisk.ru.localization.constants");

		internal LiteralPatcher(ManualLogSource log)
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_0010: Expected O, but got Unknown
			_log = log;
		}

		internal int Apply(IEnumerable<LiteralPatchSpec> specs)
		{
			//IL_0239: Unknown result type (might be due to invalid IL or missing references)
			//IL_0245: Expected O, but got Unknown
			int num = 0;
			int num2 = 0;
			MethodInfo methodInfo = AccessTools.Method(typeof(LiteralPatcher), "Transpile", (Type[])null, (Type[])null);
			foreach (IGrouping<(string, string, string), LiteralPatchSpec> item in from spec in specs
				group spec by (PluginGuid: spec.PluginGuid, TypeName: spec.TypeName, MethodName: spec.MethodName))
			{
				Type type = ManagerAdapters.GetPluginAssembly(item.Key.Item1)?.GetType(item.Key.Item2);
				if (type == null)
				{
					continue;
				}
				Dictionary<string, string> dictionary = new Dictionary<string, string>(StringComparer.Ordinal);
				foreach (LiteralPatchSpec item2 in item)
				{
					foreach (KeyValuePair<string, string> replacement in item2.Replacements)
					{
						dictionary[replacement.Key] = replacement.Value;
					}
				}
				HashSet<string> matchedSources = new HashSet<string>(StringComparer.Ordinal);
				foreach (MethodBase declaredTarget in GetDeclaredTargets(type, item.Key.Item3))
				{
					int num3;
					try
					{
						num3 = 0;
						foreach (CodeInstruction originalInstruction in PatchProcessor.GetOriginalInstructions(declaredTarget, (ILGenerator)null))
						{
							if (originalInstruction.opcode == OpCodes.Ldstr && originalInstruction.operand is string text && dictionary.ContainsKey(text))
							{
								matchedSources.Add(text);
								num3++;
							}
						}
					}
					catch (Exception ex)
					{
						_log.LogWarning((object)("Literal audit skipped " + type.FullName + "." + declaredTarget.Name + ": " + ex.GetBaseException().Message));
						continue;
					}
					if (num3 != 0)
					{
						try
						{
							ReplacementsByMethod[declaredTarget] = dictionary;
							_harmony.Patch(declaredTarget, (HarmonyMethod)null, (HarmonyMethod)null, new HarmonyMethod(methodInfo), (HarmonyMethod)null, (HarmonyMethod)null);
							num++;
							num2 += num3;
						}
						catch (Exception ex2)
						{
							ReplacementsByMethod.Remove(declaredTarget);
							_log.LogWarning((object)("Literal patch skipped " + type.FullName + "." + declaredTarget.Name + ": " + ex2.GetBaseException().Message));
						}
					}
				}
				foreach (string item3 in dictionary.Keys.Where((string source) => !matchedSources.Contains(source)))
				{
					_log.LogWarning((object)("Literal audit miss " + type.FullName + "." + item.Key.Item3 + ": '" + EscapeForLog(item3) + "'"));
				}
			}
			_log.LogInfo((object)$"Installed {num} startup constant-replacement patches for {num2} IL constants.");
			return num;
		}

		private static IEnumerable<MethodBase> GetDeclaredTargets(Type type, string methodName)
		{
			BindingFlags bindingAttr = BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic;
			if (methodName == ".ctor")
			{
				return type.GetConstructors(bindingAttr).Cast<MethodBase>();
			}
			if (methodName == ".cctor")
			{
				if (!(type.TypeInitializer == null))
				{
					return new MethodBase[1] { type.TypeInitializer };
				}
				return Enumerable.Empty<MethodBase>();
			}
			return (from method in type.GetMethods(bindingAttr)
				where method.Name == methodName && !method.IsAbstract && !method.ContainsGenericParameters
				select method).Cast<MethodBase>();
		}

		private static string EscapeForLog(string text)
		{
			return text.Replace("\r", "\\r").Replace("\n", "\\n");
		}

		private static IEnumerable<CodeInstruction> Transpile(IEnumerable<CodeInstruction> instructions, MethodBase __originalMethod)
		{
			ReplacementsByMethod.TryGetValue(__originalMethod, out var replacements);
			foreach (CodeInstruction instruction in instructions)
			{
				if (replacements != null && instruction.opcode == OpCodes.Ldstr && instruction.operand is string key && replacements.TryGetValue(key, out var value))
				{
					instruction.operand = value;
				}
				yield return instruction;
			}
		}
	}
	internal static class LiteralRegistry
	{
		internal static IReadOnlyList<LiteralPatchSpec> Create()
		{
			return CreateCore(null);
		}

		internal static IReadOnlyList<LiteralPatchSpec> CreateForLoadedPlugins()
		{
			return CreateCore(delegate(string guid)
			{
				if (Chainloader.PluginInfos.TryGetValue(guid, out var value))
				{
					object obj;
					if (value == null)
					{
						obj = null;
					}
					else
					{
						BepInPlugin metadata = value.Metadata;
						obj = ((metadata != null) ? metadata.Version : null);
					}
					if ((Version?)obj != null)
					{
						return value.Metadata.Version.ToString();
					}
				}
				return (string)null;
			});
		}

		private static IReadOnlyList<LiteralPatchSpec> CreateCore(Func<string, string> pluginVersionResolver)
		{
			List<LiteralPatchSpec> result = new List<LiteralPatchSpec>();
			AddPlantMods(result);
			AddAzuMods(result);
			AddUtilityMods(result);
			AddPerfectPlacement(result);
			AddLocationPlacementAccelerator(result);
			AddMoveBuildPiecesStaticText(result);
			AddConnectionErrors(result, pluginVersionResolver);
			AddBossAdd(result);
			AddMoreWorldLocations(result);
			AddVnei(result);
			AddHuginn(result);
			AddJotunn(result);
			AddEpicLoot(result);
			AddInventorySlots(result);
			AddCreatureLevelControl(result);
			AddPassivePowers(result);
			AddXPortal(result);
			AddBalrondShipyard(result);
			AddBalrondGaps(result);
			return result;
		}

		private static void AddPassivePowers(List<LiteralPatchSpec> result)
		{
			Add(result, "org.bepinex.plugins.passivepowers", "PassivePowers.BonusSpiritDefense", "get_Desc", "$powers_additional_spirit_damage", "$powers_additional_spirit_defense");
		}

		private static void AddPlantMods(List<LiteralPatchSpec> result)
		{
			Add(result, "advize.PlantEasily", "Advize_PlantEasily.HoverTextPatches", "BuildAreaHint", " (area)", " (в области)");
			Add(result, "advize.PlantEasily", "Advize_PlantEasily.HoverTextPatches", "Postfix", "\nReplant as: <color=green>", "\nПосадить снова: <color=green>");
			Add(result, "advize.PlantEasily", "Advize_PlantEasily.KeyHintPatches", "CreateKeyBoardHints", "Grid Size", "Размер сетки");
			Add(result, "advize.PlantEasily", "Advize_PlantEasily.KeyHintPatches", "UpdateGamepadHints", "Resize Grid ", "Изменить сетку ");
			Add(result, "advize.PlantEasily", "Advize_PlantEasily.InputPatches", "Prefix", "PlantEasily.ModActive: {0}", "PlantEasily — мод включён: {0}", "PlantEasily.SnapActive: {0}", "PlantEasily — привязка включена: {0}", "PlantEasily.ReplantOnHarvest: {0}", "PlantEasily — пересадка включена: {0}");
			Add(result, "advize.PlantEverything", "Advize_PlantEverything.HoverTextPatches", "FormatTime", "{0:D2}h {1:D2}m {2:D2}s", "{0:D2} ч {1:D2} мин {2:D2} с", "{0:D2}m {1:D2}s", "{0:D2} мин {1:D2} с", "{0:D2}s", "{0:D2} с");
		}

		private static void AddAzuMods(List<LiteralPatchSpec> result)
		{
			Add(result, "Azumatt.AzuAreaRepair", "AzuAreaRepair.PlayerRepairPatch", "RepairArea", "{0} pieces repaired", "Отремонтировано построек: {0}");
			Add(result, "Azumatt.AzuAutoStore", "AzuAutoStore.Util.Functions", "TryStore", "] is not in nearby containers</color>", "] нет в ближайших контейнерах</color>", "] cannot be stored based on configuration settings</color>", "] нельзя сложить при текущих настройках</color>");
			Add(result, "Azumatt.AzuAutoStore", "AzuAutoStore.Util.Functions", "StoreSuccess", "Stored {0} items from your inventory into nearby containers", "Переложено предметов в ближайшие контейнеры: {0}");
			Add(result, "Azumatt.AzuAutoStore", "AzuAutoStore.Interfaces.BackpackContainer", "TryStore", " is not in nearby containers</color>", " нет в ближайших контейнерах</color>");
			Add(result, "Azumatt.AzuAutoStore", "AzuAutoStore.Interfaces.kgDrawer", "TryStoreToKG", " is not in nearby containers</color>", " нет в ближайших контейнерах</color>");
			Add(result, "Azumatt.AzuAutoStore", "AzuAutoStore.Interfaces.mkzDrawer", "TryStoreThisItem", "] is not in nearby drawers</color>", "] нет в ближайших ящиках</color>");
			Add(result, "Azumatt.AzuAutoStore", "AzuAutoStore.TerminalInitTerminalPatch", "Postfix", "[prefab name/query text] - search for items in chests near the player. It uses the prefab name", "[ID предмета/текст] — найти предметы в сундуках рядом с игроком; поиск учитывает ID предмета");
			Add(result, "Azumatt.AzuAutoStore", "AzuAutoStore.TerminalInitTerminalPatch+<>c", "<Postfix>b__2_0", "Found {0} items matching '{1}' in nearby containers.", "В ближайших контейнерах найдено предметов по запросу «{1}»: {0}.", "<color=red>No items matching '", "<color=red>В ближайших контейнерах нет предметов по запросу «", "' found in nearby containers.</color>", "».</color>");
			Add(result, "Azumatt.AzuAutoStore", "Backpacks.ItemContainer", "GetPressOpenText", "Press [", "Нажмите [", "] to open", "], чтобы открыть");
			AddCraftyCountHover(result, "Azumatt.AzuCraftyBoxes", "AzuCraftyBoxes.Patches.FireplaceGetHoverTextPatch", "Postfix", includeItemName: false);
			AddCraftyCountHover(result, "Azumatt.AzuCraftyBoxes", "AzuCraftyBoxes.Patches.TurretGetHoverTextPatch", "Postfix", includeItemName: false);
			AddCraftyCountHover(result, "Azumatt.AzuCraftyBoxes", "AzuCraftyBoxes.Patches.OverrideHoverTextSg", "UpdateAddFuelSwitchHoverText", includeItemName: true);
			Add(result, "Azumatt.AzuCraftyBoxes", "AzuCraftyBoxes.Patches.OverrideHoverText", "UpdateAddWoodSwitchHoverText", "\n[<b><color=yellow>{0}</color> + <color=yellow>$KEY_Use</color></b>] $piece_smelter_add {1} {2} from Inventory & Nearby Containers", "\n[<b><color=yellow>{0}</color> + <color=yellow>$KEY_Use</color></b>] $piece_smelter_add {1} {2} из инвентаря и ближайших контейнеров");
			Add(result, "Azumatt.AzuCraftyBoxes", "AzuCraftyBoxes.Patches.OverrideHoverText", "UpdateAddOreSwitchHoverText", "\n[<b><color=yellow>{0}</color> + <color=yellow>$KEY_Use</color></b>] {1} {2} from Inventory & Nearby Containers", "\n[<b><color=yellow>{0}</color> + <color=yellow>$KEY_Use</color></b>] {1} {2} из инвентаря и ближайших контейнеров");
			Add(result, "Azumatt.AzuCraftyBoxes", "AzuCraftyBoxes.Patches.OverrideHoverTextFermenter", "UpdateAddSwitchHoverText", "\n[<b><color=yellow>{0}</color> + <color=yellow>$KEY_Use</color></b>] {1} {2} from Inventory & Nearby Containers", "\n[<b><color=yellow>{0}</color> + <color=yellow>$KEY_Use</color></b>] {1} {2} из инвентаря и ближайших контейнеров");
			Add(result, "Azumatt.AzuCraftyBoxes", "AzuCraftyBoxes.Patches.SE_ContainerPull", "CreateEffect", "Preventing Pulling", "Блокировка автоподачи", "Prevents pulling from nearby containers & backpacks", "Запрещает брать ресурсы из ближайших контейнеров и рюкзаков");
			Add(result, "Azumatt.AzuCraftyBoxes", "AzuCraftyBoxes.Patches.ShieldGeneratorOnAddFuelPatch", "Prefix", "$msg_added {0} items", "$msg_added {0} предметов");
			Add(result, "Azumatt.AzuCraftyBoxes", "AzuCraftyBoxes.Patches.Turret_UseItem_Patch", "Prefix", "$msg_added {0} items", "$msg_added {0} предметов");
			Add(result, "Azumatt.AzuCraftyBoxes", "Backpacks.ItemContainer", "GetPressOpenText", "Press [", "Нажмите [", "] to open", "], чтобы открыть");
		}

		private static void AddCraftyCountHover(List<LiteralPatchSpec> result, string guid, string type, string method, bool includeItemName)
		{
			if (includeItemName)
			{
				Add(result, guid, type, method, "{0} {1} in inventory", "{0} {1} в инвентаре", "{0} {1} in nearby containers", "{0} {1} в ближайших контейнерах", "{0} needed to fill", "{0} не хватает для заполнения", " and ", " и ", "\n[<b><color=yellow>{0}</color> + <color=yellow>$KEY_Use</color></b>] Add {1}", "\n[<b><color=yellow>{0}</color> + <color=yellow>$KEY_Use</color></b>] Добавить {1}");
			}
			else
			{
				Add(result, guid, type, method, "{0} in inventory", "{0} в инвентаре", "{0} in nearby containers", "{0} в ближайших контейнерах", "{0} needed to fill", "{0} не хватает для заполнения", " and ", " и ");
			}
		}

		private static void AddUtilityMods(List<LiteralPatchSpec> result)
		{
			Add(result, "Azumatt.BuildCameraCHE", "Valheim_Build_Camera.Utils", "EnableBuildMode", "Entering Build Mode.", "Включён режим строительства.");
			Add(result, "Azumatt.FirstPersonMode", "FirstPersonMode.Util.Functions", "HandleFirstPersonMode", "Changed fov to: {0}", "Поле зрения изменено: {0}");
			Add(result, "vapok.mods.adventurebackpacks", "Vapok.Common.Managers.Skill.Skill", "Patch_Skills_CheatRaiseskill", "Skill increased ", "Навык повышен: ", "Skill ", "Навык ");
			Add(result, "vapok.mods.adventurebackpacks", "Vapok.Common.Managers.Skill.Skill", "Patch_Skills_CheatResetSkill", "Skill ", "Навык «", " reset", "» сброшен");
			Add(result, "petri.valheim.takeallcooked", "TakeAllCooked.Patches.CookingStationHoverTextPatch", "GetShortcutDisplayText", "Unbound", "Не назначено");
		}

		private static void AddPerfectPlacement(List<LiteralPatchSpec> result)
		{
			Add(result, "Azumatt_and_ValheimPlusDevs.PerfectPlacement", "PerfectPlacement.Patches.ABM", "changeModificationSpeed", "Modification Speed: ", "Скорость изменения: ");
			Add(result, "Azumatt_and_ValheimPlusDevs.PerfectPlacement", "PerfectPlacement.Patches.ABM", "startMode", "Starting ABM", "Включён расширенный режим строительства", "<color=yellow>ABM is active</color>", "<color=yellow>Расширенный режим строительства активен</color>");
			Add(result, "Azumatt_and_ValheimPlusDevs.PerfectPlacement", "PerfectPlacement.Patches.ABM", "exitMode", "Exiting ABM", "Расширенный режим строительства выключен");
			Add(result, "Azumatt_and_ValheimPlusDevs.PerfectPlacement", "PerfectPlacement.Patches.ABM", "resetObjectTransform", "Object has been reset to initial position & rotation.", "Исходные положение и поворот объекта восстановлены.");
			Add(result, "Azumatt_and_ValheimPlusDevs.PerfectPlacement", "PerfectPlacement.Patches.AEM", "changeModificationSpeed", "Modification Speed: ", "Скорость изменения: ");
			Add(result, "Azumatt_and_ValheimPlusDevs.PerfectPlacement", "PerfectPlacement.Patches.AEM", "startMode", "Entering AEM", "Включён расширенный режим редактирования", "<color=yellow>AEM is active</color>", "<color=yellow>Расширенный режим редактирования активен</color>");
			Add(result, "Azumatt_and_ValheimPlusDevs.PerfectPlacement", "PerfectPlacement.Patches.AEM", "exitMode", "Exiting AEM", "Расширенный режим редактирования выключен");
			Add(result, "Azumatt_and_ValheimPlusDevs.PerfectPlacement", "PerfectPlacement.Patches.AEM", "resetObjectTransform", "Object has been reset to initial position & rotation.", "Исходные положение и поворот объекта восстановлены.");
			Add(result, "Azumatt_and_ValheimPlusDevs.PerfectPlacement", "PerfectPlacement.Patches.GridAlignment", "Postfix", "Default grid alignment set to ", "Выравнивание по сетке по умолчанию: ", "Grid alignment by default ", "Выравнивание по сетке по умолчанию ", "enabled", "включено", "disabled", "выключено");
		}

		private static void AddLocationPlacementAccelerator(List<LiteralPatchSpec> result)
		{
			Add(result, "nickpappas.locationplacementaccelerator", "LPA.GenerationProgress", "BuildModeName", "Survey", "Разведка", "Filter", "Фильтрация", "Force", "Принудительный", "Vanilla", "Обычный", "Replaced", "Заменённый движок", "Transpiled", "Транспилированный движок", " - Parallel", " — параллельно");
			Add(result, "nickpappas.locationplacementaccelerator", "LPA.GenerationProgress", "UpdateText", "<size=28><b>Placing locations using ", "<size=28><b>Размещение локаций: ", "\n<color=#FF4444><size=22><b>FAILED - ATTEMPTING RELAXATION:</b></size>", "\n<color=#FF4444><size=22><b>НЕ УДАЛОСЬ — ОСЛАБЛЕНИЕ ОГРАНИЧЕНИЙ:</b></size>", "\n<color=#55AAFF><size=22><b>RELAXED CONSTRAINTS:</b></size>", "\n<color=#55AAFF><size=22><b>ОГРАНИЧЕНИЯ ОСЛАБЛЕНЫ:</b></size>", "\n<color=#FF4444><size=22><b>FAILED - COULD NOT PLACE:</b></size>", "\n<color=#FF4444><size=22><b>НЕ УДАЛОСЬ РАЗМЕСТИТЬ:</b></size>", "<size=20>  {0}  (exhausted {1} relaxation attempts)</size>", "<size=20>  {0}  (исчерпано попыток ослабления: {1})</size>");
			Add(result, "nickpappas.locationplacementaccelerator", "LPA.ConstraintRelaxer", "BuildAttemptDescription", "Altitude {0:F0}..{1:F0}-->{2:F0}..{3:F0}", "Высота {0:F0}..{1:F0} → {2:F0}..{3:F0}", "Distance {0:F0}..{1:F0}-->{2:F0}..{3:F0}", "Расстояние {0:F0}..{1:F0} → {2:F0}..{3:F0}", "TerrainDelta {0:F1}-->{1:F1}", "Перепад рельефа {0:F1} → {1:F1}", "ExteriorRadius {0:F0}-->{1:F0}", "Внешний радиус {0:F0} → {1:F0}", "Constraints loosened", "Ограничения ослаблены", "[attempt {0}]: {1}", "[попытка {0}]: {1}");
			Add(result, "nickpappas.locationplacementaccelerator", "LPA.ConstraintRelaxer", "GetRelaxationSummary", "(Relaxed {0} times)", "(ослаблено раз: {0})", "MinAlt: {0:F0}->{1:F0}", "Мин. высота: {0:F0} → {1:F0}", "MaxDist: {0:F0}->{1:F0}", "Макс. расстояние: {0:F0} → {1:F0}", "MinDist: {0:F0}->{1:F0}", "Мин. расстояние: {0:F0} → {1:F0}", "MaxTerr: {0:F1}->{1:F1}", "Макс. рельеф: {0:F1} → {1:F1}", "ExtRadius: {0:F0}->{1:F0}", "Внешний радиус: {0:F0} → {1:F0}", "(Relaxed {0}x: {1})", "(ослаблено {0} раз: {1})");
			Add(result, "nickpappas.locationplacementaccelerator", "LPA.PlacementEngine", "RunInlineRelaxation", "{0}  (Relaxation attempt {1})", "{0}  (попытка ослабления {1})");
		}

		private static void AddMoveBuildPiecesStaticText(List<LiteralPatchSpec> result)
		{
			Add(result, "obelisk.valheim.movebuildpieces", "Obelisk.MoveBuildPieces.MoveController", "BeginRelocationPlacement", "Move", "Перемещение");
		}

		private static void AddConnectionErrors(List<LiteralPatchSpec> result, Func<string, string> pluginVersionResolver)
		{
			string[] array = new string[18]
			{
				"advize.PlantEverything", "Azumatt.AzuAreaRepair", "Azumatt.AzuAutoStore", "Azumatt.AzuCraftyBoxes", "Azumatt.AzuWorkbenchTweaks", "Azumatt.BuildCameraCHE", "org.bepinex.plugins.creaturelevelcontrol", "Insanity.Culinary_Horizons", "Dreanegade.Eternal_Legends", "Azumatt.FirstPersonMode",
				"blacks7ar.FoodDurationMultiplier", "Dreanegade.Hunter_Legacy", "sighsorry.InventorySlots", "Dreanegade.Magic_Supremacy", "warpalicious.More_World_Locations_AIO", "org.bepinex.plugins.odinssteelworks", "org.bepinex.plugins.passivepowers", "Azumatt_and_ValheimPlusDevs.PerfectPlacement"
			};
			foreach (string guid in array)
			{
				AddServerSync(result, guid);
			}
			string pluginVersion = GetPluginVersion(pluginVersionResolver, "com.jotunn.jotunn", "2.29.2");
			Add(result, "com.jotunn.jotunn", "Jotunn.Utils.ModCompatibility", "CreateModModuleLayoutErrorMessage", "Jotunn version on client is higher than server version: " + pluginVersion, "Версия Jotunn на клиенте выше версии сервера: " + pluginVersion, "Jotunn version on server is higher than client version: " + pluginVersion, "Версия Jotunn на сервере выше версии клиента: " + pluginVersion, "Jotunn versions on server and client are not compatible.", "Версии Jotunn на сервере и клиенте несовместимы.");
			AddCustomVersionErrors(result, pluginVersionResolver);
		}

		private static void AddServerSync(List<LiteralPatchSpec> result, string guid)
		{
			Add(result, guid, "ServerSync.VersionCheck", "ErrorServer", "Disconnect: The client (", "Отключение: на клиенте (", ") doesn't have the correct ", ") установлена неподходящая версия ", " version ", " — версия ");
			Add(result, guid, "ServerSync.VersionCheck", "ErrorClient", " is not installed on the server.", " не установлен на сервере.", " needs to be at least version ", ": требуется версия не ниже ", ". You have version ", ". У вас версия ", " may not be higher than version ", ": версия не должна быть выше ");
			Add(result, guid, "ServerSync.VersionCheck", "ShowConnectionError", "\nServer expects you to have ", "\nСервер требует установить ", " (Version: ", " (версия: ", ") installed.", ").");
		}

		private static void AddCustomVersionErrors(List<LiteralPatchSpec> result, Func<string, string> pluginVersionResolver)
		{
			Add(result, "Azumatt.AzuAreaRepair", "AzuAreaRepair.RpcHandlers", "RPC_AzuAutoStore_Version", "AzuAreaRepair Installed: 1.1.6 ", "Установлен AzuAreaRepair: 1.1.6 ", "\n Needed: ", "\n Требуется: ");
			Add(result, "Azumatt.AzuAutoStore", "AzuAutoStore.RpcHandlers", "RPC_AzuAutoStore_Version", "AzuAutoStore Installed: 3.0.14\n Needed: ", "Установлен AzuAutoStore: 3.0.14\n Требуется: ");
			Add(result, "Azumatt.AzuCraftyBoxes", "AzuCraftyBoxes.RpcHandlers", "RPC_AzuCraftyBoxes_Version", "AzuCraftyBoxes Installed: 1.8.14\n Needed: ", "Установлен AzuCraftyBoxes: 1.8.14\n Требуется: ");
			Add(result, "Azumatt.AzuWorkbenchTweaks", "AzuWorkbenchTweaks.RpcHandlers", "RPC_AzuWorkbenchTweaks_Version", "AzuWorkbenchTweaks Installed: 1.0.5\n Needed: ", "Установлен AzuWorkbenchTweaks: 1.0.5\n Требуется: ");
			Add(result, "Azumatt.BuildCameraCHE", "Valheim_Build_Camera.RpcHandlers", "RPC_AzuAutoStore_Version", "BuildCameraCHE Installed: 1.2.10\n Needed: ", "Установлен BuildCameraCHE: 1.2.10\n Требуется: ");
			string pluginVersion = GetPluginVersion(pluginVersionResolver, "Insanity.Culinary_Horizons", "1.0.2");
			Add(result, "Insanity.Culinary_Horizons", "Culinary_Horizons.RpcHandlers", "RPC_Culinary_Horizons_Version", "Culinary_Horizons Installed: " + pluginVersion + "\n Needed: ", "Установлен Culinary_Horizons: " + pluginVersion + "\n Требуется: ");
			Add(result, "Dreanegade.Eternal_Legends", "Eternal_Legends.RpcHandlers", "RPC_Eternal_Legends_Version", "Eternal_Legends Installed: 1.0.4\n Needed: ", "Установлен Eternal_Legends: 1.0.4\n Требуется: ");
			Add(result, "Dreanegade.Hunter_Legacy", "Hunter_Legacy.RpcHandlers", "RPC_Hunter_Legacy_Version", "Hunter_Legacy Installed: 1.0.8\n Needed: ", "Установлен Hunter_Legacy: 1.0.8\n Требуется: ");
			string pluginVersion2 = GetPluginVersion(pluginVersionResolver, "Dreanegade.Magic_Supremacy", "3.0.7");
			Add(result, "Dreanegade.Magic_Supremacy", "Magic_Supremacy.RpcHandlers", "RPC_Magic_Supremacy_Version", "Magic_Supremacy Installed: " + pluginVersion2 + "\n Needed: ", "Установлен Magic_Supremacy: " + pluginVersion2 + "\n Требуется: ");
			string pluginVersion3 = GetPluginVersion(pluginVersionResolver, "warpalicious.More_World_Locations_AIO", "5.0.8");
			Add(result, "warpalicious.More_World_Locations_AIO", "More_World_Locations_AIO.RpcHandlers", "RPC_More_World_Locations_AIO_Version", "More_World_Locations_AIO Installed: " + pluginVersion3 + "\n Needed: ", "Установлен More_World_Locations_AIO: " + pluginVersion3 + "\n Требуется: ");
			Add(result, "Azumatt_and_ValheimPlusDevs.PerfectPlacement", "AllManagersModTemplate.RpcHandlers", "RPC_AllManagersModTemplate_Version", "PerfectPlacement Installed: 1.2.2 ", "Установлен PerfectPlacement: 1.2.2 ", "\n Needed: ", "\n Требуется: ");
		}

		private static void AddBossAdd(List<LiteralPatchSpec> result)
		{
			Add(result, "bossadd", "bossadd.Patches.BonemassKillConditionPatch", "Prefix", "분열된 본매스를 모두 처치하라!", "Уничтожьте всех разделившихся Масс Костей!");
			Add(result, "bossadd", "bossadd.Patches.MiniBonemassOrderDeathPatch", "Prefix", "[", "Сначала уничтожьте Массу Костей цвета «", "]색 본매스를 먼저 처치하라!", "»!");
		}

		private static void AddMoreWorldLocations(List<LiteralPatchSpec> result)
		{
			Add(result, "warpalicious.More_World_Locations_AIO", "More_World_Locations_AIO.PortInit+<>c", "<SetupManifests>b__13_0", "Wooden Shipment", "Грузовой деревянный сундук");
			Add(result, "warpalicious.More_World_Locations_AIO", "More_World_Locations_AIO.PortInit+<>c", "<SetupManifests>b__13_1", "Barrel Shipment", "Грузовая бочка");
			Add(result, "warpalicious.More_World_Locations_AIO", "More_World_Locations_AIO.PortInit+<>c", "<SetupManifests>b__13_2", "Fine Shipment", "Грузовой добротный сундук");
			Add(result, "warpalicious.More_World_Locations_AIO", "More_World_Locations_AIO.PortInit+<>c", "<SetupManifests>b__13_3", "Fuling Shipment", "Грузовой сундук фулингов");
			Add(result, "warpalicious.More_World_Locations_AIO", "More_World_Locations_AIO.PortInit+<>c", "<SetupManifests>b__13_4", "Dvergr Shipment", "Грузовой сундук двергов");
			Add(result, "warpalicious.More_World_Locations_AIO", "More_World_Locations_AIO.Shrines.Shrine", "GetHoverText", "Unknown Shrine", "Неизвестное святилище", "Shrine", "Святилище", "\n<color=red>Shrine is misconfigured</color>", "\n<color=red>Святилище настроено неправильно</color>", "Duration: <color=orange>{0:0.#} min</color>\n", "Длительность: <color=orange>{0:0.#} мин</color>\n", "\n<color=red>Can only be used once per day</color>\n", "\n<color=red>Можно использовать только раз в день</color>\n", "[<color=yellow><b>$KEY_Use</b></color>] Sacrifice {0}x <color=orange>{1}</color>\n", "[<color=yellow><b>$KEY_Use</b></color>] Принести в жертву {0}x <color=orange>{1}</color>\n");
			Add(result, "warpalicious.More_World_Locations_AIO", "More_World_Locations_AIO.Shrines.Shrine", "Interact", "Shrine can only be used once per day. Try again tomorrow!", "Святилище можно использовать лишь раз в день. Попробуйте завтра!");
			Add(result, "warpalicious.More_World_Locations_AIO", "More_World_Locations_AIO.Shrines.ShrineDB", "BuildShrineConfigs", "Odin's Shrine of The Boar", "Святилище Одина: кабан", "Odin's Shrine of The Deer", "Святилище Одина: олень", "Odin's Shrine of The Neck", "Святилище Одина: никс", "Odin's Shrine of The Greydwarf", "Святилище Одина: грейдворф", "Odin's Shrine of The Skeleton", "Святилище Одина: скелет", "Odin's Shrine of The Greydwarf Shaman", "Святилище Одина: шаман грейдворфов", "Odin's Shrine of The Poison Skeleton", "Святилище Одина: ядовитый скелет", "Odin's Shrine of The Draugr", "Святилище Одина: драугр", "Odin's Shrine of The Leech", "Святилище Одина: пиявка", "Odin's Shrine of The Wraith", "Святилище Одина: призрак", "Odin's Shrine of The Abomination", "Святилище Одина: порождение", "Odin's Shrine of The Wolf", "Святилище Одина: волк", "Odin's Shrine of The Hatchling", "Святилище Одина: дракончик", "Odin's Shrine of The Ulv", "Святилище Одина: ульв", "Odin's Shrine of The Cultist", "Святилище Одина: культист", "Odin's Shrine of The Goblin", "Святилище Одина: фулинг", "Odin's Shrine of The Deathsquito", "Святилище Одина: комар смерти", "Odin's Shrine of The Goblin Shaman", "Святилище Одина: шаман фулингов", "Odin's Shrine of The Goblin Brute", "Святилище Одина: берсерк фулингов", "Odin's Shrine of The Seeker", "Святилище Одина: искатель", "Odin's Shrine of The Hare", "Святилище Одина: заяц", "Odin's Shrine of The Dvergr", "Святилище Одина: дверг", "Odin's Shrine of The Seeker Brute", "Святилище Одина: солдат-искатель");
			AddMwlStatusEffects(result, "warpalicious.More_World_Locations_AIO");
			Add(result, "warpalicious.More_World_Locations_AIO", "More_World_Locations_AIO.Waystones.Waystone", "GetHoverText", "Unknown Waystone", "Неизвестный путевой камень", "Waystone", "Путевой камень", "\n[<color=yellow><b>$KEY_Use</b></color>] Use Waystone\n", "\n[<color=yellow><b>$KEY_Use</b></color>] Использовать путевой камень\n");
			Add(result, "warpalicious.More_World_Locations_AIO", "More_World_Locations_AIO.Waystones.Waystone", "Interact", "Map revealed in radius of {0} meters", "Карта открыта в радиусе {0} м");
			Add(result, "warpalicious.More_World_Locations_AIO", "More_World_Locations_AIO.Traders.BlacksmithStone_SE", "Setup", "Using Blacksmith Stone to enhance an item...", "Кузнечный камень улучшает предмет...");
			Add(result, "warpalicious.More_World_Locations_AIO", "More_World_Locations_AIO.Traders.BlacksmithStone_SE", "EnhanceItem", "Item: ", "Предмет: ", " was enhanced", " улучшен", "No suitable item found in top left corner of inventory.", "В левом верхнем углу инвентаря нет подходящего предмета.");
			Add(result, "warpalicious.More_World_Locations_AIO", "More_World_Locations_AIO.Traders.BlacksmithStoneCanConsumeItemPatch", "Prefix", "No suitable item found in top left corner of inventory.", "В левом верхнем углу инвентаря нет подходящего предмета.");
			Add(result, "warpalicious.More_World_Locations_AIO", "More_World_Locations_AIO.Traders.SkillBook_SE", "ApplySkillBook", " is already at max level", " уже достиг максимального уровня", " increased to ", " повышен до ");
			Add(result, "warpalicious.More_World_Locations_AIO", "More_World_Locations_AIO.PortUI+Tab", ".ctor", "MWL_Ports_Tooltip", "Порты");
			Add(result, "warpalicious.More_World_Locations_AIO", "Forbidden_Catacombs.AltarDoor", ".ctor", "Sacrificial Altar", "Жертвенный алтарь");
			Add(result, "warpalicious.More_World_Locations_AIO", "Forbidden_Catacombs.AltarDoor", "GetHoverText", "\n[<color=yellow><b>$KEY_Use</b></color>] Sacrifice", "\n[<color=yellow><b>$KEY_Use</b></color>] Принести жертву");
			AddMoreWorldLocationsExtras(result, "warpalicious.More_World_Locations_AIO");
		}

		private static void AddMoreWorldLocationsExtras(List<LiteralPatchSpec> result, string guid)
		{
			Add(result, guid, "Common.LootManager", "AddContainerToChild", "Chest", "$piece_chest");
			Add(result, guid, "More_World_Locations_AIO.Commands", "Setup", "list of all shipments", "список всех грузов", "pins port locations on map", "отмечает порты на карте", "removes port pins from map", "удаляет метки портов с карты", "removes known ports from player save", "удаляет известные порты из сохранения игрока");
			Add(result, guid, "More_World_Locations_AIO.Commands+<>c", "<Setup>b__1_0", "No shipments found", "Грузы не найдены");
			Add(result, guid, "More_World_Locations_AIO.Port+PortInfo", "GetTooltip", "\n\nShipments (<color=yellow>{0}</color>): ", "\n\nГрузы (<color=yellow>{0}</color>): ");
			Add(result, guid, "More_World_Locations_AIO.Shipment", "FormatTime", "{0}h", "{0} ч", "{0}m", "{0} мин", "{0}s", "{0} с", "~{0:0.#} days ({1})", "~{0:0.#} дн. ({1})");
			AddMwlTerminalCommands(result, guid);
			AddMwlWaystones(result, guid);
			AddMwlShrineStats(result, guid);
		}

		private static void AddMwlTerminalCommands(List<LiteralPatchSpec> result, string guid)
		{
			Add(result, guid, "More_World_Locations_AIO.MWLCommands", "Postfix", "Teleport to a location. Usage: gotolocation <name> [index]", "Телепортироваться к локации. Использование: gotolocation <название> [индекс]", "Pin multiple locations on map. Usage: findlocations <name1> <name2> ...", "Отметить несколько локаций на карте. Использование: findlocations <название1> <название2> ...");
			Add(result, guid, "More_World_Locations_AIO.MWLCommands+<>c", "<Postfix>b__0_0", "ZoneSystem not available", "Система зон недоступна", "No local player", "Локальный игрок не найден", "Usage: gotolocation <location_name> [index]", "Использование: gotolocation <название_локации> [индекс]", "  index: which instance to go to (default: closest)", "  индекс: к какому экземпляру перейти (по умолчанию — к ближайшему)", "Location '", "Локация «", "' exists but no instances have spawned yet", "» существует, но её экземпляры ещё не созданы", "No location found matching '", "Локация по запросу «", "'", "» не найдена", "Index {0} out of range. Only {1} instances exist.", "Индекс {0} вне диапазона. Доступно экземпляров: {1}.", "Teleporting to {0} ({1}/{2})", "Телепортация к {0} ({1}/{2})");
			Add(result, guid, "More_World_Locations_AIO.MWLCommands+<>c", "<Postfix>b__0_2", "ZoneSystem not available", "Система зон недоступна", "Minimap not available", "Мини-карта недоступна", "Usage: findlocations <location_name1> <location_name2> ...", "Использование: findlocations <название_локации1> <название_локации2> ...", "  Use 'findlocations clear' to remove all pins", "  Команда 'findlocations clear' удаляет все метки", "Removed {0} location pins", "Удалено меток локаций: {0}", "No spawned instances found matching: ", "Не найдены созданные экземпляры по запросу: ", "Added {0} pins:", "Добавлено меток: {0}:", "Use 'findlocations clear' to remove pins", "Команда 'findlocations clear' удаляет метки");
			Add(result, guid, "More_World_Locations_AIO.Utils.UpgradeWorldCommands", "AddUpgradeWorldCommands", "Adds MWL dungeon locations to corresponding biomes.", "Добавляет подземелья MWL в соответствующие биомы.", "Adds MWL locations to the Ashlands biome.", "Добавляет локации MWL в Пепельные земли.", "Adds MWL locations to the Black Forest biome.", "Добавляет локации MWL в Чёрный лес.", "Adds MWL locations to the Meadows biome.", "Добавляет локации MWL на Луга.", "Adds MWL locations to the Mistlands biome.", "Добавляет локации MWL в Туманные земли.", "Adds MWL locations to the Mountains biome.", "Добавляет локации MWL в Горы.", "Adds MWL locations to the Plains biome.", "Добавляет локации MWL на Равнины.", "Adds MWL locations to the Swamp biome.", "Добавляет локации MWL на Болота.", "Adds MWL shipping port locations to corresponding biomes.", "Добавляет грузовые порты MWL в соответствующие биомы.", "Adds MWL trader locations to corresponding biomes.", "Добавляет торговые локации MWL в соответствующие биомы.", "All MWL locations to the world.", "Добавляет в мир все локации MWL.");
		}

		private static void AddMwlWaystones(List<LiteralPatchSpec> result, string guid)
		{
			Add(result, guid, "More_World_Locations_AIO.Waystones.WaystoneDB", "BuildWaystoneConfigs", "Odin's Waystone of The Dragur", "Путевой камень Одина: драугр", "Sunken Crypt", "Затонувший склеп", "Odin's Waystone of The Ulv", "Путевой камень Одина: ульв", "Frost Cave", "Ледяная пещера", "Odin's Waystone of The Seeker", "Путевой камень Одина: искатель", "Infested Mine", "Заражённая шахта", "Odin's Waystone of Far Sight", "Путевой камень дальнего зрения Одина");
			Add(result, guid, "More_World_Locations_AIO.Waystones.WaystoneDB", "GetDefaultWaystoneConfig", "Odin's Waystone", "Путевой камень Одина");
			Add(result, guid, "More_World_Locations_AIO.Waystones.WaystoneUtils", "GetWaystoneDetails", "Marks a ", "Отмечает ", " on map", " на карте", "Reveal a radius of {0} on map", "Открывает карту в радиусе {0}");
			Add(result, guid, "More_World_Locations_AIO.PortNames", "GetRandomName", "Port", "Порт");
		}

		private static void AddMwlShrineStats(List<LiteralPatchSpec> result, string guid)
		{
			Add(result, guid, "More_World_Locations_AIO.Shrines.ShrineUtils", "GetEffectDescription", "HP per tick", "Здоровье за тик", "Health over time", "Здоровье со временем", "Stamina over time", "Выносливость со временем", "Eitr over time", "Эйтр со временем", "Health regen", "Регенерация здоровья", "Stamina regen", "Регенерация выносливости", "Eitr regen", "Регенерация эйтра", "Carry weight", "Переносимый вес", " kg", " кг", "Speed", "Скорость", "Stealth", "Скрытность", "Noise", "Шум", "Fall damage", "Урон от падения", "Max fall speed", "Макс. скорость падения", " m/s", " м/с", "Run stamina drain", "Расход выносливости при беге", "Jump stamina use", "Расход выносливости на прыжок", "Attack stamina use", "Расход выносливости на атаку", "Block stamina use", "Расход выносливости на блок", "Dodge stamina use", "Расход выносливости на уклонение", "Swim stamina use", "Расход выносливости при плавании", "Sneak stamina use", "Расход выносливости при скрытности", "Run stamina use", "Расход выносливости при беге", "Skill: {0} +{1:0.#}", "Навык: {0} +{1:0.#}", "Damage mods: ", "Модификаторы урона: ");
		}

		private static void AddMwlStatusEffects(List<LiteralPatchSpec> result, string guid)
		{
			Add(result, guid, "More_World_Locations_AIO.Shrines.StatusEffectDB", "BuildStatusEffects", "Blessing of the Boar", "Благословение кабана", "Blessing of the Greydwarf", "Благословение грейдворфа", "Blessing of the Draugr", "Благословение драугра", "Blessing of the Wolf", "Благословение волка", "Blessing of the Fuling", "Благословение фулинга", "Blessing of the Seeker", "Благословение искателя", "Blessing of the Deer", "Благословение оленя", "Blessing of the Skeleton", "Благословение скелета", "Blessing of the Leech", "Благословение пиявки", "Blessing of the Hatchling", "Благословение дракончика", "Blessing of the Deathsquito", "Благословение комара смерти", "Blessing of the Hare", "Благословение зайца", "Blessing of the Neck", "Благословение никса", "Blessing of the Greydwarf Shaman", "Благословение шамана грейдворфов", "Blessing of the Wraith", "Благословение призрака", "Blessing of the Ulv", "Благословение ульва", "Blessing of the Fuling Shaman", "Благословение шамана фулингов", "Blessing of the Dvergr", "Благословение дверга", "Blessing of the Poison Skeleton", "Благословение ядовитого скелета", "Blessing of the Abomination", "Благословение порождения", "Blessing of the Cultist", "Благословение культиста", "Blessing of the Fuling Berserker", "Благословение берсерка фулингов", "Blessing of the Seeker Soldier", "Благословение солдата-искателя");
		}

		private static void AddVnei(List<LiteralPatchSpec> result)
		{
			Add(result, "com.maxsch.valheim.vnei", "VNEI.UI.HistoryElement", "Description", "Previous: ", "Назад: ", ", Next: ", ", вперёд: ");
			Add(result, "com.maxsch.valheim.vnei", "VNEI.UI.HistorySnapshotRecipe", "Description", "Recipe: ", "Рецепт: ");
			Add(result, "com.maxsch.valheim.vnei", "VNEI.UI.HistorySnapshotSearch", "Description", "Search", "Поиск");
			Add(result, "com.maxsch.valheim.vnei", "VNEI.Logic.FileWriterController", "get_Help", "Writes all indexed items to a file", "Записывает все проиндексированные предметы в файл");
			Add(result, "com.maxsch.valheim.vnei", "VNEI.Logic.IconExport", "get_Help", "Exports icons", "Экспортирует значки");
			Add(result, "com.maxsch.valheim.vnei", "VNEI.UI.SelectUITest+ToggleUIConsoleCommand", "get_Help", "Shows the selection test", "Показывает тестовое окно выбора");
			Add(result, "com.maxsch.valheim.vnei", "VNEI.Logic.Item", "PrintItem", " -- invalid item -- ", " -- недопустимый предмет -- ", "Internal Name: ", "Внутреннее имя: ", ", Localized Name: ", ", локализованное имя: ", ", Item Type: ", ", тип предмета: ", ", Description: ", ", описание: ", ", Source Mod: ", ", исходный мод: ");
			Add(result, "com.maxsch.valheim.vnei", "VNEI.Logic.Item", "PrintItemCSV", " -- invalid item -- ", " -- недопустимый предмет -- ");
			Add(result, "com.maxsch.valheim.vnei", "VNEI.Logic.Item", "PrintCSVHeader", "Internal Name", "Внутреннее имя", "Localized Name", "Локализованное имя", "Item Type", "Тип предмета", "Description", "Описание", "Source Mod", "Исходный мод");
		}

		private static void AddHuginn(List<LiteralPatchSpec> result)
		{
			Add(result, "nightofgames.huginn", "Huginn.Names", "GroupLabel", "Meadows", "Луга", "Black Forest", "Чёрный лес", "Swamp", "Болота", "Mountain", "Горы", "Plains", "Равнины", "Mistlands", "Туманные земли", "Ashlands", "Пепельные земли", "Deep North", "Крайний север", "Ocean", "Океан", "Anywhere", "Везде", "Other", "Прочее");
			Add(result, "nightofgames.huginn", "Huginn.Names", "Leaf", "Unknown", "Неизвестно", "Portal", "Портал", "Boat", "Судно", "Location", "Локация");
			Add(result, "nightofgames.huginn", "Huginn.Names", "Pretty", "Unknown", "Неизвестно");
			Add(result, "nightofgames.huginn", "Huginn.PinFilterUI", "BuildSkeleton", "Show all", "Показать всё", "Hide all", "Скрыть всё");
			Add(result, "nightofgames.huginn", "Huginn.PinFilterUI", "BuildGroup", "Toggle all ", "Переключить всё: ");
			AddHuginnCommands(result, "nightofgames.huginn");
		}

		private static void AddHuginnCommands(List<LiteralPatchSpec> result, string guid)
		{
			Add(result, guid, "Huginn.PinCleanup+PurgeCommand", "get_Help", "Remove pins copied onto your map from other players (cartography table). Your own pins and Huginn's pins are kept.", "Удаляет метки, скопированные на вашу карту у других игроков через картографический стол. Ваши метки и метки Huginn сохраняются.");
			Add(result, guid, "Huginn.PinCleanup+PurgeCommand", "Run", "Huginn: can't purge pins — no map loaded.", "Huginn: карта не загружена, удалить метки нельзя.", "Huginn: removed {0} imported foreign pin(s).", "Huginn: удалено чужих импортированных меток: {0}.");
			Add(result, guid, "Huginn.PinCleanup+ClearRadiusCommand", "get_Help", "huginn.clearpins <radius> — remove map pins within <radius> meters of you. Affects your own and other mods' pins; Huginn's managed pins are kept.", "huginn.clearpins <радиус> — удалить метки карты в указанном радиусе. Затрагивает ваши метки и метки других модов; метки Huginn сохраняются.");
			Add(result, guid, "Huginn.PinCleanup+ClearRadiusCommand", "Run", "Huginn: no map loaded.", "Huginn: карта не загружена.", "Usage: huginn.clearpins <radius>   e.g. huginn.clearpins 50", "Использование: huginn.clearpins <радиус>   пример: huginn.clearpins 50", "Huginn: no removable pins within {0:0}m.", "Huginn: в радиусе {0:0} м нет удаляемых меток.", "Huginn: removed {0} pin(s) within {1:0}m.", "Huginn: в радиусе {1:0} м удалено меток: {0}.");
			Add(result, guid, "Huginn.PinCleanup+LocationsCommand", "get_Help", "Log all world Location names grouped by biome (optionally filtered): huginn.locations [filter]", "Записать в журнал все локации мира по биомам (необязательный фильтр): huginn.locations [фильтр]");
			Add(result, guid, "Huginn.PinCleanup+LocationsCommand", "Run", "Huginn: ZoneSystem not ready.", "Huginn: система зон ещё не готова.", "Huginn: logged {0} locations to LogOutput.log.", "Huginn: локаций записано в LogOutput.log: {0}.");
			Add(result, guid, "Huginn.PinCleanup+LookingAtCommand", "get_Help", "Print the prefab name of the object you're looking at.", "Показать ID объекта, на который вы смотрите.");
			Add(result, guid, "Huginn.PinCleanup+LookingAtCommand", "Run", "Huginn: not looking at anything (aim at it and try again).", "Huginn: цель не найдена — наведитесь на объект и повторите.", " [MineRock, removeWhenDestroyed={0}, allDestroyed={1}]", " [MineRock, удалить после разрушения={0}, всё разрушено={1}]", " [MineRock5, allDestroyed={0}]", " [MineRock5, всё разрушено={0}]", " [components: ", " [компоненты: ", "none", "нет", "Huginn: looking at '", "Huginn: выбран объект «", "'", "»");
			Add(result, guid, "Huginn.PinCleanup+DumpCommand", "get_Help", "Log a summary of all map pins (type, owner, names) for diagnostics.", "Показать сводку всех меток карты: тип, владелец и названия.");
			Add(result, guid, "Huginn.PinCleanup+DumpCommand", "Run", "Huginn: no map loaded.", "Huginn: карта не загружена.", "Huginn: {0} pins across {1} type(s):", "Huginn: меток — {0}, типов — {1}:", "(unnamed)", "(без названия)", "  PinType {0}: {1} pins (foreign={2}, saved={3}) e.g. [{4}]", "  Тип метки {0}: {1} (чужих={2}, сохранённых={3}), например [{4}]");
		}

		private static void AddJotunn(List<LiteralPatchSpec> result)
		{
			Add(result, "com.jotunn.jotunn", "Jotunn.Managers.SkillManager", "Skills_CheatRaiseSkill", "Skill increased {0}: {1}", "Навык повышен — {0}: {1}", "Skill {0} = {1}", "Навык {0} = {1}");
			Add(result, "com.jotunn.jotunn", "Jotunn.Managers.SkillManager", "Skills_CheatResetSkill", "Skill ", "Навык «", " reset", "» сброшен");
			Add(result, "com.jotunn.jotunn", "Jotunn.Utils.UndoActions+UndoCreate", "UndoMessage", "Undo: Removed ", "Отмена: удалено ");
			Add(result, "com.jotunn.jotunn", "Jotunn.Utils.UndoActions+UndoCreate", "RedoMessage", "Redo: Restored ", "Повтор: восстановлено ");
			Add(result, "com.jotunn.jotunn", "Jotunn.Utils.UndoActions+UndoRemove", "UndoMessage", "Undo: Restored ", "Отмена: восстановлено ");
			Add(result, "com.jotunn.jotunn", "Jotunn.Utils.UndoActions+UndoRemove", "RedoMessage", "Redo: Removed ", "Повтор: удалено ");
			Add(result, "com.jotunn.jotunn", "Jotunn.Utils.UndoActions+UndoTerrain", "UndoMessage", "Undoing terrain changes", "Отмена изменений рельефа");
			Add(result, "com.jotunn.jotunn", "Jotunn.Utils.UndoActions+UndoTerrain", "RedoMessage", "Redoing terrain changes", "Повтор изменений рельефа");
			Add(result, "com.jotunn.jotunn", "Jotunn.Managers.UndoManager+UndoQueue", "Undo", "Nothing to undo.", "Нечего отменять.");
			Add(result, "com.jotunn.jotunn", "Jotunn.Managers.UndoManager+UndoQueue", "Redo", "Nothing to redo.", "Нечего повторять.");
		}

		private static void AddEpicLoot(List<LiteralPatchSpec> result)
		{
			Add(result, "randyknapp.mods.epicloot", "EpicLoot.Compendium.MagicSearchField", ".ctor", "Search...", "Поиск...");
			Add(result, "randyknapp.mods.epicloot", "EpicLoot.Adventure.Container_RPC_OpenRespons_Patch", "Postfix", "Treasure Found!", "Сокровище найдено!");
			Add(result, "randyknapp.mods.epicloot", "EpicLoot.General.TerminalCommands+LuckTestCommand", "get_Help", "Rolls an example loot table with the specified luck eg: lucktest Greydwarf 1.0", "Выполняет пробный розыгрыш добычи с указанной удачей, пример: lucktest Greydwarf 1.0");
			Add(result, "randyknapp.mods.epicloot", "EpicLoot.General.TerminalCommands+LuckTestCommand", "Run", "Using Lucktest Defaults: lucktest {0} {1}", "Используются значения lucktest по умолчанию: lucktest {0} {1}");
			Add(result, "randyknapp.mods.epicloot", "EpicLoot.General.TerminalCommands+LuckTestCommand", "PrintError", "lucktest invalid arguments, was 'lucktest ", "Недопустимые аргументы lucktest: «lucktest ", "using the default: 'lucktest {0} {1}'\n", "используется команда по умолчанию: «lucktest {0} {1}»\n", "Supported formats are:\n  lucktest\n  lucktest 1.2\n  lucktest Neck 1.2", "Допустимые форматы:\n  lucktest\n  lucktest 1.2\n  lucktest Neck 1.2");
			Add(result, "randyknapp.mods.epicloot", "EpicLoot.LootRoller", "PrintLuckTest", "Luck Test: {0}, {1}", "Проверка удачи: {0}, {1}", "Rarity     Base    %       Luck    %       Diff    Factor", "Редкость   База    %       Удача   %       Разн.   Множитель");
			AddEpicLootTerminalPatch(result, "randyknapp.mods.epicloot");
		}

		private static void AddEpicLootTerminalPatch(List<LiteralPatchSpec> result, string guid)
		{
			Add(result, guid, "EpicLoot.Terminal_Patch", "CheckStackQuality", "CheckStackQuality", "Проверка качества стопок", "> ObjectDB is null", "> База объектов не загружена", "> (none)", "> (нет)");
			Add(result, guid, "EpicLoot.Terminal_Patch", "MagicItem", "magicitem - rarity:{0}, item:{1}, count:{2}", "magicitem — редкость:{0}, предмет:{1}, количество:{2}", "> Could not find item: ", "> Предмет не найден: ", ">  {0} - rarity: [{1}], item: {2}", ">  {0} — редкость: [{1}], предмет: {2}");
			Add(result, guid, "EpicLoot.Terminal_Patch", "SpawnMagicItemWithEffect", "Specify effect and item name", "Укажите эффект и ID предмета", "magicitem - ", "magicitem — ", " with effect: ", " с эффектом: ", "> Could not find effect: ", "> Эффект не найден: ", "> Could not find item: ", "> Предмет не найден: ", "> Can't be magic item: ", "> Нельзя сделать магическим: ");
			Add(result, guid, "EpicLoot.Terminal_Patch", "SpawnLegendaryMagicItem", "> Specify legendaryID, itemID (optional)", "> Укажите legendaryID и необязательный itemID", "magicitemlegendary - legendaryID:", "magicitemlegendary — legendaryID:", "magicitemmythic - legendaryID:", "magicitemmythic — legendaryID:");
			Add(result, guid, "EpicLoot.Terminal_Patch", "SpawnLegendaryItemHelper", "> Could not find legendary/mythic info for legendaryID: (", "> Данные легендарного/мифического предмета не найдены для legendaryID: (", "> Could not find suitable items with parameter (", "> Подходящие предметы не найдены для параметра (", ") for legendaryID: (", ") и legendaryID: (", "> Could not find suitable item for legendaryID: (", "> Подходящий предмет не найден для legendaryID: (");
			Add(result, guid, "EpicLoot.Terminal_Patch", "SpawnMagicItemSet", "> Specify Set ID", "> Укажите ID комплекта", "magicitemset - setID:", "magicitemset — setID:", "> Could not find set info for setID: (", "> Данные комплекта не найдены для setID: (");
			Add(result, guid, "EpicLoot.Terminal_Patch", "ToggleAlwaysDrop", "> Always Drop: {0}", "> Всегда выпадать: {0}");
			Add(result, guid, "EpicLoot.Terminal_Patch", "OnTreasureChestSpawnComplete", "> Failed to spawn treasure map chest", "> Не удалось создать сундук карты сокровищ", "> Spawning Treasure Map Chest at <{0:0.#}, {1:0.#}> (height:{2:0.#})", "> Создание сундука карты сокровищ в <{0:0.#}, {1:0.#}> (высота:{2:0.#})");
			Add(result, guid, "EpicLoot.Terminal_Patch+<>c", "<Postfix>b__0_13", "> Disable gating for magic item drops: {0}", "> Ограничения выпадения магических предметов отключены: {0}");
			Add(result, guid, "EpicLoot.Terminal_Patch+<>c", "<Postfix>b__0_18", "> Treasure Map Debug Mode: {0}", "> Отладка карт сокровищ: {0}");
			Add(result, guid, "EpicLoot.Terminal_Patch+<>c", "<Postfix>b__0_19", "> Treasure Map Debug Mode: {0}", "> Отладка карт сокровищ: {0}");
			Add(result, guid, "EpicLoot.Terminal_Patch+<>c", "<Postfix>b__0_23", "Bounties for Interval {0}:", "Награды за период {0}:");
			Add(result, guid, "EpicLoot.Terminal_Patch+<>c", "<Postfix>b__0_24", "Player Bounties:", "Награды игрока:");
			Add(result, guid, "EpicLoot.Terminal_Patch+<>c", "<Postfix>b__0_27", "> Print Global Keys:", "> Глобальные ключи:");
		}

		private static void AddInventorySlots(List<LiteralPatchSpec> result)
		{
			Add(result, "sighsorry.InventorySlots", "InventorySlots.InventorySlotsPlugin", "RebuildSlotDefinitions", "Helmet", "Шлем", "Chest", "Нагрудник", "Legs", "Поножи", "Cape", "Плащ", "Utility", "Аксессуар", "Trinket", "Безделушка");
			Add(result, "sighsorry.InventorySlots", "InventorySlots.InventorySlotsPlugin", "AddJewelcraftingSlot", "Necklace", "Ожерелье", "Ring", "Кольцо");
			Add(result, "sighsorry.InventorySlots", "InventorySlots.InventorySlotsPlugin", "TryAddAdventureBackpackSlot", "Backpack", "Рюкзак");
			Add(result, "sighsorry.InventorySlots", "InventorySlots.InventorySlotsPlugin", "TryAddSmoothbrainBackpackSlot", "Backpack", "Рюкзак");
			Add(result, "sighsorry.InventorySlots", "InventorySlots.InventorySlotsPlugin", "TryAddRustyBagSlot", "Bag", "Сумка");
			Add(result, "sighsorry.InventorySlots", "InventorySlots.InventorySlotsPlugin", "TryAddRustyQuiverSlot", "Quiver", "Колчан");
			Add(result, "sighsorry.InventorySlots", "InventorySlots.InventorySlotsPlugin", "TryAddMagicSupremacyCompatSlot", "MagicBelt", "Магический пояс");
		}

		private static void AddCreatureLevelControl(List<LiteralPatchSpec> result)
		{
			Add(result, "org.bepinex.plugins.creaturelevelcontrol", "CreatureLevelControl.CreatureLevelControl+PatchTerminal", "Prefix", "Removed all nearby creatures with at least ", "Удалены все ближайшие существа как минимум с ", " stars", " звёздами", "Removed all nearby creatures", "Удалены все ближайшие существа", "Current world level: ", "Текущий уровень мира: ", "Kills in the current sector: ", "Убийств в текущем секторе: ", "Reset all nearby creature sectors", "Сброшены все ближайшие секторы существ", "Current star chances", "Текущие шансы звёзд", " for ", " для ", " star: ", " звёзд: ", " is not a creature", " не является существом", "Spawning object ", "Создание объекта ", "Unknown effect ", "Неизвестный эффект ", "CLLC console commands - use 'cllc' followed by one of the following options", "Команды CLLC — введите 'cllc', затем один из следующих параметров", "killhighstars [stars] - removes all nearby creatures with at least stars. Default stars is 6.", "killhighstars [звёзды] — удаляет всех ближайших существ с указанным минимумом звёзд. По умолчанию: 6.", "killall - removes all nearby creatures", "killall — удаляет всех ближайших существ", "worldlevel - displays the current world level", "worldlevel — показывает текущий уровень мира", "sectorkills - displays the creatures killed in the current sector", "sectorkills — показывает число существ, убитых в текущем секторе", "resetsector - resets all nearby creature sectors", "resetsector — сбрасывает все ближайшие секторы существ", "starchance [creature] - displays the current star chances. Optionally for a specific creature.", "starchance [существо] — показывает текущие шансы звёзд, при необходимости для конкретного существа.", "spawn [creature] [level] [affix] [extraeffect] [infusion] - spawns a creature with the provided properties.", "spawn [существо] [уровень] [аффикс] [допэффект] [инфузия] — создаёт существо с указанными свойствами.", "You are not allowed to use this command on this server.", "Вам запрещено использовать эту команду на этом сервере.");
			Add(result, "org.bepinex.plugins.creaturelevelcontrol", "CreatureLevelControl.CreatureSector+PatchMinimapAwake", "Postfix", "Sector Level: 0", "Уровень сектора: 0");
		}

		private static void AddXPortal(List<LiteralPatchSpec> result)
		{
			Add(result, "yay.spikehimself.xportal", "XPortal.KnownPortal", "GetFriendlyTargetName", "{0} (invalid)", "{0} (недействителен)");
			Add(result, "yay.spikehimself.xportal", "XPortal.UI.PortalConfigurationPanel", "PopulateDropdown", "{0:0.0} km", "{0:0.0} км", "{0} m", "{0} м");
			Add(result, "yay.spikehimself.xportal", "XPortal.XPortal", "OnPrePortalHover", "Fetching portal info...", "Получение данных портала...");
			Add(result, "yay.spikehimself.xportal", "XPortal.Patches.TeleportWorld_GetHoverText", "Prefix", "This portal doesn't actually appear to exist. Heimdallr sees you...", "Похоже, этого портала не существует. Хеймдалль видит тебя...");
		}

		private static void AddBalrondShipyard(List<LiteralPatchSpec> result)
		{
			AddShipyardInteractionText(result, "balrond.astafaraios.BalrondShipyard");
			AddShipyardFactoryText(result, "balrond.astafaraios.BalrondShipyard");
		}

		private static void AddShipyardInteractionText(List<LiteralPatchSpec> result, string guid)
		{
			Add(result, guid, "BalrondShipyard.ShipyardStation", "GetLeverHoverText", "[<color=yellow><b>$KEY_Use</b></color>] Upgrade Ship", "[<color=yellow><b>$KEY_Use</b></color>] Улучшить судно");
			Add(result, guid, "BalrondShipyard.ShipyardStation", "RPC_ShipyardRespons", "Upgrade Added", "Улучшение установлено", "Wrong resource amount - failed to upgrade", "Неверное количество ресурсов — улучшение не выполнено", "Cargo is empty", "Грузовой отсек пуст", "Shipyard is in use", "Верфь уже используется", "No Ship in range", "Поблизости нет судна", "There is no ship avaible for that upgrade", "Нет судна, подходящего для этого улучшения", "Something went wrong", "Что-то пошло не так");
			Add(result, guid, "BalrondShipyard.ShipSwitch", "GetHoverText", "\n[<color=yellow><b>$KEY_Use</b></color>] Disable", "\n[<color=yellow><b>$KEY_Use</b></color>] Выключить", "\n[<color=yellow><b>$KEY_Use</b></color>] Enable", "\n[<color=yellow><b>$KEY_Use</b></color>] Включить");
			Add(result, guid, "BalrondShipyard.ShipSwitch", "Awake", " Active Me", " Переключатель");
			Add(result, guid, "BalrondShipyard.ShipSwitch", "Interact", " was ", " — ", "turned off", "выключено", "turned on", "включено");
			Add(result, guid, "BalrondShipyard.AnchorSwitch", ".ctor", "Anchor", "Якорь");
			Add(result, guid, "BalrondShipyard.AnchorSwitch", "GetHoverText", "\n[<color=yellow><b>$KEY_Use</b></color>] Drop Anchor", "\n[<color=yellow><b>$KEY_Use</b></color>] Бросить якорь", "\n[<color=yellow><b>$KEY_Use</b></color>] Pull Anchor", "\n[<color=yellow><b>$KEY_Use</b></color>] Поднять якорь");
			Add(result, guid, "BalrondShipyard.AnchorSwitch", "Interact", " picked up", " поднят", " dropped", " брошен");
			Add(result, guid, "BalrondShipyard.FishnetTrap", ".ctor", "FishnetTrap", "Рыболовная ловушка", "Add Fishbait", "Добавить наживку", "Empty the basket", "Опустошить корзину");
			Add(result, guid, "BalrondShipyard.ShipFishnet", ".ctor", "Pick Fishes", "Забрать рыбу", "Out of Luck", "Не повезло", "Add Bait", "Добавить наживку", "Set sail to catch fishes", "Поднимите парус, чтобы ловить рыбу", "Can't pick up the net. Inventory is busy/full", "Нельзя забрать сеть: инвентарь занят или заполнен", "Fishnet is empty", "Сеть пуста");
			Add(result, guid, "BalrondShipyard.ShieldPainter", ".ctor", "Paint Shields", "Раскрасить щиты");
			Add(result, guid, "BalrondShipyard.ShipProcessor", "setupShipyard", "Upgrade Ship", "Улучшить судно");
			Add(result, guid, "BalrondShipyard.ShipProcessor", "setupAnchor", "Anchor", "Якорь");
			Add(result, guid, "BalrondShipyard.ShipProcessor", "setupAnchorDrakkar", "Anchor", "Якорь");
			Add(result, guid, "BalrondShipyard.ShipProcessor", "setupLamp", "Lamp", "Фонарь");
			Add(result, guid, "BalrondShipyard.ShipOwnerName", "GetHoverText", "Restricted\n", "Доступ запрещён\n", "\n[<color=yellow><b>$KEY_Use</b></color>] Change Name", "\n[<color=yellow><b>$KEY_Use</b></color>] Изменить имя", "\n[<color=yellow><b>$KEY_Use</b></color>] Set Ship Name", "\n[<color=yellow><b>$KEY_Use</b></color>] Задать имя судна", "\n[Owner] ", "\n[Владелец] ", "Unclaimed ship \n[<color=yellow><b>$KEY_Use</b></color>] $piece_bed_claim", "Судно без владельца \n[<color=yellow><b>$KEY_Use</b></color>] $piece_bed_claim");
			Add(result, guid, "BalrondShipyard.ShipRamp", ".ctor", "ramp", "Трап");
			Add(result, guid, "BalrondBiomes.SE_WetImmunity", "Awake", "Immune to wet effect", "Невосприимчивость к эффекту промокания");
		}

		private static void AddShipyardFactoryText(List<LiteralPatchSpec> result, string guid)
		{
			Add(result, guid, "BalrondShipyard.ShipExtensionFactory", "createItemDescription", "\n Require: \n", "\n Требуется: \n", "Schematic x 1", "Чертёж x 1");
			Add(result, guid, "BalrondShipyard.ShipExtensionFactory", "createAnchor", "Adds Anchor. You gain ability to stop your ship in place", "Добавляет якорь, позволяющий остановить судно на месте");
			Add(result, guid, "BalrondShipyard.ShipExtensionFactory", "createArmor", "Add Carapace armor. Increase ships health and resistance against pierce damage", "Добавляет панцирную броню, повышающую прочность судна и сопротивление колющему урону");
			Add(result, guid, "BalrondShipyard.ShipExtensionFactory", "createAshlandsDrakkarTent", "Adds Tent. Increase health by 200", "Добавляет шатёр и повышает прочность на 200");
			Add(result, guid, "BalrondShipyard.ShipExtensionFactory", "createAshlandsRopes", "Adds side ropes. Allows you to get to upper deck from water level", "Добавляет боковые канаты, по которым можно подняться из воды на верхнюю палубу");
			Add(result, guid, "BalrondShipyard.ShipExtensionFactory", "createAshlandsSupply", "Adds supplies. Increase ship blunt resistance", "Добавляет припасы и повышает сопротивление судна дробящему урону");
			Add(result, guid, "BalrondShipyard.ShipExtensionFactory", "createDrakkarFishnet", "Adds fishnet. You can fuel it with fishing bait to catch fish while sailing. Require at leas t1 empty slot in ship's cargo!", "Добавляет рыболовную сеть. Заправьте её наживкой, чтобы ловить рыбу во время плавания. В грузовом отсеке судна нужна хотя бы одна свободная ячейка!");
			Add(result, guid, "BalrondShipyard.ShipExtensionFactory", "createDrakkarRam", "Adds Iron Spike Ram. You gain ability to ram with front spikes. REQUIRE ARMOR UPGRADE", "Добавляет таран с железными шипами. Позволяет таранить носом судна. ТРЕБУЕТ УЛУЧШЕНИЯ БРОНИ");
			Add(result, guid, "BalrondShipyard.ShipExtensionFactory", "createDrakkarSupply", "Adds Barrels. Increase blunt resistance and health", "Добавляет бочки, повышающие прочность и сопротивление дробящему урону");
			Add(result, guid, "BalrondShipyard.ShipExtensionFactory", "createDrakkarSupply2", "Adds Crates. Increase slash resistance and health", "Добавляет ящики, повышающие прочность и сопротивление рубящему урону");
			Add(result, guid, "BalrondShipyard.ShipExtensionFactory", "createDrakkarTent", "Adds Tent. Gain shelter status. Increase health by 300", "Добавляет шатёр, даёт эффект укрытия и повышает прочность на 300");
			Add(result, guid, "BalrondShipyard.ShipExtensionFactory", "createHolkRamp", "Adds cage and ramp for transporting animals", "Добавляет клетку и трап для перевозки животных");
			Add(result, guid, "BalrondShipyard.ShipExtensionFactory", "createHolkRopes", "Adds side ropes. Allows you to get to upper deck from water level", "Добавляет боковые канаты, по которым можно подняться из воды на верхнюю палубу");
			Add(result, guid, "BalrondShipyard.ShipExtensionFactory", "createHolkSu

BepInEx\plugins\System.ValueTuple.dll

Decompiled 2 weeks ago
using System;
using System.Diagnostics;
using System.Reflection;
using System.Resources;
using System.Runtime.CompilerServices;
using FxResources.System.ValueTuple;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: NeutralResourcesLanguage("en-US")]
[assembly: AssemblyTitle("System.ValueTuple")]
[assembly: AssemblyDescription("System.ValueTuple")]
[assembly: AssemblyDefaultAlias("System.ValueTuple")]
[assembly: AssemblyCompany("Microsoft Corporation")]
[assembly: AssemblyProduct("Microsoft® .NET Framework")]
[assembly: AssemblyCopyright("© Microsoft Corporation.  All rights reserved.")]
[assembly: AssemblyFileVersion("4.6.26011.01")]
[assembly: AssemblyInformationalVersion("4.6.26011.01 built by: dlab-DDVSOWINAGE026. ")]
[assembly: CLSCompliant(true)]
[assembly: AssemblyMetadata(".NETFrameworkAssembly", "")]
[assembly: AssemblyMetadata("Serviceable", "True")]
[assembly: AssemblyMetadata("PreferInbox", "True")]
[assembly: AssemblyVersion("4.0.2.0")]
[assembly: TypeForwardedTo(typeof(TupleElementNamesAttribute))]
[assembly: TypeForwardedTo(typeof(TupleExtensions))]
[assembly: TypeForwardedTo(typeof(ValueTuple))]
[assembly: TypeForwardedTo(typeof(ValueTuple<>))]
[assembly: TypeForwardedTo(typeof(ValueTuple<, >))]
[assembly: TypeForwardedTo(typeof(ValueTuple<, , >))]
[assembly: TypeForwardedTo(typeof(ValueTuple<, , , >))]
[assembly: TypeForwardedTo(typeof(ValueTuple<, , , , >))]
[assembly: TypeForwardedTo(typeof(ValueTuple<, , , , , >))]
[assembly: TypeForwardedTo(typeof(ValueTuple<, , , , , , >))]
[assembly: TypeForwardedTo(typeof(ValueTuple<, , , , , , , >))]
namespace FxResources.System.ValueTuple
{
	internal static class SR
	{
	}
}
namespace System
{
	internal static class SR
	{
		private static ResourceManager s_resourceManager;

		private const string s_resourcesName = "FxResources.System.ValueTuple.SR";

		private static ResourceManager ResourceManager => s_resourceManager ?? (s_resourceManager = new ResourceManager(ResourceType));

		internal static string ArgumentException_ValueTupleIncorrectType => GetResourceString("ArgumentException_ValueTupleIncorrectType", null);

		internal static string ArgumentException_ValueTupleLastArgumentNotAValueTuple => GetResourceString("ArgumentException_ValueTupleLastArgumentNotAValueTuple", null);

		internal static Type ResourceType => typeof(SR);

		[MethodImpl(MethodImplOptions.NoInlining)]
		private static bool UsingResourceKeys()
		{
			return false;
		}

		internal static string GetResourceString(string resourceKey, string defaultString)
		{
			string text = null;
			try
			{
				text = ResourceManager.GetString(resourceKey);
			}
			catch (MissingManifestResourceException)
			{
			}
			if (defaultString != null && resourceKey.Equals(text, StringComparison.Ordinal))
			{
				return defaultString;
			}
			return text;
		}

		internal static string Format(string resourceFormat, params object[] args)
		{
			if (args != null)
			{
				if (UsingResourceKeys())
				{
					return resourceFormat + string.Join(", ", args);
				}
				return string.Format(resourceFormat, args);
			}
			return resourceFormat;
		}

		internal static string Format(string resourceFormat, object p1)
		{
			if (UsingResourceKeys())
			{
				return string.Join(", ", resourceFormat, p1);
			}
			return string.Format(resourceFormat, p1);
		}

		internal static string Format(string resourceFormat, object p1, object p2)
		{
			if (UsingResourceKeys())
			{
				return string.Join(", ", resourceFormat, p1, p2);
			}
			return string.Format(resourceFormat, p1, p2);
		}

		internal static string Format(string resourceFormat, object p1, object p2, object p3)
		{
			if (UsingResourceKeys())
			{
				return string.Join(", ", resourceFormat, p1, p2, p3);
			}
			return string.Format(resourceFormat, p1, p2, p3);
		}
	}
}