using System; using System.Collections.Generic; using UnityEditor; using UnityEngine; using UnityEngine.Profiling; namespace HeurekaGames.AssetHunterPRO.BaseTreeviewImpl.AssetTreeView { [System.Serializable] public class AH_TreeviewElement : TreeElement, ISerializationCallbackReceiver { #region Fields [SerializeField] private string absPath; //[SerializeField] private string relativePath; [SerializeField] private string guid; //[SerializeField] private Type assetType; [SerializeField] private string assetTypeSerialized; private long assetSize; //private string assestSizeStringRepresentation; //[SerializeField] private long fileSize; //[SerializeField] //private string fileSizeStringRepresentation; [SerializeField] private List scenesReferencingAsset; [SerializeField] private bool usedInBuild; [SerializeField] private bool isFolder; [SerializeField] private Dictionary combinedAssetSizeInFolder = new Dictionary(); //Dictionary of asset types and their icons (Cant be serialized) private static Dictionary iconDictionary = new Dictionary(); #endregion #region Properties public string RelativePath { get { if(!string.IsNullOrEmpty(relativePath)) return relativePath; else return relativePath = UnityEditor.AssetDatabase.GUIDToAssetPath(GUID); } } public string GUID { get { return guid; } } public Type AssetType { get { return assetType; } } public string AssetTypeSerialized { get { if(String.IsNullOrEmpty(assetTypeSerialized) && assetType!=null) assetTypeSerialized = Heureka_Serializer.SerializeType(assetType); return assetTypeSerialized; } } public long AssetSize { get { if(UsedInBuild && assetSize == 0) { UnityEngine.Object asset = UnityEditor.AssetDatabase.LoadMainAssetAtPath(RelativePath); //#if UNITY_2017_1_OR_NEWER if (asset != null) return this.assetSize = Profiler.GetRuntimeMemorySizeLong(asset) / 2; else return -1; } else return assetSize; } } public string AssetSizeStringRepresentation { get { return AH_Utils.GetSizeAsString(AssetSize); } } public long FileSize { get { if (fileSize != 0) return fileSize; else { var fileInfo = new System.IO.FileInfo(absPath); if (fileInfo.Exists) return fileSize = fileInfo != null ? fileInfo.Length : 0; else return -1; } } } public string FileSizeStringRepresentation { get { return AH_Utils.GetSizeAsString(fileSize); } } public List ScenesReferencingAsset { get { return scenesReferencingAsset; } } public int SceneRefCount { get { return (scenesReferencingAsset != null) ? scenesReferencingAsset.Count : 0; } } public bool UsedInBuild { get { return usedInBuild; } } public bool IsFolder { get { return isFolder; } } #endregion public AH_TreeviewElement(string absPath, int depth, int id, string relativepath, string assetID, List scenesReferencing, bool isUsedInBuild) : base(System.IO.Path.GetFileName(absPath), depth, id) { this.absPath = absPath; var assetPath = relativepath; this.guid = UnityEditor.AssetDatabase.AssetPathToGUID(assetPath); this.scenesReferencingAsset = scenesReferencing; this.usedInBuild = isUsedInBuild; //Return if its a folder if (isFolder = UnityEditor.AssetDatabase.IsValidFolder(assetPath)) return; //Return if its not an asset if (!string.IsNullOrEmpty(this.guid)) { this.assetType = UnityEditor.AssetDatabase.GetMainAssetTypeAtPath(assetPath); updateIconDictEntry(); } } internal long GetFileSizeRecursively(AH_MultiColumnHeader.AssetShowMode showMode) { if (combinedAssetSizeInFolder == null) combinedAssetSizeInFolder = new Dictionary(); if (combinedAssetSizeInFolder.ContainsKey(showMode)) return combinedAssetSizeInFolder[showMode]; //TODO store these values instead of calculating each and every time? long combinedChildrenSize = 0; //Combine the size of all the children if (hasChildren) foreach (AH_TreeviewElement item in children) { bool validAsset = (showMode == AH_MultiColumnHeader.AssetShowMode.All) || ((showMode == AH_MultiColumnHeader.AssetShowMode.Unused && !item.usedInBuild) || (showMode == AH_MultiColumnHeader.AssetShowMode.Used && item.usedInBuild)); //Loop thropugh folders and assets thats used not in build if (validAsset || item.isFolder) combinedChildrenSize += item.GetFileSizeRecursively(showMode); } combinedChildrenSize += this.FileSize; //Cache the value combinedAssetSizeInFolder.Add(showMode, combinedChildrenSize); return combinedChildrenSize; } #region Serialization callbacks //TODO Maybe we can store type infos in BuildInfoTreeView instead of on each individual element, might be performance heavy //Store serializable string so we can retrieve type after serialization public void OnBeforeSerialize() { if (assetType != null) assetTypeSerialized = Heureka_Serializer.SerializeType(assetType); } //Set type from serialized property public void OnAfterDeserialize() { if (!string.IsNullOrEmpty(AssetTypeSerialized)) { this.assetType = Heureka_Serializer.DeSerializeType(AssetTypeSerialized); //assetTypeSerialized = ""; } } #endregion internal bool AssetMatchesState(AH_MultiColumnHeader.AssetShowMode showMode) { //Test if we want to add this element (We dont want to show "used" when window searches for "unused" return (AssetType != null && ((showMode == AH_MultiColumnHeader.AssetShowMode.All) || ((showMode == AH_MultiColumnHeader.AssetShowMode.Used && usedInBuild) || (showMode == AH_MultiColumnHeader.AssetShowMode.Unused && !usedInBuild)))); } internal bool HasChildrenThatMatchesState(AH_MultiColumnHeader.AssetShowMode showMode) { if (!hasChildren) return false; //Check if a valid child exit somewhere in this branch foreach (AH_TreeviewElement child in children) { if (child.AssetMatchesState(showMode)) return true; else if (child.HasChildrenThatMatchesState(showMode)) return true; else continue; } return false; } internal List GetUnusedPathsRecursively() { List unusedAssetsInFolder = new List(); //Combine the size of all the children if (hasChildren) foreach (AH_TreeviewElement item in children) { if (item.isFolder) unusedAssetsInFolder.AddRange(item.GetUnusedPathsRecursively()); //Loop thropugh folders and assets thats used not in build else if (!item.usedInBuild) unusedAssetsInFolder.Add(item.RelativePath); } return unusedAssetsInFolder; } internal static List GetStoredIconTypes() { List iconTypesSerialized = new List(); foreach (var item in iconDictionary) { iconTypesSerialized.Add(Heureka_Serializer.SerializeType(item.Key)); } return iconTypesSerialized; } internal static List GetStoredIconTextures() { List iconTexturesSerialized = new List(); foreach (var item in iconDictionary) { iconTexturesSerialized.Add(item.Value); } return iconTexturesSerialized; } private void updateIconDictEntry() { if (assetType != null && !iconDictionary.ContainsKey(assetType)) iconDictionary.Add(assetType, UnityEditor.EditorGUIUtility.ObjectContent(null, assetType).image); } internal static void UpdateIconDictAfterSerialization(List serializationHelperListIconTypes, List serializationHelperListIconTextures) { iconDictionary = new Dictionary(); for (int i = 0; i < serializationHelperListIconTypes.Count; i++) { Type deserializedType = Heureka_Serializer.DeSerializeType(serializationHelperListIconTypes[i]); if (deserializedType != null) iconDictionary.Add(Heureka_Serializer.DeSerializeType(serializationHelperListIconTypes[i]), serializationHelperListIconTextures[i]); } } internal static Texture GetIcon(Type assetType) { return iconDictionary[assetType]; } } }