398 lines
17 KiB
C#
398 lines
17 KiB
C#
#if UNITY_2022_2_OR_NEWER
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using UnityEditor.AddressableAssets.Build.Layout;
|
|
using UnityEditor.UIElements;
|
|
using UnityEngine;
|
|
using UnityEngine.UIElements;
|
|
using static UnityEditor.AddressableAssets.BuildReportVisualizer.BuildReportWindow;
|
|
|
|
namespace UnityEditor.AddressableAssets.BuildReportVisualizer
|
|
{
|
|
internal class LabelsViewBuildReportItem : IAddressablesBuildReportItem
|
|
{
|
|
public string Name { get; protected set; }
|
|
|
|
public ulong FileSizePlusRefs { get; set; }
|
|
|
|
public ulong FileSizeUncompressed { get; set; }
|
|
|
|
public ulong FileSizeBundle { get; set; }
|
|
|
|
public int RefsBy { get; set; }
|
|
|
|
public int RefsTo { get; set; }
|
|
|
|
|
|
public virtual void CreateGUI(VisualElement rootVisualElement) { }
|
|
|
|
public virtual string GetCellContent(string colName)
|
|
{
|
|
if (colName == BuildReportUtility.LabelsContentViewColLabelName)
|
|
return Name;
|
|
else if (colName == BuildReportUtility.LabelsContentViewColSizePlusRefs)
|
|
{
|
|
if (FileSizePlusRefs == 0)
|
|
return "--";
|
|
return BuildReportUtility.GetDenominatedBytesString(FileSizePlusRefs);
|
|
}
|
|
else if (colName == BuildReportUtility.LabelsContentViewColSizeUncompressed)
|
|
{
|
|
if (FileSizeUncompressed == 0)
|
|
return "--";
|
|
return BuildReportUtility.GetDenominatedBytesString(FileSizeUncompressed);
|
|
}
|
|
else if (colName == BuildReportUtility.LabelsContentViewColSizeBundle)
|
|
{
|
|
if (FileSizeBundle == 0)
|
|
return "--";
|
|
return BuildReportUtility.GetDenominatedBytesString(FileSizeBundle);
|
|
}
|
|
else if (colName == BuildReportUtility.LabelsContentViewColRefsTo)
|
|
{
|
|
if (RefsTo == -1)
|
|
return "--";
|
|
return RefsTo.ToString();
|
|
}
|
|
else if (colName == BuildReportUtility.LabelsContentViewColRefsBy)
|
|
{
|
|
if (RefsBy == -1)
|
|
return "--";
|
|
return RefsBy.ToString();
|
|
}
|
|
|
|
return "";
|
|
}
|
|
|
|
public virtual string GetSortContent(string colName)
|
|
{
|
|
if (colName == BuildReportUtility.LabelsContentViewColSizePlusRefs)
|
|
return FileSizePlusRefs.ToString();
|
|
if (colName == BuildReportUtility.LabelsContentViewColSizeUncompressed)
|
|
return FileSizeUncompressed.ToString();
|
|
if (colName == BuildReportUtility.LabelsContentViewColSizeBundle)
|
|
return FileSizeBundle.ToString();
|
|
if (colName == BuildReportUtility.LabelsContentViewColRefsBy)
|
|
return RefsBy.ToString();
|
|
if (colName == BuildReportUtility.LabelsContentViewColRefsTo)
|
|
return RefsTo.ToString();
|
|
return GetCellContent(colName);
|
|
}
|
|
}
|
|
|
|
internal class LabelsViewBuildReportLabel : LabelsViewBuildReportItem
|
|
{
|
|
public ulong SizeWDependencies { get; set; }
|
|
public List<BuildLayout.ExplicitAsset> BuildReportAssets { get; set; }
|
|
|
|
public LabelsViewBuildReportLabel(string name, List<BuildLayout.ExplicitAsset> reportAssets)
|
|
{
|
|
Name = name;
|
|
BuildReportAssets = reportAssets;
|
|
FileSizePlusRefs = 0;
|
|
FileSizeBundle = 0;
|
|
RefsBy = -1;
|
|
RefsTo = reportAssets.Count;
|
|
var seenBundles = new HashSet<BuildLayout.Bundle>();
|
|
foreach (var reportItem in reportAssets)
|
|
{
|
|
FileSizePlusRefs += reportItem.SerializedSize + reportItem.StreamedSize;
|
|
if (!seenBundles.Contains(reportItem.Bundle))
|
|
{
|
|
seenBundles.Add(reportItem.Bundle);
|
|
FileSizeBundle += reportItem.Bundle.FileSize;
|
|
}
|
|
|
|
foreach (var dep in reportItem.ExternallyReferencedAssets)
|
|
{
|
|
FileSizePlusRefs += dep.SerializedSize + dep.StreamedSize;
|
|
if (!seenBundles.Contains(dep.Bundle))
|
|
{
|
|
seenBundles.Add(dep.Bundle);
|
|
FileSizeBundle += dep.Bundle.FileSize;
|
|
}
|
|
}
|
|
}
|
|
FileSizeUncompressed = FileSizePlusRefs;
|
|
}
|
|
}
|
|
|
|
internal class LabelsViewBuildReportAsset : LabelsViewBuildReportItem, IAddressablesBuildReportAsset
|
|
{
|
|
public BuildLayout.ExplicitAsset ExplicitAsset { get; }
|
|
|
|
public BuildLayout.DataFromOtherAsset DataFromOtherAsset { get; }
|
|
|
|
public List<BuildLayout.ExplicitAsset> InternallyReferencedAssets { get; }
|
|
|
|
public List<BuildLayout.ExplicitAsset> ExternallyReferencedAssets { get; }
|
|
|
|
List<BuildLayout.ExplicitAsset> ReferencingAssets { get; }
|
|
public List<BuildLayout.DataFromOtherAsset> ImplicitDependencies { get; }
|
|
public List<BuildLayout.Bundle> Bundles { get; }
|
|
public ulong SizeWDependencies { get; }
|
|
|
|
public bool IsAddressable => ExplicitAsset != null;
|
|
|
|
public LabelsViewBuildReportAsset(BuildLayout.ExplicitAsset asset)
|
|
{
|
|
ExplicitAsset = asset;
|
|
Name = asset.AddressableName;
|
|
ExternallyReferencedAssets = asset.ExternallyReferencedAssets;
|
|
InternallyReferencedAssets = asset.InternalReferencedExplicitAssets;
|
|
ImplicitDependencies = asset.InternalReferencedOtherAssets;
|
|
ReferencingAssets = asset.ReferencingAssets;
|
|
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;
|
|
RefsTo = asset.ExternallyReferencedAssets.Count + asset.InternalReferencedExplicitAssets.Count;
|
|
RefsBy = asset.ReferencingAssets != null ? asset.ReferencingAssets.Count : -1;
|
|
}
|
|
|
|
public LabelsViewBuildReportAsset(BuildLayout.DataFromOtherAsset asset)
|
|
{
|
|
DataFromOtherAsset = asset;
|
|
Bundles = new List<BuildLayout.Bundle>() { asset.File.Bundle };
|
|
Name = asset.AssetPath;
|
|
RefsBy = asset.ReferencingAssets.Count;
|
|
RefsTo = -1;
|
|
FileSizeUncompressed = asset.SerializedSize + asset.StreamedSize;
|
|
FileSizePlusRefs = asset.SerializedSize + asset.StreamedSize;
|
|
}
|
|
}
|
|
|
|
internal class LabelsViewBuildReportBundle : LabelsViewBuildReportItem, IAddressablesBuildReportBundle
|
|
{
|
|
public LabelsViewBuildReportBundle(BuildLayout.Bundle bundle)
|
|
{
|
|
Name = bundle.Name;
|
|
Bundle = bundle;
|
|
FileSizePlusRefs = bundle.FileSize + bundle.ExpandedDependencyFileSize + bundle.DependencyFileSize;
|
|
FileSizeBundle = bundle.FileSize;
|
|
FileSizeUncompressed = bundle.UncompressedFileSize;
|
|
RefsTo = Bundle.ExpandedDependencies.Count;
|
|
RefsBy = Bundle.DependentBundles.Count;
|
|
}
|
|
|
|
public BuildLayout.Bundle Bundle { get; }
|
|
}
|
|
|
|
internal class LabelsViewBuildReportUnrelatedAssets : LabelsViewBuildReportItem
|
|
{
|
|
public LabelsViewBuildReportUnrelatedAssets(ulong assetSize, int assetCount)
|
|
{
|
|
Name = $"({assetCount} unrelated assets)";
|
|
FileSizeUncompressed = assetSize;
|
|
}
|
|
}
|
|
|
|
class LabelsContentView : ContentView
|
|
{
|
|
public LabelsContentView(BuildReportHelperConsumer helperConsumer, DetailsView detailsView)
|
|
: base(helperConsumer, detailsView) { }
|
|
|
|
internal override ContentViewColumnData[] ColumnDataForView
|
|
{
|
|
get
|
|
{
|
|
return new ContentViewColumnData[]
|
|
{
|
|
new ContentViewColumnData(BuildReportUtility.LabelsContentViewColLabelName, this, true, "Label Name"),
|
|
new ContentViewColumnData(BuildReportUtility.LabelsContentViewColSizePlusRefs, this, false, "Total Size (+ refs)"),
|
|
new ContentViewColumnData(BuildReportUtility.LabelsContentViewColSizeUncompressed, this, false, "Uncompressed Size"),
|
|
new ContentViewColumnData(BuildReportUtility.LabelsContentViewColSizeBundle, this, false, "Bundle File Size"),
|
|
new ContentViewColumnData(BuildReportUtility.LabelsContentViewColRefsTo, this, false, "Refs To"),
|
|
new ContentViewColumnData(BuildReportUtility.LabelsContentViewColRefsBy, this, false, "Refs By")
|
|
};
|
|
}
|
|
}
|
|
|
|
public override IList<IAddressablesBuildReportItem> CreateTreeViewItems(BuildLayout report)
|
|
{
|
|
List<IAddressablesBuildReportItem> buildReportLabels = new List<IAddressablesBuildReportItem>();
|
|
if (report == null)
|
|
return buildReportLabels;
|
|
|
|
var labelToAssets = new Dictionary<string, List<BuildLayout.ExplicitAsset>>();
|
|
foreach (var asset in BuildLayoutHelpers.EnumerateAssets(report))
|
|
{
|
|
foreach (string label in asset.Labels)
|
|
{
|
|
if (labelToAssets.ContainsKey(label))
|
|
labelToAssets[label].Add(asset);
|
|
else
|
|
labelToAssets.Add(label, new List<BuildLayout.ExplicitAsset> { asset });
|
|
}
|
|
}
|
|
|
|
foreach (var pair in labelToAssets)
|
|
{
|
|
buildReportLabels.Add(new LabelsViewBuildReportLabel(pair.Key, pair.Value));
|
|
}
|
|
|
|
return buildReportLabels;
|
|
}
|
|
|
|
IList<TreeViewItemData<LabelsViewBuildReportItem>> CreateTreeRootsNestedList(IList<IAddressablesBuildReportItem> items)
|
|
{
|
|
int id = 0;
|
|
var roots = new List<TreeViewItemData<LabelsViewBuildReportItem>>();
|
|
foreach (var item in items)
|
|
{
|
|
var label = item as LabelsViewBuildReportLabel;
|
|
if (label == null)
|
|
continue;
|
|
|
|
bool includeAllDependencies = EntryAppearsInSearch(label, m_SearchValue);
|
|
|
|
var assetsUnderLabel = new List<TreeViewItemData<LabelsViewBuildReportItem>>();
|
|
foreach (var asset in label.BuildReportAssets)
|
|
{
|
|
var assetReportItem = new LabelsViewBuildReportAsset(asset);
|
|
bool assetAppearsInSearch = EntryAppearsInSearch(assetReportItem, m_SearchValue) || includeAllDependencies;
|
|
var childrenOfAsset = GenerateChildrenOfAsset(asset, ref id, assetAppearsInSearch);
|
|
if (assetAppearsInSearch || childrenOfAsset.Count > 0)
|
|
{
|
|
var tvid = new TreeViewItemData<LabelsViewBuildReportItem>(++id, assetReportItem, childrenOfAsset);
|
|
m_DataHashtoReportItem.TryAdd(BuildReportUtility.ComputeDataHash(label.Name, asset.AddressableName), new TreeDataReportItem(id, tvid.data));
|
|
assetsUnderLabel.Add(tvid);
|
|
}
|
|
}
|
|
|
|
if (includeAllDependencies || assetsUnderLabel.Count > 0)
|
|
{
|
|
var rootItem = new TreeViewItemData<LabelsViewBuildReportItem>(++id, label, assetsUnderLabel);
|
|
m_DataHashtoReportItem.TryAdd(BuildReportUtility.ComputeDataHash(label.Name), new TreeDataReportItem(id, rootItem.data));
|
|
roots.Add(rootItem);
|
|
}
|
|
}
|
|
|
|
return roots;
|
|
}
|
|
|
|
private List<TreeViewItemData<LabelsViewBuildReportItem>> GenerateChildrenOfAsset(BuildLayout.ExplicitAsset asset, ref int id, bool includeAllDependencies)
|
|
{
|
|
var childrenOfAsset = new List<TreeViewItemData<LabelsViewBuildReportItem>>();
|
|
foreach (var dep in asset.InternalReferencedExplicitAssets)
|
|
{
|
|
var reportDepAsset = new LabelsViewBuildReportAsset(dep);
|
|
if (includeAllDependencies || EntryAppearsInSearch(reportDepAsset, m_SearchValue))
|
|
{
|
|
var tvid = new TreeViewItemData<LabelsViewBuildReportItem>(++id, reportDepAsset);
|
|
childrenOfAsset.Add(tvid);
|
|
}
|
|
}
|
|
|
|
Dictionary<BuildLayout.Bundle, List<BuildLayout.ExplicitAsset>> bundleToAssetList = new Dictionary<BuildLayout.Bundle, List<BuildLayout.ExplicitAsset>>();
|
|
foreach (var dep in asset.ExternallyReferencedAssets)
|
|
{
|
|
if (!bundleToAssetList.ContainsKey(dep.Bundle))
|
|
bundleToAssetList.Add(dep.Bundle, new List<BuildLayout.ExplicitAsset>());
|
|
bundleToAssetList[dep.Bundle].Add(dep);
|
|
}
|
|
|
|
foreach (var bundle in bundleToAssetList.Keys)
|
|
{
|
|
var bundleReportAsset = new LabelsViewBuildReportBundle(bundle);
|
|
bool includeAllDependenciesUnderBundle = EntryAppearsInSearch(bundleReportAsset, m_SearchValue) || includeAllDependencies;
|
|
var assetTreeViewItems = new List<TreeViewItemData<LabelsViewBuildReportItem>>();
|
|
var assetList = bundleToAssetList[bundle];
|
|
ulong unrelatedAssetSize = bundle.FileSize;
|
|
foreach (var bundleAsset in assetList)
|
|
{
|
|
var reportAsset = new LabelsViewBuildReportAsset(bundleAsset);
|
|
if (includeAllDependenciesUnderBundle || EntryAppearsInSearch(reportAsset, m_SearchValue))
|
|
{
|
|
var tvid = new TreeViewItemData<LabelsViewBuildReportItem>(++id, reportAsset);
|
|
assetTreeViewItems.Add(tvid);
|
|
unrelatedAssetSize -= bundleAsset.SerializedSize + bundleAsset.StreamedSize;
|
|
}
|
|
}
|
|
|
|
int unrelatedAssetCount = bundle.AssetCount - assetList.Count;
|
|
if (unrelatedAssetCount > 0 && includeAllDependenciesUnderBundle)
|
|
{
|
|
var tvid = new TreeViewItemData<LabelsViewBuildReportItem>(++id, new LabelsViewBuildReportUnrelatedAssets(unrelatedAssetSize, unrelatedAssetCount));
|
|
assetTreeViewItems.Add(tvid);
|
|
}
|
|
|
|
if (includeAllDependenciesUnderBundle || assetTreeViewItems.Count > 0)
|
|
{
|
|
var rootItem = new TreeViewItemData<LabelsViewBuildReportItem>(++id, bundleReportAsset, assetTreeViewItems);
|
|
childrenOfAsset.Add(rootItem);
|
|
}
|
|
}
|
|
|
|
foreach (var dep in asset.InternalReferencedOtherAssets)
|
|
{
|
|
var reportDepAsset = new LabelsViewBuildReportAsset(dep);
|
|
if (includeAllDependencies || EntryAppearsInSearch(reportDepAsset, m_SearchValue))
|
|
{
|
|
var tvid = new TreeViewItemData<LabelsViewBuildReportItem>(++id, reportDepAsset);
|
|
childrenOfAsset.Add(tvid);
|
|
}
|
|
}
|
|
|
|
return childrenOfAsset;
|
|
}
|
|
|
|
public override void Consume(BuildLayout buildReport)
|
|
{
|
|
if (buildReport == null)
|
|
return;
|
|
|
|
m_Report = buildReport;
|
|
m_TreeItems = CreateTreeViewItems(m_Report);
|
|
m_DataHashtoReportItem = new Dictionary<Hash128, TreeDataReportItem>();
|
|
IList<TreeViewItemData<LabelsViewBuildReportItem>> treeRoots = CreateTreeRootsNestedList(m_TreeItems);
|
|
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_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.ToLower();
|
|
m_TreeView.SetRootItems(CreateTreeRootsNestedList(m_TreeItems));
|
|
m_TreeView.Rebuild();
|
|
}
|
|
|
|
}
|
|
}
|
|
#endif
|