| New file |
| | |
| | | using System.Collections.Generic; |
| | | using System.Linq; |
| | | using System.Reflection; |
| | | using UnityEditor; |
| | | using UnityEngine; |
| | | |
| | | /// <summary> |
| | | /// 战斗网络包查看器 |
| | | /// 用于查看和搜索 DTCB430_tagSCTurnFightReport 解析的战斗包 |
| | | /// 快捷键:Alt+8 |
| | | /// </summary> |
| | | public class BattleReportChecker : EditorWindow |
| | | { |
| | | #region 静态数据存储 |
| | | |
| | | // 存储所有战斗包数据,按 guid 组织 |
| | | private static Dictionary<string, List<PackageInfo>> allBattlePackages = new Dictionary<string, List<PackageInfo>>(); |
| | | |
| | | // 跟踪已执行的包UID(按 guid 组织) |
| | | private static Dictionary<string, HashSet<ulong>> executedPackUIDs = new Dictionary<string, HashSet<ulong>>(); |
| | | |
| | | // 跟踪当前正在执行的包UID(按 guid 组织) |
| | | private static Dictionary<string, ulong> currentExecutingPackUID = new Dictionary<string, ulong>(); |
| | | |
| | | // 包信息类 |
| | | public class PackageInfo |
| | | { |
| | | public GameNetPackBasic package; |
| | | public string displayName; |
| | | public ulong packUID; |
| | | public string typeName; |
| | | public bool isExpanded; |
| | | public Dictionary<string, string> fields = new Dictionary<string, string>(); |
| | | public Dictionary<string, FieldDetail> fieldDetails = new Dictionary<string, FieldDetail>(); |
| | | |
| | | public PackageInfo(GameNetPackBasic pack) |
| | | { |
| | | package = pack; |
| | | packUID = pack.packUID; |
| | | typeName = pack.GetType().Name; |
| | | displayName = $"[{packUID}] {typeName}"; |
| | | isExpanded = false; |
| | | ExtractFields(); |
| | | } |
| | | |
| | | private void ExtractFields() |
| | | { |
| | | if (package == null) return; |
| | | |
| | | var type = package.GetType(); |
| | | var fieldInfos = type.GetFields(BindingFlags.Public | BindingFlags.Instance); |
| | | |
| | | foreach (var field in fieldInfos) |
| | | { |
| | | try |
| | | { |
| | | var value = field.GetValue(package); |
| | | string valueStr = value != null ? value.ToString() : "null"; |
| | | |
| | | var detail = new FieldDetail { value = value }; |
| | | |
| | | // 特殊处理数组(注意:先判断Array,因为Array不是IList的子类) |
| | | if (value != null && value.GetType().IsArray) |
| | | { |
| | | System.Array array = value as System.Array; |
| | | valueStr = $"Array[{array.Length}]"; |
| | | detail.isArray = true; |
| | | detail.arrayValue = array; |
| | | } |
| | | // 特殊处理列表(IList包括List<T>和其他列表类型) |
| | | else if (value is System.Collections.IList list && !(value is string)) |
| | | { |
| | | valueStr = $"List[{list.Count}]"; |
| | | detail.isList = true; |
| | | detail.listValue = list; |
| | | } |
| | | |
| | | fields[field.Name] = valueStr; |
| | | fieldDetails[field.Name] = detail; |
| | | } |
| | | catch (System.Exception ex) |
| | | { |
| | | fields[field.Name] = "读取失败: " + ex.Message; |
| | | fieldDetails[field.Name] = new FieldDetail { value = null }; |
| | | } |
| | | } |
| | | } |
| | | } |
| | | |
| | | // 字段详细信息类 |
| | | public class FieldDetail |
| | | { |
| | | public object value; |
| | | public bool isArray; |
| | | public bool isList; |
| | | public bool isExpanded; |
| | | public System.Array arrayValue; |
| | | public System.Collections.IList listValue; |
| | | |
| | | // 嵌套的子字段详情(用于复杂类型) |
| | | public Dictionary<string, FieldDetail> subFieldDetails = new Dictionary<string, FieldDetail>(); |
| | | |
| | | // 数组/列表元素的展开状态 |
| | | public Dictionary<int, ElementDetail> elementDetails = new Dictionary<int, ElementDetail>(); |
| | | } |
| | | |
| | | // 数组/列表元素详细信息类 |
| | | public class ElementDetail |
| | | { |
| | | public bool isExpanded; |
| | | public Dictionary<string, FieldDetail> fieldDetails = new Dictionary<string, FieldDetail>(); |
| | | } |
| | | |
| | | /// <summary> |
| | | /// 供外部调用,添加解析后的包 |
| | | /// </summary> |
| | | public static void AddBattlePackages(string guid, List<GameNetPackBasic> packages) |
| | | { |
| | | if (packages == null || packages.Count == 0) return; |
| | | |
| | | var packInfoList = packages.Select(p => new PackageInfo(p)).ToList(); |
| | | |
| | | if (allBattlePackages.ContainsKey(guid)) |
| | | { |
| | | allBattlePackages[guid].AddRange(packInfoList); |
| | | } |
| | | else |
| | | { |
| | | allBattlePackages[guid] = packInfoList; |
| | | } |
| | | |
| | | Debug.Log($"[BattleReportChecker] 已记录 {packages.Count} 个包,GUID: {guid}"); |
| | | } |
| | | |
| | | /// <summary> |
| | | /// 清空所有记录 |
| | | /// </summary> |
| | | public static void ClearAllPackages() |
| | | { |
| | | allBattlePackages.Clear(); |
| | | executedPackUIDs.Clear(); |
| | | currentExecutingPackUID.Clear(); |
| | | Debug.Log("[BattleReportChecker] 已清空所有包记录"); |
| | | } |
| | | |
| | | /// <summary> |
| | | /// 标记包开始执行 |
| | | /// </summary> |
| | | public static void MarkPackageExecuting(string guid, ulong packUID) |
| | | { |
| | | if (!currentExecutingPackUID.ContainsKey(guid)) |
| | | { |
| | | currentExecutingPackUID[guid] = packUID; |
| | | } |
| | | else |
| | | { |
| | | currentExecutingPackUID[guid] = packUID; |
| | | } |
| | | } |
| | | |
| | | /// <summary> |
| | | /// 标记包执行完成 |
| | | /// </summary> |
| | | public static void MarkPackageExecuted(string guid, ulong packUID) |
| | | { |
| | | if (!executedPackUIDs.ContainsKey(guid)) |
| | | { |
| | | executedPackUIDs[guid] = new HashSet<ulong>(); |
| | | } |
| | | executedPackUIDs[guid].Add(packUID); |
| | | |
| | | // 清除当前执行标记 |
| | | if (currentExecutingPackUID.ContainsKey(guid) && currentExecutingPackUID[guid] == packUID) |
| | | { |
| | | currentExecutingPackUID.Remove(guid); |
| | | } |
| | | } |
| | | |
| | | #endregion |
| | | |
| | | #region 窗口管理 |
| | | |
| | | [MenuItem("程序/战斗网络包查看器 &8")] // Alt+8 |
| | | public static void ShowWindow() |
| | | { |
| | | var window = GetWindow<BattleReportChecker>("战斗包查看器"); |
| | | window.minSize = new Vector2(600, 400); |
| | | window.Show(); |
| | | } |
| | | |
| | | #endregion |
| | | |
| | | #region UI 状态 |
| | | |
| | | private Vector2 scrollPosition; |
| | | private Vector2 detailScrollPosition; |
| | | private string searchText = ""; |
| | | private string selectedGuid = ""; |
| | | private List<string> guidList = new List<string>(); |
| | | private int selectedGuidIndex = 0; |
| | | private List<PackageInfo> filteredPackages = new List<PackageInfo>(); |
| | | private PackageInfo selectedPackage = null; |
| | | |
| | | #endregion |
| | | |
| | | #region Unity 生命周期 |
| | | |
| | | private void OnEnable() |
| | | { |
| | | RefreshGuidList(); |
| | | // 启用编辑器更新,让颜色实时刷新 |
| | | EditorApplication.update += OnEditorUpdate; |
| | | } |
| | | |
| | | private void OnDisable() |
| | | { |
| | | // 移除更新回调 |
| | | EditorApplication.update -= OnEditorUpdate; |
| | | } |
| | | |
| | | private void OnEditorUpdate() |
| | | { |
| | | // 定期刷新UI以更新包的执行状态颜色 |
| | | Repaint(); |
| | | } |
| | | |
| | | private void OnGUI() |
| | | { |
| | | EditorGUILayout.BeginVertical(); |
| | | |
| | | DrawToolbar(); |
| | | DrawGuidSelector(); |
| | | DrawSearchBar(); |
| | | |
| | | EditorGUILayout.BeginHorizontal(); |
| | | DrawPackageList(); |
| | | DrawPackageDetails(); |
| | | EditorGUILayout.EndHorizontal(); |
| | | |
| | | EditorGUILayout.EndVertical(); |
| | | } |
| | | |
| | | #endregion |
| | | |
| | | #region UI 绘制 |
| | | |
| | | private void DrawToolbar() |
| | | { |
| | | EditorGUILayout.BeginHorizontal(EditorStyles.toolbar); |
| | | |
| | | if (GUILayout.Button("刷新", EditorStyles.toolbarButton, GUILayout.Width(60))) |
| | | { |
| | | RefreshGuidList(); |
| | | FilterPackages(); |
| | | } |
| | | |
| | | if (GUILayout.Button("清空所有", EditorStyles.toolbarButton, GUILayout.Width(80))) |
| | | { |
| | | if (EditorUtility.DisplayDialog("确认", "确定要清空所有包记录吗?", "确定", "取消")) |
| | | { |
| | | ClearAllPackages(); |
| | | RefreshGuidList(); |
| | | FilterPackages(); |
| | | } |
| | | } |
| | | |
| | | GUILayout.FlexibleSpace(); |
| | | |
| | | GUILayout.Label($"总包数: {filteredPackages.Count}", EditorStyles.toolbarButton); |
| | | |
| | | EditorGUILayout.EndHorizontal(); |
| | | } |
| | | |
| | | private void DrawGuidSelector() |
| | | { |
| | | EditorGUILayout.BeginHorizontal(); |
| | | |
| | | GUILayout.Label("战场GUID:", GUILayout.Width(80)); |
| | | |
| | | if (guidList.Count == 0) |
| | | { |
| | | GUILayout.Label("暂无数据", EditorStyles.helpBox); |
| | | } |
| | | else |
| | | { |
| | | int newIndex = EditorGUILayout.Popup(selectedGuidIndex, guidList.ToArray()); |
| | | if (newIndex != selectedGuidIndex) |
| | | { |
| | | selectedGuidIndex = newIndex; |
| | | selectedGuid = guidList[selectedGuidIndex]; |
| | | FilterPackages(); |
| | | } |
| | | } |
| | | |
| | | EditorGUILayout.EndHorizontal(); |
| | | EditorGUILayout.Space(5); |
| | | } |
| | | |
| | | private void DrawSearchBar() |
| | | { |
| | | EditorGUILayout.BeginHorizontal(); |
| | | |
| | | GUILayout.Label("搜索:", GUILayout.Width(80)); |
| | | |
| | | string newSearchText = EditorGUILayout.TextField(searchText); |
| | | if (newSearchText != searchText) |
| | | { |
| | | searchText = newSearchText; |
| | | FilterPackages(); |
| | | } |
| | | |
| | | if (GUILayout.Button("清空", GUILayout.Width(60))) |
| | | { |
| | | searchText = ""; |
| | | FilterPackages(); |
| | | } |
| | | |
| | | EditorGUILayout.EndHorizontal(); |
| | | |
| | | GUILayout.Label("支持搜索:包类型名、UID、字段值", EditorStyles.miniLabel); |
| | | EditorGUILayout.Space(5); |
| | | } |
| | | |
| | | private void DrawPackageList() |
| | | { |
| | | EditorGUILayout.BeginVertical(GUILayout.Width(position.width * 0.5f)); |
| | | |
| | | GUILayout.Label("包列表", EditorStyles.boldLabel); |
| | | |
| | | scrollPosition = EditorGUILayout.BeginScrollView(scrollPosition, GUI.skin.box); |
| | | |
| | | if (filteredPackages.Count == 0) |
| | | { |
| | | GUILayout.Label("没有找到匹配的包", EditorStyles.helpBox); |
| | | } |
| | | else |
| | | { |
| | | foreach (var packInfo in filteredPackages) |
| | | { |
| | | DrawPackageItem(packInfo); |
| | | } |
| | | } |
| | | |
| | | EditorGUILayout.EndScrollView(); |
| | | EditorGUILayout.EndVertical(); |
| | | } |
| | | |
| | | private void DrawPackageItem(PackageInfo packInfo) |
| | | { |
| | | // 判断包的执行状态 |
| | | bool isExecuting = currentExecutingPackUID.ContainsKey(selectedGuid) && |
| | | currentExecutingPackUID[selectedGuid] == packInfo.packUID; |
| | | bool isExecuted = executedPackUIDs.ContainsKey(selectedGuid) && |
| | | executedPackUIDs[selectedGuid].Contains(packInfo.packUID); |
| | | |
| | | // 设置背景颜色 |
| | | Color originalBgColor = GUI.backgroundColor; |
| | | if (isExecuting) |
| | | { |
| | | GUI.backgroundColor = new Color(0.3f, 0.3f, 0.3f); // 深黑色(正在执行) |
| | | } |
| | | else if (isExecuted) |
| | | { |
| | | GUI.backgroundColor = new Color(0.6f, 0.6f, 0.6f); // 灰色(已执行) |
| | | } |
| | | else |
| | | { |
| | | GUI.backgroundColor = new Color(0.8f, 0.8f, 0.8f); // 浅灰色(未执行) |
| | | } |
| | | |
| | | EditorGUILayout.BeginVertical(GUI.skin.box); |
| | | |
| | | GUI.backgroundColor = originalBgColor; // 恢复原始颜色 |
| | | |
| | | EditorGUILayout.BeginHorizontal(); |
| | | |
| | | // 展开/折叠按钮 |
| | | string foldoutLabel = packInfo.isExpanded ? "▼" : "▶"; |
| | | if (GUILayout.Button(foldoutLabel, EditorStyles.label, GUILayout.Width(20))) |
| | | { |
| | | packInfo.isExpanded = !packInfo.isExpanded; |
| | | } |
| | | |
| | | // 包名称(可点击选中) |
| | | bool isSelected = selectedPackage == packInfo; |
| | | |
| | | // 根据状态设置文本颜色 |
| | | GUIStyle style; |
| | | if (isSelected) |
| | | { |
| | | style = new GUIStyle(EditorStyles.boldLabel) { normal = { textColor = Color.cyan } }; |
| | | } |
| | | else if (isExecuting) |
| | | { |
| | | style = new GUIStyle(EditorStyles.label) { normal = { textColor = Color.yellow } }; // 黄色高亮 |
| | | } |
| | | else if (isExecuted) |
| | | { |
| | | style = new GUIStyle(EditorStyles.label) { normal = { textColor = Color.gray } }; |
| | | } |
| | | else |
| | | { |
| | | style = EditorStyles.label; |
| | | } |
| | | |
| | | if (GUILayout.Button(packInfo.displayName, style)) |
| | | { |
| | | selectedPackage = packInfo; |
| | | } |
| | | |
| | | EditorGUILayout.EndHorizontal(); |
| | | |
| | | // 展开显示简要信息 |
| | | if (packInfo.isExpanded) |
| | | { |
| | | EditorGUI.indentLevel++; |
| | | |
| | | // 显示前5个字段 |
| | | int count = 0; |
| | | foreach (var field in packInfo.fields) |
| | | { |
| | | if (count >= 5) break; |
| | | |
| | | EditorGUILayout.BeginHorizontal(); |
| | | GUILayout.Label(field.Key + ":", GUILayout.Width(120)); |
| | | GUILayout.Label(field.Value, EditorStyles.wordWrappedLabel); |
| | | EditorGUILayout.EndHorizontal(); |
| | | |
| | | count++; |
| | | } |
| | | |
| | | if (packInfo.fields.Count > 5) |
| | | { |
| | | GUILayout.Label($"... 更多字段请在右侧查看", EditorStyles.miniLabel); |
| | | } |
| | | |
| | | EditorGUI.indentLevel--; |
| | | } |
| | | |
| | | EditorGUILayout.EndVertical(); |
| | | } |
| | | |
| | | private void DrawPackageDetails() |
| | | { |
| | | EditorGUILayout.BeginVertical(GUILayout.Width(position.width * 0.5f - 10)); |
| | | |
| | | GUILayout.Label("包详情", EditorStyles.boldLabel); |
| | | |
| | | if (selectedPackage == null) |
| | | { |
| | | GUILayout.Label("请从左侧列表选择一个包查看详情", EditorStyles.helpBox); |
| | | } |
| | | else |
| | | { |
| | | detailScrollPosition = EditorGUILayout.BeginScrollView(detailScrollPosition, GUI.skin.box); |
| | | |
| | | // 标题 |
| | | GUILayout.Label(selectedPackage.displayName, EditorStyles.boldLabel); |
| | | EditorGUILayout.Space(5); |
| | | |
| | | // 基本信息 |
| | | DrawDetailField("包类型", selectedPackage.typeName); |
| | | DrawDetailField("UID", selectedPackage.packUID.ToString()); |
| | | DrawDetailField("Cmd", selectedPackage.package.cmd.ToString()); |
| | | EditorGUILayout.Space(10); |
| | | |
| | | // 所有字段 |
| | | GUILayout.Label("字段列表:", EditorStyles.boldLabel); |
| | | foreach (var field in selectedPackage.fields) |
| | | { |
| | | DrawDetailFieldWithExpand(field.Key, field.Value, selectedPackage); |
| | | } |
| | | |
| | | EditorGUILayout.EndScrollView(); |
| | | } |
| | | |
| | | EditorGUILayout.EndVertical(); |
| | | } |
| | | |
| | | private void DrawDetailField(string fieldName, string value) |
| | | { |
| | | EditorGUILayout.BeginHorizontal(); |
| | | |
| | | GUILayout.Label(fieldName + ":", GUILayout.Width(150)); |
| | | |
| | | EditorGUILayout.SelectableLabel(value, EditorStyles.textField, GUILayout.Height(EditorGUIUtility.singleLineHeight)); |
| | | |
| | | EditorGUILayout.EndHorizontal(); |
| | | } |
| | | |
| | | private void DrawDetailFieldWithExpand(string fieldName, string value, PackageInfo packInfo) |
| | | { |
| | | if (!packInfo.fieldDetails.ContainsKey(fieldName)) |
| | | { |
| | | DrawDetailField(fieldName, value); |
| | | return; |
| | | } |
| | | |
| | | var detail = packInfo.fieldDetails[fieldName]; |
| | | |
| | | // 判断是否是复杂对象(非基本类型、非字符串、非枚举) |
| | | bool isComplexObject = detail.value != null && |
| | | !detail.value.GetType().IsPrimitive && |
| | | detail.value.GetType() != typeof(string) && |
| | | !detail.value.GetType().IsEnum && |
| | | !detail.isArray && |
| | | !detail.isList; |
| | | |
| | | // 如果是数组、列表或复杂对象,显示展开按钮 |
| | | if (detail.isArray || detail.isList || isComplexObject) |
| | | { |
| | | EditorGUILayout.BeginHorizontal(); |
| | | |
| | | // 展开按钮 |
| | | string foldoutLabel = detail.isExpanded ? "▼" : "▶"; |
| | | if (GUILayout.Button(foldoutLabel, EditorStyles.label, GUILayout.Width(20))) |
| | | { |
| | | detail.isExpanded = !detail.isExpanded; |
| | | } |
| | | |
| | | GUILayout.Label(fieldName + ":", GUILayout.Width(130)); |
| | | EditorGUILayout.SelectableLabel(value, EditorStyles.textField, GUILayout.Height(EditorGUIUtility.singleLineHeight)); |
| | | |
| | | EditorGUILayout.EndHorizontal(); |
| | | |
| | | // 如果展开,显示内容 |
| | | if (detail.isExpanded) |
| | | { |
| | | EditorGUI.indentLevel++; |
| | | |
| | | if (detail.isArray && detail.arrayValue != null) |
| | | { |
| | | DrawArrayElements(detail.arrayValue, detail); |
| | | } |
| | | else if (detail.isList && detail.listValue != null) |
| | | { |
| | | DrawListElements(detail.listValue, detail); |
| | | } |
| | | else if (isComplexObject) |
| | | { |
| | | // 展开复杂对象的字段 |
| | | DrawObjectFields(detail.value, detail.subFieldDetails); |
| | | } |
| | | |
| | | EditorGUI.indentLevel--; |
| | | } |
| | | } |
| | | else |
| | | { |
| | | DrawDetailField(fieldName, value); |
| | | } |
| | | } |
| | | |
| | | private void DrawArrayElements(System.Array array, FieldDetail parentDetail) |
| | | { |
| | | if (array == null) |
| | | { |
| | | EditorGUILayout.LabelField("Array is null"); |
| | | return; |
| | | } |
| | | |
| | | // 显示数组元素数量 |
| | | EditorGUILayout.LabelField($"总共 {array.Length} 个元素:", EditorStyles.miniLabel); |
| | | |
| | | for (int i = 0; i < array.Length; i++) |
| | | { |
| | | var element = array.GetValue(i); |
| | | DrawArrayElement(i, element, parentDetail); |
| | | } |
| | | } |
| | | |
| | | private void DrawListElements(System.Collections.IList list, FieldDetail parentDetail) |
| | | { |
| | | if (list == null) |
| | | { |
| | | EditorGUILayout.LabelField("List is null"); |
| | | return; |
| | | } |
| | | |
| | | // 显示列表元素数量 |
| | | EditorGUILayout.LabelField($"总共 {list.Count} 个元素:", EditorStyles.miniLabel); |
| | | |
| | | for (int i = 0; i < list.Count; i++) |
| | | { |
| | | var element = list[i]; |
| | | DrawArrayElement(i, element, parentDetail); |
| | | } |
| | | } |
| | | |
| | | private void DrawArrayElement(int index, object element, FieldDetail parentDetail) |
| | | { |
| | | if (element == null) |
| | | { |
| | | EditorGUILayout.LabelField($"[{index}]", "null"); |
| | | return; |
| | | } |
| | | |
| | | var type = element.GetType(); |
| | | |
| | | // 如果是基本类型,直接显示 |
| | | if (type.IsPrimitive || type == typeof(string) || type.IsEnum) |
| | | { |
| | | EditorGUILayout.BeginHorizontal(); |
| | | EditorGUILayout.PrefixLabel($"[{index}]"); |
| | | EditorGUILayout.SelectableLabel(element.ToString(), EditorStyles.textField, GUILayout.Height(EditorGUIUtility.singleLineHeight)); |
| | | EditorGUILayout.EndHorizontal(); |
| | | } |
| | | else |
| | | { |
| | | // 复杂类型,需要展开 |
| | | // 确保有ElementDetail |
| | | if (parentDetail != null && !parentDetail.elementDetails.ContainsKey(index)) |
| | | { |
| | | parentDetail.elementDetails[index] = new ElementDetail(); |
| | | } |
| | | |
| | | var elemDetail = parentDetail?.elementDetails[index]; |
| | | |
| | | // 展开按钮 + 类型名 |
| | | if (elemDetail != null) |
| | | { |
| | | string foldoutLabel = elemDetail.isExpanded ? "▼" : "▶"; |
| | | elemDetail.isExpanded = EditorGUILayout.Foldout(elemDetail.isExpanded, $"[{index}] {type.Name}", true); |
| | | } |
| | | else |
| | | { |
| | | EditorGUILayout.LabelField($"[{index}] {type.Name}"); |
| | | } |
| | | |
| | | // 如果展开,显示字段 |
| | | if (elemDetail != null && elemDetail.isExpanded) |
| | | { |
| | | EditorGUI.indentLevel++; |
| | | DrawObjectFields(element, elemDetail.fieldDetails); |
| | | EditorGUI.indentLevel--; |
| | | } |
| | | } |
| | | } |
| | | |
| | | // 绘制对象的字段(支持递归展开) |
| | | private void DrawObjectFields(object obj, Dictionary<string, FieldDetail> fieldDetailsDict) |
| | | { |
| | | if (obj == null) return; |
| | | |
| | | var type = obj.GetType(); |
| | | var fields = type.GetFields(BindingFlags.Public | BindingFlags.Instance); |
| | | |
| | | foreach (var field in fields) |
| | | { |
| | | try |
| | | { |
| | | var value = field.GetValue(obj); |
| | | |
| | | // 确保有FieldDetail |
| | | if (!fieldDetailsDict.ContainsKey(field.Name)) |
| | | { |
| | | var detail = new FieldDetail { value = value }; |
| | | |
| | | if (value != null && value.GetType().IsArray) |
| | | { |
| | | detail.isArray = true; |
| | | detail.arrayValue = value as System.Array; |
| | | } |
| | | else if (value is System.Collections.IList list && !(value is string)) |
| | | { |
| | | detail.isList = true; |
| | | detail.listValue = list; |
| | | } |
| | | |
| | | fieldDetailsDict[field.Name] = detail; |
| | | } |
| | | |
| | | var fieldDetail = fieldDetailsDict[field.Name]; |
| | | |
| | | // 绘制字段 |
| | | DrawFieldWithRecursiveExpand(field.Name, value, fieldDetail); |
| | | } |
| | | catch |
| | | { |
| | | EditorGUILayout.LabelField(field.Name, "读取失败"); |
| | | } |
| | | } |
| | | } |
| | | |
| | | // 递归地绘制字段(支持多层展开) |
| | | private void DrawFieldWithRecursiveExpand(string fieldName, object value, FieldDetail fieldDetail) |
| | | { |
| | | if (value == null) |
| | | { |
| | | EditorGUILayout.LabelField(fieldName + ":", "null"); |
| | | return; |
| | | } |
| | | |
| | | var type = value.GetType(); |
| | | |
| | | // 基本类型直接显示 |
| | | if (type.IsPrimitive || type == typeof(string) || type.IsEnum) |
| | | { |
| | | EditorGUILayout.BeginHorizontal(); |
| | | EditorGUILayout.PrefixLabel(fieldName); |
| | | EditorGUILayout.SelectableLabel(value.ToString(), EditorStyles.textField, GUILayout.Height(EditorGUIUtility.singleLineHeight)); |
| | | EditorGUILayout.EndHorizontal(); |
| | | } |
| | | // 数组类型 |
| | | else if (type.IsArray && fieldDetail.arrayValue != null) |
| | | { |
| | | fieldDetail.isExpanded = EditorGUILayout.Foldout(fieldDetail.isExpanded, $"{fieldName}: Array[{fieldDetail.arrayValue.Length}]", true); |
| | | |
| | | if (fieldDetail.isExpanded) |
| | | { |
| | | EditorGUI.indentLevel++; |
| | | for (int i = 0; i < fieldDetail.arrayValue.Length; i++) |
| | | { |
| | | var element = fieldDetail.arrayValue.GetValue(i); |
| | | DrawArrayElement(i, element, fieldDetail); |
| | | } |
| | | EditorGUI.indentLevel--; |
| | | } |
| | | } |
| | | // 列表类型 |
| | | else if (fieldDetail.isList && fieldDetail.listValue != null) |
| | | { |
| | | fieldDetail.isExpanded = EditorGUILayout.Foldout(fieldDetail.isExpanded, $"{fieldName}: List[{fieldDetail.listValue.Count}]", true); |
| | | |
| | | if (fieldDetail.isExpanded) |
| | | { |
| | | EditorGUI.indentLevel++; |
| | | for (int i = 0; i < fieldDetail.listValue.Count; i++) |
| | | { |
| | | var element = fieldDetail.listValue[i]; |
| | | DrawArrayElement(i, element, fieldDetail); |
| | | } |
| | | EditorGUI.indentLevel--; |
| | | } |
| | | } |
| | | // 其他复杂类型 |
| | | else |
| | | { |
| | | EditorGUILayout.BeginHorizontal(); |
| | | EditorGUILayout.PrefixLabel(fieldName); |
| | | EditorGUILayout.SelectableLabel(value.ToString(), EditorStyles.textField, GUILayout.Height(EditorGUIUtility.singleLineHeight)); |
| | | EditorGUILayout.EndHorizontal(); |
| | | } |
| | | } |
| | | |
| | | #endregion |
| | | |
| | | #region 数据处理 |
| | | |
| | | private void RefreshGuidList() |
| | | { |
| | | guidList = allBattlePackages.Keys.ToList(); |
| | | |
| | | if (guidList.Count > 0) |
| | | { |
| | | if (string.IsNullOrEmpty(selectedGuid) || !guidList.Contains(selectedGuid)) |
| | | { |
| | | selectedGuidIndex = 0; |
| | | selectedGuid = guidList[0]; |
| | | } |
| | | else |
| | | { |
| | | selectedGuidIndex = guidList.IndexOf(selectedGuid); |
| | | } |
| | | |
| | | FilterPackages(); |
| | | } |
| | | else |
| | | { |
| | | selectedGuid = ""; |
| | | selectedGuidIndex = 0; |
| | | filteredPackages.Clear(); |
| | | } |
| | | } |
| | | |
| | | private void FilterPackages() |
| | | { |
| | | if (string.IsNullOrEmpty(selectedGuid) || !allBattlePackages.ContainsKey(selectedGuid)) |
| | | { |
| | | filteredPackages.Clear(); |
| | | return; |
| | | } |
| | | |
| | | var allPackages = allBattlePackages[selectedGuid]; |
| | | |
| | | if (string.IsNullOrEmpty(searchText)) |
| | | { |
| | | filteredPackages = new List<PackageInfo>(allPackages); |
| | | } |
| | | else |
| | | { |
| | | string searchLower = searchText.ToLower(); |
| | | |
| | | filteredPackages = allPackages.Where(p => |
| | | { |
| | | // 搜索包类型名 |
| | | if (p.typeName.ToLower().Contains(searchLower)) |
| | | return true; |
| | | |
| | | // 搜索 UID |
| | | if (p.packUID.ToString().Contains(searchLower)) |
| | | return true; |
| | | |
| | | // 递归搜索所有字段(包括嵌套内容) |
| | | if (RecursiveSearchInPackage(p.package, searchLower)) |
| | | return true; |
| | | |
| | | return false; |
| | | }).ToList(); |
| | | } |
| | | |
| | | // 按照 packUID 从小到大排序 |
| | | filteredPackages.Sort((a, b) => a.packUID.CompareTo(b.packUID)); |
| | | |
| | | Repaint(); |
| | | } |
| | | |
| | | /// <summary> |
| | | /// 递归搜索对象的所有字段(包括嵌套数组、列表等) |
| | | /// </summary> |
| | | private bool RecursiveSearchInPackage(object obj, string searchLower) |
| | | { |
| | | if (obj == null) return false; |
| | | |
| | | var type = obj.GetType(); |
| | | |
| | | // 基本类型直接比较 |
| | | if (type.IsPrimitive || type == typeof(string) || type.IsEnum) |
| | | { |
| | | return obj.ToString().ToLower().Contains(searchLower); |
| | | } |
| | | |
| | | // 数组类型 |
| | | if (obj is System.Array array) |
| | | { |
| | | foreach (var element in array) |
| | | { |
| | | if (RecursiveSearchInPackage(element, searchLower)) |
| | | return true; |
| | | } |
| | | return false; |
| | | } |
| | | |
| | | // 列表类型 |
| | | if (obj is System.Collections.IList list) |
| | | { |
| | | foreach (var element in list) |
| | | { |
| | | if (RecursiveSearchInPackage(element, searchLower)) |
| | | return true; |
| | | } |
| | | return false; |
| | | } |
| | | |
| | | // 复杂对象,递归搜索所有字段 |
| | | var fields = type.GetFields(BindingFlags.Public | BindingFlags.Instance); |
| | | foreach (var field in fields) |
| | | { |
| | | try |
| | | { |
| | | // 搜索字段名 |
| | | if (field.Name.ToLower().Contains(searchLower)) |
| | | return true; |
| | | |
| | | var value = field.GetValue(obj); |
| | | if (value == null) continue; |
| | | |
| | | // 递归搜索字段值 |
| | | if (RecursiveSearchInPackage(value, searchLower)) |
| | | return true; |
| | | } |
| | | catch |
| | | { |
| | | // 忽略读取失败的字段 |
| | | } |
| | | } |
| | | |
| | | return false; |
| | | } |
| | | |
| | | #endregion |
| | | } |