三国卡牌客户端基础资源仓库
yyl
2026-01-23 41856d9c515b039e3b0444c62b4f12ea282bff03
战报检查
2个文件已添加
893 ■■■■■ 已修改文件
Assets/Editor/ScriptEditor/BattleReportChecker.cs 882 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Assets/Editor/ScriptEditor/BattleReportChecker.cs.meta 11 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Assets/Editor/ScriptEditor/BattleReportChecker.cs
New file
@@ -0,0 +1,882 @@
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
}
Assets/Editor/ScriptEditor/BattleReportChecker.cs.meta
New file
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: eb17c312bfd448b4f85f4c2538288704
MonoImporter:
  externalObjects: {}
  serializedVersion: 2
  defaultReferences: []
  executionOrder: 0
  icon: {instanceID: 0}
  userData:
  assetBundleName:
  assetBundleVariant: