Files
zeling_v2/Assets/_Game/Scripts/Editor/Shared/AssetOperations.cs
Joywayer bb3afd130f feat: Add SkillModule and WeaponModule for managing skills and weapons
- Implemented SkillModule to manage FormSkillSO assets with a detailed UI for editing and displaying skill properties.
- Implemented WeaponModule to manage WeaponSO assets with a detailed UI for editing and displaying weapon properties.
- Created AssetOperations class for centralized CRUD operations on ScriptableObject assets, including create, rename, delete, and clone functionalities.
- Added DetailHeader for displaying and renaming asset names in the UI.
- Introduced SoListPane for a reusable ScriptableObject list panel with search functionality and context menus.
- Added meta files for all new scripts to ensure proper asset management in Unity.
2026-05-21 07:09:53 +08:00

159 lines
6.6 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.
using System.Collections.Generic;
using System.IO;
using UnityEditor;
using UnityEngine;
namespace BaseGames.Editor
{
/// <summary>
/// 集中管理 ScriptableObject 资产的 CRUD 操作(含 Undo 支持)。
/// </summary>
public static class AssetOperations
{
// ── 创建 ──────────────────────────────────────────────────────────────
/// <summary>
/// 弹出 SaveFilePanel 让用户选择路径,创建并返回新资产。
/// 创建失败或用户取消时返回 null。
/// </summary>
public static T Create<T>(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<T>();
asset.name = Path.GetFileNameWithoutExtension(path);
AssetDatabase.CreateAsset(asset, path);
Undo.RegisterCreatedObjectUndo(asset, "Create " + typeof(T).Name);
AssetDatabase.SaveAssets();
AssetDatabase.Refresh();
return asset;
}
// ── 重命名 ───────────────────────────────────────────────────────────
/// <summary>
/// 重命名资产(同时更新磁盘文件名和 asset.name
/// 返回 (true, null) 成功;(false, errorMsg) 失败。
/// </summary>
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);
}
// ── 删除 ─────────────────────────────────────────────────────────────
/// <summary>弹出确认对话框,确认后删除资产文件。返回是否已删除。</summary>
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;
}
// ── 克隆 ─────────────────────────────────────────────────────────────
/// <summary>复制资产文件并返回克隆的资产;用户取消或失败时返回 null。</summary>
public static T Clone<T>(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<T>(path);
if (clone != null)
Undo.RegisterCreatedObjectUndo(clone, "Clone " + source.name);
return clone;
}
// ── 查询 ─────────────────────────────────────────────────────────────
/// <summary>在 AssetDatabase 中查找所有 T 类型资产。</summary>
public static List<T> FindAll<T>() where T : ScriptableObject
{
var result = new List<T>();
string[] guids = AssetDatabase.FindAssets("t:" + typeof(T).Name);
foreach (var guid in guids)
{
string p = AssetDatabase.GUIDToAssetPath(guid);
var asset = AssetDatabase.LoadAssetAtPath<T>(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<T>(string guid) where T : UnityEngine.Object
{
if (string.IsNullOrEmpty(guid)) return null;
return AssetDatabase.LoadAssetAtPath<T>(AssetDatabase.GUIDToAssetPath(guid));
}
}
}