#if UNITY_EDITOR using UnityEngine; using UnityEditor; using ArtResource; using System.Linq; namespace ArtTools { /// /// 美术资源路径自动填充工具 /// /// 功能: /// 1. 在保存SO时自动填充SpritePath和SpineAssetPath /// 2. 提供手动批量更新所有SO的工具 /// /// 使用方法: /// - 自动:在ArtTableSO的OnValidate或保存时调用FillResourcePaths /// - 手动:菜单 -> 美术工具 -> 更新所有美术资源路径 /// public static class ArtResourcePathFiller { /// /// 自动填充单个SO的资源路径 /// 应该在ArtTableSO保存时调用 /// 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})"); } } /// /// 手动批量更新所有ArtTableSO的资源路径 /// [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(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"); EditorUtility.DisplayDialog( "更新完成", $"已更新 {updatedCount} 个美术资源表的路径信息\n\n现在可以在Runtime模式下正常加载资源了", "确定" ); } /// /// 验证所有SO的路径完整性 /// [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(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建议运行【美术工具 -> 更新所有美术资源路径】修复", "确定" ); } } } /// /// ArtTableSO的自定义Inspector /// 在Inspector底部添加"更新路径"按钮 /// [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 ); } } /// /// 资源保存时自动填充路径 /// 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(assetPath); if (table != null) { ArtResourcePathFiller.FillResourcePaths(table); } } } } } #endif