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 Sweet RU RepoRoles v1.0.0
SweetRuRepoRoles.dll
Decompiled 17 hours agousing System; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Linq; using System.Reflection; using System.Reflection.Emit; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Text; using BepInEx; using BepInEx.Bootstrap; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; using Microsoft.CodeAnalysis; using SweetRu; using UnityEngine; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")] [assembly: AssemblyCompany("SweetRuRepoRoles")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0")] [assembly: AssemblyProduct("SweetRuRepoRoles")] [assembly: AssemblyTitle("SweetRuRepoRoles")] [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 SweetRu { internal static class Core { internal static ManualLogSource Log; internal static string Folder; internal static readonly Dictionary<string, string> ItemNames = new Dictionary<string, string>(); internal static readonly Dictionary<string, string> EnemyNames = new Dictionary<string, string>(); internal static readonly Dictionary<string, string> ChatLines = new Dictionary<string, string>(); internal static bool UseLocalizedNames; internal static Dictionary<string, string> LoadTsv(string fileName, Dictionary<string, string> into = null) { Dictionary<string, string> dictionary = into ?? new Dictionary<string, string>(); string text = Path.Combine(Folder, fileName); if (!File.Exists(text)) { Log.LogWarning((object)("Missing translation file: " + text)); return dictionary; } try { string[] array = File.ReadAllLines(text, Encoding.UTF8); foreach (string text2 in array) { if (!string.IsNullOrWhiteSpace(text2) && !text2.StartsWith("#")) { string[] array2 = text2.Split('\t'); if (array2.Length == 2 && !string.IsNullOrWhiteSpace(array2[1])) { dictionary[Unescape(array2[0])] = Unescape(array2[1]); } } } Log.LogInfo((object)("Loaded " + dictionary.Count + " lines from " + fileName + ".")); } catch (Exception ex) { Log.LogError((object)("Failed to read " + fileName + ": " + ex.Message)); } return dictionary; } private static string Unescape(string value) { return value.Replace("\\n", "\n").Replace("\\t", "\t").Replace("\\s", " "); } internal static Assembly AssemblyOfPlugin(string pluginGuid) { if (Chainloader.PluginInfos.TryGetValue(pluginGuid, out var value) && (Object)(object)value.Instance != (Object)null) { return ((object)value.Instance).GetType().Assembly; } Log.LogError((object)("Plugin " + pluginGuid + " is not loaded.")); return null; } } internal static class Literals { private const BindingFlags AllMembers = BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic; private const byte LdstrOpcode = 114; private const int StringTokenType = 1879048192; private static Dictionary<string, string> map; internal static int Apply(Harmony harmony, Assembly target, Dictionary<string, string> dictionary) { //IL_0040: Unknown result type (might be due to invalid IL or missing references) //IL_0046: Expected O, but got Unknown if (target == null) { Core.Log.LogError((object)"Target assembly not loaded, nothing to rewrite."); return 0; } if (dictionary.Count == 0) { return 0; } map = dictionary; HarmonyMethod val = new HarmonyMethod(AccessTools.Method(typeof(Literals), "Transpiler", (Type[])null, (Type[])null)); int num = 0; foreach (Type item in TypesOf(target)) { if (item == null || item.IsGenericTypeDefinition) { continue; } foreach (MethodBase item2 in MembersOf(item)) { if (LoadsTranslatedString(item2, item.Module)) { try { harmony.Patch(item2, (HarmonyMethod)null, (HarmonyMethod)null, val, (HarmonyMethod)null, (HarmonyMethod)null); num++; } catch (Exception ex) { Core.Log.LogWarning((object)("Could not rewrite " + item.FullName + "." + item2.Name + ": " + ex.Message)); } } } } Core.Log.LogInfo((object)("Rewrote text in " + num + " methods of " + target.GetName().Name + ".")); return num; } private static IEnumerable<Type> TypesOf(Assembly assembly) { try { return assembly.GetTypes(); } catch (ReflectionTypeLoadException ex) { return ex.Types.Where((Type t) => t != null); } } private static IEnumerable<MethodBase> MembersOf(Type type) { return from m in type.GetMethods(BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic).Cast<MethodBase>().Concat(type.GetConstructors(BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic)) where !m.IsAbstract && !m.ContainsGenericParameters select m; } private static bool LoadsTranslatedString(MethodBase method, Module module) { byte[] array; try { array = method.GetMethodBody()?.GetILAsByteArray(); } catch { return false; } if (array == null) { return false; } for (int i = 0; i + 4 < array.Length; i++) { if (array[i] != 114) { continue; } int num = BitConverter.ToInt32(array, i + 1); if ((num & -16777216) != 1879048192) { continue; } try { if (map.ContainsKey(module.ResolveString(num))) { return true; } } catch { } } return false; } private static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instructions) { foreach (CodeInstruction instruction in instructions) { if (instruction.opcode == OpCodes.Ldstr && instruction.operand is string key && map.TryGetValue(key, out var value)) { instruction.operand = value; } yield return instruction; } } } [HarmonyPatch(typeof(ItemAttributes), "ShowingInfo")] internal static class ItemNamePatch { private const string TagMarker = " <color=#FFFFFF>["; [HarmonyPostfix] private static void Postfix(ref string ___promptName) { if (!string.IsNullOrEmpty(___promptName)) { int num = ___promptName.IndexOf(" <color=#FFFFFF>[", StringComparison.Ordinal); string key = ((num >= 0) ? ___promptName.Substring(0, num) : ___promptName); if (Core.ItemNames.TryGetValue(key, out var value)) { ___promptName = ((num >= 0) ? (value + ___promptName.Substring(num)) : value); } } } } [HarmonyPatch(typeof(EnemyParent), "Awake")] internal static class EnemyNamePatch { [HarmonyPostfix] private static void Postfix(EnemyParent __instance) { if (Core.UseLocalizedNames && (Object)(object)__instance.enemyNameLocalized != (Object)null) { string text = null; try { text = __instance.enemyNameLocalized.GetLocalizedString(); } catch { } if (!string.IsNullOrEmpty(text)) { __instance.enemyName = text; } } if (__instance.enemyName != null && Core.EnemyNames.TryGetValue(__instance.enemyName, out var value)) { __instance.enemyName = value; } } } [HarmonyPatch(typeof(ChatManager), "PossessChat")] internal static class ChatLinePatch { [HarmonyPrefix] private static void Prefix(ref string message) { if (message != null && Core.ChatLines.TryGetValue(message, out var value)) { message = value; } } } } namespace SweetRuRepoRoles { [BepInPlugin("sweet.ru.reporoles", "Sweet RU: REPO Roles Classic", "1.0.0")] [BepInDependency(/*Could not decode attribute arguments.*/)] [BepInDependency(/*Could not decode attribute arguments.*/)] public class Plugin : BaseUnityPlugin { public const string Guid = "sweet.ru.reporoles"; public const string Version = "1.0.0"; private const string TargetGuid = "R3Labs.Repo_Roles.Classic"; private const string RolesType = "Repo_Roles.RepoRoles"; private const string GuiType = "R.E.P.O.Roles.patches.guiManager"; private const string RoleIdEntry = "savedRole"; private static readonly string[] OverlayFonts = new string[4] { "Liberation Sans Narrow", "Arial Narrow", "Segoe UI", "Arial" }; private static FieldInfo customFontField; private static Font cyrillicFont; private void Awake() { //IL_0025: Unknown result type (might be due to invalid IL or missing references) //IL_002b: Expected O, but got Unknown Core.Log = ((BaseUnityPlugin)this).Logger; Core.Folder = Path.GetDirectoryName(((BaseUnityPlugin)this).Info.Location); Harmony val = new Harmony("sweet.ru.reporoles"); Core.LoadTsv("Items.tsv", Core.ItemNames); if (Core.ItemNames.Count > 0) { val.PatchAll(typeof(ItemNamePatch)); } Literals.Apply(val, Core.AssemblyOfPlugin("R3Labs.Repo_Roles.Classic"), Core.LoadTsv("Hardcoded.tsv")); TranslateRoleConfig(); ReplaceOverlayFont(val); Core.UseLocalizedNames = true; val.PatchAll(typeof(EnemyNamePatch)); } private void TranslateRoleConfig() { Type type = AccessTools.TypeByName("Repo_Roles.RepoRoles"); if (type == null) { Core.Log.LogError((object)"Type Repo_Roles.RepoRoles not found, role names stay English."); return; } Dictionary<string, string> dictionary = Core.LoadTsv("Roles.tsv"); int num = 0; foreach (FieldInfo declaredField in AccessTools.GetDeclaredFields(type)) { if (declaredField.IsStatic && !(declaredField.FieldType != typeof(ConfigEntry<string>)) && !(declaredField.Name == "savedRole") && declaredField.GetValue(null) is ConfigEntry<string> val && val.Value != null && dictionary.TryGetValue(val.Value, out var value)) { val.Value = value; num++; } } Core.Log.LogInfo((object)("Translated " + num + " role names and descriptions.")); } private void ReplaceOverlayFont(Harmony harmony) { //IL_0080: Unknown result type (might be due to invalid IL or missing references) //IL_008d: Expected O, but got Unknown Type type = AccessTools.TypeByName("R.E.P.O.Roles.patches.guiManager"); MethodInfo methodInfo = ((type != null) ? AccessTools.Method(type, "loadFont", (Type[])null, (Type[])null) : null); customFontField = ((type != null) ? AccessTools.Field(type, "customFont") : null); if (methodInfo == null || customFontField == null) { Core.Log.LogError((object)"guiManager.loadFont not found, the overlay keeps its Latin-only font."); } else { harmony.Patch((MethodBase)methodInfo, (HarmonyMethod)null, new HarmonyMethod(AccessTools.Method(typeof(Plugin), "AfterLoadFont", (Type[])null, (Type[])null)), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); } } private static void AfterLoadFont() { Font val = CyrillicFont(); if ((Object)(object)val != (Object)null) { customFontField.SetValue(null, val); } } private static Font CyrillicFont() { if ((Object)(object)cyrillicFont != (Object)null) { return cyrillicFont; } cyrillicFont = Font.CreateDynamicFontFromOSFont(OverlayFonts, 24); if ((Object)(object)cyrillicFont == (Object)null) { Core.Log.LogError((object)"No system font could be loaded, the overlay keeps its own font."); return null; } ((Object)cyrillicFont).hideFlags = (HideFlags)32; Core.Log.LogInfo((object)("Overlay font set to " + ((Object)cyrillicFont).name + " (dynamic: " + cyrillicFont.dynamic + ").")); return cyrillicFont; } } }