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();
}
}
}