2022-02-02 19:08:18 +03:00

198 lines
7.9 KiB
C#

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using UnityEditor;
using UnityEngine;
namespace HeurekaGames.AssetHunterPRO
{
[Serializable]
public class AH_DuplicateDataManager : ScriptableSingleton<AH_DuplicateDataManager>, ISerializationCallbackReceiver
{
[Serializable]
public class DuplicateAssetData
{
public List<string> Guids;
private List<string> paths;
private Texture2D preview;
public Texture2D Preview
{
get
{
if (preview != null)
return preview;
else
{
var loadedObj = AssetDatabase.LoadMainAssetAtPath(Paths[0]);
return preview = AssetPreview.GetAssetPreview(loadedObj);
}
}
}
public List<string> Paths
{
get
{
if (paths != null)
return paths;
else
return this.paths = this.Guids.Select(x => AssetDatabase.GUIDToAssetPath(x)).ToList();
}
}
public DuplicateAssetData(List<string> guids)
{
this.Guids = guids;
}
}
[SerializeField] public bool IsDirty = true;
public bool RequiresScrollviewRebuild { get; internal set; }
public bool HasCache { get; private set; }
[SerializeField] private Dictionary<string, DuplicateAssetData> duplicateDict = new Dictionary<string, DuplicateAssetData>();
#region serializationHelpers
[SerializeField] private List<string> _duplicateDictKeys = new List<string>();
[SerializeField] private List<DuplicateAssetData> _duplicateDictValues = new List<DuplicateAssetData>();
public Dictionary<string, DuplicateAssetData> Entries { get {return duplicateDict; } }
#endregion
internal bool HasDuplicates()
{
return duplicateDict.Count > 0;
}
public void OnBeforeSerialize()
{
_duplicateDictKeys.Clear();
_duplicateDictValues.Clear();
foreach (var kvp in duplicateDict)
{
_duplicateDictKeys.Add(kvp.Key);
_duplicateDictValues.Add(kvp.Value);
}
}
public void OnAfterDeserialize()
{
duplicateDict = new Dictionary<string, DuplicateAssetData>();
for (int i = 0; i != Math.Min(_duplicateDictKeys.Count, _duplicateDictValues.Count); i++)
duplicateDict.Add(_duplicateDictKeys[i], new DuplicateAssetData(_duplicateDictValues[i].Guids));
}
internal void RefreshData()
{
//We need to analyze the scrollview to optimize how we draw it
RequiresScrollviewRebuild = true;
duplicateDict = new Dictionary<string, DuplicateAssetData>();
var hashDict = new Dictionary<string, List<string>>();
var paths = AssetDatabase.GetAllAssetPaths();
var pathCount = paths.Length;
using (System.Security.Cryptography.MD5 md5 = System.Security.Cryptography.MD5.Create())
{
string assetPathGuid;
string hash;
UnityEngine.Object LoadedObj;
int maxReadCount = 30;//We dont need to read every line using streamreader. We only need the m_name property, and that comes early in the file
int lineCounter = 0;
for (int i = 0; i < pathCount; i++)
{
var path = paths[i];
if (AssetDatabase.IsValidFolder(path) || !path.StartsWith("Assets")) //Slow, could be done recusively
continue;
if (EditorUtility.DisplayCancelableProgressBar("Finding duplicates", path, ((float)i / (float)pathCount)))
{
duplicateDict = new Dictionary<string, DuplicateAssetData>();
break;
}
assetPathGuid = AssetDatabase.AssetPathToGUID(path);
LoadedObj = AssetDatabase.LoadMainAssetAtPath(path);
string line = "";
bool foundName = false;
if (path.EndsWith("LightingData.asset") || path.Contains("NavMesh"))
Debug.Log("LOOK HERE");
if (LoadedObj != null)
{
try
{
using (FileStream stream = File.OpenRead(path))
{
//We need to loop through certain native types (such as materials) to remove name from metadata - if we dont they wont have same hash
if (AssetDatabase.IsNativeAsset(LoadedObj) && !LoadedObj.GetType().IsSubclassOf(typeof(ScriptableObject)))
{
string appendString = "";
using (StreamReader sr = new StreamReader(stream))
{
//bool foundFileName = false;
lineCounter = 0;
while (!sr.EndOfStream)
{
lineCounter++;
if (lineCounter >= maxReadCount)
appendString += sr.ReadToEnd();
else
{
line = sr.ReadLine();
foundName = line.Contains(LoadedObj.name);
if (!foundName)//we want to ignore the m_name property, since that modifies the hashvalue
appendString += line;
else
{
appendString += sr.ReadToEnd();
}
}
}
}
hash = BitConverter.ToString(System.Text.UnicodeEncoding.Unicode.GetBytes(appendString));
//hash = appendString.GetHashCode().ToString();
}
else
{
hash = BitConverter.ToString(md5.ComputeHash(stream));
}
if (!hashDict.ContainsKey(hash))
hashDict.Add(hash, new List<string>() { assetPathGuid });
else
hashDict[hash].Add(assetPathGuid);
}
}
catch (Exception e)
{
Debug.LogError(e);
}
}
}
foreach (var pair in hashDict)
{
if (pair.Value.Count > 1)
{
duplicateDict.Add(pair.Key, new DuplicateAssetData(pair.Value));
}
}
IsDirty = false;
HasCache = true;
EditorUtility.ClearProgressBar();
}
}
}
}