- 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.
185 lines
6.6 KiB
C#
185 lines
6.6 KiB
C#
using System;
|
||
using UnityEditor;
|
||
using UnityEditor.UIElements;
|
||
using UnityEngine;
|
||
using UnityEngine.UIElements;
|
||
using BaseGames.Player;
|
||
|
||
namespace BaseGames.Editor.Modules
|
||
{
|
||
/// <summary>
|
||
/// DataHub 武器模块 —— 管理 WeaponSO 资产。
|
||
/// </summary>
|
||
public class WeaponModule : IDataModule
|
||
{
|
||
private const string Folder = "Assets/_Game/Data/Weapons";
|
||
private const string Prefix = "WPN_";
|
||
|
||
public string ModuleId => "weapon";
|
||
public string DisplayName => "武器";
|
||
public string IconName => "d_Sword Icon";
|
||
|
||
private SoListPane<WeaponSO> _listPane;
|
||
private DetailHeader _header;
|
||
private VisualElement _detailRoot;
|
||
private WeaponSO _selected;
|
||
|
||
public void Initialize()
|
||
{
|
||
_listPane = new SoListPane<WeaponSO>(
|
||
Folder, Prefix,
|
||
w => w.weaponType.ToString());
|
||
}
|
||
|
||
public void BuildListPane(VisualElement container, Action<UnityEngine.Object> onSelected)
|
||
{
|
||
_listPane.SelectionChanged = sel =>
|
||
{
|
||
_selected = sel;
|
||
onSelected?.Invoke(sel);
|
||
};
|
||
container.Add(_listPane);
|
||
_listPane.Refresh();
|
||
}
|
||
|
||
public void BuildDetailPane(VisualElement container, UnityEngine.Object selected)
|
||
{
|
||
_selected = selected as WeaponSO;
|
||
|
||
// Header(重命名)
|
||
_header = new DetailHeader();
|
||
_header.SetAsset(_selected);
|
||
_header.RenameRequested += OnRenameRequested;
|
||
container.Add(_header);
|
||
|
||
if (_selected == null) return;
|
||
|
||
// Stats Card
|
||
var statsCard = BuildStatsCard(_selected);
|
||
container.Add(statsCard);
|
||
|
||
// 操作按钮行
|
||
var toolbar = BuildActionBar(_selected);
|
||
container.Add(toolbar);
|
||
|
||
// 分隔线
|
||
container.Add(MakeDivider());
|
||
|
||
// Inspector
|
||
var insp = new InspectorElement(_selected);
|
||
insp.style.flexGrow = 1;
|
||
container.Add(insp);
|
||
}
|
||
|
||
public void OnActivated()
|
||
{
|
||
_listPane?.Refresh();
|
||
}
|
||
|
||
// ── 内部 ─────────────────────────────────────────────────────────────
|
||
|
||
private void OnRenameRequested(string newName)
|
||
{
|
||
if (_selected == null) return;
|
||
var (ok, err) = AssetOperations.Rename(_selected, newName);
|
||
if (!ok)
|
||
EditorUtility.DisplayDialog("重命名失败", err, "确定");
|
||
else
|
||
{
|
||
_header.SetAsset(_selected);
|
||
_listPane.Invalidate();
|
||
}
|
||
}
|
||
|
||
private static VisualElement BuildStatsCard(WeaponSO w)
|
||
{
|
||
var card = new VisualElement();
|
||
card.style.flexDirection = FlexDirection.Row;
|
||
card.style.flexWrap = Wrap.Wrap;
|
||
card.style.paddingLeft = 12;
|
||
card.style.paddingRight = 12;
|
||
card.style.paddingTop = 8;
|
||
card.style.paddingBottom = 8;
|
||
card.style.marginBottom = 4;
|
||
card.style.backgroundColor = new StyleColor(new Color(0.5f, 0.5f, 0.5f, 0.08f));
|
||
card.style.borderBottomWidth = 1;
|
||
card.style.borderBottomColor = new StyleColor(new Color(0.5f, 0.5f, 0.5f, 0.2f));
|
||
|
||
AddStatChip(card, "类型", w.weaponType.ToString());
|
||
AddStatChip(card, "地面段数", (w.groundComboSteps?.Length ?? 0).ToString());
|
||
AddStatChip(card, "空中段数", (w.airComboSteps?.Length ?? 0).ToString());
|
||
AddStatChip(card, "ID", string.IsNullOrEmpty(w.weaponId) ? "-" : w.weaponId);
|
||
return card;
|
||
}
|
||
|
||
private static void AddStatChip(VisualElement parent, string label, string value)
|
||
{
|
||
var chip = new VisualElement();
|
||
chip.style.flexDirection = FlexDirection.Row;
|
||
chip.style.alignItems = Align.Center;
|
||
chip.style.marginRight = 14;
|
||
chip.style.marginBottom = 2;
|
||
|
||
var lbl = new Label(label + ":");
|
||
lbl.style.opacity = 0.6f;
|
||
lbl.style.fontSize = 11;
|
||
lbl.style.marginRight = 3;
|
||
chip.Add(lbl);
|
||
|
||
var val = new Label(value);
|
||
val.style.fontSize = 11;
|
||
val.style.unityFontStyleAndWeight = UnityEngine.FontStyle.Bold;
|
||
chip.Add(val);
|
||
|
||
parent.Add(chip);
|
||
}
|
||
|
||
private VisualElement BuildActionBar(WeaponSO w)
|
||
{
|
||
var bar = new VisualElement();
|
||
bar.style.flexDirection = FlexDirection.Row;
|
||
bar.style.paddingLeft = 12;
|
||
bar.style.paddingRight = 12;
|
||
bar.style.paddingTop = 6;
|
||
bar.style.paddingBottom = 6;
|
||
bar.style.flexWrap = Wrap.Wrap;
|
||
|
||
var btnPing = new Button(() => { EditorGUIUtility.PingObject(w); Selection.activeObject = w; })
|
||
{ text = "在 Project 中定位", tooltip = "在 Project 窗口高亮此资产" };
|
||
bar.Add(btnPing);
|
||
|
||
var btnClone = new Button(() =>
|
||
{
|
||
var clone = AssetOperations.Clone(w, Folder);
|
||
if (clone != null) _listPane.Refresh(clone);
|
||
}) { text = "克隆..." };
|
||
bar.Add(btnClone);
|
||
|
||
var btnDel = new Button(() =>
|
||
{
|
||
if (AssetOperations.Delete(w)) _listPane.Refresh(null);
|
||
}) { text = "删除" };
|
||
btnDel.style.borderLeftColor = new StyleColor(new Color(0.8f, 0.3f, 0.3f, 0.6f));
|
||
btnDel.style.borderRightColor = new StyleColor(new Color(0.8f, 0.3f, 0.3f, 0.6f));
|
||
btnDel.style.borderTopColor = new StyleColor(new Color(0.8f, 0.3f, 0.3f, 0.6f));
|
||
btnDel.style.borderBottomColor = new StyleColor(new Color(0.8f, 0.3f, 0.3f, 0.6f));
|
||
btnDel.style.borderLeftWidth = 1;
|
||
btnDel.style.borderRightWidth = 1;
|
||
btnDel.style.borderTopWidth = 1;
|
||
btnDel.style.borderBottomWidth = 1;
|
||
btnDel.style.marginLeft = 8;
|
||
bar.Add(btnDel);
|
||
|
||
return bar;
|
||
}
|
||
|
||
private static VisualElement MakeDivider()
|
||
{
|
||
var d = new VisualElement();
|
||
d.style.height = 1;
|
||
d.style.backgroundColor = new StyleColor(new Color(0.5f, 0.5f, 0.5f, 0.2f));
|
||
return d;
|
||
}
|
||
}
|
||
}
|