Please disclose if any significant portion of your mod was created using AI tools by adding the 'AI Generated' category. Failing to do so may result in the mod being removed from Thunderstore.
Decompiled source of Test RTLC v0.0.14
BepInEx/plugins/RTLC/RTLC.dll
Decompiled 2 years agousing System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.Globalization; using System.IO; using System.Linq; using System.Linq.Expressions; using System.Reflection; using System.Reflection.Emit; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Security; using System.Security.Permissions; using System.Text; using System.Text.RegularExpressions; using BepInEx; using BepInEx.Bootstrap; using BepInEx.Configuration; using BepInEx.Logging; using GameNetcodeStuff; using HarmonyLib; using Microsoft.CodeAnalysis; using Mono.Cecil; using Mono.Cecil.Cil; using Mono.Collections.Generic; using MonoMod.Cil; using MonoMod.Utils; using Newtonsoft.Json; using RTLC.API; using RTLC.API.LethalExpansion; using RTLC.Extensions; using RTLC.Helpers; using RTLC.SmartFormat; using SmartFormat; using SmartFormat.Core.Extensions; using SmartFormat.Core.Parsing; using SmartFormat.Core.Settings; using SmartFormat.Extensions; using SmartFormat.ZString; using Steamworks.Data; using TMPro; using Unity.Netcode; using UnityEngine; using UnityEngine.EventSystems; using UnityEngine.SceneManagement; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")] [assembly: AssemblyCompany("RTLC")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("0.0.14.0")] [assembly: AssemblyInformationalVersion("0.0.14+3c4897e2d7da14b6cd0bf57e46b3ec36b73519af")] [assembly: AssemblyProduct("RTLC")] [assembly: AssemblyTitle("RTLC")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("0.0.14.0")] [module: UnverifiableCode] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)] internal sealed class NullableAttribute : Attribute { public readonly byte[] NullableFlags; public NullableAttribute(byte P_0) { NullableFlags = new byte[1] { P_0 }; } public NullableAttribute(byte[] P_0) { NullableFlags = P_0; } } [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)] internal sealed class NullableContextAttribute : Attribute { public readonly byte Flag; public NullableContextAttribute(byte P_0) { Flag = P_0; } } [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)] internal sealed class RefSafetyRulesAttribute : Attribute { public readonly int Version; public RefSafetyRulesAttribute(int P_0) { Version = P_0; } } } namespace RTLC { public class RTLCConfiguration { public ConfigEntry<bool> AutoClearUntranslatedOnAwake { get; private set; } internal RTLCConfiguration() { ConfigFile config = ((BaseUnityPlugin)RTLCPlugin.Instance).Config; AutoClearUntranslatedOnAwake = config.Bind<bool>("General", "ClearUntranslatedOnAwake", true, (ConfigDescription)null); } } [BepInPlugin("RTLC", "RTLC", "0.0.14")] [BepInDependency(/*Could not decode attribute arguments.*/)] [BepInDependency(/*Could not decode attribute arguments.*/)] [BepInDependency(/*Could not decode attribute arguments.*/)] [BepInDependency(/*Could not decode attribute arguments.*/)] [BepInDependency(/*Could not decode attribute arguments.*/)] [BepInDependency(/*Could not decode attribute arguments.*/)] public class RTLCPlugin : BaseUnityPlugin { public static RTLCPlugin Instance { get; private set; } public RTLCConfiguration Config { get; private set; } internal ManualLogSource Logger { get; private set; } internal string WorkingDirectory { get; private set; } internal Harmony Harmony { get; private set; } private void Awake() { //IL_00e1: Unknown result type (might be due to invalid IL or missing references) //IL_00eb: Expected O, but got Unknown Instance = this; Logger = ((BaseUnityPlugin)this).Logger; WorkingDirectory = new FileInfo(((BaseUnityPlugin)this).Info.Location).DirectoryName; Config = new RTLCConfiguration(); foreach (MethodInfo item in from m in typeof(RTLCPlugin).Assembly.GetTypes().SelectMany((Type t) => t.GetMethods(BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic)) where m.GetCustomAttribute<InitializeOnAwakeAttribute>() != null select m) { item.Invoke(null, null); Logger.LogInfo((object)("Initialized " + item.GetReadableString())); } Harmony = new Harmony("RTLC"); Harmony.PatchAll(typeof(RTLCPlugin).Assembly); LethalExpansionTranslation.TryAddScrapsToUntranslated(); Logger.LogInfo((object)"Plugin RTLC is loaded!"); } } internal static class KnownPluginDependency { public const string c_HDLethalCompany = "HDLethalCompany"; public const string c_ShipLoot = "com.github.tinyhoot.ShipLoot"; public const string c_LethalExpansionCore = "com.github.lethalmods.lethalexpansioncore"; public const string c_LethalExpansion = "LethalExpansion"; public const string c_LethalThings = "evaisa.lethalthings"; public const string c_FacilityMeltdown = "me.loaforc.facilitymeltdown"; } internal static class Translation { private const char c_LineFeedChar = '\n'; private const char c_CarriageReturnChar = '\r'; private const char c_EmptySpaceChar = '\u200b'; private const char c_SpaceChar = ' '; private static readonly Dictionary<string, string> s_Translations; private static readonly Dictionary<Regex, string> s_RegexTranslations; private static readonly CultureInfo s_RussianCultureInfo; private static readonly SmartFormatter s_SmartFormatter; private static Dictionary<string, string> s_UntranslatedCache; private static string s_UntranslatedFilePath; private static readonly ZStringBuilder s_ZStringBuilder; public static string Concat(string str0, string str1) { ZStringBuilder stringBuilder = GetStringBuilder(); stringBuilder.Append(str0); stringBuilder.Append(str1); return GetLocalizedText(((object)stringBuilder).ToString(), shouldIgnoreKey: true); } public static string Concat(string str0, string str1, string str2) { ZStringBuilder stringBuilder = GetStringBuilder(); stringBuilder.Append(str0); stringBuilder.Append(str1); stringBuilder.Append(str2); return GetLocalizedText(((object)stringBuilder).ToString(), shouldIgnoreKey: true); } public static string Concat(string str0, string str1, string str2, string str3) { ZStringBuilder stringBuilder = GetStringBuilder(); stringBuilder.Append(str0); stringBuilder.Append(str1); stringBuilder.Append(str2); stringBuilder.Append(str3); return GetLocalizedText(((object)stringBuilder).ToString(), shouldIgnoreKey: true); } public static string Concat(params string[] values) { ZStringBuilder stringBuilder = GetStringBuilder(); foreach (string text in values) { stringBuilder.Append(text); } return GetLocalizedText(((object)stringBuilder).ToString(), shouldIgnoreKey: true); } static Translation() { //IL_0038: Unknown result type (might be due to invalid IL or missing references) //IL_0042: Expected O, but got Unknown //IL_0048: Unknown result type (might be due to invalid IL or missing references) //IL_004e: Expected O, but got Unknown //IL_0062: Unknown result type (might be due to invalid IL or missing references) //IL_0067: Unknown result type (might be due to invalid IL or missing references) //IL_006f: Expected O, but got Unknown s_Translations = new Dictionary<string, string>(); s_RegexTranslations = new Dictionary<Regex, string>(); s_RussianCultureInfo = new CultureInfo("ru-RU"); s_UntranslatedCache = new Dictionary<string, string>(); s_UntranslatedFilePath = string.Empty; s_ZStringBuilder = new ZStringBuilder(false); SmartSettings.IsThreadSafeMode = false; ParserSettings val = new ParserSettings(); val.AddCustomSelectorChars((IList<char>)new List<char>(1) { '"' }); SmartSettings val2 = new SmartSettings { Parser = val }; s_SmartFormatter = Smart.CreateDefaultSmartFormat(val2).AddExtensions((ISource[])(object)new ISource[6] { (ISource)new StringToNumberSource(), (ISource)new TranslationSource(), (ISource)new SelectorTextToStringSource(), (ISource)new ReplaceNewLinesSource(), (ISource)new AppendStringSource(), (ISource)new CollectionCountSource() }); s_SmartFormatter.RemoveFormatterExtension<IsMatchFormatter>(); s_SmartFormatter.AddExtensions((IFormatter[])(object)new IFormatter[2] { new IsMatchFormatterEx(), new IsMatchesFormatterEx() }); } [InitializeOnAwake] public static void LoadTranslation() { string text = Path.Combine(RTLCPlugin.Instance.WorkingDirectory, "Translations"); s_UntranslatedFilePath = Path.Combine(text, "Untranslated.json"); CreateUntranslatedFile(); foreach (string item in Directory.EnumerateFiles(text, "*.json", SearchOption.AllDirectories)) { string fileName = Path.GetFileName(item); if (!(fileName == "Untranslated.json")) { ReadTranslationFile(item); } } } private static void ReadTranslationFile(string? translationFile) { IDictionary<string, string> dictionary = JsonConvert.DeserializeObject<IDictionary<string, string>>(File.ReadAllText(translationFile)); foreach (KeyValuePair<string, string> item in dictionary) { if (item.Key.StartsWith("__")) { continue; } if (item.Key.StartsWith("r:")) { Dictionary<Regex, string> dictionary2 = s_RegexTranslations; string key = item.Key; dictionary2.Add(new Regex(key.Substring(2, key.Length - 2), RegexOptions.Multiline | RegexOptions.Compiled, TimeSpan.FromMilliseconds(500.0)), item.Value); continue; } string text = item.Key; if (text.StartsWith("key:")) { ReadOnlySpan<char> readOnlySpan = text.AsSpan(); ReadOnlySpan<char> span = readOnlySpan.Slice(4); int num = span.IndexOf(':'); if (num == -1) { RTLCPlugin.Instance.Logger.LogWarning((object)(item.Key + " has invalid key reference. Check the file: " + Path.GetFileName(translationFile))); continue; } readOnlySpan = span.Slice(num + 1); text = readOnlySpan.ToString(); readOnlySpan = span.Slice(0, num); string key2 = readOnlySpan.ToString(); AddTranslation(key2, item.Value); } AddTranslation(text, item.Value); } } private static void CreateUntranslatedFile() { if (File.Exists(s_UntranslatedFilePath)) { if (RTLCPlugin.Instance.Config.AutoClearUntranslatedOnAwake.Value) { File.Delete(s_UntranslatedFilePath); s_UntranslatedCache = new Dictionary<string, string>(); } else { s_UntranslatedCache = JsonConvert.DeserializeObject<Dictionary<string, string>>(File.ReadAllText(s_UntranslatedFilePath)) ?? new Dictionary<string, string>(); } } } private static void AddTranslation(string key, string translation) { if (s_Translations.ContainsKey(key)) { RTLCPlugin.Instance.Logger.LogWarning((object)(key + " already exists.")); } else { s_Translations[key] = translation; } } private static void AddUntranslatedText(string? key, string? originalTranslation = null) { if (!s_UntranslatedCache.ContainsKey(key)) { s_UntranslatedCache[key] = originalTranslation ?? key; File.WriteAllText(s_UntranslatedFilePath, JsonConvert.SerializeObject((object)s_UntranslatedCache, (Formatting)1)); } } private static bool ShouldIgnoreTranslation(string? text) { if (string.IsNullOrWhiteSpace(text) || text.Length < 3) { return true; } if (Regex.IsMatch(text, "^\\[\\w*\\]\\n*$")) { return true; } char c = text[0]; int num = -1; ReadOnlySpan<char> readOnlySpan = text.AsSpan(); for (int i = 0; i < readOnlySpan.Length; i++) { char c2 = readOnlySpan[i]; if (c2 == '\n' || c2 == '\r' || c2 == '\u200b' || c2 == ' ' || c2 == c || (c2 >= '\0' && c2 <= '?') || (c2 >= '[' && c2 <= '`') || (c2 >= '{' && c2 <= '\u007f') || (c2 >= 'Ѐ' && c2 <= 'ӿ')) { num++; } } return text.Length - num < 3; } internal static string Format(string format, object arg0) { format = GetLocalizedText(format, shouldIgnoreKey: true); ZStringBuilder stringBuilder = GetStringBuilder(); stringBuilder.AppendFormat<object>(format, arg0); return GetLocalizedText(((object)stringBuilder).ToString(), shouldIgnoreKey: true); } internal static string Format(string format, object arg0, object arg1) { format = GetLocalizedText(format, shouldIgnoreKey: true); ZStringBuilder stringBuilder = GetStringBuilder(); stringBuilder.AppendFormat<object, object>(format, arg0, arg1); return GetLocalizedText(((object)stringBuilder).ToString(), shouldIgnoreKey: true); } internal static string Format(string format, object arg0, object arg1, object arg2) { format = GetLocalizedText(format, shouldIgnoreKey: true); ZStringBuilder stringBuilder = GetStringBuilder(); stringBuilder.AppendFormat<object, object, object>(format, arg0, arg1, arg2); return GetLocalizedText(((object)stringBuilder).ToString(), shouldIgnoreKey: true); } internal static string Format(string format, params object[] args) { format = GetLocalizedText(format, shouldIgnoreKey: true); ZStringBuilder stringBuilder = GetStringBuilder(); stringBuilder.AppendFormat<object[]>(format, args); return GetLocalizedText(((object)stringBuilder).ToString(), shouldIgnoreKey: true); } private static ZStringBuilder GetStringBuilder() { s_ZStringBuilder.Clear(); return s_ZStringBuilder; } internal static string GetLocalizedText(string? key) { return GetLocalizedText(key, key, shouldIgnoreKey: false); } internal static string GetLocalizedText(string? key, bool shouldIgnoreKey) { return GetLocalizedText(key, key, shouldIgnoreKey); } internal static string GetLocalizedText(string? key, string? originalTranslation) { return GetLocalizedText(key, originalTranslation, shouldIgnoreKey: false); } internal static string GetLocalizedText(string? key, string? originalTranslation, bool shouldIgnoreKey) { if (ShouldIgnoreTranslation(originalTranslation) || s_Translations.ContainsValue(key)) { return originalTranslation; } if (s_Translations.TryGetValue(key, out string value)) { return s_SmartFormatter.Format((IFormatProvider)s_RussianCultureInfo, value, new object[1] { new { Original = originalTranslation } }); } if (s_UntranslatedCache.ContainsKey(key)) { return originalTranslation; } foreach (KeyValuePair<Regex, string> s_RegexTranslation in s_RegexTranslations) { Match match = s_RegexTranslation.Key.Match(originalTranslation); if (match.Success) { List<string> matches = (from Group grp in match.Groups select grp.Value).Skip(1).ToList(); return s_SmartFormatter.Format((IFormatProvider)s_RussianCultureInfo, s_RegexTranslation.Value, new object[1] { new { Original = originalTranslation, Matches = matches } }); } } if (!shouldIgnoreKey) { AddUntranslatedText(key, originalTranslation); } return originalTranslation; } } public static class MyPluginInfo { public const string PLUGIN_GUID = "RTLC"; public const string PLUGIN_NAME = "RTLC"; public const string PLUGIN_VERSION = "0.0.14"; } } namespace RTLC.Textures { [HarmonyPatch] internal static class ReplaceTexturesHandler { private static AssetBundle s_AssetBundle; [InitializeOnAwake] public static void LoadTextures() { s_AssetBundle = AssetBundle.LoadFromFile(Path.Combine(RTLCPlugin.Instance.WorkingDirectory, "Bundles", "rtlc.main")); _ = (Object)(object)s_AssetBundle == (Object)null; } [HarmonyPatch(typeof(StartOfRound), "Start")] [HarmonyPostfix] [HarmonyPriority(0)] private static void StartOfRoundLoaded() { ReplaceTextures(); } private static void ReplaceTextures() { Texture2D[] array = Resources.FindObjectsOfTypeAll<Texture2D>(); foreach (Texture2D val in array) { string name = ((Object)val).name; if (!string.IsNullOrEmpty(name)) { Texture2D val2 = s_AssetBundle.LoadAsset<Texture2D>(name); if (!((Object)(object)val2 == (Object)null)) { ImageConversion.LoadImage(val, ImageConversion.EncodeToPNG(val2)); } } } } } } namespace RTLC.Texts { [HarmonyPatch] internal static class LoadCyrillicFonts { private static TMP_FontAsset? s_TransmitFontAsset; private static TMP_FontAsset? s_MainFontAsset; private static TMP_FontAsset? s_MainBigFontAsset; private static Shader s_FontShader; private static bool s_IgnoreAwake; [InitializeOnAwake] public static void LoadFonts() { AssetBundle val = AssetBundle.LoadFromFile(Path.Combine(RTLCPlugin.Instance.WorkingDirectory, "Bundles", "rtlcfont.assetbundle")); s_MainFontAsset = val.LoadAsset<TMP_FontAsset>("Assets/Fonts/3270-Regular.asset"); s_MainBigFontAsset = val.LoadAsset<TMP_FontAsset>("Assets/Fonts/3270-Big.asset"); s_TransmitFontAsset = val.LoadAsset<TMP_FontAsset>("Assets/Fonts/3716-font.asset"); s_FontShader = val.LoadAsset<Shader>("Assets/TextMesh Pro/Shaders/TMP_SDF SSD.shader"); TMP_Settings.fallbackFontAssets.Add(s_MainFontAsset); } [HarmonyPatch(typeof(TMP_FontAsset), "Awake")] [HarmonyPrefix] private static void LoadFontAsset(TMP_FontAsset __instance) { if (!s_IgnoreAwake) { __instance.atlasPopulationMode = (AtlasPopulationMode)0; if (((Object)__instance).name.StartsWith("edunline")) { __instance.fallbackFontAssetTable.Add(CreateVariant(__instance, s_TransmitFontAsset)); } else { __instance.fallbackFontAssetTable.Add(CreateVariant(__instance, s_MainFontAsset)); } } } private static TMP_FontAsset CreateVariant(TMP_FontAsset original, TMP_FontAsset dst) { //IL_0028: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Expected O, but got Unknown //IL_000e: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)dst == (Object)(object)s_MainFontAsset && original.creationSettings.pointSize > 110) { dst = s_MainBigFontAsset; } Material val = new Material(s_FontShader); val.CopyMatchingPropertiesFromMaterial(((TMP_Asset)original).material); val.shaderKeywords = ((TMP_Asset)original).material.shaderKeywords; val.mainTexture = (Texture)(object)dst.atlasTexture; val.SetFloat("_TextureWidth", (float)dst.atlasWidth); val.SetFloat("_TextureHeight", (float)dst.atlasHeight); s_IgnoreAwake = true; dst = Object.Instantiate<TMP_FontAsset>(dst); ((TMP_Asset)dst).material = val; s_IgnoreAwake = false; return dst; } } internal static class ReplaceTextOnSceneLoaded { [InitializeOnAwake] private static void Init() { SceneManager.sceneLoaded += SceneManager_sceneLoaded; } private static void SceneManager_sceneLoaded(Scene scene, LoadSceneMode mode) { string name = ((Scene)(ref scene)).name; if (!name.Equals("InitScene") && !name.Equals("InitSceneLaunchOptions") && !name.Equals("MainMenu") && !name.Equals("SampleSceneRelay")) { return; } UIBehaviour[] array = Object.FindObjectsOfType<UIBehaviour>(true); foreach (UIBehaviour val in array) { TextMeshProUGUI val2 = (TextMeshProUGUI)(object)((val is TextMeshProUGUI) ? val : null); if (val2 != null) { ((TMP_Text)val2).text = Translation.GetLocalizedText(((TMP_Text)val2).text); continue; } TMP_Dropdown val3 = (TMP_Dropdown)(object)((val is TMP_Dropdown) ? val : null); if (val3 == null || val3.options == null) { continue; } foreach (OptionData option in val3.options) { option.text = Translation.GetLocalizedText(option.text); } } } } } namespace RTLC.SmartFormat { internal class AppendStringSource : Source { public override bool TryEvaluateSelector(ISelectorInfo selectorInfo) { if (selectorInfo.CurrentValue is string text && selectorInfo.SelectorText.StartsWith("Append_")) { string selectorText = selectorInfo.SelectorText; selectorInfo.Result = text + selectorText.Substring(7, selectorText.Length - 7); return true; } return false; } } internal class CollectionCountSource : Source { public override bool TryEvaluateSelector(ISelectorInfo selectorInfo) { if (selectorInfo.CurrentValue is ICollection collection && selectorInfo.SelectorText.Equals("Count")) { selectorInfo.Result = collection.Count; return true; } return false; } } internal class IsMatchesFormatterEx : IFormatter { private const char c_SplitChar = '|'; public string Name { get; set; } = "ismatches"; public bool CanAutoDetect { get; set; } public bool TryEvaluateFormat(IFormattingInfo formattingInfo) { //IL_0178: Unknown result type (might be due to invalid IL or missing references) //IL_017f: Expected O, but got Unknown if (formattingInfo.CurrentValue == null) { return false; } string pattern = formattingInfo.FormatterOptions.Replace("\n", "\\n"); Format format = formattingInfo.Format; IList<Format> list = ((format != null) ? format.Split('|') : null); if (list == null || list.Count != 2) { if (list != null && list.Count == 0) { return true; } Placeholder placeholder = formattingInfo.Placeholder; if (string.IsNullOrEmpty((placeholder != null) ? placeholder.FormatterName : null)) { return false; } Placeholder placeholder2 = formattingInfo.Placeholder; throw new FormatException("Formatter named '" + ((placeholder2 != null) ? placeholder2.FormatterName : null) + "' requires at least 2 format options."); } MatchCollection matchCollection = Regex.Matches(formattingInfo.CurrentValue.ToString(), pattern, RegexOptions.Multiline, TimeSpan.FromMilliseconds(500.0)); if (matchCollection.Count == 0) { formattingInfo.FormatAsChild(list[1], formattingInfo.CurrentValue); return true; } List<string> list2 = matchCollection.SelectMany((Match m) => m.Groups.Select((Group g) => g.Value)).ToList(); int num = list2.Count / matchCollection.Count; for (int num2 = list2.Count - num; num2 >= 0; num2 -= num) { list2.RemoveAt(num2); } foreach (FormatItem item in list[0].Items) { Placeholder val = (Placeholder)(object)((item is Placeholder) ? item : null); if (val != null) { KeyValuePair<string, object> keyValuePair = new KeyValuePair<string, object>("m", list2); Format(formattingInfo, val, keyValuePair); continue; } LiteralText val2 = (LiteralText)item; Format format2 = formattingInfo.Format; Format val3 = ((format2 != null) ? format2.Substring(((FormatItem)val2).StartIndex - ((FormatItem)formattingInfo.Format).StartIndex, ((FormatItem)val2).Length) : null); try { if (val3 != null) { formattingInfo.FormatAsChild(val3, formattingInfo.CurrentValue); } } finally { ((IDisposable)val3)?.Dispose(); } } return true; } private void Format(IFormattingInfo formattingInfo, Placeholder placeholder, object matchingGroupValues) { Format format = formattingInfo.Format; Format val = ((format != null) ? format.Substring(((FormatItem)placeholder).StartIndex - ((FormatItem)formattingInfo.Format).StartIndex, ((FormatItem)placeholder).Length) : null); try { if (val == null) { return; } if (placeholder.GetSelectors().Count > 0) { Selector obj = placeholder.GetSelectors()[0]; if (((obj != null) ? ((FormatItem)obj).RawText : null) == "m") { formattingInfo.FormatAsChild(val, matchingGroupValues); return; } } formattingInfo.FormatAsChild(val, formattingInfo.CurrentValue); } finally { ((IDisposable)val)?.Dispose(); } } } internal class IsMatchFormatterEx : IFormatter { private const char c_SplitChar = '|'; public string Name { get; set; } = "ismatch"; public bool CanAutoDetect { get; set; } public bool TryEvaluateFormat(IFormattingInfo formattingInfo) { //IL_0159: Unknown result type (might be due to invalid IL or missing references) //IL_0160: Expected O, but got Unknown if (formattingInfo.CurrentValue == null) { return false; } string pattern = formattingInfo.FormatterOptions.Replace("\n", "\\n"); Format format = formattingInfo.Format; IList<Format> list = ((format != null) ? format.Split('|') : null); if (list == null || list.Count != 2) { if (list != null && list.Count == 0) { return true; } Placeholder placeholder = formattingInfo.Placeholder; if (string.IsNullOrEmpty((placeholder != null) ? placeholder.FormatterName : null)) { return false; } Placeholder placeholder2 = formattingInfo.Placeholder; throw new FormatException("Formatter named '" + ((placeholder2 != null) ? placeholder2.FormatterName : null) + "' requires at least 2 format options."); } Match match = Regex.Match(formattingInfo.CurrentValue.ToString(), pattern, RegexOptions.Multiline, TimeSpan.FromMilliseconds(500.0)); if (!match.Success) { formattingInfo.FormatAsChild(list[1], formattingInfo.CurrentValue); return true; } List<string> list2 = (from Group grp in match.Groups select grp.Value).ToList(); list2.RemoveAt(0); foreach (FormatItem item in list[0].Items) { Placeholder val = (Placeholder)(object)((item is Placeholder) ? item : null); if (val != null) { KeyValuePair<string, object> keyValuePair = new KeyValuePair<string, object>("m", list2); Format(formattingInfo, val, keyValuePair); continue; } LiteralText val2 = (LiteralText)item; Format format2 = formattingInfo.Format; Format val3 = ((format2 != null) ? format2.Substring(((FormatItem)val2).StartIndex - ((FormatItem)formattingInfo.Format).StartIndex, ((FormatItem)val2).Length) : null); try { if (val3 != null) { formattingInfo.FormatAsChild(val3, formattingInfo.CurrentValue); } } finally { ((IDisposable)val3)?.Dispose(); } } return true; } private void Format(IFormattingInfo formattingInfo, Placeholder placeholder, object matchingGroupValues) { Format format = formattingInfo.Format; Format val = ((format != null) ? format.Substring(((FormatItem)placeholder).StartIndex - ((FormatItem)formattingInfo.Format).StartIndex, ((FormatItem)placeholder).Length) : null); try { if (val == null) { return; } if (placeholder.GetSelectors().Count > 0) { Selector obj = placeholder.GetSelectors()[0]; if (((obj != null) ? ((FormatItem)obj).RawText : null) == "m") { formattingInfo.FormatAsChild(val, matchingGroupValues); return; } } formattingInfo.FormatAsChild(val, formattingInfo.CurrentValue); } finally { ((IDisposable)val)?.Dispose(); } } } internal class ReplaceNewLinesSource : Source { public override bool TryEvaluateSelector(ISelectorInfo selectorInfo) { if (selectorInfo.CurrentValue is string text && selectorInfo.SelectorText.Equals("NewLines")) { selectorInfo.Result = text.Replace("\\n", "\n"); return true; } return false; } } internal class SelectorTextToStringSource : Source { public override bool TryEvaluateSelector(ISelectorInfo selectorInfo) { if (selectorInfo.SelectorText.StartsWith('"') && selectorInfo.SelectorText.EndsWith('"')) { string selectorText = selectorInfo.SelectorText; selectorInfo.Result = selectorText.Substring(1, selectorText.Length - 1 - 1); return true; } return false; } } internal class StringToNumberSource : Source { public override bool TryEvaluateSelector(ISelectorInfo selectorInfo) { if (!(selectorInfo.CurrentValue is string value)) { return false; } if (!selectorInfo.SelectorText.Equals("ToNumber")) { return false; } selectorInfo.Result = Convert.ToInt64(value); return true; } } internal class TranslationSource : Source { public override bool TryEvaluateSelector(ISelectorInfo selectorInfo) { if (selectorInfo.CurrentValue is string key && selectorInfo.SelectorText.Equals("Translate")) { selectorInfo.Result = Translation.GetLocalizedText(key); return true; } return false; } } } namespace RTLC.Translations { [HarmonyPatch] [HarmonyPriority(300)] internal static class Patch_LoadStringBasic { [HarmonyTargetMethods] public static IEnumerable<MethodBase> EnumeratePatchingMethods() { yield return AccessTools.Method(typeof(SteamValveHazard), "Update", (Type[])null, (Type[])null); yield return AccessTools.Method(typeof(ShipTeleporter), "Update", (Type[])null, (Type[])null); yield return AccessTools.Method(typeof(ElevatorAnimationEvents), "ElevatorFullyRunning", (Type[])null, (Type[])null); yield return AccessTools.Method(typeof(PlayerControllerB), "ConnectClientToPlayerObject", (Type[])null, (Type[])null); yield return AccessTools.Method(typeof(Terminal), "TextPostProcess", (Type[])null, (Type[])null); yield return AccessTools.Method(typeof(ChallengeLeaderboardSlot), "SetSlotValues", (Type[])null, (Type[])null); yield return AccessTools.Method(typeof(DeleteFileButton), "SetFileToDelete", (Type[])null, (Type[])null); yield return AccessTools.Method(typeof(SettingsOption), "ToggleEnabledImage", (Type[])null, (Type[])null); yield return AccessTools.Method(typeof(KepRemapPanel), "LoadKeybindsUI", (Type[])null, (Type[])null); yield return AccessTools.Method(typeof(SaveFileUISlot), "OnEnable", (Type[])null, (Type[])null); yield return AccessTools.Method(typeof(ShipBuildModeManager), "CreateGhostObjectAndHighlight", (Type[])null, (Type[])null); yield return AccessTools.EnumeratorMoveNext((MethodBase)AccessTools.Method(typeof(ManualCameraRenderer), "updateMapTarget", (Type[])null, (Type[])null)); yield return AccessTools.Method(typeof(IngamePlayerSettings), "RefreshAndDisplayCurrentMicrophone", (Type[])null, (Type[])null); yield return AccessTools.Method(typeof(IngamePlayerSettings), "SetMicPushToTalk", (Type[])null, (Type[])null); yield return AccessTools.Method(typeof(IngamePlayerSettings), "SwitchMicrophoneSetting", (Type[])null, (Type[])null); yield return AccessTools.Method(typeof(IngamePlayerSettings), "UpdateMicPushToTalkButton", (Type[])null, (Type[])null); yield return AccessTools.Method(typeof(IngamePlayerSettings), "SetChangesNotAppliedTextVisible", (Type[])null, (Type[])null); yield return AccessTools.Method(typeof(HUDManager), "ChangeControlTipMultiple", (Type[])null, (Type[])null); yield return AccessTools.Method(typeof(HUDManager), "ScanNewCreatureServerRpc", (Type[])null, (Type[])null); yield return AccessTools.Method(typeof(HUDManager), "ScanNewCreatureClientRpc", (Type[])null, (Type[])null); yield return AccessTools.Method(typeof(HUDManager), "GetNewStoryLogServerRpc", (Type[])null, (Type[])null); yield return AccessTools.Method(typeof(HUDManager), "GetNewStoryLogClientRpc", (Type[])null, (Type[])null); yield return AccessTools.Method(typeof(HUDManager), "ApplyPenalty", (Type[])null, (Type[])null); yield return AccessTools.Method(typeof(HUDManager), "DisplayNewScrapFound", (Type[])null, (Type[])null); yield return AccessTools.Method(typeof(HUDManager), "DisplayNewDeadline", (Type[])null, (Type[])null); yield return AccessTools.Method(typeof(HUDManager), "FillEndGameStats", (Type[])null, (Type[])null); yield return AccessTools.Method(typeof(HUDManager), "SetShipLeaveEarlyVotesText", (Type[])null, (Type[])null); yield return AccessTools.Method(typeof(HUDManager), "Update", (Type[])null, (Type[])null); yield return AccessTools.Method(typeof(HUDManager), "SetSpectatingTextToPlayer", (Type[])null, (Type[])null); yield return AccessTools.Method(typeof(HUDManager), "DisplayCreditsEarning", (Type[])null, (Type[])null); yield return AccessTools.Method(typeof(StartOfRound), "SetMapScreenInfoToCurrentLevel", (Type[])null, (Type[])null); yield return AccessTools.Method(typeof(StartOfRound), "EndGameClientRpc", (Type[])null, (Type[])null); yield return AccessTools.EnumeratorMoveNext((MethodBase)AccessTools.Method(typeof(StartOfRound), "openingDoorsSequence", (Type[])null, (Type[])null)); yield return AccessTools.Method(typeof(StartOfRound), "SceneManager_OnLoad", (Type[])null, (Type[])null); yield return AccessTools.Method(typeof(StartOfRound), "SceneManager_OnLoadComplete1", (Type[])null, (Type[])null); yield return AccessTools.Method(typeof(PreInitSceneScript), "PressContinueButton", (Type[])null, (Type[])null); yield return AccessTools.Method(typeof(PreInitSceneScript), "SkipToFinalSetting", (Type[])null, (Type[])null); yield return AccessTools.Method(typeof(MenuManager), "StartAClient", (Type[])null, (Type[])null); yield return AccessTools.Method(typeof(MenuManager), "ConfirmHostButton", (Type[])null, (Type[])null); yield return AccessTools.Method(typeof(MenuManager), "HostSetLobbyPublic", (Type[])null, (Type[])null); yield return AccessTools.Method(typeof(MenuManager), "DisplayLeaderboardSlots", (Type[])null, (Type[])null); yield return AccessToolsHelper.AsyncMoveNext(typeof(MenuManager), "GetLeaderboardForChallenge"); yield return AccessToolsHelper.AsyncMoveNext(typeof(SteamLobbyManager), "LoadServerList"); yield return AccessTools.Method(typeof(TimeOfDay), "UpdateProfitQuotaCurrentTime", (Type[])null, (Type[])null); yield return AccessTools.Method(typeof(RoundManager), "GenerateNewLevelClientRpc", (Type[])null, (Type[])null); } [HarmonyILManipulator] public static void ReplaceText(ILContext context, MethodBase? originalMethod) { ILContextHelper.PatchModsPrefixesAndPostfixes(originalMethod, LoadStringPatch.ReplaceLoadStringWithTranslatedMethod); LoadStringPatch.ReplaceLoadStringWithTranslated(context); } } [HarmonyPatch] [HarmonyPriority(299)] internal static class Patch_ReplaceStringFormat { [HarmonyTargetMethods] public static IEnumerable<MethodBase> GetPatchingMethods() { yield return AccessTools.Method(typeof(HUDManager), "DisplayDaysLeft", (Type[])null, (Type[])null); yield return AccessTools.Method(typeof(TimeOfDay), "UpdateProfitQuotaCurrentTime", (Type[])null, (Type[])null); } [HarmonyILManipulator] public static void ReplaceFormat(ILContext context, MethodBase originalMethod) { ILContextHelper.PatchModsPrefixesAndPostfixes(originalMethod, LoadStringPatch.ReplaceLoadStringWithTranslatedMethod); ReplaceStringFormatPatch.ReplaceStringFormatToTranslationFormat(context); } } } namespace RTLC.Translations.Specific { [HarmonyPatch(typeof(HUDManager))] internal static class Patch_HUDManager_Tips { [HarmonyPatch("ChangeControlTip")] [HarmonyPrefix] public static void ChangeControlTip(ref string changeTo) { changeTo = Translation.GetLocalizedText(changeTo); } [HarmonyPatch("ChangeControlTipMultiple")] [HarmonyPrefix] public static void ChangeControlTipMultiple(string[] allLines) { if (allLines != null) { for (int i = 0; i < allLines.Length; i++) { allLines[i] = Translation.GetLocalizedText(allLines[i]); } } } [HarmonyPatch("ChangeControlTipMultiple")] [HarmonyTranspiler] public static IEnumerable<CodeInstruction> RemoveItemNameInDrop(IEnumerable<CodeInstruction> instructions) { //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_000e: Expected O, but got Unknown CodeMatcher val = new CodeMatcher(instructions, (ILGenerator)null); FieldInfo itemNameField = AccessTools.Field(typeof(Item), "itemName"); val.SearchForward((Func<CodeInstruction, bool>)((CodeInstruction c) => CodeInstructionExtensions.LoadsField(c, itemNameField, false))).SetOperandAndAdvance((object)AccessTools.Field(typeof(string), "Empty")); return val.InstructionEnumeration(); } [HarmonyPatch("DisplayTip")] [HarmonyPrefix] public static void DisplayTip(ref string headerText, ref string bodyText) { headerText = Translation.GetLocalizedText(headerText); bodyText = Translation.GetLocalizedText(bodyText); } } [HarmonyPatch] internal static class Patch_HUDManager_UpdateScanNodes { [HarmonyTargetMethod] public static MethodBase GetPatchingMethod() { if (Chainloader.PluginInfos.TryGetValue("HDLethalCompany", out var _)) { MethodInfo methodInfo = AccessTools.Method("HDLethalCompany.Patch.GraphicsPatch:UpdateScanNodesPostfix", (Type[])null, (Type[])null); if (methodInfo != null) { return methodInfo; } } return AccessTools.Method(typeof(HUDManager), "UpdateScanNodes", (Type[])null, (Type[])null); } [HarmonyILManipulator] public static void ReplaceText(ILContext ctx) { //IL_003b: Unknown result type (might be due to invalid IL or missing references) //IL_0041: Expected O, but got Unknown //IL_0044: Unknown result type (might be due to invalid IL or missing references) FieldInfo headerTextField = AccessTools.Field(typeof(ScanNodeProperties), "headerText"); FieldInfo subTextField = AccessTools.Field(typeof(ScanNodeProperties), "subText"); ILCursor val = new ILCursor(ctx); while (val.TryGotoNext((MoveType)2, new Func<Instruction, bool>[1] { (Instruction c) => ILPatternMatchingExt.MatchLdfld(c, headerTextField) || ILPatternMatchingExt.MatchLdfld(c, subTextField) })) { val.Emit(OpCodes.Call, (MethodBase)SymbolExtensions.GetMethodInfo((Expression<Action>)(() => Translation.GetLocalizedText(null)))); int index = val.Index; val.Index = index + 1; } } } [HarmonyPatch(typeof(KepRemapPanel), "OnEnable")] internal static class Patch_KepRemapPanel_OnEnable { [HarmonyPrefix] public static void TranslateKeybinds(KepRemapPanel __instance) { if (__instance.remappableKeys == null) { return; } foreach (RemappableKey remappableKey in __instance.remappableKeys) { if (remappableKey != null) { remappableKey.ControlName = Translation.GetLocalizedText(remappableKey.ControlName); } } } } [HarmonyPatch(typeof(LobbySlot), "Awake")] internal static class Patch_LobbySlot_Awake { [HarmonyPrefix] public static void ReplaceText(LobbySlot __instance) { Transform val = ((Component)__instance).transform.Find("JoinButton"); if (!((Object)(object)val == (Object)null)) { TextMeshProUGUI componentInChildren = ((Component)val).GetComponentInChildren<TextMeshProUGUI>(); if ((Object)(object)componentInChildren != (Object)null) { ((TMP_Text)componentInChildren).text = Translation.GetLocalizedText(((TMP_Text)componentInChildren).text); } } } } [HarmonyPatch(typeof(PlayerControllerB), "SetHoverTipAndCurrentInteractTrigger")] internal static class Patch_PlayerControllerB_SetHoverTipAndCurrentInteractTrigger { [HarmonyTranspiler] public static IEnumerable<CodeInstruction> ReplaceText(IEnumerable<CodeInstruction> instructions) { //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_000e: Expected O, but got Unknown //IL_0059: Unknown result type (might be due to invalid IL or missing references) //IL_005f: Expected O, but got Unknown CodeMatcher val = new CodeMatcher(instructions, (ILGenerator)null); FieldInfo cursorTipField = AccessTools.Field(typeof(PlayerControllerB), "cursorTip"); MethodInfo getTextProperty = AccessTools.PropertyGetter(typeof(TMP_Text), "text"); val.MatchForward(false, (CodeMatch[])(object)new CodeMatch[1] { new CodeMatch((Func<CodeInstruction, bool>)((CodeInstruction c) => CodeInstructionExtensions.LoadsField(c, cursorTipField, false)), (string)null) }).Repeat((Action<CodeMatcher>)delegate(CodeMatcher m) { CodeInstruction val2 = m.InstructionAt(1); if (val2.opcode == OpCodes.Ldstr) { val2.operand = Translation.GetLocalizedText((string)val2.operand); m.Advance(1); } else if (CodeInstructionExtensions.Calls(val2, getTextProperty) || val2.opcode == OpCodes.Ldloc || val2.opcode == OpCodes.Ldloc_S) { m.Advance(1); } else { CodeInstruction val3 = m.InstructionAt(2); if (CodeInstructionExtensions.LoadsField(val3, cursorTipField, false)) { m.Advance(4); } else { m.Advance(3).Insert((CodeInstruction[])(object)new CodeInstruction[1] { CodeInstruction.Call((Expression<Action>)(() => Translation.GetLocalizedText(string.Empty))) }); } } }, (Action<string>)null); return val.InstructionEnumeration(); } } [HarmonyPatch(typeof(StartOfRound), "Awake")] internal static class Patch_StartOfRound_Awake { [HarmonyPostfix] [HarmonyPriority(0)] public static void TranslateLevelDescription(StartOfRound __instance) { SelectableLevel[] levels = __instance.levels; if (levels == null) { return; } SelectableLevel[] array = levels; foreach (SelectableLevel val in array) { if (!((Object)(object)val == (Object)null)) { val.LevelDescription = Translation.GetLocalizedText(val.LevelDescription); } } } } [HarmonyPatch(typeof(Terminal))] [HarmonyPriority(0)] internal static class Patch_Terminal_Awake { private static bool s_Initialized; [HarmonyPatch("Awake")] [HarmonyPostfix] [HarmonyWrapSafe] public static void TranslateNodes(Terminal __instance) { if (s_Initialized) { return; } HashSet<TerminalNode> hashSet = new HashSet<TerminalNode>(); IEnumerable<TerminalNode> enumerable = __instance.terminalNodes.allKeywords.SelectMany(delegate(TerminalKeyword tk) { IEnumerable<TerminalNode> source = tk.compatibleNouns?.Select((CompatibleNoun c) => c.result) ?? Array.Empty<TerminalNode>(); return source.Append(tk.specialKeywordResult); }).Concat(__instance.terminalNodes.specialNodes).Concat(__instance.terminalNodes.terminalNodes); foreach (TerminalNode item in enumerable) { if ((Object)(object)item == (Object)null || !hashSet.Add(item)) { continue; } item.displayText = Translation.GetLocalizedText(GetTerminalNodeName(item), item.displayText, shouldIgnoreKey: false); CompatibleNoun[] terminalOptions = item.terminalOptions; if (terminalOptions == null) { continue; } CompatibleNoun[] array = terminalOptions; foreach (CompatibleNoun val in array) { if (val != null && !((Object)(object)val.result == (Object)null) && hashSet.Add(val.result)) { val.result.displayText = Translation.GetLocalizedText(GetTerminalNodeName(val.result), val.result.displayText, shouldIgnoreKey: false); } } } s_Initialized = true; } private static string GetTerminalNodeName(TerminalNode node) { string name = ((Object)node).name; if (!string.IsNullOrWhiteSpace(name)) { return name; } return node.displayText; } [HarmonyPatch("TextPostProcess")] [HarmonyPostfix] public static void ReplaceTimeOfDay(ref string __result) { string newValue = DateTime.Now.DayOfWeek switch { DayOfWeek.Monday => "Счастливого понедельника", DayOfWeek.Tuesday => "Счастливого вторника", DayOfWeek.Wednesday => "Счастливой среды", DayOfWeek.Thursday => "Счастливого четверга", DayOfWeek.Friday => "Счастливой пятницы", DayOfWeek.Saturday => "Счастливой субботы", DayOfWeek.Sunday => "Счастливого воскресенья", _ => string.Empty, }; __result = __result.Replace("[currentDayRussian]", newValue); } } } namespace RTLC.Patches { [HarmonyPatch(typeof(HUDManager))] internal static class Patch_HUDManager { [HarmonyPatch("SetClock")] [HarmonyPrefix] private static bool ShowClockIn24Hour(float timeNormalized, float numberOfHours, out string __result) { int num = (int)(timeNormalized * (60f * numberOfHours)) + 360; string text = $"{num / 60:00}:{num % 60:00}"; ((TMP_Text)HUDManager.Instance.clockNumber).text = (__result = text); return false; } [HarmonyPatch("Update")] [HarmonyTranspiler] private static IEnumerable<CodeInstruction> ShowKilograms(IEnumerable<CodeInstruction> instructions) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0008: Expected O, but got Unknown CodeMatcher val = new CodeMatcher(instructions, (ILGenerator)null); val.Start().SearchForward((Func<CodeInstruction, bool>)((CodeInstruction c) => c.opcode == OpCodes.Ldc_R4 && (float)c.operand == 105f)).Operand = 47.627197f; val.SearchForward((Func<CodeInstruction, bool>)((CodeInstruction c) => c.opcode == OpCodes.Ldstr && (string)c.operand == "{0} lb")).Operand = "{0} кг"; val.SearchForward((Func<CodeInstruction, bool>)((CodeInstruction c) => c.opcode == OpCodes.Ldc_R4 && (float)c.operand == 130f)).Operand = 58.967007f; return val.InstructionEnumeration(); } } } namespace RTLC.Patches.Translations { internal static class Patch_ReplaceStringConcat { [HarmonyTargetMethods] public static IEnumerable<MethodBase> GetPatchingMethods() { yield break; } [HarmonyILManipulator] public static void ReplaceFormat(ILContext context, MethodBase originalMethod) { ILContextHelper.PatchModsPrefixesAndPostfixes(originalMethod, LoadStringPatch.ReplaceLoadStringWithTranslatedMethod); ReplaceStringConcatPatch.ReplaceStringConcatToTranslationFormat(context); } } } namespace RTLC.Patches.Translations.Specific { [HarmonyPatch(typeof(HUDManager), "DisplayStatusEffect")] [HarmonyPriority(0)] internal static class Patch_HUDManager_DisplayStatusEffect { [HarmonyPatch] [HarmonyPrefix] public static void DisplayStatusEffect(ref string statusEffect) { statusEffect = Translation.GetLocalizedText(statusEffect); } } [HarmonyPatch(typeof(HUDManager), "Start")] [HarmonyPriority(0)] internal static class Patch_HUDManager_PlayerLevels { [HarmonyPatch] [HarmonyPostfix] public static void TranslatePlayerLevels(HUDManager __instance) { PlayerLevel[] playerLevels = __instance.playerLevels; foreach (PlayerLevel val in playerLevels) { if (val != null) { val.levelName = Translation.GetLocalizedText(val.levelName); } } } } [HarmonyPatch(typeof(HUDManager))] internal static class Patch_HUDManager_ReadOutDialogue { [HarmonyPatch("ReadDialogue")] [HarmonyPrefix] public static void ReadDialogue(DialogueSegment[] dialogueArray) { if (dialogueArray == null) { return; } foreach (DialogueSegment val in dialogueArray) { if (val == null) { break; } val.bodyText = Translation.GetLocalizedText(val.bodyText); val.speakerText = Translation.GetLocalizedText(val.speakerText); } } } } namespace RTLC.Mods.ShipLoot { [HarmonyPatch] internal class Patch_ShipLoot_OnScan { [HarmonyPrepare] public static bool CheckModLoaded() { return ModHelper.TryFindMethod("com.github.tinyhoot.ShipLoot", "ShipLoot.Patches.HudManagerPatcher", "OnScan"); } [HarmonyTargetMethod] public static MethodBase GetMethodPatch() { return ModHelper.GetMethod(); } [HarmonyILManipulator] public static void ReplaceString(ILContext context) { LoadStringPatch.ReplaceLoadStringWithTranslated(context); } } } namespace RTLC.Helpers { internal static class AccessToolsHelper { public static MethodInfo AsyncMoveNext(Type type, string name) { MethodInfo methodInfo = AccessTools.Method(type, name, (Type[])null, (Type[])null); if ((object)methodInfo == null) { return null; } AsyncStateMachineAttribute customAttribute = methodInfo.GetCustomAttribute<AsyncStateMachineAttribute>(); if (customAttribute == null) { return null; } Type stateMachineType = customAttribute.StateMachineType; MethodInfo methodInfo2 = AccessTools.DeclaredMethod(stateMachineType, "MoveNext", (Type[])null, (Type[])null); if ((object)methodInfo2 == null) { return null; } return methodInfo2; } } internal static class ILContextHelper { private static readonly HashSet<Type> s_IgnoredTypes = new HashSet<Type> { typeof(Debug), typeof(Animation), typeof(Animator), typeof(Regex), typeof(CustomMessagingManager), typeof(ManualLogSource), typeof(AssetBundle), typeof(GameObject), typeof(Transform), typeof(Path), typeof(Directory), typeof(File), typeof(FileStream), typeof(ConfigFile), typeof(ConfigDescription), typeof(ES3), typeof(LobbyQuery) }; private static readonly HashSet<string> s_IgnoredTypeNames = s_IgnoredTypes.Select((Type t) => t.FullName).ToHashSet(); private static readonly HashSet<MethodInfo> s_IgnoredMethods = new HashSet<MethodInfo> { AccessTools.PropertySetter(typeof(Object), "name") }; private static readonly string[] s_IgnoredMethodsNames = s_IgnoredMethods.Select((MethodInfo t) => t.GetFullName()).Concat(new <>z__ReadOnlyArray<string>(new string[4] { "Log", "SpawnPrefab", "System.Boolean System.String::Equals(System.String", "System.Boolean System.String::Contains(System.String" })).ToArray(); public static bool TestIgnore(ILCursor cursor) { //IL_0022: 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_003e: Unknown result type (might be due to invalid IL or missing references) //IL_0043: Unknown result type (might be due to invalid IL or missing references) //IL_0058: Unknown result type (might be due to invalid IL or missing references) //IL_005d: 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_008d: Expected O, but got Unknown //IL_006b: Unknown result type (might be due to invalid IL or missing references) //IL_0070: Unknown result type (might be due to invalid IL or missing references) int index = cursor.Index; bool result = false; int num = 0; for (int i = index; i < cursor.Instrs.Count; i++) { Instruction val = cursor.Instrs[i]; if (val.OpCode == OpCodes.Ldstr) { num++; continue; } if (val.OpCode == OpCodes.Stfld) { result = true; break; } if (val.OpCode == OpCodes.Call || val.OpCode == OpCodes.Callvirt) { MethodReference val2 = (MethodReference)val.Operand; if (s_IgnoredTypeNames.Contains(((MemberReference)((MemberReference)val2).DeclaringType).FullName)) { result = true; break; } if (IsMethodIgnored(val2)) { result = true; break; } int num2 = (((IEnumerable<ParameterDefinition>)val2.Parameters).Any((ParameterDefinition p) => Extensions.Is((MemberReference)(object)((ParameterReference)p).ParameterType, "System.String[]")) ? 99 : ((IEnumerable<ParameterDefinition>)val2.Parameters).Count((ParameterDefinition p) => Extensions.Is((MemberReference)(object)((ParameterReference)p).ParameterType, "System.String"))); TypeReference returnType = val2.ReturnType; bool flag = returnType != null && Extensions.Is((MemberReference)(object)returnType, "System.String"); num = Mathf.Clamp(num - num2, 0, 10); if (flag) { num++; } if (num == 0) { break; } } } cursor.Index = index; return result; } public static void PatchModsPrefixesAndPostfixes(MethodBase? originalMethod, MethodInfo ilManipulatorPatch) { if (originalMethod == null || originalMethod.DeclaringType.Assembly == typeof(ILContextHelper).Assembly) { return; } Patches patchInfo = Harmony.GetPatchInfo(originalMethod); if (patchInfo == null) { return; } foreach (Patch item in patchInfo.Prefixes.Concat(patchInfo.Postfixes)) { if (!(item.PatchMethod.DeclaringType.Assembly == typeof(ILContextHelper).Assembly) && !(item.PatchMethod.ReturnType != typeof(bool))) { Patches patchInfo2 = Harmony.GetPatchInfo((MethodBase)item.PatchMethod); if (patchInfo2 != null && patchInfo2.Owners.Contains("RTLC")) { RTLCPlugin.Instance.Logger.LogInfo((object)("Ignored patching of " + item.PatchMethod.GetReadableString() + " due to already patched")); continue; } RTLCPlugin.Instance.Logger.LogInfo((object)("Patching " + item.PatchMethod.GetReadableString())); RTLCPlugin.Instance.Harmony.CreateProcessor((MethodBase)item.PatchMethod).AddILManipulator(ilManipulatorPatch).Patch(); } } } private static bool IsMethodIgnored(MethodReference method) { string fullName = ((MemberReference)method).FullName; if ((fullName == "System.Boolean System.String::op_Inequality(System.String,System.String)" || fullName == "System.Boolean System.String::op_Equality(System.String,System.String)") ? true : false) { return true; } string name = ((MemberReference)method).Name; for (int i = 0; i < s_IgnoredMethodsNames.Length; i++) { if (name.StartsWith(s_IgnoredMethodsNames[i], StringComparison.OrdinalIgnoreCase) || fullName.StartsWith(s_IgnoredMethodsNames[i], StringComparison.OrdinalIgnoreCase)) { return true; } } return false; } } internal static class ModHelper { private static MethodInfo? s_MethodToPatch; public static bool TryFindMethod(string modId, string type, string method) { if (!Chainloader.PluginInfos.TryGetValue(modId, out var value)) { return false; } Assembly assembly = ((object)value.Instance).GetType().Assembly; Type type2 = assembly.GetType(type, throwOnError: false); s_MethodToPatch = AccessTools.Method(type2, method, (Type[])null, (Type[])null); return s_MethodToPatch != null; } public static MethodBase GetMethod() { return s_MethodToPatch; } } } namespace RTLC.Extensions { internal static class MethodBaseExtensions { public static string GetReadableString(this MethodBase method) { Type declaringType = method.DeclaringType; string text = ((declaringType.Namespace == null) ? string.Empty : (declaringType.Namespace + ".")); return text + declaringType.Name + "::" + method.Name; } public static string GetFullName(this MethodInfo method) { Type returnType = method.ReturnType; StringBuilder stringBuilder = new StringBuilder(); stringBuilder.Append(returnType.FullName); stringBuilder.Append(' '); stringBuilder.Append(method.GetReadableString()); stringBuilder.Append('('); ParameterInfo[] parameters = method.GetParameters(); for (int i = 0; i < parameters.Length; i++) { ParameterInfo parameterInfo = parameters[i]; if (i > 0) { stringBuilder.Append(","); } stringBuilder.Append(parameterInfo.ParameterType.FullName); } stringBuilder.Append(')'); return stringBuilder.ToString(); } } } namespace RTLC.API { [AttributeUsage(AttributeTargets.Method, AllowMultiple = false)] internal class InitializeOnAwakeAttribute : Attribute { } internal static class LoadStringPatch { public static readonly MethodInfo ReplaceLoadStringWithTranslatedMethod = typeof(LoadStringPatch).GetMethod("ReplaceLoadStringWithTranslated", AccessTools.all); public static void ReplaceLoadStringWithTranslated(ILContext context) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Expected O, but got Unknown ILCursor val = new ILCursor(context); while (val.TryGotoNext(new Func<Instruction, bool>[1] { (Instruction i) => i.OpCode == OpCodes.Ldstr })) { if (ILContextHelper.TestIgnore(val)) { int index = val.Index; val.Index = index + 1; } else { val.Next.Operand = Translation.GetLocalizedText((string)val.Next.Operand); int index = val.Index; val.Index = index + 1; } } } } internal static class ReplaceStringConcatPatch { public static readonly MethodInfo ReplaceLoadStringWithTranslatedMethod = typeof(ReplaceStringConcatPatch).GetMethod("ReplaceStringConcatPatch", AccessTools.all); public static void ReplaceStringConcatToTranslationFormat(ILContext context) { //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_000d: Expected O, but got Unknown //IL_0051: Unknown result type (might be due to invalid IL or missing references) //IL_0057: Expected O, but got Unknown ILCursor val = new ILCursor(context); string corLibStringTypeFullName = typeof(string).FullName; while (val.TryGotoNext(new Func<Instruction, bool>[1] { delegate(Instruction i) { object operand = i.Operand; MethodReference val4 = (MethodReference)((operand is MethodReference) ? operand : null); return val4 != null && ((MemberReference)((MemberReference)val4).DeclaringType).FullName == corLibStringTypeFullName && ((MemberReference)val4).Name.Equals("Concat"); } })) { int index; if (ILContextHelper.TestIgnore(val)) { index = val.Index; val.Index = index + 1; continue; } MethodReference val2 = (MethodReference)val.Next.Operand; Collection<ParameterDefinition> parameters = val2.Parameters; Collection<ParameterDefinition> val3 = parameters; if (val3 == null) { goto IL_01be; } MethodInfo methodInfo; if (parameters.Count == 2) { methodInfo = SymbolExtensions.GetMethodInfo((Expression<Action>)(() => Translation.Concat(null, null))); } else if (parameters.Count == 3) { methodInfo = SymbolExtensions.GetMethodInfo((Expression<Action>)(() => Translation.Concat(null, null, null))); } else { if (parameters.Count != 4) { goto IL_01be; } methodInfo = SymbolExtensions.GetMethodInfo((Expression<Action>)(() => Translation.Concat(null, null, null, null))); } goto IL_0207; IL_0207: MethodInfo methodInfo2 = methodInfo; val.Next.Operand = context.Import((MethodBase)methodInfo2); index = val.Index; val.Index = index + 1; continue; IL_01be: methodInfo = SymbolExtensions.GetMethodInfo((Expression<Action>)(() => Translation.Concat())); goto IL_0207; } } } internal static class ReplaceStringFormatPatch { public static readonly MethodInfo ReplaceLoadStringWithTranslatedMethod = typeof(ReplaceStringFormatPatch).GetMethod("ReplaceStringFormatToTranslationFormat", AccessTools.all); public static void ReplaceStringFormatToTranslationFormat(ILContext context) { //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_0012: Expected O, but got Unknown //IL_0065: Unknown result type (might be due to invalid IL or missing references) //IL_006b: Expected O, but got Unknown ILCursor cursor = new ILCursor(context); string corLibStringTypeFullName = typeof(string).FullName; while (cursor.TryGotoNext(new Func<Instruction, bool>[1] { delegate(Instruction i) { object operand = i.Operand; MethodReference val3 = (MethodReference)((operand is MethodReference) ? operand : null); return val3 != null && ((MemberReference)((MemberReference)val3).DeclaringType).FullName == corLibStringTypeFullName && ((MemberReference)val3).Name.Equals("Format"); } })) { int index; if (ILContextHelper.TestIgnore(cursor)) { ILCursor obj = cursor; index = obj.Index; obj.Index = index + 1; continue; } MethodReference val = (MethodReference)cursor.Next.Operand; Collection<ParameterDefinition> parameters = val.Parameters; Collection<ParameterDefinition> val2 = parameters; if (val2 == null) { goto IL_01fb; } MethodInfo methodInfo; if (parameters.Count == 3) { methodInfo = SymbolExtensions.GetMethodInfo((Expression<Action>)(() => Translation.Format(null, null, null))); } else if (parameters.Count == 4) { methodInfo = SymbolExtensions.GetMethodInfo((Expression<Action>)(() => Translation.Format(null, null, null, null))); } else { if (!((IEnumerable<CustomAttribute>)parameters[1].CustomAttributes).Any((CustomAttribute a) => ((MemberReference)((MemberReference)a.Constructor).DeclaringType).FullName == typeof(ParamArrayAttribute).FullName)) { goto IL_01fb; } methodInfo = SymbolExtensions.GetMethodInfo((Expression<Action>)(() => Translation.Format(null, null))); } goto IL_025c; IL_01fb: methodInfo = SymbolExtensions.GetMethodInfo((Expression<Action>)(() => Translation.Format(null, cursor))); goto IL_025c; IL_025c: MethodInfo methodInfo2 = methodInfo; cursor.Next.Operand = context.Import((MethodBase)methodInfo2); ILCursor obj2 = cursor; index = obj2.Index; obj2.Index = index + 1; } } } } namespace RTLC.API.LethalExpansion { internal static class LethalExpansionTranslation { public static void TryAddScrapsToUntranslated() { if (!Chainloader.PluginInfos.ContainsKey("LethalExpansion") && !Chainloader.PluginInfos.ContainsKey("com.github.lethalmods.lethalexpansioncore")) { return; } try { Type type = AccessTools.TypeByName("LethalExpansionCore.Utils.AssetBundlesManager"); object obj = AccessTools.PropertyGetter(type, "Instance").Invoke(null, null); IDictionary dictionary = (IDictionary)AccessTools.Field(obj.GetType(), "assetBundles").GetValue(obj); foreach (DictionaryEntry item in dictionary) { ITuple tuple = (ITuple)item.Value; object obj2 = tuple[1]; Console.WriteLine($"Got mod manifest: {item.Key}"); Array array = (Array)AccessTools.Field(obj2.GetType(), "scraps").GetValue(obj2); foreach (object item2 in array) { string key = (string)AccessTools.Field(item2.GetType(), "itemName").GetValue(item2); key = Translation.GetLocalizedText(key); Console.WriteLine("Found " + key); } } } catch (Exception ex) { RTLCPlugin.Instance.Logger.LogError((object)ex); } } } } internal sealed class <>z__ReadOnlyArray<T> : IEnumerable, ICollection, IList, IEnumerable<T>, IReadOnlyCollection<T>, IReadOnlyList<T>, ICollection<T>, IList<T> { int ICollection.Count => _items.Length; bool ICollection.IsSynchronized => false; object ICollection.SyncRoot => this; object IList.this[int index] { get { return _items[index]; } set { throw new NotSupportedException(); } } bool IList.IsFixedSize => true; bool IList.IsReadOnly => true; int IReadOnlyCollection<T>.Count => _items.Length; T IReadOnlyList<T>.this[int index] => _items[index]; int ICollection<T>.Count => _items.Length; bool ICollection<T>.IsReadOnly => true; T IList<T>.this[int index] { get { return _items[index]; } set { throw new NotSupportedException(); } } public <>z__ReadOnlyArray(T[] items) { _items = items; } IEnumerator IEnumerable.GetEnumerator() { return ((IEnumerable)_items).GetEnumerator(); } void ICollection.CopyTo(Array array, int index) { ((ICollection)_items).CopyTo(array, index); } int IList.Add(object value) { throw new NotSupportedException(); } void IList.Clear() { throw new NotSupportedException(); } bool IList.Contains(object value) { return ((IList)_items).Contains(value); } int IList.IndexOf(object value) { return ((IList)_items).IndexOf(value); } void IList.Insert(int index, object value) { throw new NotSupportedException(); } void IList.Remove(object value) { throw new NotSupportedException(); } void IList.RemoveAt(int index) { throw new NotSupportedException(); } IEnumerator<T> IEnumerable<T>.GetEnumerator() { return ((IEnumerable<T>)_items).GetEnumerator(); } void ICollection<T>.Add(T item) { throw new NotSupportedException(); } void ICollection<T>.Clear() { throw new NotSupportedException(); } bool ICollection<T>.Contains(T item) { return ((ICollection<T>)_items).Contains(item); } void ICollection<T>.CopyTo(T[] array, int arrayIndex) { ((ICollection<T>)_items).CopyTo(array, arrayIndex); } bool ICollection<T>.Remove(T item) { throw new NotSupportedException(); } int IList<T>.IndexOf(T item) { return ((IList<T>)_items).IndexOf(item); } void IList<T>.Insert(int index, T item) { throw new NotSupportedException(); } void IList<T>.RemoveAt(int index) { throw new NotSupportedException(); } }