using System; using System.Collections; using System.Collections.Generic; using System.ComponentModel; 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.Serialization; using System.Runtime.Versioning; using System.Security; using System.Security.Cryptography; using System.Security.Permissions; using System.Text; using System.Text.RegularExpressions; using BepInEx; using BepInEx.Bootstrap; using BepInEx.Configuration; using BepInEx.Logging; using DG.Tweening; using DG.Tweening.Core; using DG.Tweening.Plugins.Options; using Febucci.UI; using Febucci.UI.Core; using HarmonyLib; using Microsoft.CodeAnalysis; using Newtonsoft.Json; using Newtonsoft.Json.Serialization; using Steamworks; using Steamworks.Data; using TMPro; using UnityEngine; using UnityEngine.Events; using UnityEngine.SceneManagement; using UnityEngine.TextCore; using UnityEngine.TextCore.LowLevel; using UnityEngine.UI; using WKLocalizationLoader.Config; using WKLocalizationLoader.FontFactory; using WKLocalizationLoader.Modules; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)] [assembly: IgnoresAccessChecksTo("Assembly-CSharp")] [assembly: IgnoresAccessChecksTo("Unity.TextMeshPro")] [assembly: IgnoresAccessChecksTo("UnityEngine.UI")] [assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")] [assembly: AssemblyCompany("WKLocalizationLoader")] [assembly: AssemblyConfiguration("Debug")] [assembly: AssemblyFileVersion("0.6.3.0")] [assembly: AssemblyInformationalVersion("0.6.3+69a5d4aa1d94e44ad1972915f95ed94bcad92993")] [assembly: AssemblyProduct("WKLocalizationLoader")] [assembly: AssemblyTitle("WKLocalizationLoader")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("0.6.3.0")] [module: UnverifiableCode] [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 WKLocalizationLoader { public static class CacheManager { private static JsonSerializerSettings _jsonSerializerSettings; private static Dictionary _fontCache; private static Dictionary _fontAssetCache; private static Dictionary<(string, RegexOptions), Regex> _regexCache; private static ValueCollection _scriptableObjectCache; private static Dictionary _textAssetCache; private static Plugin _plugin; private static ManualLogSource _logger; public static void Initialize(Plugin plugin) { //IL_0001: 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_000c: Unknown result type (might be due to invalid IL or missing references) //IL_000d: Unknown result type (might be due to invalid IL or missing references) //IL_0017: Expected O, but got Unknown //IL_001d: Expected O, but got Unknown //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_002e: 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_003e: Unknown result type (might be due to invalid IL or missing references) //IL_004b: Expected O, but got Unknown _jsonSerializerSettings = new JsonSerializerSettings { ContractResolver = (IContractResolver)new DefaultContractResolver { NamingStrategy = (NamingStrategy)new DefaultNamingStrategy() }, Formatting = (Formatting)1, TypeNameHandling = (TypeNameHandling)0, NullValueHandling = (NullValueHandling)1, MissingMemberHandling = (MissingMemberHandling)0, ReferenceLoopHandling = (ReferenceLoopHandling)1 }; _fontCache = new Dictionary(); _fontAssetCache = new Dictionary(); if (plugin != null) { _plugin = plugin; string text = ((BaseUnityPlugin)_plugin).Info.Metadata.Name + "/CacheManager"; _logger = Logger.CreateLogSource(text); } } public static void AddFontToMemoryCache(string hash, Font font) { if (_fontCache == null) { _fontCache = new Dictionary(); } if (!string.IsNullOrWhiteSpace(hash) && font != null) { _fontCache[hash] = font; } } public static Font GetFontFromMemoryCache(string hash) { if (!string.IsNullOrWhiteSpace(hash) && _fontCache != null && _fontCache.TryGetValue(hash, out var value)) { return value; } return null; } public static Font CreateFontFromDiskCache(string hash) { if (string.IsNullOrWhiteSpace(hash) || _jsonSerializerSettings == null) { return null; } Font result = null; try { if (FileManager.TryGetFontCachePaths(hash, out var cacheDataPath, out var atlasPath)) { result = FontBuilder.CreateFontFromDiskCache(cacheDataPath, atlasPath, _jsonSerializerSettings, _logger); } } catch (Exception ex) { ManualLogSource logger = _logger; if (logger != null) { logger.LogWarning((object)("An error occurred while creating Font (hash: " + hash + ") from disk cache.")); } ManualLogSource logger2 = _logger; if (logger2 != null) { logger2.LogWarning((object)ex.Message); } result = null; } return result; } public static void WriteFontDiskCache(string hash, Font font) { if (string.IsNullOrWhiteSpace(hash) || font == null || _jsonSerializerSettings == null) { return; } try { string cacheFolder = Path.Combine(FileManager.FontCacheFolder, hash); FontBuilder.WriteFontDiskCache(cacheFolder, font, _jsonSerializerSettings, _logger); } catch (Exception ex) { ManualLogSource logger = _logger; if (logger != null) { logger.LogWarning((object)("An error occurred while writing Font (hash: " + hash + ") cache to disk.")); } ManualLogSource logger2 = _logger; if (logger2 != null) { logger2.LogWarning((object)ex.Message); } } } public static void AddFontAssetToMemoryCache(string hash, TMP_FontAsset fontAsset) { if (_fontAssetCache == null) { _fontAssetCache = new Dictionary(); } if (!string.IsNullOrWhiteSpace(hash) && fontAsset != null) { _fontAssetCache[hash] = fontAsset; } } public static TMP_FontAsset GetFontAssetFromMemoryCache(string hash) { if (!string.IsNullOrWhiteSpace(hash) && _fontAssetCache != null && _fontAssetCache.TryGetValue(hash, out var value)) { return value; } return null; } public static TMP_FontAsset CreateFontAssetFromDiskCache(string hash) { if (string.IsNullOrWhiteSpace(hash) || _jsonSerializerSettings == null) { return null; } TMP_FontAsset result = null; try { if (FileManager.TryGetFontAssetCachePaths(hash, out var cacheDataPath, out var atlasPathMatches)) { List atlasPaths = (from p in atlasPathMatches orderby int.Parse(p.MatchResult.Groups[1].Value) select p.Path).ToList(); result = FontAssetBuilder.CreateFontAssetFromDiskCache(cacheDataPath, atlasPaths, _jsonSerializerSettings, _logger); } } catch (Exception ex) { ManualLogSource logger = _logger; if (logger != null) { logger.LogWarning((object)("An error occurred while creating FontAsset (hash: " + hash + ") from disk cache.")); } ManualLogSource logger2 = _logger; if (logger2 != null) { logger2.LogWarning((object)ex.Message); } result = null; } return result; } public static void WriteFontAssetDiskCache(string hash, TMP_FontAsset fontAsset) { if (string.IsNullOrWhiteSpace(hash) || fontAsset == null || _jsonSerializerSettings == null) { return; } try { string cacheFolder = Path.Combine(FileManager.FontAssetCacheFolder, hash); FontAssetBuilder.WriteFontAssetDiskCache(cacheFolder, fontAsset, _jsonSerializerSettings, _logger); } catch (Exception ex) { ManualLogSource logger = _logger; if (logger != null) { logger.LogWarning((object)("An error occurred while writing FontAsset (hash: " + hash + ") cache to disk.")); } ManualLogSource logger2 = _logger; if (logger2 != null) { logger2.LogWarning((object)ex.Message); } } } public static Regex GetOrCreateRegex(string pattern, RegexOptions regexOptions = RegexOptions.None) { if (_regexCache == null) { _regexCache = new Dictionary<(string, RegexOptions), Regex>(); } (string, RegexOptions) key = (pattern, regexOptions); Regex value = null; if (_regexCache.TryGetValue(key, out value) && value != null) { return value; } value = new Regex(pattern, regexOptions); _regexCache[key] = value; return value; } public static void ScanScriptableObjects() { if (_scriptableObjectCache == null) { _scriptableObjectCache = new ValueCollection(); } Object[] array = Resources.FindObjectsOfTypeAll(typeof(ScriptableObject)); foreach (Object val in array) { _scriptableObjectCache.Add(((object)val).GetType(), val); } } public static IEnumerable EnumerateScriptableObjects() where TScriptableObject : ScriptableObject { if (_scriptableObjectCache == null || !_scriptableObjectCache.TryGetValues(typeof(TScriptableObject), out var scriptableObjects)) { yield break; } foreach (Object scriptableObject in scriptableObjects) { TScriptableObject so = (TScriptableObject)(object)((scriptableObject is TScriptableObject) ? scriptableObject : null); if (so != null) { yield return so; } } } public static TextAsset GetOrCreateTextAsset(string text) { //IL_0037: Unknown result type (might be due to invalid IL or missing references) //IL_003d: Expected O, but got Unknown if (_textAssetCache == null) { _textAssetCache = new Dictionary(); } TextAsset value = null; if (_textAssetCache.TryGetValue(text, out value) && (Object)(object)value != (Object)null) { return value; } value = new TextAsset(text); _textAssetCache[text] = value; return value; } } public static class ConfigManager { private static Plugin _plugin; private static ConfigFile _config; private static ManualLogSource _logger; public static void Initialize(Plugin plugin) { if (plugin != null) { _plugin = plugin; _config = ((BaseUnityPlugin)plugin).Config; string text = ((BaseUnityPlugin)_plugin).Info.Metadata.Name + "/ConfigManager"; _logger = Logger.CreateLogSource(text); } } public static bool IsModuleEnabled(string section, string moduleDescription = null) { //IL_001a: Unknown result type (might be due to invalid IL or missing references) //IL_0020: Expected O, but got Unknown //IL_006a: Unknown result type (might be due to invalid IL or missing references) //IL_0070: Expected O, but got Unknown if (_config == null) { return true; } ConfigDefinition val = new ConfigDefinition(section, "IsEnabled"); string text = "Set this field to \"false\" to disable this module."; ConfigEntry val2 = default(ConfigEntry); if (moduleDescription != null) { text = moduleDescription + "\n" + text; } else if (_config.TryGetEntry(val, ref val2)) { text = ((ConfigEntryBase)val2).Description.Description; } ConfigDescription val3 = new ConfigDescription(text, (AcceptableValueBase)null, Array.Empty()); ConfigEntry val4 = _config.Bind(val, true, val3); return val4.Value; } public static bool IsModuleUserOverridesEnabled(string section) { if (_config == null) { return false; } ConfigEntry val = _config.Bind(section, "EnableUserOverrides", false, "Set this field to \"true\" to apply the custom values below."); return val.Value; } public static object GetConfigEntryValue(string section, string moduleDescription, string key, object defaultValue, string entryDescription) { if (_config == null) { return defaultValue; } bool flag = IsModuleEnabled(section, moduleDescription); bool flag2 = IsModuleUserOverridesEnabled(section); object obj = BindConfigEntryValue(section, key, defaultValue, entryDescription); return (flag && flag2) ? obj : defaultValue; } public static object BindConfigEntryValue(string section, string key, object defaultValue, string entryDescription) { if (1 == 0) { } ConfigEntryBase val; if (!(defaultValue is bool flag)) { if (!(defaultValue is int num)) { if (!(defaultValue is float num2)) { if (!(defaultValue is string text)) { throw new NotSupportedException("\"" + (defaultValue?.GetType().Name ?? "Null") + "\" entry type isn't currently supported."); } val = (ConfigEntryBase)(object)_config.Bind(section, key, text, entryDescription); } else { val = (ConfigEntryBase)(object)_config.Bind(section, key, num2, entryDescription); } } else { val = (ConfigEntryBase)(object)_config.Bind(section, key, num, entryDescription); } } else { val = (ConfigEntryBase)(object)_config.Bind(section, key, flag, entryDescription); } if (1 == 0) { } ConfigEntryBase val2 = val; return val2.BoxedValue; } } public static class FileManager { private static Plugin _plugin; private static ManualLogSource _logger; private static string _rootFolder; private static string _languageFolder; public static string RootFolder { get { if (_rootFolder == null) { ManualLogSource logger = _logger; if (logger != null) { logger.LogWarning((object)"RootFolder is null."); } } else if (!Directory.Exists(_rootFolder)) { ManualLogSource logger2 = _logger; if (logger2 != null) { logger2.LogWarning((object)("RootFolder \"" + _rootFolder + "\" does not exist.")); } } return _rootFolder ?? Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location); } } public static string LanguageFolder { get { if (_languageFolder == null) { ManualLogSource logger = _logger; if (logger != null) { logger.LogWarning((object)"LanguageFolder is null."); } } else if (!Directory.Exists(_languageFolder)) { ManualLogSource logger2 = _logger; if (logger2 != null) { logger2.LogWarning((object)("LanguageFolder \"" + _languageFolder + "\" does not exist.")); } } return _languageFolder ?? RootFolder; } } public static string FontsFolder => Path.Combine(LanguageFolder, "Fonts"); public static string CacheFolder => Path.Combine(RootFolder, "Cache"); public static string FontCacheFolder => Path.Combine(CacheFolder, "Fonts"); public static string FontAssetCacheFolder => Path.Combine(CacheFolder, "FontAssets"); public static void Initialize(Plugin plugin) { _rootFolder = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location); if (plugin != null) { _plugin = plugin; string text = ((BaseUnityPlugin)_plugin).Info.Metadata.Name + "/FileManager"; _logger = Logger.CreateLogSource(text); SetLanguageFolder(_plugin.LanguageFolder); } } public static void SetLanguageFolder(string languageFolder) { _languageFolder = Path.GetFullPath(Path.Combine(Paths.PluginPath, languageFolder)); } public static bool TryGetModuleFilePath(string fileName, out string filePath) { filePath = null; return TryGetExistingFilePath(LanguageFolder, fileName, out filePath); } public static bool TryGetFontFilePath(string fileName, out string filePath) { filePath = null; return TryGetExistingFilePath(FontsFolder, fileName, out filePath); } public static bool TryGetFontCachePaths(string hash, out string cacheDataPath, out string atlasPath) { cacheDataPath = null; atlasPath = null; if (TryGetExistingFolderPath(FontCacheFolder, hash, out var folderPath)) { return TryGetExistingFilePath(folderPath, "CachedFontData.json", out cacheDataPath) && TryGetExistingFilePath(folderPath, "RawAtlasTextureData", out atlasPath); } return false; } public static bool TryGetFontAssetCachePaths(string hash, out string cacheDataPath, out IEnumerable atlasPathMatches) { cacheDataPath = null; atlasPathMatches = null; if (TryGetExistingFolderPath(FontAssetCacheFolder, hash, out var folderPath)) { return TryGetExistingFilePath(folderPath, "CachedFontAssetData.json", out cacheDataPath) && TrySearchFilePaths(folderPath, "^RawAtlasTextureData_(\\d+)", out atlasPathMatches); } return false; } public static bool TryGetExistingFilePath(string folder, string fileName, out string filePath) { try { filePath = Path.Combine(folder, fileName); return File.Exists(filePath); } catch (Exception ex) { ManualLogSource logger = _logger; if (logger != null) { logger.LogError((object)ex.Message); } filePath = null; return false; } } public static bool TryGetExistingFolderPath(string parentFolder, string folder, out string folderPath) { try { folderPath = Path.Combine(parentFolder, folder); return Directory.Exists(folderPath); } catch (Exception ex) { ManualLogSource logger = _logger; if (logger != null) { logger.LogError((object)ex.Message); } folderPath = null; return false; } } public static bool TrySearchFilePaths(string folder, string fileNamePattern, out IEnumerable matchResults) { try { Regex regex = CacheManager.GetOrCreateRegex(fileNamePattern); matchResults = from f in Directory.EnumerateFiles(folder) select new PathMatchResult(f, regex.Match(Path.GetFileName(f))) into p where p.MatchResult.Success select p; return matchResults.Count() > 0; } catch (Exception ex) { ManualLogSource logger = _logger; if (logger != null) { logger.LogError((object)ex.Message); } matchResults = null; return false; } } } public static class HashCalculator { private static JsonSerializerSettings _jsonSerializerSettings; public static void Initialize() { //IL_0001: 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_000c: Unknown result type (might be due to invalid IL or missing references) //IL_000d: Unknown result type (might be due to invalid IL or missing references) //IL_0017: Expected O, but got Unknown //IL_001d: Expected O, but got Unknown //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Unknown result type (might be due to invalid IL or missing references) //IL_003b: Expected O, but got Unknown _jsonSerializerSettings = new JsonSerializerSettings { ContractResolver = (IContractResolver)new DefaultContractResolver { NamingStrategy = (NamingStrategy)new DefaultNamingStrategy() }, Formatting = (Formatting)0, NullValueHandling = (NullValueHandling)0, DefaultValueHandling = (DefaultValueHandling)2 }; } public static string GetHashString(string characters, FontProperties fontProperties, int hashStringLength = 6) { var targetObject = new { Characters = characters, Properties = fontProperties }; return GetHashString(targetObject, hashStringLength); } public static string GetHashString(string characters, FontAssetProperties fontAssetProperties, int hashStringLength = 6) { var targetObject = new { Characters = characters, Properties = fontAssetProperties }; return GetHashString(targetObject, hashStringLength); } public static string GetHashString(object targetObject, int hashStringLength) { if (_jsonSerializerSettings == null) { Initialize(); } string s = JsonConvert.SerializeObject(targetObject, _jsonSerializerSettings); using SHA256 sHA = SHA256.Create(); byte[] array = sHA.ComputeHash(Encoding.UTF8.GetBytes(s)); string text = BitConverter.ToString(array).Replace("-", ""); return text.Substring(0, hashStringLength).ToLower(); } } public static class LanguageScanner { public static List Scan(int maxRecersionDepth = 5, ManualLogSource logger = null) { List list = new List(); ScanLanguageFolders(Paths.PluginPath, maxRecersionDepth, 0, list, logger); return list; } public static void ScanLanguageFolders(string directory, int maxDepth, int currentDepth, List results, ManualLogSource logger = null) { IEnumerable enumerable = Directory.EnumerateFiles(directory, "*", SearchOption.TopDirectoryOnly); foreach (string item in enumerable) { if (!IsLanguageFolderMarkerFile(item)) { continue; } string text = "." + directory.Substring(Paths.PluginPath.Length); text = text.Replace("\\", "/"); if (!results.Contains(text)) { if (logger != null) { logger.LogInfo((object)("Auto-detected Language Folder \"" + text + "\".")); } results.Add(text); } } if (currentDepth >= maxDepth) { return; } IEnumerable enumerable2 = Directory.EnumerateDirectories(directory, "*", SearchOption.TopDirectoryOnly); foreach (string item2 in enumerable2) { ScanLanguageFolders(item2, maxDepth, currentDepth + 1, results, logger); } } public static bool IsLanguageFolderMarkerFile(string filePath) { string fileName = Path.GetFileName(filePath); if (1 == 0) { } bool result = fileName == ".wklocalization"; if (1 == 0) { } return result; } } public class ModuleInfo { public Type ModuleClass; public ModuleStatus Status; public string Message; public ModuleInfo(Type moduleClass, ModuleStatus status, string message) { ModuleClass = moduleClass; Status = status; Message = message; } } public class ModuleLoadResult { private ManualLogSource _logger; public List ModuleInfos; public ModuleLoadResult(ManualLogSource logger) { _logger = logger; ModuleInfos = new List(); } public void AddOKModule(Type moduleClass) { string message = "Loaded \"" + moduleClass.Name + "\" successfully."; AddModuleInfo(moduleClass, ModuleStatus.OK, message); } public void AddDisabledModule(Type moduleClass) { string message = "\"" + moduleClass.Name + "\" is loaded but manually disabled in config."; AddModuleInfo(moduleClass, ModuleStatus.Disabled, message); } public void AddFileMissingModule(Type moduleClass) { string message = "\"" + moduleClass.Name + "\" is missing its associated .json file and disabled by default."; AddModuleInfo(moduleClass, ModuleStatus.Disabled, message); } public void AddConflictedModule(Type moduleClass, List conflictedModGUIDs) { string text = null; text = ((conflictedModGUIDs != null && conflictedModGUIDs.Count != 0) ? ("\"" + moduleClass.Name + "\" is disabled to avoid conflicts with the following mod(s):\n" + string.Join("\n", conflictedModGUIDs)) : ("\"" + moduleClass.Name + "\" is disabled to avoid conflicts.")); AddModuleInfo(moduleClass, ModuleStatus.Conflicted, text); } public void AddDeserializationFailedModule(Type moduleClass, string filePath, Exception e) { string message = "An error occurred while deserializing \"" + moduleClass.Name + "\" from \"" + filePath + "\".\n" + e.Message; AddModuleInfo(moduleClass, ModuleStatus.Failed, message); } public void AddModuleInfo(Type moduleClass, ModuleStatus status, string message) { ModuleInfo item = new ModuleInfo(moduleClass, status, message); ModuleInfos.Add(item); } public List FilterModuleClassesByModuleStatus(ModuleStatus status) { if (ModuleInfos == null) { return null; } return (from m in ModuleInfos where m.Status == status select m.ModuleClass).ToList(); } public void PrintModuleInfoMessageBySeverity(ModuleStatus minSeverity) { if (ModuleInfos == null || _logger == null) { return; } List list = ModuleInfos.Where((ModuleInfo m) => m.Status >= minSeverity).ToList(); foreach (ModuleInfo item in list) { PrintModuleInfoMessage(item); } } public void PrintModuleInfoMessage(ModuleInfo moduleInfo) { if (_logger != null) { switch (moduleInfo.Status) { case ModuleStatus.OK: _logger.LogInfo((object)moduleInfo.Message); break; case ModuleStatus.Disabled: _logger.LogInfo((object)moduleInfo.Message); break; case ModuleStatus.Conflicted: _logger.LogInfo((object)moduleInfo.Message); break; case ModuleStatus.Failed: _logger.LogError((object)moduleInfo.Message); break; default: throw new ArgumentOutOfRangeException("How?"); } } } } public static class ModuleManager { private static Plugin _plugin; private static ManualLogSource _logger; private static JsonSerializerSettings _jsonSerializerSettings; private static ModuleLoadResult _moduleLoadResult; private static ValueCollection _conflictedModsInfo = new ValueCollection(); public static void Initialize(Plugin plugin) { //IL_0001: 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_0013: Expected O, but got Unknown _jsonSerializerSettings = new JsonSerializerSettings { NullValueHandling = (NullValueHandling)1 }; if (plugin != null) { _plugin = plugin; string text = ((BaseUnityPlugin)_plugin).Info.Metadata.Name + "/ModuleManager"; _logger = Logger.CreateLogSource(text); _moduleLoadResult = new ModuleLoadResult(_logger); } } public static void LoadAllModules() { LoadModule("Achievements.json"); LoadModule("AnnouncementSubtitles.json"); LoadModule("AnnouncementSubtitleTimings.json"); LoadModule("Cosmetics.json"); LoadModule("DeathTexts.json"); LoadModule("Documents.json"); LoadModule("FacilityUpgrades.json"); LoadModule("Fonts.json"); LoadModule("FontAssets.json"); LoadModule("Gamemodes.json"); LoadModule("GameplayTexts.json"); LoadModule("ItemDescriptions.json"); LoadModule("LocationNames.json"); LoadModule("MainMenu.json"); LoadModule("MotherSubtitles.json"); LoadModule("Notes.json"); LoadModule("Objectives.json"); LoadModule("Perks.json"); LoadModule("ProgressionUnlocks.json"); LoadModule("QuietOS.json"); LoadModule("RecordingSubtitles.json"); LoadModule("RecordingSubtitleTimings.json"); LoadModule("RoachTraderSubtitles.json"); LoadModule("ScoreScreen.json"); LoadModule("StaticTexts.json"); LoadModule("TextScrawls.json"); LoadModule("Trinkets.json"); } public static void LoadModule(string fileName) where TModule : ModuleBase { Type typeFromHandle = typeof(TModule); if (DetectConflictedMods(typeFromHandle, out var conflictedModGUIDs)) { _moduleLoadResult.AddConflictedModule(typeFromHandle, conflictedModGUIDs); return; } if (!FileManager.TryGetModuleFilePath(fileName, out var filePath)) { _moduleLoadResult.AddFileMissingModule(typeFromHandle); return; } try { string text = File.ReadAllText(filePath); if (string.IsNullOrWhiteSpace(text)) { throw new InvalidDataException("File content is empty or whitespace."); } JsonConvert.DeserializeObject(text, _jsonSerializerSettings); } catch (Exception e) { _moduleLoadResult.AddDeserializationFailedModule(typeFromHandle, fileName, e); return; } if (ModuleBase.IsEnabled) { _moduleLoadResult.AddOKModule(typeFromHandle); } else { _moduleLoadResult.AddDisabledModule(typeFromHandle); } } public static bool DetectConflictedMods(Type moduleClass, out List conflictedModGUIDs) { conflictedModGUIDs = null; if (_conflictedModsInfo != null && _conflictedModsInfo.TryGetValues(moduleClass, out conflictedModGUIDs)) { return conflictedModGUIDs.Any((string g) => Chainloader.PluginInfos.ContainsKey(g)); } return false; } public static List FilterModuleClassesByModuleStatus(ModuleStatus status) { return _moduleLoadResult?.FilterModuleClassesByModuleStatus(status); } public static void PrintModuleInfoMessageBySeverity(ModuleStatus minSeverity) { _moduleLoadResult?.PrintModuleInfoMessageBySeverity(minSeverity); } } public enum ModuleStatus { OK, Disabled, Conflicted, Failed } public class PathMatchResult { public string Path; public Match MatchResult; public PathMatchResult(string path, Match matchResult) { Path = path; MatchResult = matchResult; } } [BepInPlugin("mimimi-turret.wk-localization-loader", "WKLocalizationLoader", "0.6.3")] [BepInProcess("White Knuckle.exe")] public class Plugin : BaseUnityPlugin { private ConfigEntry _languageFolder; private ConfigEntry _maxScanDepth; public static ManualLogSource Logger; private string _languageFolderDescription => "Specifies the path to a Language Folder.\nA relative path is resolved from \"BepInEx\\plugins\\\".\n\nA Language Folder may contain any of the following files:\n* Texts.json\n* FontAssets.json\n* Fonts\\\n* Licenses\\ (licenses of the fonts, etc.)\n\nLeave this field empty to auto-detect a \nLanguage Folder installed in \"BepInEx\\plugins\\\".\nBy default, the plugin will load the first valid Language Folder it detects.\nFor further info, see \"MaxScanDepth\" below or plugin wiki."; private string _maxScanDepthDescription => "Limits the directory depth when auto-detecting Language Folders.\n\nA Language Folder is detected when it contains the following file:\n* .wklocalization\nNote: This file is for auto-detection purpose only.\nIt does not store any actual information or data.\n\nScanning will start from \"BepInEx\\plugins\\\" where the directory depth is 0."; public string LanguageFolder => _languageFolder?.Value; public int MaxScanDepth => _maxScanDepth?.Value ?? 5; private void Awake() { Initialize(); if (string.IsNullOrWhiteSpace(LanguageFolder)) { Logger.LogFatal((object)"Failed to auto-detect Language Folders."); return; } FileManager.Initialize(this); ConfigManager.Initialize(this); ModuleManager.Initialize(this); ResourceLoader.Initialize(this); CacheManager.Initialize(this); List moduleClasses = LoadAllModules(); ApplyHarmonyPatches(moduleClasses); ApplyScriptableObjectPatches(moduleClasses); } private void Initialize() { _languageFolder = ((BaseUnityPlugin)this).Config.Bind("General", "LanguageFolder", "", _languageFolderDescription); _maxScanDepth = ((BaseUnityPlugin)this).Config.Bind("General", "MaxScanDepth", 5, _maxScanDepthDescription); Logger = ((BaseUnityPlugin)this).Logger; if (string.IsNullOrWhiteSpace(LanguageFolder)) { List list = LanguageScanner.Scan(MaxScanDepth, Logger); if (list.Count != 0) { Logger.LogInfo((object)"Loading the first valid Language Folder detected by default."); _languageFolder.Value = list.FirstOrDefault(); } } } private List LoadAllModules() { ModuleManager.LoadAllModules(); List result = ModuleManager.FilterModuleClassesByModuleStatus(ModuleStatus.OK); ModuleManager.PrintModuleInfoMessageBySeverity(ModuleStatus.OK); return result; } private void ApplyHarmonyPatches(List moduleClasses) { //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_0017: Expected O, but got Unknown Harmony val = new Harmony(((BaseUnityPlugin)this).Info.Metadata.GUID); foreach (Type moduleClass in moduleClasses) { if (((MemberInfo)moduleClass).GetCustomAttribute() != null) { PatchClassProcessor val2 = val.CreateClassProcessor(moduleClass); val2.Patch(); } } } private void ApplyScriptableObjectPatches(List moduleClasses) { ScriptableObjectPatcher.Initialize(moduleClasses); } } public static class ResourceLoader { private static Plugin _plugin; private static ManualLogSource _logger; public static void Initialize(Plugin plugin) { if (plugin != null) { _plugin = plugin; string text = ((BaseUnityPlugin)_plugin).Info.Metadata.Name + "/ResourceLoader"; _logger = Logger.CreateLogSource(text); } } public static bool TryGetOrCreateFont(string characters, FontProperties fontProperties, out Font font, bool isDiskCacheEnabled = false) { string hashString = HashCalculator.GetHashString(characters, fontProperties); font = CacheManager.GetFontFromMemoryCache(hashString); if ((Object)(object)font != (Object)null) { return true; } bool flag = isDiskCacheEnabled; if (isDiskCacheEnabled) { font = CacheManager.CreateFontFromDiskCache(hashString); flag = font == null; } if (font == null) { font = CreateFont(hashString, characters, fontProperties); } flag = flag && (Object)(object)font != (Object)null; if (font == null) { font = FontBuilder.CreateFontFromOSFont(fontProperties); } if (font == null) { return false; } if (flag) { CacheManager.WriteFontDiskCache(hashString, font); } CacheManager.AddFontToMemoryCache(hashString, font); return true; } public static Font CreateFont(string hash, string characters, FontProperties fontProperties) { try { if (FileManager.TryGetFontFilePath(fontProperties.FileName, out var filePath)) { if (string.IsNullOrEmpty(fontProperties.FontName)) { fontProperties.FontName = "SubstituteFont - " + Path.GetFileNameWithoutExtension(filePath); } return FontBuilder.CreateFont(filePath, characters, fontProperties, _logger); } return null; } catch (Exception ex) { ManualLogSource logger = _logger; if (logger != null) { logger.LogError((object)("An error occurred while creating Font (hash: " + hash + ").")); } ManualLogSource logger2 = _logger; if (logger2 != null) { logger2.LogError((object)ex.Message); } return null; } } public static bool TryGetOrCreateFontAsset(string characters, FontAssetProperties fontAssetProperties, out TMP_FontAsset fontAsset, bool isDiskCacheEnabled = false) { string hashString = HashCalculator.GetHashString(characters, fontAssetProperties); fontAsset = CacheManager.GetFontAssetFromMemoryCache(hashString); if ((Object)(object)fontAsset != (Object)null) { return true; } bool flag = isDiskCacheEnabled; if (isDiskCacheEnabled) { fontAsset = CacheManager.CreateFontAssetFromDiskCache(hashString); flag = fontAsset == null; } if (fontAsset == null) { fontAsset = CreateFontAsset(hashString, characters, fontAssetProperties); } if (fontAsset == null) { return false; } if (flag) { CacheManager.WriteFontAssetDiskCache(hashString, fontAsset); } CacheManager.AddFontAssetToMemoryCache(hashString, fontAsset); return true; } public static TMP_FontAsset CreateFontAsset(string hash, string characters, FontAssetProperties fontAssetProperties) { try { if (FileManager.TryGetFontFilePath(fontAssetProperties.FileName, out var filePath)) { if (string.IsNullOrEmpty(fontAssetProperties.FontName)) { fontAssetProperties.FontName = "FallbackFontAsset - " + Path.GetFileNameWithoutExtension(filePath); } return FontAssetBuilder.CreateFontAsset(filePath, characters, fontAssetProperties, _logger); } return null; } catch (Exception ex) { ManualLogSource logger = _logger; if (logger != null) { logger.LogError((object)("An error occurred while creating FontAsset (hash: " + hash + ").")); } _logger.LogError((object)ex.Message); return null; } } } public class ScriptableObjectPatcher { public static List ModuleClasses; public static void Initialize(List moduleClasses) { ModuleClasses = moduleClasses; FilterScriptableObjectPatchClasses(); if (ModuleClasses != null && ModuleClasses.Count != 0) { SceneManager.sceneLoaded += OnSceneLoaded; } } public static void OnSceneLoaded(Scene scene, LoadSceneMode loadSceneMode) { if (((Scene)(ref scene)).name == "Main-Menu") { CacheManager.ScanScriptableObjects(); ApplyScriptableObjectPatches(); SceneManager.sceneLoaded -= OnSceneLoaded; } } public static void ApplyScriptableObjectPatches() { foreach (Type moduleClass in ModuleClasses) { moduleClass.GetMethod("PatchScriptableObjects", BindingFlags.Static | BindingFlags.Public)?.Invoke(null, null); } } public static void FilterScriptableObjectPatchClasses() { if (ModuleClasses != null && ModuleClasses.Count != 0) { ModuleClasses = ModuleClasses.Where((Type m) => typeof(IScriptableObjectPatch).IsAssignableFrom(m) && m.GetMethod("PatchScriptableObjects", BindingFlags.Static | BindingFlags.Public) != null).ToList(); } } } public class TemplateTranslations { private Dictionary _textTranslations; private Dictionary _templateMappings; private readonly Regex _templateGroupRegex; private readonly Regex _escapedTemplateGroupRegex; public TemplateTranslations(Dictionary textTranslations) { _templateGroupRegex = CacheManager.GetOrCreateRegex("\\{(\\d+)\\}", RegexOptions.Compiled); _escapedTemplateGroupRegex = CacheManager.GetOrCreateRegex("\\\\\\{\\d+\\}", RegexOptions.Compiled); AddTemplateTranslations(textTranslations); } public void AddTemplateTranslations(Dictionary textTranslations) { foreach (KeyValuePair textTranslation in textTranslations) { AddTemplateTranslation(textTranslation.Key, textTranslation.Value); } } public void AddTemplateTranslation(string originalTemplateString, string translatedTemplateString) { if (_textTranslations == null) { _textTranslations = new Dictionary(); } if (_templateMappings == null) { _templateMappings = new Dictionary(); } if (originalTemplateString != null && translatedTemplateString != null) { _textTranslations[originalTemplateString] = translatedTemplateString; if (_templateGroupRegex.IsMatch(originalTemplateString)) { Regex key = CreateTemplateRegex(originalTemplateString); _templateMappings[key] = translatedTemplateString; } } } public string GetTemplateTranslation(string originalText) { if (string.IsNullOrWhiteSpace(originalText)) { return originalText; } if (_textTranslations != null && _textTranslations.TryGetValue(originalText, out var value) && value != null) { return value; } if (_templateMappings != null) { foreach (KeyValuePair templateMapping in _templateMappings) { Regex key = templateMapping.Key; if (key != null) { Match match = key.Match(originalText); if (match.Success) { string value2 = templateMapping.Value; return (value2 == null) ? originalText : BuildStringFromTemplate(value2, match); } } } } return originalText; } public string BuildStringFromTemplate(string templateString, Match templateMatch) { return _templateGroupRegex.Replace(templateString, delegate(Match m) { int num = Convert.ToInt32(m.Groups[1].Value) + 1; return (num > templateMatch.Groups.Count) ? "" : templateMatch.Groups[num].Value; }); } public Regex CreateTemplateRegex(string templateString) { string input = Regex.Escape(templateString); string text = _escapedTemplateGroupRegex.Replace(input, "(.*)"); text = "^" + text + "$"; return CacheManager.GetOrCreateRegex(text, RegexOptions.Singleline); } } public class ValueCollection { private Dictionary> _dictionary; public void Add(TKey key, TValue value) { if (_dictionary == null) { _dictionary = new Dictionary>(); } if (key == null || value == null) { return; } if (TryGetValues(key, out var values)) { if (!values.Contains(value)) { values.Add(value); } } else { _dictionary[key] = new List { value }; } } public bool TryGetValues(TKey key, out List values) { if (key == null || _dictionary == null || !_dictionary.TryGetValue(key, out values) || values == null) { values = null; return false; } return true; } } public static class MyPluginInfo { public const string PLUGIN_GUID = "WKLocalizationLoader"; public const string PLUGIN_NAME = "WKLocalizationLoader"; public const string PLUGIN_VERSION = "0.6.3"; } } namespace WKLocalizationLoader.Modules { [HarmonyPatch] public class AchievementPatch : TextTranslator { [JsonProperty] public static Dictionary AchievementTitles; [JsonProperty] public static Dictionary AchievementDescriptions; [JsonIgnore] public static AchievementPatchSettings ModuleSettings; [HarmonyPostfix] [HarmonyPatch(typeof(CL_AchievementManager), "Awake")] public static void Postfix_AchievementManager_Awake(CL_AchievementManager __instance) { if (!ModuleBase.IsEnabled) { return; } foreach (GameAchievement achievement in __instance.achievements) { if (achievement.announce) { achievement.name = TextTranslator.GetTextTranslation(AchievementTitles, achievement.name); achievement.announceText = TextTranslator.GetTextTranslation(AchievementDescriptions, achievement.announceText); } } } } [ConfigSection("Modules.AchievementPatch", "This module replaces texts for achievements.")] public class AchievementPatchSettings : ModuleSettingsBase { } [HarmonyPatch] public class AnnouncementSubtitlePatch : ModuleBase { [JsonProperty] public static Dictionary AnnouncementSubtitles; [JsonIgnore] public static AnnouncementSubtitlePatchSettings ModuleSettings; [HarmonyPostfix] [HarmonyPatch(typeof(Localization), "GetLine")] public static string Postfix_Localization_GetLine(string __result, string group, string key) { if (!ModuleBase.IsEnabled || group != "announcements" || AnnouncementSubtitles == null || !AnnouncementSubtitles.ContainsKey(key)) { return __result; } return AnnouncementSubtitles[key] ?? __result; } } [ConfigSection("Modules.AnnouncementSubtitlePatch", "This module replaces announcer subtitle texts.")] public class AnnouncementSubtitlePatchSettings : ModuleSettingsBase { } [HarmonyPriority(0)] [HarmonyPatch] public class AnnouncementSubtitleTimingPatch : ModuleBase { [JsonProperty] public static AnnouncementSubtitleTimingPatchSettings ModuleSettings; [JsonProperty] public static Dictionary> AnnouncementSubtitleTimings; [JsonIgnore] public static readonly string[] LinebreakPattern = new string[1] { "
" }; [JsonIgnore] public static readonly Regex DelayRegex = CacheManager.GetOrCreateRegex("", RegexOptions.IgnoreCase | RegexOptions.Compiled); [HarmonyPostfix] [HarmonyPatch(typeof(Localization), "GetLine")] public static string Postfix_Localization_GetLine(string __result, string group, string key) { if (!ModuleBase.IsEnabled || group != "announcements" || AnnouncementSubtitleTimings == null || !AnnouncementSubtitleTimings.ContainsKey(key) || (ModuleSettings.UseOriginalDelay && DelayRegex.IsMatch(__result))) { return __result; } return RebuildSubtitleTextWithTimings(__result, AnnouncementSubtitleTimings[key]); } public static string RebuildSubtitleTextWithTimings(string subtitleText, List subtitleTimings) { if (subtitleTimings == null || subtitleTimings.Count == 0) { return subtitleText; } string[] array = subtitleText.Split(LinebreakPattern, StringSplitOptions.None); int num = Math.Min(array.Length, subtitleTimings.Count); for (int i = 0; i < num; i++) { string subtitleLine = array[i]; subtitleLine = RemoveDelayTag(subtitleLine); float num2 = (float)subtitleLine.Length * ModuleSettings.CharacterInterval + ModuleSettings.BaseDuration; float num3 = subtitleTimings[i]; if (i > 0) { num3 -= subtitleTimings[i - 1]; } if (i == num - 1) { num3 += ModuleSettings.EndDelay; } float num4 = num3 - num2; string delayTag = ((num4 < 0f) ? $"" : $""); subtitleLine = InsertDelayTag(subtitleLine, delayTag); array[i] = subtitleLine; } return string.Join(LinebreakPattern[0], array); } public static string RemoveDelayTag(string subtitleLine) { Match match = DelayRegex.Match(subtitleLine); return match.Success ? subtitleLine.Remove(match.Index, match.Length) : subtitleLine; } public static string InsertDelayTag(string subtitleLine, string delayTag) { if (string.IsNullOrEmpty(delayTag)) { return subtitleLine; } Match match = DelayRegex.Match(subtitleLine); return match.Success ? subtitleLine.Insert(match.Index, delayTag) : (subtitleLine + delayTag); } } [ConfigSection("Modules.AnnouncementSubtitleTimingPatch", "This module adjusts display timings of announcer subtitles.")] public class AnnouncementSubtitleTimingPatchSettings : ModuleSettingsBase { [ConfigEntry("BaseDuration", 2.2f, "Base duration (in seconds) for displaying a subtitle.")] public float BaseDuration; [ConfigEntry("CharacterInterval", 0.1f, "Additional duration (in seconds) added per character in the subtitle text.")] public float CharacterInterval; [ConfigEntry("EndDelay", 0.5f, "Extra duration (in seconds) added at the end of a subtitle.")] public float EndDelay; [ConfigEntry("UseOriginalDelay", false, "Set this field to \"true\" to retain original timings of\nsubtitles that contain \"\" tag(s).")] public bool UseOriginalDelay; } [HarmonyPatch] public class CosmeticPatch : TextTranslator { [JsonProperty] public static Dictionary CosmeticDescriptions; [JsonProperty] public static Dictionary PaletteNames; [JsonProperty] public static string PaletteTextTemplate; [JsonIgnore] public static CosmeticPatchSettings ModuleSettings; [HarmonyPostfix] [HarmonyPatch(typeof(UI_CosmeticInfoPanel), "Open")] public static void Postfix_CosmeticInfoPanel_Open(UI_CosmeticInfoPanel __instance) { if (ModuleBase.IsEnabled) { __instance.descText.text = TextTranslator.GetTextTranslation(CosmeticDescriptions, __instance.descText.text); } } [HarmonyPostfix] [HarmonyPatch(typeof(UI_CosmeticInfoPanel), "UpdateSprite")] public static void Postfix_CosmeticInfoPanel_UpdateSprite(UI_CosmeticInfoPanel __instance) { if (ModuleBase.IsEnabled) { TranslatePaletteText(__instance); } } [HarmonyPostfix] [HarmonyPatch(typeof(UI_CosmeticInfoPanel), "ChangePalette")] public static void Postfix_CosmeticInfoPanel_ChangePalette(UI_CosmeticInfoPanel __instance) { if (ModuleBase.IsEnabled) { TranslatePaletteText(__instance); } } public static void TranslatePaletteText(UI_CosmeticInfoPanel infoPanel) { Cosmetic_Base selectedCosmetic = infoPanel.selectedCosmetic; if (!(selectedCosmetic.cosmeticInfo.tag != "hand")) { Cosmetic_HandItem val = (Cosmetic_HandItem)(object)((selectedCosmetic is Cosmetic_HandItem) ? selectedCosmetic : null); List palettes = val.cosmeticData.palettes; if (palettes != null && palettes.Count != 0) { ColorPalette val2 = palettes[val.currentPaletteId]; string textTranslation = TextTranslator.GetTextTranslation(PaletteNames, val2.title); int num = val.currentPaletteId + 1; int count = palettes.Count; string text = PaletteTextTemplate ?? "{name} ({current}/{count})"; infoPanel.debugText.text = text.Replace("{name}", textTranslation).Replace("{current}", num.ToString()).Replace("{count}", count.ToString()); } } } } [ConfigSection("Modules.CosmeticPatch", "This module replaces texts for cosmetics.")] public class CosmeticPatchSettings : ModuleSettingsBase { } [HarmonyPatch] public class DeathTextPatch : TextTranslator { [JsonProperty] public static Dictionary DeathMessages; [JsonProperty] public static Dictionary DeathTips; [JsonIgnore] public static DeathTextPatchSettings ModuleSettings; [HarmonyPostfix] [HarmonyPatch(typeof(Localization), "GetLine")] public static string Postfix_Localization_GetLine(string __result, string group, string key) { if (!ModuleBase.IsEnabled || group != "deathmessages" || DeathMessages == null || !DeathMessages.ContainsKey(key)) { return __result; } return DeathMessages[key] ?? __result; } [HarmonyPostfix] [HarmonyPatch(typeof(UI_ScoreScreen), "SetTip")] public static void Postfix_ScoreScreen_SetTip(UI_ScoreScreen __instance) { if (ModuleBase.IsEnabled && __instance.useDeathText && __instance.tipText != null) { __instance.tipText.text = TextTranslator.GetTextTranslation(DeathTips, __instance.tipText.text); } } } [ConfigSection("Modules.DeathTextPatch", "This module replaces death messages and death tips.")] public class DeathTextPatchSettings : ModuleSettingsBase { } [HarmonyPatch] public class DocumentPatch : TextTranslator { [JsonProperty] public static Dictionary DocumentTexts; [JsonIgnore] public static DocumentPatchSettings ModuleSettings; [HarmonyPrefix] [HarmonyPatch(typeof(App_DocumentReader), "Start")] public static void Prefix_DocumentReader_Start(App_DocumentReader __instance) { if (ModuleBase.IsEnabled) { string text = ""; OS_Window component = ((Component)__instance).GetComponent(); FileInfo fileInfo = component.file.fileInfo; if (fileInfo.textAssetData == null) { string data = fileInfo.data; string text2 = DarkMachineFunctions.ProcessText(data, true); text = TextTranslator.GetTextTranslation(DocumentTexts, text2); fileInfo.data = data.Replace(text2, text); } else { text = TextTranslator.GetTextTranslation(DocumentTexts, fileInfo.textAssetData.text); fileInfo.textAssetData = CacheManager.GetOrCreateTextAsset(text); } } } } [ConfigSection("Modules.DocumentPatch", "This module replaces texts for QuietOS document files.")] public class DocumentPatchSettings : ModuleSettingsBase { } [HarmonyPatch] public class FacilityUpgradePatch : TextTranslator { [JsonProperty] public static Dictionary UpgradePageTitles; [JsonProperty] public static Dictionary UpgradeTitles; [JsonProperty] public static Dictionary UpgradeDescriptions; [JsonProperty] public static Dictionary UpgradeUnlockDescriptions; [JsonProperty] public static string UpgradePageCounterTemplate; [JsonProperty] public static string UpgradeLockedHoverTextTemplate; [JsonProperty] public static string UpgradeCantAffordHoverTextTemplate; [JsonIgnore] public static FacilityUpgradePatchSettings ModuleSettings; [HarmonyPrefix] [HarmonyPatch(typeof(UI_FacilityMenu_Button), "Initialize")] public static void Prefix_FacilityMenuButton_Initialize(ref FacilityUpgrade upg) { if (ModuleBase.IsEnabled) { PatchFacilityUpgrade(upg); } } [HarmonyPostfix] [HarmonyPatch(typeof(UI_FacilityMenu_Button), "Refresh")] public static void Postfix_FacilityMenuButton_Refresh(UI_FacilityMenu_Button __instance) { if (!ModuleBase.IsEnabled) { return; } FacilityUpgrade upgrade = __instance.upgrade; Facility facility = __instance.facility; if (upgrade == null || facility == null) { return; } if (upgrade.IsLocked(facility.id)) { if (UpgradeLockedHoverTextTemplate != null) { __instance.tooltip.tip = UpgradeLockedHoverTextTemplate.Replace("{unlockDescription}", upgrade.unlockDesc).Replace("{description}", upgrade.description); } return; } int value = StatManager.saveData.GetRoachBankByID("campaign").value; if (!upgrade.IsOwned(facility.id) && upgrade.cost >= value && UpgradeCantAffordHoverTextTemplate != null) { __instance.tooltip.tip = UpgradeCantAffordHoverTextTemplate.Replace("{description}", upgrade.description); } } [HarmonyPrefix] [HarmonyPatch(typeof(App_Facility_Card), "Initialize")] public static void Prefix_FacilityApp_Initialize(ref FacilityUpgrade up) { if (ModuleBase.IsEnabled) { PatchFacilityUpgrade(up); } } [HarmonyPostfix] [HarmonyPatch(typeof(App_Facility_Card), "CheckLock")] public static void Postfix_FacilityAppCard_CheckLock(App_Facility_Card __instance) { if (ModuleBase.IsEnabled) { FacilityUpgrade upgrade = __instance.upgrade; if (!string.IsNullOrEmpty(upgrade.unlockFlag) && !CL_GameManager.HasActiveFlag(upgrade.unlockFlag, true) && upgrade.prerequisiteUpgrade != null && !__instance.facility.HasUpgrade(upgrade.prerequisiteUpgrade.id) && UpgradeLockedHoverTextTemplate != null) { __instance.tooltip.tip = UpgradeLockedHoverTextTemplate.Replace("{unlockDescription}", upgrade.unlockDesc).Replace("{description}", upgrade.description); } } } [HarmonyPostfix] [HarmonyPatch(typeof(App_FacilitySlotHolder), "SetPage")] public static void Postfix_FacilitySlotHolder_SetPage(List pageList, ref int pageNumber, TMP_Text titleObject, string title) { if (ModuleBase.IsEnabled) { string textTranslation = TextTranslator.GetTextTranslation(UpgradePageTitles, title); int count = pageList.Count; if (count < 2) { titleObject.text = textTranslation; return; } int num = pageNumber + 1; string text = UpgradePageCounterTemplate ?? "{title} ({current}/{total})"; titleObject.text = text.Replace("{title}", textTranslation).Replace("{current}", num.ToString()).Replace("{total}", count.ToString()); } } public static void PatchFacilityUpgrade(FacilityUpgrade upgrade) { upgrade.cardName = TextTranslator.GetTextTranslation(UpgradeTitles, upgrade.cardName); upgrade.description = TextTranslator.GetTextTranslation(UpgradeDescriptions, upgrade.description); upgrade.unlockDesc = TextTranslator.GetTextTranslation(UpgradeUnlockDescriptions, upgrade.unlockDesc); } } [ConfigSection("Modules.FacilityUpgradePatch", "This module replaces texts of facility upgrades.")] public class FacilityUpgradePatchSettings : ModuleSettingsBase { } [HarmonyPatch] public class FontAssetPatch : ModuleBase { [JsonProperty] public static FontAssetPatchSettings ModuleSettings; [JsonProperty] public static Dictionary> CustomFontAssets; [JsonProperty] public static string CharactersToRender; [JsonIgnore] public static ValueCollection FallbackFontAssets = new ValueCollection(); [OnDeserialized] private void OnDeserialized(StreamingContext _) { if (!ModuleBase.IsEnabled) { return; } foreach (KeyValuePair> customFontAsset in CustomFontAssets) { string key = customFontAsset.Key; List value = customFontAsset.Value; foreach (FontAssetProperties item in value) { CreateAndRegisterFallbackFontAsset(key, item); } } } [HarmonyPostfix] [HarmonyPatch(typeof(TMP_FontAsset), "Awake")] public static void Postfix_FontAsset_Awake(TMP_FontAsset __instance) { if (ModuleBase.IsEnabled) { AddFallbackFontAssets(__instance); } } public static void AddFallbackFontAssets(TMP_FontAsset __instance) { if (TryGetFallbackFontAssets(((Object)__instance).name, out var fallbackFontAssets)) { if (ModuleSettings.HighFallbackPriority) { __instance.fallbackFontAssetTable = fallbackFontAssets.Union(__instance.fallbackFontAssetTable).ToList(); } else { __instance.fallbackFontAssetTable = __instance.fallbackFontAssetTable.Union(fallbackFontAssets).ToList(); } } } public static void CreateAndRegisterFallbackFontAsset(string targetFontName, FontAssetProperties fallbackFontAssetProperties) { if (ResourceLoader.TryGetOrCreateFontAsset(CharactersToRender, fallbackFontAssetProperties, out var fontAsset, ModuleSettings.SaveFontAssetCacheOnDisk)) { RegisterFallbackFontAsset(targetFontName, fontAsset); } } public static void RegisterFallbackFontAsset(string targetFontName, TMP_FontAsset fallbackFontAsset) { FallbackFontAssets?.Add(targetFontName, fallbackFontAsset); } public static bool TryGetFallbackFontAssets(string targetFontName, out List fallbackFontAssets) { if (FallbackFontAssets != null && FallbackFontAssets.TryGetValues(targetFontName, out fallbackFontAssets)) { return true; } fallbackFontAssets = null; return false; } } [ConfigSection("Modules.FontAssetPatch", "This module adds fallback font assets.")] public class FontAssetPatchSettings : ModuleSettingsBase { [ConfigEntry("HighFallbackPriority", true, "Set this field to \"false\" to\nlower fallback priority of custom fallback font assets.")] public bool HighFallbackPriority; [ConfigEntry("SaveFontAssetCacheOnDisk", false, "Set this field to \"true\" to cache generated TMP_FontAsset\non disk to reduce load times on subsequent game launches.\nWarning: Cache size may grow significantly --\nA 4096×4096 atlas alone is about 16MB.\nEnable this only if you have spare disk space.\nCache files are stored in the same directory as plugin .dll.")] public bool SaveFontAssetCacheOnDisk; } [HarmonyPriority(0)] [HarmonyPatch] public class FontPatch : ModuleBase { [JsonProperty] public static FontPatchSettings ModuleSettings; [JsonProperty] public static Dictionary CustomFonts; [JsonProperty] public static string CharactersToRender; [JsonIgnore] public static Dictionary SubstituteFonts = new Dictionary(); [OnDeserialized] private void OnDeserialized(StreamingContext _) { if (!ModuleBase.IsEnabled) { return; } foreach (KeyValuePair customFont in CustomFonts) { string key = customFont.Key; FontProperties value = customFont.Value; CreateAndRegisterSubstituteFont(key, value); } } [HarmonyPostfix] [HarmonyPatch(typeof(Text), "OnEnable")] public static void Postfix_Text_OnEnable(Text __instance) { if (ModuleBase.IsEnabled) { ReplaceFont(__instance); } } public static void ReplaceFont(Text __instance) { Font font = __instance.font; string targetFontName = ((font != null) ? ((Object)font).name : null); if (TryGetSubstituteFont(targetFontName, out var substituteFont)) { __instance.font = substituteFont; } } public static void CreateAndRegisterSubstituteFont(string targetFontName, FontProperties substituteFontProperties) { if (ResourceLoader.TryGetOrCreateFont(CharactersToRender, substituteFontProperties, out var font, ModuleSettings.SaveFontCacheOnDisk)) { RegisterSubstituteFont(targetFontName, font); } } public static void RegisterSubstituteFont(string targetFontName, Font substituteFont) { if (SubstituteFonts == null) { SubstituteFonts = new Dictionary(); } if (targetFontName != null && substituteFont != null) { SubstituteFonts[targetFontName] = substituteFont; } } public static bool TryGetSubstituteFont(string targetFontName, out Font substituteFont) { if (targetFontName == null || SubstituteFonts == null || !SubstituteFonts.TryGetValue(targetFontName, out substituteFont) || substituteFont == null) { substituteFont = null; return false; } return true; } } [ConfigSection("Modules.FontPatch", "This module replaces font of Text class instances.")] public class FontPatchSettings : ModuleSettingsBase { [ConfigEntry("SaveFontCacheOnDisk", false, "Set this field to \"true\" to cache generated Font\non disk to reduce load times on subsequent game launches.\nWarning: Cache size may grow significantly --\nA 4096×4096 atlas alone is about 16MB.\nEnable this only if you have spare disk space.\nCache files are stored in the same directory as plugin .dll.")] public bool SaveFontCacheOnDisk; } [HarmonyPatch] public class GamemodePatch : TextTranslator, IScriptableObjectPatch { [JsonProperty] public static Dictionary CapsuleNames; [JsonProperty] public static Dictionary GamemodeUnlockHints; [JsonProperty] public static Dictionary GamemodeDescriptions; [JsonProperty] public static Dictionary NewGameTexts; [JsonProperty] public static Dictionary GamemodeIntroTexts; [JsonProperty] public static Dictionary GamemodeTextPrefixes; [JsonProperty] public static Dictionary ModifierTitles; [JsonProperty] public static Dictionary ModifierDescriptions; [JsonProperty] public static Dictionary ModifierAppends; [JsonProperty] public static bool KeepWhiteSpaceInGamemodeName; [JsonProperty] public static string GamemodeTextTemplate; [JsonProperty] public static string ModifierConflictedDescription; [JsonProperty] public static string ModifierLockedDescriptionTemplate; [JsonProperty] public static string ModifierUnlockProgressTemplate; [JsonIgnore] public static Regex WhiteSpaceRegex = CacheManager.GetOrCreateRegex("\\s+|", RegexOptions.IgnoreCase); [JsonIgnore] public static GamemodePatchSettings ModuleSettings; public static void PatchScriptableObjects() { if (ModuleBase.IsEnabled) { PatchGamemodes(); PatchGamemodeSettings(); } } public static void PatchGamemodes() { IEnumerable enumerable = CacheManager.EnumerateScriptableObjects(); foreach (M_Gamemode item in enumerable) { item.unlockHint = TextTranslator.GetTextTranslation(GamemodeUnlockHints, item.unlockHint); item.modeDescription = TextTranslator.GetTextTranslation(GamemodeDescriptions, item.modeDescription); item.newGameText = TextTranslator.GetTextTranslation(NewGameTexts, item.newGameText); item.introText = TextTranslator.GetTextTranslation(GamemodeIntroTexts, item.introText); } } public static void PatchGamemodeSettings() { IEnumerable enumerable = CacheManager.EnumerateScriptableObjects(); foreach (GamemodeSetting item in enumerable) { item.title = TextTranslator.GetTextTranslation(ModifierTitles, item.title); item.description = TextTranslator.GetTextTranslation(ModifierDescriptions, item.description); } } [HarmonyPostfix] [HarmonyPatch(typeof(UI_Gamemode_Button), "Initialize")] public static void Postfix_GamemodeButton_Initialize(UI_Gamemode_Button __instance) { if (ModuleBase.IsEnabled && __instance.gamemode != null && CapsuleNames != null && CapsuleNames.TryGetValue(__instance.gamemode.gamemodeName, out var value) && value != null) { __instance.title.text = value; } } [HarmonyPostfix] [HarmonyPatch(typeof(UI_GamemodeText), "Refresh")] public static void Postfix_GamemodeText_Refresh(UI_GamemodeText __instance) { if (ModuleBase.IsEnabled && CL_GameManager.gamemode != null) { __instance.text.text = GetTranslatedGamemodeText(CL_GameManager.gamemode, __instance.text.text); } } [HarmonyPostfix] [HarmonyPatch(typeof(UI_LeaderboardEntryDetailWindow), "ShowDetails")] public static void Postfix_LeaderboardEntryWindow_ShowDetails(UI_LeaderboardEntryDetailWindow __instance) { if (ModuleBase.IsEnabled) { __instance.gamemodeText.text = GetTranslatedGamemodeText(CL_GameManager.GetBaseGamemode(), __instance.gamemodeText.text); } } [HarmonyPostfix] [HarmonyPatch(typeof(UI_LeaderboardEntryDetailWindow), "ShowNoEntryDetails")] public static void Postfix_LeaderboardEntryWindow_ShowNoEntryDetails(UI_LeaderboardEntryDetailWindow __instance) { if (ModuleBase.IsEnabled) { __instance.gamemodeText.text = GetTranslatedGamemodeText(CL_GameManager.GetBaseGamemode(), __instance.gamemodeText.text); } } [HarmonyPostfix] [HarmonyPatch(typeof(UI_GamemodeSetting), "UpdateColor")] public static void Postfix_GamemodeSettingUI_UpdateColor(UI_GamemodeSetting __instance) { if (!ModuleBase.IsEnabled) { return; } string text = __instance.descriptionText.text; if (text == "LOCKED") { __instance.descriptionText.text = ModifierConflictedDescription ?? "LOCKED"; return; } ProgressionUnlock unlock = __instance.gamemodeSetting.unlock; if (!unlock.CheckUnlock()) { string newValue = (unlock.showProgression ? GetTranslatedProgress(unlock) : ""); string text2 = ModifierLockedDescriptionTemplate ?? "{unlockHint}{progress}"; __instance.descriptionText.text = text2.Replace("{unlockHint}", unlock.unlockHint).Replace("{progress}", newValue); } } public static string GetTranslatedGamemodeText(M_Gamemode gamemode, string gamemodeText) { string text = gamemode.gamemodeName; string[] array = gamemodeText.Split(new string[1] { text }, 2, StringSplitOptions.None); if (array.Length != 2) { return gamemodeText; } string originalText = array[0]; string text2 = array[1]; originalText = TextTranslator.GetTextTranslation(GamemodeTextPrefixes, originalText); if (CapsuleNames != null && CapsuleNames.TryGetValue(text, out var value) && value != null) { text = WhiteSpaceRegex.Replace(value, KeepWhiteSpaceInGamemodeName ? " " : ""); } if (text2 != null && ModifierAppends != null) { foreach (KeyValuePair modifierAppend in ModifierAppends) { string key = modifierAppend.Key; string value2 = modifierAppend.Value; if (key != null && value2 != null) { text2 = text2.Replace(key, value2); } } } string text3 = GamemodeTextTemplate ?? "{prefix}{gamemodeName}{modifierAppends}"; return text3.Replace("{prefix}", originalText).Replace("{gamemodeName}", text).Replace("{modifierAppends}", text2); } public static string GetTranslatedProgress(ProgressionUnlock unlock) { string text = unlock.GetProgressString(); if (text != "N/A" && ModifierUnlockProgressTemplate != null) { string[] array = text.Split(new char[1] { '/' }, 2); if (array.Length == 2) { string newValue = array[0]; string newValue2 = array[1]; text = ModifierUnlockProgressTemplate.Replace("{current}", newValue).Replace("{required}", newValue2); } } return text; } } [ConfigSection("Modules.GamemodePatch", "This module replaces texts for gamemodes and gamemode settings.")] public class GamemodePatchSettings : ModuleSettingsBase { } [HarmonyPatch] public class GameplayTextPatch : TextTranslator { [JsonProperty] public static Dictionary RoachCounterTemplates; [JsonProperty] public static Dictionary BadgeTitles; [JsonProperty] public static string ScoreTrackerTemplate; [JsonProperty] public static string DistanceTrackerTemplate; [JsonProperty] public static string SpeedTrackerTemplate; [JsonProperty] public static string HighScoreTrackerTemplate; [JsonProperty] public static string ForlornGatewayDoorPoweredText; [JsonProperty] public static string VendorUnavailableText; [JsonProperty] public static string VendorCostTemplate; [JsonProperty] public static string VendorPurchasedText; [JsonIgnore] public static GameplayTextPatchSettings ModuleSettings; [HarmonyPostfix] [HarmonyPatch(typeof(CL_GameManager), "Update")] public static void Postfix_GameManager_Update(CL_GameManager __instance) { if (!ModuleBase.IsEnabled || CL_GameManager.runHasEnded) { return; } CL_UIManager uiMan = __instance.uiMan; if (uiMan != null && uiMan.scoreTracker != null) { string text = uiMan.scoreTracker.text; if (text.StartsWith("Score: ") && ScoreTrackerTemplate != null) { string newValue = text.Substring(7); uiMan.scoreTracker.text = ScoreTrackerTemplate.Replace("{score}", newValue); } string text2 = uiMan.ascentTracker.text; if (text2.StartsWith("Climb Distance: ") && DistanceTrackerTemplate != null) { string newValue2 = text2.Substring(16); uiMan.ascentTracker.text = DistanceTrackerTemplate.Replace("{distance}", newValue2); } string text3 = uiMan.ascentRateTracker.text; if (text3.StartsWith("Climb Speed: ") && SpeedTrackerTemplate != null) { string newValue3 = text3.Substring(13); uiMan.ascentRateTracker.text = SpeedTrackerTemplate.Replace("{speed}", newValue3); } string text4 = uiMan.highScoreTracker.text; if (text4.StartsWith("High Score: ") && HighScoreTrackerTemplate != null) { string newValue4 = text4.Substring(12); uiMan.highScoreTracker.text = HighScoreTrackerTemplate.Replace("{highScore}", newValue4); } } } [HarmonyPostfix] [HarmonyPatch(typeof(UT_CheckFlag), "CheckFlag")] public static void Postfix_CheckFlag_CheckFlag(UT_CheckFlag __instance) { if (!ModuleBase.IsEnabled || ForlornGatewayDoorPoweredText == null) { return; } string flagName = __instance.flagName; if (flagName != "habentrywaypowered" && flagName != "habentryunlocked") { return; } SessionFlag gameFlag = CL_GameManager.GetGameFlag(flagName); if (gameFlag == null || !gameFlag.state) { return; } TMP_Text[] componentsInChildren = ((Component)((Component)__instance).transform.parent).GetComponentsInChildren(); if (componentsInChildren == null || componentsInChildren.Length == 0) { return; } foreach (TMP_Text val in componentsInChildren) { if (val.text == "POWERED") { val.text = ForlornGatewayDoorPoweredText; break; } } } [HarmonyPrefix] [HarmonyPatch(typeof(UT_RoachTextCounter), "UpdateText")] public static void Prefix_RoachTextCounter_UpdateText(UT_RoachTextCounter __instance) { if (ModuleBase.IsEnabled) { __instance.textFormat = TextTranslator.GetTextTranslation(RoachCounterTemplates, __instance.textFormat); } } [HarmonyPrefix] [HarmonyPatch(typeof(UI_Badge), "ShowBadge")] public static void Prefix_Badge_ShowBadge(Sprite sprite, ref string title) { if (ModuleBase.IsEnabled) { title = TextTranslator.GetTextTranslation(BadgeTitles, title); } } [HarmonyPrefix] [HarmonyPatch(typeof(ENV_Vendor_Disk), "CheckBlock")] public static void Prefix_DiskVendor_CheckBlock(ENV_Vendor_Disk __instance) { if (ModuleBase.IsEnabled && VendorUnavailableText != null && !__instance.isBlocked && !__instance.hasBeenBought && CL_GameManager.HasActiveFlag("blockshops", false)) { __instance.isBlocked = true; __instance.purchaseButton.SetInteractable(false); __instance.costText.text = VendorUnavailableText; } } [HarmonyPrefix] [HarmonyPatch(typeof(ENV_Vendor_Disk), "CheckRoaches")] public static void Prefix_DiskVendor_CheckRoaches(ENV_Vendor_Disk __instance) { if (ModuleBase.IsEnabled && VendorPurchasedText != null && __instance.allowPurchases && !__instance.isBlocked && !__instance.hasBeenBought && !(__instance.id == "")) { SessionFlag gameFlag = CL_GameManager.GetGameFlag("boughtdisk-" + __instance.id + "-station"); if (gameFlag != null && gameFlag.state) { __instance.hasBeenBought = true; __instance.costText.text = VendorPurchasedText; ((Component)__instance.purchaseSprite).gameObject.SetActive(false); } } } [HarmonyPostfix] [HarmonyPatch(typeof(ENV_Vendor_Disk), "CheckRoaches")] public static void Postfix_DiskVendor_CheckRoaches(ENV_Vendor_Disk __instance) { if (ModuleBase.IsEnabled && VendorCostTemplate != null && __instance.allowPurchases && !__instance.isBlocked && !__instance.hasBeenBought) { int cost = __instance.cost; int roaches = CL_GameManager.GetRoaches(false); __instance.costText.text = VendorCostTemplate.Replace("{cost}", cost.ToString()).Replace("{balance}", roaches.ToString()); } } [HarmonyPostfix] [HarmonyPatch(typeof(ENV_Vendor_Disk), "Purchase")] public static void Postfix_DiskVendor_Purchase(ENV_Vendor_Disk __instance) { if (ModuleBase.IsEnabled && !__instance.isBlocked && !((Component)__instance.purchaseSprite).gameObject.activeInHierarchy && VendorPurchasedText != null) { __instance.costText.text = VendorPurchasedText; } } [HarmonyPrefix] [HarmonyPatch(typeof(ENV_Vendor_Event), "CheckRoaches")] public static void Prefix_EventVendor_CheckRoaches(ENV_Vendor_Event __instance) { if (ModuleBase.IsEnabled && VendorPurchasedText != null && __instance.allowPurchases && !__instance.hasBeenBought && !(__instance.id == "")) { SessionFlag gameFlag = CL_GameManager.GetGameFlag("boughtdisk-" + __instance.id + "-station"); if (gameFlag != null && gameFlag.state) { __instance.hasBeenBought = true; __instance.costText.text = VendorPurchasedText; ((Component)__instance.purchaseSprite).gameObject.SetActive(false); } } } [HarmonyPostfix] [HarmonyPatch(typeof(ENV_Vendor_Event), "CheckRoaches")] public static void Postfix_EventVendor_CheckRoaches(ENV_Vendor_Event __instance) { if (ModuleBase.IsEnabled && VendorCostTemplate != null && __instance.allowPurchases && !__instance.hasBeenBought) { int cost = __instance.cost; int roaches = CL_GameManager.GetRoaches(false); __instance.costText.text = VendorCostTemplate.Replace("{cost}", cost.ToString()).Replace("{balance}", roaches.ToString()); } } [HarmonyPostfix] [HarmonyPatch(typeof(ENV_Vendor_Event), "Purchase")] public static void Postfix_EventVendor_Purchase(ENV_Vendor_Event __instance) { if (ModuleBase.IsEnabled && !((Component)__instance.purchaseSprite).gameObject.activeInHierarchy && VendorPurchasedText != null) { __instance.costText.text = VendorPurchasedText; } } } [ConfigSection("Modules.GameplayTextPatch", "This module replaces texts of\nroach counters, vendors and stat trackers.")] public class GameplayTextPatchSettings : ModuleSettingsBase { } public interface IScriptableObjectPatch { } [HarmonyPatch] public class ItemDescriptionPatch : ModuleBase { [JsonProperty] public static Dictionary ItemDescriptions; [JsonIgnore] public static ItemDescriptionPatchSettings ModuleSettings; [HarmonyPostfix] [HarmonyPatch(typeof(Localization), "GetLine")] public static string Postfix_Localization_GetLine(string __result, string group, string key) { if (!ModuleBase.IsEnabled || group != "items" || ItemDescriptions == null || !ItemDescriptions.ContainsKey(key)) { return __result; } return ItemDescriptions[key] ?? __result; } } [ConfigSection("Modules.ItemDescriptionPatch", "This module replaces item description texts.")] public class ItemDescriptionPatchSettings : ModuleSettingsBase { } [HarmonyPatch] public class LocationNamePatch : TextTranslator, IScriptableObjectPatch { [JsonProperty] public static Dictionary RegionIntroTexts; [JsonProperty] public static Dictionary SubregionIntroTexts; [JsonProperty] public static Dictionary LevelIntroTexts; [JsonProperty] public static Dictionary LevelSaveNames; [JsonProperty] public static string ContinueTextTemplate; [JsonIgnore] public static LocationNamePatchSettings ModuleSettings; public static void PatchScriptableObjects() { if (ModuleBase.IsEnabled) { PatchRegions(); PatchSubregions(); } } public static void PatchRegions() { IEnumerable enumerable = CacheManager.EnumerateScriptableObjects(); foreach (M_Region item in enumerable) { item.introText = TextTranslator.GetTextTranslation(RegionIntroTexts, item.introText); } } public static void PatchSubregions() { IEnumerable enumerable = CacheManager.EnumerateScriptableObjects(); foreach (M_Subregion item in enumerable) { item.introText = TextTranslator.GetTextTranslation(SubregionIntroTexts, item.introText); } } [HarmonyPostfix] [HarmonyPatch(typeof(UT_ZoneTitler), "Start")] public static void Postfix_ZoneTitler_Start(UT_ZoneTitler __instance) { if (ModuleBase.IsEnabled) { __instance.region = TextTranslator.GetTextTranslation(RegionIntroTexts, __instance.region); __instance.subRegion = TextTranslator.GetTextTranslation(SubregionIntroTexts, __instance.subRegion); } } [HarmonyPostfix] [HarmonyPatch(typeof(M_Level), "Awake")] public static void Postfix_Level_Awake(M_Level __instance) { if (ModuleBase.IsEnabled) { __instance.introText = TextTranslator.GetTextTranslation(LevelIntroTexts, __instance.introText); } } [HarmonyPostfix] [HarmonyPatch(typeof(UI_GamemodeScreen), "RefreshCurrentGamemode")] public static void Postfix_GamemodeScreen_RefreshCurrentGamemode(UI_GamemodeScreen __instance) { if (ModuleBase.IsEnabled) { string text = __instance.currentPanel.continueButtonText.text; if (CL_SaveManager.SessionFileExists(__instance.baseGamemode.gamemodeName, CL_GameManager.IsHardmode()) && !CL_GameManager.gamemode.IsCompetitive() && !CL_GameManager.GetBaseGamemode().IsCompetitive() && text.StartsWith("Continue: ")) { string originalText = text.Substring(10); originalText = TextTranslator.GetTextTranslation(LevelSaveNames, originalText); string text2 = ContinueTextTemplate ?? "Continue: {saveName}"; __instance.currentPanel.continueButtonText.text = text2.Replace("{saveName}", originalText); } } } } [ConfigSection("Modules.LocationNamePatch", "This module replaces location intro texts and level save names.")] public class LocationNamePatchSettings : ModuleSettingsBase { } [HarmonyPatch] public class MainMenuPatch : TextTranslator { [JsonProperty] public static Dictionary PageTitles; [JsonProperty] public static string LoadingProgressTemplate; [JsonProperty] public static string PageCounterTemplate; [JsonIgnore] public static MainMenuPatchSettings ModuleSettings; [HarmonyPrefix] [HarmonyPatch(typeof(UT_Intro), "EndIntro")] public static bool Prefix_Intro_EndIntro(UT_Intro __instance) { if (!ModuleBase.IsEnabled || LoadingProgressTemplate == null) { return true; } __instance.video.Stop(); __instance.hasSkipped = true; TMP_Text loadPercentageText = __instance.loadPercentageText; ((Component)loadPercentageText.transform.parent).gameObject.SetActive(true); loadPercentageText.text = LoadingProgressTemplate.Replace("{progress}", "0"); ((MonoBehaviour)__instance).StartCoroutine(CustomLoadingIntro(__instance)); return false; } [HarmonyPostfix] [HarmonyPatch(typeof(UI_PageHolder), "UpdatePage")] public static void Postfix_PageHolder_UpdatePage(UI_PageHolder __instance) { if (!ModuleBase.IsEnabled) { return; } TMP_Text pageTitle = __instance.pageTitle; if (pageTitle != null) { List pages = __instance.pages; int count = pages.Count; if (count != 0) { string textTranslation = TextTranslator.GetTextTranslation(PageTitles, pages[__instance.currentPage].title); int num = __instance.currentPage + 1; string text = PageCounterTemplate ?? "{title} ({current}/{total})"; pageTitle.text = text.Replace("{title}", textTranslation).Replace("{current}", num.ToString()).Replace("{total}", count.ToString()); } } } public static IEnumerator CustomLoadingIntro(UT_Intro intro) { yield return (object)new WaitForSeconds(0.1f); UnityEvent onEnd = intro.onEnd; if (onEnd != null) { onEnd.Invoke(); } yield return (object)new WaitForSeconds(0.1f); while (true) { UpdateLoadingProgressText(); yield return null; yield return null; if (intro.loadMenuOperation != null && !((double)intro.loadMenuOperation.progress < 0.89)) { intro.loadMenuOperation.allowSceneActivation = true; if (intro.loadMenuOperation.isDone) { break; } } } UpdateLoadingProgressText(); intro.loadMenuOperation.allowSceneActivation = true; void UpdateLoadingProgressText() { if (intro.loadMenuOperation != null) { string newValue = Mathf.RoundToInt(intro.loadMenuOperation.progress * 100f).ToString(); intro.loadPercentageText.text = LoadingProgressTemplate.Replace("{progress}", newValue); } } } } [ConfigSection("Modules.MainMenuPatch", "This module replaces texts of loading intro and menu pages.")] public class MainMenuPatchSettings : ModuleSettingsBase { } public abstract class ModuleBase { [JsonIgnore] public static bool IsEnabled; public ModuleBase() { FieldInfo field = GetType().GetField("ModuleSettings", BindingFlags.Static | BindingFlags.Public); if ((object)field != null) { ConfigSectionAttribute customAttribute = field.FieldType.GetCustomAttribute(); if (customAttribute != null) { customAttribute.Deconstruct(out var section, out var moduleDescription); string section2 = section; string moduleDescription2 = moduleDescription; IsEnabled = ConfigManager.IsModuleEnabled(section2, moduleDescription2); } if (IsEnabled && field.GetValue(this) == null) { object value = Activator.CreateInstance(field.FieldType); field.SetValue(this, value); } } } } public class ModuleSettingsBase { public ModuleSettingsBase() { Type type = GetType(); ConfigSectionAttribute customAttribute = type.GetCustomAttribute(); FieldInfo[] fields = type.GetFields(); foreach (FieldInfo fieldInfo in fields) { ConfigEntryAttribute customAttribute2 = fieldInfo.GetCustomAttribute(); PopulateModuleSettingsField(this, fieldInfo, customAttribute, customAttribute2); } } private void PopulateModuleSettingsField(ModuleSettingsBase moduleSettings, FieldInfo field, ConfigSectionAttribute configSectionAttribute, ConfigEntryAttribute configEntryAttribute) { if (field.GetValue(moduleSettings) == null || configEntryAttribute != null) { field.SetValue(moduleSettings, configEntryAttribute.DefaultValue); if (configSectionAttribute != null) { configSectionAttribute.Deconstruct(out var section, out var moduleDescription); string section2 = section; string moduleDescription2 = moduleDescription; configEntryAttribute.Deconstruct(out moduleDescription, out var defaultValue, out section); string key = moduleDescription; object defaultValue2 = defaultValue; string entryDescription = section; object configEntryValue = ConfigManager.GetConfigEntryValue(section2, moduleDescription2, key, defaultValue2, entryDescription); field.SetValue(moduleSettings, configEntryValue); } } } } [HarmonyPatch] public class MotherSubtitlePatch : ModuleBase { [JsonProperty] public static string RandomCharacters; [JsonProperty] public static string NonRandomCharacters; [JsonProperty] public static Dictionary MotherSubtitles; [JsonIgnore] public static MotherSubtitlePatchSettings ModuleSettings; [HarmonyPostfix] [HarmonyPatch(typeof(Localization), "GetLine")] public static string Postfix_GetLine(string __result, string group, string key) { if (!ModuleBase.IsEnabled || group != "mother" || MotherSubtitles == null || !MotherSubtitles.ContainsKey(key)) { return __result; } return MotherSubtitles[key] ?? __result; } [HarmonyTranspiler] [HarmonyPatch(typeof(HUD_CustomElement_PsychicCommunication), "PlaySubtitle")] public static IEnumerable Transpiler_PlaySubtitle(IEnumerable codeInstructions) { //IL_0003: Unknown result type (might be due to invalid IL or missing references) //IL_0009: Expected O, but got Unknown //IL_0033: Unknown result type (might be due to invalid IL or missing references) //IL_0039: Expected O, but got Unknown //IL_0092: Unknown result type (might be due to invalid IL or missing references) //IL_0098: Expected O, but got Unknown //IL_00dd: Unknown result type (might be due to invalid IL or missing references) //IL_00e3: Expected O, but got Unknown //IL_00eb: Unknown result type (might be due to invalid IL or missing references) //IL_00f1: Expected O, but got Unknown //IL_00f9: Unknown result type (might be due to invalid IL or missing references) //IL_00ff: Expected O, but got Unknown CodeMatcher val = new CodeMatcher(codeInstructions, (ILGenerator)null); val.MatchForward(false, (CodeMatch[])(object)new CodeMatch[1] { new CodeMatch((Func)((CodeInstruction i) => i.opcode == OpCodes.Stfld && i.operand is FieldInfo fieldInfo2 && fieldInfo2.Name == "rand"), (string)null) }); if (!val.IsValid) { return codeInstructions; } FieldInfo fieldInfo = (FieldInfo)val.Instruction.operand; FieldInfo field = fieldInfo.DeclaringType.GetField("startString"); val.MatchBack(false, (CodeMatch[])(object)new CodeMatch[1] { new CodeMatch((OpCode?)OpCodes.Ldstr, (object)"abcdefghijklmnopqrstuvwxyz", (string)null) }); if (!val.IsValid) { return codeInstructions; } MethodInfo method = typeof(MotherSubtitlePatch).GetMethod("GetRandomCharacters"); val.RemoveInstruction(); val.Insert((CodeInstruction[])(object)new CodeInstruction[3] { new CodeInstruction(OpCodes.Dup, (object)null), new CodeInstruction(OpCodes.Ldfld, (object)field), new CodeInstruction(OpCodes.Call, (object)method) }); return val.InstructionEnumeration(); } public static string GetRandomCharacters(string startString) { if (!ModuleBase.IsEnabled || string.IsNullOrWhiteSpace(startString)) { return "abcdefghijklmnopqrstuvwxyz"; } string text = (string.IsNullOrEmpty(RandomCharacters) ? new string(startString.Distinct().ToArray()) : RandomCharacters); text = text.ToLower(); if (!string.IsNullOrEmpty(NonRandomCharacters)) { NonRandomCharacters = NonRandomCharacters.ToLower(); text = new string(text.Where((char c) => !Enumerable.Contains(NonRandomCharacters, c)).ToArray()); } return text; } } [ConfigSection("Modules.MotherSubtitlePatch", "This module replaces Mother subtitle texts.")] public class MotherSubtitlePatchSettings : ModuleSettingsBase { } [HarmonyPatch] public class NotePatch : TextTranslator { [JsonProperty] public static Dictionary NoteTexts; [JsonIgnore] public static Dictionary TrimmedNoteTexts; [JsonIgnore] public static NotePatchSettings ModuleSettings; [OnDeserialized] private void OnDeserialized(StreamingContext _) { TrimmedNoteTexts = NoteTexts.ToDictionary((KeyValuePair t) => t.Key.TrimStart(Array.Empty()), (KeyValuePair t) => t.Value); } [HarmonyPostfix] [HarmonyPatch(typeof(HandItem_Note), "Initialize")] public static void Postfix_HandItemNote_Initialize(HandItem_Note __instance) { if (ModuleBase.IsEnabled) { __instance.text.text = TextTranslator.GetTextTranslation(TrimmedNoteTexts, __instance.text.text); } } } [ConfigSection("Modules.NotePatch", "This module replaces texts for paper notes.")] public class NotePatchSettings : ModuleSettingsBase { } [HarmonyPatch] public class ObjectivePatch : TemplateTranslator { [JsonProperty] public static Dictionary ObjectiveViewerTitleTemplates; [JsonProperty] public static Dictionary ObjectiveTitleTemplates; [JsonProperty] public static Dictionary ObjectiveDescriptionTemplates; [JsonProperty] public static Dictionary ObjectiveProgressHeaderTemplates; [JsonProperty] public static Dictionary ObjectiveSuccessHeaders; [JsonIgnore] public static TemplateTranslations ViewerTitleTemplates; [JsonIgnore] public static TemplateTranslations TitleTemplates; [JsonIgnore] public static TemplateTranslations DescriptionTemplates; [JsonIgnore] public static ObjectivePatchSettings ModuleSettings; [OnDeserialized] private void OnDeserialized(StreamingContext _) { if (ModuleBase.IsEnabled) { ViewerTitleTemplates = new TemplateTranslations(ObjectiveViewerTitleTemplates); TitleTemplates = new TemplateTranslations(ObjectiveTitleTemplates); DescriptionTemplates = new TemplateTranslations(ObjectiveDescriptionTemplates); } } [HarmonyPostfix] [HarmonyPatch(typeof(UI_ObjectiveViewer), "Awake")] public static void Postfix_ObjectiveViewer_Awake(UI_ObjectiveViewer __instance) { if (ModuleBase.IsEnabled) { __instance.objectiveViewerTitle.text = TemplateTranslator.GetTemplateTranslation(ViewerTitleTemplates, __instance.objectiveViewerTitle.text); } } [HarmonyPrefix] [HarmonyPatch(typeof(UI_ObjectiveViewer), "SetTitle")] public static void Prefix_ObjectiveViewer_SetTitle(ref string s) { if (ModuleBase.IsEnabled) { s = TemplateTranslator.GetTemplateTranslation(ViewerTitleTemplates, s); } } [HarmonyPrefix] [HarmonyPatch(typeof(UI_ObjectiveViewer), "CreateOrUpdateObjective")] public static void Prefix_ObjectiveViewer_CreateOrUpdateObjective(string id, ref string title, ref string desc) { if (ModuleBase.IsEnabled) { title = TemplateTranslator.GetTemplateTranslation(TitleTemplates, title); desc = TemplateTranslator.GetTemplateTranslation(DescriptionTemplates, desc); } } [HarmonyPrefix] [HarmonyPatch(typeof(CH_ChallengeCounter), "Start")] public static void Prefix_ChallengeCounter_Start(CH_ChallengeCounter __instance) { if (!ModuleBase.IsEnabled) { return; } foreach (ObjectiveCounter objective in __instance.objectives) { objective.objectiveTitle = TemplateTranslator.GetTemplateTranslation(TitleTemplates, objective.objectiveTitle); objective.objectiveDesc = TemplateTranslator.GetTemplateTranslation(DescriptionTemplates, objective.objectiveDesc); objective.progressHeaderDesc = TextTranslator.GetTextTranslation(ObjectiveProgressHeaderTemplates, objective.progressHeaderDesc); objective.finishedHeaderDesc = TextTranslator.GetTextTranslation(ObjectiveSuccessHeaders, objective.finishedHeaderDesc); } } [HarmonyPostfix] [HarmonyPatch(typeof(CH_RoachCollector), "Start")] public static void Postfix_RoachCollector_Start(CH_RoachCollector __instance) { if (ModuleBase.IsEnabled) { __instance.successText = TextTranslator.GetTextTranslation(ObjectiveSuccessHeaders, __instance.successText); } } } [ConfigSection("Modules.ObjectivePatch", "This module replaces text information of objectives.")] public class ObjectivePatchSettings : ModuleSettingsBase { } [HarmonyPatch] public class PerkPatch : TextTranslator, IScriptableObjectPatch { [JsonProperty] public static Dictionary PerkTitles; [JsonProperty] public static Dictionary PerkDescriptions; [JsonProperty] public static Dictionary PerkFlavorTexts; [JsonProperty] public static Dictionary DurationRoughTexts; [JsonProperty] public static string DurationSecondTemplate; [JsonProperty] public static string DurationSecondsTemplate; [JsonProperty] public static string AppPerkHoverTextTemplate; [JsonProperty] public static string AppPerkAmountTemplate; [JsonProperty] public static string AppRefreshPurchasedText; [JsonIgnore] public static readonly Regex SecondsFormatRegex = CacheManager.GetOrCreateRegex("\\{.*?\\^s.*?\\}", RegexOptions.Compiled); [JsonIgnore] public static readonly Regex SecondsRegex = CacheManager.GetOrCreateRegex("([+-]?\\d+(?:\\.\\d+)?) Seconds?", RegexOptions.Compiled); [JsonIgnore] public static PerkPatchSettings ModuleSettings; public static void PatchScriptableObjects() { if (ModuleBase.IsEnabled) { PatchPerks(); } } public static void PatchPerks() { IEnumerable enumerable = CacheManager.EnumerateScriptableObjects(); foreach (Perk item in enumerable) { item.title = TextTranslator.GetTextTranslation(PerkTitles, item.title); item.description = TextTranslator.GetTextTranslation(PerkDescriptions, item.description); item.flavorText = TextTranslator.GetTextTranslation(PerkFlavorTexts, item.flavorText); } } [HarmonyPostfix] [HarmonyPatch(typeof(Perk), "GetTitle")] public static string Postfix_Perk_GetTitle(string __result, Perk __instance) { //IL_0009: Unknown result type (might be due to invalid IL or missing references) //IL_000f: Invalid comparison between Unknown and I4 //IL_0012: Unknown result type (might be due to invalid IL or missing references) //IL_0019: Invalid comparison between Unknown and I4 if (!ModuleBase.IsEnabled || ((int)__instance.perkType != 8 && (int)__instance.perkType != 9)) { return __result; } string translatedTrinketType = GetTranslatedTrinketType(__instance); string trinketPerkTitle = GetTrinketPerkTitle(__instance); return translatedTrinketType + "\n" + trinketPerkTitle + ""; } [HarmonyPostfix] [HarmonyPatch(typeof(Perk), "GetDescription")] public static string Postfix_Perk_GetDescription(string __result, Perk __instance) { if (!ModuleBase.IsEnabled || !SecondsFormatRegex.IsMatch(__instance.description)) { return __result; } return SecondsRegex.Replace(__result, delegate(Match m) { string value = m.Groups[1].Value; string text = ((value == "1") ? (DurationSecondTemplate ?? "{time} Second") : (DurationSecondsTemplate ?? "{time} Seconds")); return text.Replace("{time}", value); }); } [HarmonyPostfix] [HarmonyPatch(typeof(PerkModule_RemovalTimer), "GetCounterString")] public static string Postfix_RemovalTimerModule_GetCounterString(string __result, PerkModule_RemovalTimer __instance) { //IL_0009: Unknown result type (might be due to invalid IL or missing references) //IL_000f: Invalid comparison between Unknown and I4 if (!ModuleBase.IsEnabled || (int)__instance.removalTimerDisplayType != 3) { return __result; } string removalTimerPrefix = __instance.removalTimerPrefix; string originalText = __result.Substring(removalTimerPrefix.Length); originalText = TextTranslator.GetTextTranslation(DurationRoughTexts, originalText); return removalTimerPrefix + originalText; } [HarmonyPostfix] [HarmonyPatch(typeof(App_PerkPage), "GenerateIcons")] public static void Postfix_PerkPage_GenerateIcons(App_PerkPage __instance) { if (!ModuleBase.IsEnabled) { return; } Image[] componentsInChildren = ((Component)__instance.iconParent).GetComponentsInChildren(); if (componentsInChildren == null || componentsInChildren.Length == 0) { return; } List perks = CL_GameManager.gMan.localPlayer.perks; if (perks == null || perks.Count == 0) { return; } Dictionary dictionary = perks.ToDictionary((Perk p) => p.icon, (Perk p) => p); foreach (Image val in componentsInChildren) { OS_Tooltip component = ((Component)val).GetComponent(); if ((Object)(object)component != (Object)null && dictionary.TryGetValue(val.sprite, out var value)) { string title = value.GetTitle(true); string newValue = "" + GetTranslatedAppPerkAmount(value, isPreview: false); string newValue2 = "" + value.GetDescription(true, true, true, true) + ""; string text = AppPerkHoverTextTemplate ?? "{title}{amount}\n{description}"; component.tip = text.Replace("{title}", title).Replace("{amount}", newValue).Replace("{description}", newValue2); } } } [HarmonyPostfix] [HarmonyPatch(typeof(App_PerkPage_Card), "Initialize")] public static void Postfix_PerkPageCard_Initialize(App_PerkPage_Card __instance, App_PerkPage page, Perk p) { if (ModuleBase.IsEnabled) { string title = p.GetTitle(true); string newValue = "" + GetTranslatedAppPerkAmount(p, isPreview: true); string newValue2 = "" + p.GetDescription(true, false, true, true) + ""; string text = AppPerkHoverTextTemplate ?? "{title}{amount}\n{description}"; __instance.tooltip.tip = text.Replace("{title}", title).Replace("{amount}", newValue).Replace("{description}", newValue2); } } [HarmonyPostfix] [HarmonyPatch(typeof(App_PerkPage), "PurchaseRefresh")] public static void Postfix_PerkPage_PurchaseRefresh(App_PerkPage __instance) { if (!ModuleBase.IsEnabled || AppRefreshPurchasedText == null) { return; } GameObject reloadSettingsRoot = __instance.reloadSettingsRoot; TMP_Text[] componentsInChildren = reloadSettingsRoot.GetComponentsInChildren(); if (componentsInChildren == null || componentsInChildren.Length == 0) { return; } foreach (TMP_Text val in componentsInChildren) { if (val.text == "PURCHASED") { val.text = AppRefreshPurchasedText; break; } } } public static string GetTranslatedTrinketType(Perk perk) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0009: Invalid comparison between Unknown and I4 bool flag = (int)perk.perkType == 9; string textTranslation = TextTranslator.GetTextTranslation(TrinketPatch.TrinketTypes, flag ? "Binding" : "Trinket"); return flag ? ("" + textTranslation) : ("" + textTranslation); } public static string GetTrinketPerkTitle(Perk perk) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0008: Invalid comparison between Unknown and I4 return ((int)perk.perkType == 9) ? ("" + perk.title + "") : perk.title; } public static string GetTranslatedAppPerkAmount(Perk perk, bool isPreview) { if (perk == null) { return ""; } string newValue = (isPreview ? $"{perk.stackAmount + 1}" : $"{perk.stackAmount}"); string text = AppPerkAmountTemplate ?? " ({amount}x)"; return text.Replace("{amount}", newValue); } } [ConfigSection("Modules.PerkPatch", "This module replaces texts for perks and perk modules.")] public class PerkPatchSettings : ModuleSettingsBase { } [HarmonyPatch] public class ProgressionUnlockPatch : TextTranslator { [JsonProperty] public static Dictionary LogbookUnlockTitles; [JsonProperty] public static Dictionary UnlockTitles; [JsonProperty] public static Dictionary UnlockDescriptions; [JsonProperty] public static Dictionary UnlockHints; [JsonProperty] public static Dictionary UnlockProgressTextTemplates; [JsonProperty] public static string LogbookUnlockedDescription; [JsonProperty] public static string LogbookRedactedTitle; [JsonIgnore] public static ProgressionUnlockPatchSettings ModuleSettings; [HarmonyPostfix] [HarmonyPatch(typeof(ProgressionUnlock), "CheckUnlock")] public static void Postfix_ProgressionUnlock_CheckUnlock(ProgressionUnlock __instance) { if (ModuleBase.IsEnabled) { __instance.unlockLogDescription = TextTranslator.GetTextTranslation(LogbookUnlockTitles, __instance.unlockLogDescription); __instance.unlockTitle = TextTranslator.GetTextTranslation(UnlockTitles, __instance.unlockTitle); __instance.unlockDescription = TextTranslator.GetTextTranslation(UnlockDescriptions, __instance.unlockDescription); __instance.unlockHint = TextTranslator.GetTextTranslation(UnlockHints, __instance.unlockHint); } } [HarmonyPostfix] [HarmonyPatch(typeof(UI_ProgressionLog), "Start")] public static void Postfix_ProgressionLog_Start(UI_ProgressionLog __instance) { if (!ModuleBase.IsEnabled) { return; } ProgressionUnlock unlock = __instance.unlock; ProgressionUnlock prerequisite = __instance.prerequisite; UI_ProgressionPopup component = ((Component)__instance).GetComponent(); if (unlock.CheckUnlock() && (prerequisite == null || prerequisite.CheckUnlock())) { component.UpdateInformation(unlock.unlockIcon, unlock.unlockLogDescription, LogbookUnlockedDescription ?? "Unlocked"); return; } string text = unlock.unlockHint; if (unlock.showProgression && unlock.GetProgress() > 0f) { text = GetTranslatedProgressText(unlock); } component.UpdateInformation(__instance.unknownIcon, LogbookRedactedTitle ?? "REDACTED", text); } [HarmonyTranspiler] [HarmonyPatch(typeof(CL_ProgressionManager), "UpdateUnlocks")] public static IEnumerable Transpiler_ProgressionManager_UpdateUnlocks(IEnumerable codeInstructions) { //IL_0003: Unknown result type (might be due to invalid IL or missing references) //IL_0009: Expected O, but got Unknown //IL_0023: Unknown result type (might be due to invalid IL or missing references) //IL_0029: Expected O, but got Unknown //IL_00b0: Unknown result type (might be due to invalid IL or missing references) //IL_00b6: Expected O, but got Unknown //IL_0111: Unknown result type (might be due to invalid IL or missing references) //IL_0117: Expected O, but got Unknown //IL_011f: Unknown result type (might be due to invalid IL or missing references) //IL_0125: Expected O, but got Unknown CodeMatcher val = new CodeMatcher(codeInstructions, (ILGenerator)null); val.MatchForward(false, (CodeMatch[])(object)new CodeMatch[1] { new CodeMatch((OpCode?)OpCodes.Ldstr, (object)"Progress: ", (string)null) }); if (!val.IsValid) { return codeInstructions; } int pos = val.Pos; val.MatchForward(false, (CodeMatch[])(object)new CodeMatch[1] { new CodeMatch((OpCode?)OpCodes.Call, (object)typeof(string).GetMethod("Concat", new Type[4] { typeof(string), typeof(string), typeof(string), typeof(string) }), (string)null) }); if (!val.IsValid) { return codeInstructions; } int pos2 = val.Pos; MethodInfo method = typeof(ProgressionUnlockPatch).GetMethod("GetTranslatedProgressText"); val.RemoveInstructionsInRange(pos, pos2); val.Start().Advance(pos); val.Insert((CodeInstruction[])(object)new CodeInstruction[2] { new CodeInstruction(OpCodes.Ldloc_1, (object)null), new CodeInstruction(OpCodes.Call, (object)method) }); return val.InstructionEnumeration(); } public static string GetTranslatedProgressText(ProgressionUnlock unlock) { string progressString = unlock.GetProgressString(); if (progressString != "N/A") { string[] array = progressString.Split(new char[1] { '/' }, 2); if (array.Length == 2 && UnlockProgressTextTemplates != null && UnlockProgressTextTemplates.TryGetValue(unlock.id, out var value) && value != null) { string newValue = array[0]; string newValue2 = array[1]; return value.Replace("{current}", newValue).Replace("{required}", newValue2); } } return "Progress: " + progressString + " " + unlock.progressionString; } } [ConfigSection("Modules.ProgressionUnlockPatch", "This module replaces texts of unlocks.")] public class ProgressionUnlockPatchSettings : ModuleSettingsBase { } [HarmonyPatch] public class QuietOSPatch : TemplateTranslator { [JsonProperty] public static Dictionary FolderNames; [JsonProperty] public static Dictionary FileNames; [JsonProperty] public static Dictionary MessageTextTemplates; [JsonProperty] public static Dictionary MessageOptions; [JsonProperty] public static Dictionary HoverTexts; [JsonProperty] public static Dictionary ContextMenuOptions; [JsonProperty] public static Dictionary StationIDs; [JsonProperty] public static Dictionary UnlockerAccessTitles; [JsonProperty] public static string FileCounterTemplate; [JsonProperty] public static string PageCounterTemplate; [JsonProperty] public static string DiskCardTemplate; [JsonProperty] public static string NoSaveText; [JsonProperty] public static string SaveTextTemplate; [JsonProperty] public static string SaveTemplate; [JsonProperty] public static string UnlockerCostTemplate; [JsonProperty] public static string SolarKnightScoreTemplate; [JsonProperty] public static string SolarKnightLivesTemplate; [JsonProperty] public static string SolarKnightTimeTemplate; [JsonIgnore] public static TemplateTranslations MessageTemplates; [JsonIgnore] public static QuietOSPatchSettings ModuleSettings; [OnDeserialized] private void OnDeserialized(StreamingContext _) { if (ModuleBase.IsEnabled) { MessageTemplates = new TemplateTranslations(MessageTextTemplates); } } [HarmonyPrefix] [HarmonyPatch(typeof(OS_File), "Initialize")] public static void Prefix_File_Initialize(OS_File __instance, ref FileInfo info) { //IL_0011: 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) //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_001f: Invalid comparison between Unknown and I4 if (ModuleBase.IsEnabled) { fileType type = info.type; if (1 == 0) { } Dictionary dictionary = (((int)type != 1) ? FileNames : FolderNames); if (1 == 0) { } Dictionary textTranslations = dictionary; info.name = TextTranslator.GetTextTranslation(textTranslations, info.name); InputField nameText = __instance.nameText; nameText.characterLimit = Math.Max(info.name.Length, nameText.characterLimit); } } [HarmonyPostfix] [HarmonyPatch(typeof(OS_File), "Initialize")] public static void Postfix_File_Initialize(OS_File __instance) { //IL_004a: Unknown result type (might be due to invalid IL or missing references) //IL_004f: Unknown result type (might be due to invalid IL or missing references) //IL_0059: Unknown result type (might be due to invalid IL or missing references) //IL_005e: Unknown result type (might be due to invalid IL or missing references) //IL_0076: Unknown result type (might be due to invalid IL or missing references) //IL_007b: Unknown result type (might be due to invalid IL or missing references) if (!ModuleBase.IsEnabled) { return; } Text textComponent = __instance.nameText.textComponent; RectTransform component = ((Component)textComponent).GetComponent(); Transform parent = ((Component)textComponent).transform.parent; RectTransform component2 = ((Component)parent).GetComponent(); if ((Object)(object)component != (Object)null && (Object)(object)component2 != (Object)null) { Rect rect = component.rect; float width = ((Rect)(ref rect)).width; rect = component2.rect; if (width < ((Rect)(ref rect)).width) { rect = component2.rect; component.SetSizeWithCurrentAnchors((Axis)0, ((Rect)(ref rect)).width); } } } [HarmonyPostfix] [HarmonyPatch(typeof(OS_Folder), "UpdateInfoText")] public static void Postfix_Folder_UpdateInfoText(OS_Folder __instance) { if (ModuleBase.IsEnabled && __instance.infoText != null && FileCounterTemplate != null) { int count = __instance.subFiles.Count; __instance.infoText.text = FileCounterTemplate.Replace("{count}", count.ToString()); } } [HarmonyPrefix] [HarmonyPatch(typeof(OS_Tooltip_Manager), "ShowTip")] public static void Prefix_TooltipManager_ShowTip(ref string tip) { if (ModuleBase.IsEnabled) { tip = TextTranslator.GetTextTranslation(HoverTexts, tip); } } [HarmonyPrefix] [HarmonyPatch(typeof(Message_Manager), "CreateMessage")] public static void Prefix_MessageManager_CreateMessage(ref Message_Packet packet) { if (ModuleBase.IsEnabled) { packet.message = TemplateTranslator.GetTemplateTranslation(MessageTemplates, packet.message); packet.closeText = TextTranslator.GetTextTranslation(MessageOptions, packet.closeText); packet.aText = TextTranslator.GetTextTranslation(MessageOptions, packet.aText); } } [HarmonyPrefix] [HarmonyPatch(typeof(ContextMenu), "ShowMessage")] public static void Prefix_ContextMenu_ShowMessage(ContextMenu __instance) { if (!ModuleBase.IsEnabled) { return; } foreach (ContextOption option in __instance.options) { option.text = TextTranslator.GetTextTranslation(ContextMenuOptions, option.text); } } [HarmonyPostfix] [HarmonyPatch(typeof(App_DocumentReader), "UpdateButtons")] public static void Postfix_DocumentReader_UpdateButtons(App_DocumentReader __instance) { if (ModuleBase.IsEnabled && PageCounterTemplate != null) { int num = __instance.curPage + 1; int count = __instance.pages.Count; if (count > 1) { __instance.pageCounter.text = PageCounterTemplate.Replace("{current}", num.ToString()).Replace("{total}", count.ToString()); } } } [HarmonyPostfix] [HarmonyPatch(typeof(App_SavePage), "UpdateSaveText")] public static void Postfix_SavePage_UpdateSaveText(App_SavePage __instance) { if (!ModuleBase.IsEnabled) { return; } if (CL_SaveManager.GetNumberOfDiskLives() == 0) { __instance.floppyText.text = NoSaveText ?? "SAVES | NO BACKUP DATA FOUND"; return; } string text = __instance.floppyText.text; if (!text.StartsWith("SAVES | ")) { return; } string text2 = SaveTextTemplate ?? "SAVES | {saves} "; string text3 = SaveTemplate ?? "{stationID}:{saveCount}"; string[] array = text.TrimEnd(Array.Empty()).Substring(18).Split(new char[1] { ' ' }); List list = new List(); foreach (string text4 in array) { string[] array2 = text4.Split(new char[1] { ':' }, 2); if (array2.Length != 2) { list.Add(text4); continue; } string originalText = array2[0]; originalText = TextTranslator.GetTextTranslation(StationIDs, originalText); string newValue = array2[1]; string item = text3.Replace("{stationID}", originalText).Replace("{saveCount}", newValue); list.Add(item); } string newValue2 = string.Join(" ", list); __instance.floppyText.text = text2.Replace("{saves}", newValue2); } [HarmonyPostfix] [HarmonyPatch(typeof(App_SavePage_DiskCard), "Initialize")] public static void Postfix_DiskCard_Initialize(App_SavePage_DiskCard __instance, ref string diskName, ref int capacity) { if (ModuleBase.IsEnabled) { diskName = TextTranslator.GetTextTranslation(FolderNames, diskName); string text = DiskCardTemplate ?? "{diskName}\nCapacity: {capacity}x"; __instance.text.text = text.Replace("{diskName}", diskName).Replace("{capacity}", capacity.ToString()); } } [HarmonyPostfix] [HarmonyPatch(typeof(App_Unlocker), "CheckAuthorize")] public static void Postfix_Unlocker_CheckAuthorize(App_Unlocker __instance) { if (ModuleBase.IsEnabled && __instance.showAuthorizationMenu && UnlockerCostTemplate != null) { __instance.authorizationTitleObject.text = TextTranslator.GetTextTranslation(UnlockerAccessTitles, __instance.authorizationTitleObject.text); int authorizationCost = __instance.authorizationCost; if (authorizationCost > 0) { string text = ((CL_GameManager.GetRoaches(false) < authorizationCost) ? ("" + UnlockerCostTemplate + "") : UnlockerCostTemplate); __instance.authorizationCostTextObject.text = text.Replace("{cost}", authorizationCost.ToString()); } } } [HarmonyPostfix] [HarmonyPatch(typeof(App_SolarKnight), "AddScore")] public static void Postfix_SolarKnight_AddScore(App_SolarKnight __instance) { if (ModuleBase.IsEnabled) { TranslateSolarKnightScoreText(__instance); } } [HarmonyPostfix] [HarmonyPatch(typeof(App_SolarKnight), "AddLife")] public static void Postfix_SolarKnight_AddLife(App_SolarKnight __instance) { if (ModuleBase.IsEnabled) { TranslateSolarKnightLivesText(__instance); } } [HarmonyPostfix] [HarmonyPatch(typeof(App_SolarKnight), "LoseLife")] public static void Postfix_SolarKnight_LoseLife(App_SolarKnight __instance) { if (ModuleBase.IsEnabled) { ((MonoBehaviour)__instance).StartCoroutine(TranslateLivesText()); } IEnumerator TranslateLivesText() { yield return null; yield return (object)new WaitForSeconds(1f); TranslateSolarKnightLivesText(__instance); } } [HarmonyPostfix] [HarmonyPatch(typeof(App_SolarKnight), "Reset")] public static void Postfix_SolarKnight_Reset(App_SolarKnight __instance) { if (ModuleBase.IsEnabled) { TranslateSolarKnightScoreText(__instance); TranslateSolarKnightLivesText(__instance); } } [HarmonyPostfix] [HarmonyPatch(typeof(App_SolarKnight), "Update")] public static void Postfix_SolarKnight_Update(App_SolarKnight __instance) { if (ModuleBase.IsEnabled) { string text = __instance.timeText.text; if (text.StartsWith("Time: ") && SolarKnightTimeTemplate != null) { string newValue = text.Substring(6); __instance.timeText.text = SolarKnightTimeTemplate.Replace("{time}", newValue); } } } public static void TranslateSolarKnightLivesText(App_SolarKnight solarKnight) { string text = solarKnight.livesText.text; if (text.StartsWith("Lives: ") && SolarKnightLivesTemplate != null) { string newValue = text.Substring(7); solarKnight.livesText.text = SolarKnightLivesTemplate.Replace("{lives}", newValue); } } public static void TranslateSolarKnightScoreText(App_SolarKnight solarKnight) { string text = solarKnight.scoreText.text; if (text.StartsWith("Score: ") && SolarKnightScoreTemplate != null) { string newValue = text.Substring(7); solarKnight.scoreText.text = SolarKnightScoreTemplate.Replace("{score}", newValue); } } } [ConfigSection("Modules.QuietOSPatch", "This module replaces some texts of QuietOS UI.")] public class QuietOSPatchSettings : ModuleSettingsBase { } [HarmonyPatch] public class RecordingSubtitlePatch : ModuleBase { [JsonProperty] public static Dictionary RecordingSubtitles; [JsonIgnore] public static RecordingSubtitlePatchSettings ModuleSettings; [HarmonyPostfix] [HarmonyPatch(typeof(Localization), "GetLine")] public static string Postfix_Localization_GetLine(string __result, string group, string key) { if (!ModuleBase.IsEnabled || group != "recordings" || RecordingSubtitles == null || !RecordingSubtitles.ContainsKey(key)) { return __result; } return RecordingSubtitles[key] ?? __result; } } [ConfigSection("Modules.RecordingSubtitlePatch", "This module replaces recording subtitle texts.")] public class RecordingSubtitlePatchSettings : ModuleSettingsBase { } [HarmonyPriority(0)] [HarmonyPatch] public class RecordingSubtitleTimingPatch : ModuleBase { [JsonProperty] public static RecordingSubtitleTimingPatchSettings ModuleSettings; [JsonProperty] public static Dictionary> RecordingSubtitleTimings; [JsonIgnore] public static readonly string[] LinebreakPattern = new string[1] { "
" }; [JsonIgnore] public static readonly Regex DelayRegex = CacheManager.GetOrCreateRegex("", RegexOptions.IgnoreCase | RegexOptions.Compiled); [HarmonyPostfix] [HarmonyPatch(typeof(Localization), "GetLine")] public static string Postfix_Localization_GetLine(string __result, string group, string key) { if (!ModuleBase.IsEnabled || group != "recordings" || RecordingSubtitleTimings == null || !RecordingSubtitleTimings.ContainsKey(key) || (ModuleSettings.UseOriginalDelay && DelayRegex.IsMatch(__result))) { return __result; } return RebuildSubtitleTextWithTimings(__result, RecordingSubtitleTimings[key]); } public static string RebuildSubtitleTextWithTimings(string subtitleText, List subtitleTimings) { if (subtitleTimings == null || subtitleTimings.Count == 0) { return subtitleText; } string[] array = subtitleText.Split(LinebreakPattern, StringSplitOptions.None); int num = Math.Min(array.Length, subtitleTimings.Count); for (int i = 0; i < num; i++) { string subtitleLine = array[i]; subtitleLine = RemoveDelayTag(subtitleLine); float num2 = (float)subtitleLine.Length * ModuleSettings.CharacterInterval + ModuleSettings.BaseDuration; float num3 = subtitleTimings[i]; if (i > 0) { num3 -= subtitleTimings[i - 1]; } if (i == num - 1) { num3 += ModuleSettings.EndDelay; } float num4 = num3 - num2; string delayTag = ((num4 < 0f) ? $"" : $""); subtitleLine = InsertDelayTag(subtitleLine, delayTag); array[i] = subtitleLine; } return string.Join(LinebreakPattern[0], array); } public static string RemoveDelayTag(string subtitleLine) { Match match = DelayRegex.Match(subtitleLine); return match.Success ? subtitleLine.Remove(match.Index, match.Length) : subtitleLine; } public static string InsertDelayTag(string subtitleLine, string delayTag) { if (string.IsNullOrEmpty(delayTag)) { return subtitleLine; } Match match = DelayRegex.Match(subtitleLine); return match.Success ? subtitleLine.Insert(match.Index, delayTag) : (subtitleLine + delayTag); } } [ConfigSection("Modules.RecordingSubtitleTimingPatch", "This module adjusts display timings of recording subtitles.")] public class RecordingSubtitleTimingPatchSettings : ModuleSettingsBase { [ConfigEntry("BaseDuration", 2.2f, "Base duration (in seconds) for displaying a subtitle.")] public float BaseDuration; [ConfigEntry("CharacterInterval", 0.1f, "Additional duration (in seconds) added per character in the subtitle text.")] public float CharacterInterval; [ConfigEntry("EndDelay", 0.5f, "Extra duration (in seconds) added at the end of a subtitle.")] public float EndDelay; [ConfigEntry("UseOriginalDelay", false, "Set this field to \"true\" to retain original timings of\nsubtitles that contain \"\" tag(s).")] public bool UseOriginalDelay; } [HarmonyPatch] public class RoachTraderSubtitlePatch : ModuleBase { [JsonProperty] public static Dictionary RoachTraderSubtitles; [JsonIgnore] public static RoachTraderSubtitlePatchSettings ModuleSettings; [HarmonyPostfix] [HarmonyPatch(typeof(Localization), "GetLine")] public static string Postfix_Localization_GetLine(string __result, string group, string key) { if (!ModuleBase.IsEnabled || group != "roachtrader" || RoachTraderSubtitles == null || !RoachTraderSubtitles.ContainsKey(key)) { return __result; } return RoachTraderSubtitles[key]; } } [ConfigSection("Modules.RoachTraderSubtitlePatch", "This module replaces Soach subtitle texts.")] public class RoachTraderSubtitlePatchSettings : ModuleSettingsBase { } [HarmonyPatch] public class ScoreScreenPatch : TextTranslator { [JsonProperty] public static Dictionary StatDefaultTexts; [JsonProperty] public static Dictionary StatTextTemplates; [JsonProperty] public static Dictionary ScoreItemTitles; [JsonProperty] public static Dictionary MedalTitles; [JsonProperty] public static Dictionary LeaderboardRangeTypes; [JsonProperty] public static Dictionary LeaderboardScoreTypes; [JsonProperty] public static string StatMetersTemplate; [JsonProperty] public static string StatMeterPerSecondTemplate; [JsonProperty] public static string StatTimeTemplate; [JsonProperty] public static string StatTimeDayTemplate; [JsonProperty] public static string StatTimeHourTemplate; [JsonProperty] public static string StatTimeMinuteTemplate; [JsonProperty] public static string StatTimeSecondTemplate; [JsonProperty] public static string EndScreenDistanceDefaultText; [JsonProperty] public static string EndScreenDistanceTemplate; [JsonProperty] public static string EndScreenSpeedDefaultText; [JsonProperty] public static string EndScreenSpeedTemplate; [JsonProperty] public static string EndScreenFillerText; [JsonProperty] public static string EndScreenBaseScoreTemplate; [JsonProperty] public static string EndScreenFinalScoreTemplate; [JsonProperty] public static string EndScreenScoreItemTitleTemplate; [JsonProperty] public static string LeaderboardDetailNameTemplate; [JsonProperty] public static string LeaderboardDetailNoSessionDataText; [JsonProperty] public static string LeaderboardDetailNoScoreDataText; [JsonProperty] public static string LeaderboardSessionScoreTemplate; [JsonProperty] public static string LeaderboardSessionDistanceTemplate; [JsonProperty] public static string LeaderboardSessionTimeTemplate; [JsonProperty] public static string LeaderboardSessionSpeedTemplate; [JsonProperty] public static string LeaderboardSessionDateTemplate; [JsonProperty] public static string LeaderboardScoreBonusTemplate; [JsonProperty] public static string LeaderboardScoreMultiplierTemplate; [JsonProperty] public static string PopupRoachBankedTitle; [JsonProperty] public static string PopupRoachBankedDescriptionTemplate; [JsonProperty] public static string PopupCreditWonTitle; [JsonProperty] public static string PopupCreditWonDescriptionTemplate; [JsonIgnore] public static ScoreScreenPatchSettings ModuleSettings; [HarmonyPostfix] [HarmonyPatch(typeof(UT_StatText), "RefreshText")] public static void Postfix_StatText_RefreshText(UT_StatText __instance) { if (!ModuleBase.IsEnabled) { return; } string text = __instance.text.text; if (text == __instance.defaultText) { __instance.text.text = TextTranslator.GetTextTranslation(StatDefaultTexts, text); return; } string textPrefix = __instance.textPrefix; if (StatTextTemplates != null && StatTextTemplates.TryGetValue(textPrefix + "{value}", out var value) && value != null) { string newValue = text.Substring(textPrefix.Length); __instance.text.text = value.Replace("{value}", newValue); } } [HarmonyPostfix] [HarmonyPatch(typeof(Statistic), "GetString")] public static string Postfix_Statistic_GetString(string __result, Statistic __instance) { //IL_0015: Unknown result type (might be due to invalid IL or missing references) //IL_001a: 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_001d: Invalid comparison between Unknown and I4 //IL_0040: Unknown result type (might be due to invalid IL or missing references) //IL_0042: Invalid comparison between Unknown and I4 //IL_0086: Unknown result type (might be due to invalid IL or missing references) //IL_0088: Invalid comparison between Unknown and I4 //IL_00c9: Unknown result type (might be due to invalid IL or missing references) //IL_00cb: Invalid comparison between Unknown and I4 if (!ModuleBase.IsEnabled) { return __result; } DisplayType displayType = __instance.displayType; if ((int)displayType == 0) { return __result; } double value = Math.Round((float)__instance.GetValue(), 2); if ((int)displayType == 1) { string newValue = Math.Round(value, 2).ToString(CultureInfo.InvariantCulture); string text = StatMetersTemplate ?? "{meter} Meters"; return text.Replace("{meter}", newValue); } if ((int)displayType == 2) { string newValue2 = Math.Round(value, 2).ToString(CultureInfo.InvariantCulture); string text2 = StatMeterPerSecondTemplate ?? "{mps} m/s"; return text2.Replace("{mps}", newValue2); } if ((int)displayType == 4) { TimeSpan timeSpan = TimeSpan.FromSeconds(value); return (timeSpan.TotalHours < 1.0) ? timeSpan.ToString("mm\\:ss\\:ff") : DarkMachineFunctions.SecondsToTimeLeaderboardString((float)__instance.GetValue()); } return __result; } [HarmonyPostfix] [HarmonyPatch(typeof(DarkMachineFunctions), "SecondsToTimeLeaderboardString")] public static string Postfix_SecondsToString(string __result, float seconds) { if (!ModuleBase.IsEnabled) { return __result; } TimeSpan timeSpan = TimeSpan.FromSeconds(seconds); string newValue = ""; if (timeSpan.TotalDays >= 1.0) { string text = StatTimeDayTemplate ?? "D:{day} "; newValue = text.Replace("{day}", timeSpan.Days.ToString()); } string newValue2 = ""; if (timeSpan.TotalHours >= 1.0) { string text2 = StatTimeHourTemplate ?? "H:{hour} "; newValue2 = text2.Replace("{hour}", timeSpan.Hours.ToString()); } string text3 = StatTimeMinuteTemplate ?? "M:{minute} "; string newValue3 = text3.Replace("{minute}", timeSpan.Minutes.ToString()); string text4 = StatTimeSecondTemplate ?? "S:{second}.{millisecond}"; string newValue4 = text4.Replace("{second}", timeSpan.Seconds.ToString()).Replace("{millisecond}", timeSpan.Milliseconds.ToString()); string text5 = StatTimeTemplate ?? "{day}{hour}{minute}{second}"; return text5.Replace("{day}", newValue).Replace("{hour}", newValue2).Replace("{minute}", newValue3) .Replace("{second}", newValue4); } [HarmonyPrefix] [HarmonyPatch(typeof(UI_EndScreenScoreWindow), "StartAnimation")] public static bool Prefix_EndScreenScoreWindow_StartAnimation(UI_EndScreenScoreWindow __instance) { //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_002c: Expected O, but got Unknown if (!ModuleBase.IsEnabled) { return true; } foreach (Transform item in __instance.scoreItemRoot) { Transform val = item; Object.Destroy((Object)(object)((Component)val).gameObject); } ((MonoBehaviour)__instance).StartCoroutine(CustomAnimateEndScreen(__instance)); return false; } [HarmonyPostfix] [HarmonyPatch(typeof(UI_EndScreenScoreWindow_ScoreItem), "Initialize")] public static void Postfix_EndScreenScoreItem_Initialize(UI_EndScreenScoreWindow_ScoreItem __instance, ref string title, float bonus, float multiplier, in int count) { if (ModuleBase.IsEnabled) { title = TextTranslator.GetTextTranslation(ScoreItemTitles, title); if (count == 0) { __instance.titleText.text = title; return; } string text = EndScreenScoreItemTitleTemplate ?? "{title} ({count})"; TMP_Text titleText = __instance.titleText; string text2 = text.Replace("{title}", title); int num = count; titleText.text = text2.Replace("{count}", num.ToString()); } } [HarmonyPostfix] [HarmonyPatch(typeof(UI_ScoreScreen), "SetMedalInfo")] public static void Postfix_ScoreScreen_SetMedalInfo(UI_ScoreScreen __instance) { if (ModuleBase.IsEnabled) { __instance.scoreRankText.text = TextTranslator.GetTextTranslation(MedalTitles, __instance.scoreRankText.text); } } [HarmonyPostfix] [HarmonyPatch(typeof(Leaderboard_Panel), "StartUpdateScore")] public static void Postfix_LeaderboardPanel_StartUpdateScore(Leaderboard_Panel __instance) { if (ModuleBase.IsEnabled) { __instance.title.text = TextTranslator.GetTextTranslation(LeaderboardRangeTypes, __instance.title.text); __instance.scoreTypeText.text = TextTranslator.GetTextTranslation(LeaderboardScoreTypes, __instance.scoreTypeText.text); } } [HarmonyPostfix] [HarmonyPatch(typeof(UI_LeaderboardEntryDetailWindow), "ShowDetails")] public static void Postfix_LeaderboardEntryWindow_ShowDetails(UI_LeaderboardEntryDetailWindow __instance, in LeaderboardEntry scoreInfo, WK_Leaderboard_UserData data) { //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_0029: Unknown result type (might be due to invalid IL or missing references) if (!ModuleBase.IsEnabled) { return; } if (LeaderboardDetailNameTemplate != null) { Friend user = scoreInfo.User; string name = ((Friend)(ref user)).Name; int globalRank = scoreInfo.GlobalRank; __instance.nameText.text = LeaderboardDetailNameTemplate.Replace("{player}", name).Replace("{rank}", globalRank.ToString()); } string text = __instance.statText.text; string[] array = text.Split(new char[1] { '\n' }); for (int i = 0; i < array.Length; i++) { string text2 = array[i]; if (text2.StartsWith("Score: ") && text2.EndsWith("")) { string newValue = text2.Substring(27, text2.Length - 42); string text3 = LeaderboardSessionScoreTemplate ?? "Score: {score}"; text2 = text3.Replace("{score}", newValue); } else if (text2.StartsWith("Distance: ") && text2.EndsWith("m")) { string newValue2 = text2.Substring(24, text2.Length - 33); string text4 = LeaderboardSessionDistanceTemplate ?? "Distance: {meter}m"; text2 = text4.Replace("{meter}", newValue2); } else if (text2.StartsWith("Run Playtime: ")) { string newValue3 = text2.Substring(14); string text5 = LeaderboardSessionTimeTemplate ?? "Run Playtime: {time}"; text2 = text5.Replace("{time}", newValue3); } else if (text2.StartsWith("Speed: ") && text2.EndsWith("m/s")) { string newValue4 = text2.Substring(7, text2.Length - 10); string text6 = LeaderboardSessionSpeedTemplate ?? "Speed: {mps}m/s"; text2 = text6.Replace("{mps}", newValue4); } else if (text2.StartsWith("Date: ")) { string newValue5 = text2.Substring(6); string text7 = LeaderboardSessionDateTemplate ?? "Date: {date}"; text2 = text7.Replace("{date}", newValue5); } array[i] = text2; } text = string.Join("\n", array); __instance.statText.text = text; List list = new List(); if (data.scoreData == null || data.scoreData.Count == 0) { return; } foreach (string scoreDatum in data.scoreData) { string[] array2 = scoreDatum.Split(new char[1] { ':' }); if (array2.Length >= 5) { string textTranslation = TextTranslator.GetTextTranslation(ScoreItemTitles, array2[1]); int.TryParse(array2[2], out var result); result = Mathf.Max(result, 1); float.TryParse(array2[3], out var result2); result2 = (float)Math.Round(result2, 2); float.TryParse(array2[4], out var result3); result3 = (float)Math.Round(result3, 2); string text8 = ""; text8 = ((result3 != 1f) ? (LeaderboardScoreMultiplierTemplate ?? "{title} ({count}): {multiplier}x") : (LeaderboardScoreBonusTemplate ?? "{title} ({count}): {bonus}")); string item = text8.Replace("{title}", textTranslation).Replace("{count}", result.ToString()).Replace("{bonus}", result2.ToString()) .Replace("{multiplier}", result3.ToString()); list.Add(item); } } string text9 = string.Join("\n", list); __instance.scoreText.text = text9; } [HarmonyPostfix] [HarmonyPatch(typeof(UI_LeaderboardEntryDetailWindow), "ShowNoEntryDetails")] public static void Postfix_LeaderboardEntryWindow_ShowNoEntryDetails(UI_LeaderboardEntryDetailWindow __instance, in LeaderboardEntry scoreInfo) { //IL_0020: 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) if (ModuleBase.IsEnabled) { if (LeaderboardDetailNameTemplate != null) { Friend user = scoreInfo.User; string name = ((Friend)(ref user)).Name; int globalRank = scoreInfo.GlobalRank; __instance.nameText.text = LeaderboardDetailNameTemplate.Replace("{player}", name).Replace("{rank}", globalRank.ToString()); } __instance.statText.text = LeaderboardDetailNoSessionDataText ?? "No Run Data Found."; __instance.scoreText.text = LeaderboardDetailNoScoreDataText ?? "No Score Data Found."; } } [HarmonyPrefix] [HarmonyPatch(typeof(CL_ProgressionManager), "ShowUnlockProgress")] public static void Prefix_ProgressionManager_ShowUnlockProgress(Sprite icon, ref string title, ref string desc) { if (ModuleBase.IsEnabled && !(title != "ROACHES BANKED")) { title = PopupRoachBankedTitle ?? "ROACHES BANKED"; if (desc.StartsWith("Banked ") && desc.EndsWith(" from your inventory.") && PopupRoachBankedDescriptionTemplate != null) { string newValue = desc.Substring(7, desc.Length - 28); desc = PopupRoachBankedDescriptionTemplate.Replace("{count}", newValue); } } } [HarmonyPrefix] [HarmonyPatch(typeof(CL_ProgressionManager), "ShowUnlockPopup", new Type[] { typeof(Sprite), typeof(string), typeof(string), typeof(Color), typeof(AudioClip), typeof(bool) })] public static void Prefix_ProgressionManager_ShowUnlockPopup(Sprite icon, ref string title, ref string desc) { if (ModuleBase.IsEnabled && !(title != "WIN BONUS")) { title = PopupCreditWonTitle ?? "WIN BONUS"; if (desc.EndsWith(" Facility Credits Added") && PopupCreditWonDescriptionTemplate != null) { string newValue = desc.Substring(0, desc.Length - 23); desc = PopupCreditWonDescriptionTemplate.Replace("{count}", newValue); } } } public static IEnumerator CustomAnimateEndScreen(UI_EndScreenScoreWindow scoreWindow) { Image scoreTitle = scoreWindow.scoreTitle; Color scoreTitleColor = scoreWindow.titleColor; string loadingText = scoreWindow.loadingText; TextAnimator_TMP loadingTextAnimator = scoreWindow.loadingTextAnimator; TypewriterCore loadingTextTypewriter = ((Component)loadingTextAnimator).GetComponent(); float distance = CL_GameManager.gMan.GetPlayerBestTravelDistance(); TMP_Text distanceText = scoreWindow.distanceScoreText; float speed = CL_GameManager.gMan.GetPlayerTravelSpeed(); TMP_Text speedText = scoreWindow.speedScoreText; TMP_Text modifierTitle = scoreWindow.modifierTitleText; float currentScore = Mathf.Round(distance * speed); float currentMultiplier = 1f; TMP_Text baseScoreText = scoreWindow.baseScoreText; float finalScore = CL_GameManager.GetCurrentGamemode().GetPlayerScore(false); TMP_Text finalScoreText = scoreWindow.totalScoreText; TextAnimator_TMP finalScoreTextAnimator = ((Component)finalScoreText).GetComponent(); TMP_Text highScoreText = scoreWindow.highScoreText; UI_EndScreenScoreWindow_ScoreItem scoreItemAsset = scoreWindow.scoreItemAsset; Transform scoreItemRoot = scoreWindow.scoreItemRoot; AudioSource tickSound = scoreWindow.tickSound; List finishSounds = scoreWindow.finishSounds; string distanceDefaultText = EndScreenDistanceDefaultText ?? "DISTANCE: ............................."; string distanceTemplate = EndScreenDistanceTemplate ?? "DISTANCE: ...................{filler}{meter}M"; string speedDefaultText = EndScreenSpeedDefaultText ?? "SPEED: .........................."; string speedTemplate = EndScreenSpeedTemplate ?? "SPEED: ................{filler}{mps}m/s"; string fillerText = EndScreenFillerText ?? ".........."; string baseScoreTemplate = EndScreenBaseScoreTemplate ?? "SCORE: {score}"; string finalScoreTemplate = EndScreenFinalScoreTemplate ?? "FINAL: {score}"; ((Graphic)scoreTitle).color = Color.clear; ((Graphic)loadingTextAnimator.TMProComponent).color = Color.clear; distanceText.text = ""; speedText.text = ""; ((Component)modifierTitle).gameObject.SetActive(false); baseScoreText.text = ""; finalScoreText.text = finalScoreTemplate.Replace("{score}", "0"); if (!scoreWindow.skip) { yield return (object)new WaitForSecondsRealtime(0.5f); AudioManager.PlayUISound(scoreWindow.startSound, 0.7f, 1f); } TweenSettingsExtensions.SetUpdate(ShortcutExtensions.DOPunchScale(((Component)scoreTitle).transform, Vector3.one * -0.05f, 0.5f, 10, 1f), true); TweenSettingsExtensions.SetUpdate(ShortcutExtensions.DOPunchRotation(((Component)scoreTitle).transform, Vector3.forward * 5f, 0.5f, 16, 1f), true); TweenSettingsExtensions.SetUpdate>(DOTweenModuleUI.DOColor(scoreTitle, scoreTitleColor, 0.5f), true); ((TAnimCore)loadingTextAnimator).SetText(loadingText); ((Graphic)loadingTextAnimator.TMProComponent).color = scoreTitleColor; loadingTextTypewriter.StartShowingText(true); if (!scoreWindow.skip) { yield return (object)new WaitForSecondsRealtime(0.8f); } loadingTextTypewriter.StartDisappearingText(); distanceText.text = distanceDefaultText; speedText.text = speedDefaultText; baseScoreText.text = baseScoreTemplate.Replace("{score}", "0"); if (currentScore > 10f) { scoreWindow.PlayTickSound(); if (!scoreWindow.skip) { yield return (object)new WaitForSecondsRealtime(0.5f); } tickSound.Play(); float tickTime = 0f; while (tickTime < 1f && !scoreWindow.skip) { tickTime += Time.unscaledDeltaTime; string lerpDistance = Mathf.RoundToInt(Mathf.Lerp(0f, distance, tickTime)).ToString(); UpdateDistanceText(lerpDistance); string lerpSpeed = Math.Round(Mathf.Lerp(0f, speed, tickTime), 2).ToString(); UpdateSpeedText(lerpSpeed); string lerpBaseScore = Mathf.Round(Mathf.Lerp(0f, currentScore, tickTime)).ToString(); baseScoreText.text = baseScoreTemplate.Replace("{score}", lerpBaseScore); ((TAnimCore)finalScoreTextAnimator).SetText(finalScoreTemplate.Replace("{score}", lerpBaseScore)); yield return null; } tickSound.Stop(); } UpdateDistanceText(Mathf.RoundToInt(distance).ToString()); UpdateSpeedText(Math.Round(speed, 2).ToString()); baseScoreText.text = "" + baseScoreTemplate.Replace("{score}", currentScore.ToString()); TweenSettingsExtensions.SetUpdate(ShortcutExtensions.DOPunchScale(baseScoreText.transform, Vector3.one * 0.02f, 0.5f, 10, 1f), true); DOTween.Complete((object)finalScoreText.transform, false); finalScoreText.text = finalScoreTemplate.Replace("{score}", currentScore.ToString()); TweenSettingsExtensions.SetUpdate(ShortcutExtensions.DOPunchScale(finalScoreText.transform, Vector3.one * 0.02f, 0.5f, 10, 1f), true); scoreWindow.PlayTickSound(); if (!scoreWindow.skip) { yield return (object)new WaitForSecondsRealtime(0.5f); } ((Component)modifierTitle).gameObject.SetActive(true); List scores = CL_ScoreManager.sessionScore.scores; if (scores.Count > 0) { foreach (Score score in scores) { scoreWindow.PlayTickSound(); if (!scoreWindow.skip) { yield return (object)new WaitForSecondsRealtime(0.08f); } UI_EndScreenScoreWindow_ScoreItem scoreItem = Object.Instantiate(scoreItemAsset, scoreItemRoot); scoreItem.Initialize(score.title, score.bonus, score.multiplier, score.count); TweenSettingsExtensions.SetUpdate(ShortcutExtensions.DOPunchScale(((Component)scoreItem).transform, Vector3.one * 0.05f, 0.5f, 10, 1f), true); currentScore += score.bonus; currentMultiplier += score.multiplier; string currentFinalScore = Mathf.Round(currentScore * currentMultiplier).ToString(); if (!scoreWindow.skip) { yield return (object)new WaitForSecondsRealtime(0.08f); } finalScoreText.text = finalScoreTemplate.Replace("{score}", currentFinalScore); DOTween.Complete((object)finalScoreText.transform, false); } } TweenSettingsExtensions.SetUpdate(ShortcutExtensions.DOPunchScale(finalScoreText.transform, Vector3.one * 0.2f, 0.8f, 10, 1f), true); TweenSettingsExtensions.SetUpdate>(TweenSettingsExtensions.SetLoops>(DOTweenModuleUI.DOColor((Graphic)(object)finalScoreText, Color.white, 0.5f), 2, (LoopType)1), true); bool isHighScore = M_Gamemode.IsCurrentlyAHighScore(); FinishSound finishSound; if (isHighScore) { finishSound = scoreWindow.personalBestFinishSound; } else { int soundIndex = finishSounds.FindIndex((FinishSound s) => s.minimumScore < finalScore); finishSound = finishSounds[Math.Max(0, soundIndex)]; } finalScoreText.text = finishSound.scoreTitlePrefix + finalScoreTemplate.Replace("{score}", finalScore.ToString()) + finishSound.scoreTitleSuffix; if (!scoreWindow.skip) { AudioManager.PlayUISound(finishSound.clip, 0.7f, 1f); TweenSettingsExtensions.SetUpdate(ShortcutExtensions.DOPunchRotation(((Component)scoreWindow).transform, Vector3.forward * 0.5f, 0.5f, 10, 1f), true); yield return (object)new WaitForSecondsRealtime(0.5f); } if (isHighScore) { ((Component)highScoreText).gameObject.SetActive(true); ShortcutExtensions.DOPunchScale(highScoreText.transform, Vector3.one * 0.1f, 0.5f, 10, 1f); } if (!scoreWindow.skip) { yield return (object)new WaitForSecondsRealtime(3.5f); } CL_ProgressionManager instance = CL_ProgressionManager.instance; if (instance != null) { UI_ProgressionUnlockList deathList = instance.deathList; if (deathList != null) { deathList.Check(); } } void UpdateDistanceText(string meter) { int startIndex = Math.Min(fillerText.Length, meter.Length); string newValue = fillerText.Substring(startIndex); distanceText.text = distanceTemplate.Replace("{meter}", meter).Replace("{filler}", newValue); } void UpdateSpeedText(string mps) { int startIndex = Math.Min(fillerText.Length, mps.Length); string newValue = fillerText.Substring(startIndex); speedText.text = speedTemplate.Replace("{mps}", mps).Replace("{filler}", newValue); } } } [ConfigSection("Modules.ScoreScreenPatch", "This module replaces texts of\nstats, scores, medals, popups and leaderboards.")] public class ScoreScreenPatchSettings : ModuleSettingsBase { } [HarmonyPatch] public class StaticTextPatch : TextTranslator { [JsonProperty] public static Dictionary StaticTexts; [JsonIgnore] public static StaticTextPatchSettings ModuleSettings; [HarmonyPostfix] [HarmonyPatch(typeof(Text), "OnEnable")] public static void Postfix_Text_OnEnable(Text __instance) { if (ModuleBase.IsEnabled) { __instance.text = TextTranslator.GetTextTranslation(StaticTexts, __instance.text); } } [HarmonyPostfix] [HarmonyPatch(typeof(TextMeshPro), "Awake")] public static void Postfix_TextMeshPro_Awake(TextMeshPro __instance) { if (ModuleBase.IsEnabled) { ((TMP_Text)__instance).text = TextTranslator.GetTextTranslation(StaticTexts, ((TMP_Text)__instance).text); } } [HarmonyPostfix] [HarmonyPatch(typeof(TextMeshProUGUI), "Awake")] public static void Postfix_TextMeshProUGUI_Awake(TextMeshProUGUI __instance) { if (ModuleBase.IsEnabled) { ((TMP_Text)__instance).text = TextTranslator.GetTextTranslation(StaticTexts, ((TMP_Text)__instance).text); } } } [ConfigSection("Modules.StaticTextPatch", "This module replaces text content of Text/TMP_Text class instances.")] public class StaticTextPatchSettings : ModuleSettingsBase { } public class TemplateTranslator : TextTranslator { public static string GetTemplateTranslation(TemplateTranslations templateTranslations, string originalText) { if (string.IsNullOrWhiteSpace(originalText) || templateTranslations == null) { return originalText; } return templateTranslations.GetTemplateTranslation(originalText) ?? originalText; } } [HarmonyPatch] public class TextScrawlPatch : TemplateTranslator { [JsonProperty] public static Dictionary ScrawlTextTemplates; [JsonIgnore] public static TemplateTranslations ScrawlTemplates; [JsonIgnore] public static TextScrawlPatchSettings ModuleSettings; [OnDeserialized] private void OnDeserialized(StreamingContext _) { if (ModuleBase.IsEnabled) { ScrawlTemplates = new TemplateTranslations(ScrawlTextTemplates); } } [HarmonyPrefix] [HarmonyPatch(typeof(UT_TextScrawl), "ShowText")] public static void Prefix_TextScrawl_ShowText(ref string s) { if (ModuleBase.IsEnabled) { s = TemplateTranslator.GetTemplateTranslation(ScrawlTemplates, s); } } } [ConfigSection("Modules.TextScrawlPatch", "This module replaces text content of UT_TextScrawl class instances.")] public class TextScrawlPatchSettings : ModuleSettingsBase { } public class TextTranslator : ModuleBase { public static string GetTextTranslation(Dictionary textTranslations, string originalText) { if (string.IsNullOrWhiteSpace(originalText) || textTranslations == null || !textTranslations.ContainsKey(originalText)) { return originalText; } return textTranslations[originalText] ?? originalText; } } [HarmonyPatch] public class TrinketPatch : TextTranslator { [JsonProperty] public static Dictionary TrinketTypes; [JsonProperty] public static Dictionary TrinketTitles; [JsonProperty] public static Dictionary TrinketDescriptions; [JsonProperty] public static Dictionary TrinketFlavorTexts; [JsonProperty] public static string TrinketDescriptionTemplate; [JsonProperty] public static string TrinketLockedDescriptionTemplate; [JsonProperty] public static string TrinketUnlockProgressTemplate; [JsonProperty] public static string TooExpensiveText; [JsonProperty] public static string NoTrinketsAvailableDescription; [JsonProperty] public static string NoTrinketsInIronKnuckleDescription; [JsonIgnore] public static TrinketPatchSettings ModuleSettings; [HarmonyPostfix] [HarmonyPatch(typeof(Trinket), "IsUnlocked")] public static void Postfix_Trinket_IsUnlocked(Trinket __instance) { if (ModuleBase.IsEnabled) { __instance.title = TextTranslator.GetTextTranslation(TrinketTitles, __instance.title); __instance.description = TextTranslator.GetTextTranslation(TrinketDescriptions, __instance.description); __instance.flavorText = TextTranslator.GetTextTranslation(TrinketFlavorTexts, __instance.flavorText); } } [HarmonyPostfix] [HarmonyPatch(typeof(Trinket), "GetDescription")] public static string Postfix_Trinket_GetDescription(string __result, Trinket __instance) { if (!ModuleBase.IsEnabled) { return __result; } string translatedTrinketType = GetTranslatedTrinketType(__instance); string trinketTitle = GetTrinketTitle(__instance); string trinketDescription = GetTrinketDescription(__instance); string text = TrinketDescriptionTemplate ?? "{type}: {title}. {description}\n{flavorText}"; return text.Replace("{type}", translatedTrinketType).Replace("{title}", trinketTitle).Replace("{description}", trinketDescription) .Replace("{flavorText}", __instance.flavorText); } [HarmonyPostfix] [HarmonyPatch(typeof(Trinket), "GetLockedDescription")] public static string Postfix_Trinket_GetLockedDescription(string __result, Trinket __instance) { if (!ModuleBase.IsEnabled) { return __result; } string translatedTrinketType = GetTranslatedTrinketType(__instance); string trinketTitle = GetTrinketTitle(__instance); ProgressionUnlock progressionUnlock = __instance.progressionUnlock; string newValue = (progressionUnlock.showProgression ? GetTranslatedProgress(progressionUnlock) : ""); string text = TrinketLockedDescriptionTemplate ?? "Locked {type}: {title}\nUnlock Requirement: {unlockHint}{progress}"; return text.Replace("{type}", translatedTrinketType).Replace("{title}", trinketTitle).Replace("{unlockHint}", progressionUnlock.unlockHint) .Replace("{progress}", newValue); } [HarmonyPostfix] [HarmonyPatch(typeof(UI_TrinketPicker), "ReloadTrinkets")] public static void Postfix_TrinketPicker_ReloadTrinkets(UI_TrinketPicker __instance) { if (ModuleBase.IsEnabled) { TMP_Text descriptionText = __instance.descriptionText; M_Gamemode currentGamemode = __instance.currentGamemode; if (currentGamemode.availableTrinkets == null) { descriptionText.text = NoTrinketsAvailableDescription ?? "No trinkets available for this gamemode."; } if (currentGamemode.IsIronKnuckle()) { descriptionText.text = NoTrinketsInIronKnuckleDescription ?? "Trinkets are not available in Iron Knuckle"; } } } [HarmonyPostfix] [HarmonyPatch(typeof(UI_TrinketPicker), "UpdateTrinketActivation")] public static void Postfix_TrinketPicker_UpdateTrinketActivation(UI_TrinketPicker __instance) { if (ModuleBase.IsEnabled && __instance.costText.text == "Too expensive!") { __instance.costText.text = TooExpensiveText ?? "Too expensive!"; } } public static string GetTranslatedTrinketType(Trinket trinket) { return TextTranslator.GetTextTranslation(TrinketTypes, trinket.isBinding ? "Binding" : "Trinket"); } public static string GetTrinketTitle(Trinket trinket) { string text = (trinket.isBinding ? "" : ""); return text + "" + trinket.title + ""; } public static string GetTrinketDescription(Trinket trinket) { return trinket.isBinding ? ("" + trinket.description + "") : trinket.description; } public static string GetTranslatedProgress(ProgressionUnlock unlock) { string text = unlock.GetProgressString(); if (text == "N/A" && TrinketUnlockProgressTemplate != null) { string[] array = text.Split(new char[1] { '/' }, 2); if (array.Length == 2) { string newValue = array[0]; string newValue2 = array[1]; text = TrinketUnlockProgressTemplate.Replace("{current}", newValue).Replace("{required}", newValue2); } } return text; } } [ConfigSection("Modules.TrinketPatch", "This module replaces texts for trinkets (and bindings).")] public class TrinketPatchSettings : ModuleSettingsBase { } } namespace WKLocalizationLoader.FontFactory { public class CachedCharacterInfoData { [JsonProperty] public int CharCode; [JsonProperty] public float U; [JsonProperty] public float V; [JsonProperty] public float U2; [JsonProperty] public float V2; [JsonProperty] public int MinX; [JsonProperty] public int MaxX; [JsonProperty] public int MinY; [JsonProperty] public int MaxY; [JsonProperty] public int Advance; public CachedCharacterInfoData() { } public CachedCharacterInfoData(CharacterInfo characterInfo) { //IL_0009: Unknown result type (might be due to invalid IL or missing references) //IL_0017: Unknown result type (might be due to invalid IL or missing references) //IL_0029: Unknown result type (might be due to invalid IL or missing references) //IL_003b: Unknown result type (might be due to invalid IL or missing references) //IL_004d: Unknown result type (might be due to invalid IL or missing references) CharCode = characterInfo.index; U = ((CharacterInfo)(ref characterInfo)).uvBottomLeft.x; V = ((CharacterInfo)(ref characterInfo)).uvBottomLeft.y; U2 = ((CharacterInfo)(ref characterInfo)).uvTopRight.x; V2 = ((CharacterInfo)(ref characterInfo)).uvTopRight.y; MinX = ((CharacterInfo)(ref characterInfo)).minX; MaxX = ((CharacterInfo)(ref characterInfo)).maxX; MinY = ((CharacterInfo)(ref characterInfo)).minY; MaxY = ((CharacterInfo)(ref characterInfo)).maxY; Advance = ((CharacterInfo)(ref characterInfo)).advance; } public CharacterInfo ToCharacterInfo() { //IL_0002: 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_003c: 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_006e: Unknown result type (might be due to invalid IL or missing references) //IL_00bf: Unknown result type (might be due to invalid IL or missing references) CharacterInfo result = new CharacterInfo { index = CharCode }; ((CharacterInfo)(ref result)).uvBottomLeft = new Vector2(U, V); ((CharacterInfo)(ref result)).uvBottomRight = new Vector2(U2, V); ((CharacterInfo)(ref result)).uvTopLeft = new Vector2(U, V2); ((CharacterInfo)(ref result)).uvTopRight = new Vector2(U2, V2); ((CharacterInfo)(ref result)).minX = MinX; ((CharacterInfo)(ref result)).maxX = MaxX; ((CharacterInfo)(ref result)).minY = MinY; ((CharacterInfo)(ref result)).maxY = MaxY; ((CharacterInfo)(ref result)).advance = Advance; return result; } } public class CachedFontAssetData { [JsonProperty] public string FontName; [JsonProperty] public string FontVersion; [JsonProperty] public int AtlasWidth; [JsonProperty] public int AtlasHeight; [JsonProperty] public int AtlasPadding; [JsonProperty] public FilterMode TextureFilterMode; [JsonProperty] public GlyphRenderMode AtlasRenderMode; [JsonProperty] public string ShaderName; [JsonProperty] public FaceInfo FontFaceInfo; [JsonProperty] public List GlyphTable; [JsonProperty] public List CharacterUnicodes; public CachedFontAssetData() { } public CachedFontAssetData(TMP_FontAsset fontAsset) { //IL_004b: Unknown result type (might be due to invalid IL or missing references) //IL_0050: Unknown result type (might be due to invalid IL or missing references) //IL_0057: Unknown result type (might be due to invalid IL or missing references) //IL_005c: 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_007e: Unknown result type (might be due to invalid IL or missing references) FontName = ((Object)fontAsset).name; FontVersion = fontAsset.version; AtlasWidth = fontAsset.atlasWidth; AtlasHeight = fontAsset.atlasHeight; AtlasPadding = fontAsset.atlasPadding; TextureFilterMode = ((Texture)fontAsset.atlasTexture).filterMode; AtlasRenderMode = fontAsset.atlasRenderMode; ShaderName = ((Object)((TMP_Asset)fontAsset).material.shader).name; FontFaceInfo = fontAsset.faceInfo; GlyphTable = fontAsset.glyphTable.Select((Glyph g) => new CachedGlyphData(g)).ToList(); CharacterUnicodes = fontAsset.characterTable.Select((TMP_Character c) => ((TMP_TextElement)c).unicode).ToList(); } public void Deconstruct(out string fontName, out string fontVersion, out int atlasWidth, out int atlasHeight, out int atlasPadding, out FilterMode textureFilterMode, out GlyphRenderMode atlasRenderMode, out string shaderName, out FaceInfo faceInfo, out List glyphTable, out List characterTable) { //IL_002e: Unknown result type (might be due to invalid IL or missing references) //IL_0034: Expected I4, but got Unknown //IL_0037: Unknown result type (might be due to invalid IL or missing references) //IL_003d: Expected I4, but got Unknown //IL_0049: Unknown result type (might be due to invalid IL or missing references) //IL_004e: Unknown result type (might be due to invalid IL or missing references) fontName = FontName; fontVersion = FontVersion; atlasWidth = AtlasWidth; atlasHeight = AtlasHeight; atlasPadding = AtlasPadding; textureFilterMode = (FilterMode)(int)TextureFilterMode; atlasRenderMode = (GlyphRenderMode)(int)AtlasRenderMode; shaderName = ShaderName; faceInfo = FontFaceInfo; glyphTable = GlyphTable.Select((CachedGlyphData g) => g.ToGlyph()).ToList(); characterTable = ((IEnumerable)glyphTable).Select((Func)((Glyph g, int i) => new TMP_Character(CharacterUnicodes[i], g))).ToList(); } } public class CachedFontData { [JsonProperty] public string FontName; [JsonProperty] public int AtlasWidth; [JsonProperty] public int AtlasHeight; [JsonProperty] public FilterMode TextureFilterMode; [JsonProperty] public string ShaderName; [JsonProperty] public List CharacterInfos; public CachedFontData() { } public CachedFontData(Font font) { //IL_004c: 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) FontName = ((Object)font).name; AtlasWidth = font.material.mainTexture.width; AtlasHeight = font.material.mainTexture.height; TextureFilterMode = font.material.mainTexture.filterMode; ShaderName = ((Object)font.material.shader).name; CharacterInfos = font.characterInfo.Select((CharacterInfo c) => new CachedCharacterInfoData(c)).ToList(); } public void Deconstruct(out string fontName, out int atlasWidth, out int atlasHeight, out FilterMode textureFilterMode, out string shaderName, out CharacterInfo[] characterInfos) { //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_0022: Expected I4, but got Unknown fontName = FontName; atlasWidth = AtlasWidth; atlasHeight = AtlasHeight; textureFilterMode = (FilterMode)(int)TextureFilterMode; shaderName = ShaderName; characterInfos = CharacterInfos.Select((CachedCharacterInfoData c) => c.ToCharacterInfo()).ToArray(); } } public class CachedGlyphData { [JsonProperty] public int AtlasIndex; [JsonProperty] public uint Index; [JsonProperty] public float Scale; [JsonProperty] public CachedGlyphMetricsData GlyphMetrics; [JsonProperty] public CachedGlyphRectData GlyphRect; public CachedGlyphData() { } public CachedGlyphData(Glyph glyph) { //IL_002e: Unknown result type (might be due to invalid IL or missing references) //IL_003f: Unknown result type (might be due to invalid IL or missing references) AtlasIndex = glyph.atlasIndex; Index = glyph.index; Scale = glyph.scale; GlyphMetrics = new CachedGlyphMetricsData(glyph.metrics); GlyphRect = new CachedGlyphRectData(glyph.glyphRect); } public Glyph ToGlyph() { //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_0017: Unknown result type (might be due to invalid IL or missing references) //IL_0028: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Expected O, but got Unknown return new Glyph(Index, GlyphMetrics.ToGlyphMetrics(), GlyphRect.ToGlyphRect(), Scale, AtlasIndex); } } public class CachedGlyphMetricsData { [JsonProperty] public float Width; [JsonProperty] public float Height; [JsonProperty] public float HorizontalBearingX; [JsonProperty] public float HorizontalBearingY; [JsonProperty] public float HorizontalAdvance; public CachedGlyphMetricsData() { } public CachedGlyphMetricsData(GlyphMetrics glyphMetrics) { Width = ((GlyphMetrics)(ref glyphMetrics)).width; Height = ((GlyphMetrics)(ref glyphMetrics)).height; HorizontalBearingX = ((GlyphMetrics)(ref glyphMetrics)).horizontalBearingX; HorizontalBearingY = ((GlyphMetrics)(ref glyphMetrics)).horizontalBearingY; HorizontalAdvance = ((GlyphMetrics)(ref glyphMetrics)).horizontalAdvance; } public GlyphMetrics ToGlyphMetrics() { //IL_001e: Unknown result type (might be due to invalid IL or missing references) return new GlyphMetrics(Width, Height, HorizontalBearingX, HorizontalBearingY, HorizontalAdvance); } } public class CachedGlyphRectData { [JsonProperty] public int X; [JsonProperty] public int Y; [JsonProperty] public int Width; [JsonProperty] public int Height; public CachedGlyphRectData() { } public CachedGlyphRectData(GlyphRect glyphRect) { X = ((GlyphRect)(ref glyphRect)).x; Y = ((GlyphRect)(ref glyphRect)).y; Width = ((GlyphRect)(ref glyphRect)).width; Height = ((GlyphRect)(ref glyphRect)).height; } public GlyphRect ToGlyphRect() { //IL_0018: Unknown result type (might be due to invalid IL or missing references) return new GlyphRect(X, Y, Width, Height); } } public static class FontAssetBuilder { public static TMP_FontAsset CreateFontAsset(string filePath, string characters, FontAssetProperties fontAssetProperties, ManualLogSource logger = null) { //IL_004e: Unknown result type (might be due to invalid IL or missing references) //IL_0050: Unknown result type (might be due to invalid IL or missing references) //IL_0052: Unknown result type (might be due to invalid IL or missing references) //IL_0054: Unknown result type (might be due to invalid IL or missing references) //IL_0056: Unknown result type (might be due to invalid IL or missing references) //IL_0058: 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_005c: 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_0074: Unknown result type (might be due to invalid IL or missing references) //IL_0076: 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) var (fontName, fontVersion, scale, ascentLineOffset, descentLineOffset, pointSize, atlasWidth, atlasHeight, atlasPadding, singleAtlas, shaderName, glyphLoadFlags, textureFilterMode, glyphPackingMode, atlasRenderMode) = fontAssetProperties; return CreateFontAsset(filePath, fontName, fontVersion, characters, scale, ascentLineOffset, descentLineOffset, pointSize, atlasWidth, atlasHeight, atlasPadding, singleAtlas, shaderName, glyphLoadFlags, textureFilterMode, glyphPackingMode, atlasRenderMode, logger); } public static TMP_FontAsset CreateFontAsset(string filePath, string fontName, string fontVersion, string characters, float scale, float ascentLineOffset, float descentLineOffset, int pointSize, int atlasWidth, int atlasHeight, int atlasPadding, bool singleAtlas, string shaderName, GlyphLoadFlags glyphLoadFlags, FilterMode textureFilterMode, GlyphPackingMode glyphPackingMode, GlyphRenderMode atlasRenderMode, ManualLogSource logger = null) { //IL_0014: Unknown result type (might be due to invalid IL or missing references) //IL_001a: Invalid comparison between Unknown and I4 //IL_0054: Unknown result type (might be due to invalid IL or missing references) //IL_005a: Invalid comparison between Unknown and I4 //IL_0084: Unknown result type (might be due to invalid IL or missing references) //IL_0089: Unknown result type (might be due to invalid IL or missing references) //IL_00ce: Unknown result type (might be due to invalid IL or missing references) //IL_00f1: Unknown result type (might be due to invalid IL or missing references) //IL_010d: Unknown result type (might be due to invalid IL or missing references) //IL_01b0: Unknown result type (might be due to invalid IL or missing references) //IL_01b2: Unknown result type (might be due to invalid IL or missing references) //IL_0164: Unknown result type (might be due to invalid IL or missing references) //IL_0166: Unknown result type (might be due to invalid IL or missing references) //IL_0268: Unknown result type (might be due to invalid IL or missing references) if (logger != null) { logger.LogInfo((object)"[1/7] Initializing FontEngine."); } if ((int)FontEngine.InitializeFontEngine() > 0) { if (logger != null) { logger.LogError((object)"Failed to initialize FontEngine."); } return null; } if (logger != null) { logger.LogInfo((object)"[2/7] Loading FontFace."); } if ((int)FontEngine.LoadFontFace(filePath, pointSize) > 0) { if (logger != null) { logger.LogError((object)"Failed to load FontFace."); } return null; } TMP_FontAsset val = ScriptableObject.CreateInstance(); FaceInfo faceInfo = FontEngine.GetFaceInfo(); ((FaceInfo)(ref faceInfo)).scale = scale; ((FaceInfo)(ref faceInfo)).ascentLine = ((FaceInfo)(ref faceInfo)).ascentLine + ascentLineOffset; ((FaceInfo)(ref faceInfo)).descentLine = ((FaceInfo)(ref faceInfo)).descentLine + descentLineOffset; ((FaceInfo)(ref faceInfo)).lineHeight = ((FaceInfo)(ref faceInfo)).ascentLine - ((FaceInfo)(ref faceInfo)).descentLine; val.faceInfo = faceInfo; val.atlasWidth = atlasWidth; val.atlasHeight = atlasHeight; val.atlasPadding = atlasPadding; val.atlasRenderMode = atlasRenderMode; if (logger != null) { logger.LogInfo((object)"[3/7] Collecting Glyphs."); } List list = CollectGlyphInfos(characters, glyphLoadFlags); if (list.Count == 0) { if (logger != null) { logger.LogError((object)"Failed to collect any Glyphs."); } return null; } if (logger != null) { logger.LogInfo((object)"[4/7] Rendering Glyphs to Atlas(es)."); } List list2 = new List(); if (singleAtlas) { int renderedCount; Texture2D val2 = RenderGlyphsToAtlas(val, list, textureFilterMode, glyphPackingMode, out renderedCount); if (val2 == null || renderedCount == 0) { if (logger != null) { logger.LogError((object)"Failed to render any Glyphs to a single Atlas."); } return null; } list2.Add(val2); } else { list2 = RenderGlyphsToAtlases(val, list, textureFilterMode, glyphPackingMode, out var totalRenderedCount); if (list2 == null || totalRenderedCount == 0) { if (logger != null) { logger.LogError((object)"Failed to render any Glyphs to multiple Atlases."); } return null; } } val.isMultiAtlasTexturesEnabled = list2.Count > 1; val.atlasTextures = list2.ToArray(); if (logger != null) { logger.LogInfo((object)"[5/7] Initializing DictionaryLookupTables."); } val.ReadFontAssetDefinition(); if (logger != null) { logger.LogInfo((object)"[6/7] Adding Material."); } AddMaterial(val, shaderName); if (logger != null) { logger.LogInfo((object)"[7/7] Finalizing."); } val.atlasPopulationMode = (AtlasPopulationMode)0; ((Object)val).name = fontName; val.version = fontVersion; FontEngine.UnloadFontFace(); return val; } public static TMP_FontAsset CreateFontAssetFromDiskCache(string cacheDataPath, List atlasPaths, JsonSerializerSettings jsonSerializerSettings, ManualLogSource logger = null) { //IL_0097: Unknown result type (might be due to invalid IL or missing references) //IL_0099: Unknown result type (might be due to invalid IL or missing references) //IL_009b: Unknown result type (might be due to invalid IL or missing references) //IL_009d: Unknown result type (might be due to invalid IL or missing references) //IL_00a3: Unknown result type (might be due to invalid IL or missing references) //IL_00a5: Unknown result type (might be due to invalid IL or missing references) //IL_00c9: Unknown result type (might be due to invalid IL or missing references) //IL_00f0: Unknown result type (might be due to invalid IL or missing references) //IL_010d: Unknown result type (might be due to invalid IL or missing references) if (string.IsNullOrWhiteSpace(cacheDataPath) || atlasPaths.Any((string p) => string.IsNullOrWhiteSpace(p)) || jsonSerializerSettings == null) { return null; } if (logger != null) { logger.LogInfo((object)"[1/6] Loading CachedFontAssetData."); } string text = File.ReadAllText(cacheDataPath, Encoding.UTF8); JsonConvert.DeserializeObject(text, jsonSerializerSettings).Deconstruct(out var fontName, out var fontVersion, out var atlasWidth, out var atlasHeight, out var atlasPadding, out var textureFilterMode, out var atlasRenderMode, out var shaderName, out var faceInfo, out var glyphTable, out var characterTable); string name = fontName; string version = fontVersion; int atlasWidth2 = atlasWidth; int atlasHeight2 = atlasHeight; int atlasPadding2 = atlasPadding; FilterMode textureFilterMode2 = textureFilterMode; GlyphRenderMode atlasRenderMode2 = atlasRenderMode; string shaderName2 = shaderName; FaceInfo faceInfo2 = faceInfo; List glyphTable2 = glyphTable; List characterTable2 = characterTable; TMP_FontAsset val = ScriptableObject.CreateInstance(); if (logger != null) { logger.LogInfo((object)"[2/6] Loading cached FaceInfo."); } val.faceInfo = faceInfo2; val.atlasWidth = atlasWidth2; val.atlasHeight = atlasHeight2; val.atlasPadding = atlasPadding2; val.atlasRenderMode = atlasRenderMode2; if (logger != null) { logger.LogInfo((object)"[3/6] Loading cached Atlas(es)."); } List list = LoadAtlasesFromDisk(atlasPaths, atlasWidth2, atlasHeight2, textureFilterMode2, logger); if (list == null || list.Count == 0) { if (logger != null) { logger.LogError((object)"Failed to load cached Atlas(es)."); } return null; } val.isMultiAtlasTexturesEnabled = list.Count > 1; val.atlasTextures = list.ToArray(); if (logger != null) { logger.LogInfo((object)"[4/6] Initializing DictionaryLookupTables."); } val.glyphTable = glyphTable2; val.characterTable = characterTable2; val.ReadFontAssetDefinition(); if (logger != null) { logger.LogInfo((object)"[5/6] Adding Material."); } AddMaterial(val, shaderName2); if (logger != null) { logger.LogInfo((object)"[6/6] Finalizing."); } val.atlasPopulationMode = (AtlasPopulationMode)0; ((Object)val).name = name; val.version = version; return val; } public static void WriteFontAssetDiskCache(string cacheFolder, TMP_FontAsset fontAsset, JsonSerializerSettings jsonSerializerSettings, ManualLogSource logger = null) { if (!string.IsNullOrWhiteSpace(cacheFolder) && fontAsset != null && jsonSerializerSettings != null) { if (logger != null) { logger.LogInfo((object)"[1/3] Creating CacheFolder."); } Directory.CreateDirectory(cacheFolder); if (logger != null) { logger.LogInfo((object)"[2/3] Writing CachedFontAssetData."); } CachedFontAssetData cachedFontAssetData = new CachedFontAssetData(fontAsset); string contents = JsonConvert.SerializeObject((object)cachedFontAssetData, jsonSerializerSettings); string path = Path.Combine(cacheFolder, "CachedFontAssetData.json"); File.WriteAllText(path, contents); if (logger != null) { logger.LogInfo((object)"[3/3] Writing Atlas(es) cache."); } for (int i = 0; i < fontAsset.atlasTextures.Length; i++) { byte[] rawTextureData = fontAsset.atlasTextures[i].GetRawTextureData(); string path2 = Path.Combine(cacheFolder, $"RawAtlasTextureData_{i}"); File.WriteAllBytes(path2, rawTextureData); } } } public static List CollectGlyphInfos(string characters, GlyphLoadFlags glyphLoadFlags) { //IL_0058: Unknown result type (might be due to invalid IL or missing references) List list = new List(); if (string.IsNullOrEmpty(characters)) { return list; } IEnumerable enumerable = characters.Distinct().Select((Func)((char c) => c)); Glyph glyphInstance = default(Glyph); foreach (uint item in enumerable) { if (FontEngine.TryGetGlyphWithUnicodeValue(item, glyphLoadFlags, ref glyphInstance)) { list.Add(new GlyphInfo(item, glyphInstance)); } } return list; } public static List RenderGlyphsToAtlases(TMP_FontAsset fontAsset, List glyphInfos, FilterMode textureFilterMode, GlyphPackingMode glyphPackingMode, out int totalRenderedCount) { //IL_002a: 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) totalRenderedCount = 0; if (glyphInfos == null || glyphInfos.Count == 0) { return null; } List list = new List(); int renderedCount; for (int i = 0; i < glyphInfos.Count; i += renderedCount) { Texture2D val = RenderGlyphsToAtlas(fontAsset, glyphInfos, textureFilterMode, glyphPackingMode, out renderedCount, i, list.Count); if (val == null || renderedCount == 0) { break; } list.Add(val); totalRenderedCount += renderedCount; } return (totalRenderedCount > 0) ? list : null; } public static Texture2D RenderGlyphsToAtlas(TMP_FontAsset fontAsset, List glyphInfos, FilterMode textureFilterMode, GlyphPackingMode glyphPackingMode, out int renderedCount, int startGlyphInfoIndex = 0, int atlasIndex = 0) { //IL_0040: Unknown result type (might be due to invalid IL or missing references) //IL_0046: Expected O, but got Unknown //IL_0047: Unknown result type (might be due to invalid IL or missing references) //IL_0056: Unknown result type (might be due to invalid IL or missing references) //IL_005b: Unknown result type (might be due to invalid IL or missing references) //IL_0064: Unknown result type (might be due to invalid IL or missing references) //IL_007e: Unknown result type (might be due to invalid IL or missing references) //IL_00b3: Unknown result type (might be due to invalid IL or missing references) //IL_00b7: Unknown result type (might be due to invalid IL or missing references) renderedCount = 0; if (glyphInfos == null || glyphInfos.Count == 0) { return null; } startGlyphInfoIndex = Math.Min(glyphInfos.Count - 1, startGlyphInfoIndex); Texture2D val = new Texture2D(fontAsset.atlasWidth, fontAsset.atlasHeight, (TextureFormat)1, false); ((Texture)val).filterMode = textureFilterMode; FontEngine.ResetAtlasTexture(val); FaceInfo faceInfo = fontAsset.faceInfo; FontEngine.SetFaceSize(((FaceInfo)(ref faceInfo)).pointSize); List list = new List { new GlyphRect(0, 0, ((Texture)val).width, ((Texture)val).height) }; List list2 = new List(); Glyph glyphInstance = default(Glyph); for (int i = startGlyphInfoIndex; i < glyphInfos.Count; i++) { GlyphInfo glyphInfo = glyphInfos[i]; if (FontEngine.TryAddGlyphToTexture(glyphInfo.GlyphInstance.index, fontAsset.atlasPadding, glyphPackingMode, list, list2, fontAsset.atlasRenderMode, val, ref glyphInstance)) { glyphInfo.GlyphInstance = glyphInstance; AppendGlyphTable(fontAsset, glyphInfo.GlyphInstance, atlasIndex); AppendCharacterTable(fontAsset, glyphInfo.CharCode, glyphInfo.GlyphInstance); renderedCount++; continue; } break; } val.Apply(); return (renderedCount > 0) ? val : null; } public static void AppendGlyphTable(TMP_FontAsset fontAsset, Glyph glyph, int atlasIndex) { //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_002a: Expected O, but got Unknown if (fontAsset.glyphTable == null) { List list = (fontAsset.glyphTable = new List()); } if (glyph != null) { Glyph val = new Glyph(glyph); val.atlasIndex = atlasIndex; fontAsset.glyphTable.Add(val); } } public static void AppendCharacterTable(TMP_FontAsset fontAsset, uint charCode, Glyph glyph) { //IL_0025: Unknown result type (might be due to invalid IL or missing references) //IL_002b: Expected O, but got Unknown if (fontAsset.characterTable == null) { List list = (fontAsset.characterTable = new List()); } if (glyph != null) { TMP_Character item = new TMP_Character(charCode, glyph); fontAsset.characterTable.Add(item); } } public static void AddMaterial(TMP_FontAsset fontAsset, string shaderName = "") { //IL_000d: Unknown result type (might be due to invalid IL or missing references) //IL_0012: Unknown result type (might be due to invalid IL or missing references) //IL_0091: Unknown result type (might be due to invalid IL or missing references) //IL_0097: Expected O, but got Unknown //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_001f: Invalid comparison between Unknown and I4 //IL_0042: Unknown result type (might be due to invalid IL or missing references) //IL_0049: Invalid comparison between Unknown and I4 //IL_0021: Unknown result type (might be due to invalid IL or missing references) //IL_0028: Invalid comparison between Unknown and I4 //IL_004d: Unknown result type (might be due to invalid IL or missing references) //IL_0054: Invalid comparison between Unknown and I4 //IL_002c: Unknown result type (might be due to invalid IL or missing references) //IL_0033: Invalid comparison between Unknown and I4 //IL_0058: Unknown result type (might be due to invalid IL or missing references) //IL_005f: Invalid comparison between Unknown and I4 //IL_0037: Unknown result type (might be due to invalid IL or missing references) //IL_003e: Invalid comparison between Unknown and I4 string text; if (string.IsNullOrEmpty(shaderName)) { GlyphRenderMode atlasRenderMode = fontAsset.atlasRenderMode; if (1 == 0) { } if ((int)atlasRenderMode <= 4169) { if ((int)atlasRenderMode == 4134 || (int)atlasRenderMode == 4165 || (int)atlasRenderMode == 4169) { goto IL_0063; } } else if ((int)atlasRenderMode == 8230 || (int)atlasRenderMode == 16422 || (int)atlasRenderMode == 32806) { goto IL_0063; } text = "TextMeshPro/Bitmap"; goto IL_0073; } goto IL_007b; IL_0073: if (1 == 0) { } shaderName = text; goto IL_007b; IL_007b: Shader val = Shader.Find(shaderName) ?? Shader.Find("TextMeshPro/Bitmap"); Material val2 = new Material(val); val2.mainTexture = (Texture)(object)fontAsset.atlasTexture; val2.SetFloat(ShaderUtilities.ID_TextureWidth, (float)fontAsset.atlasWidth); val2.SetFloat(ShaderUtilities.ID_TextureHeight, (float)fontAsset.atlasHeight); if (shaderName == "TextMeshPro/Distance Field") { val2.SetFloat(ShaderUtilities.ID_GradientScale, (float)(fontAsset.atlasPadding + 1)); val2.SetFloat(ShaderUtilities.ID_WeightNormal, 0f); val2.SetFloat(ShaderUtilities.ID_WeightBold, 0f); } ((TMP_Asset)fontAsset).material = val2; ((TMP_Asset)fontAsset).materialHashCode = ((object)val2).GetHashCode(); return; IL_0063: text = "TextMeshPro/Distance Field"; goto IL_0073; } public static List LoadAtlasesFromDisk(List atlasPaths, int atlasWidth, int atlasHeight, FilterMode textureFilterMode, ManualLogSource logger = null) { //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_002d: Expected O, but got Unknown //IL_002f: Unknown result type (might be due to invalid IL or missing references) List list = new List(); foreach (string atlasPath in atlasPaths) { try { byte[] array = File.ReadAllBytes(atlasPath); Texture2D val = new Texture2D(atlasWidth, atlasHeight, (TextureFormat)1, false); ((Texture)val).filterMode = textureFilterMode; val.LoadRawTextureData(array); val.Apply(); list.Add(val); } catch (Exception ex) { if (logger != null) { logger.LogError((object)("An error occurred while loading \"" + atlasPath + "\".")); } if (logger != null) { logger.LogError((object)ex.Message); } } } return (list.Count > 0) ? list : null; } } public class FontAssetProperties { [JsonProperty] public string FileName; [JsonProperty(/*Could not decode attribute arguments.*/)] [DefaultValue("")] public string FontName; [JsonProperty(/*Could not decode attribute arguments.*/)] [DefaultValue("1.1.0")] public string FontVersion; [JsonProperty(/*Could not decode attribute arguments.*/)] [DefaultValue(1f)] public float Scale; [JsonProperty(/*Could not decode attribute arguments.*/)] [DefaultValue(0f)] public float AscentLineOffset; [JsonProperty(/*Could not decode attribute arguments.*/)] [DefaultValue(0f)] public float DescentLineOffset; [JsonProperty(/*Could not decode attribute arguments.*/)] [DefaultValue(64)] public int PointSize; [JsonProperty(/*Could not decode attribute arguments.*/)] [DefaultValue(4096)] public int AtlasWidth; [JsonProperty(/*Could not decode attribute arguments.*/)] [DefaultValue(4096)] public int AtlasHeight; [JsonProperty(/*Could not decode attribute arguments.*/)] [DefaultValue(5)] public int AtlasPadding; [JsonProperty(/*Could not decode attribute arguments.*/)] [DefaultValue(false)] public bool SingleAtlas; [JsonProperty(/*Could not decode attribute arguments.*/)] [DefaultValue("")] public string ShaderName; [JsonProperty(/*Could not decode attribute arguments.*/)] [DefaultValue(/*Could not decode attribute arguments.*/)] public GlyphLoadFlags FontGlyphLoadFlags; [JsonProperty(/*Could not decode attribute arguments.*/)] [DefaultValue(/*Could not decode attribute arguments.*/)] public FilterMode AtlasTextureFilterMode; [JsonProperty(/*Could not decode attribute arguments.*/)] [DefaultValue(/*Could not decode attribute arguments.*/)] public GlyphPackingMode AtlasGlyphPackingMode; [JsonProperty(/*Could not decode attribute arguments.*/)] [DefaultValue(/*Could not decode attribute arguments.*/)] public GlyphRenderMode AtlasRenderMode; public void Deconstruct(out string fontName, out string fontVersion, out float scale, out float ascentLineOffset, out float descentLineOffset, out int pointSize, out int atlasWidth, out int atlasHeight, out int atlasPadding, out bool singleAtlas, out string shaderName, out GlyphLoadFlags glyphLoadFlags, out FilterMode textureFilterMode, out GlyphPackingMode glyphPackingMode, out GlyphRenderMode atlasRenderMode) { //IL_0064: Unknown result type (might be due to invalid IL or missing references) //IL_006a: Expected I4, but got Unknown //IL_006d: Unknown result type (might be due to invalid IL or missing references) //IL_0073: Expected I4, but got Unknown //IL_0076: Unknown result type (might be due to invalid IL or missing references) //IL_007c: Expected I4, but got Unknown //IL_007f: Unknown result type (might be due to invalid IL or missing references) //IL_0085: Expected I4, but got Unknown fontName = FontName; fontVersion = FontVersion; scale = Scale; ascentLineOffset = AscentLineOffset; descentLineOffset = DescentLineOffset; pointSize = PointSize; atlasWidth = AtlasWidth; atlasHeight = AtlasHeight; atlasPadding = AtlasPadding; singleAtlas = SingleAtlas; shaderName = ShaderName; glyphLoadFlags = (GlyphLoadFlags)(int)FontGlyphLoadFlags; textureFilterMode = (FilterMode)(int)AtlasTextureFilterMode; glyphPackingMode = (GlyphPackingMode)(int)AtlasGlyphPackingMode; atlasRenderMode = (GlyphRenderMode)(int)AtlasRenderMode; } } public static class FontBuilder { public static Font CreateFont(string filePath, string characters, FontProperties fontProperties, ManualLogSource logger = null) { //IL_0036: Unknown result type (might be due to invalid IL or missing references) //IL_0038: Unknown result type (might be due to invalid IL or missing references) //IL_003a: Unknown result type (might be due to invalid IL or missing references) //IL_003c: 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_0040: Unknown result type (might be due to invalid IL or missing references) //IL_0042: Unknown result type (might be due to invalid IL or missing references) //IL_0044: Unknown result type (might be due to invalid IL or missing references) //IL_0052: Unknown result type (might be due to invalid IL or missing references) //IL_0054: Unknown result type (might be due to invalid IL or missing references) //IL_0056: Unknown result type (might be due to invalid IL or missing references) //IL_0058: Unknown result type (might be due to invalid IL or missing references) var (fontName, pointSize, verticalOffset, atlasWidth, atlasHeight, atlasPadding, shaderName, glyphLoadFlags, textureFilterMode, glyphPackingMode, atlasRenderMode) = fontProperties; return CreateFont(filePath, fontName, characters, pointSize, verticalOffset, atlasWidth, atlasHeight, atlasPadding, shaderName, glyphLoadFlags, textureFilterMode, glyphPackingMode, atlasRenderMode, logger); } public static Font CreateFont(string filePath, string fontName, string characters, int pointSize, float verticalOffset, int atlasWidth, int atlasHeight, int atlasPadding, string shaderName, GlyphLoadFlags glyphLoadFlags, FilterMode textureFilterMode, GlyphPackingMode glyphPackingMode, GlyphRenderMode atlasRenderMode, ManualLogSource logger = null) { //IL_0014: Unknown result type (might be due to invalid IL or missing references) //IL_001a: Invalid comparison between Unknown and I4 //IL_0053: Unknown result type (might be due to invalid IL or missing references) //IL_0059: Invalid comparison between Unknown and I4 //IL_007d: Unknown result type (might be due to invalid IL or missing references) //IL_0082: Unknown result type (might be due to invalid IL or missing references) //IL_00a3: Unknown result type (might be due to invalid IL or missing references) //IL_00f3: Unknown result type (might be due to invalid IL or missing references) //IL_00f5: Unknown result type (might be due to invalid IL or missing references) //IL_00f7: Unknown result type (might be due to invalid IL or missing references) //IL_0135: Unknown result type (might be due to invalid IL or missing references) //IL_013c: Expected O, but got Unknown //IL_0198: Unknown result type (might be due to invalid IL or missing references) if (logger != null) { logger.LogInfo((object)"[1/7] Initializing FontEngine."); } if ((int)FontEngine.InitializeFontEngine() > 0) { if (logger != null) { logger.LogError((object)"Failed to initialize FontEngine."); } return null; } if (logger != null) { logger.LogInfo((object)"[2/7] Loading FontFace."); } if ((int)FontEngine.LoadFontFace(filePath, pointSize) > 0) { if (logger != null) { logger.LogError((object)"Failed to load FontFace."); } return null; } FaceInfo faceInfo = FontEngine.GetFaceInfo(); verticalOffset += ((FaceInfo)(ref faceInfo)).descentLine; if (logger != null) { logger.LogInfo((object)"[3/7] Collecting Glyphs."); } List list = CollectGlyphInfos(characters, glyphLoadFlags); if (list.Count == 0) { if (logger != null) { logger.LogError((object)"Failed to collect any Glyphs."); } return null; } if (logger != null) { logger.LogInfo((object)"[4/7] Rendering Glyphs to Atlas."); } int renderedCount; List characterInfos; Texture2D val = RenderGlyphsToAtlas(list, pointSize, verticalOffset, atlasWidth, atlasHeight, atlasPadding, textureFilterMode, glyphPackingMode, atlasRenderMode, out renderedCount, out characterInfos); if (val == null || renderedCount == 0 || characterInfos.Count == 0) { if (logger != null) { logger.LogError((object)"Failed to render any Glyphs to Atlas."); } return null; } Font val2 = new Font(); if (logger != null) { logger.LogInfo((object)"[5/7] Populating CharacterInfos."); } val2.characterInfo = characterInfos.ToArray(); if (logger != null) { logger.LogInfo((object)"[6/7] Adding Material."); } AddMaterial(val2, val, shaderName); if (logger != null) { logger.LogInfo((object)"[7/7] Finalizing."); } ((Object)val2).name = fontName; FontEngine.UnloadFontFace(); return val2; } public static Font CreateFontFromDiskCache(string cacheDataPath, string atlasPath, JsonSerializerSettings jsonSerializerSettings, ManualLogSource logger = null) { //IL_0066: 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) //IL_0086: Unknown result type (might be due to invalid IL or missing references) //IL_00b2: Unknown result type (might be due to invalid IL or missing references) //IL_00b9: Expected O, but got Unknown if (string.IsNullOrWhiteSpace(cacheDataPath) || string.IsNullOrWhiteSpace(atlasPath) || jsonSerializerSettings == null) { return null; } if (logger != null) { logger.LogInfo((object)"[1/5] Loading CachedFontData."); } string text = File.ReadAllText(cacheDataPath, Encoding.UTF8); var (name, atlasWidth, atlasHeight, textureFilterMode, shaderName, characterInfo) = JsonConvert.DeserializeObject(text, jsonSerializerSettings); if (logger != null) { logger.LogInfo((object)"[2/5] Loading cached Atlas."); } Texture2D val2 = LoadAtlasFromDisk(atlasPath, atlasWidth, atlasHeight, textureFilterMode, logger); if (val2 == null) { if (logger != null) { logger.LogError((object)"Failed to load cached Atlas."); } return null; } Font val3 = new Font(); if (logger != null) { logger.LogInfo((object)"[3/5] Populating CharacterInfos."); } val3.characterInfo = characterInfo; if (logger != null) { logger.LogInfo((object)"[4/5] Adding Material."); } AddMaterial(val3, val2, shaderName); if (logger != null) { logger.LogInfo((object)"[5/5] Finalizing."); } ((Object)val3).name = name; return val3; } public static Font CreateFontFromOSFont(FontProperties fontProperties) { return string.IsNullOrEmpty(fontProperties.DefaultOSFont) ? null : Font.CreateDynamicFontFromOSFont(fontProperties.DefaultOSFont, 12); } public static void WriteFontDiskCache(string cacheFolder, Font font, JsonSerializerSettings jsonSerializerSettings, ManualLogSource logger = null) { if (!string.IsNullOrWhiteSpace(cacheFolder) && font != null && jsonSerializerSettings != null) { if (logger != null) { logger.LogInfo((object)"[1/3] Creating CacheFolder."); } Directory.CreateDirectory(cacheFolder); if (logger != null) { logger.LogInfo((object)"[2/3] Writing CachedFontData."); } CachedFontData cachedFontData = new CachedFontData(font); string contents = JsonConvert.SerializeObject((object)cachedFontData, jsonSerializerSettings); string path = Path.Combine(cacheFolder, "CachedFontData.json"); File.WriteAllText(path, contents); if (logger != null) { logger.LogInfo((object)"[3/3] Writing Atlas cache."); } Texture mainTexture = font.material.mainTexture; Texture2D val = (Texture2D)(object)((mainTexture is Texture2D) ? mainTexture : null); byte[] rawTextureData = val.GetRawTextureData(); string path2 = Path.Combine(cacheFolder, "RawAtlasTextureData"); File.WriteAllBytes(path2, rawTextureData); } } public static List CollectGlyphInfos(string characters, GlyphLoadFlags glyphLoadFlags) { //IL_0058: Unknown result type (might be due to invalid IL or missing references) List list = new List(); if (string.IsNullOrEmpty(characters)) { return list; } IEnumerable enumerable = characters.Distinct().Select((Func)((char c) => c)); Glyph glyphInstance = default(Glyph); foreach (uint item in enumerable) { if (FontEngine.TryGetGlyphWithUnicodeValue(item, glyphLoadFlags, ref glyphInstance)) { list.Add(new GlyphInfo(item, glyphInstance)); } } return list; } public static Texture2D RenderGlyphsToAtlas(List glyphInfos, int pointSize, float verticalOffset, int atlasWidth, int atlasHeight, int atlasPadding, FilterMode textureFilterMode, GlyphPackingMode glyphPackingMode, GlyphRenderMode atlasRenderMode, out int renderedCount, out List characterInfos) { //IL_002e: Unknown result type (might be due to invalid IL or missing references) //IL_0034: Expected O, but got Unknown //IL_0035: Unknown result type (might be due to invalid IL or missing references) //IL_0045: Unknown result type (might be due to invalid IL or missing references) //IL_0056: Unknown result type (might be due to invalid IL or missing references) //IL_008b: Unknown result type (might be due to invalid IL or missing references) //IL_008f: 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_00b4: Unknown result type (might be due to invalid IL or missing references) //IL_00b9: Unknown result type (might be due to invalid IL or missing references) renderedCount = 0; characterInfos = new List(); if (glyphInfos == null || glyphInfos.Count == 0) { return null; } Texture2D val = new Texture2D(atlasWidth, atlasHeight, (TextureFormat)1, false); ((Texture)val).filterMode = textureFilterMode; FontEngine.ResetAtlasTexture(val); FontEngine.SetFaceSize(pointSize); List list = new List { new GlyphRect(0, 0, atlasWidth, atlasHeight) }; List list2 = new List(); Glyph glyphInstance = default(Glyph); foreach (GlyphInfo glyphInfo in glyphInfos) { if (FontEngine.TryAddGlyphToTexture(glyphInfo.GlyphInstance.index, atlasPadding, glyphPackingMode, list, list2, atlasRenderMode, val, ref glyphInstance)) { glyphInfo.GlyphInstance = glyphInstance; CharacterInfo item = CreateCharacterInfo(verticalOffset, atlasWidth, atlasHeight, glyphInfo); characterInfos.Add(item); renderedCount++; continue; } break; } val.Apply(); return (renderedCount > 0) ? val : null; } public static CharacterInfo CreateCharacterInfo(float verticalOffset, int atlasWidth, int atlasHeight, GlyphInfo glyphInfo) { //IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_0020: Unknown result type (might be due to invalid IL or missing references) //IL_0027: 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) //IL_00ab: Unknown result type (might be due to invalid IL or missing references) //IL_00b0: Unknown result type (might be due to invalid IL or missing references) //IL_00b3: Unknown result type (might be due to invalid IL or missing references) if (glyphInfo == null) { throw new ArgumentNullException("GlyphInfo is null."); } GlyphRect glyphRect = glyphInfo.GlyphInstance.glyphRect; GlyphMetrics metrics = glyphInfo.GlyphInstance.metrics; return CreateCharacterInfo((int)glyphInfo.CharCode, (float)((GlyphRect)(ref glyphRect)).x / (float)atlasWidth, (float)((GlyphRect)(ref glyphRect)).y / (float)atlasHeight, (float)(((GlyphRect)(ref glyphRect)).x + ((GlyphRect)(ref glyphRect)).width) / (float)atlasWidth, (float)(((GlyphRect)(ref glyphRect)).y + ((GlyphRect)(ref glyphRect)).height) / (float)atlasHeight, (int)((GlyphMetrics)(ref metrics)).horizontalBearingX, (int)(((GlyphMetrics)(ref metrics)).horizontalBearingX + ((GlyphMetrics)(ref metrics)).width), (int)(((GlyphMetrics)(ref metrics)).horizontalBearingY - ((GlyphMetrics)(ref metrics)).height + verticalOffset), (int)(((GlyphMetrics)(ref metrics)).horizontalBearingY + verticalOffset), (int)((GlyphMetrics)(ref metrics)).horizontalAdvance); } public static CharacterInfo CreateCharacterInfo(int charCode, float u, float v, float u2, float v2, int minX, int maxX, int minY, int maxY, int advance) { //IL_0003: Unknown result type (might be due to invalid IL or missing references) //IL_0015: Unknown result type (might be due to invalid IL or missing references) //IL_0024: 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) //IL_0044: Unknown result type (might be due to invalid IL or missing references) //IL_0081: Unknown result type (might be due to invalid IL or missing references) //IL_0082: Unknown result type (might be due to invalid IL or missing references) //IL_0085: Unknown result type (might be due to invalid IL or missing references) CharacterInfo result = new CharacterInfo { index = charCode }; ((CharacterInfo)(ref result)).uvBottomLeft = new Vector2(u, v); ((CharacterInfo)(ref result)).uvBottomRight = new Vector2(u2, v); ((CharacterInfo)(ref result)).uvTopLeft = new Vector2(u, v2); ((CharacterInfo)(ref result)).uvTopRight = new Vector2(u2, v2); ((CharacterInfo)(ref result)).minX = minX; ((CharacterInfo)(ref result)).maxX = maxX; ((CharacterInfo)(ref result)).minY = minY; ((CharacterInfo)(ref result)).maxY = maxY; ((CharacterInfo)(ref result)).advance = advance; return result; } public static void AddMaterial(Font font, Texture2D atlas, string shaderName = "") { //IL_0038: Unknown result type (might be due to invalid IL or missing references) //IL_003e: Expected O, but got Unknown //IL_0047: Unknown result type (might be due to invalid IL or missing references) if (string.IsNullOrEmpty(shaderName)) { shaderName = "GUI/Text Shader"; } Shader val = Shader.Find(shaderName) ?? Shader.Find("GUI/Text Shader") ?? Shader.Find("UI/Default"); Material val2 = new Material(val); val2.mainTexture = (Texture)(object)atlas; val2.color = Color.white; font.material = val2; } public static Texture2D LoadAtlasFromDisk(string atlasPath, int atlasWidth, int atlasHeight, FilterMode textureFilterMode, ManualLogSource logger = null) { //IL_000d: Unknown result type (might be due to invalid IL or missing references) //IL_0013: Expected O, but got Unknown //IL_0014: Unknown result type (might be due to invalid IL or missing references) try { byte[] array = File.ReadAllBytes(atlasPath); Texture2D val = new Texture2D(atlasWidth, atlasHeight, (TextureFormat)1, false); ((Texture)val).filterMode = textureFilterMode; val.LoadRawTextureData(array); val.Apply(); return val; } catch (Exception ex) { if (logger != null) { logger.LogError((object)("An error occurred while loading \"" + atlasPath + "\".")); } if (logger != null) { logger.LogError((object)ex.Message); } return null; } } } public class FontProperties { [JsonProperty] public string FileName; [JsonProperty(/*Could not decode attribute arguments.*/)] [DefaultValue("")] public string FontName; [JsonProperty] public int PointSize; [JsonProperty(/*Could not decode attribute arguments.*/)] [DefaultValue(0f)] public float VerticalOffset; [JsonProperty(/*Could not decode attribute arguments.*/)] [DefaultValue(4096)] public int AtlasWidth; [JsonProperty(/*Could not decode attribute arguments.*/)] [DefaultValue(4096)] public int AtlasHeight; [JsonProperty(/*Could not decode attribute arguments.*/)] [DefaultValue(5)] public int AtlasPadding; [JsonProperty(/*Could not decode attribute arguments.*/)] [DefaultValue("")] public string ShaderName; [JsonProperty(/*Could not decode attribute arguments.*/)] [DefaultValue("")] public string DefaultOSFont; [JsonProperty(/*Could not decode attribute arguments.*/)] [DefaultValue(/*Could not decode attribute arguments.*/)] public GlyphLoadFlags FontGlyphLoadFlags; [JsonProperty(/*Could not decode attribute arguments.*/)] [DefaultValue(/*Could not decode attribute arguments.*/)] public FilterMode AtlasTextureFilterMode; [JsonProperty(/*Could not decode attribute arguments.*/)] [DefaultValue(/*Could not decode attribute arguments.*/)] public GlyphPackingMode AtlasGlyphPackingMode; [JsonProperty(/*Could not decode attribute arguments.*/)] [DefaultValue(/*Could not decode attribute arguments.*/)] public GlyphRenderMode AtlasRenderMode; public void Deconstruct(out string fontName, out int pointSize, out float verticalOffset, out int atlasWidth, out int atlasHeight, out int atlasPadding, out string shaderName, out GlyphLoadFlags glyphLoadFlags, out FilterMode textureFilterMode, out GlyphPackingMode glyphPackingMode, out GlyphRenderMode atlasRenderMode) { //IL_0040: Unknown result type (might be due to invalid IL or missing references) //IL_0046: Expected I4, but got Unknown //IL_0049: Unknown result type (might be due to invalid IL or missing references) //IL_004f: Expected I4, but got Unknown //IL_0052: Unknown result type (might be due to invalid IL or missing references) //IL_0058: Expected I4, but got Unknown //IL_005b: Unknown result type (might be due to invalid IL or missing references) //IL_0061: Expected I4, but got Unknown fontName = FontName; pointSize = PointSize; verticalOffset = VerticalOffset; atlasWidth = AtlasWidth; atlasHeight = AtlasHeight; atlasPadding = AtlasPadding; shaderName = ShaderName; glyphLoadFlags = (GlyphLoadFlags)(int)FontGlyphLoadFlags; textureFilterMode = (FilterMode)(int)AtlasTextureFilterMode; glyphPackingMode = (GlyphPackingMode)(int)AtlasGlyphPackingMode; atlasRenderMode = (GlyphRenderMode)(int)AtlasRenderMode; } } public class GlyphInfo { public uint CharCode; public Glyph GlyphInstance; public GlyphInfo(uint charCode, Glyph glyphInstance) { CharCode = charCode; GlyphInstance = glyphInstance; } } } namespace WKLocalizationLoader.Config { [AttributeUsage(AttributeTargets.Field, AllowMultiple = false, Inherited = false)] public class ConfigEntryAttribute : Attribute { public string Key { get; } public object DefaultValue { get; } public string EntryDescription { get; } public ConfigEntryAttribute(string key, object defaultValue, string entryDescription) { Key = key; DefaultValue = defaultValue; EntryDescription = entryDescription; } public void Deconstruct(out string key, out object defaultValue, out string entryDescription) { key = Key; defaultValue = DefaultValue; entryDescription = EntryDescription; } } [AttributeUsage(AttributeTargets.Class, AllowMultiple = false, Inherited = false)] public class ConfigSectionAttribute : Attribute { public string Section { get; } public string ModuleDescription { get; } public ConfigSectionAttribute(string section, string moduleDescription = null) { Section = section; ModuleDescription = moduleDescription; } public void Deconstruct(out string section, out string moduleDescription) { section = Section; moduleDescription = ModuleDescription; } } } namespace System.Runtime.CompilerServices { [AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)] internal sealed class IgnoresAccessChecksToAttribute : Attribute { public IgnoresAccessChecksToAttribute(string assemblyName) { } } }