using UnityEditor;
using UnityEngine;
using System.Collections.Generic;
using System.IO;
using System.Text.RegularExpressions;
namespace ChillConnect.Editor
{
///
/// 第三方关卡配置批量转换工具
/// 输入:文件夹内所有第三方单关JSON
/// 输出:对应转换后的我方格式单关JSON
///
public class LevelBatchConverter : EditorWindow
{
#region 数据结构定义
// 第三方单关结构(只声明需要的字段,多余自动忽略)
[System.Serializable]
private class ThirdPartyLevel
{
public Vector2Int size;
public string name;
public List arrows;
}
[System.Serializable]
private class ThirdPartyArrow
{
public List nodes;
public int color;
}
// 我方单关结构(和运行时对齐)
[System.Serializable]
public class ArrowConfig
{
public int id;
public int startPoint;
public List path = new List();
}
[System.Serializable]
public class LevelConfig
{
public int levelId;
public string levelName;
public int gridRows;
public int gridCols;
public int pointSpacing = 60;
public List arrows = new List();
}
#endregion
private string _inputFolder = "";
private string _outputFolder = "";
private int _pointSpacing = 60;
private Vector2 _scrollPos;
private List _logList = new List();
[MenuItem("Window/Arrow Game/批量关卡转换工具")]
public static void ShowWindow()
{
var window = GetWindow("批量关卡转换");
window.minSize = new Vector2(500, 400);
}
private void OnGUI()
{
EditorGUILayout.Space(10);
// 输入文件夹
EditorGUILayout.LabelField("输入文件夹(第三方单关JSON)", EditorStyles.boldLabel);
EditorGUILayout.BeginHorizontal();
_inputFolder = EditorGUILayout.TextField(_inputFolder);
if (GUILayout.Button("选择", GUILayout.Width(60)))
{
string path = EditorUtility.OpenFolderPanel("选择输入文件夹", Application.dataPath, "");
if (!string.IsNullOrEmpty(path))
_inputFolder = path;
}
EditorGUILayout.EndHorizontal();
EditorGUILayout.Space(8);
// 输出文件夹
EditorGUILayout.LabelField("输出文件夹(转换后JSON)", EditorStyles.boldLabel);
EditorGUILayout.BeginHorizontal();
_outputFolder = EditorGUILayout.TextField(_outputFolder);
if (GUILayout.Button("选择", GUILayout.Width(60)))
{
string path = EditorUtility.OpenFolderPanel("选择输出文件夹", Application.dataPath, "");
if (!string.IsNullOrEmpty(path))
_outputFolder = path;
}
EditorGUILayout.EndHorizontal();
EditorGUILayout.Space(8);
// 基础配置
_pointSpacing = EditorGUILayout.IntField("默认点间距", _pointSpacing);
EditorGUILayout.Space(10);
// 转换按钮
if (GUILayout.Button("开始批量转换", GUILayout.Height(30)))
{
BatchConvert();
}
EditorGUILayout.Space(10);
// 日志区域
EditorGUILayout.LabelField("转换日志", EditorStyles.boldLabel);
_scrollPos = EditorGUILayout.BeginScrollView(_scrollPos, GUILayout.ExpandHeight(true));
foreach (string log in _logList)
{
EditorGUILayout.LabelField(log);
}
EditorGUILayout.EndScrollView();
}
///
/// 批量转换核心逻辑
///
private void BatchConvert()
{
_logList.Clear();
if (string.IsNullOrEmpty(_inputFolder) || !Directory.Exists(_inputFolder))
{
_logList.Add("❌ 输入文件夹不存在");
return;
}
if (string.IsNullOrEmpty(_outputFolder))
{
_logList.Add("❌ 请选择输出文件夹");
return;
}
// 创建输出目录
if (!Directory.Exists(_outputFolder))
{
Directory.CreateDirectory(_outputFolder);
}
// 获取所有json文件
string[] files = Directory.GetFiles(_inputFolder, "*.json", SearchOption.TopDirectoryOnly);
if (files.Length == 0)
{
_logList.Add("⚠️ 输入文件夹内未找到JSON文件");
return;
}
_logList.Add($"找到 {files.Length} 个JSON文件,开始转换...");
int successCount = 0;
int failCount = 0;
for (int i = 0; i < files.Length; i++)
{
string filePath = files[i];
string fileName = Path.GetFileNameWithoutExtension(filePath);
try
{
// 1. 读取并解析第三方配置
string json = File.ReadAllText(filePath);
ThirdPartyLevel thirdLevel = JsonUtility.FromJson(json);
if (thirdLevel == null || thirdLevel.arrows == null)
{
_logList.Add($"❌ {fileName}:解析失败,格式不匹配");
failCount++;
continue;
}
// 2. 转换为我方格式
LevelConfig level = ConvertLevel(thirdLevel, fileName, i + 1);
// 3. 导出到输出文件夹
string outJson = JsonUtility.ToJson(level, true);
string outPath = Path.Combine(_outputFolder, $"{fileName}.json");
File.WriteAllText(outPath, outJson);
_logList.Add($"✅ {fileName}:转换成功 | {level.gridCols}×{level.gridRows} | {level.arrows.Count}个箭头");
successCount++;
}
catch (System.Exception e)
{
_logList.Add($"❌ {fileName}:转换异常 - {e.Message}");
failCount++;
}
}
_logList.Add("");
_logList.Add($"===== 转换完成 =====");
_logList.Add($"成功:{successCount} 个");
_logList.Add($"失败:{failCount} 个");
_logList.Add($"输出路径:{_outputFolder}");
EditorUtility.DisplayDialog("批量转换完成",
$"成功:{successCount}\n失败:{failCount}\n输出路径:{_outputFolder}",
"确定");
AssetDatabase.Refresh();
}
///
/// 单个关卡转换逻辑(和之前编辑器内转换完全一致)
///
private LevelConfig ConvertLevel(ThirdPartyLevel thirdLevel, string fileName, int index)
{
LevelConfig level = new LevelConfig
{
levelId = index,
levelName = string.IsNullOrEmpty(thirdLevel.name) ? fileName : thirdLevel.name,
gridCols = thirdLevel.size.x,
gridRows = thirdLevel.size.y,
pointSpacing = _pointSpacing,
arrows = new List()
};
for (int i = 0; i < thirdLevel.arrows.Count; i++)
{
var thirdArrow = thirdLevel.arrows[i];
if (thirdArrow.nodes == null || thirdArrow.nodes.Count == 0)
continue;
ArrowConfig arrow = new ArrowConfig
{
id = i + 1,
path = new List()
};
// 起点转换:(x,y) → 点ID = y * 列数 + x
Vector2Int startNode = thirdArrow.nodes[0];
arrow.startPoint = startNode.y * level.gridCols + startNode.x;
// 路径转换:相邻节点计算方向
for (int j = 1; j < thirdArrow.nodes.Count; j++)
{
Vector2Int prev = thirdArrow.nodes[j - 1];
Vector2Int cur = thirdArrow.nodes[j];
int dx = cur.x - prev.x;
int dy = cur.y - prev.y;
if (dx == 1) arrow.path.Add("right");
else if (dx == -1) arrow.path.Add("left");
else if (dy == 1) arrow.path.Add("down");
else if (dy == -1) arrow.path.Add("up");
}
level.arrows.Add(arrow);
}
return level;
}
}
}