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 REPOFurryRU v1.0.2
plugins/REPOFurryRU/REPOFurryRU.dll
Decompiled 6 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 BepInEx; using BepInEx.Logging; using HarmonyLib; using Microsoft.CodeAnalysis; using Newtonsoft.Json; using TMPro; using UnityEngine; using UnityEngine.Localization.Settings; using UnityEngine.Localization.Tables; using UnityEngine.SceneManagement; using UnityEngine.TextCore.LowLevel; [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("REPOFurryRU")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0")] [assembly: AssemblyProduct("REPOFurryRU")] [assembly: AssemblyTitle("REPOFurryRU")] [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 REPOFurry { [BepInPlugin("clauderushub.repofurry", "REPOFurryRU", "1.0.2")] public class Plugin : BaseUnityPlugin { public const string Guid = "clauderushub.repofurry"; internal static ManualLogSource Log; internal static string Dir; private void Awake() { //IL_004d: Unknown result type (might be due to invalid IL or missing references) //IL_0053: 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")); Harmony val = new Harmony("clauderushub.repofurry"); 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))); } } } CodeStrings.Patch(val); SceneManager.sceneLoaded += delegate { Sweep(); }; Log.LogInfo((object)$"готово: строк {Texts.Count}, в коде {CodeStrings.Patched} методов"); } internal static void Sweep() { Safe("шрифты", Fonts.Apply); Safe("текст сцены", Texts.ApplyScene); } internal static void Safe(string what, Action a) { try { a(); } catch (Exception ex) { Log.LogError((object)(what + ": " + ex)); } } } [HarmonyPatch(typeof(LocalizationManager), "LoadLocalizationOverrides")] internal static class Tables { private static void Postfix() { //IL_0056: Unknown result type (might be due to invalid IL or missing references) int num = 0; string[] array = new string[3] { "HUD", "Menu", "Game" }; foreach (string text in array) { string path = Path.Combine(Plugin.Dir, text + ".tsv"); if (!File.Exists(path)) { continue; } try { StringTable table = ((LocalizedDatabase<StringTable, StringTableEntry>)(object)LocalizationSettings.StringDatabase).GetTable(TableReference.op_Implicit(text), LocalizationSettings.ProjectLocale); string[] array2 = File.ReadAllLines(path, Encoding.UTF8); for (int j = 0; j < array2.Length; j++) { string[] array3 = array2[j].Split('\t'); if (array3.Length == 2) { string text2 = array3[1].Replace("\\n", "\n"); StringTableEntry entry = ((DetailedLocalizationTable<StringTableEntry>)(object)table).GetEntry(array3[0]); if (entry != null) { entry.Value = text2; } else { ((DetailedLocalizationTable<StringTableEntry>)(object)table).AddEntry(array3[0], text2); } num++; } } } catch (Exception ex) { Plugin.Log.LogError((object)("таблица " + text + ": " + ex.Message)); } } Plugin.Log.LogInfo((object)$"таблицы: строк {num}"); Plugin.Safe("шрифты", Fonts.Apply); } } internal static class Texts { private static Dictionary<string, string> exact = new Dictionary<string, string>(); public static int Count => exact.Count; public static void Load(string path) { if (File.Exists(path)) { exact = JsonConvert.DeserializeObject<Dictionary<string, string>>(File.ReadAllText(path)); } } 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 && text.Length > 0 && 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 s; } 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; } } CosmeticAsset[] array2 = Resources.FindObjectsOfTypeAll<CosmeticAsset>(); foreach (CosmeticAsset obj in array2) { obj.assetName = Translate(obj.assetName); } SemiColor[] array3 = Resources.FindObjectsOfTypeAll<SemiColor>(); foreach (SemiColor obj2 in array3) { obj2.colorName = Translate(obj2.colorName); } } } [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); } } 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) { if (item.Key.StartsWith("_")) { continue; } int num = item.Key.LastIndexOf("::", StringComparison.Ordinal); Type type = AccessTools.TypeByName(item.Key.Substring(0, num)); 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)); } } } } } 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 Phrases { private static readonly Random rnd = new Random(); private static readonly string[] LeftBehind = new string[15] { "Меня бросили...", "Они ушли без меня.", "Экипаж уехал, а я осталась лапками кверху.", "Никто не подождал пушистика...", "Меня забыли в темноте.", "Грузовичок уехал без меня.", "Я думал, мы одна команда.", "Почему они не подождали?", "Что я сделал не так?", "Теперь я совсем один.", "Они были моей последней надеждой.", "Так нечестно, фыр.", "Бросили маленького робота...", "Ушли и даже хвостиком не махнули.", "Я так и знал." }; private static readonly string[] Love = new string[14] { "{0} такой милашка, аж мурчу!", "Не могу перестать думать о {0}.", "{0}, ты лучше всех!", "Хочу обнимашек с {0}!", "Каждый раз, когда вижу {0}, виляю хвостиком.", "{0} — моё солнышко.", "С {0} даже бяки не страшны.", "Кажется, я влюбился в {0}...", "{0}, ты самый пушистый!", "Пойдём собирать блестяшки вместе, {0}?", "Сердечко пищит, когда рядом {0}.", "{0} — мой лучший друг навсегда!", "Хочу почесать {0} за ушком.", "Ня! {0} сегодня особенно мил." }; private static string Pick(string[] a) { return a[rnd.Next(a.Length)]; } public static string GetLeftBehind() { return Pick(LeftBehind); } public static string GetLove(string name) { return string.Format(Pick(Love), name); } } [HarmonyPatch(typeof(SemiFunc), "MessageGeneratedGetLeftBehind")] internal static class LeftBehindPatch { private static bool Prefix(ref string __result) { __result = Phrases.GetLeftBehind(); return false; } } [HarmonyPatch(typeof(ValuableLovePotion), "GenerateAffectionateSentence")] internal static class LovePotionPatch { private static bool Prefix(ValuableLovePotion __instance, ref string __result) { string name = (AccessTools.Field(typeof(ValuableLovePotion), "playerName")?.GetValue(__instance) as string) ?? ""; __result = Phrases.GetLove(name); return false; } } internal static class Translit { private static readonly Dictionary<char, string> map = new Dictionary<char, string> { ['а'] = "a", ['б'] = "b", ['в'] = "v", ['г'] = "g", ['д'] = "d", ['е'] = "ye", ['ё'] = "yo", ['ж'] = "zh", ['з'] = "z", ['и'] = "ee", ['й'] = "y", ['к'] = "k", ['л'] = "l", ['м'] = "m", ['н'] = "n", ['о'] = "o", ['п'] = "p", ['р'] = "r", ['с'] = "s", ['т'] = "t", ['у'] = "oo", ['ф'] = "f", ['х'] = "kh", ['ц'] = "ts", ['ч'] = "ch", ['ш'] = "sh", ['щ'] = "sch", ['ъ'] = "", ['ы'] = "i", ['ь'] = "", ['э'] = "e", ['ю'] = "yu", ['я'] = "ya" }; internal static readonly Dictionary<string, string> back = new Dictionary<string, string>(); public static string Word(string w) { StringBuilder stringBuilder = new StringBuilder(); bool flag = false; foreach (char c in w) { char key = char.ToLowerInvariant(c); if (map.TryGetValue(key, out var value)) { flag = true; stringBuilder.Append((char.IsUpper(c) && value.Length > 0) ? (char.ToUpperInvariant(value[0]) + value.Substring(1)) : value); } else { stringBuilder.Append(c); } } if (!flag) { return w; } string text = stringBuilder.ToString(); back[text] = w; return text; } public static string Text(string s) { if (string.IsNullOrEmpty(s)) { return s; } string[] array = s.Split(' '); for (int i = 0; i < array.Length; i++) { array[i] = Word(array[i]); } return string.Join(" ", array); } } [HarmonyPatch(typeof(TTSVoice), "StartSpeakingWithHighlight")] internal static class TtsSpeak { private static void Prefix(ref string text) { Translit.back.Clear(); text = Translit.Text(text); } } [HarmonyPatch(typeof(TTSVoice), "VoiceText")] internal static class TtsShow { private static void Prefix(ref string text) { if (text != null && Translit.back.TryGetValue(text.Trim(), out var value)) { text = value; } } } internal static class Fonts { internal const string Marker = "REPOFurry_"; internal static readonly Dictionary<string, string> files = new Dictionary<string, string>(); private static TMP_FontAsset oswald; public static void Apply() { //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_0063: Expected O, but got Unknown //IL_007d: Expected O, but got Unknown if ((Object)(object)oswald == (Object)null) { string text = Path.Combine(Plugin.Dir, "fonts", "OswaldTeko.ttf"); if (!File.Exists(text)) { Plugin.Log.LogWarning((object)("нет шрифта: " + text)); return; } files["REPOFurry_Oswald"] = text; Font val = new Font("REPOFurry_Oswald"); Object.DontDestroyOnLoad((Object)val); oswald = TMP_FontAsset.CreateFontAsset(val, 90, 9, (GlyphRenderMode)4165, 1024, 1024, (AtlasPopulationMode)1, true); if ((Object)(object)oswald == (Object)null) { Plugin.Log.LogError((object)"шрифт Oswald не создан"); return; } ((Object)oswald).name = "REPOFurry Oswald"; Object.DontDestroyOnLoad((Object)(object)oswald); } List<string> list = new List<string>(); TMP_FontAsset[] array = Resources.FindObjectsOfTypeAll<TMP_FontAsset>(); foreach (TMP_FontAsset val2 in array) { if (val2 != oswald && ((Object)val2).name != null && ((Object)val2).name.StartsWith("Teko")) { if (val2.fallbackFontAssetTable == null) { val2.fallbackFontAssetTable = new List<TMP_FontAsset>(); } if (!val2.fallbackFontAssetTable.Contains(oswald)) { val2.fallbackFontAssetTable.Insert(0, oswald); list.Add(((Object)val2).name); } } } if (list.Count > 0) { Plugin.Log.LogInfo((object)("шрифты: Oswald -> " + string.Join(", ", list))); } } } [HarmonyPatch(typeof(FontEngine), "LoadFontFace", new Type[] { typeof(Font), typeof(int) })] internal static class LoadFace { private static bool Prefix(Font font, int pointSize, ref FontEngineError __result) { //IL_002a: Unknown result type (might be due to invalid IL or missing references) //IL_0030: Expected I4, but got Unknown if ((Object)(object)font == (Object)null || ((Object)font).name == null || !Fonts.files.TryGetValue(((Object)font).name, out var value)) { return true; } __result = (FontEngineError)(int)FontEngine.LoadFontFace(value, pointSize); return false; } } }