NLDClient-yudde/ProjectNLD/Assets/Editor/Tools/UITextureExporter.cs

527 lines
19 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

using System.IO;
using System.Collections.Generic;
using System.Linq;
using UnityEditor;
using UnityEngine;
using Newtonsoft.Json.Linq;
/// <summary>
/// UI贴图导出工具 - 将Art目录的UI贴图复制到Art_Out目录
/// </summary>
public class UITextureExporter : EditorWindow
{
[MenuItem("Tools/*美术资源工具/UI贴图导出Art -> Art_Out")]
public static void ShowWindow()
{
GetWindow<UITextureExporter>("UI贴图导出工具");
}
private string sourceFolder = "Assets/Art/UI/Texture/Activity/Activity_CheckIn";
private string targetFolder = "Assets/Art_Out/UI/Texture/Activity/Activity_CheckIn";
private string pictorialDataFolder = "Assets/Config/Data/ActivityPicturialData";
private Vector2 scrollPosition;
private int currentTab = 0;
private string[] tabNames = { "目录导出", "画报图片导出" };
private void OnGUI()
{
GUILayout.Label("UI贴图导出工具", EditorStyles.boldLabel);
GUILayout.Space(10);
// 标签页切换
currentTab = GUILayout.Toolbar(currentTab, tabNames);
GUILayout.Space(10);
if (currentTab == 0)
{
DrawDirectoryExportTab();
}
else if (currentTab == 1)
{
DrawPictorialExportTab();
}
}
/// <summary>
/// 目录导出标签页
/// </summary>
private void DrawDirectoryExportTab()
{
EditorGUILayout.HelpBox(
"此工具用于将 Assets/Art/UI/Texture 目录下的贴图复制到 Assets/Art_Out/UI/Texture 目录\n" +
"确保运行时 YooAsset 可以加载这些资源。",
MessageType.Info
);
GUILayout.Space(10);
// 输入区域
GUILayout.Label("源目录Art:", EditorStyles.boldLabel);
sourceFolder = EditorGUILayout.TextField(sourceFolder);
GUILayout.Space(5);
GUILayout.Label("目标目录Art_Out:", EditorStyles.boldLabel);
targetFolder = EditorGUILayout.TextField(targetFolder);
GUILayout.Space(10);
// 快速选项
GUILayout.Label("快速选项:", EditorStyles.boldLabel);
EditorGUILayout.BeginHorizontal();
if (GUILayout.Button("Activity_CheckIn"))
{
sourceFolder = "Assets/Art/UI/Texture/Activity/Activity_CheckIn";
targetFolder = "Assets/Art_Out/UI/Texture/Activity/Activity_CheckIn";
}
if (GUILayout.Button("全部Activity"))
{
sourceFolder = "Assets/Art/UI/Texture/Activity";
targetFolder = "Assets/Art_Out/UI/Texture/Activity";
}
if (GUILayout.Button("全部UI/Texture"))
{
sourceFolder = "Assets/Art/UI/Texture";
targetFolder = "Assets/Art_Out/UI/Texture";
}
EditorGUILayout.EndHorizontal();
GUILayout.Space(10);
// 执行按钮
EditorGUILayout.BeginHorizontal();
if (GUILayout.Button("开始导出", GUILayout.Height(40)))
{
ExportTextures();
}
if (GUILayout.Button("清空目标目录", GUILayout.Height(40)))
{
ClearTargetFolder();
}
EditorGUILayout.EndHorizontal();
GUILayout.Space(10);
// 说明
scrollPosition = EditorGUILayout.BeginScrollView(scrollPosition);
GUILayout.Label("说明:", EditorStyles.boldLabel);
GUILayout.Label("1. 此工具会递归复制源目录下的所有文件");
GUILayout.Label("2. 会自动创建不存在的目录");
GUILayout.Label("3. 会同步复制 .meta 文件并生成新的GUID");
GUILayout.Label("4. 复制完成后会自动刷新 AssetDatabase");
GUILayout.Label("");
GUILayout.Label("注意:", EditorStyles.boldLabel);
GUILayout.Label("• 如果目标文件已存在,会覆盖");
GUILayout.Label("• 请确保源目录路径正确");
GUILayout.Label("• 大量文件复制可能需要较长时间");
GUILayout.Label("• meta文件会自动生成新GUID避免冲突");
EditorGUILayout.EndScrollView();
}
/// <summary>
/// 画报图片导出标签页
/// </summary>
private void DrawPictorialExportTab()
{
EditorGUILayout.HelpBox(
"此功能会自动读取 ActivityPicturialData 目录中所有画报 JSON 文件\n" +
"提取其中的资源路径mainBackgroundPath、backgroundPath、imagePath\n" +
"将 Assets/Art/ 目录下的资源复制到 Assets/Art_Out/ 目录。",
MessageType.Info
);
GUILayout.Space(10);
// 画报数据目录
GUILayout.Label("画报数据目录:", EditorStyles.boldLabel);
pictorialDataFolder = EditorGUILayout.TextField(pictorialDataFolder);
GUILayout.Space(10);
// 执行按钮
if (GUILayout.Button("开始导出画报图片", GUILayout.Height(40)))
{
ExportPictorialTextures();
}
GUILayout.Space(10);
// 说明
scrollPosition = EditorGUILayout.BeginScrollView(scrollPosition);
GUILayout.Label("说明:", EditorStyles.boldLabel);
GUILayout.Label("1. 此工具会读取所有 .json 文件");
GUILayout.Label("2. 解析画报数据的资源路径字段");
GUILayout.Label("3. 自动去除子资源后缀 [SpriteName]");
GUILayout.Label("4. 将 Art 目录资源复制到 Art_Out 目录");
GUILayout.Label("5. 同步复制 .meta 文件并生成新GUID");
GUILayout.Label("6. 保持相同的目录结构");
GUILayout.Label("");
GUILayout.Label("支持的字段:", EditorStyles.boldLabel);
GUILayout.Label("• mainBackgroundPath - 大背景路径");
GUILayout.Label("• backgroundPath - 普通背景路径");
GUILayout.Label("• items[].imagePath - 画报元素图片路径");
GUILayout.Label("");
GUILayout.Label("注意:", EditorStyles.boldLabel);
GUILayout.Label("• 只会处理 Assets/Art/ 开头的路径");
GUILayout.Label("• 如果目标文件已存在,会覆盖");
GUILayout.Label("• 会自动创建不存在的目录");
GUILayout.Label("• meta文件会自动生成新GUID避免冲突");
EditorGUILayout.EndScrollView();
}
private void ExportTextures()
{
if (!Directory.Exists(sourceFolder))
{
EditorUtility.DisplayDialog("错误", $"源目录不存在:\n{sourceFolder}", "确定");
return;
}
bool confirm = EditorUtility.DisplayDialog(
"确认导出",
$"将要从:\n{sourceFolder}\n\n复制到:\n{targetFolder}\n\n是否继续",
"确定",
"取消"
);
if (!confirm)
return;
try
{
EditorUtility.DisplayProgressBar("导出UI贴图", "正在复制文件...", 0f);
// 确保目标目录存在
if (!Directory.Exists(targetFolder))
{
Directory.CreateDirectory(targetFolder);
}
// 获取所有文件
string[] files = Directory.GetFiles(sourceFolder, "*.*", SearchOption.AllDirectories);
int totalFiles = files.Length;
int copiedFiles = 0;
Debug.Log($"[UI贴图导出] 开始导出,共 {totalFiles} 个文件");
foreach (string sourceFile in files)
{
// 跳过.meta文件我们会手动处理
if (sourceFile.EndsWith(".meta"))
continue;
// 计算相对路径
string relativePath = sourceFile.Replace(sourceFolder, "").TrimStart('\\', '/');
string targetFile = Path.Combine(targetFolder, relativePath).Replace("\\", "/");
// 确保目标文件的目录存在
string targetDir = Path.GetDirectoryName(targetFile);
if (!Directory.Exists(targetDir))
{
Directory.CreateDirectory(targetDir);
}
// 复制文件
File.Copy(sourceFile, targetFile, true);
copiedFiles++;
// 复制并修改 .meta 文件
string sourceMetaPath = sourceFile + ".meta";
string targetMetaPath = targetFile + ".meta";
if (File.Exists(sourceMetaPath))
{
// 读取源 meta 文件
string metaContent = File.ReadAllText(sourceMetaPath);
// 生成新的 GUID
string newGuid = GUID.Generate().ToString();
// 替换 GUID
metaContent = System.Text.RegularExpressions.Regex.Replace(
metaContent,
@"guid: [a-f0-9]{32}",
$"guid: {newGuid}",
System.Text.RegularExpressions.RegexOptions.IgnoreCase
);
// 写入目标 meta 文件
File.WriteAllText(targetMetaPath, metaContent);
}
// 更新进度条
float progress = (float)copiedFiles / totalFiles;
EditorUtility.DisplayProgressBar(
"导出UI贴图",
$"正在复制: {Path.GetFileName(sourceFile)} ({copiedFiles}/{totalFiles})",
progress
);
Debug.Log($"[UI贴图导出] 已复制: {relativePath}");
}
EditorUtility.ClearProgressBar();
// 刷新AssetDatabase
Debug.Log("[UI贴图导出] 正在刷新 AssetDatabase...");
AssetDatabase.Refresh();
EditorUtility.DisplayDialog(
"导出完成",
$"成功复制 {copiedFiles} 个文件到:\n{targetFolder}",
"确定"
);
Debug.Log($"[UI贴图导出] 导出完成,共复制 {copiedFiles} 个文件");
}
catch (System.Exception e)
{
EditorUtility.ClearProgressBar();
EditorUtility.DisplayDialog("错误", $"导出失败:\n{e.Message}", "确定");
Debug.LogError($"[UI贴图导出] 导出失败: {e.Message}\n{e.StackTrace}");
}
}
private void ClearTargetFolder()
{
if (!Directory.Exists(targetFolder))
{
EditorUtility.DisplayDialog("提示", $"目标目录不存在:\n{targetFolder}", "确定");
return;
}
bool confirm = EditorUtility.DisplayDialog(
"确认清空",
$"将要删除目录:\n{targetFolder}\n\n此操作不可恢复是否继续",
"确定",
"取消"
);
if (!confirm)
return;
try
{
Directory.Delete(targetFolder, true);
AssetDatabase.Refresh();
EditorUtility.DisplayDialog("清空完成", $"已删除:\n{targetFolder}", "确定");
Debug.Log($"[UI贴图导出] 已清空目录: {targetFolder}");
}
catch (System.Exception e)
{
EditorUtility.DisplayDialog("错误", $"清空失败:\n{e.Message}", "确定");
Debug.LogError($"[UI贴图导出] 清空失败: {e.Message}\n{e.StackTrace}");
}
}
/// <summary>
/// 导出画报图片
/// </summary>
private void ExportPictorialTextures()
{
if (!Directory.Exists(pictorialDataFolder))
{
EditorUtility.DisplayDialog("错误", $"画报数据目录不存在:\n{pictorialDataFolder}", "确定");
return;
}
try
{
EditorUtility.DisplayProgressBar("导出画报图片", "正在读取JSON文件...", 0f);
// 获取所有JSON文件
string[] jsonFiles = Directory.GetFiles(pictorialDataFolder, "*.json", SearchOption.TopDirectoryOnly);
Debug.Log($"[画报图片导出] 找到 {jsonFiles.Length} 个JSON文件");
// 收集所有资源路径
HashSet<string> assetPaths = new HashSet<string>();
foreach (string jsonFile in jsonFiles)
{
try
{
string jsonContent = File.ReadAllText(jsonFile);
JObject json = JObject.Parse(jsonContent);
// 提取大背景路径
string mainBgPath = json["mainBackgroundPath"]?.ToString();
if (!string.IsNullOrEmpty(mainBgPath))
{
assetPaths.Add(RemoveSubAssetSuffix(mainBgPath));
}
// 提取普通背景路径
string bgPath = json["backgroundPath"]?.ToString();
if (!string.IsNullOrEmpty(bgPath))
{
assetPaths.Add(RemoveSubAssetSuffix(bgPath));
}
// 提取画报元素图片路径
JArray items = json["items"] as JArray;
if (items != null)
{
foreach (JObject item in items)
{
string imagePath = item["imagePath"]?.ToString();
if (!string.IsNullOrEmpty(imagePath))
{
assetPaths.Add(RemoveSubAssetSuffix(imagePath));
}
}
}
Debug.Log($"[画报图片导出] 已解析: {Path.GetFileName(jsonFile)}");
}
catch (System.Exception e)
{
Debug.LogError($"[画报图片导出] 解析JSON失败: {Path.GetFileName(jsonFile)}, 错误: {e.Message}");
}
}
Debug.Log($"[画报图片导出] 共收集到 {assetPaths.Count} 个资源路径");
// 筛选出 Assets/Art/ 开头的路径
List<string> artPaths = assetPaths
.Where(p => p.StartsWith("Assets/Art/") && !p.StartsWith("Assets/Art_Out/"))
.ToList();
Debug.Log($"[画报图片导出] 需要复制 {artPaths.Count} 个 Art 目录资源");
if (artPaths.Count == 0)
{
EditorUtility.ClearProgressBar();
EditorUtility.DisplayDialog("提示", "没有找到需要复制的 Assets/Art/ 资源", "确定");
return;
}
// 显示确认对话框
bool confirm = EditorUtility.DisplayDialog(
"确认导出",
$"将要复制 {artPaths.Count} 个资源文件\n" +
$"从 Assets/Art/ 到 Assets/Art_Out/\n\n" +
$"是否继续?",
"确定",
"取消"
);
if (!confirm)
{
EditorUtility.ClearProgressBar();
return;
}
// 复制文件
int copiedCount = 0;
int skippedCount = 0;
for (int i = 0; i < artPaths.Count; i++)
{
string sourcePath = artPaths[i];
string targetPath = sourcePath.Replace("Assets/Art/", "Assets/Art_Out/");
// 更新进度条
float progress = (float)i / artPaths.Count;
EditorUtility.DisplayProgressBar(
"导出画报图片",
$"正在复制: {Path.GetFileName(sourcePath)} ({i + 1}/{artPaths.Count})",
progress
);
// 检查源文件是否存在
if (!File.Exists(sourcePath))
{
Debug.LogWarning($"[画报图片导出] 源文件不存在,跳过: {sourcePath}");
skippedCount++;
continue;
}
// 确保目标目录存在
string targetDir = Path.GetDirectoryName(targetPath);
if (!Directory.Exists(targetDir))
{
Directory.CreateDirectory(targetDir);
}
// 复制文件
File.Copy(sourcePath, targetPath, true);
copiedCount++;
// 复制并修改 .meta 文件
string sourceMetaPath = sourcePath + ".meta";
string targetMetaPath = targetPath + ".meta";
if (File.Exists(sourceMetaPath))
{
// 读取源 meta 文件
string metaContent = File.ReadAllText(sourceMetaPath);
// 生成新的 GUID
string newGuid = GUID.Generate().ToString();
// 替换 GUID查找 "guid: " 后面的值)
metaContent = System.Text.RegularExpressions.Regex.Replace(
metaContent,
@"guid: [a-f0-9]{32}",
$"guid: {newGuid}",
System.Text.RegularExpressions.RegexOptions.IgnoreCase
);
// 写入目标 meta 文件
File.WriteAllText(targetMetaPath, metaContent);
Debug.Log($"[画报图片导出] 已复制并更新meta: {Path.GetFileName(sourceMetaPath)} (新GUID: {newGuid})");
}
else
{
Debug.LogWarning($"[画报图片导出] 源meta文件不存在: {sourceMetaPath}");
}
Debug.Log($"[画报图片导出] 已复制: {sourcePath} -> {targetPath}");
}
EditorUtility.ClearProgressBar();
// 刷新AssetDatabase
Debug.Log("[画报图片导出] 正在刷新 AssetDatabase...");
AssetDatabase.Refresh();
EditorUtility.DisplayDialog(
"导出完成",
$"成功复制 {copiedCount} 个文件\n" +
(skippedCount > 0 ? $"跳过 {skippedCount} 个不存在的文件\n" : "") +
$"\n请查看控制台日志了解详情。",
"确定"
);
Debug.Log($"[画报图片导出] 导出完成,复制 {copiedCount} 个文件,跳过 {skippedCount} 个");
}
catch (System.Exception e)
{
EditorUtility.ClearProgressBar();
EditorUtility.DisplayDialog("错误", $"导出失败:\n{e.Message}", "确定");
Debug.LogError($"[画报图片导出] 导出失败: {e.Message}\n{e.StackTrace}");
}
}
/// <summary>
/// 去除子资源后缀 [SpriteName]
/// </summary>
private string RemoveSubAssetSuffix(string path)
{
if (string.IsNullOrEmpty(path))
return path;
// 检查是否是子资源格式:"Assets/xxx.png[SpriteName]"
if (path.Contains("[") && path.EndsWith("]"))
{
int bracketIndex = path.IndexOf('[');
return path.Substring(0, bracketIndex);
}
return path;
}
}