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 BetterEXP Chinese v0.1.0
BepInEx/plugins/BetterEXPChinese/BetterEXPChinese.dll
Decompiled 2 hours agousing System; using System.Collections.Generic; using System.IO; using System.Reflection; using System.Reflection.Emit; using System.Runtime.CompilerServices; using System.Xml; using BepInEx; using BepInEx.Bootstrap; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; using TMPro; using UnityEngine; [assembly: AssemblyFileVersion("0.1.0.0")] [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: AssemblyVersion("0.1.0.0")] namespace BetterEXPChinese; [BepInDependency("Swaggies.BetterEXP", "3.0.1")] [BepInDependency("Aueser.LCChineseProject", "3.3.2")] [BepInPlugin("hjm.betterexp.zhcn", "BetterEXP 简体中文", "0.1.0")] public sealed class Plugin : BaseUnityPlugin { public const string Guid = "hjm.betterexp.zhcn"; private Harmony harmony; internal static ManualLogSource Log; private void Awake() { //IL_00a3: Unknown result type (might be due to invalid IL or missing references) //IL_00ad: Expected O, but got Unknown //IL_00da: Unknown result type (might be due to invalid IL or missing references) //IL_00e6: Expected O, but got Unknown Log = ((BaseUnityPlugin)this).Logger; PluginInfo val = Chainloader.PluginInfos["Swaggies.BetterEXP"]; if (val.Metadata.Version != new Version(3, 0, 1)) { ((BaseUnityPlugin)this).Logger.LogWarning((object)"BetterEXP Chinese 0.1.0 targets BetterEXP 3.0.1. Other versions are left unchanged."); return; } try { string path = Path.Combine(Path.GetDirectoryName(((BaseUnityPlugin)this).Info.Location), "translations.zh-CN.xml"); if (File.Exists(path)) { using FileStream stream = File.OpenRead(path); Translator.Load(stream); } else { Translator.LoadEmbedded(); } List<MethodBase> list = DisplayPatches.FindTargets(((object)val.Instance).GetType().Assembly); harmony = new Harmony("hjm.betterexp.zhcn"); foreach (MethodBase item in list) { harmony.Patch(item, (HarmonyMethod)null, (HarmonyMethod)null, new HarmonyMethod(typeof(DisplayPatches), "Transpile", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null); } ((BaseUnityPlugin)this).Logger.LogInfo((object)("Loaded " + Translator.Count + " Chinese entries; installed " + list.Count + " display patches. EXP calculations and rank/save data are untouched.")); } catch (Exception ex) { if (harmony != null) { harmony.UnpatchSelf(); } ((BaseUnityPlugin)this).Logger.LogError((object)("Chinese display patches could not be installed; keeping BetterEXP unchanged. " + ex)); } } private void OnApplicationQuit() { if (harmony != null) { harmony.UnpatchSelf(); } } } public static class DisplayPatches { public static List<MethodBase> FindTargets(Assembly assembly) { List<MethodBase> list = new List<MethodBase>(); Add(list, assembly, "LCBetterEXP.NotesList+Note", "Name"); Add(list, assembly, "LCBetterEXP.NotesList+Note", "Listing"); Add(list, assembly, "LCBetterEXP.EXPBarManager", "StartEXPBarAnimation"); Add(list, assembly, "LCBetterEXP.EXPBarManager", "UpdateEXPBar"); Add(list, assembly, "LCBetterEXP.PauseMenuDisplay", "Update"); Add(list, assembly, "LCBetterEXP.PerformanceReportManager", "OnPerformanceReport"); int num = 0; Type[] types = assembly.GetTypes(); foreach (Type type in types) { if (!(type.DeclaringType == null) && !(type.DeclaringType.FullName != "LCBetterEXP.GlobalManager") && type.Name.IndexOf("ShowExpGains", StringComparison.Ordinal) >= 0) { MethodInfo methodInfo = AccessTools.DeclaredMethod(type, "MoveNext", (Type[])null, (Type[])null); if (methodInfo != null) { list.Add(methodInfo); num++; } } } if (num != 1) { throw new MissingMethodException("Expected exactly one BetterEXP summary iterator."); } return list; } private static void Add(List<MethodBase> methods, Assembly assembly, string type, string name) { Type type2 = assembly.GetType(type, throwOnError: true); MethodInfo methodInfo = AccessTools.DeclaredMethod(type2, name, (Type[])null, (Type[])null); if (methodInfo == null) { throw new MissingMethodException(type, name); } methods.Add(methodInfo); } public static IEnumerable<CodeInstruction> Transpile(IEnumerable<CodeInstruction> source, MethodBase __originalMethod) { MethodInfo exact = AccessTools.Method(typeof(Translator), "Exact", (Type[])null, (Type[])null); MethodInfo label = AccessTools.Method(typeof(Translator), "ExpLabel", (Type[])null, (Type[])null); MethodInfo setter = AccessTools.Method(typeof(ChineseText), "SetText", (Type[])null, (Type[])null); bool listing = __originalMethod.Name == "Listing"; foreach (CodeInstruction instruction in source) { if (instruction.opcode == OpCodes.Ldstr) { instruction.operand = Translator.Exact((string)instruction.operand); } MethodInfo called = instruction.operand as MethodInfo; if (called != null && called.Name == "set_text" && called.DeclaringType == typeof(TMP_Text)) { instruction.opcode = OpCodes.Call; instruction.operand = setter; } yield return instruction; FieldInfo field = instruction.operand as FieldInfo; if (instruction.opcode == OpCodes.Ldfld && field != null && field.FieldType == typeof(string)) { string owner = field.DeclaringType.FullName; bool name = field.Name == "name" && (owner == "LCBetterEXP.EXPLevels+EXPLevel" || owner == "LCBetterEXP.NotesList+Note"); bool unit = listing && field.DeclaringType.IsGenericType && field.DeclaringType.GetGenericTypeDefinition() == typeof(ValueTuple<, >) && (field.Name == "Item1" || field.Name == "Item2"); if (name || unit) { yield return new CodeInstruction(OpCodes.Call, (object)exact); } } if (called != null && called.Name == "get_Value" && called.ReturnType == typeof(string) && called.DeclaringType.IsGenericType && called.DeclaringType.GetGenericTypeDefinition() == typeof(ConfigEntry<>)) { yield return new CodeInstruction(OpCodes.Call, (object)label); } } } } public static class ChineseText { private static bool warned; public static void SetText(TMP_Text text, string value) { if (!((Object)(object)text == (Object)null)) { if (Translator.ContainsChinese(value)) { EnsureFont(text); } text.text = value; } } private static void EnsureFont(TMP_Text text) { List<TMP_FontAsset> fallbackFontAssets = TMP_Settings.fallbackFontAssets; if ((Object)(object)text.font == (Object)null || fallbackFontAssets == null) { return; } foreach (TMP_FontAsset item in fallbackFontAssets) { if ((Object)(object)item == (Object)null || !item.HasCharacter('中', false, false)) { continue; } if (!((Object)(object)item == (Object)(object)text.font)) { List<TMP_FontAsset> list = text.font.fallbackFontAssetTable; if (list == null) { list = (text.font.fallbackFontAssetTable = new List<TMP_FontAsset>()); } if (!list.Contains(item)) { list.Add(item); } } return; } if (!warned) { warned = true; if (Plugin.Log != null) { Plugin.Log.LogWarning((object)"No Chinese fallback font is available yet. Check LC Chinese Project font loading."); } } } } public static class Translator { private static Dictionary<string, string> entries = new Dictionary<string, string>(StringComparer.Ordinal); public static int Count => entries.Count; public static void Load(Stream stream) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Expected O, but got Unknown //IL_001a: Unknown result type (might be due to invalid IL or missing references) //IL_0021: Expected O, but got Unknown //IL_006d: Unknown result type (might be due to invalid IL or missing references) //IL_0074: Expected O, but got Unknown XmlReaderSettings val = new XmlReaderSettings(); val.DtdProcessing = (DtdProcessing)0; val.XmlResolver = null; XmlReaderSettings val2 = val; XmlDocument val3 = new XmlDocument(); val3.XmlResolver = null; XmlDocument val4 = val3; XmlReader val5 = XmlReader.Create(stream, val2); try { val4.Load(val5); } finally { ((IDisposable)val5)?.Dispose(); } Dictionary<string, string> dictionary = new Dictionary<string, string>(StringComparer.Ordinal); foreach (XmlNode item in ((XmlNode)val4).SelectNodes("/translations/entry")) { XmlNode val6 = item; string text = ((XmlNode)val6["source"]).InnerText.Replace("\r\n", "\n"); if (dictionary.ContainsKey(text)) { throw new InvalidDataException("Duplicate translation: " + text); } dictionary.Add(text, ((XmlNode)val6["target"]).InnerText); } entries = dictionary; } public static void LoadEmbedded() { using Stream stream = Assembly.GetExecutingAssembly().GetManifestResourceStream("BetterEXPChinese.zhCN.xml"); if (stream == null) { throw new FileNotFoundException("Embedded Chinese translation is missing."); } Load(stream); } public static string Exact(string source) { if (source == null) { return null; } if (!entries.TryGetValue(source.Replace("\r\n", "\n"), out var value)) { return source; } return value; } public static string ExpLabel(string source) { switch (source) { default: return source; case "EXP": case "BXP": case "XP": return "经验"; } } public static bool ContainsChinese(string value) { if (value == null) { return false; } foreach (char c in value) { if (c >= '㐀' && c <= '鿿') { return true; } } return false; } }