2022-01-16 05:40:49 +03:00

309 lines
10 KiB
C#

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<string> scenesReferencingAsset;
[SerializeField]
private bool usedInBuild;
[SerializeField]
private bool isFolder;
[SerializeField]
private Dictionary<AH_MultiColumnHeader.AssetShowMode, long> combinedAssetSizeInFolder = new Dictionary<AH_MultiColumnHeader.AssetShowMode, long>();
//Dictionary of asset types and their icons (Cant be serialized)
private static Dictionary<Type, Texture> iconDictionary = new Dictionary<Type, Texture>();
#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<string> 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<string> 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<AH_MultiColumnHeader.AssetShowMode, long>();
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<string> GetUnusedPathsRecursively()
{
List<string> unusedAssetsInFolder = new List<string>();
//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<string> GetStoredIconTypes()
{
List<string> iconTypesSerialized = new List<string>();
foreach (var item in iconDictionary)
{
iconTypesSerialized.Add(Heureka_Serializer.SerializeType(item.Key));
}
return iconTypesSerialized;
}
internal static List<Texture> GetStoredIconTextures()
{
List<Texture> iconTexturesSerialized = new List<Texture>();
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<string> serializationHelperListIconTypes, List<Texture> serializationHelperListIconTextures)
{
iconDictionary = new Dictionary<Type, Texture>();
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];
}
}
}