325 lines
12 KiB
C#
325 lines
12 KiB
C#
//------------------------------------------------------------
|
|
// Game Framework
|
|
// Copyright © 2013-2021 Jiang Yin. All rights reserved.
|
|
// Homepage: https://gameframework.cn/
|
|
// Feedback: mailto:ellan@gameframework.cn
|
|
//------------------------------------------------------------
|
|
|
|
using GameFramework;
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using UnityEditor;
|
|
using UnityEngine;
|
|
|
|
namespace UnityGameFramework.Editor.ResourceTools
|
|
{
|
|
public sealed partial class ResourceAnalyzerController
|
|
{
|
|
private readonly ResourceCollection m_ResourceCollection;
|
|
|
|
private readonly Dictionary<string, DependencyData> m_DependencyDatas;
|
|
private readonly Dictionary<string, List<Asset>> m_ScatteredAssets;
|
|
private readonly List<string[]> m_CircularDependencyDatas;
|
|
private readonly HashSet<Stamp> m_AnalyzedStamps;
|
|
|
|
public ResourceAnalyzerController()
|
|
: this(null)
|
|
{
|
|
}
|
|
|
|
public ResourceAnalyzerController(ResourceCollection resourceCollection)
|
|
{
|
|
m_ResourceCollection = resourceCollection != null ? resourceCollection : new ResourceCollection();
|
|
|
|
m_ResourceCollection.OnLoadingResource += delegate (int index, int count)
|
|
{
|
|
if (OnLoadingResource != null)
|
|
{
|
|
OnLoadingResource(index, count);
|
|
}
|
|
};
|
|
|
|
m_ResourceCollection.OnLoadingAsset += delegate (int index, int count)
|
|
{
|
|
if (OnLoadingAsset != null)
|
|
{
|
|
OnLoadingAsset(index, count);
|
|
}
|
|
};
|
|
|
|
m_ResourceCollection.OnLoadCompleted += delegate ()
|
|
{
|
|
if (OnLoadCompleted != null)
|
|
{
|
|
OnLoadCompleted();
|
|
}
|
|
};
|
|
|
|
m_DependencyDatas = new Dictionary<string, DependencyData>(StringComparer.Ordinal);
|
|
m_ScatteredAssets = new Dictionary<string, List<Asset>>(StringComparer.Ordinal);
|
|
m_AnalyzedStamps = new HashSet<Stamp>();
|
|
m_CircularDependencyDatas = new List<string[]>();
|
|
}
|
|
|
|
public event GameFrameworkAction<int, int> OnLoadingResource = null;
|
|
|
|
public event GameFrameworkAction<int, int> OnLoadingAsset = null;
|
|
|
|
public event GameFrameworkAction OnLoadCompleted = null;
|
|
|
|
public event GameFrameworkAction<int, int> OnAnalyzingAsset = null;
|
|
|
|
public event GameFrameworkAction OnAnalyzeCompleted = null;
|
|
|
|
public void Clear()
|
|
{
|
|
m_ResourceCollection.Clear();
|
|
m_DependencyDatas.Clear();
|
|
m_ScatteredAssets.Clear();
|
|
m_CircularDependencyDatas.Clear();
|
|
m_AnalyzedStamps.Clear();
|
|
}
|
|
|
|
public bool Prepare()
|
|
{
|
|
m_ResourceCollection.Clear();
|
|
return m_ResourceCollection.Load();
|
|
}
|
|
|
|
public void Analyze()
|
|
{
|
|
m_DependencyDatas.Clear();
|
|
m_ScatteredAssets.Clear();
|
|
m_CircularDependencyDatas.Clear();
|
|
m_AnalyzedStamps.Clear();
|
|
|
|
HashSet<string> scriptAssetNames = GetFilteredAssetNames("t:Script");
|
|
Asset[] assets = m_ResourceCollection.GetAssets();
|
|
int count = assets.Length;
|
|
for (int i = 0; i < count; i++)
|
|
{
|
|
if (OnAnalyzingAsset != null)
|
|
{
|
|
OnAnalyzingAsset(i, count);
|
|
}
|
|
|
|
string assetName = assets[i].Name;
|
|
if (string.IsNullOrEmpty(assetName))
|
|
{
|
|
Debug.LogWarning(Utility.Text.Format("Can not find asset by guid '{0}'.", assets[i].Guid));
|
|
continue;
|
|
}
|
|
|
|
DependencyData dependencyData = new DependencyData();
|
|
AnalyzeAsset(assetName, assets[i], dependencyData, scriptAssetNames);
|
|
dependencyData.RefreshData();
|
|
m_DependencyDatas.Add(assetName, dependencyData);
|
|
}
|
|
|
|
foreach (List<Asset> scatteredAsset in m_ScatteredAssets.Values)
|
|
{
|
|
scatteredAsset.Sort((a, b) => a.Name.CompareTo(b.Name));
|
|
}
|
|
|
|
m_CircularDependencyDatas.AddRange(new CircularDependencyChecker(m_AnalyzedStamps.ToArray()).Check());
|
|
|
|
if (OnAnalyzeCompleted != null)
|
|
{
|
|
OnAnalyzeCompleted();
|
|
}
|
|
}
|
|
|
|
private void AnalyzeAsset(string assetName, Asset hostAsset, DependencyData dependencyData, HashSet<string> scriptAssetNames)
|
|
{
|
|
string[] dependencyAssetNames = AssetDatabase.GetDependencies(assetName, false);
|
|
foreach (string dependencyAssetName in dependencyAssetNames)
|
|
{
|
|
if (scriptAssetNames.Contains(dependencyAssetName))
|
|
{
|
|
continue;
|
|
}
|
|
|
|
if (dependencyAssetName == assetName)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
if (dependencyAssetName.EndsWith(".unity", StringComparison.Ordinal))
|
|
{
|
|
// 忽略对场景的依赖
|
|
continue;
|
|
}
|
|
|
|
Stamp stamp = new Stamp(hostAsset.Name, dependencyAssetName);
|
|
if (m_AnalyzedStamps.Contains(stamp))
|
|
{
|
|
continue;
|
|
}
|
|
|
|
m_AnalyzedStamps.Add(stamp);
|
|
|
|
string guid = AssetDatabase.AssetPathToGUID(dependencyAssetName);
|
|
if (string.IsNullOrEmpty(guid))
|
|
{
|
|
Debug.LogWarning(Utility.Text.Format("Can not find guid by asset '{0}'.", dependencyAssetName));
|
|
continue;
|
|
}
|
|
|
|
Asset asset = m_ResourceCollection.GetAsset(guid);
|
|
if (asset != null)
|
|
{
|
|
dependencyData.AddDependencyAsset(asset);
|
|
}
|
|
else
|
|
{
|
|
dependencyData.AddScatteredDependencyAsset(dependencyAssetName);
|
|
|
|
List<Asset> scatteredAssets = null;
|
|
if (!m_ScatteredAssets.TryGetValue(dependencyAssetName, out scatteredAssets))
|
|
{
|
|
scatteredAssets = new List<Asset>();
|
|
m_ScatteredAssets.Add(dependencyAssetName, scatteredAssets);
|
|
}
|
|
|
|
scatteredAssets.Add(hostAsset);
|
|
|
|
AnalyzeAsset(dependencyAssetName, hostAsset, dependencyData, scriptAssetNames);
|
|
}
|
|
}
|
|
}
|
|
|
|
public Asset GetAsset(string assetName)
|
|
{
|
|
return m_ResourceCollection.GetAsset(AssetDatabase.AssetPathToGUID(assetName));
|
|
}
|
|
|
|
public string[] GetAssetNames()
|
|
{
|
|
return GetAssetNames(AssetsOrder.AssetNameAsc, null);
|
|
}
|
|
|
|
public string[] GetAssetNames(AssetsOrder order, string filter)
|
|
{
|
|
HashSet<string> filteredAssetNames = GetFilteredAssetNames(filter);
|
|
IEnumerable<KeyValuePair<string, DependencyData>> filteredResult = m_DependencyDatas.Where(pair => filteredAssetNames.Contains(pair.Key));
|
|
IEnumerable<KeyValuePair<string, DependencyData>> orderedResult = null;
|
|
switch (order)
|
|
{
|
|
case AssetsOrder.AssetNameAsc:
|
|
orderedResult = filteredResult.OrderBy(pair => pair.Key);
|
|
break;
|
|
|
|
case AssetsOrder.AssetNameDesc:
|
|
orderedResult = filteredResult.OrderByDescending(pair => pair.Key);
|
|
break;
|
|
|
|
case AssetsOrder.DependencyResourceCountAsc:
|
|
orderedResult = filteredResult.OrderBy(pair => pair.Value.DependencyResourceCount);
|
|
break;
|
|
|
|
case AssetsOrder.DependencyResourceCountDesc:
|
|
orderedResult = filteredResult.OrderByDescending(pair => pair.Value.DependencyResourceCount);
|
|
break;
|
|
|
|
case AssetsOrder.DependencyAssetCountAsc:
|
|
orderedResult = filteredResult.OrderBy(pair => pair.Value.DependencyAssetCount);
|
|
break;
|
|
|
|
case AssetsOrder.DependencyAssetCountDesc:
|
|
orderedResult = filteredResult.OrderByDescending(pair => pair.Value.DependencyAssetCount);
|
|
break;
|
|
|
|
case AssetsOrder.ScatteredDependencyAssetCountAsc:
|
|
orderedResult = filteredResult.OrderBy(pair => pair.Value.ScatteredDependencyAssetCount);
|
|
break;
|
|
|
|
case AssetsOrder.ScatteredDependencyAssetCountDesc:
|
|
orderedResult = filteredResult.OrderByDescending(pair => pair.Value.ScatteredDependencyAssetCount);
|
|
break;
|
|
|
|
default:
|
|
orderedResult = filteredResult;
|
|
break;
|
|
}
|
|
|
|
return orderedResult.Select(pair => pair.Key).ToArray();
|
|
}
|
|
|
|
public DependencyData GetDependencyData(string assetName)
|
|
{
|
|
DependencyData dependencyData = null;
|
|
if (m_DependencyDatas.TryGetValue(assetName, out dependencyData))
|
|
{
|
|
return dependencyData;
|
|
}
|
|
|
|
return dependencyData;
|
|
}
|
|
|
|
public string[] GetScatteredAssetNames()
|
|
{
|
|
return GetScatteredAssetNames(ScatteredAssetsOrder.HostAssetCountDesc, null);
|
|
}
|
|
|
|
public string[] GetScatteredAssetNames(ScatteredAssetsOrder order, string filter)
|
|
{
|
|
HashSet<string> filterAssetNames = GetFilteredAssetNames(filter);
|
|
IEnumerable<KeyValuePair<string, List<Asset>>> filteredResult = m_ScatteredAssets.Where(pair => filterAssetNames.Contains(pair.Key) && pair.Value.Count > 1);
|
|
IEnumerable<KeyValuePair<string, List<Asset>>> orderedResult = null;
|
|
switch (order)
|
|
{
|
|
case ScatteredAssetsOrder.AssetNameAsc:
|
|
orderedResult = filteredResult.OrderBy(pair => pair.Key);
|
|
break;
|
|
|
|
case ScatteredAssetsOrder.AssetNameDesc:
|
|
orderedResult = filteredResult.OrderByDescending(pair => pair.Key);
|
|
break;
|
|
|
|
case ScatteredAssetsOrder.HostAssetCountAsc:
|
|
orderedResult = filteredResult.OrderBy(pair => pair.Value.Count);
|
|
break;
|
|
|
|
case ScatteredAssetsOrder.HostAssetCountDesc:
|
|
orderedResult = filteredResult.OrderByDescending(pair => pair.Value.Count);
|
|
break;
|
|
|
|
default:
|
|
orderedResult = filteredResult;
|
|
break;
|
|
}
|
|
|
|
return orderedResult.Select(pair => pair.Key).ToArray();
|
|
}
|
|
|
|
public Asset[] GetHostAssets(string scatteredAssetName)
|
|
{
|
|
List<Asset> assets = null;
|
|
if (m_ScatteredAssets.TryGetValue(scatteredAssetName, out assets))
|
|
{
|
|
return assets.ToArray();
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
public string[][] GetCircularDependencyDatas()
|
|
{
|
|
return m_CircularDependencyDatas.ToArray();
|
|
}
|
|
|
|
private HashSet<string> GetFilteredAssetNames(string filter)
|
|
{
|
|
string[] filterAssetGuids = AssetDatabase.FindAssets(filter);
|
|
HashSet<string> filterAssetNames = new HashSet<string>();
|
|
foreach (string filterAssetGuid in filterAssetGuids)
|
|
{
|
|
filterAssetNames.Add(AssetDatabase.GUIDToAssetPath(filterAssetGuid));
|
|
}
|
|
|
|
return filterAssetNames;
|
|
}
|
|
}
|
|
}
|