using System.Collections.Generic;
using System.IO;
using UnityEditor;
using UnityEngine;
namespace BaseGames.Editor
{
///
/// 集中管理 ScriptableObject 资产的 CRUD 操作(含 Undo 支持)。
///
public static class AssetOperations
{
// ── 创建 ──────────────────────────────────────────────────────────────
///
/// 弹出 SaveFilePanel 让用户选择路径,创建并返回新资产。
/// 创建失败或用户取消时返回 null。
///
public static T Create(string defaultFolder, string defaultName) where T : ScriptableObject
{
if (!Directory.Exists(defaultFolder))
Directory.CreateDirectory(defaultFolder);
string path = EditorUtility.SaveFilePanelInProject(
"新建 " + typeof(T).Name,
defaultName + ".asset",
"asset",
"选择保存路径",
defaultFolder);
if (string.IsNullOrEmpty(path))
return null;
var asset = ScriptableObject.CreateInstance();
asset.name = Path.GetFileNameWithoutExtension(path);
AssetDatabase.CreateAsset(asset, path);
Undo.RegisterCreatedObjectUndo(asset, "Create " + typeof(T).Name);
AssetDatabase.SaveAssets();
AssetDatabase.Refresh();
return asset;
}
// ── 重命名 ───────────────────────────────────────────────────────────
///
/// 重命名资产(同时更新磁盘文件名和 asset.name)。
/// 返回 (true, null) 成功;(false, errorMsg) 失败。
///
public static (bool ok, string error) Rename(UnityEngine.Object asset, string newName)
{
if (asset == null) return (false, "资产为 null");
if (string.IsNullOrWhiteSpace(newName)) return (false, "名称不能为空");
newName = newName.Trim();
string path = AssetDatabase.GetAssetPath(asset);
if (string.IsNullOrEmpty(path)) return (false, "资产不在 AssetDatabase 中");
// 先更新序列化内部名称
string oldName = asset.name;
Undo.RecordObject(asset, "Rename " + oldName);
asset.name = newName;
EditorUtility.SetDirty(asset);
// 再重命名磁盘文件
string err = AssetDatabase.RenameAsset(path, newName);
if (!string.IsNullOrEmpty(err))
{
asset.name = oldName;
EditorUtility.SetDirty(asset);
return (false, err);
}
AssetDatabase.SaveAssets();
AssetDatabase.Refresh();
return (true, null);
}
// ── 删除 ─────────────────────────────────────────────────────────────
/// 弹出确认对话框,确认后删除资产文件。返回是否已删除。
public static bool Delete(UnityEngine.Object asset)
{
if (asset == null) return false;
string path = AssetDatabase.GetAssetPath(asset);
if (string.IsNullOrEmpty(path)) return false;
if (!EditorUtility.DisplayDialog(
"确认删除",
$"删除资产:{asset.name}\n路径:{path}\n\n此操作不可撤销。",
"删除", "取消"))
return false;
AssetDatabase.DeleteAsset(path);
AssetDatabase.Refresh();
return true;
}
// ── 克隆 ─────────────────────────────────────────────────────────────
/// 复制资产文件并返回克隆的资产;用户取消或失败时返回 null。
public static T Clone(T source, string defaultFolder) where T : ScriptableObject
{
if (source == null) return null;
string srcPath = AssetDatabase.GetAssetPath(source);
string path = EditorUtility.SaveFilePanelInProject(
"克隆 " + source.name,
source.name + "_Copy.asset",
"asset",
"选择保存路径",
defaultFolder);
if (string.IsNullOrEmpty(path)) return null;
if (!AssetDatabase.CopyAsset(srcPath, path))
{
Debug.LogError($"[AssetOperations] 克隆失败:{srcPath} → {path}");
return null;
}
AssetDatabase.Refresh();
var clone = AssetDatabase.LoadAssetAtPath(path);
if (clone != null)
Undo.RegisterCreatedObjectUndo(clone, "Clone " + source.name);
return clone;
}
// ── 查询 ─────────────────────────────────────────────────────────────
/// 在 AssetDatabase 中查找所有 T 类型资产。
public static List FindAll() where T : ScriptableObject
{
var result = new List();
string[] guids = AssetDatabase.FindAssets("t:" + typeof(T).Name);
foreach (var guid in guids)
{
string p = AssetDatabase.GUIDToAssetPath(guid);
var asset = AssetDatabase.LoadAssetAtPath(p);
if (asset != null) result.Add(asset);
}
return result;
}
// ── GUID 工具 ─────────────────────────────────────────────────────────
public static string GetGuid(UnityEngine.Object asset)
{
if (asset == null) return string.Empty;
return AssetDatabase.AssetPathToGUID(AssetDatabase.GetAssetPath(asset));
}
public static T LoadByGuid(string guid) where T : UnityEngine.Object
{
if (string.IsNullOrEmpty(guid)) return null;
return AssetDatabase.LoadAssetAtPath(AssetDatabase.GUIDToAssetPath(guid));
}
}
}