架构大更
This commit is contained in:
@@ -1,134 +1,177 @@
|
||||
#if UNITY_EDITOR
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using Sirenix.OdinInspector;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
using Continentis.MainGame.Card;
|
||||
using Continentis.MainGame.Character;
|
||||
using SLSFramework.UModAssistance;
|
||||
|
||||
namespace Continentis.MainGame.Equipment
|
||||
{
|
||||
[CustomEditor(typeof(EquipmentData))]
|
||||
public class EquipmentDataEditor : DataEditor
|
||||
{
|
||||
// Fundamental
|
||||
private SerializedProperty _haveCustomClassProp;
|
||||
private SerializedProperty _modNameProp;
|
||||
private SerializedProperty _classNameProp;
|
||||
private SerializedProperty _displayNameProp;
|
||||
private SerializedProperty _tagsProp;
|
||||
private SerializedProperty _equipmentRarityProp;
|
||||
private SerializedProperty _equipmentIconProp;
|
||||
private SerializedProperty _equipmentDescriptionProp;
|
||||
|
||||
// Attributes
|
||||
private SerializedProperty _coreNumericChangeProp;
|
||||
private SerializedProperty _corePercentageChangeOfAccumulationProp;
|
||||
private SerializedProperty _corePercentageChangeOfMultiplicationProp;
|
||||
private SerializedProperty _generalNumericChangeProp;
|
||||
private SerializedProperty _generalPercentageChangeOfAccumulationProp;
|
||||
private SerializedProperty _generalPercentageChangeOfMultiplicationProp;
|
||||
|
||||
// References
|
||||
private SerializedProperty _prefabRefsProp;
|
||||
private SerializedProperty _derivativeCardDataRefsProp;
|
||||
private SerializedProperty _derivativeCharacterDataRefsProp;
|
||||
private SerializedProperty _belongingCardDataRefsProp;
|
||||
// =========================================================================
|
||||
// EquipmentDataEditor
|
||||
//
|
||||
// 注意:此类已不再使用 [CustomEditor] 注解。
|
||||
// Odin Inspector 会自动接管 EquipmentData(ScriptableObject)的 Inspector 渲染,
|
||||
// 无需任何自定义 Editor 类。本文件现主要用于承载 EquipmentData 的编辑器扩展分部类。
|
||||
// =========================================================================
|
||||
internal static class EquipmentDataEditorPlaceholder
|
||||
{
|
||||
// 保留此类以维持文件存在意义,可在此添加未来的编辑器工具方法。
|
||||
}
|
||||
|
||||
protected override void OnEnable()
|
||||
// =========================================================================
|
||||
// partial class EquipmentData — 编辑器专属扩展
|
||||
//
|
||||
// 包含:
|
||||
// 1. GetEquipmentLogicDropdownItems() — 装备逻辑类下拉列表(静态)
|
||||
// 2. OnEquipmentLogicClassSelected() — 选中逻辑类后自动填充字段的回调
|
||||
// 3. GetAvailable*() — References 列表的资产名称选择器
|
||||
// 4. 内部共享辅助方法(AssetDatabase 查询)
|
||||
// =========================================================================
|
||||
public partial class EquipmentData
|
||||
{
|
||||
// ── 1. 装备逻辑类选择器 ────────────────────────────────────────────────
|
||||
// 替代旧 EquipmentDataEditor 中的 DrawSearchableTypeSelector()
|
||||
// 配合 EquipmentData.cs 中 _classSelector 字段上的
|
||||
// [ValueDropdown("@EquipmentData.GetEquipmentLogicDropdownItems()")]
|
||||
|
||||
/// <summary>
|
||||
/// 为 [ValueDropdown] 提供所有 EquipmentBase 子类的层级下拉项。
|
||||
/// 路径格式为 "ModName/Category/ClassName",与旧 TypeSelectorWindow 分组逻辑一致。
|
||||
/// 此方法为 static,故在 [ValueDropdown] 中使用 @ 表达式语法引用。
|
||||
/// </summary>
|
||||
public static IEnumerable<ValueDropdownItem<string>> GetEquipmentLogicDropdownItems()
|
||||
{
|
||||
base.OnEnable();
|
||||
// --- 在OnEnable中找到所有属性 ---
|
||||
_haveCustomClassProp = serializedObject.FindProperty("haveCustomClass");
|
||||
_modNameProp = serializedObject.FindProperty("modName");
|
||||
_classNameProp = serializedObject.FindProperty("className");
|
||||
_displayNameProp = serializedObject.FindProperty("displayName");
|
||||
_tagsProp = serializedObject.FindProperty("tags");
|
||||
_equipmentRarityProp = serializedObject.FindProperty("equipmentRarity");
|
||||
_equipmentIconProp = serializedObject.FindProperty("equipmentIcon");
|
||||
_equipmentDescriptionProp = serializedObject.FindProperty("equipmentDescription");
|
||||
const string namespacePrefix = "Continentis.Mods";
|
||||
const string namespaceToRemove = "Equipments";
|
||||
|
||||
_coreNumericChangeProp = serializedObject.FindProperty("coreNumericChange");
|
||||
_corePercentageChangeOfAccumulationProp = serializedObject.FindProperty("corePercentageChangeOfAccumulation");
|
||||
_corePercentageChangeOfMultiplicationProp = serializedObject.FindProperty("corePercentageChangeOfMultiplication");
|
||||
_generalNumericChangeProp = serializedObject.FindProperty("generalNumericChange");
|
||||
_generalPercentageChangeOfAccumulationProp = serializedObject.FindProperty("generalPercentageChangeOfAccumulation");
|
||||
_generalPercentageChangeOfMultiplicationProp = serializedObject.FindProperty("generalPercentageChangeOfMultiplication");
|
||||
IEnumerable<Type> types = AppDomain.CurrentDomain.GetAssemblies()
|
||||
.SelectMany(a =>
|
||||
{
|
||||
try { return a.GetTypes(); }
|
||||
catch { return Type.EmptyTypes; }
|
||||
})
|
||||
.Where(t => typeof(EquipmentBase).IsAssignableFrom(t)
|
||||
&& !t.IsAbstract
|
||||
&& !t.IsInterface
|
||||
&& t != typeof(EquipmentBase));
|
||||
|
||||
_prefabRefsProp = serializedObject.FindProperty("prefabRefs");
|
||||
_derivativeCardDataRefsProp = serializedObject.FindProperty("derivativeCardDataRefs");
|
||||
_derivativeCharacterDataRefsProp = serializedObject.FindProperty("derivativeCharacterDataRefs");
|
||||
_belongingCardDataRefsProp = serializedObject.FindProperty("belongingCardDataRefs");
|
||||
foreach (Type type in types.OrderBy(t => t.FullName))
|
||||
{
|
||||
string path;
|
||||
|
||||
if (type.Namespace != null && type.Namespace.StartsWith(namespacePrefix))
|
||||
{
|
||||
List<string> segments = type.Namespace
|
||||
.Substring(namespacePrefix.Length)
|
||||
.Split('.')
|
||||
.Where(s => !string.IsNullOrEmpty(s) && s != namespaceToRemove)
|
||||
.ToList();
|
||||
|
||||
path = segments.Count > 0
|
||||
? string.Join("/", segments) + "/" + type.Name
|
||||
: type.Name;
|
||||
}
|
||||
else
|
||||
{
|
||||
path = "Uncategorized/" + type.Name;
|
||||
}
|
||||
|
||||
// value 存储类型的完整名称(FullName),便于在 OnValueChanged 中精确反查
|
||||
yield return new ValueDropdownItem<string>(path, type.FullName ?? type.Name);
|
||||
}
|
||||
}
|
||||
|
||||
public override void OnInspectorGUI()
|
||||
/// <summary>
|
||||
/// 当 classFullName 通过下拉菜单改变后,自动填充 className / modName / displayName。
|
||||
/// 被 EquipmentData.cs 中 classFullName 字段上的 [OnValueChanged("OnEquipmentLogicClassSelected")] 触发。
|
||||
/// </summary>
|
||||
private void OnEquipmentLogicClassSelected()
|
||||
{
|
||||
serializedObject.Update();
|
||||
if (string.IsNullOrEmpty(classFullName)) return;
|
||||
|
||||
// --- 按照你在EquipmentData.cs中声明的顺序手动绘制所有字段 ---
|
||||
|
||||
EditorGUILayout.LabelField("Fundamental", EditorStyles.boldLabel);
|
||||
EditorGUILayout.PropertyField(_haveCustomClassProp);
|
||||
// 根据 FullName 反查对应 Type
|
||||
Type selectedType = AppDomain.CurrentDomain.GetAssemblies()
|
||||
.SelectMany(a =>
|
||||
{
|
||||
try { return a.GetTypes(); }
|
||||
catch { return Type.EmptyTypes; }
|
||||
})
|
||||
.FirstOrDefault(t =>
|
||||
(t.FullName == classFullName || t.Name == classFullName)
|
||||
&& typeof(EquipmentBase).IsAssignableFrom(t)
|
||||
&& !t.IsAbstract);
|
||||
|
||||
// --- 核心逻辑:根据 haveCustomClass 的值来决定显示/隐藏 ---
|
||||
if (_haveCustomClassProp.boolValue)
|
||||
if (selectedType == null) return;
|
||||
|
||||
const string prefix = "Continentis.Mods";
|
||||
string ns = selectedType.Namespace ?? string.Empty;
|
||||
|
||||
if (ns.StartsWith(prefix))
|
||||
{
|
||||
// 如果勾选,则显示class选择器 (假设基类为EquipmentBase, 命名空间为.Equipments)
|
||||
DrawSearchableTypeSelector(
|
||||
_classNameProp,
|
||||
"Equipment Class",
|
||||
typeof(EquipmentBase),
|
||||
(outType) =>
|
||||
{
|
||||
string className = outType.Name;
|
||||
string modName = outType.Namespace!.Replace("Continentis.Mods.", "").Split('.')[0];
|
||||
string displayName = "Card_" + modName + "_" + className + "_DisplayName";
|
||||
// 例:ns = "Continentis.Mods.Basic.Equipments.Sword"
|
||||
// → afterPrefix = ".Basic.Equipments.Sword" (if prefix is without dot)
|
||||
// 统一处理点号
|
||||
string afterPrefix = ns.Substring(prefix.Length).TrimStart('.');
|
||||
string[] parts = afterPrefix.Split('.');
|
||||
string resolvedMod = parts.Length > 0 ? parts[0] : string.Empty;
|
||||
|
||||
_classNameProp.stringValue = className;
|
||||
_modNameProp.stringValue = modName;
|
||||
_displayNameProp.stringValue = displayName;
|
||||
},
|
||||
"Continentis.Mods",
|
||||
"Equipments");
|
||||
// 移除 "Equipments" 层级并计算 className(短路径模式)
|
||||
string equipmentsSegment = "Equipments";
|
||||
string resolvedCategory = ns.Contains(equipmentsSegment)
|
||||
? ns.Split(new[] { equipmentsSegment }, StringSplitOptions.None).Last().TrimStart('.')
|
||||
: string.Empty;
|
||||
|
||||
modName = resolvedMod;
|
||||
className = string.IsNullOrEmpty(resolvedCategory)
|
||||
? selectedType.Name
|
||||
: resolvedCategory + "." + selectedType.Name;
|
||||
|
||||
EditorGUI.BeginDisabledGroup(true);
|
||||
displayName = $"Equipment_{resolvedMod}_{selectedType.Name}_DisplayName";
|
||||
}
|
||||
|
||||
EditorGUILayout.PropertyField(_modNameProp);
|
||||
EditorGUILayout.PropertyField(_classNameProp);
|
||||
EditorGUILayout.PropertyField(_displayNameProp);
|
||||
|
||||
if (_haveCustomClassProp.boolValue)
|
||||
else
|
||||
{
|
||||
EditorGUI.EndDisabledGroup();
|
||||
modName = string.Empty;
|
||||
className = selectedType.Name;
|
||||
displayName = $"Equipment_{selectedType.Name}_DisplayName";
|
||||
}
|
||||
|
||||
EditorGUILayout.PropertyField(_tagsProp, true);
|
||||
EditorGUILayout.PropertyField(_equipmentRarityProp);
|
||||
EditorGUILayout.PropertyField(_equipmentIconProp);
|
||||
EditorGUILayout.PropertyField(_equipmentDescriptionProp);
|
||||
|
||||
EditorGUILayout.Space();
|
||||
EditorGUILayout.LabelField("Attributes", EditorStyles.boldLabel);
|
||||
EditorGUILayout.PropertyField(_coreNumericChangeProp, true);
|
||||
EditorGUILayout.PropertyField(_corePercentageChangeOfAccumulationProp, true);
|
||||
EditorGUILayout.PropertyField(_corePercentageChangeOfMultiplicationProp, true);
|
||||
EditorGUILayout.PropertyField(_generalNumericChangeProp, true);
|
||||
EditorGUILayout.PropertyField(_generalPercentageChangeOfAccumulationProp, true);
|
||||
EditorGUILayout.PropertyField(_generalPercentageChangeOfMultiplicationProp, true);
|
||||
|
||||
EditorGUILayout.Space();
|
||||
EditorGUILayout.LabelField("References", EditorStyles.boldLabel);
|
||||
DrawCharacterListGUI<GameObject>(_prefabRefsProp);
|
||||
DrawCharacterListGUI<CardData>(_derivativeCardDataRefsProp);
|
||||
DrawCharacterListGUI<CharacterData>(_derivativeCharacterDataRefsProp);
|
||||
DrawCharacterListGUI<CardData>(_belongingCardDataRefsProp);
|
||||
EditorUtility.SetDirty(this);
|
||||
|
||||
// 处理所有可能发生的ObjectPicker事件
|
||||
HandleObjectPicker();
|
||||
|
||||
serializedObject.ApplyModifiedProperties();
|
||||
Debug.Log($"[EquipmentData] 已自动填充 → modName: {modName}, className: {className}, " +
|
||||
$"displayName: {displayName}, classFullName: {classFullName}");
|
||||
}
|
||||
}
|
||||
|
||||
// ── 2. References 列表的资产名称选择器 ──────────────────────────────────
|
||||
// 替代旧 DrawCharacterListGUI<T>(prop)
|
||||
|
||||
private IEnumerable<ValueDropdownItem<string>> GetAvailablePrefabs()
|
||||
=> GetAssetNameDropdown("t:Prefab");
|
||||
|
||||
private IEnumerable<ValueDropdownItem<string>> GetAvailableCardData()
|
||||
=> GetAssetNameDropdown("t:CardData");
|
||||
|
||||
private IEnumerable<ValueDropdownItem<string>> GetAvailableCharacterData()
|
||||
=> GetAssetNameDropdown("t:CharacterData");
|
||||
|
||||
// ── 内部共享辅助方法 ─────────────────────────────────────────────────
|
||||
|
||||
/// <summary>
|
||||
/// 通过 AssetDatabase 搜索特定类型/标签的资产,将文件名(无扩展名)作为下拉项返回。
|
||||
/// 用于 References 列表的字符串引用选择。
|
||||
/// </summary>
|
||||
private static IEnumerable<ValueDropdownItem<string>> GetAssetNameDropdown(string searchFilter)
|
||||
{
|
||||
string[] guids = AssetDatabase.FindAssets(searchFilter);
|
||||
foreach (string guid in guids)
|
||||
{
|
||||
string path = AssetDatabase.GUIDToAssetPath(guid);
|
||||
string name = Path.GetFileNameWithoutExtension(path);
|
||||
yield return new ValueDropdownItem<string>(name, name);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
Reference in New Issue
Block a user