Compare commits

...

2 Commits

Author SHA1 Message Date
何冠峰 b74a44dc36 update UIElements 2025-03-03 20:57:50 +08:00
何冠峰 6b36cdb5ee update AssetBundleDebugger
内置了新的UIElments的TreeViewer组件。
2025-03-03 18:28:02 +08:00
11 changed files with 364 additions and 56 deletions

View File

@ -22,11 +22,8 @@ namespace YooAsset.Editor
private TableView _operationTableView;
private Toolbar _bottomToolbar;
#if UNITY_2022_3_OR_NEWER
private TreeView _childTreeView;
#endif
private TreeViewer _childTreeView;
private int _treeItemID = 0;
private List<ITableData> _sourceDatas;
@ -53,11 +50,9 @@ namespace YooAsset.Editor
CreateBottomToolbarHeaders();
// 子列表
#if UNITY_2022_3_OR_NEWER
_childTreeView = _root.Q<TreeView>("BottomTreeView");
_childTreeView = _root.Q<TreeViewer>("BottomTreeView");
_childTreeView.makeItem = MakeTreeViewItem;
_childTreeView.bindItem = BindTreeViewItem;
#endif
// 面板分屏
var topGroup = _root.Q<VisualElement>("TopGroup");
@ -307,11 +302,8 @@ namespace YooAsset.Editor
{
// 清空旧数据
_operationTableView.ClearAll(false, true);
#if UNITY_2022_3_OR_NEWER
_childTreeView.SetRootItems(new List<TreeViewItemData<DebugOperationInfo>>());
_childTreeView.Rebuild();
#endif
_childTreeView.ClearAll();
_childTreeView.RebuildView();
// 填充数据源
_sourceDatas = new List<ITableData>(1000);
@ -345,10 +337,7 @@ namespace YooAsset.Editor
public void ClearView()
{
_operationTableView.ClearAll(false, true);
#if UNITY_2022_3_OR_NEWER
_childTreeView.SetRootItems(new List<TreeViewItemData<DebugOperationInfo>>());
_childTreeView.Rebuild();
#endif
_childTreeView.ClearAll();
RebuildView(null);
}
@ -362,6 +351,7 @@ namespace YooAsset.Editor
// 重建视图
_operationTableView.RebuildView();
_childTreeView.RebuildView();
}
/// <summary>
@ -380,23 +370,20 @@ namespace YooAsset.Editor
_root.RemoveFromHierarchy();
}
#if UNITY_2022_3_OR_NEWER
private void OnOperationTableViewSelectionChanged(ITableData data)
{
var operationTableData = data as OperationTableData;
DebugPackageData packageData = operationTableData.PackageData;
DebugOperationInfo operationInfo = operationTableData.OperationInfo;
_treeItemID = 0;
var rootItems = CreateTreeData(operationInfo);
_childTreeView.SetRootItems(rootItems);
_childTreeView.Rebuild();
TreeNode rootNode = new TreeNode(operationInfo);
FillTreeData(operationInfo, rootNode);
_childTreeView.ClearAll();
_childTreeView.SetRootItem(rootNode);
_childTreeView.RebuildView();
}
private VisualElement MakeTreeViewItem()
private void MakeTreeViewItem(VisualElement container)
{
VisualElement treeViewElement = new VisualElement();
treeViewElement.style.flexDirection = FlexDirection.Row;
// OperationName
{
Label label = new Label();
@ -404,7 +391,7 @@ namespace YooAsset.Editor
label.style.flexGrow = 0f;
label.style.width = 300;
label.style.unityTextAlign = TextAnchor.MiddleLeft;
treeViewElement.Add(label);
container.Add(label);
}
// Progress
@ -414,7 +401,7 @@ namespace YooAsset.Editor
label.style.flexGrow = 0f;
label.style.width = 100;
label.style.unityTextAlign = TextAnchor.MiddleLeft;
treeViewElement.Add(label);
container.Add(label);
}
// BeginTime
@ -424,7 +411,7 @@ namespace YooAsset.Editor
label.style.flexGrow = 0f;
label.style.width = 100;
label.style.unityTextAlign = TextAnchor.MiddleLeft;
treeViewElement.Add(label);
container.Add(label);
}
// ProcessTime
@ -434,7 +421,7 @@ namespace YooAsset.Editor
label.style.flexGrow = 0f;
label.style.width = 100;
label.style.unityTextAlign = TextAnchor.MiddleLeft;
treeViewElement.Add(label);
container.Add(label);
}
// Status
@ -444,7 +431,7 @@ namespace YooAsset.Editor
label.style.flexGrow = 0f;
label.style.width = 100;
label.style.unityTextAlign = TextAnchor.MiddleLeft;
treeViewElement.Add(label);
container.Add(label);
}
// Desc
@ -454,36 +441,34 @@ namespace YooAsset.Editor
label.style.flexGrow = 1f;
label.style.width = 500;
label.style.unityTextAlign = TextAnchor.MiddleLeft;
treeViewElement.Add(label);
container.Add(label);
}
return treeViewElement;
}
private void BindTreeViewItem(VisualElement element, int index)
private void BindTreeViewItem(VisualElement container, object userData)
{
var operationInfo = _childTreeView.GetItemDataForIndex<DebugOperationInfo>(index);
var operationInfo = userData as DebugOperationInfo;
// OperationName
{
var label = element.Q<Label>("OperationName");
var label = container.Q<Label>("OperationName");
label.text = operationInfo.OperationName;
}
// Progress
{
var label = element.Q<Label>("Progress");
var label = container.Q<Label>("Progress");
label.text = operationInfo.Progress.ToString();
}
// BeginTime
{
var label = element.Q<Label>("BeginTime");
var label = container.Q<Label>("BeginTime");
label.text = operationInfo.BeginTime;
}
// ProcessTime
{
var label = element.Q<Label>("ProcessTime");
var label = container.Q<Label>("ProcessTime");
label.text = operationInfo.ProcessTime.ToString();
}
@ -495,33 +480,26 @@ namespace YooAsset.Editor
else
textColor = new StyleColor(Color.white);
var label = element.Q<Label>("Status");
var label = container.Q<Label>("Status");
label.text = operationInfo.Status;
label.style.color = textColor;
}
// Desc
{
var label = element.Q<Label>("Desc");
var label = container.Q<Label>("Desc");
label.text = operationInfo.OperationDesc;
}
}
private List<TreeViewItemData<DebugOperationInfo>> CreateTreeData(DebugOperationInfo parentOperation)
private void FillTreeData(DebugOperationInfo parentOperation, TreeNode rootNode)
{
var rootItemList = new List<TreeViewItemData<DebugOperationInfo>>();
foreach (var childOperation in parentOperation.Childs)
{
var childItemList = CreateTreeData(childOperation);
var treeItem = new TreeViewItemData<DebugOperationInfo>(_treeItemID++, childOperation, childItemList);
rootItemList.Add(treeItem);
var childNode = new TreeNode(childOperation);
rootNode.AddChild(childNode);
FillTreeData(childOperation, childNode);
}
return rootItemList;
}
#else
private void OnOperationTableViewSelectionChanged(ITableData data)
{
}
#endif
}
}
#endif

