WuhuIslandTesting/Library/PackageCache/com.unity.addressables@1.21.12/Editor/BuildReportVisualizer/ContentView/BundlesContentView.cs

482 lines
21 KiB
C#
Raw Normal View History

2025-01-07 02:06:59 +01:00
#if UNITY_2022_2_OR_NEWER
using System;
using System.Collections.Generic;
using UnityEditor.AddressableAssets.Build.Layout;
using UnityEditor.Build.Reporting;
using UnityEditor.UIElements;
using UnityEngine;
using UnityEngine.UIElements;
using BuildLayout = UnityEditor.AddressableAssets.Build.Layout.BuildLayout;
namespace UnityEditor.AddressableAssets.BuildReportVisualizer
{
// Nested class that represents a generic item in the bundle view (can be an asset, header, or bundle).
class BundlesViewBuildReportItem : IAddressablesBuildReportItem
{
public string Name { get; protected set; }
public ulong FileSize { get; protected set; }
public int RefsTo { get; protected set; }
public int RefsBy { get; protected set; }
public ulong FileSizeUncompressed { get; set; }
public ulong FileSizePlusRefs { get; set; }
public ulong FileSizeBundle { get; set; }
public int AssetsCount { get; set; }
public string GroupName { get; protected set; }
public virtual void CreateGUI(VisualElement rootVisualElement) { }
public virtual string GetCellContent(string colName)
{
if (colName == BuildReportUtility.BundlesContentViewColBundleName)
return Name;
else if (colName == BuildReportUtility.BundlesContentViewColSizePlusRefs)
{
if (FileSizePlusRefs == 0)
return "--";
return BuildReportUtility.GetDenominatedBytesString(FileSizePlusRefs);
}
if (colName == BuildReportUtility.BundlesContentViewColSizeUncompressed)
{
if (FileSizeUncompressed == 0)
return "--";
return BuildReportUtility.GetDenominatedBytesString(FileSizeUncompressed);
}
else if (colName == BuildReportUtility.BundlesContentViewBundleSize)
{
if (FileSizeBundle == 0)
return "--";
return BuildReportUtility.GetDenominatedBytesString(FileSizeBundle);
}
else if (colName == BuildReportUtility.BundlesContentViewColRefsTo)
{
if (RefsTo == -1)
return "--";
return RefsTo.ToString();
}
else if (colName == BuildReportUtility.BundlesContentViewColRefsBy)
{
if (RefsBy == -1)
return "--";
return RefsBy.ToString();
}
return "";
}
public string GetSortContent(string colName)
{
if (colName == BuildReportUtility.BundlesContentViewColSizePlusRefs)
return FileSizePlusRefs.ToString();
if (colName == BuildReportUtility.BundlesContentViewColSizeUncompressed)
return FileSizeUncompressed.ToString();
if (colName == BuildReportUtility.BundlesContentViewBundleSize)
return FileSizeBundle.ToString();
return GetCellContent(colName);
}
}
// Nested class that represents an bundle.
class BundlesViewBuildReportBundle : BundlesViewBuildReportItem, IAddressablesBuildReportBundle
{
public BuildLayout.Bundle Bundle { get; set; }
public List<BuildLayout.Bundle> Dependencies { get; set; }
public List<BuildLayout.Bundle> DependentBundles { get; set; }
public BundlesViewBuildReportBundle(BuildLayout.Bundle bundle)
{
Bundle = bundle;
Name = bundle.Name;
foreach (var file in bundle.Files)
RefsTo += file.Assets.Count + file.OtherAssets.Count;
RefsBy = bundle.DependentBundles.Count;
GroupName = bundle.Group?.Name;
Dependencies = bundle.Dependencies;
DependentBundles = bundle.DependentBundles;
foreach (var f in bundle.Files)
{
foreach (var ex in f.Assets)
ExplicitAssetsFromLayout.Add(ex);
}
FileSizeBundle = bundle.FileSize;
FileSizeUncompressed = bundle.UncompressedFileSize;
FileSizePlusRefs = bundle.FileSize + bundle.ExpandedDependencyFileSize + bundle.DependencyFileSize;
}
public List<BuildLayout.ExplicitAsset> ExplicitAssetsFromLayout = new List<BuildLayout.ExplicitAsset>();
public List<BuildLayout.ExplicitAsset> ExplicitAssets { get; set; }
public List<BuildLayout.DataFromOtherAsset> ImplicitAssets { get; set; }
}
class BundlesViewBuildReportAsset : BundlesViewBuildReportItem, IAddressablesBuildReportAsset
{
public BuildLayout.ExplicitAsset ExplicitAsset { get; }
public BuildLayout.DataFromOtherAsset DataFromOtherAsset { get; }
public List<BuildLayout.Bundle> Bundles { get;}
public string AssetPath { get; private set; }
public ulong SizeWDependencies { get; set; }
public bool IsAddressable = false;
public BundlesViewBuildReportAsset(BuildLayout.ExplicitAsset asset)
{
ExplicitAsset = asset;
Bundles = new List<BuildLayout.Bundle>(){ asset.Bundle };
Name = asset.AddressableName;
RefsTo = asset.InternalReferencedOtherAssets.Count + asset.ExternallyReferencedAssets.Count + asset.InternalReferencedExplicitAssets.Count;
RefsBy = asset.ReferencingAssets != null ? asset.ReferencingAssets.Count : -1;
FileSize = asset.SerializedSize + asset.StreamedSize;
AssetPath = asset.AssetPath;
IsAddressable = true;
FileSizeUncompressed = asset.SerializedSize + asset.StreamedSize;
FileSizePlusRefs = FileSizeUncompressed;
foreach (var r in asset.ExternallyReferencedAssets)
if (r != null)
FileSizePlusRefs += r.SerializedSize + r.StreamedSize;
foreach (var r in asset.InternalReferencedExplicitAssets)
if (r != null)
FileSizePlusRefs += r.SerializedSize + r.StreamedSize;
SizeWDependencies = FileSizePlusRefs;
}
public BundlesViewBuildReportAsset(BuildLayout.DataFromOtherAsset asset)
{
DataFromOtherAsset = asset;
Bundles = new List<BuildLayout.Bundle>() { asset.File.Bundle };
Name = asset.AssetPath;
AssetPath = asset.AssetPath;
RefsBy = asset.ReferencingAssets.Count;
RefsTo = -1;
IsAddressable = false;
FileSizeUncompressed = asset.SerializedSize + asset.StreamedSize;
FileSizePlusRefs = asset.SerializedSize + asset.StreamedSize;
SizeWDependencies = FileSizePlusRefs;
FileSizeBundle = 0;
}
}
class BundlesViewBuildReportUnrelatedAssets : BundlesViewBuildReportItem
{
public BundlesViewBuildReportUnrelatedAssets(ulong assetSize, int assetCount)
{
Name = $"({assetCount} unrelated assets)";
FileSizeUncompressed = assetSize;
}
}
class BundlesViewBuildReportIndirectlyReferencedBundles : BundlesViewBuildReportItem
{
public BundlesViewBuildReportIndirectlyReferencedBundles(List<BuildLayout.Bundle> bundles)
{
Name = bundles.Count > 1 ? $"{bundles.Count} indirectly referenced bundles" : $"{bundles.Count} indirectly referenced bundle";
FileSizeBundle = 0;
FileSizeUncompressed = 0;
HashSet<BuildLayout.Bundle> countedBundles = new HashSet<BuildLayout.Bundle>();
foreach (var b in bundles)
{
FileSizeBundle += b.FileSize;
FileSizeUncompressed += b.UncompressedFileSize;
if (!countedBundles.Contains(b))
{
FileSizePlusRefs += b.FileSize;
countedBundles.Add(b);
}
foreach (var depB in b.ExpandedDependencies)
{
if (!countedBundles.Contains(depB))
{
FileSizePlusRefs += depB.FileSize;
countedBundles.Add(depB);
}
}
foreach (var depB in b.Dependencies)
{
if (!countedBundles.Contains(depB))
{
FileSizePlusRefs += depB.FileSize;
countedBundles.Add(depB);
}
}
}
}
}
class BundlesContentView : ContentView
{
IList<TreeViewItemData<BundlesViewBuildReportItem>> m_TreeRoots;
public BundlesContentView(BuildReportHelperConsumer helperConsumer, DetailsView detailsView)
: base(helperConsumer, detailsView)
{
}
internal override ContentViewColumnData[] ColumnDataForView
{
get
{
return new ContentViewColumnData[]
{
new ContentViewColumnData(BuildReportUtility.BundlesContentViewColBundleName, this, true, "Bundle Name"),
new ContentViewColumnData(BuildReportUtility.BundlesContentViewColSizePlusRefs, this, false, "Total Size (+ refs)"),
new ContentViewColumnData(BuildReportUtility.BundlesContentViewColSizeUncompressed, this, false, "Uncompressed Size"),
new ContentViewColumnData(BuildReportUtility.BundlesContentViewBundleSize, this, false, "Bundle File Size"),
new ContentViewColumnData(BuildReportUtility.BundlesContentViewColRefsTo, this, false, "Refs To"),
new ContentViewColumnData(BuildReportUtility.BundlesContentViewColRefsBy, this, false, "Refs By"),
};
}
}
// Data about bundles from our currently selected build report.
public override IList<IAddressablesBuildReportItem> CreateTreeViewItems(BuildLayout report)
{
List<IAddressablesBuildReportItem> buildReportBundles = new List<IAddressablesBuildReportItem>();
if (report == null)
return buildReportBundles;
foreach (BuildLayout.Bundle bundle in BuildLayoutHelpers.EnumerateBundles(report))
{
var buildReportBundle = new BundlesViewBuildReportBundle(bundle);
var explicitAssets = new List<BuildLayout.ExplicitAsset>();
var implicitAssets = new List<BuildLayout.DataFromOtherAsset>();
foreach (BuildLayout.File file in bundle.Files)
{
foreach (BuildLayout.ExplicitAsset asset in file.Assets)
{
explicitAssets.Add(asset);
}
foreach (BuildLayout.DataFromOtherAsset asset in file.OtherAssets)
{
implicitAssets.Add(asset);
}
}
buildReportBundle.AssetsCount = explicitAssets.Count + implicitAssets.Count;
buildReportBundle.ExplicitAssets = explicitAssets;
buildReportBundle.ImplicitAssets = implicitAssets;
buildReportBundles.Add(buildReportBundle);
}
return buildReportBundles;
}
public override void Consume(BuildLayout buildReport)
{
if (buildReport == null)
return;
m_DataHashtoReportItem = new Dictionary<Hash128, TreeDataReportItem>();
m_Report = buildReport;
m_TreeItems = CreateTreeViewItems(m_Report);
IList<TreeViewItemData<BundlesViewBuildReportItem>> treeRoots = CreateTreeRootsNestedList(m_TreeItems, m_DataHashtoReportItem);
m_TreeView.SetRootItems(treeRoots);
m_TreeView.Rebuild();
m_TreeView.columnSortingChanged += ColumnSortingChanged;
}
private void ColumnSortingChanged()
{
var columnList = m_TreeView.sortedColumns;
IList<IAddressablesBuildReportItem> sortedRootList = new List<IAddressablesBuildReportItem>();
foreach (var col in columnList)
{
sortedRootList = SortByColumnDescription(col);
}
m_TreeView.SetRootItems(CreateTreeRootsNestedList(sortedRootList, m_DataHashtoReportItem));
m_TreeView.Rebuild();
}
public override void CreateGUI(VisualElement rootVisualElement)
{
VisualElement view = rootVisualElement.Q<VisualElement>(BuildReportUtility.ContentView);
TreeBuilder tb = new TreeBuilder()
.With(ColumnDataForView)
.With((items) => ItemsSelected.Invoke(items));
m_TreeView = tb.Build();
view.Add(m_TreeView);
SetCallbacksForColumns(m_TreeView.columns, ColumnDataForView);
m_SearchField = rootVisualElement.Q<ToolbarSearchField>(BuildReportUtility.SearchField);
m_SearchField.RegisterValueChangedCallback(OnSearchValueChanged);
m_SearchValue = m_SearchField.value;
}
private void OnSearchValueChanged(ChangeEvent<string> evt)
{
if (m_TreeItems == null)
return;
m_SearchValue = evt.newValue.ToLowerInvariant();
m_TreeRoots = CreateTreeRootsNestedList(m_TreeItems, m_DataHashtoReportItem);
m_TreeView.SetRootItems(m_TreeRoots);
m_TreeView.Rebuild();
}
// Expresses bundle data as a hierarchal list of BuildReportBundleViewItem objects.
public IList<TreeViewItemData<BundlesViewBuildReportItem>> CreateTreeRootsNestedList(IList<IAddressablesBuildReportItem> items, Dictionary<Hash128, TreeDataReportItem> dataHashToReportItem)
{
int id = 0;
var roots = new List<TreeViewItemData<BundlesViewBuildReportItem>>();
foreach (BundlesViewBuildReportItem item in items)
{
BundlesViewBuildReportBundle bundle = item as BundlesViewBuildReportBundle;
if (bundle == null)
continue;
bool includeAllDependencies = EntryAppearsInSearch(item, m_SearchValue);
var children = CreateChildrenOfBundle(bundle, ref id, includeAllDependencies);
if (children.Count > 0 || includeAllDependencies)
{
var rootItem = new TreeViewItemData<BundlesViewBuildReportItem>(++id, item, children);
dataHashToReportItem.TryAdd(BuildReportUtility.ComputeDataHash(item.Name), new TreeDataReportItem(id, rootItem.data));
roots.Add(rootItem);
}
}
return roots;
}
private List<TreeViewItemData<BundlesViewBuildReportItem>> CreateChildrenOfBundle(BundlesViewBuildReportBundle bundle, ref int id, bool includeAllDependencies)
{
var children = new List<TreeViewItemData<BundlesViewBuildReportItem>>();
var indirectlyReferencedBundleReportItems = new List<TreeViewItemData<BundlesViewBuildReportItem>>();
var indirectlyReferencedBundles = new List<BuildLayout.Bundle>();
CreateAssetEntries(children, out var bundlesReferencedByAssetEntries, bundle, ref id, includeAllDependencies);
foreach (var depBundle in bundle.Bundle.ExpandedDependencies)
{
if (!bundlesReferencedByAssetEntries.Contains(depBundle))
{
var reportBundle = new BundlesViewBuildReportBundle(depBundle);
if (includeAllDependencies || EntryAppearsInSearch(reportBundle, m_SearchValue))
{
indirectlyReferencedBundleReportItems.Add(new TreeViewItemData<BundlesViewBuildReportItem>(++id, reportBundle));
indirectlyReferencedBundles.Add(depBundle);
}
}
}
if (indirectlyReferencedBundles.Count > 0)
{
children.Add(new TreeViewItemData<BundlesViewBuildReportItem>(++id, new BundlesViewBuildReportIndirectlyReferencedBundles(indirectlyReferencedBundles), indirectlyReferencedBundleReportItems));
}
return children;
}
private void CreateAssetEntries(List<TreeViewItemData<BundlesViewBuildReportItem>> children, out HashSet<BuildLayout.Bundle> directlyReferencedBundles, BundlesViewBuildReportBundle bundle, ref int id, bool includeAllDependencies)
{
directlyReferencedBundles = new HashSet<BuildLayout.Bundle>();
foreach (var asset in bundle.ExplicitAssets)
{
if (asset == null)
continue;
var reportAsset = new BundlesViewBuildReportAsset(asset);
bool includeAsset = EntryAppearsInSearch(reportAsset, m_SearchValue);
var childrenOfAsset = GenerateChildrenOfAsset(asset, ref id, directlyReferencedBundles, includeAllDependencies || includeAsset);
if (includeAsset || includeAllDependencies || childrenOfAsset.Count > 0)
{
var dataItem = new TreeViewItemData<BundlesViewBuildReportItem>(++id, reportAsset, childrenOfAsset);
m_DataHashtoReportItem.TryAdd(BuildReportUtility.ComputeDataHash(bundle.Name, asset.AddressableName), new TreeDataReportItem(id, dataItem.data));
children.Add(dataItem);
}
}
foreach (var asset in bundle.ImplicitAssets)
{
if (asset == null)
continue;
var reportAsset = new BundlesViewBuildReportAsset(asset);
if (EntryAppearsInSearch(reportAsset, m_SearchValue) || includeAllDependencies)
{
children.Add(new TreeViewItemData<BundlesViewBuildReportItem>(++id, reportAsset));
}
}
}
private List<TreeViewItemData<BundlesViewBuildReportItem>> GenerateChildrenOfAsset(BuildLayout.ExplicitAsset asset, ref int id, HashSet<BuildLayout.Bundle> referencedBundles, bool includeAllDependencies)
{
var childrenOfAsset = new List<TreeViewItemData<BundlesViewBuildReportItem>>();
Dictionary<BuildLayout.Bundle, List<BuildLayout.ExplicitAsset>> bundleToAssetList = new Dictionary<BuildLayout.Bundle, List<BuildLayout.ExplicitAsset>>();
foreach (var dep in asset.InternalReferencedExplicitAssets)
{
var reportAsset = new BundlesViewBuildReportAsset(dep);
if (EntryAppearsInSearch(reportAsset, m_SearchValue) || includeAllDependencies)
{
childrenOfAsset.Add(new TreeViewItemData<BundlesViewBuildReportItem>(++id, reportAsset));
}
}
foreach (var dep in asset.ExternallyReferencedAssets)
{
if (!bundleToAssetList.ContainsKey(dep.Bundle))
{
bundleToAssetList.Add(dep.Bundle, new List<BuildLayout.ExplicitAsset>());
referencedBundles.Add(dep.Bundle);
}
bundleToAssetList[dep.Bundle].Add(dep);
}
foreach (var bundle in bundleToAssetList.Keys)
{
var reportBundle = new BundlesViewBuildReportBundle(bundle);
bool bundleIncludedInSearch = EntryAppearsInSearch(reportBundle, m_SearchValue) || includeAllDependencies;
var assetTreeViewItems = new List<TreeViewItemData<BundlesViewBuildReportItem>>();
var assetList = bundleToAssetList[bundle];
ulong unrelatedAssetSize = bundle.FileSize;
foreach (var bundleAsset in assetList)
{
var reportBundleAsset = new BundlesViewBuildReportAsset(bundleAsset);
if (bundleIncludedInSearch || EntryAppearsInSearch(reportBundleAsset, m_SearchValue))
{
assetTreeViewItems.Add(new TreeViewItemData<BundlesViewBuildReportItem>(++id, reportBundleAsset));
unrelatedAssetSize -= bundleAsset.SerializedSize + bundleAsset.StreamedSize;
}
}
int unrelatedAssetCount = bundle.AssetCount - assetList.Count;
if (unrelatedAssetCount > 0 && bundleIncludedInSearch)
assetTreeViewItems.Add(new TreeViewItemData<BundlesViewBuildReportItem>(++id, new BundlesViewBuildReportUnrelatedAssets(unrelatedAssetSize, unrelatedAssetCount)));
if (bundleIncludedInSearch || assetTreeViewItems.Count > 0)
{
childrenOfAsset.Add(new TreeViewItemData<BundlesViewBuildReportItem>(++id, reportBundle, assetTreeViewItems));
}
}
foreach (var dep in asset.InternalReferencedOtherAssets)
{
var reportAsset = new BundlesViewBuildReportAsset(dep);
if (EntryAppearsInSearch(reportAsset, m_SearchValue) || includeAllDependencies)
{
childrenOfAsset.Add(new TreeViewItemData<BundlesViewBuildReportItem>(++id, reportAsset));
}
}
return childrenOfAsset;
}
}
}
#endif