using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Reflection;
using System.Reflection.Emit;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Text;
using System.Text.RegularExpressions;
using BepInEx;
using BepInEx.Bootstrap;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using Newtonsoft.Json.Linq;
using TMPro;
using UnityEngine;
using UnityEngine.TextCore.LowLevel;
[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("CampfireCardsRU")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0")]
[assembly: AssemblyProduct("Campfire Cards RU")]
[assembly: AssemblyTitle("CampfireCardsRU")]
[assembly: AssemblyVersion("1.0.0.0")]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
[CompilerGenerated]
[Embedded]
internal sealed class EmbeddedAttribute : Attribute
{
}
}
namespace System.Runtime.CompilerServices
{
[CompilerGenerated]
[Embedded]
[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
internal sealed class RefSafetyRulesAttribute : Attribute
{
public readonly int Version;
public RefSafetyRulesAttribute(int P_0)
{
Version = P_0;
}
}
}
namespace CampfireCardsRU
{
public enum FontChoice
{
Auto,
Game,
Mod
}
internal static class Fonts
{
public const string RtlcId = "ru.RTLC.fontreplacer";
private static string _pluginDir;
private static TMP_FontAsset _own;
private static bool _ownTried;
private static string _lastSource;
public static void Install(Harmony harmony, Assembly campfireCards, string pluginDir)
{
//IL_004d: Unknown result type (might be due to invalid IL or missing references)
//IL_005b: Expected O, but got Unknown
_pluginDir = pluginDir;
MethodInfo methodInfo = AccessTools.PropertyGetter(campfireCards.GetType("CampfireCards.Ui.UiKit"), "Font");
if (methodInfo == null)
{
Plugin.Log.LogWarning((object)"Campfire Cards has no UiKit.Font; its font is left as it is.");
}
else
{
harmony.Patch((MethodBase)methodInfo, new HarmonyMethod(AccessTools.Method(typeof(Fonts), "FontPrefix", (Type[])null, (Type[])null)), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
}
}
private static bool FontPrefix(ref TMP_FontAsset __result)
{
if (!Tr.Active)
{
return true;
}
string source;
TMP_FontAsset val = Pick(out source);
if ((Object)(object)val == (Object)null)
{
return true;
}
if (source != _lastSource)
{
_lastSource = source;
Plugin.Log.LogInfo((object)("Font for Russian text: " + source + " (" + ((Object)val).name + ")"));
}
__result = val;
return false;
}
internal static TMP_FontAsset Pick(out string source)
{
source = null;
switch ((Plugin.Font != null) ? Plugin.Font.Value : FontChoice.Auto)
{
case FontChoice.Mod:
return null;
case FontChoice.Auto:
{
TMP_FontAsset val = Rtlc();
if ((Object)(object)val != (Object)null)
{
source = "PEAK Russian Translation";
return val;
}
TMP_FontAsset val2 = Own();
if ((Object)(object)val2 != (Object)null)
{
source = "the font folder";
return val2;
}
break;
}
}
TMP_FontAsset val3 = null;
try
{
val3 = TMP_Settings.defaultFontAsset;
}
catch
{
}
if ((Object)(object)val3 != (Object)null)
{
source = "the game's default font";
}
return val3;
}
private static TMP_FontAsset Rtlc()
{
try
{
if (!Chainloader.PluginInfos.TryGetValue("ru.RTLC.fontreplacer", out var value) || (Object)(object)value.Instance == (Object)null)
{
return null;
}
FieldInfo field = ((object)value.Instance).GetType().GetField("newFontTextMeshPro", BindingFlags.Static | BindingFlags.Public);
return (TMP_FontAsset)((field != null) ? /*isinst with value type is only supported in some contexts*/: null);
}
catch
{
return null;
}
}
private static TMP_FontAsset Own()
{
if (_ownTried)
{
return _own;
}
_ownTried = true;
try
{
string path = Path.Combine(_pluginDir ?? "", "font");
if (!Directory.Exists(path))
{
return null;
}
string text = null;
string[] files = Directory.GetFiles(path);
foreach (string text2 in files)
{
string text3 = Path.GetExtension(text2).ToLowerInvariant();
if (text3 == ".ttf" || text3 == ".otf")
{
text = text2;
break;
}
}
if (text == null)
{
return null;
}
TMP_FontAsset val = TMP_FontAsset.CreateFontAsset(text, 0, 90, 9, (GlyphRenderMode)4165, 1024, 1024);
if ((Object)(object)val == (Object)null)
{
return null;
}
((Object)val).name = Path.GetFileNameWithoutExtension(text);
val.isMultiAtlasTexturesEnabled = true;
val.boldStyle = 0.3f;
val.boldSpacing = 2f;
TMP_FontAsset val2 = null;
try
{
val2 = TMP_Settings.defaultFontAsset;
}
catch
{
}
if ((Object)(object)val2 != (Object)null)
{
val.fallbackFontAssetTable = new List<TMP_FontAsset> { val2 };
}
((Object)val).hideFlags = (HideFlags)52;
if ((Object)(object)((TMP_Asset)val).material != (Object)null)
{
((Object)((TMP_Asset)val).material).hideFlags = (HideFlags)52;
}
if ((Object)(object)val.atlasTexture != (Object)null)
{
((Object)val.atlasTexture).hideFlags = (HideFlags)52;
}
_own = val;
}
catch (Exception ex)
{
Plugin.Log.LogWarning((object)("The font in the font folder could not be loaded: " + ex.Message));
}
return _own;
}
}
internal sealed class Lang
{
public string MadeFor = "";
public readonly Dictionary<string, string> Strings = new Dictionary<string, string>(StringComparer.Ordinal);
public readonly Dictionary<string, Dictionary<string, string>> Scoped = new Dictionary<string, Dictionary<string, string>>(StringComparer.Ordinal);
public readonly Dictionary<string, string> CardText = new Dictionary<string, string>(StringComparer.Ordinal);
public readonly Dictionary<string, string> Rarities = new Dictionary<string, string>(StringComparer.Ordinal);
public readonly Dictionary<string, string> Statuses = new Dictionary<string, string>(StringComparer.Ordinal);
public readonly List<KeyValuePair<Regex, string>> Patterns = new List<KeyValuePair<Regex, string>>();
public int Count => Strings.Count + CardText.Count + Rarities.Count + Statuses.Count + ScopedCount + Patterns.Count;
private int ScopedCount
{
get
{
int num = 0;
foreach (KeyValuePair<string, Dictionary<string, string>> item in Scoped)
{
num += item.Value.Count;
}
return num;
}
}
public bool MatchesPattern(string s)
{
for (int i = 0; i < Patterns.Count; i++)
{
if (Patterns[i].Key.IsMatch(s))
{
return true;
}
}
return false;
}
public string ApplyPattern(string s)
{
for (int i = 0; i < Patterns.Count; i++)
{
if (Patterns[i].Key.IsMatch(s))
{
return Patterns[i].Key.Replace(s, Patterns[i].Value);
}
}
return s;
}
public static Lang Load(string path)
{
Lang lang = new Lang();
JObject val = JObject.Parse(File.ReadAllText(path));
lang.MadeFor = ((string)val["madeFor"]) ?? "";
JToken obj = val["strings"];
Fill((JObject)(object)((obj is JObject) ? obj : null), lang.Strings);
JToken obj2 = val["rarities"];
Fill((JObject)(object)((obj2 is JObject) ? obj2 : null), lang.Rarities);
JToken obj3 = val["statuses"];
Fill((JObject)(object)((obj3 is JObject) ? obj3 : null), lang.Statuses);
JToken obj4 = val["scoped"];
JObject val2 = (JObject)(object)((obj4 is JObject) ? obj4 : null);
if (val2 != null)
{
foreach (JProperty item in val2.Properties())
{
Dictionary<string, string> dictionary = new Dictionary<string, string>(StringComparer.Ordinal);
JToken value = item.Value;
Fill((JObject)(object)((value is JObject) ? value : null), dictionary);
if (dictionary.Count > 0)
{
lang.Scoped[item.Name] = dictionary;
}
}
}
JToken obj5 = val["patterns"];
JArray val3 = (JArray)(object)((obj5 is JArray) ? obj5 : null);
if (val3 != null)
{
foreach (JToken item2 in val3)
{
string text = (string)item2[(object)"match"];
string text2 = (string)item2[(object)"ru"];
if (!string.IsNullOrEmpty(text) && text2 != null)
{
try
{
lang.Patterns.Add(new KeyValuePair<Regex, string>(new Regex(text), text2));
}
catch (ArgumentException)
{
}
}
}
}
JToken obj6 = val["cards"];
JObject val4 = (JObject)(object)((obj6 is JObject) ? obj6 : null);
if (val4 != null)
{
foreach (JProperty item3 in val4.Properties())
{
JToken obj7 = item3.Value[(object)"en"];
JObject val5 = (JObject)(object)((obj7 is JObject) ? obj7 : null);
JToken obj8 = item3.Value[(object)"ru"];
JObject val6 = (JObject)(object)((obj8 is JObject) ? obj8 : null);
if (val5 == null || val6 == null)
{
continue;
}
foreach (JProperty item4 in val5.Properties())
{
string text3 = (string)item4.Value;
string value2 = (string)val6[item4.Name];
if (!string.IsNullOrEmpty(text3) && !string.IsNullOrEmpty(value2))
{
lang.CardText[text3] = value2;
}
}
}
}
return lang;
}
private static void Fill(JObject from, Dictionary<string, string> into)
{
//IL_001f: Unknown result type (might be due to invalid IL or missing references)
//IL_0025: Invalid comparison between Unknown and I4
if (from == null)
{
return;
}
foreach (JProperty item in from.Properties())
{
if ((int)item.Value.Type == 8)
{
string value = (string)item.Value;
if (!string.IsNullOrEmpty(value))
{
into[item.Name] = value;
}
}
}
}
}
public enum Mode
{
Auto,
Always,
Off
}
[BepInPlugin("cavycrew.campfirecards.ru", "Campfire Cards RU", "1.0.0")]
[BepInDependency(/*Could not decode attribute arguments.*/)]
[BepInDependency(/*Could not decode attribute arguments.*/)]
public class Plugin : BaseUnityPlugin
{
public const string Id = "cavycrew.campfirecards.ru";
public const string Name = "Campfire Cards RU";
public const string Version = "1.0.0";
public const string TargetId = "notnic.campfirecards";
internal static ManualLogSource Log;
internal static ConfigEntry<Mode> Language;
internal static ConfigEntry<FontChoice> Font;
private void Awake()
{
//IL_0145: Unknown result type (might be due to invalid IL or missing references)
//IL_014c: Expected O, but got Unknown
Log = ((BaseUnityPlugin)this).Logger;
Language = ((BaseUnityPlugin)this).Config.Bind<Mode>("General", "Language", Mode.Auto, "Auto: карты на русском, когда сама игра на русском. Always: на русском всегда. Off: оригинальный английский. (Auto: Russian when the game is set to Russian. Always: always Russian. Off: the mod's own English.)");
Font = ((BaseUnityPlugin)this).Config.Bind<FontChoice>("General", "Font", FontChoice.Auto, "Шрифт русского текста. Auto: шрифт из папки font рядом с этим модом (Darumadrop One с кириллицей; файл можно заменить своим .ttf или .otf). Если установлен мод PEAK Russian Translation, берется его шрифт. Game: шрифт игры. Mod: не трогать шрифт Campfire Cards. (Font for Russian text. Auto: the font in this mod's font folder, a Cyrillic Darumadrop One; replace the file with any .ttf/.otf. With the PEAK Russian Translation mod installed, its font is used. Game: the game's font. Mod: leave the Campfire Cards font alone.)");
string text = Path.GetDirectoryName(((BaseUnityPlugin)this).Info.Location) ?? "";
string text2 = Path.Combine(text, "ru.json");
Lang lang;
try
{
lang = Lang.Load(text2);
}
catch (Exception ex)
{
((BaseUnityPlugin)this).Logger.LogError((object)("Translation file could not be read (" + text2 + "): " + ex.Message + ". Campfire Cards stays in English."));
return;
}
if (!Chainloader.PluginInfos.TryGetValue("notnic.campfirecards", out var value) || (Object)(object)value.Instance == (Object)null)
{
((BaseUnityPlugin)this).Logger.LogWarning((object)"Campfire Cards is not loaded; nothing to translate.");
return;
}
Tr.Lang = lang;
Tr.IsOn = IsOn;
string text3 = value.Metadata.Version.ToString();
Assembly assembly = ((object)value.Instance).GetType().Assembly;
Stopwatch stopwatch = Stopwatch.StartNew();
Harmony harmony = new Harmony("cavycrew.campfirecards.ru");
Rewriter.Result result = Rewriter.Apply(harmony, assembly, lang, (Action<string>)((BaseUnityPlugin)this).Logger.LogInfo);
stopwatch.Stop();
try
{
Fonts.Install(harmony, assembly, text);
}
catch (Exception ex2)
{
((BaseUnityPlugin)this).Logger.LogWarning((object)("Font support is off: " + ex2.Message));
}
((BaseUnityPlugin)this).Logger.LogInfo((object)(string.Format("Russian translation {0} for Campfire Cards {1}: {2} texts, ", "1.0.0", text3, lang.Count) + $"{result.Methods} display methods rewritten ({result.Literals} literals, {result.Fields} table reads, " + $"{result.Calls} calls) in {stopwatch.ElapsedMilliseconds} ms, {result.Failed} skipped. " + "Display text only: cards, rules, saves and network are untouched."));
if (!string.IsNullOrEmpty(lang.MadeFor) && lang.MadeFor != text3)
{
((BaseUnityPlugin)this).Logger.LogInfo((object)("The translation was written for Campfire Cards " + lang.MadeFor + "; texts added or changed in " + text3 + " stay in English."));
}
}
private static bool IsOn()
{
//IL_0019: Unknown result type (might be due to invalid IL or missing references)
//IL_001f: Invalid comparison between Unknown and I4
return Language.Value switch
{
Mode.Always => true,
Mode.Off => false,
_ => (int)LocalizedText.CURRENT_LANGUAGE == 7,
};
}
}
internal static class Rewriter
{
public struct Result
{
public int Methods;
public int Literals;
public int Fields;
public int Calls;
public int Failed;
}
private enum Kind
{
None,
Literal,
ScopedLiteral,
CardField,
StatField,
PhraseTable,
NameCall,
RarityCall,
StatusCall,
SetText,
GetText
}
private static readonly MethodInfo S = AccessTools.Method(typeof(Tr), "S", (Type[])null, (Type[])null);
private static readonly MethodInfo S2 = AccessTools.Method(typeof(Tr), "S2", (Type[])null, (Type[])null);
private static readonly MethodInfo Card = AccessTools.Method(typeof(Tr), "Card", (Type[])null, (Type[])null);
private static readonly MethodInfo Rarity = AccessTools.Method(typeof(Tr), "Rarity", (Type[])null, (Type[])null);
private static readonly MethodInfo Status = AccessTools.Method(typeof(Tr), "Status", (Type[])null, (Type[])null);
private static readonly MethodInfo Arr = AccessTools.Method(typeof(Tr), "Arr", (Type[])null, (Type[])null);
private static readonly MethodInfo SetText = AccessTools.Method(typeof(Tr), "SetText", (Type[])null, (Type[])null);
private static readonly MethodInfo GetText = AccessTools.Method(typeof(Tr), "GetText", (Type[])null, (Type[])null);
private static readonly HashSet<string> KeepEnglishNames = new HashSet<string>(StringComparer.Ordinal) { "CampfireCards.Plugin", "CampfireCards.Hooks", "CampfireCards.Cards.Deck", "CampfireCards.Cards.Effects", "CampfireCards.Cards.LocalCards", "CampfireCards.Cards.RunMemoryFile", "CampfireCards.Abilities.AbilityRegistry", "CampfireCards.Core.ReportJson", "CampfireCards.Ui.BugReportScreen" };
private static readonly HashSet<string> StatFields = new HashSet<string>(StringComparer.Ordinal) { "ChannelDef.Label", "ChannelDef.More", "ChannelDef.Less", "ChannelDef.Never", "StatWords.More", "StatWords.Less", "StatWords.Never", "StatLine.Label", "Row.Label" };
private static readonly HashSet<string> CardFields = new HashSet<string>(StringComparer.Ordinal) { "CardDef.Name", "CardDef.Positive", "CardDef.Negative", "CardDef.Flavor" };
private static readonly HashSet<string> PhraseTables = new HashSet<string>(StringComparer.Ordinal) { "ConditionTable.Shown", "ConditionTable.Meaning", "DifficultyScale.TierNames", "SettingsFingerprint.RuleNames" };
private static Lang _lang;
public static Result Apply(Harmony harmony, Assembly target, Lang lang, Action<string> warn)
{
//IL_0024: Unknown result type (might be due to invalid IL or missing references)
//IL_002a: Expected O, but got Unknown
_lang = lang;
Result result = default(Result);
HarmonyMethod val = new HarmonyMethod(AccessTools.Method(typeof(Rewriter), "Transpile", (Type[])null, (Type[])null));
Type[] array;
try
{
array = target.GetTypes();
}
catch (ReflectionTypeLoadException ex)
{
array = Array.FindAll(ex.Types, (Type t) => t != null);
}
Type[] array2 = array;
foreach (Type type in array2)
{
if (type.ContainsGenericParameters)
{
continue;
}
string text = OuterName(type);
List<MethodBase> list = new List<MethodBase>();
list.AddRange(type.GetMethods(BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic));
list.AddRange(type.GetConstructors(BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic));
foreach (MethodBase item in list)
{
if (item.IsAbstract || item.ContainsGenericParameters || (item.IsConstructor && item.IsStatic) || item.GetMethodBody() == null)
{
continue;
}
int literals = 0;
int fields = 0;
int calls = 0;
try
{
foreach (KeyValuePair<OpCode, object> item2 in PatchProcessor.ReadMethodBody(item))
{
Classify(item2.Key, item2.Value, text, ref literals, ref fields, ref calls);
}
if (literals + fields + calls != 0)
{
harmony.Patch(item, (HarmonyMethod)null, (HarmonyMethod)null, val, (HarmonyMethod)null, (HarmonyMethod)null);
result.Methods++;
result.Literals += literals;
result.Fields += fields;
result.Calls += calls;
}
}
catch (Exception ex2)
{
result.Failed++;
int num2 = 0;
try
{
foreach (KeyValuePair<OpCode, object> item3 in PatchProcessor.ReadMethodBody(item))
{
if (!(item3.Key != OpCodes.Ldstr) && item3.Value is string text2)
{
string value = null;
if (lang.Scoped.TryGetValue(text, out var value2))
{
value2.TryGetValue(text2, out value);
}
if (value == null)
{
lang.Strings.TryGetValue(text2, out value);
}
if (value != null)
{
int wholeCount = Tr.WholeCount;
Tr.AddWhole(text2, value);
num2 += Tr.WholeCount - wholeCount;
}
}
}
}
catch
{
}
string text3 = ((ex2.InnerException != null) ? (" / " + ex2.InnerException.Message) : "");
warn(type.FullName + "::" + item.Name + " could not be rewritten (" + ex2.GetType().Name + ": " + ex2.Message + text3 + "); " + $"{num2} of its messages will be translated when shown instead.");
}
}
}
return result;
}
private static string OuterName(Type t)
{
while (t.DeclaringType != null)
{
t = t.DeclaringType;
}
return t.FullName;
}
private static Kind KindOf(OpCode op, object operand, string scope)
{
if (op == OpCodes.Ldstr && operand is string text)
{
if (_lang.Scoped.TryGetValue(scope, out var value) && value.ContainsKey(text))
{
return Kind.ScopedLiteral;
}
if (!_lang.Strings.ContainsKey(text) && !_lang.MatchesPattern(text))
{
return Kind.None;
}
return Kind.Literal;
}
if (op == OpCodes.Ldfld && operand is FieldInfo fieldInfo && fieldInfo.FieldType == typeof(string) && fieldInfo.DeclaringType != null)
{
string item = fieldInfo.DeclaringType.Name + "." + fieldInfo.Name;
if (CardFields.Contains(item))
{
if (!KeepEnglishNames.Contains(scope))
{
return Kind.CardField;
}
return Kind.None;
}
if (StatFields.Contains(item))
{
return Kind.StatField;
}
return Kind.None;
}
if (op == OpCodes.Ldsfld && operand is FieldInfo fieldInfo2 && fieldInfo2.FieldType == typeof(string[]) && fieldInfo2.DeclaringType != null)
{
if (!PhraseTables.Contains(fieldInfo2.DeclaringType.Name + "." + fieldInfo2.Name))
{
return Kind.None;
}
return Kind.PhraseTable;
}
if ((op == OpCodes.Call || op == OpCodes.Callvirt) && operand is MethodInfo methodInfo && methodInfo.DeclaringType != null)
{
string name = methodInfo.DeclaringType.Name;
if (methodInfo.DeclaringType == typeof(TMP_Text))
{
if (methodInfo.Name == "set_text")
{
return Kind.SetText;
}
if (methodInfo.Name == "get_text")
{
return Kind.GetText;
}
return Kind.None;
}
if (methodInfo.ReturnType != typeof(string))
{
return Kind.None;
}
if (name == "Deck" && (methodInfo.Name == "NameOf" || methodInfo.Name == "NameOfAbility"))
{
if (!KeepEnglishNames.Contains(scope))
{
return Kind.NameCall;
}
return Kind.None;
}
if (name == "Deck" && methodInfo.Name == "RarityName")
{
return Kind.RarityCall;
}
if (name == "Ability" && methodInfo.Name == "StatusName")
{
return Kind.StatusCall;
}
}
return Kind.None;
}
private static void Classify(OpCode op, object operand, string scope, ref int literals, ref int fields, ref int calls)
{
switch (KindOf(op, operand, scope))
{
case Kind.Literal:
case Kind.ScopedLiteral:
literals++;
break;
case Kind.CardField:
case Kind.StatField:
case Kind.PhraseTable:
fields++;
break;
default:
calls++;
break;
case Kind.None:
break;
}
}
private static IEnumerable<CodeInstruction> Transpile(IEnumerable<CodeInstruction> instructions, MethodBase original)
{
string scope = OuterName(original.DeclaringType);
foreach (CodeInstruction instruction in instructions)
{
switch (KindOf(instruction.opcode, instruction.operand, scope))
{
case Kind.Literal:
yield return instruction;
yield return new CodeInstruction(OpCodes.Call, (object)S);
break;
case Kind.ScopedLiteral:
yield return instruction;
yield return new CodeInstruction(OpCodes.Ldstr, (object)scope);
yield return new CodeInstruction(OpCodes.Call, (object)S2);
break;
case Kind.CardField:
case Kind.NameCall:
yield return instruction;
yield return new CodeInstruction(OpCodes.Call, (object)Card);
break;
case Kind.StatField:
yield return instruction;
yield return new CodeInstruction(OpCodes.Call, (object)S);
break;
case Kind.PhraseTable:
yield return instruction;
yield return new CodeInstruction(OpCodes.Call, (object)Arr);
break;
case Kind.RarityCall:
yield return instruction;
yield return new CodeInstruction(OpCodes.Call, (object)Rarity);
break;
case Kind.StatusCall:
yield return instruction;
yield return new CodeInstruction(OpCodes.Call, (object)Status);
break;
case Kind.SetText:
instruction.opcode = OpCodes.Call;
instruction.operand = SetText;
yield return instruction;
break;
case Kind.GetText:
instruction.opcode = OpCodes.Call;
instruction.operand = GetText;
yield return instruction;
break;
default:
yield return instruction;
break;
}
}
}
}
public static class Tr
{
private sealed class Shown
{
public string Raw;
public string Final;
}
private sealed class Whole
{
public Regex Match;
public int[] ArgOfGroup;
public int ArgCount;
public string Russian;
}
internal static Lang Lang;
internal static Func<bool> IsOn = () => false;
private static readonly Dictionary<string[], string[]> _arrays = new Dictionary<string[], string[]>();
private static readonly ConditionalWeakTable<TMP_Text, Shown> _shown = new ConditionalWeakTable<TMP_Text, Shown>();
private static readonly List<Whole> _whole = new List<Whole>();
private static readonly Dictionary<string, string> _wholeExact = new Dictionary<string, string>(StringComparer.Ordinal);
private const char Open = '⟦';
private const char Close = '⟧';
public static bool Active
{
get
{
if (Lang != null)
{
return IsOn();
}
return false;
}
}
internal static int WholeCount => _whole.Count + _wholeExact.Count;
public static string S(string s)
{
if (s == null || !Active)
{
return s;
}
if (!Lang.Strings.TryGetValue(s, out var value))
{
return Lang.ApplyPattern(s);
}
return value;
}
public static string S2(string s, string scope)
{
if (s == null || !Active)
{
return s;
}
if (Lang.Scoped.TryGetValue(scope, out var value) && value.TryGetValue(s, out var value2))
{
return value2;
}
if (!Lang.Strings.TryGetValue(s, out var value3))
{
return Lang.ApplyPattern(s);
}
return value3;
}
public static string Card(string s)
{
if (string.IsNullOrEmpty(s) || !Active)
{
return s;
}
if (!Lang.CardText.TryGetValue(s, out var value))
{
return s;
}
return value;
}
public static string Rarity(string s)
{
if (s == null || !Active)
{
return s;
}
if (!Lang.Rarities.TryGetValue(s, out var value))
{
return s;
}
return value;
}
public static string Status(string s)
{
if (s == null || !Active)
{
return s;
}
if (!Lang.Statuses.TryGetValue(s, out var value))
{
return s;
}
return value;
}
public static string[] Arr(string[] source)
{
if (source == null || !Active)
{
return source;
}
if (_arrays.TryGetValue(source, out var value))
{
return value;
}
string[] array = new string[source.Length];
for (int i = 0; i < source.Length; i++)
{
array[i] = ((source[i] != null && Lang.Strings.TryGetValue(source[i], out var value2)) ? value2 : source[i]);
}
_arrays[source] = array;
return array;
}
internal static void AddWhole(string english, string russian)
{
if (string.IsNullOrEmpty(english) || string.IsNullOrEmpty(russian))
{
return;
}
MatchCollection matchCollection = Regex.Matches(english, "\\{(\\d+)(?::[^}]*)?\\}");
if (matchCollection.Count == 0)
{
if (english.Trim().Length >= 12 && english == english.Trim())
{
_wholeExact[english] = russian;
}
return;
}
StringBuilder stringBuilder = new StringBuilder("^");
List<int> list = new List<int>();
int num = 0;
int num2 = -1;
foreach (Match item in matchCollection)
{
stringBuilder.Append(Regex.Escape(english.Substring(num, item.Index - num))).Append("(.+?)");
int num3 = int.Parse(item.Groups[1].Value);
list.Add(num3);
if (num3 > num2)
{
num2 = num3;
}
num = item.Index + item.Length;
}
stringBuilder.Append(Regex.Escape(english.Substring(num))).Append('$');
_whole.Add(new Whole
{
Match = new Regex(stringBuilder.ToString(), RegexOptions.Singleline),
ArgOfGroup = list.ToArray(),
ArgCount = num2 + 1,
Russian = russian
});
}
private static string Recognise(string value)
{
if (_wholeExact.TryGetValue(value, out var value2))
{
return value2;
}
for (int i = 0; i < _whole.Count; i++)
{
Match match = _whole[i].Match.Match(value);
if (match.Success)
{
object[] array = new object[_whole[i].ArgCount];
for (int j = 0; j < array.Length; j++)
{
array[j] = "";
}
for (int k = 0; k < _whole[i].ArgOfGroup.Length; k++)
{
array[_whole[i].ArgOfGroup[k]] = match.Groups[k + 1].Value;
}
try
{
return string.Format(_whole[i].Russian, array);
}
catch (FormatException)
{
return value;
}
}
}
return value;
}
public static void SetText(TMP_Text label, string value)
{
if ((Object)(object)label == (Object)null)
{
return;
}
if (value == null || !Active)
{
label.text = value;
return;
}
string text = Final((WholeCount > 0) ? Recognise(value) : value);
if ((object)text != value)
{
Shown orCreateValue = _shown.GetOrCreateValue(label);
orCreateValue.Raw = value;
orCreateValue.Final = text;
}
label.text = text;
}
public static string GetText(TMP_Text label)
{
if ((Object)(object)label == (Object)null)
{
return null;
}
string text = label.text;
if (_shown.TryGetValue(label, out var value) && value.Final == text)
{
return value.Raw;
}
return text;
}
public static string Final(string s)
{
if (string.IsNullOrEmpty(s))
{
return s;
}
bool num = s.IndexOf('⟦') >= 0;
bool flag = HasDecimalPoint(s);
if (!num && !flag)
{
return s;
}
StringBuilder stringBuilder = new StringBuilder(s.Length + 8);
int num2 = 0;
while (num2 < s.Length)
{
char c = s[num2];
if (c == '<')
{
int num3 = s.IndexOf('>', num2);
if (num3 > num2 && num3 - num2 <= 64)
{
stringBuilder.Append(s, num2, num3 - num2 + 1);
num2 = num3 + 1;
continue;
}
}
if (c == '⟦')
{
int num4 = s.IndexOf('⟧', num2);
if (num4 > num2)
{
stringBuilder.Append(Resolve(s.Substring(num2 + 1, num4 - num2 - 1), stringBuilder));
num2 = num4 + 1;
continue;
}
}
if (c == '.' && IsDecimalPoint(s, num2))
{
stringBuilder.Append(',');
num2++;
}
else
{
stringBuilder.Append(c);
num2++;
}
}
string text = stringBuilder.ToString();
if (!(text == s))
{
return text;
}
return s;
}
private static bool HasDecimalPoint(string s)
{
for (int i = 1; i + 1 < s.Length; i++)
{
if (s[i] == '.' && IsDecimalPoint(s, i))
{
return true;
}
}
return false;
}
private static bool IsDecimalPoint(string s, int i)
{
if (i <= 0 || i + 1 >= s.Length || !char.IsDigit(s[i - 1]) || !char.IsDigit(s[i + 1]))
{
return false;
}
int num = i - 1;
while (num > 0 && char.IsDigit(s[num - 1]))
{
num--;
}
if (num > 1 && s[num - 1] == '.' && char.IsDigit(s[num - 2]))
{
return false;
}
int j;
for (j = i + 1; j + 1 < s.Length && char.IsDigit(s[j + 1]); j++)
{
}
if (j + 2 < s.Length && s[j + 1] == '.' && char.IsDigit(s[j + 2]))
{
return false;
}
return true;
}
private static string Resolve(string mark, StringBuilder before)
{
int num = mark.IndexOf(':');
if (num <= 0)
{
return mark;
}
string text = mark.Substring(0, num);
string[] array = mark.Substring(num + 1).Split('|');
string plainBefore = Tail(before);
if (text == "n" && array.Length == 3)
{
return array[PluralIndex(plainBefore)];
}
if (text == "you" && array.Length == 2)
{
return array[(!StartsWithYou(before)) ? 1u : 0u];
}
if (array.Length == 0)
{
return "";
}
return array[^1];
}
private static string Tail(StringBuilder before)
{
int num = Math.Max(0, before.Length - 96);
StringBuilder stringBuilder = new StringBuilder();
bool flag = false;
for (int i = num; i < before.Length; i++)
{
char c = before[i];
if (c == '<')
{
flag = true;
}
else if (c == '>' && flag)
{
flag = false;
}
else if (!flag)
{
stringBuilder.Append(c);
}
}
return stringBuilder.ToString().TrimEnd();
}
internal static int PluralIndex(string plainBefore)
{
int length = plainBefore.Length;
int num = length;
bool flag = false;
while (num > 0)
{
char c = plainBefore[num - 1];
if (char.IsDigit(c))
{
num--;
continue;
}
if ((c != ',' && c != '.') || num - 2 < 0 || !char.IsDigit(plainBefore[num - 2]) || num >= length)
{
break;
}
flag = true;
num--;
}
if (num == length)
{
return 2;
}
if (flag)
{
return 1;
}
string text = plainBefore.Substring(num, length - num);
int num2 = ((text.Length >= 2) ? ((text[text.Length - 2] - 48) * 10 + (text[text.Length - 1] - 48)) : (text[text.Length - 1] - 48));
int num3 = num2 % 10;
if (num2 >= 11 && num2 <= 14)
{
return 2;
}
switch (num3)
{
case 1:
return 0;
case 2:
case 3:
case 4:
return 1;
default:
return 2;
}
}
private static bool StartsWithYou(StringBuilder before)
{
int num = 0;
for (int num2 = before.Length - 1; num2 >= 0; num2--)
{
if (before[num2] == '\n')
{
num = num2 + 1;
break;
}
}
StringBuilder stringBuilder = new StringBuilder();
bool flag = false;
for (int i = num; i < before.Length; i++)
{
if (stringBuilder.Length >= 4)
{
break;
}
char c = before[i];
if (c == '<')
{
flag = true;
}
else if (c == '>' && flag)
{
flag = false;
}
else if (!flag)
{
stringBuilder.Append(c);
}
}
string text = stringBuilder.ToString();
if (text.StartsWith("Вы", StringComparison.Ordinal))
{
if (text.Length != 2)
{
return !char.IsLetter(text[2]);
}
return true;
}
return false;
}
}
}