YooAsset/Editor/AssetBundleDebugger/VisualViewers/DebuggerCompareViewer.cs

529 lines
19 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

#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
{
/// <summary>
/// 帧对比查看器
/// </summary>
internal class DebuggerCompareViewer
{
/// <summary>
/// 差异类型
/// </summary>
internal enum DiffType
{
RefIncreased, // 引用计数增加(包括新增资源)
RefDecreased, // 引用计数减少(包括移除资源)
Unchanged // 无变化
}
/// <summary>
/// 差异信息
/// </summary>
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<DiffProviderInfo> _allDiffInfos = new List<DiffProviderInfo>();
private List<DiffProviderInfo> _filteredDiffInfos = new List<DiffProviderInfo>();
private string _searchKeyWord;
/// <summary>
/// 初始化页面
/// </summary>
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;
}
/// <summary>
/// 设置对比的两帧数据
/// </summary>
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();
}
/// <summary>
/// 设置搜索关键字
/// </summary>
public void SetSearchKeyWord(string searchKeyWord)
{
_searchKeyWord = searchKeyWord;
RefreshFilteredList();
}
/// <summary>
/// 计算差异
/// </summary>
private void ComputeDiff()
{
_allDiffInfos.Clear();
if (_report1 == null || _report2 == null)
{
UpdateSummary();
return;
}
// 收集两帧的所有Provider信息
var providers1 = new Dictionary<string, DebugProviderInfo>();
var providers2 = new Dictionary<string, DebugProviderInfo>();
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();
}
/// <summary>
/// 更新统计信息
/// </summary>
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}";
}
/// <summary>
/// 刷新过滤后的列表
/// </summary>
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();
}
/// <summary>
/// 清空页面
/// </summary>
public void ClearView()
{
_report1 = null;
_report2 = null;
_allDiffInfos.Clear();
_filteredDiffInfos.Clear();
_frame1Label.text = "Frame A: 未选择";
_frame2Label.text = "Frame B: 未选择";
_summaryLabel.text = "";
_diffListView.Rebuild();
}
/// <summary>
/// 挂接到父类页面上
/// </summary>
public void AttachParent(VisualElement parent)
{
parent.Add(_root);
}
/// <summary>
/// 从父类页面脱离开
/// </summary>
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<Label>("Label0");
label0.text = diffInfo.GetDiffTypeString();
label0.style.color = diffInfo.GetDiffColor();
// 包裹名
var label1 = element.Q<Label>("Label1");
label1.text = providerInfo.PackageName;
// 资源路径
var label2 = element.Q<Label>("Label2");
label2.text = providerInfo.AssetPath;
// 一级引用计数
var label3 = element.Q<Label>("Label3");
if (diffInfo.RefCountDelta != 0 && diffInfo.OldProviderInfo != null)
{
label3.text = $"{diffInfo.OldProviderInfo.RefCount} -> {providerInfo.RefCount}";
}
else
{
label3.text = providerInfo.RefCount.ToString();
}
// 一级引用变化
var label4 = element.Q<Label>("Label4");
if (diffInfo.RefCountDelta > 0)
{
label4.text = $"+{diffInfo.RefCountDelta}";
label4.style.color = new Color(0.3f, 0.8f, 0.3f);
}
else if (diffInfo.RefCountDelta < 0)
{
label4.text = diffInfo.RefCountDelta.ToString();
label4.style.color = new Color(0.9f, 0.3f, 0.3f);
}
else
{
label4.text = "0";
label4.style.color = Color.gray;
}
// 二级引用计数
var label5 = element.Q<Label>("Label5");
if (diffInfo.SecondaryRefCountDelta != 0 && diffInfo.OldProviderInfo != null)
{
label5.text = $"{diffInfo.OldProviderInfo.SecondaryRefCount} -> {providerInfo.SecondaryRefCount}";
}
else
{
label5.text = providerInfo.SecondaryRefCount.ToString();
}
// 二级引用变化
var label6 = element.Q<Label>("Label6");
if (diffInfo.SecondaryRefCountDelta > 0)
{
label6.text = $"+{diffInfo.SecondaryRefCountDelta}";
label6.style.color = new Color(0.3f, 0.8f, 0.3f);
}
else if (diffInfo.SecondaryRefCountDelta < 0)
{
label6.text = diffInfo.SecondaryRefCountDelta.ToString();
label6.style.color = new Color(0.9f, 0.3f, 0.3f);
}
else
{
label6.text = "0";
label6.style.color = Color.gray;
}
}
}
}
#endif