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 LethalFurryRU v1.0.3
plugins/LethalFurryRU/LethalFurry.dll
Decompiled 7 hours agousing System; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Reflection; using System.Reflection.Emit; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Text; using System.Text.RegularExpressions; using BepInEx; using BepInEx.Logging; using HarmonyLib; using Microsoft.CodeAnalysis; using Newtonsoft.Json; using TMPro; using UnityEngine; using UnityEngine.SceneManagement; using UnityEngine.TextCore; using UnityEngine.TextCore.LowLevel; using UnityEngine.UI; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")] [assembly: AssemblyCompany("LethalFurry")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0")] [assembly: AssemblyProduct("LethalFurry")] [assembly: AssemblyTitle("LethalFurry")] [assembly: AssemblyVersion("1.0.0.0")] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)] internal sealed class RefSafetyRulesAttribute : Attribute { public readonly int Version; public RefSafetyRulesAttribute(int P_0) { Version = P_0; } } } namespace LethalFurry { [BepInPlugin("clauderushub.lethalfurry", "LethalFurry", "1.0.3")] public class Plugin : BaseUnityPlugin { public const string Guid = "clauderushub.lethalfurry"; internal static ManualLogSource Log; internal static string Dir; private void Awake() { //IL_009d: Unknown result type (might be due to invalid IL or missing references) //IL_00a3: Expected O, but got Unknown Log = ((BaseUnityPlugin)this).Logger; Dir = Path.GetDirectoryName(((BaseUnityPlugin)this).Info.Location); Texts.Load(Path.Combine(Dir, "texts.json")); CodeStrings.Load(Path.Combine(Dir, "code.json")); Commands.Load(Path.Combine(Dir, "commands.json")); StoreNames.Load(Path.Combine(Dir, "store_names.json")); Voice.Load(Path.Combine(Dir, "audio")); Textures.Load(Path.Combine(Dir, "textures")); Harmony val = new Harmony("clauderushub.lethalfurry"); Type[] typesFromAssembly = AccessTools.GetTypesFromAssembly(Assembly.GetExecutingAssembly()); foreach (Type type in typesFromAssembly) { if (type.GetCustomAttributes(typeof(HarmonyPatch), inherit: false).Length != 0) { try { val.CreateClassProcessor(type).Patch(); } catch (Exception ex) { Log.LogError((object)("перехват " + type.Name + ": " + (ex.InnerException?.Message ?? ex.Message))); } } } SceneManager.sceneLoaded += delegate(Scene scene, LoadSceneMode mode) { Sweep(((Scene)(ref scene)).name); }; CodeStrings.Patch(val); Log.LogInfo((object)$"готово: строк {Texts.Count}, в коде {CodeStrings.Patched} методов, команд {Commands.Count}, голосов {Voice.Count}, текстур {Textures.Count}"); } private static void Sweep(string scene) { Safe("текстуры", Textures.Apply); Safe("шрифты", Fonts.Apply); Safe("терминал", Texts.ApplyTerminal); Safe("данные", Texts.ApplyData); Safe("ввод терминала", Commands.AllowCyrillic); Safe("текст сцены", Texts.ApplyScene); } private static void Safe(string what, Action a) { try { a(); } catch (Exception ex) { Log.LogError((object)(what + ": " + ex)); } } } internal static class Texts { private class File_ { public Dictionary<string, string> exact; } private static Dictionary<string, string> exact = new Dictionary<string, string>(); private static readonly (Type type, string[] fields)[] DataFields = new(Type, string[])[5] { (typeof(SelectableLevel), new string[1] { "LevelDescription" }), (typeof(InteractTrigger), new string[3] { "hoverTip", "disabledHoverTip", "holdTip" }), (typeof(Item), new string[1] { "toolTips" }), (typeof(ScanNodeProperties), new string[2] { "headerText", "subText" }), (typeof(StunGrenadeItem), new string[1] { "throwString" }) }; public static int Count => exact.Count; public static void Load(string path) { if (File.Exists(path)) { File_ file_ = JsonConvert.DeserializeObject<File_>(File.ReadAllText(path)); if (file_?.exact != null) { exact = file_.exact; } } } public static string Translate(string s) { if (string.IsNullOrEmpty(s) || exact.Count == 0) { return s; } if (exact.TryGetValue(s, out var value)) { return value; } string text = s.Trim(); if (text.Length != s.Length && exact.TryGetValue(text, out value)) { return s.Substring(0, s.IndexOf(text, StringComparison.Ordinal)) + value + s.Substring(s.IndexOf(text, StringComparison.Ordinal) + text.Length); } return Words.Apply(s); } public static void ApplyTerminal() { TerminalNode[] array = Resources.FindObjectsOfTypeAll<TerminalNode>(); foreach (TerminalNode val in array) { string text = Translate(val.displayText); if ((object)text != val.displayText) { val.displayText = text; } } } public static void ApplyData() { (Type, string[])[] dataFields = DataFields; for (int i = 0; i < dataFields.Length; i++) { (Type, string[]) tuple = dataFields[i]; Type item = tuple.Item1; string[] item2 = tuple.Item2; List<FieldInfo> list = new List<FieldInfo>(); string[] array = item2; foreach (string text in array) { FieldInfo fieldInfo = AccessTools.Field(item, text); if (fieldInfo != null) { list.Add(fieldInfo); } } Object[] array2 = Resources.FindObjectsOfTypeAll(item); foreach (Object o in array2) { foreach (FieldInfo item3 in list) { TranslateField(o, item3); } } } TimeOfDay[] array3 = Resources.FindObjectsOfTypeAll<TimeOfDay>(); foreach (TimeOfDay obj in array3) { string[] array = new string[2] { "shipLeavingSoonDialogue", "shipLeavingEarlyDialogue" }; foreach (string text2 in array) { if (AccessTools.Field(typeof(TimeOfDay), text2)?.GetValue(obj) is DialogueSegment[] array4) { DialogueSegment[] array5 = array4; foreach (DialogueSegment obj2 in array5) { obj2.bodyText = Translate(obj2.bodyText); obj2.speakerText = Translate(obj2.speakerText); } } } } } private static void TranslateField(object o, FieldInfo fi) { if (fi.FieldType == typeof(string)) { string obj = (string)fi.GetValue(o); string text = Translate(obj); if ((object)obj != text) { fi.SetValue(o, text); } } else if (fi.FieldType == typeof(string[]) && fi.GetValue(o) is string[] array) { for (int i = 0; i < array.Length; i++) { array[i] = Translate(array[i]); } } } public static void ApplyScene() { TMP_Text[] array = Resources.FindObjectsOfTypeAll<TMP_Text>(); foreach (TMP_Text val in array) { string text = Translate(val.text); if ((object)text != val.text) { val.text = text; } } Text[] array2 = Resources.FindObjectsOfTypeAll<Text>(); foreach (Text val2 in array2) { string text2 = Translate(val2.text); if ((object)text2 != val2.text) { val2.text = text2; } } } } internal static class CodeStrings { private static Dictionary<string, Dictionary<string, string>> map = new Dictionary<string, Dictionary<string, string>>(); private static readonly Dictionary<MethodBase, Dictionary<string, string>> byMethod = new Dictionary<MethodBase, Dictionary<string, string>>(); public static int Patched; public static void Load(string path) { if (File.Exists(path)) { map = JsonConvert.DeserializeObject<Dictionary<string, Dictionary<string, string>>>(File.ReadAllText(path)); } } public static void Patch(Harmony harmony) { //IL_0016: Unknown result type (might be due to invalid IL or missing references) //IL_001c: Expected O, but got Unknown HarmonyMethod val = new HarmonyMethod(AccessTools.Method(typeof(CodeStrings), "Transpiler", (Type[])null, (Type[])null)); foreach (KeyValuePair<string, Dictionary<string, string>> item in map) { int num = item.Key.LastIndexOf("::", StringComparison.Ordinal); Type type = AccessTools.TypeByName(item.Key.Substring(0, num).Replace('/', '+')); string text = item.Key.Substring(num + 2); if (type == null) { Plugin.Log.LogWarning((object)("нет типа: " + item.Key)); continue; } foreach (MethodInfo declaredMethod in AccessTools.GetDeclaredMethods(type)) { if (!(declaredMethod.Name != text) && !declaredMethod.IsAbstract) { byMethod[declaredMethod] = item.Value; try { harmony.Patch((MethodBase)declaredMethod, (HarmonyMethod)null, (HarmonyMethod)null, val, (HarmonyMethod)null, (HarmonyMethod)null); Patched++; } catch (Exception ex) { Plugin.Log.LogError((object)("код " + item.Key + ": " + ex.Message)); } } } if (!(text == ".ctor") && !(text == ".cctor")) { continue; } foreach (ConstructorInfo declaredConstructor in AccessTools.GetDeclaredConstructors(type, (bool?)null)) { byMethod[declaredConstructor] = item.Value; try { harmony.Patch((MethodBase)declaredConstructor, (HarmonyMethod)null, (HarmonyMethod)null, val, (HarmonyMethod)null, (HarmonyMethod)null); Patched++; } catch (Exception ex2) { Plugin.Log.LogError((object)("код " + item.Key + ": " + ex2.Message)); } } } } private static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> code, MethodBase original) { byMethod.TryGetValue(original, out var strings); foreach (CodeInstruction item in code) { if (strings != null && item.opcode == OpCodes.Ldstr && item.operand is string key && strings.TryGetValue(key, out var value)) { item.operand = value; } yield return item; } } } internal static class Commands { private static List<KeyValuePair<string[], string>> phrases = new List<KeyValuePair<string[], string>>(); public static int Count => phrases.Count; public static void Load(string path) { if (!File.Exists(path)) { return; } foreach (KeyValuePair<string, string> item in JsonConvert.DeserializeObject<Dictionary<string, string>>(File.ReadAllText(path))) { if (!item.Key.StartsWith("_")) { string[] key = item.Key.ToLowerInvariant().Split(new char[1] { ' ' }, StringSplitOptions.RemoveEmptyEntries); phrases.Add(new KeyValuePair<string[], string>(key, item.Value)); } } phrases.Sort((KeyValuePair<string[], string> a, KeyValuePair<string[], string> b) => b.Key.Length.CompareTo(a.Key.Length)); } public static void AllowCyrillic() { //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_002f: Unknown result type (might be due to invalid IL or missing references) Terminal[] array = Resources.FindObjectsOfTypeAll<Terminal>(); for (int i = 0; i < array.Length; i++) { TMP_InputField screenText = array[i].screenText; if (!((Object)(object)screenText == (Object)null) && (int)screenText.characterValidation != 0) { Plugin.Log.LogInfo((object)$"терминал: снят фильтр ввода {screenText.characterValidation}"); screenText.characterValidation = (CharacterValidation)0; } } } public static string Translate(string input) { if (phrases.Count == 0 || string.IsNullOrEmpty(input)) { return input; } string[] array = input.Split(new char[1] { ' ' }, StringSplitOptions.RemoveEmptyEntries); List<string> list = new List<string>(); int num = 0; while (num < array.Length) { bool flag = false; foreach (KeyValuePair<string[], string> phrase in phrases) { string[] key = phrase.Key; if (num + key.Length <= array.Length) { bool flag2 = true; for (int i = 0; i < key.Length && flag2; i++) { flag2 = string.Equals(array[num + i], key[i], StringComparison.OrdinalIgnoreCase); } if (flag2) { list.Add(phrase.Value); num += key.Length; flag = true; break; } } } if (!flag) { list.Add(ByPrefix(array[num]) ?? array[num]); num++; } } return string.Join(" ", list); } private static string ByPrefix(string w) { if (w.Length < 2) { return null; } string text = null; foreach (KeyValuePair<string[], string> phrase in phrases) { if (phrase.Key.Length == 1 && phrase.Key[0].StartsWith(w, StringComparison.OrdinalIgnoreCase)) { if (text != null && text != phrase.Value) { return null; } text = phrase.Value; } } return text; } } internal static class StoreNames { private static readonly List<KeyValuePair<Regex, string>> rules = new List<KeyValuePair<Regex, string>>(); public static int Count => rules.Count; public static void Load(string path) { if (!File.Exists(path)) { return; } foreach (KeyValuePair<string, string> item in JsonConvert.DeserializeObject<Dictionary<string, string>>(File.ReadAllText(path))) { if (!item.Key.StartsWith("_")) { Regex key = new Regex("(?m)^(\\*\\s*)?" + Regex.Escape(item.Key) + "[ \\t]+//[ \\t]+"); rules.Add(new KeyValuePair<Regex, string>(key, "$1" + item.Key + " (" + item.Value + ") // ")); } } } public static string Apply(string s) { if (string.IsNullOrEmpty(s) || s.IndexOf("//", StringComparison.Ordinal) < 0) { return s; } foreach (KeyValuePair<Regex, string> rule in rules) { s = rule.Key.Replace(s, rule.Value); } return s; } } [HarmonyPatch(typeof(Terminal), "TextPostProcess")] internal static class StoreScreen { private static void Postfix(ref string __result) { __result = Words.Apply(StoreNames.Apply(__result)); } } [HarmonyPatch(typeof(HUDManager), "ReadDialogue")] internal static class PilotDialogue { private static void Prefix(DialogueSegment[] __0) { if (__0 == null) { return; } foreach (DialogueSegment val in __0) { if (val != null) { val.speakerText = Texts.Translate(val.speakerText); val.bodyText = Texts.Translate(val.bodyText); } } } } internal static class Words { private static readonly Dictionary<string, string> Weather = new Dictionary<string, string> { ["Rainy"] = "Дождь", ["Stormy"] = "Гроза", ["Foggy"] = "Туман", ["Flooded"] = "Потоп", ["Eclipsed"] = "Затмение", ["DustClouds"] = "Пыльная буря", ["None"] = "Ясно" }; private static readonly Dictionary<string, string> Days = new Dictionary<string, string> { ["Monday"] = "понедельник", ["Tuesday"] = "вторник", ["Wednesday"] = "среда", ["Thursday"] = "четверг", ["Friday"] = "пятница", ["Saturday"] = "суббота", ["Sunday"] = "воскресенье" }; private static readonly Regex InList = new Regex("\\((Rainy|Stormy|Foggy|Flooded|Eclipsed|DustClouds)\\)"); private static readonly Regex OnScreen = new Regex("(Погода: )(Rainy|Stormy|Foggy|Flooded|Eclipsed|DustClouds|None)\\b"); private static readonly Regex Today = new Regex("(Сегодня )(Monday|Tuesday|Wednesday|Thursday|Friday|Saturday|Sunday)\\b"); public static string Apply(string s) { if (string.IsNullOrEmpty(s)) { return s; } if (s.IndexOf('(') >= 0) { s = InList.Replace(s, (Match m) => "(" + Weather[m.Groups[1].Value] + ")"); } if (s.IndexOf("Погода: ", StringComparison.Ordinal) >= 0) { s = OnScreen.Replace(s, (Match m) => m.Groups[1].Value + Weather[m.Groups[2].Value]); } if (s.IndexOf("Сегодня ", StringComparison.Ordinal) >= 0) { s = Today.Replace(s, (Match m) => m.Groups[1].Value + Days[m.Groups[2].Value]); } return s; } } [HarmonyPatch(typeof(Terminal), "RemovePunctuation")] internal static class TerminalInput { private static void Postfix(ref string __result) { string text = Commands.Translate(__result); if (text != __result) { Plugin.Log.LogInfo((object)("терминал: «" + __result + "» -> «" + text + "»")); } __result = text; } } [HarmonyPatch(/*Could not decode attribute arguments.*/)] internal static class TmpTextSetter { private static void Prefix(ref string value) { value = Texts.Translate(value); } } [HarmonyPatch] internal static class TmpSetText { private static IEnumerable<MethodBase> TargetMethods() { Type[][] array = new Type[2][] { new Type[1] { typeof(string) }, new Type[2] { typeof(string), typeof(bool) } }; foreach (Type[] array2 in array) { MethodInfo methodInfo = AccessTools.Method(typeof(TMP_Text), "SetText", array2, (Type[])null); if (methodInfo != null) { yield return methodInfo; } } } private static void Prefix(ref string sourceText) { sourceText = Texts.Translate(sourceText); } } [HarmonyPatch(/*Could not decode attribute arguments.*/)] internal static class UiTextSetter { private static void Prefix(ref string value) { value = Texts.Translate(value); } } internal static class Voice { private static readonly Dictionary<string, AudioClip> clips = new Dictionary<string, AudioClip>(); private static readonly HashSet<string> logged = new HashSet<string>(); public static int Count => clips.Count; public static void Load(string dir) { if (!Directory.Exists(dir)) { return; } string[] files = Directory.GetFiles(dir, "*.wav"); foreach (string path in files) { try { AudioClip val = Wav.Read(path, Path.GetFileNameWithoutExtension(path)); Object.DontDestroyOnLoad((Object)(object)val); ((Object)val).hideFlags = (HideFlags)61; clips[((Object)val).name] = val; } catch (Exception ex) { Plugin.Log.LogError((object)(Path.GetFileName(path) + ": " + ex.Message)); } } } public static AudioClip Swap(AudioClip c) { if ((Object)(object)c == (Object)null || !clips.TryGetValue(((Object)c).name, out var value) || c == value) { return c; } if (logged.Add(((Object)c).name)) { Plugin.Log.LogInfo((object)("голос: " + ((Object)c).name)); } return value; } } [HarmonyPatch(typeof(AudioSource), "PlayOneShot", new Type[] { typeof(AudioClip), typeof(float) })] internal static class PlayOneShot { private static void Prefix(ref AudioClip clip) { clip = Voice.Swap(clip); } } [HarmonyPatch(/*Could not decode attribute arguments.*/)] internal static class ClipSetter { private static void Prefix(ref AudioClip value) { value = Voice.Swap(value); } } [HarmonyPatch] internal static class PlayStored { private static IEnumerable<MethodBase> TargetMethods() { yield return AccessTools.Method(typeof(AudioSource), "Play", Type.EmptyTypes, (Type[])null); yield return AccessTools.Method(typeof(AudioSource), "Play", new Type[1] { typeof(ulong) }, (Type[])null); yield return AccessTools.Method(typeof(AudioSource), "PlayDelayed", new Type[1] { typeof(float) }, (Type[])null); } private static void Prefix(AudioSource __instance) { AudioClip clip = __instance.clip; AudioClip val = Voice.Swap(clip); if (clip != val) { __instance.clip = val; } } } [HarmonyPatch(typeof(AudioSource), "PlayClipAtPoint", new Type[] { typeof(AudioClip), typeof(Vector3), typeof(float) })] internal static class PlayAtPoint { private static void Prefix(ref AudioClip clip) { clip = Voice.Swap(clip); } } internal static class Wav { public static AudioClip Read(string path, string name) { byte[] array = File.ReadAllBytes(path); if (array.Length < 44 || array[0] != 82 || array[8] != 87) { throw new Exception("не WAV"); } int num = 0; int num2 = 0; int num3 = 0; int num4 = -1; int num5 = 0; int num6; for (int i = 12; i + 8 <= array.Length; i += 8 + num6 + (num6 & 1)) { string text = Encoding.ASCII.GetString(array, i, 4); num6 = BitConverter.ToInt32(array, i + 4); if (text == "fmt ") { if (BitConverter.ToInt16(array, i + 8) != 1) { throw new Exception("не PCM"); } num = BitConverter.ToInt16(array, i + 10); num2 = BitConverter.ToInt32(array, i + 12); num3 = BitConverter.ToInt16(array, i + 22); } else if (text == "data") { num4 = i + 8; num5 = Math.Min(num6, array.Length - num4); break; } } if (num3 != 16 || num4 < 0) { throw new Exception($"нужен PCM 16 бит (здесь {num3})"); } int num7 = num5 / 2; float[] array2 = new float[num7]; for (int j = 0; j < num7; j++) { array2[j] = (float)BitConverter.ToInt16(array, num4 + j * 2) / 32768f; } AudioClip obj = AudioClip.Create(name, num7 / num, num, num2, false); obj.SetData(array2, 0); return obj; } } internal static class Textures { private static readonly Dictionary<string, string> files = new Dictionary<string, string>(); private static readonly HashSet<int> done = new HashSet<int>(); private static readonly HashSet<string> point = new HashSet<string>(); public static int Count => files.Count; public static void Load(string dir) { if (!Directory.Exists(dir)) { return; } string[] array = Directory.GetFiles(dir, "*.png"); foreach (string text in array) { files[Path.GetFileNameWithoutExtension(text)] = text; } string path = Path.Combine(dir, "point.txt"); if (!File.Exists(path)) { return; } array = File.ReadAllLines(path); foreach (string text2 in array) { if (text2.Trim().Length > 0 && !text2.TrimStart().StartsWith("#")) { point.Add(text2.Trim()); } } } public static void Apply() { if (files.Count == 0) { return; } Texture2D[] array = Resources.FindObjectsOfTypeAll<Texture2D>(); foreach (Texture2D val in array) { if (!files.TryGetValue(((Object)val).name, out var value) || done.Contains(((Object)val).GetInstanceID())) { continue; } if (ImageConversion.LoadImage(val, File.ReadAllBytes(value), false)) { done.Add(((Object)val).GetInstanceID()); if (point.Contains(((Object)val).name)) { ((Texture)val).filterMode = (FilterMode)0; } Plugin.Log.LogInfo((object)("текстура: " + ((Object)val).name)); } else { Plugin.Log.LogWarning((object)("текстура не загрузилась: " + ((Object)val).name)); } } } } internal static class Fonts { private static readonly HashSet<int> opened = new HashSet<int>(); private static readonly Dictionary<string, TMP_FontAsset> fallbacks = new Dictionary<string, TMP_FontAsset>(); public static void Apply() { //IL_0075: Unknown result type (might be due to invalid IL or missing references) //IL_007b: Invalid comparison between Unknown and I4 //IL_00a4: Unknown result type (might be due to invalid IL or missing references) //IL_00a9: Unknown result type (might be due to invalid IL or missing references) //IL_00b6: Unknown result type (might be due to invalid IL or missing references) //IL_00bb: Unknown result type (might be due to invalid IL or missing references) //IL_0288: Unknown result type (might be due to invalid IL or missing references) //IL_028d: Unknown result type (might be due to invalid IL or missing references) Font val = null; Font[] array = Resources.FindObjectsOfTypeAll<Font>(); foreach (Font val2 in array) { if (((Object)val2).name == "3270-Regular") { val = val2; break; } } if ((Object)(object)val == (Object)null) { return; } FieldInfo fieldInfo = AccessTools.Field(typeof(TMP_FontAsset), "m_SourceFontFile"); List<string> list = new List<string>(); TMP_FontAsset[] array2 = Resources.FindObjectsOfTypeAll<TMP_FontAsset>(); FaceInfo faceInfo; foreach (TMP_FontAsset val3 in array2) { if ((int)val3.atlasPopulationMode != 1 || val3.atlasTextures == null || !opened.Add(((Object)val3).GetInstanceID())) { continue; } faceInfo = val3.faceInfo; int num; if (((FaceInfo)(ref faceInfo)).familyName != null) { faceInfo = val3.faceInfo; num = (((FaceInfo)(ref faceInfo)).familyName.Contains("3270") ? 1 : 0); } else { num = 0; } bool flag = (byte)num != 0; string text = ""; if ((Object)(object)val3.sourceFontFile == (Object)null && flag && fieldInfo != null) { fieldInfo.SetValue(val3, val); text += " +исходник"; } for (int j = 0; j < val3.atlasTextures.Length; j++) { Texture2D val4 = val3.atlasTextures[j]; if ((Object)(object)val4 == (Object)null || ((Texture)val4).isReadable) { continue; } Texture2D val5 = Readable(val4); val3.atlasTextures[j] = val5; Material[] array3 = Resources.FindObjectsOfTypeAll<Material>(); foreach (Material val6 in array3) { if (val6.HasProperty(ShaderUtilities.ID_MainTex) && (Object)(object)val6.GetTexture(ShaderUtilities.ID_MainTex) == (Object)(object)val4) { val6.SetTexture(ShaderUtilities.ID_MainTex, (Texture)(object)val5); } } text += " +атлас"; } list.Add(((Object)val3).name + ((text.Length > 0) ? text : " (как есть)") + (((Object)(object)val3.sourceFontFile == (Object)null) ? " БЕЗ ИСХОДНИКА" : "")); } if (list.Count > 0) { Plugin.Log.LogInfo((object)("шрифты: " + string.Join("; ", list))); } array2 = Resources.FindObjectsOfTypeAll<TMP_FontAsset>(); foreach (TMP_FontAsset val7 in array2) { if (((Object)val7).name.StartsWith("LethalFurry") || (val7.HasCharacter('Ж', false, true) && val7.HasCharacter('л', false, true))) { continue; } faceInfo = val7.faceInfo; if ((((FaceInfo)(ref faceInfo)).familyName ?? "").Contains("Liberation")) { continue; } TMP_FontAsset val8 = FallbackFor(val, val7); if (val7.fallbackFontAssetTable == null) { val7.fallbackFontAssetTable = new List<TMP_FontAsset>(); } if (!val7.fallbackFontAssetTable.Contains(val8)) { val7.fallbackFontAssetTable.Insert(0, val8); ManualLogSource log = Plugin.Log; string[] obj = new string[6] { "шрифты: ", ((Object)val7).name, " (", null, null, null }; Material material = ((TMP_Asset)val7).material; object obj2; if (material == null) { obj2 = null; } else { Shader shader = material.shader; obj2 = ((shader != null) ? ((Object)shader).name : null); } obj[3] = (string)obj2; obj[4] = ") <- "; obj[5] = ((Object)val8).name; log.LogInfo((object)string.Concat(obj)); } } } private static TMP_FontAsset FallbackFor(Font src, TMP_FontAsset like) { //IL_0002: 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_0031: 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_0048: 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: Invalid comparison between Unknown and I4 //IL_00e0: Unknown result type (might be due to invalid IL or missing references) //IL_00e5: Unknown result type (might be due to invalid IL or missing references) //IL_00fe: Expected O, but got Unknown //IL_00c1: Unknown result type (might be due to invalid IL or missing references) FaceInfo faceInfo = like.faceInfo; int num = Mathf.Max(8, Mathf.RoundToInt((float)((FaceInfo)(ref faceInfo)).pointSize)); int num2 = ((like.atlasPadding > 0) ? like.atlasPadding : 9); GlyphRenderMode atlasRenderMode = like.atlasRenderMode; string text = $"{num}/{num2}/{atlasRenderMode}"; if (fallbacks.TryGetValue(text, out var value) && (Object)(object)value != (Object)null) { return value; } value = TMP_FontAsset.CreateFontAsset(src, num, num2, (GlyphRenderMode)4165, 1024, 1024, (AtlasPopulationMode)1, true); ((Object)value).name = "LethalFurry Cyrillic " + text; if ((int)atlasRenderMode != 4165) { AccessTools.Field(typeof(TMP_FontAsset), "m_AtlasRenderMode")?.SetValue(value, atlasRenderMode); } if ((Object)(object)((TMP_Asset)like).material != (Object)null) { Material val = new Material(((TMP_Asset)like).material) { name = ((Object)value).name + " Material" }; val.SetTexture(ShaderUtilities.ID_MainTex, (Texture)(object)value.atlasTexture); ((TMP_Asset)value).material = val; } Object.DontDestroyOnLoad((Object)(object)value); fallbacks[text] = value; return value; } private static Texture2D Readable(Texture2D src) { //IL_0030: Unknown result type (might be due to invalid IL or missing references) //IL_0036: Expected O, but got Unknown //IL_0045: Unknown result type (might be due to invalid IL or missing references) //IL_0065: Unknown result type (might be due to invalid IL or missing references) //IL_006b: Invalid comparison between Unknown and I4 //IL_0073: Unknown result type (might be due to invalid IL or missing references) //IL_0078: Unknown result type (might be due to invalid IL or missing references) //IL_0084: 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_0090: Unknown result type (might be due to invalid IL or missing references) //IL_0092: Unknown result type (might be due to invalid IL or missing references) //IL_009c: Unknown result type (might be due to invalid IL or missing references) //IL_00a8: Unknown result type (might be due to invalid IL or missing references) //IL_00b6: Unknown result type (might be due to invalid IL or missing references) //IL_00bc: Expected O, but got Unknown //IL_00bd: Expected O, but got Unknown int width = ((Texture)src).width; int height = ((Texture)src).height; RenderTexture temporary = RenderTexture.GetTemporary(width, height, 0, (RenderTextureFormat)0, (RenderTextureReadWrite)1); Graphics.Blit((Texture)(object)src, temporary); RenderTexture active = RenderTexture.active; RenderTexture.active = temporary; Texture2D val = new Texture2D(width, height, (TextureFormat)4, false, true); val.ReadPixels(new Rect(0f, 0f, (float)width, (float)height), 0, 0); val.Apply(); RenderTexture.active = active; RenderTexture.ReleaseTemporary(temporary); Texture2D val2 = new Texture2D(width, height, (TextureFormat)(((int)src.format == 1) ? 1 : 4), false, true) { name = ((Object)src).name, filterMode = ((Texture)src).filterMode, wrapMode = ((Texture)src).wrapMode }; val2.SetPixels32(val.GetPixels32()); val2.Apply(false, false); Object.Destroy((Object)(object)val); Object.DontDestroyOnLoad((Object)val2); return val2; } } }