using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using System.Text;
using BepInEx;
using BepInEx.Logging;
using HarmonyLib;
using Jettcodey.FontAPI;
using UnityEngine;
using UnityEngine.UI;
[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: AssemblyTitle("YapYapCnFontMod")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("YapYapCnFontMod")]
[assembly: AssemblyCopyright("Copyright © 2026")]
[assembly: AssemblyTrademark("")]
[assembly: ComVisible(false)]
[assembly: Guid("b470584b-ed47-456f-971d-9cc1817fe7bd")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")]
[assembly: AssemblyVersion("1.0.0.0")]
[BepInPlugin("cn.player.yapyapcnfont", "YapYap中文字体模组", "1.0.0")]
[BepInDependency(/*Could not decode attribute arguments.*/)]
public class YapYapCnFontMod : BaseUnityPlugin
{
private static HashSet<char> missingCharacters = new HashSet<char>();
private static HashSet<string> missingCharacterContexts = new HashSet<string>();
private static string missingCharsPath;
private static Harmony harmony;
private static float lastSaveTime = 0f;
private const float SAVE_INTERVAL = 30f;
public static YapYapCnFontMod Instance { get; private set; }
internal static ManualLogSource Logger { get; private set; }
private void Awake()
{
Instance = this;
Logger = ((BaseUnityPlugin)this).Logger;
Logger.LogInfo((object)"YapYap中文字体模组初始化...");
string directoryName = Path.GetDirectoryName(((BaseUnityPlugin)this).Info.Location);
missingCharsPath = Path.Combine(directoryName, "missing_chinese_characters.txt");
LoadMissingCharacters();
if (string.IsNullOrEmpty(directoryName))
{
Logger.LogError((object)"无法获取插件目录路径");
return;
}
string text = Path.Combine(directoryName, "yapyapcnfontbundle");
Logger.LogInfo((object)("正在加载字体资源包: " + text));
if (!File.Exists(text))
{
Logger.LogError((object)("文件不存在: " + text));
return;
}
AssetBundle val = AssetBundle.LoadFromFile(text);
if ((Object)(object)val == (Object)null)
{
Logger.LogError((object)"AssetBundle加载失败");
return;
}
Logger.LogInfo((object)$"AssetBundle加载成功,包含 {val.GetAllAssetNames().Length} 个资源");
string[] allAssetNames = val.GetAllAssetNames();
foreach (string text2 in allAssetNames)
{
Logger.LogInfo((object)("资源名称: " + text2));
}
ExploreFontAPI(val);
InitializeHarmonyPatches();
Logger.LogInfo((object)"缺失字符监控已启动。当遇到显示为方框的中文字符时,它们将被记录到文件中。");
}
private void Update()
{
if (Time.time - lastSaveTime > 30f && missingCharacters.Count > 0)
{
SaveMissingCharacters();
lastSaveTime = Time.time;
}
}
private void ExploreFontAPI(AssetBundle bundle)
{
try
{
TryCallFontAPI(bundle);
if (!CheckIfFontApplied())
{
TryAlternativeApproach(bundle);
}
}
catch (Exception ex)
{
Logger.LogError((object)("探索FontAPI时出错: " + ex.Message));
}
}
private void TryCallFontAPI(AssetBundle bundle)
{
bool flag = false;
Type typeFromHandle = typeof(FontAPI);
MethodInfo[] methods = typeFromHandle.GetMethods(BindingFlags.Static | BindingFlags.Public);
Logger.LogInfo((object)$"FontAPI共有 {methods.Length} 个公共静态方法:");
MethodInfo[] array = methods;
foreach (MethodInfo methodInfo in array)
{
Logger.LogInfo((object)$"方法: {methodInfo.Name}, 参数: {methodInfo.GetParameters().Length}");
if (!methodInfo.Name.Contains("Font") && !methodInfo.Name.Contains("Set") && !methodInfo.Name.Contains("Load"))
{
continue;
}
try
{
ParameterInfo[] parameters = methodInfo.GetParameters();
if (parameters.Length == 0)
{
methodInfo.Invoke(null, null);
Logger.LogInfo((object)("成功调用 " + methodInfo.Name + "()"));
flag = true;
}
else if (parameters.Length == 1)
{
if (parameters[0].ParameterType == typeof(AssetBundle))
{
methodInfo.Invoke(null, new object[1] { bundle });
Logger.LogInfo((object)("成功调用 " + methodInfo.Name + "(AssetBundle)"));
flag = true;
}
else if (parameters[0].ParameterType == typeof(string))
{
methodInfo.Invoke(null, new object[1] { "ZhengQingKeNanBeiCiGongPuSongTi-2 SDF" });
Logger.LogInfo((object)("成功调用 " + methodInfo.Name + "(string)"));
flag = true;
}
}
else if (parameters.Length == 2)
{
methodInfo.Invoke(null, new object[2] { bundle, "ZhengQingKeNanBeiCiGongPuSongTi-2 SDF" });
Logger.LogInfo((object)("成功调用 " + methodInfo.Name + "(AssetBundle, string)"));
flag = true;
}
}
catch (Exception ex)
{
Logger.LogWarning((object)("调用 " + methodInfo.Name + " 失败: " + (ex.InnerException?.Message ?? ex.Message)));
}
}
if (flag)
{
Logger.LogInfo((object)"至少一个FontAPI方法调用成功");
}
else
{
Logger.LogWarning((object)"所有FontAPI方法调用尝试均失败");
}
}
private bool CheckIfFontApplied()
{
return false;
}
private void TryAlternativeApproach(AssetBundle bundle)
{
Logger.LogInfo((object)"尝试替代方法...");
try
{
Object val = bundle.LoadAsset("ZhengQingKeNanBeiCiGongPuSongTi-2 SDF");
if (val != (Object)null)
{
Logger.LogInfo((object)("成功加载对象,类型: " + ((object)val).GetType().FullName));
Logger.LogInfo((object)("对象名称: " + val.name));
return;
}
Logger.LogError((object)"无法从AssetBundle加载指定名称的对象");
Object[] array = bundle.LoadAllAssets();
Logger.LogInfo((object)$"AssetBundle中包含 {array.Length} 个对象:");
Object[] array2 = array;
foreach (Object val2 in array2)
{
Logger.LogInfo((object)(" - " + val2.name + " (" + ((object)val2).GetType().Name + ")"));
}
}
catch (Exception ex)
{
Logger.LogError((object)("替代方法失败: " + ex.Message));
}
}
private void InitializeHarmonyPatches()
{
//IL_0007: Unknown result type (might be due to invalid IL or missing references)
//IL_0011: Expected O, but got Unknown
//IL_0063: Unknown result type (might be due to invalid IL or missing references)
//IL_0070: Expected O, but got Unknown
try
{
harmony = new Harmony("cn.player.yapyapcnfont.monitor");
Type typeFromHandle = typeof(Text);
if (typeFromHandle != null)
{
MethodInfo methodInfo = typeFromHandle.GetProperty("text")?.GetSetMethod();
if (methodInfo != null)
{
harmony.Patch((MethodBase)methodInfo, (HarmonyMethod)null, new HarmonyMethod(typeof(TextMeshProMonitor), "RecordUIText", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
Logger.LogInfo((object)"已应用UnityEngine.UI.Text补丁");
}
}
TryPatchTextMeshProTypes();
Logger.LogInfo((object)"Harmony补丁已应用,开始监控缺失字符...");
}
catch (Exception ex)
{
Logger.LogError((object)("应用Harmony补丁失败: " + ex.Message));
}
}
private void TryPatchTextMeshProTypes()
{
//IL_0087: Unknown result type (might be due to invalid IL or missing references)
//IL_0094: Expected O, but got Unknown
//IL_00f7: Unknown result type (might be due to invalid IL or missing references)
//IL_0104: Expected O, but got Unknown
try
{
Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies();
Assembly[] array = assemblies;
foreach (Assembly assembly in array)
{
try
{
Type type = assembly.GetType("TMPro.TextMeshProUGUI");
Type type2 = assembly.GetType("TMPro.TextMeshPro");
if (type != null)
{
MethodInfo methodInfo = type.GetProperty("text")?.GetSetMethod();
if (methodInfo != null)
{
harmony.Patch((MethodBase)methodInfo, (HarmonyMethod)null, new HarmonyMethod(typeof(TextMeshProMonitor), "RecordTMPText", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
Logger.LogInfo((object)"已动态应用TextMeshProUGUI补丁");
}
}
if (type2 != null)
{
MethodInfo methodInfo2 = type2.GetProperty("text")?.GetSetMethod();
if (methodInfo2 != null)
{
harmony.Patch((MethodBase)methodInfo2, (HarmonyMethod)null, new HarmonyMethod(typeof(TextMeshProMonitor), "RecordTMP3DText", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
Logger.LogInfo((object)"已动态应用TextMeshPro补丁");
}
}
}
catch
{
}
}
}
catch (Exception ex)
{
Logger.LogWarning((object)("动态加载TextMeshPro类型失败: " + ex.Message));
}
}
private void OnDestroy()
{
if (missingCharacters.Count > 0)
{
SaveMissingCharacters();
}
if (harmony != null)
{
harmony.UnpatchSelf();
Logger.LogInfo((object)"Harmony补丁已清理");
}
}
private void LoadMissingCharacters()
{
if (!File.Exists(missingCharsPath))
{
return;
}
try
{
string text = File.ReadAllText(missingCharsPath, Encoding.UTF8);
string text2 = text;
foreach (char c in text2)
{
if (IsChineseCharacter(c))
{
missingCharacters.Add(c);
}
}
Logger.LogInfo((object)$"从文件加载了 {missingCharacters.Count} 个先前记录的缺失字符");
}
catch (Exception ex)
{
Logger.LogError((object)("加载缺失字符文件失败: " + ex.Message));
}
}
private void SaveMissingCharacters()
{
try
{
StringBuilder stringBuilder = new StringBuilder();
stringBuilder.AppendLine($"# YapYap缺失中文字符记录 - {DateTime.Now:yyyy-MM-dd HH:mm:ss}");
stringBuilder.AppendLine($"# 总缺失字符数: {missingCharacters.Count}");
stringBuilder.AppendLine();
stringBuilder.AppendLine("# 缺失字符列表(直接复制到Unity的字符集文件中):");
int num = 0;
List<char> list = new List<char>(missingCharacters);
list.Sort();
foreach (char item in list)
{
stringBuilder.Append(item);
num++;
if (num % 50 == 0)
{
stringBuilder.AppendLine();
}
}
stringBuilder.AppendLine();
stringBuilder.AppendLine();
stringBuilder.AppendLine("# 缺失字符上下文(出现这些字符的文本示例):");
foreach (string missingCharacterContext in missingCharacterContexts)
{
if (missingCharacterContext.Length > 100)
{
stringBuilder.AppendLine("- " + missingCharacterContext.Substring(0, 100) + "...");
}
else
{
stringBuilder.AppendLine("- " + missingCharacterContext);
}
}
File.WriteAllText(missingCharsPath, stringBuilder.ToString(), Encoding.UTF8);
Logger.LogInfo((object)$"已保存 {missingCharacters.Count} 个缺失字符到: {missingCharsPath}");
}
catch (Exception ex)
{
Logger.LogError((object)("保存缺失字符文件失败: " + ex.Message));
}
}
public static void RecordMissingCharacter(char c, string context = "")
{
if (IsChineseCharacter(c) && !missingCharacters.Contains(c))
{
missingCharacters.Add(c);
if (!string.IsNullOrEmpty(context) && !missingCharacterContexts.Contains(context))
{
missingCharacterContexts.Add(context);
}
if (Logger != null && missingCharacters.Count % 10 == 0)
{
Logger.LogInfo((object)$"已记录 {missingCharacters.Count} 个缺失字符,最新: '{c}' (U+{(int)c:X4})");
}
}
}
public static bool IsChineseCharacter(char c)
{
return (c >= '一' && c <= '\u9fff') || (c >= '㐀' && c <= '䶿') || (c >= 131072 && c <= 173791) || (c >= 173824 && c <= 177983) || (c >= 177984 && c <= 178207) || (c >= 178208 && c <= 183983) || (c >= 183984 && c <= 191471);
}
}
public static class TextMeshProMonitor
{
public static void RecordUIText(Text __instance)
{
if ((Object)(object)__instance != (Object)null && __instance.text != null)
{
CheckAndRecordCharacters(__instance.text, "UnityEngine.UI.Text");
}
}
public static void RecordTMPText(object __instance)
{
try
{
PropertyInfo property = __instance.GetType().GetProperty("text");
if (property != null)
{
string text = property.GetValue(__instance) as string;
if (!string.IsNullOrEmpty(text))
{
CheckAndRecordCharacters(text, "TextMeshProUGUI");
}
}
}
catch
{
}
}
public static void RecordTMP3DText(object __instance)
{
try
{
PropertyInfo property = __instance.GetType().GetProperty("text");
if (property != null)
{
string text = property.GetValue(__instance) as string;
if (!string.IsNullOrEmpty(text))
{
CheckAndRecordCharacters(text, "TextMeshPro");
}
}
}
catch
{
}
}
private static void CheckAndRecordCharacters(string text, string componentType)
{
try
{
bool flag = false;
foreach (char c in text)
{
if (YapYapCnFontMod.IsChineseCharacter(c))
{
flag = true;
YapYapCnFontMod.RecordMissingCharacter(c, text);
}
}
}
catch
{
}
}
}