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 I18N v1.1.1
Silksong.I18N.dll
Decompiled 2 weeks 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 BepInEx; using BepInEx.Bootstrap; using BepInEx.Configuration; using BepInEx.Logging; using GlobalEnums; using HarmonyLib; using Microsoft.CodeAnalysis; using Newtonsoft.Json; using TeamCherry.Localization; using UnityEngine; [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("Silksong.I18N")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyDescription("A Hollow Knight: Silksong library that automatically loads localized text for other mods. Note that most consumers do not need to NuGet dependency on this package.")] [assembly: AssemblyFileVersion("1.1.1.0")] [assembly: AssemblyInformationalVersion("1.1.1+0279b17abf96c24b6527d48d0d1ce3d562b22389")] [assembly: AssemblyProduct("Silksong.I18N")] [assembly: AssemblyTitle("I18N")] [assembly: AssemblyMetadata("RepositoryUrl", "https://github.com/silksong-modding/Silksong.I18N")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("1.1.1.0")] [module: UnverifiableCode] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)] internal sealed class NullableAttribute : Attribute { public readonly byte[] NullableFlags; public NullableAttribute(byte P_0) { NullableFlags = new byte[1] { P_0 }; } public NullableAttribute(byte[] P_0) { NullableFlags = P_0; } } [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)] internal sealed class NullableContextAttribute : Attribute { public readonly byte Flag; public NullableContextAttribute(byte P_0) { Flag = P_0; } } [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)] internal sealed class RefSafetyRulesAttribute : Attribute { public readonly int Version; public RefSafetyRulesAttribute(int P_0) { Version = P_0; } } } namespace BepInEx { [AttributeUsage(AttributeTargets.Class, Inherited = false, AllowMultiple = false)] [Conditional("CodeGeneration")] 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")] internal sealed class PatcherAutoPluginAttribute : Attribute { public PatcherAutoPluginAttribute(string? id = null, string? name = null, string? version = null) { } } } namespace Silksong.I18N { [BepInPlugin("org.silksong-modding.i18n", "I18N", "1.1.1")] public sealed class I18NPlugin : BaseUnityPlugin { private static I18NPlugin? _instance; private ConfigEntry<bool>? useLanguageOverride; private ConfigEntry<SupportedLanguages>? languageOverride; public const string Id = "org.silksong-modding.i18n"; internal ManualLogSource Logger => ((BaseUnityPlugin)this).Logger; internal static I18NPlugin Instance { get { if (!((Object)(object)_instance != (Object)null)) { throw new NullReferenceException("I18N instance is not ready"); } return _instance; } } public LanguageCode? LanguageOverride { get { //IL_002a: Unknown result type (might be due to invalid IL or missing references) //IL_004a: Unknown result type (might be due to invalid IL or missing references) if (useLanguageOverride != null && useLanguageOverride.Value) { return (LanguageCode?)languageOverride?.Value; } return null; } } public bool UseLanguageOverride { get { if (useLanguageOverride == null) { return false; } return useLanguageOverride.Value; } } public static string Name => "I18N"; public static string Version => "1.1.1"; private void Start() { //IL_000b: Unknown result type (might be due to invalid IL or missing references) _instance = this; new Harmony("org.silksong-modding.i18n").PatchAll(); useLanguageOverride = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "Use Language Override", false, "Whether to manually specify the language used for all modded text."); languageOverride = ((BaseUnityPlugin)this).Config.Bind<SupportedLanguages>("General", "Language Override", (SupportedLanguages)44, "Modded text will use this language if Use Language Override is enabled."); useLanguageOverride.SettingChanged += delegate { LanguagePatches.LoadAllModSheets(); }; languageOverride.SettingChanged += delegate { LanguagePatches.LoadAllModSheets(); }; LanguagePatches.LoadAllModSheets(); } } [HarmonyPatch] internal static class LanguagePatches { [HarmonyPatch(typeof(Language), "DoSwitch")] [HarmonyPostfix] private static void OnLanguageSwitched() { LoadAllModSheets(); } public unsafe static void LoadAllModSheets() { //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_0014: Unknown result type (might be due to invalid IL or missing references) //IL_0022: Unknown result type (might be due to invalid IL or missing references) //IL_003e: Unknown result type (might be due to invalid IL or missing references) //IL_01d0: Unknown result type (might be due to invalid IL or missing references) LanguageCode val = (LanguageCode)(((??)I18NPlugin.Instance.LanguageOverride) ?? Language._currentLanguage); if (I18NPlugin.Instance.UseLanguageOverride) { I18NPlugin.Instance.Logger.LogDebug((object)$"using language override {val}"); } foreach (KeyValuePair<string, PluginInfo> pluginInfo in Chainloader.PluginInfos) { pluginInfo.Deconstruct(out var key, out var value); string text = key; BaseUnityPlugin instance = value.Instance; if (!Object.op_Implicit((Object)(object)instance)) { continue; } Assembly assembly = ((object)instance).GetType().Assembly; if (Utility.IsNullOrWhiteSpace(assembly.Location)) { I18NPlugin.Instance.Logger.LogDebug((object)("mod " + text + " assembly has no location, if you are using ScriptEngine, please enable DumpedAssemblies of ScriptEngine and place the languages folder in BepInEx\\ScriptEngineDumpedAssemblies")); continue; } string directoryName = Path.GetDirectoryName(assembly.Location); if (!Directory.Exists(directoryName)) { continue; } if (string.Equals(Path.GetFullPath(directoryName).TrimEnd(Path.DirectorySeparatorChar), Path.GetFullPath(Paths.PluginPath).TrimEnd(Path.DirectorySeparatorChar), StringComparison.InvariantCultureIgnoreCase)) { I18NPlugin.Instance.Logger.LogInfo((object)("mod " + text + " installed directly in plugins dir, not loading languages")); continue; } Dictionary<string, string> dictionary = null; NeutralResourcesLanguageAttribute customAttribute = assembly.GetCustomAttribute<NeutralResourcesLanguageAttribute>(); if (customAttribute != null) { string text2 = customAttribute.CultureName.ToUpper(); dictionary = LoadModSheet(directoryName, text2.ToLower()); if (dictionary != null) { I18NPlugin.Instance.Logger.LogDebug((object)("loaded fallback sheet in language " + text2 + " for mod " + text)); } } Dictionary<string, string> dictionary2 = LoadModSheet(directoryName, ((object)(*(LanguageCode*)(&val))/*cast due to .constrained prefix*/).ToString().ToLower(), dictionary); if (dictionary2 != null) { Language._currentEntrySheets["Mods." + text] = dictionary2; I18NPlugin.Instance.Logger.LogDebug((object)$"loaded sheet in language {val} for mod {text}"); } } } private static Dictionary<string, string>? LoadModSheet(string modDir, string lang, Dictionary<string, string>? fallback = null) { EnumerationOptions opts = new EnumerationOptions(); opts.MatchCasing = MatchCasing.CaseInsensitive; bool flag = false; Dictionary<string, string> dictionary = fallback ?? new Dictionary<string, string>(); try { foreach (Dictionary<string, string> item in (from p in Directory.EnumerateDirectories(modDir, "languages", opts).SelectMany((string dir) => Directory.EnumerateFiles(dir, lang + ".json", opts)) orderby p select ReadSheetFile(p)).OfType<Dictionary<string, string>>()) { if (flag) { I18NPlugin.Instance.Logger.LogWarning((object)("multiple casings found for language " + lang.ToUpper() + " in: " + modDir)); } flag = true; foreach (KeyValuePair<string, string> item2 in item) { item2.Deconstruct(out var key, out var value); string key2 = key; string value2 = value; dictionary[key2] = value2; } } } catch (Exception arg) { I18NPlugin.Instance.Logger.LogError((object)$"unable to load mod sheets: {modDir}\n{arg}"); return null; } if (flag || fallback != null) { return dictionary; } return null; } private static Dictionary<string, string>? ReadSheetFile(string path) { try { using StreamReader streamReader = new StreamReader(File.OpenRead(path), Encoding.UTF8, detectEncodingFromByteOrderMarks: false); return JsonConvert.DeserializeObject<Dictionary<string, string>>(streamReader.ReadToEnd()); } catch (Exception arg) { I18NPlugin.Instance.Logger.LogError((object)$"unable to read language file: {path}\n{arg}"); return null; } } [HarmonyPatch(typeof(Language), "Get", new Type[] { typeof(string), typeof(string) })] [HarmonyPostfix] private static void OnGetLocalizedText(string? key, string? sheetTitle) { WarnIfModKeyMissing(sheetTitle, key); } [HarmonyPatch(typeof(LocalisedString), "ToString", new Type[] { typeof(bool) })] [HarmonyPostfix] private static void OnGetLocalizedString(LocalisedString __instance, bool allowBlankText) { //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) WarnIfModKeyMissing(__instance.Sheet, __instance.Key, allowBlankText); } private static void WarnIfModKeyMissing(string? sheet, string? key, bool allowBlankText = true) { //IL_004c: Unknown result type (might be due to invalid IL or missing references) //IL_0043: Unknown result type (might be due to invalid IL or missing references) //IL_0051: Unknown result type (might be due to invalid IL or missing references) //IL_0072: Unknown result type (might be due to invalid IL or missing references) //IL_00b8: Unknown result type (might be due to invalid IL or missing references) //IL_00af: Unknown result type (might be due to invalid IL or missing references) //IL_00bd: Unknown result type (might be due to invalid IL or missing references) //IL_00df: Unknown result type (might be due to invalid IL or missing references) if (!string.IsNullOrEmpty(sheet) && !string.IsNullOrEmpty(key) && sheet.StartsWith("Mods.")) { if (!Language.Has(key, sheet)) { LanguageCode val = (LanguageCode)(((??)I18NPlugin.Instance.LanguageOverride) ?? Language._currentLanguage); string arg = sheet.Substring("Mods.".Length); I18NPlugin.Instance.Logger.LogWarning((object)$"language {val} for mod {arg} missing: {key}"); } else if (!allowBlankText && string.IsNullOrWhiteSpace(LocalisedString.ReplaceTags(Language.Get(key, sheet)))) { LanguageCode val2 = (LanguageCode)(((??)I18NPlugin.Instance.LanguageOverride) ?? Language._currentLanguage); string arg2 = sheet.Substring("Mods.".Length); I18NPlugin.Instance.Logger.LogWarning((object)$"language {val2} for mod {arg2} is blank at: {key}"); } } } } }