#if UNITY_EDITOR
using System;
using System.Collections.Generic;
using System.Linq;
using UnityEditor;
using UnityEngine;
using BaseGames.Equipment;
namespace BaseGames.Editor.Equipment
{
///
/// 为 CharmSO.effects(List<ICharmEffect>)提供友好的 Inspector 体验(架构 09_ProgressionModule §4.1)。
/// - 下拉菜单选类型(显示中文名而非 C# 全称)
/// - 每条效果展开显示字段 + GetEffectDescription() 预览文字
/// - 支持单条删除
///
[CustomEditor(typeof(CharmSO))]
public class CharmSOEditor : UnityEditor.Editor
{
// 已注册的所有 ICharmEffect 实现类型(反射收集)
private static readonly Type[] _effectTypes = CollectEffectTypes();
// 策划友好名称映射
private static readonly Dictionary _typeLabels = new()
{
{ typeof(StatModifierEffect), "属性加成" },
{ typeof(AttackSpeedEffect), "攻击速度" },
{ typeof(OnHitEffect), "命中触发" },
{ typeof(SoulSpellEffect), "灵魂法术" },
{ typeof(SkillNumericModifierEffect), "技能数值修改" },
{ typeof(SkillSlotOverrideEffect), "技能插槽替换" },
{ typeof(WeaponOverrideEffect), "武器替换" },
};
private SerializedProperty _effectsProp;
private void OnEnable()
=> _effectsProp = serializedObject.FindProperty("effects");
public override void OnInspectorGUI()
{
serializedObject.Update();
DrawPropertiesExcluding(serializedObject, "effects");
EditorGUILayout.Space(8);
EditorGUILayout.LabelField("Effects", EditorStyles.boldLabel);
if (_effectsProp != null)
{
for (int i = 0; i < _effectsProp.arraySize; i++)
{
var elemProp = _effectsProp.GetArrayElementAtIndex(i);
var effect = elemProp.managedReferenceValue as ICharmEffect;
string label = effect != null && _typeLabels.TryGetValue(effect.GetType(), out var n)
? n : (effect?.GetType().Name ?? "null");
EditorGUILayout.BeginVertical(EditorStyles.helpBox);
EditorGUILayout.BeginHorizontal();
EditorGUILayout.LabelField(label, EditorStyles.boldLabel);
if (GUILayout.Button("✕", GUILayout.Width(24)))
{
_effectsProp.DeleteArrayElementAtIndex(i);
serializedObject.ApplyModifiedProperties();
break;
}
EditorGUILayout.EndHorizontal();
EditorGUILayout.PropertyField(elemProp, GUIContent.none, true);
if (effect != null)
EditorGUILayout.LabelField(effect.GetEffectDescription(),
EditorStyles.miniLabel);
EditorGUILayout.EndVertical();
EditorGUILayout.Space(2);
}
}
// 添加效果按钮(下拉菜单)
if (GUILayout.Button("+ 添加效果"))
{
var menu = new GenericMenu();
foreach (var t in _effectTypes)
{
var captured = t;
string menuLabel = _typeLabels.GetValueOrDefault(t, t.Name);
menu.AddItem(new GUIContent(menuLabel), false, () =>
{
if (_effectsProp == null) return;
_effectsProp.arraySize++;
_effectsProp
.GetArrayElementAtIndex(_effectsProp.arraySize - 1)
.managedReferenceValue = Activator.CreateInstance(captured);
serializedObject.ApplyModifiedProperties();
});
}
menu.ShowAsContext();
}
serializedObject.ApplyModifiedProperties();
}
private static Type[] CollectEffectTypes()
{
var baseType = typeof(ICharmEffect);
return AppDomain.CurrentDomain.GetAssemblies()
.SelectMany(a =>
{
try { return a.GetTypes(); }
catch { return Array.Empty(); }
})
.Where(t => t.IsClass && !t.IsAbstract && baseType.IsAssignableFrom(t))
.ToArray();
}
}
}
#endif