Art_SubModule/Editor/Art_Tools/ArtResourcePathFiller.cs
2026-02-03 12:18:13 +08:00

372 lines
13 KiB
C#
Raw 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.

#if UNITY_EDITOR
using UnityEngine;
using UnityEditor;
using ArtResource;
using System.Linq;
using System.IO;
using System.Collections.Generic;
namespace ArtTools
{
/// <summary>
/// 美术资源路径自动填充工具
///
/// 功能:
/// 1. 在保存SO时自动填充SpritePath和SpineAssetPath
/// 2. 提供手动批量更新所有SO的工具
/// 3. 同步更新JSON配置文件
///
/// 使用方法:
/// - 自动在ArtTableSO的OnValidate或保存时调用FillResourcePaths
/// - 手动:菜单 -> 美术工具 -> 更新所有美术资源路径
/// </summary>
public static class ArtResourcePathFiller
{
private const string SO_ROOT_PATH = "Assets/Art_SubModule/Art_SO";
private const string JSON_ROOT_PATH = "Assets/Art_SubModule/Art_Json";
/// <summary>
/// 自动填充单个SO的资源路径
/// 应该在ArtTableSO保存时调用
/// </summary>
public static void FillResourcePaths(ArtTableSO table)
{
if (table == null || table.Items == null)
return;
bool hasChanges = false;
foreach (var item in table.Items)
{
// 填充Sprite路径
if (item.Sprite != null)
{
string spritePath = AssetDatabase.GetAssetPath(item.Sprite);
if (!string.IsNullOrEmpty(spritePath) && item.SpritePath != spritePath)
{
item.SpritePath = spritePath;
hasChanges = true;
}
}
else
{
// 引用为空时,清空路径
if (!string.IsNullOrEmpty(item.SpritePath))
{
item.SpritePath = "";
hasChanges = true;
}
}
// 填充Spine路径
if (item.SpineAsset != null)
{
string spinePath = AssetDatabase.GetAssetPath(item.SpineAsset);
if (!string.IsNullOrEmpty(spinePath) && item.SpineAssetPath != spinePath)
{
item.SpineAssetPath = spinePath;
hasChanges = true;
}
}
else
{
// 引用为空时,清空路径
if (!string.IsNullOrEmpty(item.SpineAssetPath))
{
item.SpineAssetPath = "";
hasChanges = true;
}
}
}
if (hasChanges)
{
EditorUtility.SetDirty(table);
Debug.Log($"[ArtResourcePathFiller] 已更新资源路径: {table.TableName} ({table.TableId})");
// 同步到JSON
SyncToJson(table);
}
}
/// <summary>
/// 同步SO数据到JSON文件
/// </summary>
private static void SyncToJson(ArtTableSO table)
{
try
{
string soPath = AssetDatabase.GetAssetPath(table);
string relativePath = soPath.Replace(SO_ROOT_PATH, "").Replace(".asset", ".json");
string jsonPath = JSON_ROOT_PATH + relativePath;
// 确保目录存在
string directory = Path.GetDirectoryName(jsonPath);
if (!Directory.Exists(directory))
{
Directory.CreateDirectory(directory);
}
// 创建JSON数据
var jsonData = new ArtTableJsonData
{
TableId = table.TableId,
TableName = table.TableName,
Items = table.Items.Select(item => new ArtItemJsonData
{
Id = item.Id,
Name = item.Name,
Desc = item.Desc,
SpritePath = item.SpritePath,
SpineAssetPath = item.SpineAssetPath,
SpineAnimName = item.SpineAnimName
}).ToList()
};
string json = JsonUtility.ToJson(jsonData, true);
File.WriteAllText(jsonPath, json);
Debug.Log($"[ArtResourcePathFiller] JSON同步成功: {jsonPath}");
}
catch (System.Exception ex)
{
Debug.LogError($"[ArtResourcePathFiller] JSON同步失败: {ex.Message}");
}
}
/// <summary>
/// 手动批量更新所有ArtTableSO的资源路径
/// </summary>
[MenuItem("美术工具/路径管理/更新所有美术资源路径")]
public static void UpdateAllArtTablePaths()
{
// 查找所有ArtTableSO
string[] guids = AssetDatabase.FindAssets("t:ArtTableSO");
if (guids.Length == 0)
{
Debug.LogWarning("[ArtResourcePathFiller] 未找到任何ArtTableSO文件");
return;
}
int updatedCount = 0;
int totalCount = guids.Length;
EditorUtility.DisplayProgressBar("更新美术资源路径", "正在扫描...", 0);
for (int i = 0; i < guids.Length; i++)
{
string path = AssetDatabase.GUIDToAssetPath(guids[i]);
var table = AssetDatabase.LoadAssetAtPath<ArtTableSO>(path);
if (table != null)
{
EditorUtility.DisplayProgressBar(
"更新美术资源路径",
$"处理: {table.TableName} ({i + 1}/{totalCount})",
(float)i / totalCount
);
FillResourcePaths(table);
updatedCount++;
}
}
EditorUtility.ClearProgressBar();
// 保存所有修改
AssetDatabase.SaveAssets();
AssetDatabase.Refresh();
Debug.Log($"[ArtResourcePathFiller] ✓ 批量更新完成: 处理了 {updatedCount} 个ArtTableSO已同步JSON配置");
EditorUtility.DisplayDialog(
"更新完成",
$"已更新 {updatedCount} 个美术资源表的路径信息\n并同步更新了JSON配置文件\n\n现在可以在Runtime模式下正常加载资源了",
"确定"
);
}
/// <summary>
/// 验证所有SO的路径完整性
/// </summary>
[MenuItem("美术工具/路径管理/验证美术资源路径完整性")]
public static void ValidateAllPaths()
{
string[] guids = AssetDatabase.FindAssets("t:ArtTableSO");
if (guids.Length == 0)
{
Debug.LogWarning("[ArtResourcePathFiller] 未找到任何ArtTableSO文件");
return;
}
int missingPathCount = 0;
int totalItemCount = 0;
foreach (string guid in guids)
{
string path = AssetDatabase.GUIDToAssetPath(guid);
var table = AssetDatabase.LoadAssetAtPath<ArtTableSO>(path);
if (table == null || table.Items == null)
continue;
foreach (var item in table.Items)
{
totalItemCount++;
// 检查Sprite
if (item.Sprite != null && string.IsNullOrEmpty(item.SpritePath))
{
Debug.LogWarning($"[{table.TableName}] 资源项 '{item.Name}' 有Sprite引用但缺少路径");
missingPathCount++;
}
// 检查Spine
if (item.SpineAsset != null && string.IsNullOrEmpty(item.SpineAssetPath))
{
Debug.LogWarning($"[{table.TableName}] 资源项 '{item.Name}' 有Spine引用但缺少路径");
missingPathCount++;
}
}
}
if (missingPathCount == 0)
{
Debug.Log($"[ArtResourcePathFiller] ✓ 验证通过: 所有 {totalItemCount} 个资源项的路径都完整");
EditorUtility.DisplayDialog(
"验证通过",
$"所有 {totalItemCount} 个资源项的路径都完整\n\n可以正常使用Runtime模式",
"确定"
);
}
else
{
Debug.LogError($"[ArtResourcePathFiller] ✗ 发现 {missingPathCount} 个缺少路径的资源项");
EditorUtility.DisplayDialog(
"发现问题",
$"发现 {missingPathCount} 个缺少路径的资源项\n\n建议运行【美术工具 -> 更新所有美术资源路径】修复",
"确定"
);
}
}
}
/// <summary>
/// ArtTableSO的自定义Inspector
/// 在Inspector底部添加"更新路径"按钮
/// </summary>
[CustomEditor(typeof(ArtTableSO))]
public class ArtTableSOInspector : Editor
{
public override void OnInspectorGUI()
{
// 绘制默认Inspector
DrawDefaultInspector();
EditorGUILayout.Space(10);
EditorGUILayout.LabelField("", GUI.skin.horizontalSlider);
EditorGUILayout.Space(5);
var table = target as ArtTableSO;
if (table == null)
return;
// 统计信息
int spriteCount = table.Items.Count(item => item.Sprite != null);
int spineCount = table.Items.Count(item => item.SpineAsset != null);
int missingPathCount = table.Items.Count(item =>
(item.Sprite != null && string.IsNullOrEmpty(item.SpritePath)) ||
(item.SpineAsset != null && string.IsNullOrEmpty(item.SpineAssetPath))
);
EditorGUILayout.BeginVertical(EditorStyles.helpBox);
EditorGUILayout.LabelField("资源路径状态", EditorStyles.boldLabel);
EditorGUILayout.LabelField($"Sprite数量: {spriteCount}");
EditorGUILayout.LabelField($"Spine数量: {spineCount}");
if (missingPathCount > 0)
{
var oldColor = GUI.contentColor;
GUI.contentColor = Color.red;
EditorGUILayout.LabelField($"⚠️ 缺少路径: {missingPathCount}");
GUI.contentColor = oldColor;
}
else if (spriteCount > 0 || spineCount > 0)
{
var oldColor = GUI.contentColor;
GUI.contentColor = Color.green;
EditorGUILayout.LabelField("✓ 路径完整");
GUI.contentColor = oldColor;
}
EditorGUILayout.EndVertical();
EditorGUILayout.Space(5);
// 更新路径按钮
if (GUILayout.Button("🔄 更新此表的资源路径", GUILayout.Height(30)))
{
ArtResourcePathFiller.FillResourcePaths(table);
EditorUtility.SetDirty(table);
AssetDatabase.SaveAssets();
EditorUtility.DisplayDialog("更新完成", $"已更新 {table.TableName} 的资源路径", "确定");
}
EditorGUILayout.Space(5);
EditorGUILayout.HelpBox(
"提示保存SO时会自动更新路径手动点击按钮可强制更新",
MessageType.Info
);
}
}
/// <summary>
/// 资源保存时自动填充路径
/// </summary>
public class ArtTableSOAssetPostprocessor : AssetPostprocessor
{
static void OnPostprocessAllAssets(
string[] importedAssets,
string[] deletedAssets,
string[] movedAssets,
string[] movedFromAssetPaths)
{
foreach (string assetPath in importedAssets)
{
// 只处理ArtTableSO
if (!assetPath.EndsWith(".asset"))
continue;
var table = AssetDatabase.LoadAssetAtPath<ArtTableSO>(assetPath);
if (table != null)
{
ArtResourcePathFiller.FillResourcePaths(table);
}
}
}
}
/// <summary>
/// JSON数据结构
/// </summary>
[System.Serializable]
public class ArtTableJsonData
{
public int TableId;
public string TableName;
public List<ArtItemJsonData> Items;
}
[System.Serializable]
public class ArtItemJsonData
{
public int Id;
public string Name;
public string Desc;
public string SpritePath;
public string SpineAssetPath;
public string SpineAnimName;
}
}
#endif