#if ENABLE_ADDRESSABLE_PROFILER && UNITY_2022_2_OR_NEWER using System; using System.Collections.Generic; using UnityEditor.AddressableAssets.Build.Layout; using UnityEngine; using UnityEngine.ResourceManagement.Profiling; using UnityEngine.ResourceManagement.Util; namespace UnityEditor.AddressableAssets.Diagnostics { internal class ContentData { public string Name; public int AddressableHandles; public ContentStatus Status; protected float m_PercentComplete; public float PercentComplete { get { if (Status == ContentStatus.Loading) return m_PercentComplete; if (Status == ContentStatus.Active) return 1f; return -1f; } } public virtual int TreeViewID { get { return Name.GetHashCode(); } } public readonly List Children = new List(); public ContentData Parent = null; public readonly List ThisReferencesOther = new List(); public readonly List ReferencesToThis = new List(); public void AddReferenceTo(ContentData value) { if (!ThisReferencesOther.Contains(value)) ThisReferencesOther.Add(value); } public void AddReferenceBy(ContentData value) { if (!ReferencesToThis.Contains(value)) ReferencesToThis.Add(value); } public void AddChild(ContentData child) { Children.Add(child); child.Parent = this; } public virtual string GetCellContent(string colName) { return colName switch { TreeColumnNames.TreeColumnName => Name, TreeColumnNames.TreeColumnType => "", TreeColumnNames.TreeColumnAddressedCount => AddressableHandles.ToString(), TreeColumnNames.TreeColumnStatus => Status.ToString(), TreeColumnNames.TreeColumnPercentage => PercentComplete < 0.5f ? "" : (int)(PercentComplete*100f)+"%", TreeColumnNames.TreeColumnReferencedBy => ReferencesToThis.Count.ToString(), TreeColumnNames.TreeColumnReferencesTo => ThisReferencesOther.Count.ToString(), _ => "" }; } } internal class GroupData : ContentData { public BuildLayout.Group m_ReportGroup; public GroupData(BuildLayout.Group reportGroup) { m_ReportGroup = reportGroup; if (m_ReportGroup == null) { Name = "Missing group"; return; } Name = reportGroup.Name; } public override string GetCellContent(string colName) { return colName switch { TreeColumnNames.TreeColumnName => Name, _ => "" }; } } internal class BundleData : ContentData { public readonly int BundleCode; public readonly BundleSource Source; public bool CheckSumEnabled; public bool CachingEnabled; internal BuildLayout.Bundle ReportBundle; public List NotLoadedChildren = new List(); public Dictionary AssetGuidToChildIndex = new Dictionary(); public override int TreeViewID { get { return BundleCode; } } public override string GetCellContent(string colName) { if (colName == TreeColumnNames.TreeColumnType) return "Asset Bundle"; return base.GetCellContent(colName); } public BundleData(BuildLayout.Bundle reportBundle, BundleFrameData frameData) { ReportBundle = reportBundle; Name = reportBundle != null ? reportBundle.Name : frameData.BundleCode.ToString(); BundleCode = frameData.BundleCode; Source = frameData.Source; m_PercentComplete = frameData.PercentComplete; CachingEnabled = frameData.LoadingOptions.HasFlag(BundleOptions.CachingEnabled); CheckSumEnabled = frameData.LoadingOptions.HasFlag(BundleOptions.CheckSumEnabled); AddressableHandles = frameData.ReferenceCount; Status = frameData.Status; } public AssetData GetOrCreateAssetData(BuildLayout.ExplicitAsset asset) { if (AssetGuidToChildIndex.TryGetValue(asset.Guid, out int value)) return Children[value] as AssetData; AssetData assetData = new AssetData(asset); AssetGuidToChildIndex.Add(asset.Guid, Children.Count); Children.Add(assetData); assetData.Parent = this; return assetData; } public AssetData GetOrCreateAssetData(BuildLayout.DataFromOtherAsset asset) { if (AssetGuidToChildIndex.TryGetValue(asset.AssetGuid, out int value)) return Children[value] as AssetData; AssetData assetData = new AssetData(asset); AssetGuidToChildIndex.Add(asset.AssetGuid, Children.Count); Children.Add(assetData); assetData.Parent = this; return assetData; } /// /// /// /// /// /// true if new assetData is created, else false is already a child of bundle public bool GetOrCreateAssetData(BuildLayout.DataFromOtherAsset asset, out AssetData assetData) { if (AssetGuidToChildIndex.TryGetValue(asset.AssetGuid, out int value)) { assetData = Children[value] as AssetData; return false; } assetData = new AssetData(asset); AssetGuidToChildIndex.Add(asset.AssetGuid, Children.Count); Children.Add(assetData); assetData.Parent = this; return true; } /// /// /// /// /// /// true if new assetData is created, else false is already a child of bundle public bool GetOrCreateAssetData(BuildLayout.ExplicitAsset asset, out AssetData assetData) { if (AssetGuidToChildIndex.TryGetValue(asset.Guid, out int value)) { assetData = Children[value] as AssetData; return false; } assetData = new AssetData(asset); AssetGuidToChildIndex.Add(asset.Guid, Children.Count); Children.Add(assetData); assetData.Parent = this; return true; } } internal class AssetData : ContentData { public readonly string AssetGuid; public readonly AssetType MainAssetType; public bool IsImplicit => ReportImplicitData != null; public bool FullyLoaded => LoadedObjectIndices.Count == 0 || LoadedObjectIndices.Count == Children.Count; public readonly BuildLayout.ExplicitAsset ReportExplicitData; public readonly BuildLayout.DataFromOtherAsset ReportImplicitData; public List ReportObjects { get { if (ReportExplicitData != null) return ReportExplicitData.Objects; return ReportImplicitData.Objects; } } // if empty = all public HashSet LoadedObjectIndices = new HashSet(); public Dictionary LocalIdToChildIndex = new Dictionary(); public string AssetPath => ReportExplicitData != null ? ReportExplicitData.AssetPath : ReportImplicitData != null ? ReportImplicitData.AssetPath : null; public override int TreeViewID { get { if (IsImplicit && Parent != null) { BundleData bundleData = (BundleData)Parent; return HashCode.Combine(bundleData.BundleCode, AssetGuid.GetHashCode()); } return AssetGuid.GetHashCode(); } } public override string GetCellContent(string colName) { if (colName == TreeColumnNames.TreeColumnType) return MainAssetType.ToString(); return base.GetCellContent(colName); } public AssetData(AssetFrameData frameData) { Name = frameData.AssetCode.ToString(); AddressableHandles = frameData.ReferenceCount; Status = frameData.Status; AssetGuid = ""; } public AssetData(BuildLayout.ExplicitAsset reportAsset) { Debug.Assert(reportAsset != null); Name = reportAsset.AddressableName == null ? reportAsset.AssetPath : reportAsset.AddressableName; AddressableHandles = 0; AssetGuid = reportAsset.Guid; MainAssetType = reportAsset.MainAssetType; ReportExplicitData = reportAsset; } public AssetData(BuildLayout.DataFromOtherAsset reportAsset) { Debug.Assert(reportAsset != null); Name = reportAsset.AssetPath; AddressableHandles = 0; AssetGuid = reportAsset.AssetGuid; MainAssetType = reportAsset.MainAssetType; ReportImplicitData = reportAsset; } public void Update(AssetFrameData frameData) { AddressableHandles = frameData.ReferenceCount; Status = frameData.Status; m_PercentComplete = frameData.PercentComplete; } public void AddLoadedObjects(List indicesAdding) { // if (this.AddressedCount > 0) // fully loaded // return; this.LoadedObjectIndices.UnionWith(indicesAdding); } public ObjectData GetOrCreateObjectData(BuildLayout.ObjectData obj) { if (LocalIdToChildIndex.TryGetValue(obj.LocalIdentifierInFile, out int value)) return Children[value] as ObjectData; ObjectData objectData = new ObjectData(obj); LocalIdToChildIndex.Add(obj.LocalIdentifierInFile, Children.Count); Children.Add(objectData); objectData.Parent = this; return objectData; } } internal class ObjectData : ContentData { public readonly AssetType AssetType; public readonly string ComponentName; private readonly long LocalIdentifierInFile; public override int TreeViewID { get { if (Parent != null) { AssetData assetData = (AssetData)Parent; return HashCode.Combine(assetData.TreeViewID, LocalIdentifierInFile.GetHashCode()); } return LocalIdentifierInFile.GetHashCode(); } } public override string GetCellContent(string colName) { return colName switch { TreeColumnNames.TreeColumnType => AssetType.ToString(), TreeColumnNames.TreeColumnAddressedCount => "", _ => base.GetCellContent(colName) }; } public ObjectData(BuildLayout.ObjectData obj) { LocalIdentifierInFile = obj.LocalIdentifierInFile; if (string.IsNullOrEmpty(obj.ObjectName)) Name = obj.LocalIdentifierInFile.ToString(); else if (!string.IsNullOrEmpty(obj.ComponentName)) Name = $"{obj.ObjectName} ({obj.ComponentName})"; else Name = obj.ObjectName; AssetType = obj.AssetType; ComponentName = obj.ComponentName; } } internal class ContainerData : ContentData { public override int TreeViewID { get { if (Parent != null) { if (Parent is BundleData bundleParent) return HashCode.Combine(bundleParent.BundleCode, Name.GetHashCode()); return HashCode.Combine(Parent.GetHashCode(), Name.GetHashCode()); } return Name.GetHashCode(); } } public override string GetCellContent(string colName) { return colName switch { TreeColumnNames.TreeColumnType => "", TreeColumnNames.TreeColumnAddressedCount => "", TreeColumnNames.TreeColumnStatus => "", TreeColumnNames.TreeColumnReferencedBy => "", TreeColumnNames.TreeColumnReferencesTo => "", _ => base.GetCellContent(colName) }; } } } #endif