767 lines
30 KiB
C#
767 lines
30 KiB
C#
/*
|
||
* @Author: 白哉
|
||
* @Description: WikiData 自定义编辑器
|
||
* @Date: 2026年04月01日 星期三 11:04:20
|
||
* @Modify:
|
||
*/
|
||
|
||
|
||
using System.Collections.Generic;
|
||
using Logic.Multilingual;
|
||
using TH1_Logic.Config;
|
||
using TH1_Logic.MatchConfig;
|
||
using UI.HintUI;
|
||
using UnityEditor;
|
||
using UnityEngine;
|
||
|
||
|
||
[CustomEditor(typeof(WikiData))]
|
||
public class WikiDataEditor : Editor
|
||
{
|
||
// ── 状态 ─────────────────────────────────────────────────────────────────
|
||
private string _searchText = "";
|
||
private Vector2 _scrollPos;
|
||
private bool _typeInfoFoldout = false;
|
||
private bool _descTypeInfoFoldout = false;
|
||
|
||
// 以 ItemId 为 key,避免增删后 index 偏移导致折叠状态错乱
|
||
private readonly Dictionary<uint, bool> _foldouts = new Dictionary<uint, bool>();
|
||
|
||
private WikiData Target => (WikiData)target;
|
||
|
||
// ── 样式(延迟初始化) ───────────────────────────────────────────────────
|
||
private GUIStyle _itemBoxStyle;
|
||
private GUIStyle _descBoxStyle;
|
||
private GUIStyle _hintBoxStyle;
|
||
private GUIStyle _headerLabelStyle;
|
||
private bool _stylesReady;
|
||
|
||
private void EnsureStyles()
|
||
{
|
||
if (_stylesReady) return;
|
||
_stylesReady = true;
|
||
|
||
_itemBoxStyle = new GUIStyle(GUI.skin.box)
|
||
{
|
||
padding = new RectOffset(10, 10, 6, 8),
|
||
margin = new RectOffset(0, 0, 2, 2),
|
||
};
|
||
|
||
_descBoxStyle = new GUIStyle(EditorStyles.helpBox)
|
||
{
|
||
padding = new RectOffset(8, 8, 6, 6),
|
||
margin = new RectOffset(0, 0, 2, 4),
|
||
};
|
||
|
||
// Hint 子面板:比 descBox 多一层视觉缩进
|
||
_hintBoxStyle = new GUIStyle(EditorStyles.helpBox)
|
||
{
|
||
padding = new RectOffset(10, 8, 6, 6),
|
||
margin = new RectOffset(0, 0, 3, 2),
|
||
};
|
||
|
||
_headerLabelStyle = new GUIStyle(EditorStyles.boldLabel)
|
||
{
|
||
fontSize = 12,
|
||
};
|
||
}
|
||
|
||
// ── 搜索匹配(不区分大小写子串匹配 Name + 所有 GetDesc())──────────────
|
||
private bool Matches(WikiItem item)
|
||
{
|
||
if (string.IsNullOrEmpty(_searchText)) return true;
|
||
var keyword = _searchText.ToLower();
|
||
|
||
if (!string.IsNullOrEmpty(item.Name) && item.Name.ToLower().Contains(keyword))
|
||
return true;
|
||
|
||
foreach (var d in item.DescItems)
|
||
{
|
||
try
|
||
{
|
||
// UseHint 时 GetDesc() 走 HintProvider.GetHintText(),需要运行时单例;
|
||
// 编辑器非运行时会抛异常,catch 后安全跳过
|
||
var text = d.GetDesc();
|
||
if (!string.IsNullOrEmpty(text) && text.ToLower().Contains(keyword))
|
||
return true;
|
||
}
|
||
catch { /* 运行时单例未就绪,忽略 */ }
|
||
}
|
||
|
||
return false;
|
||
}
|
||
|
||
// ── 主入口 ───────────────────────────────────────────────────────────────
|
||
public override void OnInspectorGUI()
|
||
{
|
||
MultilingualManager.Instance.SetMultilingualType(MultilingualType.ZH);
|
||
if (Table.Instance == null) new Table();
|
||
EnsureStyles();
|
||
// Update / ApplyModifiedProperties 保证 PropertyField(HintProvider 子字段)正确工作
|
||
serializedObject.Update();
|
||
|
||
DrawSearchBar();
|
||
EditorGUILayout.Space(6);
|
||
DrawTypeInfoList();
|
||
EditorGUILayout.Space(4);
|
||
DrawDescTypeInfoList();
|
||
EditorGUILayout.Space(8);
|
||
DrawItemList();
|
||
EditorGUILayout.Space(10);
|
||
DrawAddItemButton();
|
||
|
||
serializedObject.ApplyModifiedProperties();
|
||
}
|
||
|
||
// ── WikiTypeInfo 列表 ────────────────────────────────────────────────────
|
||
private void DrawTypeInfoList()
|
||
{
|
||
var list = Target.WikiTypeInfoList;
|
||
|
||
EditorGUILayout.BeginVertical(_itemBoxStyle);
|
||
|
||
EditorGUILayout.BeginHorizontal();
|
||
_typeInfoFoldout = EditorGUILayout.Foldout(
|
||
_typeInfoFoldout,
|
||
$"WikiType 名称表 ({list.Count} 条)",
|
||
true,
|
||
EditorStyles.foldoutHeader);
|
||
GUILayout.FlexibleSpace();
|
||
|
||
var prevBg = GUI.backgroundColor;
|
||
GUI.backgroundColor = new Color(0.48f, 0.85f, 0.48f);
|
||
if (GUILayout.Button("+ 添加", GUILayout.Width(60)))
|
||
{
|
||
Undo.RecordObject(target, "Add WikiTypeInfo");
|
||
list.Add(new WikiTypeInfo { Type = FirstUnusedWikiType(list), Name = "" });
|
||
EditorUtility.SetDirty(target);
|
||
}
|
||
GUI.backgroundColor = prevBg;
|
||
EditorGUILayout.EndHorizontal();
|
||
|
||
if (_typeInfoFoldout)
|
||
{
|
||
EditorGUILayout.Space(3);
|
||
|
||
int removeIdx = -1;
|
||
for (int i = 0; i < list.Count; i++)
|
||
{
|
||
var info = list[i];
|
||
if (info == null)
|
||
{
|
||
list[i] = new WikiTypeInfo();
|
||
info = list[i];
|
||
}
|
||
|
||
EditorGUILayout.BeginHorizontal();
|
||
|
||
var newType = (WikiType)EditorGUILayout.EnumPopup(info.Type, GUILayout.Width(180));
|
||
if (newType != info.Type)
|
||
{
|
||
Undo.RecordObject(target, "Edit WikiTypeInfo Type");
|
||
info.Type = newType;
|
||
EditorUtility.SetDirty(target);
|
||
}
|
||
|
||
var newName = EditorGUILayout.TextField(info.Name ?? "");
|
||
if (newName != info.Name)
|
||
{
|
||
Undo.RecordObject(target, "Edit WikiTypeInfo Name");
|
||
info.Name = newName;
|
||
EditorUtility.SetDirty(target);
|
||
}
|
||
|
||
var delBg = GUI.backgroundColor;
|
||
GUI.backgroundColor = new Color(1f, 0.42f, 0.42f);
|
||
if (GUILayout.Button("x", GUILayout.Width(22))) removeIdx = i;
|
||
GUI.backgroundColor = delBg;
|
||
|
||
EditorGUILayout.EndHorizontal();
|
||
}
|
||
|
||
if (removeIdx >= 0)
|
||
{
|
||
Undo.RecordObject(target, "Remove WikiTypeInfo");
|
||
list.RemoveAt(removeIdx);
|
||
EditorUtility.SetDirty(target);
|
||
}
|
||
|
||
if (list.Count == 0)
|
||
{
|
||
EditorGUILayout.HelpBox("尚未配置任何 WikiType 名称。", MessageType.Info);
|
||
}
|
||
}
|
||
|
||
EditorGUILayout.EndVertical();
|
||
}
|
||
|
||
private static WikiType FirstUnusedWikiType(List<WikiTypeInfo> list)
|
||
{
|
||
foreach (WikiType t in (WikiType[])System.Enum.GetValues(typeof(WikiType)))
|
||
{
|
||
bool used = false;
|
||
for (int i = 0; i < list.Count; i++)
|
||
if (list[i] != null && list[i].Type == t) { used = true; break; }
|
||
if (!used) return t;
|
||
}
|
||
return default;
|
||
}
|
||
|
||
// ── WikiDescTypeInfo 列表 ────────────────────────────────────────────────
|
||
private void DrawDescTypeInfoList()
|
||
{
|
||
var list = Target.WikiDescTypeInfoList;
|
||
|
||
EditorGUILayout.BeginVertical(_itemBoxStyle);
|
||
|
||
EditorGUILayout.BeginHorizontal();
|
||
_descTypeInfoFoldout = EditorGUILayout.Foldout(
|
||
_descTypeInfoFoldout,
|
||
$"WikiDescType 名称表 ({list.Count} 条)",
|
||
true,
|
||
EditorStyles.foldoutHeader);
|
||
GUILayout.FlexibleSpace();
|
||
|
||
var prevBg = GUI.backgroundColor;
|
||
GUI.backgroundColor = new Color(0.48f, 0.85f, 0.48f);
|
||
if (GUILayout.Button("+ 添加", GUILayout.Width(60)))
|
||
{
|
||
Undo.RecordObject(target, "Add WikiDescTypeInfo");
|
||
list.Add(new WikiDescTypeInfo { Type = FirstUnusedWikiDescType(list), Name = "" });
|
||
EditorUtility.SetDirty(target);
|
||
}
|
||
GUI.backgroundColor = prevBg;
|
||
EditorGUILayout.EndHorizontal();
|
||
|
||
if (_descTypeInfoFoldout)
|
||
{
|
||
EditorGUILayout.Space(3);
|
||
|
||
int removeIdx = -1;
|
||
for (int i = 0; i < list.Count; i++)
|
||
{
|
||
var info = list[i];
|
||
if (info == null)
|
||
{
|
||
list[i] = new WikiDescTypeInfo();
|
||
info = list[i];
|
||
}
|
||
|
||
EditorGUILayout.BeginHorizontal();
|
||
|
||
var newType = (WikiDescType)EditorGUILayout.EnumPopup(info.Type, GUILayout.Width(180));
|
||
if (newType != info.Type)
|
||
{
|
||
Undo.RecordObject(target, "Edit WikiDescTypeInfo Type");
|
||
info.Type = newType;
|
||
EditorUtility.SetDirty(target);
|
||
}
|
||
|
||
var newName = EditorGUILayout.TextField(info.Name ?? "");
|
||
if (newName != info.Name)
|
||
{
|
||
Undo.RecordObject(target, "Edit WikiDescTypeInfo Name");
|
||
info.Name = newName;
|
||
EditorUtility.SetDirty(target);
|
||
}
|
||
|
||
var delBg = GUI.backgroundColor;
|
||
GUI.backgroundColor = new Color(1f, 0.42f, 0.42f);
|
||
if (GUILayout.Button("x", GUILayout.Width(22))) removeIdx = i;
|
||
GUI.backgroundColor = delBg;
|
||
|
||
EditorGUILayout.EndHorizontal();
|
||
}
|
||
|
||
if (removeIdx >= 0)
|
||
{
|
||
Undo.RecordObject(target, "Remove WikiDescTypeInfo");
|
||
list.RemoveAt(removeIdx);
|
||
EditorUtility.SetDirty(target);
|
||
}
|
||
|
||
if (list.Count == 0)
|
||
{
|
||
EditorGUILayout.HelpBox("尚未配置任何 WikiDescType 名称。", MessageType.Info);
|
||
}
|
||
}
|
||
|
||
EditorGUILayout.EndVertical();
|
||
}
|
||
|
||
private static WikiDescType FirstUnusedWikiDescType(List<WikiDescTypeInfo> list)
|
||
{
|
||
foreach (WikiDescType t in (WikiDescType[])System.Enum.GetValues(typeof(WikiDescType)))
|
||
{
|
||
bool used = false;
|
||
for (int i = 0; i < list.Count; i++)
|
||
if (list[i] != null && list[i].Type == t) { used = true; break; }
|
||
if (!used) return t;
|
||
}
|
||
return default;
|
||
}
|
||
|
||
// ── 搜索栏 ───────────────────────────────────────────────────────────────
|
||
private void DrawSearchBar()
|
||
{
|
||
EditorGUILayout.BeginHorizontal(EditorStyles.toolbar);
|
||
EditorGUILayout.LabelField("搜索", GUILayout.Width(36));
|
||
|
||
GUI.SetNextControlName("SearchField");
|
||
var newText = EditorGUILayout.TextField(_searchText, EditorStyles.toolbarSearchField);
|
||
if (newText != _searchText) _searchText = newText;
|
||
|
||
GUI.enabled = !string.IsNullOrEmpty(_searchText);
|
||
if (GUILayout.Button("清空", EditorStyles.toolbarButton, GUILayout.Width(42)))
|
||
{
|
||
_searchText = "";
|
||
GUI.FocusControl(null);
|
||
}
|
||
GUI.enabled = true;
|
||
|
||
EditorGUILayout.EndHorizontal();
|
||
}
|
||
|
||
// ── 词条列表 ─────────────────────────────────────────────────────────────
|
||
private void DrawItemList()
|
||
{
|
||
var items = Target.Items;
|
||
int total = items.Count;
|
||
int matched = 0;
|
||
foreach (var item in items)
|
||
if (Matches(item)) matched++;
|
||
|
||
string titleText = string.IsNullOrEmpty(_searchText)
|
||
? $"词条列表 ({total} 条)"
|
||
: $"词条列表 (匹配 {matched} / 共 {total} 条)";
|
||
EditorGUILayout.LabelField(titleText, _headerLabelStyle);
|
||
|
||
var line = EditorGUILayout.GetControlRect(false, 1f);
|
||
EditorGUI.DrawRect(line, new Color(0.45f, 0.45f, 0.45f, 0.6f));
|
||
EditorGUILayout.Space(4);
|
||
|
||
_scrollPos = EditorGUILayout.BeginScrollView(_scrollPos, GUILayout.MaxHeight(520f));
|
||
|
||
int deleteIndex = -1;
|
||
for (int i = 0; i < items.Count; i++)
|
||
{
|
||
if (!Matches(items[i])) continue;
|
||
if (DrawItem(items[i], i)) // i = 在 Items 列表中的真实下标
|
||
deleteIndex = i;
|
||
EditorGUILayout.Space(3);
|
||
}
|
||
|
||
if (total == 0 || (matched == 0 && !string.IsNullOrEmpty(_searchText)))
|
||
{
|
||
EditorGUILayout.HelpBox(
|
||
matched == 0 && !string.IsNullOrEmpty(_searchText)
|
||
? "没有找到匹配的词条。"
|
||
: "暂无词条,点击下方按钮添加。",
|
||
MessageType.Info);
|
||
}
|
||
|
||
EditorGUILayout.EndScrollView();
|
||
|
||
if (deleteIndex >= 0)
|
||
{
|
||
Undo.RecordObject(target, "Delete Wiki Item");
|
||
Target.Items.RemoveAt(deleteIndex);
|
||
EditorUtility.SetDirty(target);
|
||
}
|
||
}
|
||
|
||
// ── 单条词条 ─────────────────────────────────────────────────────────────
|
||
/// <returns>true = 需要删除</returns>
|
||
private bool DrawItem(WikiItem item, int listIndex)
|
||
{
|
||
if (!_foldouts.ContainsKey(item.Id))
|
||
_foldouts[item.Id] = false;
|
||
|
||
bool doDelete = false;
|
||
|
||
EditorGUILayout.BeginVertical(_itemBoxStyle);
|
||
|
||
// —— 标题行 ——
|
||
EditorGUILayout.BeginHorizontal();
|
||
|
||
string displayName = string.IsNullOrEmpty(item.Name)
|
||
? $"<未命名> [id:{item.Id}]"
|
||
: $"{item.Name} [id:{item.Id}]";
|
||
|
||
_foldouts[item.Id] = EditorGUILayout.Foldout(
|
||
_foldouts[item.Id], displayName, true, EditorStyles.foldoutHeader);
|
||
|
||
GUILayout.FlexibleSpace();
|
||
|
||
var prevBg = GUI.backgroundColor;
|
||
GUI.backgroundColor = new Color(1f, 0.42f, 0.42f);
|
||
if (GUILayout.Button("删 除", GUILayout.Width(54)))
|
||
{
|
||
if (EditorUtility.DisplayDialog(
|
||
"确认删除",
|
||
$"确定要删除词条「{displayName}」吗?此操作不可撤销。",
|
||
"删除", "取消"))
|
||
doDelete = true;
|
||
}
|
||
GUI.backgroundColor = prevBg;
|
||
|
||
EditorGUILayout.EndHorizontal();
|
||
|
||
// —— 折叠内容 ——
|
||
if (_foldouts[item.Id])
|
||
{
|
||
EditorGUILayout.Space(4);
|
||
DrawItemName(item);
|
||
EditorGUILayout.Space(3);
|
||
DrawItemTypes(item);
|
||
EditorGUILayout.Space(3);
|
||
DrawItemDescs(item, listIndex);
|
||
}
|
||
|
||
EditorGUILayout.EndVertical();
|
||
return doDelete;
|
||
}
|
||
|
||
// ── 名称字段 ─────────────────────────────────────────────────────────────
|
||
private void DrawItemName(WikiItem item)
|
||
{
|
||
EditorGUILayout.BeginHorizontal();
|
||
EditorGUILayout.LabelField("名 称", GUILayout.Width(40));
|
||
var newName = EditorGUILayout.TextField(item.Name ?? "");
|
||
if (newName != item.Name)
|
||
{
|
||
Undo.RecordObject(target, "Edit Wiki Item Name");
|
||
item.Name = newName;
|
||
EditorUtility.SetDirty(target);
|
||
}
|
||
EditorGUILayout.EndHorizontal();
|
||
}
|
||
|
||
// ── 类型列表 ─────────────────────────────────────────────────────────────
|
||
private void DrawItemTypes(WikiItem item)
|
||
{
|
||
EditorGUILayout.BeginHorizontal();
|
||
EditorGUILayout.LabelField("类 型", GUILayout.Width(40));
|
||
|
||
int removeIdx = -1;
|
||
for (int i = 0; i < item.Types.Count; i++)
|
||
{
|
||
var newType = (WikiType)EditorGUILayout.EnumPopup(item.Types[i], GUILayout.Width(90));
|
||
if (newType != item.Types[i])
|
||
{
|
||
bool duplicate = false;
|
||
for (int j = 0; j < item.Types.Count; j++)
|
||
if (j != i && item.Types[j] == newType) { duplicate = true; break; }
|
||
|
||
if (!duplicate)
|
||
{
|
||
Undo.RecordObject(target, "Edit Wiki Item Type");
|
||
item.Types[i] = newType;
|
||
EditorUtility.SetDirty(target);
|
||
}
|
||
}
|
||
|
||
var prevBg = GUI.backgroundColor;
|
||
GUI.backgroundColor = new Color(1f, 0.42f, 0.42f);
|
||
if (GUILayout.Button("x", GUILayout.Width(22))) removeIdx = i;
|
||
GUI.backgroundColor = prevBg;
|
||
|
||
GUILayout.Space(2);
|
||
}
|
||
|
||
var firstUnused = FirstUnusedType(item);
|
||
GUI.enabled = firstUnused.HasValue;
|
||
var addBg = GUI.backgroundColor;
|
||
GUI.backgroundColor = firstUnused.HasValue ? new Color(0.48f, 0.85f, 0.48f) : Color.gray;
|
||
if (GUILayout.Button("+ 添加", GUILayout.Width(60)) && firstUnused.HasValue)
|
||
{
|
||
Undo.RecordObject(target, "Add Wiki Item Type");
|
||
item.Types.Add(firstUnused.Value);
|
||
EditorUtility.SetDirty(target);
|
||
}
|
||
GUI.backgroundColor = addBg;
|
||
GUI.enabled = true;
|
||
|
||
EditorGUILayout.EndHorizontal();
|
||
|
||
if (removeIdx >= 0)
|
||
{
|
||
Undo.RecordObject(target, "Remove Wiki Item Type");
|
||
item.Types.RemoveAt(removeIdx);
|
||
EditorUtility.SetDirty(target);
|
||
}
|
||
}
|
||
|
||
// ── 描述列表 ─────────────────────────────────────────────────────────────
|
||
private void DrawItemDescs(WikiItem item, int listIndex)
|
||
{
|
||
EditorGUILayout.LabelField("描 述", EditorStyles.boldLabel);
|
||
|
||
// 预先导航到此 item 的 DescItems 数组属性,HintProvider 子字段绘制时需要
|
||
var descItemsArrayProp = serializedObject
|
||
.FindProperty("Items")
|
||
.GetArrayElementAtIndex(listIndex)
|
||
.FindPropertyRelative("DescItems");
|
||
|
||
int removeIdx = -1;
|
||
for (int i = 0; i < item.DescItems.Count; i++)
|
||
{
|
||
var desc = item.DescItems[i];
|
||
EditorGUILayout.BeginVertical(_descBoxStyle);
|
||
|
||
// —— 头部行:DescType | 模式切换 | 删除 ——
|
||
EditorGUILayout.BeginHorizontal();
|
||
|
||
// DescType(去重校验)
|
||
var newDescType = (WikiDescType)EditorGUILayout.EnumPopup(desc.DescType, GUILayout.Width(110));
|
||
if (newDescType != desc.DescType)
|
||
{
|
||
bool duplicate = false;
|
||
for (int j = 0; j < item.DescItems.Count; j++)
|
||
if (j != i && item.DescItems[j].DescType == newDescType) { duplicate = true; break; }
|
||
if (!duplicate)
|
||
{
|
||
Undo.RecordObject(target, "Edit Desc Type");
|
||
desc.DescType = newDescType;
|
||
EditorUtility.SetDirty(target);
|
||
}
|
||
}
|
||
|
||
GUILayout.Space(6);
|
||
|
||
// 模式切换按钮
|
||
var modeBg = GUI.backgroundColor;
|
||
GUI.backgroundColor = desc.UseHint
|
||
? new Color(1f, 0.82f, 0.28f) // 黄:Hint 模式
|
||
: new Color(0.55f, 0.85f, 1f); // 蓝:文本模式
|
||
if (GUILayout.Button(desc.UseHint ? "Hint 模式" : "文本模式", GUILayout.Width(76)))
|
||
{
|
||
Undo.RecordObject(target, "Toggle Desc UseHint");
|
||
desc.UseHint = !desc.UseHint;
|
||
// 切换到 Hint 时确保 HintProvider 已初始化
|
||
if (desc.UseHint && desc.HintProvider == null)
|
||
desc.HintProvider = new HintDataProvider();
|
||
EditorUtility.SetDirty(target);
|
||
}
|
||
GUI.backgroundColor = modeBg;
|
||
|
||
GUILayout.FlexibleSpace();
|
||
|
||
var prevBg = GUI.backgroundColor;
|
||
GUI.backgroundColor = new Color(1f, 0.42f, 0.42f);
|
||
if (GUILayout.Button("删除", GUILayout.Width(50))) removeIdx = i;
|
||
GUI.backgroundColor = prevBg;
|
||
|
||
EditorGUILayout.EndHorizontal();
|
||
|
||
EditorGUILayout.Space(3);
|
||
|
||
if (desc.UseHint)
|
||
{
|
||
// ── Hint 模式:绘制 HintDataProvider ──
|
||
if (desc.HintProvider == null)
|
||
{
|
||
Undo.RecordObject(target, "Init HintProvider");
|
||
desc.HintProvider = new HintDataProvider();
|
||
EditorUtility.SetDirty(target);
|
||
}
|
||
|
||
var hintProp = descItemsArrayProp
|
||
.GetArrayElementAtIndex(i)
|
||
.FindPropertyRelative("HintProvider");
|
||
|
||
DrawHintProvider(desc.HintProvider, hintProp);
|
||
|
||
// 只读预览:显示 GetDesc() 的实际输出
|
||
// 非运行时单例未就绪时会抛异常,显示占位文字
|
||
EditorGUILayout.Space(2);
|
||
EditorGUILayout.LabelField("GetDesc() 预览(运行时)", EditorStyles.centeredGreyMiniLabel);
|
||
string preview;
|
||
try { preview = desc.GetDesc(); }
|
||
catch { preview = "(仅运行时可预览,当前单例未就绪)"; }
|
||
GUI.enabled = false;
|
||
EditorGUILayout.TextArea(preview, GUILayout.MinHeight(40), GUILayout.ExpandWidth(true));
|
||
GUI.enabled = true;
|
||
}
|
||
else
|
||
{
|
||
// ── 文本模式:直接编辑 Desc 字符串 ──
|
||
var newDesc = EditorGUILayout.TextArea(
|
||
desc.Desc ?? "",
|
||
GUILayout.MinHeight(54),
|
||
GUILayout.ExpandWidth(true));
|
||
if (newDesc != desc.Desc)
|
||
{
|
||
Undo.RecordObject(target, "Edit Desc Text");
|
||
desc.Desc = newDesc;
|
||
EditorUtility.SetDirty(target);
|
||
}
|
||
}
|
||
|
||
EditorGUILayout.EndVertical();
|
||
}
|
||
|
||
if (removeIdx >= 0)
|
||
{
|
||
Undo.RecordObject(target, "Remove Desc Item");
|
||
item.DescItems.RemoveAt(removeIdx);
|
||
EditorUtility.SetDirty(target);
|
||
}
|
||
|
||
// 添加描述按钮
|
||
var firstUnusedDesc = FirstUnusedDescType(item);
|
||
EditorGUILayout.BeginHorizontal();
|
||
GUILayout.FlexibleSpace();
|
||
GUI.enabled = firstUnusedDesc.HasValue;
|
||
var addBg = GUI.backgroundColor;
|
||
GUI.backgroundColor = firstUnusedDesc.HasValue ? new Color(0.48f, 0.85f, 0.48f) : Color.gray;
|
||
if (GUILayout.Button("+ 添加描述", GUILayout.Width(100)) && firstUnusedDesc.HasValue)
|
||
{
|
||
Undo.RecordObject(target, "Add Desc Item");
|
||
item.DescItems.Add(new DescItem { DescType = firstUnusedDesc.Value });
|
||
EditorUtility.SetDirty(target);
|
||
}
|
||
GUI.backgroundColor = addBg;
|
||
GUI.enabled = true;
|
||
EditorGUILayout.EndHorizontal();
|
||
}
|
||
|
||
// ── HintDataProvider 编辑器 ───────────────────────────────────────────────
|
||
// 简单字段(枚举 / string / bool)直接操作 provider 对象;
|
||
// 复合类型(UnitFullType、CommonActionId、SkillBase、List<uint>)内部结构未知,保留 PropertyField。
|
||
private void DrawHintProvider(HintDataProvider provider, SerializedProperty hintProp)
|
||
{
|
||
EditorGUILayout.BeginVertical(_hintBoxStyle);
|
||
|
||
// —— HintDataType ——
|
||
var newHintType = (HintDataType)EditorGUILayout.EnumPopup("Hint 类型", provider.HintDataType);
|
||
if (newHintType != provider.HintDataType)
|
||
{
|
||
Undo.RecordObject(target, "Edit HintDataType");
|
||
provider.HintDataType = newHintType;
|
||
EditorUtility.SetDirty(target);
|
||
}
|
||
|
||
EditorGUILayout.Space(3);
|
||
|
||
switch (provider.HintDataType)
|
||
{
|
||
// SkillDataAssets.GetSkillNameAndDesc_DECODE(SkillTypeData, UnitFullType, SkillParam, ...)
|
||
case HintDataType.SkillHintData:
|
||
{
|
||
var v = (SkillType)EditorGUILayout.EnumPopup("技能类型", provider.SkillTypeData);
|
||
if (v != provider.SkillTypeData) { Undo.RecordObject(target, "Edit SkillTypeData"); provider.SkillTypeData = v; EditorUtility.SetDirty(target); }
|
||
EditorGUILayout.PropertyField(hintProp.FindPropertyRelative("UnitFullType"), new GUIContent("单位类型"));
|
||
break;
|
||
}
|
||
|
||
// ActionDataAssets.GetActionDesc(ActionIdData, locked, out ret)
|
||
case HintDataType.ActionHintData:
|
||
{
|
||
EditorGUILayout.PropertyField(hintProp.FindPropertyRelative("ActionIdData"), new GUIContent("行动 ID"));
|
||
var v = EditorGUILayout.Toggle("锁定", provider.locked);
|
||
if (v != provider.locked) { Undo.RecordObject(target, "Edit locked"); provider.locked = v; EditorUtility.SetDirty(target); }
|
||
break;
|
||
}
|
||
|
||
// TechDataAssets.GetTechDesc(TechTypeData, out ret)
|
||
case HintDataType.TechHintData:
|
||
{
|
||
var v = (TechType)EditorGUILayout.EnumPopup("科技类型", provider.TechTypeData);
|
||
if (v != provider.TechTypeData) { Undo.RecordObject(target, "Edit TechTypeData"); provider.TechTypeData = v; EditorUtility.SetDirty(target); }
|
||
break;
|
||
}
|
||
|
||
// 未实现,留空
|
||
case HintDataType.CityUpgradeHintData:
|
||
EditorGUILayout.HelpBox("CityUpgrade 类型暂未实现。", MessageType.Info);
|
||
break;
|
||
|
||
// UnitTypeDataAssets.GetUnitDesc(UnitFullType, out ret)
|
||
case HintDataType.UnitHintData:
|
||
EditorGUILayout.PropertyField(hintProp.FindPropertyRelative("UnitFullType"), new GUIContent("单位类型"));
|
||
break;
|
||
|
||
// TextDataAssets.GetGiantUpgradeText_DECODE(UnitFullType.GiantType, out ret)
|
||
case HintDataType.TextDataGiantUpgrate:
|
||
EditorGUILayout.PropertyField(hintProp.FindPropertyRelative("UnitFullType"), new GUIContent("单位类型(取 GiantType)"));
|
||
break;
|
||
|
||
// TechDataAssets.GetTechAtomInfo(TechAtom, out info)
|
||
case HintDataType.TechAtomHintData:
|
||
EditorGUILayout.PropertyField(hintProp.FindPropertyRelative("TechAtom"), new GUIContent("科技"));
|
||
break;
|
||
|
||
// TextData.PlayerActionType == FinishHeroTask → 特殊逻辑;否则直接用 Text 静态文本
|
||
case HintDataType.TextData:
|
||
{
|
||
EditorGUILayout.PropertyField(hintProp.FindPropertyRelative("TextData"),
|
||
new GUIContent("行动 ID", "PlayerActionType == FinishHeroTask 时走特殊逻辑"));
|
||
var v = EditorGUILayout.TextArea(provider.Text ?? "", GUILayout.MinHeight(40));
|
||
if (v != provider.Text) { Undo.RecordObject(target, "Edit HintProvider Text"); provider.Text = v; EditorUtility.SetDirty(target); }
|
||
EditorGUILayout.LabelField("↑ 静态文本(其余情况显示,已为 DECODE 格式)", EditorStyles.centeredGreyMiniLabel);
|
||
break;
|
||
}
|
||
|
||
// 遍历 GeoIdList,逐条拼接地理名称 + 描述
|
||
case HintDataType.GeoData:
|
||
EditorGUILayout.PropertyField(hintProp.FindPropertyRelative("GeoIdList"),
|
||
new GUIContent("地理 ID 列表"), true);
|
||
break;
|
||
|
||
// PlayerTaskDataAssets.GetPlayerTaskData(PlayerTaskType, out data)
|
||
case HintDataType.PlayerTaskData:
|
||
{
|
||
var v = (PlayerTaskType)EditorGUILayout.EnumPopup("玩家任务类型", provider.PlayerTaskType);
|
||
if (v != provider.PlayerTaskType) { Undo.RecordObject(target, "Edit PlayerTaskType"); provider.PlayerTaskType = v; EditorUtility.SetDirty(target); }
|
||
break;
|
||
}
|
||
}
|
||
|
||
EditorGUILayout.EndVertical();
|
||
}
|
||
|
||
// ── 辅助:首个未使用的 WikiType,全部用完则返回 null ────────────────────
|
||
private static WikiType? FirstUnusedType(WikiItem item)
|
||
{
|
||
foreach (WikiType t in (WikiType[])System.Enum.GetValues(typeof(WikiType)))
|
||
if (!item.Types.Contains(t)) return t;
|
||
return null;
|
||
}
|
||
|
||
// ── 辅助:首个未使用的 WikiDescType,全部用完则返回 null ────────────────
|
||
private static WikiDescType? FirstUnusedDescType(WikiItem item)
|
||
{
|
||
foreach (WikiDescType dt in (WikiDescType[])System.Enum.GetValues(typeof(WikiDescType)))
|
||
{
|
||
bool used = false;
|
||
foreach (var d in item.DescItems)
|
||
if (d.DescType == dt) { used = true; break; }
|
||
if (!used) return dt;
|
||
}
|
||
return null;
|
||
}
|
||
|
||
// ── 底部添加词条按钮 ─────────────────────────────────────────────────────
|
||
private void DrawAddItemButton()
|
||
{
|
||
EditorGUILayout.BeginHorizontal();
|
||
GUILayout.FlexibleSpace();
|
||
|
||
var prevBg = GUI.backgroundColor;
|
||
GUI.backgroundColor = new Color(0.38f, 0.72f, 1f);
|
||
if (GUILayout.Button("+ 添加词条", GUILayout.Height(30), GUILayout.Width(150)))
|
||
{
|
||
Undo.RecordObject(target, "Add Wiki Item");
|
||
Target.AddWikiItem("新词条");
|
||
var newest = Target.Items[^1];
|
||
_foldouts[newest.Id] = true;
|
||
EditorUtility.SetDirty(target);
|
||
}
|
||
GUI.backgroundColor = prevBg;
|
||
|
||
GUILayout.FlexibleSpace();
|
||
EditorGUILayout.EndHorizontal();
|
||
}
|
||
}
|