Design_SubModule/Scripts/Editor/ThriftPipelineTool/LanguageCharsetGenerator.cs
2026-03-30 19:01:50 +08:00

359 lines
13 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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
{
/// <summary>
/// 语言字符集生成器
/// 从 AllConfigs 读取 LanguageData 表提取三种语言的字符集并保存为txt
/// </summary>
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<string, int> charCounts = new Dictionary<string, int>();
[MenuItem("配置表pipeline/字体/生成字符集")]
public static void ShowWindow()
{
var window = GetWindow<LanguageCharsetGenerator>("字符集生成器");
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();
}
/// <summary>
/// 自动查找 AllConfigs.bytes
/// </summary>
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<TextAsset>(path);
if (allConfigsFile != null)
{
Log($"✓ 自动找到 AllConfigs: {path}");
return;
}
}
}
Log("⚠ 未找到 AllConfigs.bytes请手动选择");
}
/// <summary>
/// 生成字符集
/// </summary>
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();
}
}
/// <summary>
/// 反序列化 AllConfigs
/// </summary>
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;
}
}
/// <summary>
/// 从 LanguageData 提取字符集
/// </summary>
private Dictionary<string, HashSet<char>> ExtractCharsets(LanguageData languageData)
{
var charsets = new Dictionary<string, HashSet<char>>
{
{ "En_US", new HashSet<char>() },
{ "Zh_CN", new HashSet<char>() },
{ "Pt_BR", new HashSet<char>() }
};
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;
}
/// <summary>
/// 添加字符到集合(排除控制字符)
/// </summary>
private void AddChars(HashSet<char> charset, string text)
{
if (string.IsNullOrEmpty(text))
return;
foreach (char c in text)
{
if (!char.IsControl(c)) // 排除换行符、制表符等控制字符
{
charset.Add(c);
}
}
}
/// <summary>
/// 保存字符集到txt文件
/// </summary>
private void SaveCharsets(Dictionary<string, HashSet<char>> 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 += $"<color=red>{message}</color>\n";
Debug.LogError(message);
Repaint();
}
}
}