#if UNITY_EDITOR
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using Sirenix.OdinInspector;
using UnityEditor;
using UnityEngine;
namespace Continentis.MainGame.Equipment
{
// =========================================================================
// EquipmentDataEditor
//
// 注意:此类已不再使用 [CustomEditor] 注解。
// Odin Inspector 会自动接管 EquipmentData(ScriptableObject)的 Inspector 渲染,
// 无需任何自定义 Editor 类。本文件现主要用于承载 EquipmentData 的编辑器扩展分部类。
// =========================================================================
internal static class EquipmentDataEditorPlaceholder
{
// 保留此类以维持文件存在意义,可在此添加未来的编辑器工具方法。
}
// =========================================================================
// 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()")]
///
/// 为 [ValueDropdown] 提供所有 EquipmentBase 子类的层级下拉项。
/// 路径格式为 "ModName/Category/ClassName",与旧 TypeSelectorWindow 分组逻辑一致。
/// 此方法为 static,故在 [ValueDropdown] 中使用 @ 表达式语法引用。
///
public static IEnumerable> GetEquipmentLogicDropdownItems()
{
const string namespacePrefix = "Continentis.Mods";
const string namespaceToRemove = "Equipments";
IEnumerable 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));
foreach (Type type in types.OrderBy(t => t.FullName))
{
string path;
if (type.Namespace != null && type.Namespace.StartsWith(namespacePrefix))
{
List 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(path, type.FullName ?? type.Name);
}
}
///
/// 当 classFullName 通过下拉菜单改变后,自动填充 className / modName / displayName。
/// 被 EquipmentData.cs 中 classFullName 字段上的 [OnValueChanged("OnEquipmentLogicClassSelected")] 触发。
///
private void OnEquipmentLogicClassSelected()
{
if (string.IsNullOrEmpty(classFullName)) return;
// 根据 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);
if (selectedType == null) return;
const string prefix = "Continentis.Mods";
string ns = selectedType.Namespace ?? string.Empty;
if (ns.StartsWith(prefix))
{
// 例: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;
// 移除 "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;
displayName = $"Equipment_{resolvedMod}_{selectedType.Name}_DisplayName";
}
else
{
modName = string.Empty;
className = selectedType.Name;
displayName = $"Equipment_{selectedType.Name}_DisplayName";
}
EditorUtility.SetDirty(this);
Debug.Log($"[EquipmentData] 已自动填充 → modName: {modName}, className: {className}, " +
$"displayName: {displayName}, classFullName: {classFullName}");
}
// ── 2. References 列表的资产名称选择器 ──────────────────────────────────
// 替代旧 DrawCharacterListGUI(prop)
private IEnumerable> GetAvailablePrefabs()
=> GetAssetNameDropdown("t:Prefab");
private IEnumerable> GetAvailableCardData()
=> GetAssetNameDropdown("t:CardData");
private IEnumerable> GetAvailableCharacterData()
=> GetAssetNameDropdown("t:CharacterData");
// ── 内部共享辅助方法 ─────────────────────────────────────────────────
///
/// 通过 AssetDatabase 搜索特定类型/标签的资产,将文件名(无扩展名)作为下拉项返回。
/// 用于 References 列表的字符串引用选择。
///
private static IEnumerable> 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(name, name);
}
}
}
}
#endif