Please disclose if any significant portion of your mod was created using AI tools by adding the 'AI Generated' category. Failing to do so may result in the mod being removed from Thunderstore.
Decompiled source of CustomTranslation v0.2.0
plugins/CustomTranslation.dll
Decompiled 2 months agousing System; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Linq; using System.Reflection; using System.Resources; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Security; using System.Security.Permissions; using System.Text; using System.Text.RegularExpressions; using System.Xml; using BepInEx; using BepInEx.Logging; using CustomFont; using GlobalEnums; using HarmonyLib; using Microsoft.CodeAnalysis; using Newtonsoft.Json; using Newtonsoft.Json.Converters; using Newtonsoft.Json.Serialization; using Silksong.DataManager; using Silksong.ModMenu.Elements; using Silksong.ModMenu.Plugin; using Silksong.ModMenu.Screens; using TMProOld; using TeamCherry.Localization; using TeamCherry.SharedUtils; using UnityEngine; using UnityEngine.UI; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")] [assembly: AssemblyCompany("CustomTranslation")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("0.2.0.0")] [assembly: AssemblyInformationalVersion("0.2.0+601cf85de81e98a6b78919bf27e1a25ae87a40f5")] [assembly: AssemblyProduct("CustomTranslation")] [assembly: AssemblyTitle("CustomTranslation")] [assembly: AssemblyMetadata("RepositoryUrl", "https://github.com/CarrieForle/CustomTranslationSilksong")] [assembly: NeutralResourcesLanguage("EN")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("0.2.0.0")] [module: UnverifiableCode] [module: RefSafetyRules(11)] namespace System.Runtime.CompilerServices { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)] internal sealed class NullableAttribute : Attribute { public readonly byte[] NullableFlags; public NullableAttribute(byte P_0) { NullableFlags = new byte[1] { P_0 }; } public NullableAttribute(byte[] P_0) { NullableFlags = P_0; } } [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)] internal sealed class NullableContextAttribute : Attribute { public readonly byte Flag; public NullableContextAttribute(byte P_0) { Flag = P_0; } } [CompilerGenerated] [Microsoft.CodeAnalysis.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 BepInEx { [AttributeUsage(AttributeTargets.Class, Inherited = false, AllowMultiple = false)] [Conditional("CodeGeneration")] [Microsoft.CodeAnalysis.Embedded] internal sealed class BepInAutoPluginAttribute : Attribute { public BepInAutoPluginAttribute(string? id = null, string? name = null, string? version = null) { } } } namespace BepInEx.Preloader.Core.Patching { [AttributeUsage(AttributeTargets.Class, Inherited = false, AllowMultiple = false)] [Conditional("CodeGeneration")] [Microsoft.CodeAnalysis.Embedded] internal sealed class PatcherAutoPluginAttribute : Attribute { public PatcherAutoPluginAttribute(string? id = null, string? name = null, string? version = null) { } } } namespace Microsoft.CodeAnalysis { [Microsoft.CodeAnalysis.Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace CustomTranslation { public enum TranslationFileKind { Single, Splitted } [BepInDependency(/*Could not decode attribute arguments.*/)] [BepInDependency(/*Could not decode attribute arguments.*/)] [BepInDependency(/*Could not decode attribute arguments.*/)] [BepInDependency(/*Could not decode attribute arguments.*/)] [BepInPlugin("io.github.carrieforle.customtranslation", "CustomTranslation", "0.2.0")] public class CustomTranslationPlugin : BaseUnityPlugin, IGlobalDataMod<GlobalData>, IRawGlobalDataMod, IModMenuCustomMenu, IModMenuInterface { public const string ENTRY_FILENAME = "entry.json"; public const string METADATA_FILENAME = "metadata.json"; public const string ASSET_DIRNAME = "assets"; public static LanguageReader languageReader = new LanguageReader(); public static DirectoryInfo translationDir; public static DirectoryInfo dir; internal static ManualLogSource logger; public static CustomTranslationPlugin Instance; private Harmony harmony; private GlobalData? globalData; public const string Id = "io.github.carrieforle.customtranslation"; public GlobalData? GlobalData { get { if (globalData == null) { globalData = new GlobalData(); } return globalData; } set { globalData = value; } } public static string Name => "CustomTranslation"; public static string Version => "0.2.0"; private void Awake() { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_0010: Expected O, but got Unknown harmony = new Harmony("io.github.carrieforle.customtranslation"); harmony.PatchAll(typeof(Patch)); logger = ((BaseUnityPlugin)this).Logger; dir = new DirectoryInfo(Path.GetDirectoryName(((BaseUnityPlugin)this).Info.Location)); translationDir = DirectoryHelper.TryCreateRecursive(dir, "translation"); Instance = this; RefreshLanguage(); } private void Start() { //IL_003f: Unknown result type (might be due to invalid IL or missing references) //IL_0055: Unknown result type (might be due to invalid IL or missing references) //IL_005a: Unknown result type (might be due to invalid IL or missing references) //IL_0060: Unknown result type (might be due to invalid IL or missing references) //IL_0068: Unknown result type (might be due to invalid IL or missing references) harmony.PatchAll(typeof(LanguagePatch)); ((BaseUnityPlugin)this).Logger.LogInfo((object)"Patched Language class"); LanguagePatch.LoadAvailableLanguages(); LanguageCode? val = GlobalData?.Language; if (val.HasValue) { LanguageCode valueOrDefault = val.GetValueOrDefault(); if (languageReader.ContainsKey(valueOrDefault)) { Language.DoSwitch(valueOrDefault); } } } private static IList<TranslationEntry> GetTranslationEntries() { List<TranslationEntry> list = new List<TranslationEntry>(); DirectoryInfo[] directories = DirectoryHelper.TryCreate(translationDir).GetDirectories(); string[] validExtensions = new string[2] { ".txt", ".bytes" }; DirectoryInfo[] array = directories; foreach (DirectoryInfo directoryInfo in array) { if (File.Exists(Path.Combine(directoryInfo.FullName, "metadata.json"))) { if (File.Exists(Path.Combine(directoryInfo.FullName, "entry.json"))) { list.Add(new TranslationEntry(directoryInfo, TranslationFileKind.Single)); } else if (directoryInfo.GetFiles().Any((FileInfo f) => ((ReadOnlySpan<string>)validExtensions).IndexOf(f.Extension) != -1)) { list.Add(new TranslationEntry(directoryInfo, TranslationFileKind.Splitted)); } } } return list; } public static void RefreshLanguage() { //IL_0039: Unknown result type (might be due to invalid IL or missing references) //IL_0096: Unknown result type (might be due to invalid IL or missing references) //IL_005a: Unknown result type (might be due to invalid IL or missing references) IList<TranslationEntry> translationEntries = GetTranslationEntries(); languageReader = new LanguageReader(); foreach (TranslationEntry item in translationEntries) { try { TranslationMetadata translationMetadata = TranslationMetadata.ReadFrom(item); Translation value = new Translation(translationMetadata, item); if (languageReader.TryGetValue(translationMetadata.Language, out Translation translation)) { logger.LogWarning((object)$"Found duplicate entries for '{translationMetadata.Language}' ('{translation.entry.Name}' and '{item.Name}'). Use '{item.Name}'."); } languageReader[translationMetadata.Language] = value; } catch (Exception ex) { logger.LogWarning((object)("Failed to load entry at '" + item.Name + "': " + ex.Message)); } } if (translationEntries.Count == 0) { logger.LogInfo((object)"No entry found."); } else { logger.LogInfo((object)string.Format("Found {0} entries. Loaded {1} entries: {2}", translationEntries.Count, languageReader.Count, string.Join(", ", languageReader.LanguageList))); } } public LocalizedText ModMenuName() { //IL_0005: Unknown result type (might be due to invalid IL or missing references) return LocalizedText.op_Implicit(Text.Localized("NAME")); } public AbstractMenuScreen BuildCustomMenu() { //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_000f: Unknown result type (might be due to invalid IL or missing references) //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_0023: Unknown result type (might be due to invalid IL or missing references) //IL_0029: Expected O, but got Unknown //IL_005e: Unknown result type (might be due to invalid IL or missing references) //IL_006a: Unknown result type (might be due to invalid IL or missing references) //IL_0079: Unknown result type (might be due to invalid IL or missing references) //IL_0083: Unknown result type (might be due to invalid IL or missing references) //IL_0089: Expected O, but got Unknown //IL_00ab: Unknown result type (might be due to invalid IL or missing references) //IL_00b7: Unknown result type (might be due to invalid IL or missing references) //IL_00c1: Unknown result type (might be due to invalid IL or missing references) //IL_00c7: Expected O, but got Unknown //IL_00fc: Unknown result type (might be due to invalid IL or missing references) //IL_0104: Expected O, but got Unknown SimpleMenuScreen val = new SimpleMenuScreen(LocalisedString.op_Implicit(Text.Localized("NAME"))); TextButton val2 = new TextButton(LocalizedText.op_Implicit(Text.Localized("OPTION_OPEN_TRANSLATION_DIRECTORY"))); val2.OnSubmit = (Action)Delegate.Combine(val2.OnSubmit, (Action)delegate { //IL_0007: Unknown result type (might be due to invalid IL or missing references) bool flag = false; try { if (languageReader.TryGetValue(Language._currentLanguage, out Translation translation)) { DirectoryInfo location = translation.entry.location; Process.Start(location.FullName); flag = true; logger.LogInfo((object)("Opened translation directory \"" + location.FullName + "\"")); } else { flag = false; } } catch { flag = false; } if (!flag) { DirectoryInfo directoryInfo5 = DirectoryHelper.TryCreate(translationDir); Process.Start(directoryInfo5.FullName); logger.LogInfo((object)("Opened translation directory \"" + directoryInfo5.FullName + "\"")); } }); val.Add((MenuElement)(object)val2); TextButton val3 = new TextButton(LocalizedText.op_Implicit(Text.Localized("OPTION_RELOAD_TRANSLATION")), LocalizedText.op_Implicit(Text.Localized("OPTION_DESCRIPTION_RELOAD_TRANSLATION"))); val3.OnSubmit = (Action)Delegate.Combine(val3.OnSubmit, (Action)delegate { //IL_0076: Unknown result type (might be due to invalid IL or missing references) //IL_0097: Unknown result type (might be due to invalid IL or missing references) logger.LogInfo((object)"Reloading translation"); MenuLanguageSetting val8 = default(MenuLanguageSetting); if (((Component)((Component)UIManager.instance).transform.Find("UICanvas/GameOptionsMenuScreen/Content/LanguageSetting/LanguageOption")).TryGetComponent<MenuLanguageSetting>(ref val8)) { RefreshLanguage(); Language.LoadAvailableLanguages(); MenuLanguageSetting.UpdateLangsArray(); int num = ((ReadOnlySpan<string>)MenuLanguageSetting.optionList).IndexOf(((object)(LanguageCode)(ref Language._currentLanguage)).ToString()); if (num != -1) { ((MenuOptionHorizontal)val8).SetOptionTo(num); } else { ((BaseUnityPlugin)this).Logger.LogWarning((object)$"Unable to load \"{Language._currentLanguage}\". Fallback to EN."); MenuLanguageSetting obj = val8; ReadOnlySpan<string> span = MenuLanguageSetting.optionList; LanguageCode val9 = (LanguageCode)44; ((MenuOptionHorizontal)obj).SetOptionTo(span.IndexOf(((object)(LanguageCode)(ref val9)).ToString())); } val8.UpdateLanguageSetting(); ChangeFontByLanguage[] array = Object.FindObjectsByType<ChangeFontByLanguage>((FindObjectsSortMode)0); for (int j = 0; j < array.Length; j++) { array[j].SetFont(); } ((BaseUnityPlugin)this).Logger.LogInfo((object)"Reloaded translation"); } }); val.Add((MenuElement)(object)val3); TextButton val4 = new TextButton(LocalizedText.op_Implicit(Text.Localized("OPTION_EXPORT_TRANSLATION"))); val4.OnSubmit = (Action)Delegate.Combine(val4.OnSubmit, (Action)delegate { //IL_006c: Unknown result type (might be due to invalid IL or missing references) //IL_0073: Expected O, but got Unknown //IL_0073: Unknown result type (might be due to invalid IL or missing references) //IL_0078: Unknown result type (might be due to invalid IL or missing references) //IL_0084: Expected O, but got Unknown //IL_0220: Unknown result type (might be due to invalid IL or missing references) //IL_0227: Expected O, but got Unknown string text = ((object)(LanguageCode)(ref Language._currentLanguage)).ToString(); logger.LogInfo((object)("Exporting: " + text)); DirectoryInfo directoryInfo = DirectoryHelper.TryCreateRecursive(dir, "export/" + text); DirectoryInfo directoryInfo2 = new DirectoryInfo(Path.GetTempPath()); DirectoryInfo directoryInfo3 = DirectoryHelper.TryCreateRecursive(directoryInfo, "entry"); using StreamWriter streamWriter = new StreamWriter(Path.Combine(directoryInfo3.FullName, "entry.json")); JsonTextWriter val5 = new JsonTextWriter((TextWriter)streamWriter); try { JsonSerializer val6 = JsonSerializer.Create(new JsonSerializerSettings { Formatting = (Formatting)1 }); Dictionary<string, Dictionary<string, string>> dictionary = new Dictionary<string, Dictionary<string, string>>(); string[] sheetTitles = Language.Settings.sheetTitles; foreach (string key in sheetTitles) { if (Language._currentEntrySheets.TryGetValue(key, out var value) && !Extensions.IsNullOrEmpty<KeyValuePair<string, string>>((ICollection<KeyValuePair<string, string>>)value)) { dictionary[key] = value; } } val6.Serialize((JsonWriter)(object)val5, (object)dictionary); DirectoryInfo directoryInfo4 = DirectoryHelper.TryCreateRecursive(directoryInfo, "sheet"); foreach (KeyValuePair<string, Dictionary<string, string>> item in dictionary) { item.Deconstruct(out var key2, out var value2); string text2 = key2; Dictionary<string, string> dictionary2 = value2; using StreamWriter streamWriter2 = new StreamWriter(Path.Combine(directoryInfo4.FullName, text + "_" + text2 + ".txt")); streamWriter2.WriteLine("<entries>"); foreach (KeyValuePair<string, string> item2 in dictionary2) { item2.Deconstruct(out key2, out var value3); string text3 = key2; string str = value3; streamWriter2.WriteLine("<entry name=\"" + text3 + "\">" + Text.EscapeXml(str) + "</entry>"); } streamWriter2.WriteLine("</entries>"); } FileInfo fileInfo = new FileInfo(Path.Combine(directoryInfo2.FullName, "metadata.json")); using (StreamWriter streamWriter3 = new StreamWriter(fileInfo.FullName)) { JsonTextWriter val7 = new JsonTextWriter((TextWriter)streamWriter3); try { val6.Serialize((JsonWriter)(object)val7, (object)new Dictionary<string, string> { ["Language"] = text }); } finally { ((IDisposable)val7)?.Dispose(); } } fileInfo.CopyTo(Path.Combine(directoryInfo4.FullName, fileInfo.Name), overwrite: true); fileInfo.CopyTo(Path.Combine(directoryInfo3.FullName, fileInfo.Name), overwrite: true); logger.LogInfo((object)("Exported \"" + text + "\"")); Process.Start(directoryInfo.FullName); } finally { ((IDisposable)val5)?.Dispose(); } }); val.Add((MenuElement)(object)val4); return (AbstractMenuScreen)val; } } public class GlobalData { [JsonConverter(typeof(StringEnumConverter))] public LanguageCode Language; } public class Assets { public enum FontKind { Title, Text } public TMP_FontAsset? TitleFont; public TMP_FontAsset? TextFont; private readonly TranslationEntry entry; private bool read; public Assets(TranslationEntry entry) { this.entry = entry; base..ctor(); } public TMP_FontAsset? GetFont(FontKind kind) { if (!read) { DirectoryInfo directoryInfo = new DirectoryInfo(Path.Combine(entry.location.FullName, "assets")); if (!directoryInfo.Exists) { read = true; return null; } FileInfo fileInfo = null; try { FileInfo[] files = directoryInfo.GetFiles(); foreach (FileInfo fileInfo2 in files) { try { if ((Object)(object)TitleFont == (Object)null && (fileInfo2.Name == "title.ttf" || fileInfo2.Name == "title.otf")) { TitleFont = Text.CreateFontFrom(fileInfo2); fileInfo = fileInfo2; CustomTranslationPlugin.logger.LogInfo((object)"Loaded title font"); } else if ((Object)(object)TextFont == (Object)null && (fileInfo2.Name == "text.ttf" || fileInfo2.Name == "text.otf")) { TextFont = Text.CreateFontFrom(fileInfo2); fileInfo = fileInfo2; CustomTranslationPlugin.logger.LogInfo((object)"Loaded text font"); } } catch (Exception ex) { CustomTranslationPlugin.logger.LogWarning((object)("Error while loading \"" + fileInfo2.FullName + "\": " + ex.Message + "\nThis asset will be skipped.")); } } if ((Object)(object)TitleFont == (Object)null && (Object)(object)TextFont != (Object)null && fileInfo != null) { TitleFont = Text.CreateFontFrom(fileInfo); } else if ((Object)(object)TitleFont != (Object)null && (Object)(object)TextFont == (Object)null && fileInfo != null) { TextFont = Text.CreateFontFrom(fileInfo); } } catch (Exception ex2) { CustomTranslationPlugin.logger.LogError((object)("Error while discovering assets: " + ex2.Message)); } finally { read = true; } } return (TMP_FontAsset?)(kind switch { FontKind.Title => TitleFont, FontKind.Text => TextFont, _ => null, }); } } public class TranslationEntry { public DirectoryInfo location; public TranslationFileKind kind; public string Name => location.Name; public TranslationEntry(DirectoryInfo location, TranslationFileKind kind) { this.location = location; this.kind = kind; base..ctor(); } } public class TranslationMetadata { [JsonProperty(/*Could not decode attribute arguments.*/)] [JsonConverter(typeof(LanguageCodeConverter))] public LanguageCode Language { get; set; } [JsonProperty(/*Could not decode attribute arguments.*/)] [JsonConverter(typeof(LanguageCodeConverter))] public LanguageCode FallbackLanguage { get; set; } = (LanguageCode)44; [JsonProperty(/*Could not decode attribute arguments.*/)] public float TextFontScale { get; set; } = 1f; [JsonProperty(/*Could not decode attribute arguments.*/)] public float TitleFontScale { get; set; } = 1f; [JsonProperty(/*Could not decode attribute arguments.*/)] public bool UseFontAsFallBack { get; set; } = true; [JsonConstructor] public TranslationMetadata(LanguageCode language) { //IL_0003: Unknown result type (might be due to invalid IL or missing references) //IL_002c: Unknown result type (might be due to invalid IL or missing references) Language = language; } public static TranslationMetadata ReadFrom(TranslationEntry entry) { //IL_001f: Unknown result type (might be due to invalid IL or missing references) TranslationMetadata translationMetadata = Text.FromJson<TranslationMetadata>(Path.Combine(entry.location.FullName, "metadata.json")); if (translationMetadata == null || (int)translationMetadata.Language == 0) { throw new CustomTranslationException("Invalid language code"); } return translationMetadata; } } public class Translation { public readonly TranslationMetadata metadata; public readonly TranslationEntry entry; public readonly Assets assets; public Translation(TranslationMetadata metadata, TranslationEntry entry) { this.metadata = metadata; this.entry = entry; assets = new Assets(entry); base..ctor(); } public bool UpdateSheet() { string text = ""; try { if (entry.kind == TranslationFileKind.Single) { Dictionary<string, Dictionary<string, string>> dictionary = Text.FromJson<Dictionary<string, Dictionary<string, string>>>(Path.Combine(entry.location.FullName, "entry.json")); if (dictionary == null) { throw new CustomTranslationException("JSON is null"); } string[] sheetTitles = Language.Settings.sheetTitles; for (int i = 0; i < sheetTitles.Length; i++) { text = sheetTitles[i]; if (!Language._currentEntrySheets.TryGetValue(text, out var value)) { value = new Dictionary<string, string>(); Language._currentEntrySheets[text] = value; } if (!dictionary.TryGetValue(text, out var value2)) { continue; } foreach (KeyValuePair<string, string> item in value2) { item.Deconstruct(out var key, out var value3); string key2 = key; string value4 = value3; value[key2] = value4; } } } else { FileInfo[] files = entry.location.GetFiles(); string[] sheetTitles = Language.Settings.sheetTitles; foreach (string obj in sheetTitles) { text = obj; if (!Language._currentEntrySheets.TryGetValue(text, out var value5)) { value5 = new Dictionary<string, string>(); Language._currentEntrySheets[text] = value5; } Regex pattern = new Regex("[a-zA-Z_]+?" + text + "\\.(?:txt|bytes)"); FileInfo fileInfo = files.FirstOrDefault((FileInfo f) => pattern.IsMatch(f.Name)); if (fileInfo == null) { continue; } using StreamReader streamReader = new StreamReader(Path.Combine(entry.location.FullName, fileInfo.Name)); string text2 = streamReader.ReadToEnd(); if (!text2.Contains('<')) { text2 = Encryption.Decrypt(text2); } using XmlReader xmlReader = XmlReader.Create(new StringReader(text2)); while (xmlReader.ReadToFollowing("entry")) { xmlReader.MoveToFirstAttribute(); string value6 = xmlReader.Value; xmlReader.MoveToElement(); string text3 = xmlReader.ReadElementContentAsString().Trim(); text3 = StringExtensions.UnescapeXml(text3); value5[value6] = text3; } } } return true; } catch (Exception ex) { CustomTranslationPlugin.logger.LogError((object)("Error while loading \"" + entry.Name + "\" entry on sheet \"" + text + "\": " + ex.Message)); return false; } } } public class LanguageReader { private readonly SortedList<LanguageCode, Translation> languages = new SortedList<LanguageCode, Translation>(Comparer<LanguageCode>.Default); public IList<LanguageCode> LanguageList => languages.Keys; public int Count => languages.Count; public Translation this[LanguageCode lang] { get { //IL_0006: Unknown result type (might be due to invalid IL or missing references) return languages[lang]; } set { //IL_0006: Unknown result type (might be due to invalid IL or missing references) languages[lang] = value; } } public bool ContainsKey(LanguageCode key) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) return languages.ContainsKey(key); } public bool TryGetValue(LanguageCode key, out Translation translation) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) return languages.TryGetValue(key, out translation); } } internal class EnumComparer<T> : Comparer<T> where T : Enum { public override int Compare(T x, T y) { return x.CompareTo(y); } } internal class LanguagePatch { [HarmonyPrefix] [HarmonyPatch(typeof(Language), "DoSwitch")] private static bool DoSwitch(LanguageCode newLang) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_002b: Unknown result type (might be due to invalid IL or missing references) //IL_0030: Unknown result type (might be due to invalid IL or missing references) //IL_00f2: Unknown result type (might be due to invalid IL or missing references) //IL_010b: Unknown result type (might be due to invalid IL or missing references) //IL_010c: Unknown result type (might be due to invalid IL or missing references) //IL_00ff: Unknown result type (might be due to invalid IL or missing references) //IL_014e: Unknown result type (might be due to invalid IL or missing references) //IL_016e: Unknown result type (might be due to invalid IL or missing references) //IL_016f: Unknown result type (might be due to invalid IL or missing references) LocalizationProjectSettings.OnSwitchedLanguage(newLang); Language._currentLanguage = newLang; Language._currentEntrySheets = new Dictionary<string, Dictionary<string, string>>(); if (CustomTranslationPlugin.languageReader.TryGetValue(newLang, out Translation translation)) { Language._currentLanguage = translation.metadata.FallbackLanguage; } string[] sheetTitles = Language.Settings.sheetTitles; foreach (string text in sheetTitles) { Language._currentEntrySheets[text] = new Dictionary<string, string>(); string languageFileContents = Language.GetLanguageFileContents(text); if (string.IsNullOrEmpty(languageFileContents)) { continue; } using XmlReader xmlReader = XmlReader.Create(new StringReader(languageFileContents)); while (xmlReader.ReadToFollowing("entry")) { xmlReader.MoveToFirstAttribute(); string value = xmlReader.Value; xmlReader.MoveToElement(); string text2 = xmlReader.ReadElementContentAsString().Trim(); text2 = StringExtensions.UnescapeXml(text2); Language._currentEntrySheets[text][value] = text2; } } if (CustomTranslationPlugin.languageReader.ContainsKey(newLang)) { CustomTranslationPlugin.languageReader[newLang].UpdateSheet(); } Language._currentLanguage = newLang; LocalizedAsset[] array = (LocalizedAsset[])(object)Object.FindObjectsOfType(typeof(LocalizedAsset)); for (int j = 0; j < array.Length; j++) { array[j].LocalizeAsset(); } Language.SendMonoMessage("ChangedLanguage", new object[1] { Language._currentLanguage }); GlobalData? globalData = CustomTranslationPlugin.Instance.GlobalData; if (globalData != null) { globalData.Language = newLang; } return false; } [HarmonyPostfix] [HarmonyPatch(typeof(Language), "GetLanguages")] private static void GetLanguages(ref string[] __result) { List<string> list = new List<string>(); list.AddRange(__result); list.AddRange(CustomTranslationPlugin.languageReader.LanguageList.Select((LanguageCode lang) => ((object)(LanguageCode)(ref lang)).ToString())); __result = list.ToArray(); } [HarmonyPostfix] [HarmonyPatch(typeof(Language), "LoadAvailableLanguages")] public static void LoadAvailableLanguages() { //IL_0013: Unknown result type (might be due to invalid IL or missing references) //IL_0018: Unknown result type (might be due to invalid IL or missing references) foreach (LanguageCode language in CustomTranslationPlugin.languageReader.LanguageList) { LanguageCode current = language; Extensions.AddIfNotPresent<string>(Language._availableLanguages, ((object)(LanguageCode)(ref current)).ToString()); } } [HarmonyPostfix] [HarmonyPatch(typeof(Language), "RestoreLanguageSelection")] private static void RestoreLanguageFromGlobalData(ref string __result) { //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_002f: Unknown result type (might be due to invalid IL or missing references) //IL_0034: Unknown result type (might be due to invalid IL or missing references) LanguageCode? val = CustomTranslationPlugin.Instance.GlobalData?.Language; if (val.HasValue) { LanguageCode valueOrDefault = val.GetValueOrDefault(); __result = ((object)(LanguageCode)(ref valueOrDefault)).ToString(); } CustomTranslationPlugin.logger.LogInfo((object)("Restored language: " + __result)); } } internal class Patch { private static string[]? originalOptionList; private static readonly string[] titleFontNames = new string[2] { "trajan_bold_tmpro", "TrajanPro-Bold SDF" }; [HarmonyPostfix] [HarmonyPatch(typeof(MenuLanguageSetting), "UpdateLangsArray")] private static void UpdateLangsArray() { if (originalOptionList == null) { originalOptionList = MenuLanguageSetting.optionList.ToArray(); } List<string> list = new List<string>(); list.AddRange(originalOptionList); list.AddRange(from lang in CustomTranslationPlugin.languageReader.LanguageList select ((object)(LanguageCode)(ref lang)).ToString() into lang where !originalOptionList.Any((string og_lang) => lang == og_lang) select lang); MenuLanguageSetting.optionList = list.ToArray(); } [HarmonyPrefix] [HarmonyPatch(typeof(MenuLanguageSetting), "UpdateLanguageSetting")] private static bool UpdateLanguageSetting(MenuLanguageSetting __instance) { //IL_0045: Unknown result type (might be due to invalid IL or missing references) //IL_0062: Unknown result type (might be due to invalid IL or missing references) //IL_0067: Unknown result type (might be due to invalid IL or missing references) //IL_0025: Unknown result type (might be due to invalid IL or missing references) //IL_0036: Unknown result type (might be due to invalid IL or missing references) //IL_0068: Unknown result type (might be due to invalid IL or missing references) LanguageCode val; if (((MenuOptionHorizontal)__instance).selectedOptionIndex < MenuLanguageSetting.langs.Length) { GameManager.instance.gameSettings.gameLanguage = MenuLanguageSetting.langs[((MenuOptionHorizontal)__instance).selectedOptionIndex]; val = (LanguageCode)MenuLanguageSetting.langs[((MenuOptionHorizontal)__instance).selectedOptionIndex]; } else { GameManager.instance.gameSettings.gameLanguage = (SupportedLanguages)44; val = CustomTranslationPlugin.languageReader.LanguageList[((MenuOptionHorizontal)__instance).selectedOptionIndex - MenuLanguageSetting.langs.Length]; } Language.SwitchLanguage(val); GameManager.instance.RefreshLocalization(); ((MenuOptionHorizontal)__instance).UpdateText(); return false; } [HarmonyPostfix] [HarmonyPatch(typeof(MenuLanguageSetting), "RefreshCurrentIndex")] private static void PatchCurrentIndex(MenuLanguageSetting __instance) { //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_0016: Unknown result type (might be due to invalid IL or missing references) if (!MenuLanguageSetting.languageCodeToSupportedLanguages.ContainsKey(Language._currentLanguage) && CustomTranslationPlugin.languageReader.ContainsKey(Language._currentLanguage)) { int num = ((ReadOnlySpan<string>)MenuLanguageSetting.optionList).IndexOf(((object)(LanguageCode)(ref Language._currentLanguage)).ToString()); if (num != -1) { ((MenuOptionHorizontal)__instance).selectedOptionIndex = num; } } } [HarmonyPostfix] [HarmonyPatch(typeof(ChangeFontByLanguage), "SetFont", new Type[] { })] private static void PatchFont(ChangeFontByLanguage __instance) { //IL_0012: Unknown result type (might be due to invalid IL or missing references) ChangeFontByLanguage __instance2 = __instance; if (!CustomTranslationPlugin.languageReader.TryGetValue(Language._currentLanguage, out Translation translation)) { return; } TMP_FontAsset font = translation.assets.GetFont(Assets.FontKind.Text); TMP_FontAsset font2 = translation.assets.GetFont(Assets.FontKind.Title); TMP_FontAsset val = null; float num = 1f; if (((Object)__instance2.defaultFont).name == "perpetua_tmpro") { val = font; num = translation.metadata.TextFontScale; } else if (titleFontNames.Any((string name) => name == ((Object)__instance2.defaultFont).name)) { val = font2; num = translation.metadata.TitleFontScale; } if ((Object)(object)val == (Object)null) { return; } TextMeshPro tmpro = __instance2.tmpro; ((TMP_Text)tmpro).fontSize = ((TMP_Text)tmpro).fontSize * num; if (translation.metadata.UseFontAsFallBack) { if (Extensions.IsNullOrEmpty<TMP_FontAsset>((ICollection<TMP_FontAsset>)((TMP_Text)__instance2.tmpro).font.fallbackFontAssets)) { ((TMP_Text)__instance2.tmpro).font.fallbackFontAssets = new List<TMP_FontAsset>(1) { val }; } else if (!((TMP_Text)__instance2.tmpro).font.fallbackFontAssets.Contains(val)) { ((TMP_Text)__instance2.tmpro).font.fallbackFontAssets.Add(val); } return; } val.fallbackFontAssets = ((TMP_Text)__instance2.tmpro).font.fallbackFontAssets; if (Extensions.IsNullOrEmpty<TMP_FontAsset>((ICollection<TMP_FontAsset>)val.fallbackFontAssets)) { val.fallbackFontAssets = new List<TMP_FontAsset>(1) { ((TMP_Text)__instance2.tmpro).font }; } else if (!val.fallbackFontAssets.Contains(((TMP_Text)__instance2.tmpro).font)) { val.fallbackFontAssets.Insert(0, ((TMP_Text)__instance2.tmpro).font); } __instance2.SetFont(val, true); } } public class CustomTranslationException : Exception { public CustomTranslationException(string message) : base(message) { } } public static class Text { public static LocalisedString Localized(string key) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) return new LocalisedString("Mods.io.github.carrieforle.customtranslation", key); } public static string Localized(string key, params object[] args) { return string.Format(Language.Get(key, "Mods.io.github.carrieforle.customtranslation"), args); } public static T? FromJson<T>(string path) { //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_000e: Expected O, but got Unknown //IL_000e: Unknown result type (might be due to invalid IL or missing references) using StreamReader streamReader = new StreamReader(path); JsonTextReader val = new JsonTextReader((TextReader)streamReader); try { return new JsonSerializer().Deserialize<T>((JsonReader)(object)val); } finally { ((IDisposable)val)?.Dispose(); } } public static string EscapeXml(string str) { Dictionary<char, string> dictionary = new Dictionary<char, string> { ['\''] = "'", ['"'] = """, ['>'] = ">", ['<'] = "<", ['&'] = "&" }; StringBuilder stringBuilder = new StringBuilder(str); for (int i = 0; i < stringBuilder.Length; i++) { if (dictionary.TryGetValue(stringBuilder[i], out var value)) { stringBuilder.Remove(i, 1); stringBuilder.Insert(i, value); i += value.Length - 1; } } return stringBuilder.ToString(); } public static TMP_FontAsset CreateFontFrom(FileInfo file) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_0010: Expected O, but got Unknown //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_0010: Unknown result type (might be due to invalid IL or missing references) //IL_001b: Unknown result type (might be due to invalid IL or missing references) return new FontAssetBuilder(new Font(file.FullName)) { AtlasWidth = 4096, AtlasHeight = 4096 }.Create(); } } public static class DirectoryHelper { public static DirectoryInfo TryCreateRecursive(DirectoryInfo dirRoot, string dir) { return TryCreate(new DirectoryInfo(Path.Combine(dirRoot.FullName, dir))); } public static DirectoryInfo TryCreate(DirectoryInfo dir) { dir.Refresh(); try { dir.Create(); } catch { } return dir; } } public class LanguageCodeConverter : JsonConverter { public override bool CanRead { get; } = true; public override bool CanWrite { get; } public override bool CanConvert(Type objectType) { return objectType == typeof(LanguageCode); } public override void WriteJson(JsonWriter writer, object? value, JsonSerializer serializer) { throw new NotImplementedException(); } public override object ReadJson(JsonReader reader, Type objectType, object? existingValue, JsonSerializer serializer) { //IL_0037: Unknown result type (might be due to invalid IL or missing references) string val = (string)reader.Value; return Enum.GetValues(typeof(LanguageCode)).Cast<LanguageCode>().First((LanguageCode lang) => ((object)(LanguageCode)(ref lang)).ToString().Equals(val, StringComparison.OrdinalIgnoreCase)); } } public class BepinExTraceWriter : ITraceWriter { [CompilerGenerated] private ManualLogSource <logger>P; public TraceLevel LevelFilter => TraceLevel.Verbose; public BepinExTraceWriter(ManualLogSource logger) { <logger>P = logger; base..ctor(); } public void Trace(TraceLevel level, string message, Exception? ex) { //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_001e: Unknown result type (might be due to invalid IL or missing references) <logger>P.Log(GetLogLevel(level), (object)message); if (ex != null) { <logger>P.Log(GetLogLevel(level), (object)ex); } } private LogLevel GetLogLevel(TraceLevel level) { return (LogLevel)(level switch { TraceLevel.Error => 2, TraceLevel.Warning => 4, TraceLevel.Info => 16, TraceLevel.Off => 0, _ => 8, }); } } }