using System; using System.Collections.Generic; using System.IO; using System.Linq; using Byway.Thrift.Data; using Thrift.Protocol; using Thrift.Transport.Client; using UnityEditor; using UnityEngine; namespace FontTools { /// /// 语言字符集生成器 /// 从 AllConfigs 读取 LanguageData 表,提取三种语言的字符集并保存为txt /// public class LanguageCharsetGenerator : EditorWindow { private const string DEFAULT_OUTPUT_PATH = "Assets/Design_SubModule/Scripts/Editor/ThriftPipelineTool/CharacterSets"; private string outputPath = DEFAULT_OUTPUT_PATH; private TextAsset allConfigsFile; private Vector2 scrollPosition; private string statusLog = ""; private bool isProcessing = false; private Dictionary charCounts = new Dictionary(); [MenuItem("配置表pipeline/字体/生成字符集")] public static void ShowWindow() { var window = GetWindow("字符集生成器"); window.minSize = new Vector2(600, 500); window.Show(); } private void OnEnable() { // 自动查找 AllConfigs.bytes AutoFindAllConfigs(); } private void OnGUI() { EditorGUILayout.Space(10); EditorGUILayout.LabelField("语言字符集生成器", EditorStyles.boldLabel); EditorGUILayout.HelpBox( "从 AllConfigs.bytes 读取 LanguageData 表\n" + "提取 En_US、Zh_CN、Pt_BR 三个语言列的所有字符(去重)\n" + "生成三个字符集txt文件", MessageType.Info ); EditorGUILayout.Space(10); // AllConfigs 文件选择 EditorGUILayout.BeginVertical("box"); EditorGUILayout.LabelField("1. 选择 AllConfigs.bytes 文件:", EditorStyles.boldLabel); EditorGUILayout.BeginHorizontal(); allConfigsFile = EditorGUILayout.ObjectField("AllConfigs:", allConfigsFile, typeof(TextAsset), false) as TextAsset; if (GUILayout.Button("自动查找", GUILayout.Width(80))) { AutoFindAllConfigs(); } EditorGUILayout.EndHorizontal(); EditorGUILayout.EndVertical(); EditorGUILayout.Space(5); // 输出路径选择 EditorGUILayout.BeginVertical("box"); EditorGUILayout.LabelField("2. 选择输出目录:", EditorStyles.boldLabel); EditorGUILayout.BeginHorizontal(); EditorGUILayout.TextField(outputPath); if (GUILayout.Button("浏览", GUILayout.Width(60))) { string selected = EditorUtility.OpenFolderPanel("选择输出目录", outputPath, ""); if (!string.IsNullOrEmpty(selected)) { // 转换为相对路径 if (selected.StartsWith(Application.dataPath)) { outputPath = "Assets" + selected.Substring(Application.dataPath.Length); } else { outputPath = selected; } } } if (GUILayout.Button("重置", GUILayout.Width(60))) { outputPath = DEFAULT_OUTPUT_PATH; } EditorGUILayout.EndHorizontal(); EditorGUILayout.EndVertical(); EditorGUILayout.Space(10); // 生成按钮 GUI.enabled = !isProcessing && allConfigsFile != null; if (GUILayout.Button("生成字符集", GUILayout.Height(40))) { GenerateCharsets(); } GUI.enabled = true; EditorGUILayout.Space(10); // 统计信息 if (charCounts.Count > 0) { EditorGUILayout.BeginVertical("box"); EditorGUILayout.LabelField("字符统计:", EditorStyles.boldLabel); foreach (var kvp in charCounts.OrderBy(x => x.Key)) { EditorGUILayout.LabelField($" {kvp.Key}: {kvp.Value} 个字符"); } EditorGUILayout.EndVertical(); EditorGUILayout.Space(5); } // 日志区域 EditorGUILayout.LabelField("执行日志:", EditorStyles.boldLabel); scrollPosition = EditorGUILayout.BeginScrollView(scrollPosition, "box", GUILayout.Height(200)); EditorGUILayout.TextArea(statusLog, EditorStyles.wordWrappedLabel); EditorGUILayout.EndScrollView(); } /// /// 自动查找 AllConfigs.bytes /// private void AutoFindAllConfigs() { string[] guids = AssetDatabase.FindAssets("AllConfigs t:TextAsset"); foreach (string guid in guids) { string path = AssetDatabase.GUIDToAssetPath(guid); if (path.EndsWith(".bytes", StringComparison.OrdinalIgnoreCase)) { allConfigsFile = AssetDatabase.LoadAssetAtPath(path); if (allConfigsFile != null) { Log($"✓ 自动找到 AllConfigs: {path}"); return; } } } Log("⚠ 未找到 AllConfigs.bytes,请手动选择"); } /// /// 生成字符集 /// private void GenerateCharsets() { isProcessing = true; statusLog = ""; charCounts.Clear(); try { Log("========================================"); Log("开始生成字符集"); Log("========================================\n"); // 步骤1: 反序列化 AllConfigs Log("[步骤1] 读取 AllConfigs.bytes..."); var allConfigs = DeserializeAllConfigs(allConfigsFile.bytes); if (allConfigs == null) { LogError("✗ 反序列化 AllConfigs 失败!"); return; } Log("✓ AllConfigs 读取成功\n"); // 步骤2: 获取 LanguageData Log("[步骤2] 提取 LanguageData..."); var languageData = allConfigs.LanguageData; if (languageData == null || languageData.Languagedatas == null) { LogError("✗ LanguageData 不存在或为空!"); return; } Log($"✓ 找到 {languageData.Languagedatas.Count} 条语言数据\n"); // 步骤3: 提取字符集 Log("[步骤3] 提取字符集..."); var charsets = ExtractCharsets(languageData); // 步骤4: 保存txt文件 Log("\n[步骤4] 保存txt文件..."); SaveCharsets(charsets); Log("\n========================================"); Log("✓ 字符集生成完成!"); Log($"输出目录: {outputPath}"); Log("========================================"); EditorUtility.DisplayDialog("完成", $"字符集生成成功!\n\n" + $"En_US: {charCounts["En_US"]} 个字符\n" + $"Zh_CN: {charCounts["Zh_CN"]} 个字符\n" + $"Pt_BR: {charCounts["Pt_BR"]} 个字符\n\n" + $"文件保存在: {outputPath}", "确定"); } catch (Exception ex) { LogError($"✗ 生成失败: {ex.Message}\n{ex.StackTrace}"); EditorUtility.DisplayDialog("错误", $"生成失败:\n{ex.Message}", "确定"); } finally { isProcessing = false; Repaint(); } } /// /// 反序列化 AllConfigs /// private AllConfigs DeserializeAllConfigs(byte[] bytes) { try { using (var transport = new TMemoryBufferTransport(bytes, new Thrift.TConfiguration())) using (var protocol = new TBinaryProtocol(transport)) { var allConfigs = new AllConfigs(); allConfigs.ReadAsync(protocol, System.Threading.CancellationToken.None).Wait(); return allConfigs; } } catch (Exception ex) { Debug.LogError($"反序列化失败: {ex.Message}"); return null; } } /// /// 从 LanguageData 提取字符集 /// private Dictionary> ExtractCharsets(LanguageData languageData) { var charsets = new Dictionary> { { "En_US", new HashSet() }, { "Zh_CN", new HashSet() }, { "Pt_BR", new HashSet() } }; int processedCount = 0; int totalCount = languageData.Languagedatas.Count; // 遍历所有行 foreach (var kvp in languageData.Languagedatas) { var item = kvp.Value; // 提取每个语言列的字符 AddChars(charsets["En_US"], item.En_US); AddChars(charsets["Zh_CN"], item.Zh_CN); AddChars(charsets["Pt_BR"], item.Pt_BR); processedCount++; if (processedCount % 100 == 0) { Log($" 处理进度: {processedCount}/{totalCount}"); } } // 确保所有字符集都包含下划线和省略号 foreach (var charset in charsets.Values) { charset.Add('_'); // 下划线 charset.Add('…'); // 省略号 } // 英文字符集额外添加美元符号 charsets["En_US"].Add('$'); // 统计 charCounts["En_US"] = charsets["En_US"].Count; charCounts["Zh_CN"] = charsets["Zh_CN"].Count; charCounts["Pt_BR"] = charsets["Pt_BR"].Count; Log($"✓ En_US: {charCounts["En_US"]} 个字符"); Log($"✓ Zh_CN: {charCounts["Zh_CN"]} 个字符"); Log($"✓ Pt_BR: {charCounts["Pt_BR"]} 个字符"); return charsets; } /// /// 添加字符到集合(排除控制字符) /// private void AddChars(HashSet charset, string text) { if (string.IsNullOrEmpty(text)) return; foreach (char c in text) { if (!char.IsControl(c)) // 排除换行符、制表符等控制字符 { charset.Add(c); } } } /// /// 保存字符集到txt文件 /// private void SaveCharsets(Dictionary> charsets) { // 创建输出目录 if (!Directory.Exists(outputPath)) { Directory.CreateDirectory(outputPath); Log($"✓ 创建目录: {outputPath}"); } foreach (var kvp in charsets) { string langName = kvp.Key; var chars = kvp.Value; // 按 Unicode 排序 var sortedChars = chars.OrderBy(c => (int)c).ToArray(); string content = new string(sortedChars); // 保存文件 string filePath = Path.Combine(outputPath, $"{langName}_charset.txt"); File.WriteAllText(filePath, content, System.Text.Encoding.UTF8); Log($"✓ {langName}: {filePath} ({chars.Count} 字符)"); } // 刷新 AssetDatabase AssetDatabase.Refresh(); } private void Log(string message) { statusLog += message + "\n"; Repaint(); } private void LogError(string message) { statusLog += $"{message}\n"; Debug.LogError(message); Repaint(); } } }