474 lines
19 KiB
C#
474 lines
19 KiB
C#
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($"positionB::row:: {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($"positionB::row:: {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);
|
||
}
|
||
} |