initial commit
This commit is contained in:
parent
6715289efe
commit
788c3389af
37645 changed files with 2526849 additions and 80 deletions
|
|
@ -0,0 +1,386 @@
|
|||
#if UNITY_2022_2_OR_NEWER
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using UnityEditor.AddressableAssets.Build.Layout;
|
||||
using UnityEditor.UIElements;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UIElements;
|
||||
|
||||
namespace UnityEditor.AddressableAssets.BuildReportVisualizer
|
||||
{
|
||||
|
||||
public class AssetsViewBuildReportItem : IAddressablesBuildReportItem
|
||||
{
|
||||
public string Name { get; set; }
|
||||
|
||||
public string BundleName { get; set; }
|
||||
|
||||
public string GroupName { get; set; }
|
||||
|
||||
public ulong FileSizePlusRefs { get; set; }
|
||||
|
||||
public ulong FileSizeUncompressed { get; set; }
|
||||
|
||||
public ulong BundleSize { get; set; }
|
||||
|
||||
public int RefsTo { get; set; }
|
||||
|
||||
public int RefsBy { get; set; }
|
||||
|
||||
public BuildLayout.ExplicitAsset ExplicitAsset { get; set; }
|
||||
|
||||
public BuildLayout.DataFromOtherAsset DataFromOtherAsset { get; set; }
|
||||
|
||||
public BuildLayout.Bundle Bundle { get; set; }
|
||||
|
||||
public List<BuildLayout.Bundle> Bundles { get; set; }
|
||||
|
||||
public ulong SizeWDependencies => 9999;
|
||||
|
||||
public virtual void CreateGUI(VisualElement rootVisualElement) { }
|
||||
|
||||
public virtual string GetCellContent(string colName)
|
||||
{
|
||||
if (colName == BuildReportUtility.AssetsContentViewColAssetName)
|
||||
return Name;
|
||||
else if (colName == BuildReportUtility.AssetsContentViewColSizePlusRefs)
|
||||
{
|
||||
if (FileSizePlusRefs == 0)
|
||||
return "--";
|
||||
return BuildReportUtility.GetDenominatedBytesString(FileSizePlusRefs);
|
||||
}
|
||||
else if (colName == BuildReportUtility.AssetsContentViewColSizeUncompressed)
|
||||
{
|
||||
if (FileSizeUncompressed == 0)
|
||||
return "--";
|
||||
return BuildReportUtility.GetDenominatedBytesString(FileSizeUncompressed);
|
||||
}
|
||||
else if (colName == BuildReportUtility.AssetsContentViewColBundleSize)
|
||||
{
|
||||
if (BundleSize == 0)
|
||||
return "--";
|
||||
return BuildReportUtility.GetDenominatedBytesString(BundleSize);
|
||||
}
|
||||
else if (colName == BuildReportUtility.AssetsContentViewColRefsTo)
|
||||
{
|
||||
if (RefsTo == -1)
|
||||
return "--";
|
||||
return RefsTo.ToString();
|
||||
}
|
||||
else if (colName == BuildReportUtility.AssetsContentViewColRefsBy)
|
||||
{
|
||||
if (RefsBy == -1)
|
||||
return "--";
|
||||
return RefsBy.ToString();
|
||||
}
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
public string GetSortContent(string colName)
|
||||
{
|
||||
if (colName == BuildReportUtility.AssetsContentViewColSizePlusRefs)
|
||||
return FileSizePlusRefs.ToString();
|
||||
if (colName == BuildReportUtility.AssetsContentViewColSizeUncompressed)
|
||||
return FileSizeUncompressed.ToString();
|
||||
if (colName == BuildReportUtility.AssetsContentViewColBundleSize)
|
||||
return BundleSize.ToString();
|
||||
return GetCellContent(colName);
|
||||
}
|
||||
}
|
||||
|
||||
public class AssetsViewTypeHeader : AssetsViewBuildReportItem
|
||||
{
|
||||
public AssetsViewTypeHeader(string name)
|
||||
{
|
||||
Name = name;
|
||||
}
|
||||
|
||||
public override string GetCellContent(string colName)
|
||||
{
|
||||
if (colName == BuildReportUtility.AssetsContentViewColAssetName)
|
||||
return Name;
|
||||
else
|
||||
{
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
public override void CreateGUI(VisualElement rootVisualElement)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public class AssetsViewBuildReportBundle : AssetsViewBuildReportItem, IAddressablesBuildReportBundle
|
||||
{
|
||||
public AssetsViewBuildReportBundle(BuildLayout.Bundle bundle)
|
||||
{
|
||||
Name = bundle.Name;
|
||||
Bundle = bundle;
|
||||
BundleSize = bundle.FileSize;
|
||||
GroupName = bundle.Group.Name;
|
||||
BundleName = "";
|
||||
FileSizePlusRefs = bundle.FileSize;
|
||||
foreach (var b in Bundle.ExpandedDependencies)
|
||||
FileSizePlusRefs += b.FileSize;
|
||||
RefsTo = Bundle.ExpandedDependencies.Count;
|
||||
RefsBy = Bundle.DependentBundles.Count;
|
||||
}
|
||||
}
|
||||
|
||||
public class AssetsViewBuildReportUnrelatedAssets : AssetsViewBuildReportItem
|
||||
{
|
||||
public AssetsViewBuildReportUnrelatedAssets(ulong assetSize, int assetCount)
|
||||
{
|
||||
Name = $"({assetCount} unrelated assets)";
|
||||
FileSizeUncompressed = assetSize;
|
||||
GroupName = "";
|
||||
BundleName = "";
|
||||
}
|
||||
}
|
||||
|
||||
public class AssetsViewBuildReportAsset : AssetsViewBuildReportItem, IAddressablesBuildReportAsset
|
||||
{
|
||||
public List<BuildLayout.ExplicitAsset> InternallyReferencedAssets { get; }
|
||||
|
||||
public List<BuildLayout.ExplicitAsset> ExternallyReferencedAssets { get; }
|
||||
|
||||
public List<BuildLayout.DataFromOtherAsset> ImplicitDependencies { get; }
|
||||
|
||||
|
||||
List<BuildLayout.ExplicitAsset> ReferencingAssets { get; }
|
||||
|
||||
|
||||
public AssetsViewBuildReportAsset(BuildLayout.ExplicitAsset asset)
|
||||
{
|
||||
ExplicitAsset = asset;
|
||||
Name = asset.AddressableName;
|
||||
Bundle = asset.Bundle;
|
||||
Bundles = new List<BuildLayout.Bundle>(){ Bundle };
|
||||
BundleName = asset.Bundle?.Name;
|
||||
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 + asset.StreamedSize;
|
||||
foreach (var r in asset.InternalReferencedExplicitAssets)
|
||||
if (r != null)
|
||||
FileSizePlusRefs += r.SerializedSize + asset.StreamedSize;
|
||||
foreach (var r in asset.InternalReferencedOtherAssets)
|
||||
if (r != null)
|
||||
FileSizePlusRefs += r.SerializedSize + asset.StreamedSize;
|
||||
RefsTo = asset.ExternallyReferencedAssets.Count + asset.InternalReferencedExplicitAssets.Count + asset.InternalReferencedOtherAssets.Count;
|
||||
RefsBy = asset.ReferencingAssets != null ? asset.ReferencingAssets.Count : -1;
|
||||
}
|
||||
|
||||
public AssetsViewBuildReportAsset(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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
class AssetsContentView : ContentView
|
||||
{
|
||||
public AssetsContentView(BuildReportHelperConsumer helperConsumer, DetailsView detailsView)
|
||||
: base(helperConsumer, detailsView)
|
||||
{
|
||||
m_DataHashtoReportItem = new Dictionary<Hash128, TreeDataReportItem>();
|
||||
}
|
||||
|
||||
internal override ContentViewColumnData[] ColumnDataForView
|
||||
{
|
||||
get
|
||||
{
|
||||
return new ContentViewColumnData[]
|
||||
{
|
||||
new ContentViewColumnData(BuildReportUtility.AssetsContentViewColAssetName, this, true, "Asset Name"),
|
||||
new ContentViewColumnData(BuildReportUtility.AssetsContentViewColSizePlusRefs, this, false, "Total Size (+ refs)"),
|
||||
new ContentViewColumnData(BuildReportUtility.AssetsContentViewColSizeUncompressed, this, false, "Uncompressed Size"),
|
||||
new ContentViewColumnData(BuildReportUtility.AssetsContentViewColBundleSize, this, false, "Bundle File Size"),
|
||||
new ContentViewColumnData(BuildReportUtility.AssetsContentViewColRefsTo, this, false, "Refs To"),
|
||||
new ContentViewColumnData(BuildReportUtility.AssetsContentViewColRefsBy, this, false, "Refs By")
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
// Data about assets from our currently selected build report.
|
||||
public override IList<IAddressablesBuildReportItem> CreateTreeViewItems(BuildLayout report)
|
||||
{
|
||||
List<IAddressablesBuildReportItem> buildReportAssets = new List<IAddressablesBuildReportItem>();
|
||||
if (report == null)
|
||||
return buildReportAssets;
|
||||
|
||||
foreach (BuildLayout.ExplicitAsset asset in BuildLayoutHelpers.EnumerateAssets(report))
|
||||
buildReportAssets.Add(new AssetsViewBuildReportAsset(asset));
|
||||
|
||||
foreach (BuildLayout.DataFromOtherAsset implicitAsset in BuildLayoutHelpers.EnumerateImplicitAssets(report))
|
||||
buildReportAssets.Add(new AssetsViewBuildReportAsset(implicitAsset));
|
||||
|
||||
return buildReportAssets;
|
||||
}
|
||||
|
||||
|
||||
public override void Consume(BuildLayout buildReport)
|
||||
{
|
||||
if (buildReport == null)
|
||||
return;
|
||||
|
||||
m_Report = buildReport;
|
||||
m_TreeItems = CreateTreeViewItems(m_Report);
|
||||
m_TreeView.SetRootItems(CreateTreeRootsNestedList(m_TreeItems));
|
||||
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_DataHashtoReportItem = new Dictionary<Hash128, TreeDataReportItem>();
|
||||
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();
|
||||
}
|
||||
|
||||
public IList<TreeViewItemData<AssetsViewBuildReportItem>> CreateTreeRootsNestedList(IList<IAddressablesBuildReportItem> items)
|
||||
{
|
||||
int id = 0;
|
||||
var roots = new List<TreeViewItemData<AssetsViewBuildReportItem>>(items.Count);
|
||||
foreach (AssetsViewBuildReportItem item in items)
|
||||
{
|
||||
AssetsViewBuildReportAsset asset = item as AssetsViewBuildReportAsset;
|
||||
|
||||
if (asset == null)
|
||||
continue;
|
||||
|
||||
bool includeAllDependencies = EntryAppearsInSearch(asset, m_SearchValue);
|
||||
|
||||
bool assetIsExplicitAsset = asset.ExplicitAsset != null;
|
||||
if (assetIsExplicitAsset)
|
||||
{
|
||||
var children = CreateChildrenOfAsset(asset, ref id, includeAllDependencies);
|
||||
|
||||
if (children.Count > 0 || EntryAppearsInSearch(asset, m_SearchValue))
|
||||
roots.Add(new TreeViewItemData<AssetsViewBuildReportItem>(++id, item, children));
|
||||
}
|
||||
else if (includeAllDependencies)
|
||||
{
|
||||
roots.Add(new TreeViewItemData<AssetsViewBuildReportItem>(++id, item));
|
||||
}
|
||||
}
|
||||
|
||||
return roots;
|
||||
}
|
||||
|
||||
List<TreeViewItemData<AssetsViewBuildReportItem>> CreateChildrenOfAsset(AssetsViewBuildReportAsset asset, ref int id, bool includeAllDependencies)
|
||||
{
|
||||
var children = new List<TreeViewItemData<AssetsViewBuildReportItem>>();
|
||||
|
||||
PopulateInternallyReferencedEntries(children, asset, ref id, includeAllDependencies);
|
||||
PopulateExternallyReferencedEntries(children, asset, ref id, includeAllDependencies);
|
||||
PopulateImplicitEntries(children, asset, ref id, includeAllDependencies);
|
||||
|
||||
return children;
|
||||
}
|
||||
|
||||
void PopulateInternallyReferencedEntries(List<TreeViewItemData<AssetsViewBuildReportItem>> children, AssetsViewBuildReportAsset asset, ref int id, bool includeAllDependencies)
|
||||
{
|
||||
foreach (var dep in asset.InternallyReferencedAssets)
|
||||
{
|
||||
var buildReportAsset = new AssetsViewBuildReportAsset(dep);
|
||||
if (EntryAppearsInSearch(buildReportAsset, m_SearchValue) || includeAllDependencies)
|
||||
children.Add(new TreeViewItemData<AssetsViewBuildReportItem>(++id, buildReportAsset));
|
||||
}
|
||||
}
|
||||
|
||||
void PopulateExternallyReferencedEntries(List<TreeViewItemData<AssetsViewBuildReportItem>> children, AssetsViewBuildReportAsset asset, ref int id, bool includeAllDependencies)
|
||||
{
|
||||
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 assetTreeViewItems = new List<TreeViewItemData<AssetsViewBuildReportItem>>();
|
||||
var assetList = bundleToAssetList[bundle];
|
||||
ulong unrelatedAssetSize = bundle.FileSize;
|
||||
foreach (var bundleAsset in assetList)
|
||||
{
|
||||
var bundleReportAsset = new AssetsViewBuildReportAsset(bundleAsset);
|
||||
if (includeAllDependencies || EntryAppearsInSearch(bundleReportAsset, m_SearchValue))
|
||||
assetTreeViewItems.Add(new TreeViewItemData<AssetsViewBuildReportItem>(++id, bundleReportAsset));
|
||||
|
||||
unrelatedAssetSize -= (bundleAsset.SerializedSize + bundleAsset.StreamedSize);
|
||||
}
|
||||
|
||||
int unrelatedAssetCount = bundle.AssetCount - assetList.Count;
|
||||
if (unrelatedAssetCount > 0 && includeAllDependencies)
|
||||
assetTreeViewItems.Add(new TreeViewItemData<AssetsViewBuildReportItem>(++id, new AssetsViewBuildReportUnrelatedAssets(unrelatedAssetSize, unrelatedAssetCount)));
|
||||
|
||||
if (includeAllDependencies || assetTreeViewItems.Count > 0)
|
||||
children.Add(new TreeViewItemData<AssetsViewBuildReportItem>(++id, new AssetsViewBuildReportBundle(bundle), assetTreeViewItems));
|
||||
}
|
||||
}
|
||||
|
||||
void PopulateImplicitEntries(List<TreeViewItemData<AssetsViewBuildReportItem>> children, AssetsViewBuildReportAsset asset, ref int id, bool includeAllDependencies)
|
||||
{
|
||||
foreach (var dep in asset.ImplicitDependencies)
|
||||
{
|
||||
var reportImplicitAsset = new AssetsViewBuildReportAsset(dep);
|
||||
if (EntryAppearsInSearch(reportImplicitAsset, m_SearchValue) || includeAllDependencies)
|
||||
children.Add(new TreeViewItemData<AssetsViewBuildReportItem>(++id, reportImplicitAsset));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
#endif
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: d314bd85e421fcf4d819507bd4554b38
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -0,0 +1,481 @@
|
|||
#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
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 97211b0f482ed5c4f94f6efe397a40ca
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -0,0 +1,311 @@
|
|||
#if UNITY_2022_2_OR_NEWER
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using UnityEditor.AddressableAssets.Build.Layout;
|
||||
using UnityEditor.UIElements;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UIElements;
|
||||
|
||||
namespace UnityEditor.AddressableAssets.BuildReportVisualizer
|
||||
{
|
||||
internal abstract class ContentView : IAddressableView, IBuildReportConsumer
|
||||
{
|
||||
protected BuildLayout m_Report;
|
||||
|
||||
internal ToolbarSearchField m_SearchField;
|
||||
internal string m_SearchValue;
|
||||
|
||||
protected MultiColumnTreeView m_TreeView = null;
|
||||
public MultiColumnTreeView ContentTreeView
|
||||
{
|
||||
get { return m_TreeView; }
|
||||
}
|
||||
|
||||
protected IList<IAddressablesBuildReportItem> m_TreeItems = null;
|
||||
public IList<IAddressablesBuildReportItem> TreeItems
|
||||
{
|
||||
get { return m_TreeItems; }
|
||||
}
|
||||
|
||||
public struct TreeDataReportItem
|
||||
{
|
||||
public int Id;
|
||||
public IAddressablesBuildReportItem ReportItem;
|
||||
|
||||
public TreeDataReportItem(int id, IAddressablesBuildReportItem reportItem)
|
||||
{
|
||||
Id = id;
|
||||
ReportItem = reportItem;
|
||||
}
|
||||
|
||||
}
|
||||
protected Dictionary<Hash128, TreeDataReportItem> m_DataHashtoReportItem = null;
|
||||
public Dictionary<Hash128, TreeDataReportItem> DataHashtoReportItem
|
||||
{
|
||||
get { return m_DataHashtoReportItem; }
|
||||
}
|
||||
|
||||
public Action<IEnumerable<object>> ItemsSelected;
|
||||
|
||||
internal abstract ContentViewColumnData[] ColumnDataForView { get; }
|
||||
|
||||
public abstract void Consume(BuildLayout buildReport);
|
||||
|
||||
public abstract void CreateGUI(VisualElement rootVisualElement);
|
||||
|
||||
public virtual void ClearGUI()
|
||||
{
|
||||
if (m_TreeView != null)
|
||||
{
|
||||
// Clear removes the column header
|
||||
// m_TreeView.Clear();
|
||||
m_TreeView.SetRootItems(default(IList<TreeViewItemData<IAddressablesBuildReportItem>>));
|
||||
m_TreeView.Rebuild();
|
||||
}
|
||||
}
|
||||
|
||||
internal BuildReportHelperConsumer m_HelperConsumer;
|
||||
DetailsView m_DetailsView;
|
||||
VisualTreeAsset m_TreeViewItem;
|
||||
VisualTreeAsset m_TreeViewNavigableItem;
|
||||
|
||||
internal ContentView(BuildReportHelperConsumer helperConsumer, DetailsView detailsView)
|
||||
{
|
||||
m_HelperConsumer = helperConsumer;
|
||||
m_DetailsView = detailsView;
|
||||
m_TreeViewItem = AssetDatabase.LoadAssetAtPath<VisualTreeAsset>(BuildReportUtility.TreeViewItemFilePath);
|
||||
m_TreeViewNavigableItem = AssetDatabase.LoadAssetAtPath<VisualTreeAsset>(BuildReportUtility.TreeViewNavigableItemFilePath);
|
||||
}
|
||||
|
||||
public abstract IList<IAddressablesBuildReportItem> CreateTreeViewItems(BuildLayout report);
|
||||
|
||||
// Expresses bundle data as a flat list of TreeViewItemData objects.
|
||||
protected IList<TreeViewItemData<IAddressablesBuildReportItem>> CreateTreeRootsFlatList(IList<IAddressablesBuildReportItem> items, Dictionary<Hash128, TreeDataReportItem> dataHashToReportItem)
|
||||
{
|
||||
int id = 0;
|
||||
var roots = new List<TreeViewItemData<IAddressablesBuildReportItem>>(items.Count);
|
||||
|
||||
foreach (IAddressablesBuildReportItem item in items)
|
||||
{
|
||||
dataHashToReportItem.Add(BuildReportUtility.ComputeDataHash(item.Name, ""), new TreeDataReportItem(id, item));
|
||||
roots.Add(new TreeViewItemData<IAddressablesBuildReportItem>(id++, item));
|
||||
}
|
||||
return roots;
|
||||
}
|
||||
|
||||
internal static void SetCallbacksForColumns(Columns columns, ContentViewColumnData[] columnNameToWidth)
|
||||
{
|
||||
foreach (ContentViewColumnData data in columnNameToWidth)
|
||||
{
|
||||
Column col = columns[data.Name];
|
||||
col.makeCell = () => new Label();
|
||||
col.bindCell = data.BindCellCallback;
|
||||
col.makeHeader = () => new Label();
|
||||
col.bindHeader = data.BindHeaderCallback;
|
||||
}
|
||||
}
|
||||
|
||||
private IOrderedEnumerable<IAddressablesBuildReportItem> OrderByType(string columnName, Type t)
|
||||
{
|
||||
if (t == typeof(int))
|
||||
return m_TreeItems.OrderBy(item => int.Parse(item.GetSortContent(columnName)));
|
||||
if (t == typeof(ulong))
|
||||
return m_TreeItems.OrderBy(item => ulong.Parse(item.GetSortContent(columnName)));
|
||||
return null;
|
||||
}
|
||||
|
||||
readonly Dictionary<string, Type> m_NumericColumnNames = new Dictionary<string, Type>()
|
||||
{
|
||||
{BuildReportUtility.AssetsContentViewColSizePlusRefs, typeof(ulong)},
|
||||
{BuildReportUtility.AssetsContentViewColSizeUncompressed, typeof(ulong)},
|
||||
{BuildReportUtility.AssetsContentViewColBundleSize, typeof(ulong)},
|
||||
{BuildReportUtility.AssetsContentViewColRefsBy, typeof(int)},
|
||||
{BuildReportUtility.AssetsContentViewColRefsTo, typeof(int)},
|
||||
{BuildReportUtility.BundlesContentViewColSizePlusRefs, typeof(ulong)},
|
||||
{BuildReportUtility.BundlesContentViewColSizeUncompressed, typeof(ulong)},
|
||||
{BuildReportUtility.BundlesContentViewBundleSize, typeof(ulong)},
|
||||
{BuildReportUtility.BundlesContentViewColRefsBy, typeof(int)},
|
||||
{BuildReportUtility.BundlesContentViewColRefsTo, typeof(int)},
|
||||
{BuildReportUtility.GroupsContentViewColSizePlusRefs, typeof(ulong)},
|
||||
{BuildReportUtility.GroupsContentViewColSizeUncompressed, typeof(ulong)},
|
||||
{BuildReportUtility.GroupsContentViewColBundleSize, typeof(ulong)},
|
||||
{BuildReportUtility.GroupsContentViewColRefsBy, typeof(int)},
|
||||
{BuildReportUtility.GroupsContentViewColRefsTo, typeof(int)},
|
||||
{BuildReportUtility.LabelsContentViewColSizePlusRefs, typeof(ulong)},
|
||||
{BuildReportUtility.LabelsContentViewColSizeUncompressed, typeof(ulong)},
|
||||
{BuildReportUtility.LabelsContentViewColSizeBundle, typeof(ulong)},
|
||||
{BuildReportUtility.LabelsContentViewColRefsBy, typeof(int)},
|
||||
{BuildReportUtility.LabelsContentViewColRefsTo, typeof(int)},
|
||||
{BuildReportUtility.DuplicatedAssetsContentViewSpaceSaved, typeof(ulong)},
|
||||
{BuildReportUtility.DuplicatedAssetsContentViewDuplicationCount, typeof(int)},
|
||||
{BuildReportUtility.DuplicatedAssetsContentViewColSize, typeof(ulong)}
|
||||
};
|
||||
|
||||
public void CreateTreeViewHeader(VisualElement element, string colName, bool isAssetColumn)
|
||||
{
|
||||
(element as Label).text = ContentTreeView.columns[colName].title;
|
||||
if (isAssetColumn)
|
||||
element.AddToClassList(BuildReportUtility.TreeViewAssetHeader);
|
||||
else
|
||||
element.AddToClassList(BuildReportUtility.TreeViewHeader);
|
||||
}
|
||||
|
||||
public void CreateTreeViewCell(VisualElement element, int index, string colName, bool isNameColumn, Type type)
|
||||
{
|
||||
IAddressablesBuildReportItem itemData = null;
|
||||
if (type == typeof(AssetsContentView))
|
||||
itemData = ContentTreeView.GetItemDataForIndex<AssetsViewBuildReportItem>(index);
|
||||
if (type == typeof(BundlesContentView))
|
||||
itemData = ContentTreeView.GetItemDataForIndex<BundlesViewBuildReportItem>(index);
|
||||
if (type == typeof(LabelsContentView))
|
||||
itemData = ContentTreeView.GetItemDataForIndex<LabelsViewBuildReportItem>(index);
|
||||
if (type == typeof(GroupsContentView))
|
||||
itemData = ContentTreeView.GetItemDataForIndex<GroupsViewBuildReportItem>(index);
|
||||
if (type == typeof(DuplicatedAssetsContentView))
|
||||
itemData = ContentTreeView.GetItemDataForIndex<DuplicatedAssetsViewBuildReportItem>(index);
|
||||
if (isNameColumn)
|
||||
{
|
||||
ShowEntryIcon(element, itemData, m_TreeViewItem, colName);
|
||||
element.AddToClassList(BuildReportUtility.TreeViewIconElement);
|
||||
}
|
||||
else
|
||||
{
|
||||
(element as Label).text = itemData.GetCellContent(colName);
|
||||
element.AddToClassList(BuildReportUtility.TreeViewElement);
|
||||
}
|
||||
}
|
||||
|
||||
protected bool EntryAppearsInSearch(IAddressablesBuildReportItem item, string searchValue)
|
||||
{
|
||||
if (string.IsNullOrEmpty(searchValue))
|
||||
return true;
|
||||
if (item.Name.ToLowerInvariant().Contains(searchValue))
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
public void ShowEntryIcon(VisualElement element, IAddressablesBuildReportItem itemData, VisualTreeAsset baseItem, string colName)
|
||||
{
|
||||
(element as Label).text = string.Empty;
|
||||
element.Clear();
|
||||
|
||||
VisualElement treeItem = baseItem.Clone(element);
|
||||
var icon = treeItem.Q<Image>(BuildReportUtility.TreeViewItemIcon);
|
||||
var name = treeItem.Q<TextElement>(BuildReportUtility.TreeViewItemName);
|
||||
name.text = itemData.GetCellContent(colName);
|
||||
|
||||
if (itemData is IAddressablesBuildReportAsset asset)
|
||||
{
|
||||
string path = asset.ExplicitAsset == null ? asset.DataFromOtherAsset.AssetPath : asset.ExplicitAsset.AssetPath;
|
||||
Texture iconTexture = AssetDatabase.GetCachedIcon(path);
|
||||
if (iconTexture == null)
|
||||
icon.AddToClassList(BuildReportUtility.TreeViewItemNoIcon);
|
||||
else
|
||||
icon.image = iconTexture;
|
||||
|
||||
if (asset.DataFromOtherAsset != null)
|
||||
name.AddToClassList(BuildReportUtility.TreeViewImplicitAsset);
|
||||
if (asset is DuplicatedAssetsViewBuildReportDuplicatedAsset)
|
||||
name.AddToClassList(BuildReportUtility.TreeViewDuplicatedAsset);
|
||||
}
|
||||
else if (itemData is LabelsViewBuildReportLabel label)
|
||||
icon.image = EditorGUIUtility.IconContent("FilterByLabel").image as Texture2D;
|
||||
else if (itemData is GroupsViewBuildReportGroup group ||
|
||||
itemData is BundlesViewBuildReportIndirectlyReferencedBundles ||
|
||||
itemData is GroupsViewBuildReportIndirectlyReferencedBundles)
|
||||
icon.image = EditorGUIUtility.IconContent("d_FolderOpened Icon").image as Texture2D;
|
||||
else if (itemData is IAddressablesBuildReportBundle)
|
||||
icon.image = EditorGUIUtility.IconContent("Package Manager").image as Texture2D;
|
||||
else
|
||||
icon.AddToClassList(BuildReportUtility.TreeViewItemNoIcon);
|
||||
|
||||
name.AddManipulator(new ContextualMenuManipulator((ContextualMenuPopulateEvent evt) =>
|
||||
{
|
||||
evt.menu.AppendAction("Search in this window", (e) =>
|
||||
{
|
||||
string newSearchValue = name.text;
|
||||
m_SearchField.Q<TextField>().value = newSearchValue;
|
||||
});
|
||||
}));
|
||||
}
|
||||
|
||||
public ContentView UseCachedView(VisualElement rootVisualElement)
|
||||
{
|
||||
VisualElement view = rootVisualElement.Q<VisualElement>(BuildReportUtility.ContentView);
|
||||
view.Add(m_TreeView);
|
||||
return this;
|
||||
}
|
||||
|
||||
internal List<IAddressablesBuildReportItem> SortByColumnDescription(SortColumnDescription col)
|
||||
{
|
||||
IOrderedEnumerable<IAddressablesBuildReportItem> sortedTreeRootEnumerable;
|
||||
if (m_NumericColumnNames.ContainsKey(col.columnName))
|
||||
{
|
||||
Type t = m_NumericColumnNames[col.columnName];
|
||||
sortedTreeRootEnumerable = OrderByType(col.columnName, t);
|
||||
}
|
||||
else
|
||||
{
|
||||
sortedTreeRootEnumerable = m_TreeItems.OrderBy(item => item.GetSortContent(col.columnName));
|
||||
}
|
||||
|
||||
List<IAddressablesBuildReportItem> finalTreeRoots = new List<IAddressablesBuildReportItem>(m_TreeItems.Count);
|
||||
foreach (var item in sortedTreeRootEnumerable)
|
||||
finalTreeRoots.Add(item);
|
||||
if (col.direction == SortDirection.Ascending)
|
||||
finalTreeRoots.Reverse();
|
||||
|
||||
return finalTreeRoots;
|
||||
}
|
||||
}
|
||||
|
||||
internal struct ContentViewColumnData
|
||||
{
|
||||
public string Name;
|
||||
public string Title;
|
||||
public Action<VisualElement, int> BindCellCallback;
|
||||
public Action<VisualElement> BindHeaderCallback;
|
||||
|
||||
public ContentViewColumnData(string name, ContentView view, bool isNameColumn, string title = "N/a")
|
||||
{
|
||||
Name = name;
|
||||
Title = title;
|
||||
BindCellCallback = ((element, index) =>
|
||||
{
|
||||
view.CreateTreeViewCell(element, index, name, isNameColumn, view.GetType());
|
||||
});
|
||||
BindHeaderCallback = ((element) =>
|
||||
{
|
||||
view.CreateTreeViewHeader(element, name, isNameColumn);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// Nested interface that can be either a bundle or asset.
|
||||
public interface IAddressablesBuildReportItem
|
||||
{
|
||||
public string Name { get; }
|
||||
|
||||
void CreateGUI(VisualElement rootVisualElement);
|
||||
|
||||
string GetCellContent(string colName);
|
||||
|
||||
string GetSortContent(string colName);
|
||||
|
||||
}
|
||||
|
||||
public interface IAddressablesBuildReportBundle
|
||||
{
|
||||
public BuildLayout.Bundle Bundle { get; }
|
||||
}
|
||||
|
||||
public interface IAddressablesBuildReportAsset
|
||||
{
|
||||
public BuildLayout.ExplicitAsset ExplicitAsset { get; }
|
||||
public BuildLayout.DataFromOtherAsset DataFromOtherAsset { get; }
|
||||
public List<BuildLayout.Bundle> Bundles { get; }
|
||||
public ulong SizeWDependencies { get; }
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 7c7dcb1750e8ec04cb1c92c4cae35c39
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -0,0 +1,95 @@
|
|||
#if UNITY_2022_2_OR_NEWER
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEditor.AddressableAssets.Build.Layout;
|
||||
using UnityEditor.AddressableAssets.GUIElements;
|
||||
using UnityEditor.UIElements;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UIElements;
|
||||
using static UnityEditor.AddressableAssets.BuildReportVisualizer.BuildReportWindow;
|
||||
|
||||
namespace UnityEditor.AddressableAssets.BuildReportVisualizer
|
||||
{
|
||||
internal enum DetailsViewTab
|
||||
{
|
||||
ReferencesTo,
|
||||
ReferencedBy
|
||||
}
|
||||
|
||||
class DetailsView : IAddressableView
|
||||
{
|
||||
DetailsViewTab m_ActiveContentsTab;
|
||||
VisualElement m_Root;
|
||||
BuildReportWindow m_Window;
|
||||
|
||||
DetailsContentView m_Contents;
|
||||
DetailsSummaryView m_Summary;
|
||||
|
||||
object m_DetailsRootObject;
|
||||
object m_DetailsActiveObject;
|
||||
|
||||
internal DetailsView(BuildReportWindow window)
|
||||
{
|
||||
m_Window = window;
|
||||
m_ActiveContentsTab = DetailsViewTab.ReferencesTo;
|
||||
}
|
||||
|
||||
public void CreateGUI(VisualElement rootVisualElement)
|
||||
{
|
||||
m_Root = rootVisualElement;
|
||||
|
||||
m_Summary = new DetailsSummaryView(rootVisualElement, m_Window);
|
||||
m_Contents = new DetailsContentView(rootVisualElement, m_Window);
|
||||
|
||||
rootVisualElement.Q<RibbonButton>("ReferencesToTab").clicked += () =>
|
||||
{
|
||||
m_ActiveContentsTab = DetailsViewTab.ReferencesTo;
|
||||
DetailsStack.Clear();
|
||||
|
||||
DisplayContents(m_DetailsActiveObject);
|
||||
|
||||
};
|
||||
|
||||
rootVisualElement.Q<RibbonButton>("ReferencedByTab").clicked += () =>
|
||||
{
|
||||
m_ActiveContentsTab = DetailsViewTab.ReferencedBy;
|
||||
DetailsStack.Clear();
|
||||
|
||||
DisplayContents(m_DetailsActiveObject);
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
public void OnSelected(IEnumerable<object> items)
|
||||
{
|
||||
ClearGUI();
|
||||
DetailsStack.Clear();
|
||||
|
||||
foreach (object item in items)
|
||||
{
|
||||
DisplayItemSummary(item);
|
||||
DisplayContents(item);
|
||||
m_DetailsRootObject = m_DetailsActiveObject = item;
|
||||
}
|
||||
}
|
||||
|
||||
public void DisplayItemSummary(object item)
|
||||
{
|
||||
m_Summary.UpdateSummary(item);
|
||||
}
|
||||
|
||||
public void DisplayContents(object contents)
|
||||
{
|
||||
m_Contents.DisplayContents(contents, m_ActiveContentsTab);
|
||||
}
|
||||
|
||||
public void ClearGUI()
|
||||
{
|
||||
m_Summary.ClearSummary();
|
||||
m_Contents.ClearContents();
|
||||
DisplayContents(null);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 0f4712e2e66a54047bd4181d8a3d827f
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -0,0 +1,304 @@
|
|||
#if UNITY_2022_2_OR_NEWER
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using UnityEditor.AddressableAssets.Build.Layout;
|
||||
using UnityEditor.IMGUI.Controls;
|
||||
using UnityEditor.UIElements;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UIElements;
|
||||
|
||||
namespace UnityEditor.AddressableAssets.BuildReportVisualizer
|
||||
{
|
||||
internal class DuplicatedAssetsViewBuildReportItem : IAddressablesBuildReportItem
|
||||
{
|
||||
public string Name { get; set; }
|
||||
|
||||
public BuildLayout.ExplicitAsset ExplicitAsset { get; set; }
|
||||
|
||||
public BuildLayout.DataFromOtherAsset DataFromOtherAsset { get; set; }
|
||||
|
||||
public List<BuildLayout.Bundle> Bundles { get; set; }
|
||||
|
||||
public List<BuildLayout.ExplicitAsset> AssetDepsOf { get; set; }
|
||||
|
||||
public ulong SizeWDependencies { get; protected set; }
|
||||
public ulong Size { get; protected set; }
|
||||
public int DepsCount { get; set; }
|
||||
public int DepsOfCount { get; set; }
|
||||
|
||||
public ulong SpaceSavedIfDeduplicated { get; set; }
|
||||
|
||||
public int DuplicationCount { get; set; }
|
||||
|
||||
public void CreateGUI(VisualElement rootVisualElement)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public string GetCellContent(string colName)
|
||||
{
|
||||
if (colName == BuildReportUtility.DuplicatedAssetsContentViewColAssetName)
|
||||
return Name;
|
||||
if (colName == BuildReportUtility.DuplicatedAssetsContentViewColSize)
|
||||
return BuildReportUtility.GetDenominatedBytesString(Size);
|
||||
if (colName == BuildReportUtility.DuplicatedAssetsContentViewSpaceSaved)
|
||||
{
|
||||
if (this is DuplicatedAssetsViewBuildReportAsset asset)
|
||||
return asset.UsedByString;
|
||||
if (DuplicationCount == -1)
|
||||
return "";
|
||||
return BuildReportUtility.GetDenominatedBytesString(SpaceSavedIfDeduplicated);
|
||||
}
|
||||
if (colName == BuildReportUtility.DuplicatedAssetsContentViewDuplicationCount)
|
||||
{
|
||||
if (DuplicationCount == -1)
|
||||
return "";
|
||||
return DuplicationCount.ToString();
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
public string GetSortContent(string colName)
|
||||
{
|
||||
if (colName == BuildReportUtility.DuplicatedAssetsContentViewColSize)
|
||||
return Size.ToString();
|
||||
if (colName == BuildReportUtility.DuplicatedAssetsContentViewSpaceSaved)
|
||||
return SpaceSavedIfDeduplicated.ToString();
|
||||
if (colName == BuildReportUtility.DuplicatedAssetsContentViewSpaceSaved)
|
||||
return DuplicationCount.ToString();
|
||||
return GetCellContent(colName);
|
||||
}
|
||||
}
|
||||
|
||||
internal class DuplicatedAssetsViewBuildReportDuplicatedAsset : DuplicatedAssetsViewBuildReportItem, IAddressablesBuildReportAsset
|
||||
{
|
||||
public new string GetCellContent(string colName)
|
||||
{
|
||||
if (colName == BuildReportUtility.DuplicatedAssetsContentViewColAssetName)
|
||||
return Name;
|
||||
if (colName == BuildReportUtility.DuplicatedAssetsContentViewColSize)
|
||||
return BuildReportUtility.GetDenominatedBytesString(Size);
|
||||
if (colName == BuildReportUtility.DuplicatedAssetsContentViewSpaceSaved)
|
||||
return BuildReportUtility.GetDenominatedBytesString(SpaceSavedIfDeduplicated);
|
||||
if (colName == BuildReportUtility.DuplicatedAssetsContentViewDuplicationCount)
|
||||
return DuplicationCount.ToString();
|
||||
return "";
|
||||
}
|
||||
|
||||
public DuplicatedAssetsViewBuildReportDuplicatedAsset(BuildReportHelperDuplicateImplicitAsset helperAsset)
|
||||
{
|
||||
DataFromOtherAsset = helperAsset.Asset;
|
||||
Name = DataFromOtherAsset.AssetPath;
|
||||
SizeWDependencies = DataFromOtherAsset.SerializedSize + DataFromOtherAsset.StreamedSize;
|
||||
Size = DataFromOtherAsset.SerializedSize + DataFromOtherAsset.StreamedSize;
|
||||
DepsCount = 0;
|
||||
Bundles = helperAsset.Bundles;
|
||||
AssetDepsOf = helperAsset.GUIDToReferencingAssets.Values.ToList();
|
||||
DepsOfCount = AssetDepsOf.Count;
|
||||
DuplicationCount = Bundles.Count;
|
||||
if (DuplicationCount > 1)
|
||||
{
|
||||
SpaceSavedIfDeduplicated = (ulong) (DuplicationCount - 1) * Size;
|
||||
}
|
||||
}
|
||||
|
||||
public DuplicatedAssetsViewBuildReportDuplicatedAsset(BuildLayout.DataFromOtherAsset implicitAsset)
|
||||
{
|
||||
DataFromOtherAsset = implicitAsset;
|
||||
Bundles = new List<BuildLayout.Bundle>() { implicitAsset.File.Bundle };
|
||||
Name = DataFromOtherAsset.AssetPath;
|
||||
SizeWDependencies = DataFromOtherAsset.SerializedSize + DataFromOtherAsset.StreamedSize;
|
||||
Size = DataFromOtherAsset.SerializedSize + DataFromOtherAsset.StreamedSize;
|
||||
DuplicationCount = -1;
|
||||
}
|
||||
}
|
||||
|
||||
internal class DuplicatedAssetsViewBuildReportAsset : DuplicatedAssetsViewBuildReportItem, IAddressablesBuildReportAsset
|
||||
{
|
||||
public string UsedByString { get; set; }
|
||||
public DuplicatedAssetsViewBuildReportAsset(BuildLayout.ExplicitAsset asset, BuildLayout.DataFromOtherAsset implicitAsset)
|
||||
{
|
||||
ExplicitAsset = asset;
|
||||
Name = asset.AddressableName;
|
||||
Size = asset.SerializedSize + asset.StreamedSize;
|
||||
UsedByString = $"Uses {implicitAsset.AssetPath}";
|
||||
DuplicationCount = -1;
|
||||
SpaceSavedIfDeduplicated = 0;
|
||||
}
|
||||
}
|
||||
|
||||
internal class DuplicatedAssetsViewBuildReportUnrelatedAssets : DuplicatedAssetsViewBuildReportItem
|
||||
{
|
||||
public DuplicatedAssetsViewBuildReportUnrelatedAssets(ulong assetSize, int assetCount)
|
||||
{
|
||||
Name = $"({assetCount} unrelated assets)";
|
||||
Size = assetSize;
|
||||
DuplicationCount = -1;
|
||||
SpaceSavedIfDeduplicated = 0;
|
||||
}
|
||||
}
|
||||
|
||||
internal class DuplicatedAssetsViewBuildReportBundle : DuplicatedAssetsViewBuildReportItem, IAddressablesBuildReportBundle
|
||||
{
|
||||
public DuplicatedAssetsViewBuildReportBundle(BuildLayout.Bundle bundle)
|
||||
{
|
||||
Bundle = bundle;
|
||||
Name = bundle.Name;
|
||||
Size = bundle.FileSize;
|
||||
DuplicationCount = -1;
|
||||
SpaceSavedIfDeduplicated = 0;
|
||||
}
|
||||
|
||||
public BuildLayout.Bundle Bundle { get; set; }
|
||||
}
|
||||
|
||||
class DuplicatedAssetsContentView : ContentView
|
||||
{
|
||||
public DuplicatedAssetsContentView(BuildReportHelperConsumer helperConsumer, DetailsView detailsView)
|
||||
: base(helperConsumer, detailsView) { }
|
||||
|
||||
internal override ContentViewColumnData[] ColumnDataForView
|
||||
{
|
||||
get
|
||||
{
|
||||
return new ContentViewColumnData[]
|
||||
{
|
||||
new ContentViewColumnData(BuildReportUtility.DuplicatedAssetsContentViewColAssetName,this, true, "Asset Name"),
|
||||
new ContentViewColumnData(BuildReportUtility.DuplicatedAssetsContentViewColSize, this, false, "Size"),
|
||||
new ContentViewColumnData(BuildReportUtility.DuplicatedAssetsContentViewSpaceSaved, this, false, "Space saved if De-duplicated"),
|
||||
new ContentViewColumnData(BuildReportUtility.DuplicatedAssetsContentViewDuplicationCount, this, false, "Number of times duplicated")
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
public override IList<IAddressablesBuildReportItem> CreateTreeViewItems(BuildLayout report)
|
||||
{
|
||||
List<IAddressablesBuildReportItem> buildReportAssets = new List<IAddressablesBuildReportItem>();
|
||||
if (report == null)
|
||||
return buildReportAssets;
|
||||
|
||||
foreach (BuildReportHelperDuplicateImplicitAsset helperAsset in m_HelperConsumer.GUIDToDuplicateAssets.Values)
|
||||
{
|
||||
buildReportAssets.Add(new DuplicatedAssetsViewBuildReportDuplicatedAsset(helperAsset));
|
||||
}
|
||||
|
||||
return buildReportAssets;
|
||||
}
|
||||
|
||||
internal IList<TreeViewItemData<DuplicatedAssetsViewBuildReportItem>> CreateTreeRootsNestedList(IList<IAddressablesBuildReportItem> items)
|
||||
{
|
||||
int id = 0;
|
||||
var roots = new List<TreeViewItemData<DuplicatedAssetsViewBuildReportItem>>();
|
||||
|
||||
foreach (DuplicatedAssetsViewBuildReportItem item in items)
|
||||
{
|
||||
DuplicatedAssetsViewBuildReportDuplicatedAsset duplicatedAsset = item as DuplicatedAssetsViewBuildReportDuplicatedAsset;
|
||||
if (duplicatedAsset == null)
|
||||
continue;
|
||||
|
||||
bool includeAllDependencies = EntryAppearsInSearch(duplicatedAsset, m_SearchValue);
|
||||
|
||||
var bundles = CreateBundleEntries(duplicatedAsset, ref id, includeAllDependencies);
|
||||
|
||||
if (includeAllDependencies || bundles != null)
|
||||
roots.Add(new TreeViewItemData<DuplicatedAssetsViewBuildReportItem>(id++, item, bundles));
|
||||
}
|
||||
|
||||
return roots;
|
||||
}
|
||||
|
||||
private List<TreeViewItemData<DuplicatedAssetsViewBuildReportItem>> CreateBundleEntries(DuplicatedAssetsViewBuildReportDuplicatedAsset duplicatedAsset, ref int id, bool includeAllDependencies)
|
||||
{
|
||||
var bundles = new List<TreeViewItemData<DuplicatedAssetsViewBuildReportItem>>();
|
||||
var bundleToAssetList = new Dictionary<BuildLayout.Bundle, List<BuildLayout.ExplicitAsset>>();
|
||||
|
||||
foreach (var dependentAsset in duplicatedAsset.AssetDepsOf)
|
||||
{
|
||||
if (!bundleToAssetList.ContainsKey(dependentAsset.Bundle))
|
||||
bundleToAssetList.Add(dependentAsset.Bundle, new List<BuildLayout.ExplicitAsset>());
|
||||
bundleToAssetList[dependentAsset.Bundle].Add(dependentAsset);
|
||||
}
|
||||
|
||||
bool includeDuplicationInSearch = includeAllDependencies;
|
||||
foreach (var bundle in bundleToAssetList.Keys)
|
||||
{
|
||||
var bundleReportItem = new DuplicatedAssetsViewBuildReportBundle(bundle);
|
||||
var depAssets = new List<TreeViewItemData<DuplicatedAssetsViewBuildReportItem>>();
|
||||
var unrelatedAssetsSize = bundle.FileSize;
|
||||
|
||||
depAssets.Add(new TreeViewItemData<DuplicatedAssetsViewBuildReportItem>(id++, new DuplicatedAssetsViewBuildReportDuplicatedAsset(duplicatedAsset.DataFromOtherAsset)));
|
||||
foreach (var dependentAsset in bundleToAssetList[bundle])
|
||||
{
|
||||
var assetReportItem = new DuplicatedAssetsViewBuildReportAsset(dependentAsset, duplicatedAsset.DataFromOtherAsset);
|
||||
includeDuplicationInSearch = includeDuplicationInSearch || EntryAppearsInSearch(assetReportItem, m_SearchValue);
|
||||
unrelatedAssetsSize -= dependentAsset.SerializedSize + dependentAsset.StreamedSize;
|
||||
depAssets.Add(new TreeViewItemData<DuplicatedAssetsViewBuildReportItem>(id++, assetReportItem));
|
||||
}
|
||||
|
||||
int unrelatedAssetCount = bundle.AssetCount - bundleToAssetList[bundle].Count;
|
||||
if (unrelatedAssetCount > 0)
|
||||
{
|
||||
depAssets.Add(new TreeViewItemData<DuplicatedAssetsViewBuildReportItem>(id++, new DuplicatedAssetsViewBuildReportUnrelatedAssets(unrelatedAssetsSize, unrelatedAssetCount)));
|
||||
}
|
||||
|
||||
bundles.Add(new TreeViewItemData<DuplicatedAssetsViewBuildReportItem>(id++, bundleReportItem, depAssets));
|
||||
}
|
||||
|
||||
if (includeDuplicationInSearch)
|
||||
return bundles;
|
||||
return null;
|
||||
}
|
||||
|
||||
public override void Consume(BuildLayout buildReport)
|
||||
{
|
||||
if (buildReport == null)
|
||||
return;
|
||||
|
||||
m_Report = buildReport;
|
||||
m_TreeItems = CreateTreeViewItems(m_Report);
|
||||
IList<TreeViewItemData<DuplicatedAssetsViewBuildReportItem>> 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
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: b5c3475f04d410a47ade712e307b9d75
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -0,0 +1,479 @@
|
|||
#if UNITY_2022_2_OR_NEWER
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using UnityEditor.AddressableAssets.Build.Layout;
|
||||
using UnityEditor.UIElements;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UIElements;
|
||||
|
||||
namespace UnityEditor.AddressableAssets.BuildReportVisualizer
|
||||
{
|
||||
internal class GroupsViewBuildReportItem : IAddressablesBuildReportItem
|
||||
{
|
||||
public BuildLayout.Group Group { get; set; }
|
||||
public string Name { get; protected set; }
|
||||
public ulong FileSizePlusRefs { get; set; }
|
||||
|
||||
public ulong FileSizeUncompressed { get; set; }
|
||||
|
||||
public ulong FileSizeBundle { get; set; }
|
||||
|
||||
public int RefsTo { get; set; }
|
||||
|
||||
public int RefsBy { get; set; }
|
||||
|
||||
public virtual void CreateGUI(VisualElement rootVisualElement)
|
||||
{
|
||||
}
|
||||
|
||||
public virtual string GetCellContent(string colName)
|
||||
{
|
||||
if (colName == BuildReportUtility.GroupsContentViewColGroupName)
|
||||
return Name;
|
||||
else if (colName == BuildReportUtility.GroupsContentViewColSizePlusRefs)
|
||||
{
|
||||
if (FileSizePlusRefs == 0)
|
||||
return "--";
|
||||
return BuildReportUtility.GetDenominatedBytesString(FileSizePlusRefs);
|
||||
}
|
||||
else if (colName == BuildReportUtility.GroupsContentViewColSizeUncompressed)
|
||||
{
|
||||
if (FileSizeUncompressed == 0)
|
||||
return "--";
|
||||
return BuildReportUtility.GetDenominatedBytesString(FileSizeUncompressed);
|
||||
}
|
||||
else if (colName == BuildReportUtility.GroupsContentViewColBundleSize)
|
||||
{
|
||||
if (FileSizeBundle == 0)
|
||||
return "--";
|
||||
return BuildReportUtility.GetDenominatedBytesString(FileSizeBundle);
|
||||
}
|
||||
else if (colName == BuildReportUtility.GroupsContentViewColRefsTo)
|
||||
{
|
||||
if (RefsTo == -1)
|
||||
return "--";
|
||||
return RefsTo.ToString();
|
||||
}
|
||||
else if (colName == BuildReportUtility.GroupsContentViewColRefsBy)
|
||||
{
|
||||
if (RefsBy == -1)
|
||||
return "--";
|
||||
return RefsBy.ToString();
|
||||
}
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
public string GetSortContent(string colName)
|
||||
{
|
||||
if (colName == BuildReportUtility.GroupsContentViewColSizePlusRefs)
|
||||
return FileSizePlusRefs.ToString();
|
||||
if (colName == BuildReportUtility.GroupsContentViewColSizeUncompressed)
|
||||
return FileSizeUncompressed.ToString();
|
||||
if (colName == BuildReportUtility.GroupsContentViewColBundleSize)
|
||||
return FileSizeBundle.ToString();
|
||||
if (colName == BuildReportUtility.GroupsContentViewColRefsBy)
|
||||
return RefsBy.ToString();
|
||||
if (colName == BuildReportUtility.GroupsContentViewColRefsTo)
|
||||
return RefsTo.ToString();
|
||||
return GetCellContent(colName);
|
||||
}
|
||||
}
|
||||
|
||||
internal class GroupsViewBuildReportGroup : GroupsViewBuildReportItem
|
||||
{
|
||||
public List<BuildLayout.ExplicitAsset> BuildReportAssets;
|
||||
|
||||
public GroupsViewBuildReportGroup(BuildLayout.Group group, List<BuildLayout.ExplicitAsset> reportAssets)
|
||||
{
|
||||
Name = group.Name;
|
||||
Group = group;
|
||||
BuildReportAssets = reportAssets;
|
||||
FileSizePlusRefs = 0;
|
||||
FileSizeBundle = 0;
|
||||
FileSizeUncompressed = 0;
|
||||
RefsBy = -1;
|
||||
RefsTo = group.Bundles.Count;
|
||||
}
|
||||
}
|
||||
|
||||
internal class GroupsViewBuildReportAsset : GroupsViewBuildReportItem, IAddressablesBuildReportAsset
|
||||
{
|
||||
public List<BuildLayout.ExplicitAsset> InternallyReferencedAssets { get; }
|
||||
|
||||
public List<BuildLayout.ExplicitAsset> ExternallyReferencedAssets { get; }
|
||||
|
||||
public List<BuildLayout.DataFromOtherAsset> ImplicitDependencies { get; }
|
||||
|
||||
|
||||
public BuildLayout.ExplicitAsset ExplicitAsset { get; }
|
||||
public BuildLayout.DataFromOtherAsset DataFromOtherAsset { get; }
|
||||
public List<BuildLayout.Bundle> Bundles { get; }
|
||||
public ulong SizeWDependencies { get; }
|
||||
|
||||
public List<BuildLayout.ExplicitAsset> ReferencingAssets { get; }
|
||||
public GroupsViewBuildReportAsset(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)
|
||||
FileSizePlusRefs += r.SerializedSize + r.StreamedSize;
|
||||
foreach (var r in asset.InternalReferencedExplicitAssets)
|
||||
FileSizePlusRefs += r.SerializedSize + r.StreamedSize;
|
||||
RefsTo = asset.ExternallyReferencedAssets.Count + asset.InternalReferencedExplicitAssets.Count;
|
||||
RefsBy = asset.ReferencingAssets != null ? asset.ReferencingAssets.Count : -1;
|
||||
}
|
||||
|
||||
public GroupsViewBuildReportAsset(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 GroupsViewBuildReportBundle : GroupsViewBuildReportItem, IAddressablesBuildReportBundle
|
||||
{
|
||||
public GroupsViewBuildReportBundle(BuildLayout.Bundle bundle)
|
||||
{
|
||||
Name = bundle.Name;
|
||||
Bundle = bundle;
|
||||
FileSizeBundle = bundle.FileSize;
|
||||
FileSizeUncompressed = bundle.UncompressedFileSize;
|
||||
FileSizePlusRefs = bundle.FileSize + bundle.ExpandedDependencyFileSize + bundle.DependencyFileSize;
|
||||
foreach (var file in bundle.Files)
|
||||
RefsTo += file.Assets.Count + file.OtherAssets.Count;
|
||||
RefsBy = Bundle.DependentBundles.Count;
|
||||
}
|
||||
|
||||
public BuildLayout.Bundle Bundle { get; }
|
||||
}
|
||||
|
||||
internal class GroupsViewBuildReportUnrelatedAssets : GroupsViewBuildReportItem
|
||||
{
|
||||
public GroupsViewBuildReportUnrelatedAssets(ulong assetSize, int assetCount)
|
||||
{
|
||||
Name = $"({assetCount} unrelated assets)";
|
||||
FileSizeUncompressed = assetSize;
|
||||
}
|
||||
}
|
||||
|
||||
internal class GroupsViewBuildReportIndirectlyReferencedBundles : GroupsViewBuildReportItem
|
||||
{
|
||||
public GroupsViewBuildReportIndirectlyReferencedBundles(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 GroupsContentView : ContentView
|
||||
{
|
||||
public GroupsContentView(BuildReportHelperConsumer helperConsumer, DetailsView detailsView)
|
||||
: base(helperConsumer, detailsView)
|
||||
{
|
||||
m_DataHashtoReportItem = new Dictionary<Hash128, TreeDataReportItem>();
|
||||
}
|
||||
|
||||
internal override ContentViewColumnData[] ColumnDataForView
|
||||
{
|
||||
get
|
||||
{
|
||||
return new ContentViewColumnData[]
|
||||
{
|
||||
new ContentViewColumnData(BuildReportUtility.GroupsContentViewColGroupName, this, true, "Group Name"),
|
||||
new ContentViewColumnData(BuildReportUtility.GroupsContentViewColSizePlusRefs, this, false, "Total Size (+ refs)"),
|
||||
new ContentViewColumnData(BuildReportUtility.GroupsContentViewColSizeUncompressed, this, false, "Uncompressed Size"),
|
||||
new ContentViewColumnData(BuildReportUtility.GroupsContentViewColBundleSize, this, false, "Bundle File Size"),
|
||||
new ContentViewColumnData(BuildReportUtility.GroupsContentViewColRefsTo, this, false, "Refs To"),
|
||||
new ContentViewColumnData(BuildReportUtility.GroupsContentViewColRefsBy, this, false, "Refs By")
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
public override IList<IAddressablesBuildReportItem> CreateTreeViewItems(BuildLayout report)
|
||||
{
|
||||
List<IAddressablesBuildReportItem> buildReportGroups = new List<IAddressablesBuildReportItem>();
|
||||
if (report == null)
|
||||
return buildReportGroups;
|
||||
|
||||
var groupToAssets = new Dictionary<BuildLayout.Group, List<BuildLayout.ExplicitAsset>>();
|
||||
foreach (var asset in BuildLayoutHelpers.EnumerateAssets(report))
|
||||
{
|
||||
if (groupToAssets.ContainsKey(asset.Bundle.Group))
|
||||
groupToAssets[asset.Bundle.Group].Add(asset);
|
||||
else
|
||||
groupToAssets.Add(asset.Bundle.Group, new List<BuildLayout.ExplicitAsset> { asset });
|
||||
}
|
||||
|
||||
foreach (var pair in groupToAssets)
|
||||
{
|
||||
buildReportGroups.Add(new GroupsViewBuildReportGroup(pair.Key, pair.Value));
|
||||
}
|
||||
|
||||
return buildReportGroups;
|
||||
}
|
||||
|
||||
internal IList<TreeViewItemData<GroupsViewBuildReportItem>> CreateTreeRootsNestedList(IList<IAddressablesBuildReportItem> items)
|
||||
{
|
||||
int id = 0;
|
||||
var roots = new List<TreeViewItemData<GroupsViewBuildReportItem>>();
|
||||
foreach (var item in items)
|
||||
{
|
||||
var group = item as GroupsViewBuildReportGroup;
|
||||
if (group == null)
|
||||
continue;
|
||||
|
||||
bool includeAllDependencies = EntryAppearsInSearch(group, m_SearchValue);
|
||||
|
||||
List<TreeViewItemData<GroupsViewBuildReportItem>> bundlesUnderGroup = CreateGroupBundles(group, ref id, includeAllDependencies);
|
||||
|
||||
if (bundlesUnderGroup.Count > 0 || includeAllDependencies)
|
||||
{
|
||||
var groupItem = new TreeViewItemData<GroupsViewBuildReportItem>(++id, group, bundlesUnderGroup);
|
||||
m_DataHashtoReportItem.TryAdd(BuildReportUtility.ComputeDataHash(group.Name), new TreeDataReportItem(id, groupItem.data));
|
||||
roots.Add(groupItem);
|
||||
}
|
||||
}
|
||||
|
||||
return roots;
|
||||
}
|
||||
|
||||
private List<TreeViewItemData<GroupsViewBuildReportItem>> CreateGroupBundles(GroupsViewBuildReportGroup group, ref int id, bool includeAllDependencies)
|
||||
{
|
||||
var bundlesUnderGroup = new List<TreeViewItemData<GroupsViewBuildReportItem>>();
|
||||
foreach (var bundle in group.Group.Bundles)
|
||||
{
|
||||
var bundleReportItem = new GroupsViewBuildReportBundle(bundle);
|
||||
var children = new List<TreeViewItemData<GroupsViewBuildReportItem>>();
|
||||
var directlyReferencedBundles = new HashSet<BuildLayout.Bundle>();
|
||||
|
||||
PopulateAssets(children, directlyReferencedBundles, bundle, ref id, includeAllDependencies);
|
||||
PopulateIndirectlyReferencedBundles(children, directlyReferencedBundles, bundle, ref id, includeAllDependencies);
|
||||
|
||||
if (children.Count > 0 || EntryAppearsInSearch(bundleReportItem, m_SearchValue))
|
||||
{
|
||||
var bundleItem = new TreeViewItemData<GroupsViewBuildReportItem>(++id, bundleReportItem, children);
|
||||
m_DataHashtoReportItem.TryAdd(BuildReportUtility.ComputeDataHash(group.Name, bundle.Name), new TreeDataReportItem(id, bundleItem.data));
|
||||
bundlesUnderGroup.Add(bundleItem);
|
||||
}
|
||||
}
|
||||
|
||||
return bundlesUnderGroup;
|
||||
}
|
||||
|
||||
private void PopulateAssets(List<TreeViewItemData<GroupsViewBuildReportItem>> children,
|
||||
HashSet<BuildLayout.Bundle> directlyReferencedBundles, BuildLayout.Bundle bundle, ref int id, bool includeAllDependencies)
|
||||
{
|
||||
foreach (var asset in BuildLayoutHelpers.EnumerateAssets(bundle))
|
||||
{
|
||||
var reportAssetItem = new GroupsViewBuildReportAsset(asset);
|
||||
bool assetAppearsInSearch = EntryAppearsInSearch(reportAssetItem, m_SearchValue) || includeAllDependencies;
|
||||
var childrenOfAsset = GenerateChildrenOfAsset(asset, ref id, directlyReferencedBundles, assetAppearsInSearch);
|
||||
if (assetAppearsInSearch || childrenOfAsset.Count > 0)
|
||||
{
|
||||
var assetItem = new TreeViewItemData<GroupsViewBuildReportItem>(++id, reportAssetItem, childrenOfAsset);
|
||||
m_DataHashtoReportItem.TryAdd(BuildReportUtility.ComputeDataHash(asset.AddressableName), new TreeDataReportItem(id, assetItem.data));
|
||||
children.Add(assetItem);
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var asset in BuildLayoutHelpers.EnumerateImplicitAssets(bundle))
|
||||
{
|
||||
var reportImplicitAssetItem = new GroupsViewBuildReportAsset(asset);
|
||||
if (includeAllDependencies || EntryAppearsInSearch(reportImplicitAssetItem, m_SearchValue))
|
||||
children.Add(new TreeViewItemData<GroupsViewBuildReportItem>(++id, reportImplicitAssetItem));
|
||||
}
|
||||
}
|
||||
|
||||
private void PopulateIndirectlyReferencedBundles(List<TreeViewItemData<GroupsViewBuildReportItem>> children,
|
||||
HashSet<BuildLayout.Bundle> directlyReferencedBundles, BuildLayout.Bundle bundle, ref int id, bool includeAllDependencies)
|
||||
{
|
||||
var indirectlyReferencedBundleReportItems = new List<TreeViewItemData<GroupsViewBuildReportItem>>();
|
||||
var indirectlyReferencedBundles = new List<BuildLayout.Bundle>();
|
||||
foreach (var depBundle in bundle.ExpandedDependencies)
|
||||
{
|
||||
if (!directlyReferencedBundles.Contains(depBundle))
|
||||
{
|
||||
var reportBundle = new GroupsViewBuildReportBundle(depBundle);
|
||||
if (includeAllDependencies || EntryAppearsInSearch(reportBundle, m_SearchValue))
|
||||
{
|
||||
indirectlyReferencedBundleReportItems.Add(new TreeViewItemData<GroupsViewBuildReportItem>(++id, reportBundle));
|
||||
indirectlyReferencedBundles.Add(depBundle);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (indirectlyReferencedBundles.Count > 0)
|
||||
{
|
||||
children.Add(new TreeViewItemData<GroupsViewBuildReportItem>(++id, new GroupsViewBuildReportIndirectlyReferencedBundles(indirectlyReferencedBundles), indirectlyReferencedBundleReportItems));
|
||||
}
|
||||
}
|
||||
|
||||
private List<TreeViewItemData<GroupsViewBuildReportItem>> GenerateChildrenOfAsset(BuildLayout.ExplicitAsset asset, ref int id, HashSet<BuildLayout.Bundle> referencedBundles, bool includeAllDependencies)
|
||||
{
|
||||
var childrenOfAsset = new List<TreeViewItemData<GroupsViewBuildReportItem>>();
|
||||
foreach (var dep in asset.InternalReferencedExplicitAssets)
|
||||
{
|
||||
var reportDepAsset = new GroupsViewBuildReportAsset(dep);
|
||||
if (includeAllDependencies || EntryAppearsInSearch(reportDepAsset, m_SearchValue))
|
||||
{
|
||||
var tvid = new TreeViewItemData<GroupsViewBuildReportItem>(++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>());
|
||||
referencedBundles.Add(dep.Bundle);
|
||||
}
|
||||
bundleToAssetList[dep.Bundle].Add(dep);
|
||||
}
|
||||
|
||||
foreach (var bundle in bundleToAssetList.Keys)
|
||||
{
|
||||
var bundleReportAsset = new GroupsViewBuildReportBundle(bundle);
|
||||
bool includeAllDependenciesUnderBundle = EntryAppearsInSearch(bundleReportAsset, m_SearchValue) || includeAllDependencies;
|
||||
var assetTreeViewItems = new List<TreeViewItemData<GroupsViewBuildReportItem>>();
|
||||
var assetList = bundleToAssetList[bundle];
|
||||
ulong unrelatedAssetSize = bundle.FileSize;
|
||||
foreach (var bundleAsset in assetList)
|
||||
{
|
||||
var reportAsset = new GroupsViewBuildReportAsset(bundleAsset);
|
||||
if (includeAllDependenciesUnderBundle || EntryAppearsInSearch(reportAsset, m_SearchValue))
|
||||
{
|
||||
var tvid = new TreeViewItemData<GroupsViewBuildReportItem>(++id, reportAsset);
|
||||
assetTreeViewItems.Add(tvid);
|
||||
unrelatedAssetSize -= bundleAsset.SerializedSize + bundleAsset.StreamedSize;
|
||||
}
|
||||
}
|
||||
|
||||
int unrelatedAssetCount = bundle.AssetCount - assetList.Count;
|
||||
if (unrelatedAssetCount > 0 && includeAllDependenciesUnderBundle)
|
||||
{
|
||||
var tvid = new TreeViewItemData<GroupsViewBuildReportItem>(++id, new GroupsViewBuildReportUnrelatedAssets(unrelatedAssetSize, unrelatedAssetCount));
|
||||
assetTreeViewItems.Add(tvid);
|
||||
}
|
||||
|
||||
if (includeAllDependenciesUnderBundle || assetTreeViewItems.Count > 0)
|
||||
{
|
||||
var rootItem = new TreeViewItemData<GroupsViewBuildReportItem>(++id, bundleReportAsset, assetTreeViewItems);
|
||||
childrenOfAsset.Add(rootItem);
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var dep in asset.InternalReferencedOtherAssets)
|
||||
{
|
||||
var reportDepAsset = new GroupsViewBuildReportAsset(dep);
|
||||
if (includeAllDependencies || EntryAppearsInSearch(reportDepAsset, m_SearchValue))
|
||||
{
|
||||
var tvid = new TreeViewItemData<GroupsViewBuildReportItem>(++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<GroupsViewBuildReportItem>> 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_DataHashtoReportItem = new Dictionary<Hash128, TreeDataReportItem>();
|
||||
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
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 238dc259a6e2a034a9a94e1a26ebb37b
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -0,0 +1,398 @@
|
|||
#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
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 96cc958f02550384ab2d0e1964ebb8ff
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
Loading…
Add table
Add a link
Reference in a new issue