TH1/Unity/Assets/Scripts/TH1_Logic/Editor/WikiDataEditor.cs
2026-06-15 16:00:53 +08:00

767 lines
30 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*
* @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 保证 PropertyFieldHintProvider 子字段)正确工作
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();
}
}