Files
ft/Client/Assets/Editor/TempCoordinateChecker.cs
2026-06-29 21:18:33 +08:00

474 lines
19 KiB
C#
Raw Permalink 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 Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using Script.RuntimeScript.model.Data;
using UnityEditor;
using UnityEngine;
public class SelectedJsonCoordinateChecker
{
// 右键菜单在选中的JSON文件上点击"检查AllTempJson重复坐标"
[MenuItem("Assets/检查AllTempJson重复坐标", false, 100)]
public static void CheckSelectedJsonFile()
{
// 获取选中的文件
string selectedFilePath = AssetDatabase.GetAssetPath(Selection.activeObject);
// 校验文件是否为JSON
if (string.IsNullOrEmpty(selectedFilePath) || !selectedFilePath.EndsWith(".json", StringComparison.OrdinalIgnoreCase))
{
Debug.LogError("请选中一个JSON文件");
return;
}
// 转换为绝对路径
string fullPath = Path.Combine(Application.dataPath, selectedFilePath.Replace("Assets/", ""));
if (!File.Exists(fullPath))
{
Debug.LogError($"文件不存在:{fullPath}");
return;
}
// 执行检查逻辑
CheckCoordinatesInFile(fullPath);
}
// 校验菜单是否可用仅选中JSON文件时可点击
[MenuItem("Assets/检查AllTempJson重复坐标", true)]
public static bool ValidateCheckSelectedJsonFile()
{
string path = AssetDatabase.GetAssetPath(Selection.activeObject);
return !string.IsNullOrEmpty(path) && path.EndsWith(".json", StringComparison.OrdinalIgnoreCase);
}
// 核心检查逻辑
private static void CheckCoordinatesInFile(string fullPath)
{
try
{
// 读取JSON内容
string jsonContent = File.ReadAllText(fullPath);
JObject rootObj = JObject.Parse(jsonContent);
// 提取AllTempJson字段
JToken allTempToken = rootObj["AllTempJson"];
if (allTempToken == null || string.IsNullOrEmpty(allTempToken.ToString()))
{
Debug.Log("文件中未找到AllTempJson字段或字段为空");
return;
}
List<List<PropTempData>> _allPropTempData = JsonConvert.DeserializeObject<List<List<PropTempData>>>(allTempToken.ToString());
// 解析AllTempJson二维列表结构
List<int[,]> ints = new List<int[,]>();
int index = 0;
// 遍历所有PropTemp提取坐标
foreach (List<PropTempData> tempList in _allPropTempData)
{
index++;
Dictionary<string, int> coordCountDict = new Dictionary<string, int>();
List<string> duplicateCoords = new List<string>();
int[,] ints1 = new int[10, 10];
ints.Add(ints1);
int index1 = 0;
foreach (PropTempData propTemp in tempList)
{
var TempArr = propTemp.ConfigData.GetArray();
int rows = TempArr.GetLength(0);
int cols = TempArr.GetLength(1);
// 起始
Vector3 startPoint = new Vector3(propTemp.x, propTemp.y, 0);
index1++;
for (int i = 0; i < rows; i++)
{
for (int j = 0; j < cols; j++)
{
int value = TempArr[i, j];
if (value > 0)
{
// 初始位置
Vector3 positionB = new Vector3(j, i, 0); //空间转换
// DiggingGameManager.LogError($"positionBrow:: {i}" + " col::" + j + " data.PropDirection::" + data.PropDirection);
Vector3 endPosition = startPoint + GetRotatePoint(propTemp.ConfigData.PropDirection, Vector3.zero, positionB);
ints1[(int)Math.Round(endPosition.x, MidpointRounding.AwayFromZero), (int)Math.Round(endPosition.y, MidpointRounding.AwayFromZero)] = index1;
string coordKey = $"({endPosition.x},{endPosition.y})";
// 统计次数
if (coordCountDict.ContainsKey(coordKey))
{
coordCountDict[coordKey]++;
if (coordCountDict[coordKey] == 2)
{
duplicateCoords.Add(coordKey);
}
}
else
{
coordCountDict[coordKey] = 1;
}
}
}
}
}
// 输出结果
Debug.Log($"检查文件:{fullPath}++{index}");
if (duplicateCoords.Count == 0)
{
Debug.Log("✅ AllTempJson 中无重复坐标");
}
else
{
Debug.LogWarning($"⚠️{index} 发现{duplicateCoords.Count}个重复坐标:");
foreach (var coord in duplicateCoords)
{
Debug.LogWarning($"- 坐标 {coord} 重复出现 {coordCountDict[coord]} 次");
}
}
}
// 生成输出文件路径与原JSON文件同目录
string outputDir = Path.GetDirectoryName(Application.dataPath);
string outputFileName = Path.GetFileNameWithoutExtension(fullPath) + "_CoordNumbers.csv";
string outputPath = Path.Combine(outputDir, outputFileName);
// 调用绘制方法
//DrawAllIntsToSingleFile(ints, outputPath);
ExportIntsToCsv(ints, outputPath);
// 输出结果
Debug.Log($"检查文件:{fullPath}");
}
catch (Exception e)
{
Debug.LogError($"检查失败:{e.Message}\n堆栈{e.StackTrace}");
}
}
private static Vector3 GetRotatePoint(int angles, Vector3 positionA, Vector3 positionB)
{
return RotatePointAroundPivot(positionB, positionA, new Vector3(0, 0, -angles));
}
private static Vector3 RotatePointAroundPivot(Vector3 point, Vector3 pivot, Vector3 angles)
{
Vector3 dir = point - pivot; // 获取点到枢轴的向量
dir = Quaternion.Euler(angles) * dir; // 旋转向量
point = dir + pivot; // 将点移动回枢轴
return point;
}
// 新增将所有int[,]导出到CSV表格
private static void ExportIntsToCsv(List<int[,]> ints, string outputFilePath)
{
if (ints == null || ints.Count == 0)
{
Debug.LogWarning("ints列表为空无法导出");
return;
}
try
{
// 1. 确定所有数组的最大X/Y范围统一表格尺寸
int maxX = 0;
int maxY = 0;
foreach (var arr in ints)
{
maxX = Mathf.Max(maxX, arr.GetLength(0));
maxY = Mathf.Max(maxY, arr.GetLength(1));
}
// 2. 准备CSV内容首行为表头分组索引+X坐标
List<string> csvLines = new List<string>();
// 3. 填充表格内容每行对应一个Y坐标
// 遍历每个分组的当前Y行数据
for (int groupIdx = 0; groupIdx < ints.Count; groupIdx++)
{
int[,] arr = ints[groupIdx];
int xLength = arr.GetLength(0);
for (int y = 0; y < maxY; y++)
{
List<string> row = new List<string>();
row.Add(y.ToString()); // 第一列Y坐标
for (int x = 0; x < maxX; x++)
{
// 数组范围内且有值则显示,否则留空
if (x < xLength && y < arr.GetLength(1))
{
int value = arr[x, y];
row.Add(value == 0 ? "" : value.ToString());
}
else
{
row.Add("");
}
}
csvLines.Add(string.Join(",", row));
}
csvLines.Add(""); // 分组间空行分隔
}
// 4. 保存CSV文件
string directory = Path.GetDirectoryName(outputFilePath);
if (!Directory.Exists(directory))
{
Directory.CreateDirectory(directory);
}
File.WriteAllLines(outputFilePath, csvLines, System.Text.Encoding.UTF8);
// 5. 提示并添加Excel格式说明
Debug.Log($"坐标数据已导出到CSV表格{outputFilePath}");
Debug.Log("提示用Excel打开后可通过「条件格式」→「数据条/色阶」为数值添加颜色标记");
EditorUtility.RevealInFinder(outputFilePath);
}
catch (Exception e)
{
Debug.LogError($"导出CSV失败{e.Message}");
}
}
private static void DrawAllIntsToSingleFile(List<int[,]> ints, string outputFilePath)
{
if (ints == null || ints.Count == 0)
{
Debug.LogWarning("ints列表为空无法绘制");
return;
}
try
{
List<string> allTextLines = new List<string>();
allTextLines.Add("===== 所有分组坐标数字汇总图 =====");
allTextLines.Add($"总分组数:{ints.Count} | 格式:每个分组独立区块,空格=无数据,数字/字母=坐标值");
allTextLines.Add("".PadRight(80, '-')); // 分隔线
// 遍历每个int[,],生成区块并添加到总文本
for (int i = 0; i < ints.Count; i++)
{
int[,] intArray = ints[i];
int groupIndex = i + 1; // 分组索引从1开始
if (intArray == null)
{
allTextLines.Add($"【分组 {groupIndex}】数组为空");
allTextLines.Add("".PadRight(80, '-'));
continue;
}
// 1. 获取当前数组维度
int xLength = intArray.GetLength(0);
int yLength = intArray.GetLength(1);
// 2. 生成当前分组的文本区块
List<string> groupLines = new List<string>();
groupLines.Add($"【分组 {groupIndex}】X范围[0~{xLength - 1}] | Y范围[0~{yLength - 1}]");
// 3. 构建坐标网格
char[][] textGrid = new char[yLength][];
for (int y = 0; y < yLength; y++)
{
textGrid[y] = new char[xLength];
Array.Fill(textGrid[y], ' ');
}
// 4. 填充数组数据
for (int x = 0; x < xLength; x++)
{
for (int y = 0; y < yLength; y++)
{
int value = intArray[x, y];
if (value == 0) continue;
textGrid[y][x] = value <= 9
? (char)('0' + value)
: (char)('A' + (value - 10));
}
}
// 5. 添加带Y轴标签的网格行
for (int y = 0; y < yLength; y++)
{
groupLines.Add($"Y={y,2} | " + new string(textGrid[y]));
}
// 6. 添加X轴标签
string xLabel = " | "; // 对齐Y轴标签
for (int x = 0; x < xLength; x++)
{
xLabel += $"{x,2}";
}
groupLines.Add(xLabel);
// 7. 将当前分组区块添加到总文本,并添加分隔线
allTextLines.AddRange(groupLines);
allTextLines.Add("".PadRight(80, '-'));
}
// 8. 保存到单个文件
string directory = Path.GetDirectoryName(outputFilePath);
if (!Directory.Exists(directory))
{
Directory.CreateDirectory(directory);
}
File.WriteAllLines(outputFilePath, allTextLines);
Debug.Log($"所有分组坐标已汇总绘制到:{outputFilePath}");
EditorUtility.RevealInFinder(outputFilePath);
}
catch (Exception e)
{
Debug.LogError($"绘制汇总文件失败:{e.Message}");
}
}
// 右键菜单:在选中的文件夹上点击"检查所有JSON的坐标重复"
[MenuItem("Assets/检查文件夹下所有JSON的坐标重复", false, 101)]
public static void CheckAllJsonInSelectedFolder()
{
// 获取选中的文件夹路径
string selectedFolderPath = AssetDatabase.GetAssetPath(Selection.activeObject);
if (string.IsNullOrEmpty(selectedFolderPath) || !Directory.Exists(selectedFolderPath))
{
Debug.LogError("请选中一个有效的文件夹!");
return;
}
// 查找文件夹下所有JSON文件包括子文件夹
string[] jsonFilePaths = Directory.GetFiles(selectedFolderPath, "*.json", SearchOption.AllDirectories);
if (jsonFilePaths.Length == 0)
{
Debug.Log("文件夹下未找到任何JSON文件");
return;
}
// 全局坐标统计(记录所有文件中的坐标及出现位置)
Dictionary<string, List<string>> globalCoordRecord = new Dictionary<string, List<string>>();
// 遍历所有JSON文件
foreach (string jsonPath in jsonFilePaths)
{
try
{
// 读取文件内容
string fullPath = Path.GetFullPath(jsonPath);
if (!fullPath.Contains("Clamp"))
{
continue;
}
string jsonContent = File.ReadAllText(fullPath);
JObject rootObj = JObject.Parse(jsonContent);
// 提取AllTempJson字段
JToken allTempToken = rootObj["AllTempJson"];
if (allTempToken == null || string.IsNullOrEmpty(allTempToken.ToString()))
{
continue; // 跳过无AllTempJson的文件
}
List<List<PropTempData>> _allPropTempData = JsonConvert.DeserializeObject<List<List<PropTempData>>>(allTempToken.ToString());
int index = 0;
// 遍历所有PropTemp提取坐标
foreach (List<PropTempData> tempList in _allPropTempData)
{
index++;
Dictionary<string, int> coordCountDict = new Dictionary<string, int>();
List<string> duplicateCoords = new List<string>();
foreach (PropTempData propTemp in tempList)
{
var TempArr = propTemp.ConfigData.GetArray();
int rows = TempArr.GetLength(0);
int cols = TempArr.GetLength(1);
// 起始
Vector3 startPoint = new Vector3(propTemp.x, propTemp.y, 0);
for (int i = 0; i < rows; i++)
{
for (int j = 0; j < cols; j++)
{
int value = TempArr[i, j];
if (value > 0)
{
// 初始位置
Vector3 positionB = new Vector3(j, i, 0); //空间转换
// DiggingGameManager.LogError($"positionBrow:: {i}" + " col::" + j + " data.PropDirection::" + data.PropDirection);
Vector3 endPosition = startPoint + GetRotatePoint(propTemp.ConfigData.PropDirection, Vector3.zero, positionB);
string coordKey = $"({endPosition.x},{endPosition.y})";
// 统计次数
if (coordCountDict.ContainsKey(coordKey))
{
coordCountDict[coordKey]++;
if (coordCountDict[coordKey] == 2)
{
duplicateCoords.Add(coordKey);
}
}
else
{
coordCountDict[coordKey] = 1;
}
}
}
}
}
// 输出结果
Debug.Log($"检查文件:{fullPath}++{index}");
if (duplicateCoords.Count == 0)
{
Debug.Log("✅ AllTempJson 中无重复坐标");
}
else
{
Debug.LogWarning($"⚠️{index} 发现{duplicateCoords.Count}个重复坐标:");
foreach (var coord in duplicateCoords)
{
Debug.LogWarning($"- 坐标 {coord} 重复出现 {coordCountDict[coord]} 次");
}
}
}
}
catch (Exception e)
{
Debug.LogError($"解析文件失败:{jsonPath}\n错误{e.Message}");
}
}
// 汇总并输出结果
Debug.Log($"===== 文件夹坐标检查结果(共扫描 {jsonFilePaths.Length} 个JSON文件 =====");
int totalDuplicateCoords = 0;
foreach (var kvp in globalCoordRecord)
{
if (kvp.Value.Count > 1)
{
totalDuplicateCoords++;
Debug.LogWarning($"⚠️ 坐标 {kvp.Key} 在 {kvp.Value.Count} 个文件中重复出现:");
foreach (var filePath in kvp.Value)
{
Debug.LogWarning($" - {filePath}");
}
}
}
if (totalDuplicateCoords == 0)
{
Debug.Log("✅ 所有文件中未发现重复坐标");
}
else
{
Debug.LogWarning($"===== 共发现 {totalDuplicateCoords} 个跨文件重复坐标 =====");
}
}
// 校验菜单是否可用(仅选中文件夹时可点击)
[MenuItem("Assets/检查文件夹下所有JSON的坐标重复", true)]
public static bool ValidateCheckAllJsonInFolder()
{
string path = AssetDatabase.GetAssetPath(Selection.activeObject);
return !string.IsNullOrEmpty(path) && Directory.Exists(path);
}
}