View File

@ -4,6 +4,6 @@
</ui:VisualElement>
<ui:VisualElement name="BottomGroup" style="flex-grow: 1;">
<uie:Toolbar name="BottomToolbar" />
<ui:TreeView name="BottomTreeView" />
<YooAsset.Editor.TreeViewer name="BottomTreeView" />
</ui:VisualElement>
</ui:UXML>

View File

@ -0,0 +1,55 @@
#if UNITY_2019_4_OR_NEWER
using System;
using UnityEditor;
using UnityEngine;
using UnityEditor.UIElements;
using UnityEngine.UIElements;
namespace YooAsset.Editor
{
/// <summary>
/// 折叠开关
/// </summary>
public class ToggleFoldout : Toggle
{
public new class UxmlFactory : UxmlFactory<ToggleFoldout, UxmlTraits>
{
}
private readonly VisualElement _checkbox;
public ToggleFoldout()
{
_checkbox = this.Q<VisualElement>("unity-checkmark");
RefreshIcon();
}
public override void SetValueWithoutNotify(bool newValue)
{
base.SetValueWithoutNotify(newValue);
RefreshIcon();
}
#if UNITY_2021_3_OR_NEWER
protected override void ToggleValue()
{
base.ToggleValue();
RefreshIcon();
}
#endif
public void RefreshIcon()
{
if (this.value)
{
var icon = EditorGUIUtility.IconContent(UIElementsIcon.FoldoutOn).image as Texture2D;
_checkbox.style.backgroundImage = icon;
}
else
{
var icon = EditorGUIUtility.IconContent(UIElementsIcon.FoldoutOff).image as Texture2D;
_checkbox.style.backgroundImage = icon;
}
}
}
}
#endif

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 2619997e70d98794da26a947f9129e25
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 1797f960cdbd5aa41a96bb02d16c4998
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,77 @@
#if UNITY_2019_4_OR_NEWER
using System.IO;
using System.Linq;
using System.Collections.Generic;
using UnityEditor;
using UnityEngine;
using UnityEditor.UIElements;
using UnityEngine.UIElements;
namespace YooAsset.Editor
{
public class TreeNode
{
/// <summary>
/// 子节点集合
/// </summary>
public List<TreeNode> Children = new List<TreeNode>(10);
/// <summary>
/// 父节点
/// </summary>
public TreeNode Parent { get; set; }
/// <summary>
/// 用户数据
/// </summary>
public object UserData { get; set; }
/// <summary>
/// 是否展开
/// </summary>
public bool IsExpanded { get; set; } = false;
public TreeNode(object userData)
{
UserData = userData;
}
/// <summary>
/// 添加子节点
/// </summary>
public void AddChild(TreeNode child)
{
child.Parent = this;
Children.Add(child);
}
/// <summary>
/// 清理所有子节点
/// </summary>
public void ClearChildren()
{
foreach(var child in Children)
{
child.Parent = null;
}
Children.Clear();
}
/// <summary>
/// 计算节点的深度
/// </summary>
public int GetDepth()
{
int depth = 0;
TreeNode current = this;
while (current.Parent != null)
{
depth++;
current = current.Parent;
}
return depth;
}
}
}
#endif

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 473cdc8e1dd7b0f43938ddb99287a2a8
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,152 @@
#if UNITY_2019_4_OR_NEWER
using System;
using System.Linq;
using System.Collections.Generic;
using UnityEditor;
using UnityEngine;
using UnityEditor.UIElements;
using UnityEngine.UIElements;
namespace YooAsset.Editor
{
public class TreeViewer : VisualElement
{
public new class UxmlFactory : UxmlFactory<TreeViewer, UxmlTraits>
{
}
private readonly ListView _listView;
private readonly List<TreeNode> _flattenList = new List<TreeNode>(1000);
private readonly List<TreeNode> _rootList = new List<TreeNode>(100);
/// <summary>
/// 制作列表元素
/// </summary>
public Action<VisualElement> makeItem { get; set; }
/// <summary>
/// 绑定列表数据
/// </summary>
public Action<VisualElement, object> bindItem { get; set; }
public TreeViewer()
{
this.style.flexShrink = 1f;
this.style.flexGrow = 1f;
// 创建ListView
_listView = new ListView();
_listView.style.flexShrink = 1f;
_listView.style.flexGrow = 1f;
_listView.itemsSource = _flattenList;
_listView.makeItem = MakeItemInternal;
_listView.bindItem = BindItemInternal;
this.Add(_listView);
}
/// <summary>
/// 设置根节点数据
/// </summary>
public void SetRootItem(TreeNode rootNode)
{
_rootList.Add(rootNode);
}
/// <summary>
/// 设置根节点数据
/// </summary>
public void SetRootItems(List<TreeNode> rootNodes)
{
_rootList.AddRange(rootNodes);
}
/// <summary>
/// 清理数据
/// </summary>
public void ClearAll()
{
_rootList.Clear();
}
/// <summary>
/// 重新绘制视图
/// </summary>
public void RebuildView()
{
_flattenList.Clear();
foreach (var treeRoot in _rootList)
{
FlattenTree(treeRoot, 0);
}
_listView.Rebuild();
}
/// <summary>
/// 将树形结构扁平化为列表
/// </summary>
private void FlattenTree(TreeNode node, int depth)
{
_flattenList.Add(node);
if (node.IsExpanded)
{
foreach (var child in node.Children)
{
FlattenTree(child, depth + 1);
}
}
}
private VisualElement MakeItemInternal()
{
var container = new VisualElement();
container.style.flexDirection = FlexDirection.Row;
// 折叠按钮
var toggle = new ToggleFoldout();
toggle.text = string.Empty;
toggle.name = "foldout";
toggle.style.alignSelf = Align.Center;
toggle.style.width = 15;
toggle.style.height = 15;
toggle.RegisterValueChangedCallback((ChangeEvent<bool> callback) =>
{
var treeNode = toggle.userData as TreeNode;
treeNode.IsExpanded = toggle.value;
RebuildView();
});
container.Add(toggle);
// 用户自定义元素
if (makeItem != null)
{
makeItem.Invoke(container);
}
return container;
}
private void BindItemInternal(VisualElement item, int index)
{
var treeNode = _flattenList[index];
// 设置折叠状态
var toggle = item.Q<ToggleFoldout>("foldout");
toggle.SetValueWithoutNotify(treeNode.IsExpanded);
toggle.userData = treeNode;
toggle.style.marginLeft = treeNode.GetDepth() * 15;
// 隐藏折叠按钮
if (treeNode.Children.Count == 0)
{
toggle.style.visibility = Visibility.Hidden;
}
// 用户自定义元素
if (bindItem != null)
{
bindItem.Invoke(item, treeNode.UserData);
}
}
}
}
#endif

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: db2fb30e2d4512149b615fe6b2562ecd
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -10,6 +10,14 @@ namespace YooAsset.Editor
public const string RecordOn = "d_Record On@2x";
public const string RecordOff = "d_Record Off@2x";
#if UNITY_2019
public const string FoldoutOn = "IN foldout on";
public const string FoldoutOff = "IN foldout";
#else
public const string FoldoutOn = "d_IN_foldout_on@2x";
public const string FoldoutOff = "d_IN_foldout@2x";
#endif
public const string VisibilityToggleOff = "animationvisibilitytoggleoff@2x";
public const string VisibilityToggleOn = "animationvisibilitytoggleon@2x";
}

View File

@ -23,12 +23,10 @@ namespace YooAsset
public void Initialize()
{
Debug.LogWarning("X=Initialize");
_messageCallbacks.Clear();
}
public void Register(Guid messageID, UnityAction<MessageEventArgs> callback)
{
Debug.LogWarning("X=Register");
if (messageID == Guid.Empty)
throw new ArgumentException("messageID is empty !");
@ -37,7 +35,6 @@ namespace YooAsset
}
public void Unregister(Guid messageID)
{
Debug.LogWarning("X=Unregister");
if (_messageCallbacks.ContainsKey(messageID))
_messageCallbacks.Remove(messageID);
}