#if UNITY_2019_4_OR_NEWER using System; using System.Collections.Generic; using System.Linq; using UnityEditor; using UnityEngine; using UnityEditor.UIElements; using UnityEngine.UIElements; namespace YooAsset.Editor { /// /// 帧对比查看器 /// internal class DebuggerCompareViewer { /// /// 差异类型 /// internal enum DiffType { RefIncreased, // 引用计数增加(包括新增资源) RefDecreased, // 引用计数减少(包括移除资源) Unchanged // 无变化 } /// /// 差异信息 /// internal class DiffProviderInfo { public DiffType Type; public DebugProviderInfo ProviderInfo; public DebugProviderInfo OldProviderInfo; // 用于对比修改前后的值 public int RefCountDelta; // 引用计数变化值 public int SecondaryRefCountDelta; // 二级引用计数变化值 public string GetDiffTypeString() { switch (Type) { case DiffType.RefIncreased: return "[↑] 引用增加"; case DiffType.RefDecreased: return "[↓] 引用减少"; case DiffType.Unchanged: return "[=] 无变化"; default: return ""; } } public Color GetDiffColor() { switch (Type) { case DiffType.RefIncreased: return new Color(0.3f, 0.8f, 0.3f); case DiffType.RefDecreased: return new Color(0.9f, 0.3f, 0.3f); case DiffType.Unchanged: return Color.gray; default: return Color.white; } } } private VisualElement _root; private ListView _diffListView; private Label _frame1Label; private Label _frame2Label; private Label _summaryLabel; private Toggle _showRefIncreasedToggle; private Toggle _showRefDecreasedToggle; private Toggle _showUnchangedToggle; private DebugReport _report1; private DebugReport _report2; private List _allDiffInfos = new List(); private List _filteredDiffInfos = new List(); private string _searchKeyWord; /// /// 初始化页面 /// public void InitViewer() { _root = new VisualElement(); _root.style.flexGrow = 1f; // 顶部信息栏 var infoBar = new VisualElement(); infoBar.style.flexDirection = FlexDirection.Row; infoBar.style.height = 25; infoBar.style.backgroundColor = new Color(0.2f, 0.2f, 0.2f); infoBar.style.paddingLeft = 5; infoBar.style.paddingRight = 5; _root.Add(infoBar); _frame1Label = new Label("Frame A: 未选择"); _frame1Label.style.unityTextAlign = TextAnchor.MiddleLeft; _frame1Label.style.width = 200; infoBar.Add(_frame1Label); _frame2Label = new Label("Frame B: 未选择"); _frame2Label.style.unityTextAlign = TextAnchor.MiddleLeft; _frame2Label.style.width = 200; infoBar.Add(_frame2Label); _summaryLabel = new Label(""); _summaryLabel.style.unityTextAlign = TextAnchor.MiddleLeft; _summaryLabel.style.flexGrow = 1; infoBar.Add(_summaryLabel); // 过滤器栏 var filterBar = new VisualElement(); filterBar.style.flexDirection = FlexDirection.Row; filterBar.style.height = 25; filterBar.style.backgroundColor = new Color(0.25f, 0.25f, 0.25f); filterBar.style.paddingLeft = 5; filterBar.style.alignItems = Align.Center; _root.Add(filterBar); var filterLabel = new Label("显示过滤: "); filterLabel.style.unityTextAlign = TextAnchor.MiddleLeft; filterLabel.style.marginRight = 10; filterBar.Add(filterLabel); _showRefIncreasedToggle = CreateFilterToggle("引用增加", true); _showRefIncreasedToggle.RegisterValueChangedCallback(evt => RefreshFilteredList()); filterBar.Add(_showRefIncreasedToggle); _showRefDecreasedToggle = CreateFilterToggle("引用减少", true); _showRefDecreasedToggle.RegisterValueChangedCallback(evt => RefreshFilteredList()); filterBar.Add(_showRefDecreasedToggle); _showUnchangedToggle = CreateFilterToggle("无变化", false); _showUnchangedToggle.RegisterValueChangedCallback(evt => RefreshFilteredList()); filterBar.Add(_showUnchangedToggle); // 列表头部 var headerBar = new VisualElement(); headerBar.style.flexDirection = FlexDirection.Row; headerBar.style.height = 22; headerBar.style.backgroundColor = new Color(0.3f, 0.3f, 0.3f); _root.Add(headerBar); AddHeaderLabel(headerBar, "差异类型", 100); AddHeaderLabel(headerBar, "包裹名", 120); AddHeaderLabel(headerBar, "资源路径", 0, true); // 自动填充剩余宽度 AddHeaderLabel(headerBar, "一级引用", 100); AddHeaderLabel(headerBar, "一级变化", 80); AddHeaderLabel(headerBar, "二级引用", 100); AddHeaderLabel(headerBar, "二级变化", 80); // 差异列表 _diffListView = new ListView(); _diffListView.style.flexGrow = 1f; _diffListView.makeItem = MakeDiffListViewItem; _diffListView.bindItem = BindDiffListViewItem; _diffListView.itemsSource = _filteredDiffInfos; #if UNITY_2021_2_OR_NEWER _diffListView.fixedItemHeight = 22; #else _diffListView.itemHeight = 22; #endif _root.Add(_diffListView); } private void AddHeaderLabel(VisualElement parent, string text, float width, bool flexGrow = false) { var label = new Label(text); label.style.unityTextAlign = TextAnchor.MiddleLeft; if (flexGrow) { label.style.flexGrow = 1f; label.style.minWidth = 200; } else { label.style.width = width; } label.style.unityFontStyleAndWeight = FontStyle.Bold; label.style.paddingLeft = 3; parent.Add(label); } private Toggle CreateFilterToggle(string label, bool defaultValue) { var toggle = new Toggle(); toggle.value = defaultValue; toggle.style.marginRight = 5; // 创建标签并设置样式 var labelElement = new Label(label); labelElement.style.marginLeft = 2; labelElement.style.marginRight = 10; toggle.Add(labelElement); return toggle; } /// /// 设置对比的两帧数据 /// public void SetCompareFrames(DebugReport report1, DebugReport report2) { _report1 = report1; _report2 = report2; if (report1 != null) _frame1Label.text = $"Frame A: {report1.FrameCount}"; else _frame1Label.text = "Frame A: 未选择"; if (report2 != null) _frame2Label.text = $"Frame B: {report2.FrameCount}"; else _frame2Label.text = "Frame B: 未选择"; ComputeDiff(); RefreshFilteredList(); } /// /// 设置搜索关键字 /// public void SetSearchKeyWord(string searchKeyWord) { _searchKeyWord = searchKeyWord; RefreshFilteredList(); } /// /// 计算差异 /// private void ComputeDiff() { _allDiffInfos.Clear(); if (_report1 == null || _report2 == null) { UpdateSummary(); return; } // 收集两帧的所有Provider信息 var providers1 = new Dictionary(); var providers2 = new Dictionary(); foreach (var packageData in _report1.PackageDatas) { foreach (var providerInfo in packageData.ProviderInfos) { var key = $"{packageData.PackageName}|{providerInfo.AssetPath}"; providerInfo.PackageName = packageData.PackageName; providers1[key] = providerInfo; } } foreach (var packageData in _report2.PackageDatas) { foreach (var providerInfo in packageData.ProviderInfos) { var key = $"{packageData.PackageName}|{providerInfo.AssetPath}"; providerInfo.PackageName = packageData.PackageName; providers2[key] = providerInfo; } } // 找出新增的(在report2中有,在report1中没有)- 归类为引用增加 foreach (var kvp in providers2) { if (!providers1.ContainsKey(kvp.Key)) { _allDiffInfos.Add(new DiffProviderInfo { Type = DiffType.RefIncreased, ProviderInfo = kvp.Value, OldProviderInfo = null, RefCountDelta = kvp.Value.RefCount, SecondaryRefCountDelta = kvp.Value.SecondaryRefCount }); } } // 找出移除的(在report1中有,在report2中没有)- 归类为引用减少 foreach (var kvp in providers1) { if (!providers2.ContainsKey(kvp.Key)) { _allDiffInfos.Add(new DiffProviderInfo { Type = DiffType.RefDecreased, ProviderInfo = kvp.Value, OldProviderInfo = null, RefCountDelta = -kvp.Value.RefCount, SecondaryRefCountDelta = -kvp.Value.SecondaryRefCount }); } } // 找出修改的和未变化的 foreach (var kvp in providers1) { if (providers2.TryGetValue(kvp.Key, out var provider2)) { var provider1 = kvp.Value; int refCountDelta = provider2.RefCount - provider1.RefCount; int secondaryRefCountDelta = provider2.SecondaryRefCount - provider1.SecondaryRefCount; // 判断差异类型:一级或二级引用计数有任一增加则为增加,有任一减少则为减少 DiffType diffType; if (refCountDelta > 0 || secondaryRefCountDelta > 0) diffType = DiffType.RefIncreased; else if (refCountDelta < 0 || secondaryRefCountDelta < 0) diffType = DiffType.RefDecreased; else diffType = DiffType.Unchanged; _allDiffInfos.Add(new DiffProviderInfo { Type = diffType, ProviderInfo = provider2, OldProviderInfo = provider1, RefCountDelta = refCountDelta, SecondaryRefCountDelta = secondaryRefCountDelta }); } } // 排序:按差异类型排序,同类型按资源路径排序 _allDiffInfos.Sort((a, b) => { int typeCompare = a.Type.CompareTo(b.Type); if (typeCompare != 0) return typeCompare; return string.CompareOrdinal(a.ProviderInfo.AssetPath, b.ProviderInfo.AssetPath); }); UpdateSummary(); } /// /// 更新统计信息 /// private void UpdateSummary() { int refIncreasedCount = _allDiffInfos.Count(d => d.Type == DiffType.RefIncreased); int refDecreasedCount = _allDiffInfos.Count(d => d.Type == DiffType.RefDecreased); int unchangedCount = _allDiffInfos.Count(d => d.Type == DiffType.Unchanged); _summaryLabel.text = $"统计: 引用↑ {refIncreasedCount} | 引用↓ {refDecreasedCount} | 无变化 {unchangedCount}"; } /// /// 刷新过滤后的列表 /// private void RefreshFilteredList() { _filteredDiffInfos.Clear(); foreach (var diffInfo in _allDiffInfos) { // 类型过滤 if (diffInfo.Type == DiffType.RefIncreased && !_showRefIncreasedToggle.value) continue; if (diffInfo.Type == DiffType.RefDecreased && !_showRefDecreasedToggle.value) continue; if (diffInfo.Type == DiffType.Unchanged && !_showUnchangedToggle.value) continue; // 关键字过滤 if (!string.IsNullOrEmpty(_searchKeyWord)) { if (!diffInfo.ProviderInfo.AssetPath.Contains(_searchKeyWord)) continue; } _filteredDiffInfos.Add(diffInfo); } _diffListView.itemsSource = _filteredDiffInfos; _diffListView.Rebuild(); } /// /// 清空页面 /// public void ClearView() { _report1 = null; _report2 = null; _allDiffInfos.Clear(); _filteredDiffInfos.Clear(); _frame1Label.text = "Frame A: 未选择"; _frame2Label.text = "Frame B: 未选择"; _summaryLabel.text = ""; _diffListView.Rebuild(); } /// /// 挂接到父类页面上 /// public void AttachParent(VisualElement parent) { parent.Add(_root); } /// /// 从父类页面脱离开 /// public void DetachParent() { _root.RemoveFromHierarchy(); } // 列表项相关 private VisualElement MakeDiffListViewItem() { VisualElement element = new VisualElement(); element.style.flexDirection = FlexDirection.Row; // 差异类型 AddItemLabel(element, "Label0", 100); // 包裹名 AddItemLabel(element, "Label1", 120); // 资源路径 - 自动填充剩余宽度 AddItemLabel(element, "Label2", 0, true); // 一级引用计数 AddItemLabel(element, "Label3", 100); // 一级引用变化 AddItemLabel(element, "Label4", 80); // 二级引用计数 AddItemLabel(element, "Label5", 100); // 二级引用变化 AddItemLabel(element, "Label6", 80); return element; } private void AddItemLabel(VisualElement parent, string name, float width, bool flexGrow = false) { var label = new Label(); label.name = name; label.style.unityTextAlign = TextAnchor.MiddleLeft; label.style.marginLeft = 3f; if (flexGrow) { label.style.flexGrow = 1f; label.style.minWidth = 200; } else { label.style.width = width; } parent.Add(label); } private void BindDiffListViewItem(VisualElement element, int index) { var diffInfo = _filteredDiffInfos[index]; var providerInfo = diffInfo.ProviderInfo; // 差异类型 var label0 = element.Q