399 lines
15 KiB
C#
399 lines
15 KiB
C#
using UnityEngine;
|
||
using UnityEditor;
|
||
using System.Collections.Generic;
|
||
using System.IO;
|
||
using System.Linq;
|
||
using Newtonsoft.Json.Linq;
|
||
|
||
namespace PictorialEditor
|
||
{
|
||
/// <summary>
|
||
/// 画报角色ID验证工具
|
||
/// 扫描 ActivityPicturialData 目录下的所有 JSON 文件,检查角色 ID 是否有效
|
||
/// </summary>
|
||
public class PictorialCharacterIdValidator : EditorWindow
|
||
{
|
||
private const string PICTORIAL_DATA_FOLDER = "Assets/Config/Data/ActivityPicturialData";
|
||
private const string CHARACTER_CONFIG_PATH = "Assets/Config/Data/charactercfg_characterattri.json";
|
||
|
||
private Vector2 scrollPosition;
|
||
private List<ValidationError> validationErrors = new List<ValidationError>();
|
||
private bool isScanning = false;
|
||
private string statusMessage = "点击「开始扫描」按钮开始验证";
|
||
private HashSet<int> validCharacterIds = new HashSet<int>();
|
||
private HashSet<string> validNameIds = new HashSet<string>(); // 角色名称ID(如 A00001)
|
||
|
||
[System.Serializable]
|
||
private class ValidationError
|
||
{
|
||
public string fileName;
|
||
public string itemName;
|
||
public string characterId;
|
||
public string errorMessage;
|
||
public int lineNumber; // JSON 中的大致行号
|
||
}
|
||
|
||
[MenuItem("Tools/画报工具/角色ID验证工具")]
|
||
public static void ShowWindow()
|
||
{
|
||
var window = GetWindow<PictorialCharacterIdValidator>("画报角色ID验证");
|
||
window.minSize = new Vector2(600, 400);
|
||
window.Show();
|
||
}
|
||
|
||
private void OnGUI()
|
||
{
|
||
EditorGUILayout.Space(10);
|
||
EditorGUILayout.LabelField("画报角色ID验证工具", EditorStyles.boldLabel);
|
||
EditorGUILayout.HelpBox(
|
||
"此工具会:\n" +
|
||
"1. 加载角色配置表 (charactercfg_characterattri.json)\n" +
|
||
"2. 扫描 ActivityPicturialData 目录下的所有画报 JSON 文件\n" +
|
||
"3. 验证画报中的 characterId 是否有效(格式正确 + 存在于配置表中)",
|
||
MessageType.Info
|
||
);
|
||
|
||
EditorGUILayout.Space(10);
|
||
|
||
// 扫描按钮
|
||
EditorGUI.BeginDisabledGroup(isScanning);
|
||
if (GUILayout.Button("开始扫描", GUILayout.Height(40)))
|
||
{
|
||
StartScan();
|
||
}
|
||
EditorGUI.EndDisabledGroup();
|
||
|
||
EditorGUILayout.Space(5);
|
||
|
||
// 状态信息
|
||
EditorGUILayout.LabelField("状态:", EditorStyles.boldLabel);
|
||
EditorGUILayout.LabelField(statusMessage);
|
||
|
||
EditorGUILayout.Space(10);
|
||
|
||
// 显示验证结果
|
||
if (validationErrors.Count > 0)
|
||
{
|
||
EditorGUILayout.LabelField($"发现 {validationErrors.Count} 个问题:", EditorStyles.boldLabel);
|
||
|
||
EditorGUILayout.Space(5);
|
||
|
||
scrollPosition = EditorGUILayout.BeginScrollView(scrollPosition);
|
||
|
||
foreach (var error in validationErrors)
|
||
{
|
||
EditorGUILayout.BeginVertical("box");
|
||
|
||
// 文件名
|
||
EditorGUILayout.LabelField("文件:", EditorStyles.boldLabel);
|
||
EditorGUILayout.SelectableLabel(error.fileName, GUILayout.Height(18));
|
||
|
||
// 元素名称
|
||
EditorGUILayout.LabelField("元素名称:", EditorStyles.boldLabel);
|
||
EditorGUILayout.SelectableLabel(error.itemName, GUILayout.Height(18));
|
||
|
||
// 角色ID
|
||
EditorGUILayout.LabelField("角色ID:", EditorStyles.boldLabel);
|
||
EditorGUILayout.SelectableLabel(error.characterId, GUILayout.Height(18));
|
||
|
||
// 错误信息
|
||
EditorGUILayout.LabelField("问题:", EditorStyles.boldLabel);
|
||
EditorGUILayout.HelpBox(error.errorMessage, MessageType.Error);
|
||
|
||
// 打开文件按钮
|
||
if (GUILayout.Button("打开 JSON 文件", GUILayout.Height(25)))
|
||
{
|
||
OpenJsonFile(error.fileName);
|
||
}
|
||
|
||
EditorGUILayout.EndVertical();
|
||
EditorGUILayout.Space(5);
|
||
}
|
||
|
||
EditorGUILayout.EndScrollView();
|
||
}
|
||
else if (!isScanning && validationErrors.Count == 0 && statusMessage.Contains("扫描完成"))
|
||
{
|
||
EditorGUILayout.HelpBox("✅ 所有画报的角色ID都是有效的!", MessageType.Info);
|
||
}
|
||
}
|
||
|
||
private void StartScan()
|
||
{
|
||
isScanning = true;
|
||
validationErrors.Clear();
|
||
statusMessage = "正在加载角色配置表...";
|
||
Repaint();
|
||
|
||
try
|
||
{
|
||
// 加载角色配置表
|
||
if (!LoadCharacterConfig())
|
||
{
|
||
statusMessage = "加载角色配置表失败,请检查文件路径";
|
||
return;
|
||
}
|
||
|
||
statusMessage = $"角色配置表加载成功,共 {validCharacterIds.Count} 个角色ID,{validNameIds.Count} 个名称ID。正在扫描画报文件...";
|
||
Repaint();
|
||
|
||
ScanPictorialJsonFiles();
|
||
|
||
if (validationErrors.Count > 0)
|
||
{
|
||
statusMessage = $"扫描完成,发现 {validationErrors.Count} 个问题";
|
||
}
|
||
else
|
||
{
|
||
statusMessage = "扫描完成,所有角色ID都有效!";
|
||
}
|
||
}
|
||
catch (System.Exception e)
|
||
{
|
||
statusMessage = $"扫描出错: {e.Message}";
|
||
Debug.LogError($"[画报角色ID验证] 扫描出错: {e.Message}\n{e.StackTrace}");
|
||
}
|
||
finally
|
||
{
|
||
isScanning = false;
|
||
Repaint();
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 加载角色配置表,获取所有有效的角色ID
|
||
/// </summary>
|
||
private bool LoadCharacterConfig()
|
||
{
|
||
validCharacterIds.Clear();
|
||
validNameIds.Clear();
|
||
|
||
if (!File.Exists(CHARACTER_CONFIG_PATH))
|
||
{
|
||
Debug.LogError($"[画报角色ID验证] 角色配置文件不存在: {CHARACTER_CONFIG_PATH}");
|
||
return false;
|
||
}
|
||
|
||
try
|
||
{
|
||
string jsonContent = File.ReadAllText(CHARACTER_CONFIG_PATH);
|
||
JArray jsonArray = JArray.Parse(jsonContent);
|
||
|
||
if (jsonArray == null)
|
||
{
|
||
Debug.LogError($"[画报角色ID验证] 无法解析角色配置文件");
|
||
return false;
|
||
}
|
||
|
||
// 解析角色配置,提取所有角色ID和名称ID
|
||
// 配置格式: [{"RoleID": 100001, "NameID": "A00001", ...}, ...]
|
||
for (int i = 0; i < jsonArray.Count; i++)
|
||
{
|
||
JObject item = jsonArray[i] as JObject;
|
||
if (item == null)
|
||
continue;
|
||
|
||
// 提取 RoleID (数字ID)
|
||
int roleId = item["RoleID"]?.Value<int>() ?? 0;
|
||
if (roleId > 0)
|
||
{
|
||
validCharacterIds.Add(roleId);
|
||
}
|
||
|
||
// 提取 NameID (字符串ID,如 A00001)
|
||
string nameId = item["NameID"]?.Value<string>();
|
||
if (!string.IsNullOrEmpty(nameId))
|
||
{
|
||
validNameIds.Add(nameId);
|
||
}
|
||
}
|
||
|
||
Debug.Log($"[画报角色ID验证] 成功加载 {validCharacterIds.Count} 个角色ID,{validNameIds.Count} 个名称ID");
|
||
return validCharacterIds.Count > 0 && validNameIds.Count > 0;
|
||
}
|
||
catch (System.Exception e)
|
||
{
|
||
Debug.LogError($"[画报角色ID验证] 加载角色配置表出错: {e.Message}\n{e.StackTrace}");
|
||
return false;
|
||
}
|
||
}
|
||
|
||
private void ScanPictorialJsonFiles()
|
||
{
|
||
if (!Directory.Exists(PICTORIAL_DATA_FOLDER))
|
||
{
|
||
statusMessage = $"目录不存在: {PICTORIAL_DATA_FOLDER}";
|
||
return;
|
||
}
|
||
|
||
string[] jsonFiles = Directory.GetFiles(PICTORIAL_DATA_FOLDER, "*.json", SearchOption.TopDirectoryOnly);
|
||
|
||
if (jsonFiles.Length == 0)
|
||
{
|
||
statusMessage = "未找到任何 JSON 文件";
|
||
return;
|
||
}
|
||
|
||
Debug.Log($"[画报角色ID验证] 开始扫描 {jsonFiles.Length} 个文件");
|
||
|
||
foreach (string jsonFile in jsonFiles)
|
||
{
|
||
ValidateJsonFile(jsonFile);
|
||
}
|
||
}
|
||
|
||
private void ValidateJsonFile(string filePath)
|
||
{
|
||
string fileName = Path.GetFileName(filePath);
|
||
|
||
try
|
||
{
|
||
string jsonContent = File.ReadAllText(filePath);
|
||
JObject jsonObj = JObject.Parse(jsonContent);
|
||
|
||
// 获取 items 数组
|
||
JArray items = jsonObj["items"] as JArray;
|
||
if (items == null)
|
||
{
|
||
Debug.LogWarning($"[画报角色ID验证] {fileName} 中没有 items 数组");
|
||
return;
|
||
}
|
||
|
||
// 遍历每个元素
|
||
for (int i = 0; i < items.Count; i++)
|
||
{
|
||
JObject item = items[i] as JObject;
|
||
if (item == null)
|
||
continue;
|
||
|
||
string itemName = item["itemName"]?.ToString() ?? $"Item_{i}";
|
||
string characterId = item["characterId"]?.ToString();
|
||
|
||
// 如果没有 characterId 或为空,跳过(这是正常的)
|
||
if (string.IsNullOrEmpty(characterId))
|
||
continue;
|
||
|
||
// 验证角色ID
|
||
string errorMessage = ValidateCharacterId(characterId);
|
||
if (!string.IsNullOrEmpty(errorMessage))
|
||
{
|
||
validationErrors.Add(new ValidationError
|
||
{
|
||
fileName = fileName,
|
||
itemName = itemName,
|
||
characterId = characterId,
|
||
errorMessage = errorMessage,
|
||
lineNumber = EstimateLineNumber(jsonContent, itemName)
|
||
});
|
||
}
|
||
}
|
||
}
|
||
catch (System.Exception e)
|
||
{
|
||
Debug.LogError($"[画报角色ID验证] 解析文件失败: {fileName}, 错误: {e.Message}");
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 验证角色ID是否有效
|
||
/// </summary>
|
||
private string ValidateCharacterId(string characterId)
|
||
{
|
||
// 检查格式
|
||
if (string.IsNullOrWhiteSpace(characterId))
|
||
{
|
||
return "角色ID为空";
|
||
}
|
||
|
||
// 情况1: NameID 格式(如 "A00001", "A00012")
|
||
if (characterId.StartsWith("A") && characterId.Length == 6)
|
||
{
|
||
// 直接在 validNameIds 中查找
|
||
if (validNameIds.Contains(characterId))
|
||
{
|
||
return null; // 验证通过
|
||
}
|
||
else
|
||
{
|
||
return $"角色名称ID不存在于配置表中: {characterId}";
|
||
}
|
||
}
|
||
|
||
// 情况2: RoleID 格式(纯数字或 A+数字)
|
||
int numericId = 0;
|
||
|
||
if (characterId.StartsWith("A") && characterId.Length > 6)
|
||
{
|
||
// "A100001" 格式
|
||
string numberPart = characterId.Substring(1);
|
||
if (!int.TryParse(numberPart, out numericId))
|
||
{
|
||
return $"无效的角色ID格式(无法解析数字部分): {characterId}";
|
||
}
|
||
}
|
||
else if (!characterId.StartsWith("A"))
|
||
{
|
||
// 纯数字格式
|
||
if (!int.TryParse(characterId, out numericId))
|
||
{
|
||
return $"无效的角色ID格式(不是数字也不是A开头): {characterId}";
|
||
}
|
||
|
||
// 如果小于 100000,补齐
|
||
if (numericId < 100000)
|
||
numericId += 100000;
|
||
}
|
||
else
|
||
{
|
||
return $"无法识别的角色ID格式: {characterId}";
|
||
}
|
||
|
||
// 检查角色ID范围
|
||
if (numericId < 100000 || numericId > 999999)
|
||
{
|
||
return $"角色ID超出有效范围 (100000-999999): {characterId} (解析后: {numericId})";
|
||
}
|
||
|
||
// 检查角色ID是否存在于配置表中
|
||
if (!validCharacterIds.Contains(numericId))
|
||
{
|
||
return $"角色ID不存在于配置表中: {characterId} (解析后: {numericId})";
|
||
}
|
||
|
||
return null; // 验证通过
|
||
}
|
||
|
||
/// <summary>
|
||
/// 估算元素在 JSON 文件中的行号(用于定位)
|
||
/// </summary>
|
||
private int EstimateLineNumber(string jsonContent, string itemName)
|
||
{
|
||
string[] lines = jsonContent.Split('\n');
|
||
for (int i = 0; i < lines.Length; i++)
|
||
{
|
||
if (lines[i].Contains($"\"itemName\": \"{itemName}\""))
|
||
{
|
||
return i + 1; // 行号从1开始
|
||
}
|
||
}
|
||
return -1;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 在外部编辑器中打开 JSON 文件
|
||
/// </summary>
|
||
private void OpenJsonFile(string fileName)
|
||
{
|
||
string fullPath = Path.Combine(PICTORIAL_DATA_FOLDER, fileName);
|
||
if (File.Exists(fullPath))
|
||
{
|
||
System.Diagnostics.Process.Start(fullPath);
|
||
}
|
||
else
|
||
{
|
||
Debug.LogError($"[画报角色ID验证] 文件不存在: {fullPath}");
|
||
}
|
||
}
|
||
}
|
||
}
|