操作前,务必备份项目
using UnityEditor;
using UnityEngine;
using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using Object = UnityEngine.Object;
using JsonUtility = Newtonsoft.Json.JsonUtility;
namespace AssetOptimizes
{
public static class Style
{
private static GUIStyle _flow_node_hex_0;
private static GUIStyle _flow_node_hex_0_on;
private static GUIStyle _flow_node_0;
private static GUIStyle _rich_text;
private static GUIStyle _info1_text;
private static GUIStyle _info2_text;
static Style()
{
//默认字号(静态构造函数/在第一次访问Style静态类时调用)
GUI.skin.label.fontSize = 12;
}
public static GUIStyle flow_node_0
{
get
{
if (_flow_node_0 == null)
{
_flow_node_0 = GUI.skin.GetStyle("flow node 0");
}
return _flow_node_0;
}
}
public static GUIStyle rich_text
{
get
{
if (_rich_text == null)
{
_rich_text = new GUIStyle(GUI.skin.label);
_rich_text.richText = true;
_rich_text.alignment = TextAnchor.MiddleCenter;
}
return _rich_text;
}
}
public static GUIStyle info1_text
{
get
{
if (_info1_text == null)
{
//_info_text = new GUIStyle(GUI.skin.label);
_info1_text = new GUIStyle(GUI.skin.GetStyle("ObjectPickerResultsOdd"));
_info1_text.fontSize = 12;
_info1_text.richText = true;
_info1_text.alignment = TextAnchor.MiddleLeft;
}
return _info1_text;
}
}
public static GUIStyle info2_text
{
get
{
if (_info2_text == null)
{
_info2_text = new GUIStyle(GUI.skin.GetStyle("ObjectPickerPreviewBackground"));
_info2_text.fontSize = 12;
_info2_text.richText = true;
_info2_text.alignment = TextAnchor.MiddleLeft;
}
return _info2_text;
}
}
}
public static class AssetUtility
{
/// <summary> 获取文件的Hash值 </summary>
public static string GetFileSha1(string path)
{
if (System.IO.File.Exists(path))
{
return HashFile(path, "sha1");
}
return string.Empty;
}
/// <summary> 获取文件的MD5值 </summary>
public static string GetFileMD5(string path)
{
if (System.IO.File.Exists(path))
{
return HashFile(path, "md5");
}
return string.Empty;
}
public static string GetSizeName(long _size)
{
var str = _size + "B";
var size = (float)_size;
if (size > 1024)
{
size /= 1024;
str = size.ToString("f1") + "KB";
}
if (size > 1024)
{
size /= 1024;
str = size.ToString("f1") + "MB";
}
return str;
}
/// <summary> 刷新Asset资产 </summary>
public static void RefreshAssetForce()
{
//刷新文件的数据(转换效率慢)
//EditorSettings.serializationMode = SerializationMode.ForceBinary;
//EditorSettings.serializationMode = SerializationMode.ForceText;
//刷新资源视图
AssetDatabase.Refresh();
}
static string HashFile(string path, string type)
{
System.IO.FileStream stream = null;
try
{
stream = new System.IO.FileStream(path, System.IO.FileMode.Open, System.IO.FileAccess.Read);
//计算Hash值
System.Security.Cryptography.HashAlgorithm algorithm;
switch (type?.ToLower())
{
case "md5":
algorithm = System.Security.Cryptography.MD5.Create();
break;
case "sha1":
algorithm = System.Security.Cryptography.SHA1.Create();
break;
default:
throw new Exception("只能使用 sha1 或 md5");
}
byte[] hash_bytes = algorithm.ComputeHash(stream);
return BitConverter.ToString(hash_bytes).Replace("-", "");
}
catch (Exception e)
{
Debug.LogError(e.Message);
}
finally
{
stream?.Close();
}
return string.Empty;
}
}
//资源优化编辑窗口
public class AssetManagerWindow : EditorWindow
{
public enum ViewState
{
/// <summary> 未选中状态 </summary>
NONE = -1,
/// <summary> 全部资源 </summary>
ALL = 0,
/// <summary> 未使用资源 </summary>
UNUSED = 1,
/// <summary> 重复资源 </summary>
MERGE = 2,
}
public enum OrderType
{
/// <summary>
/// 大小
/// </summary>
Size,
/// <summary>
/// 类型
/// </summary>
Type,
/// <summary>
/// 引用计数
/// </summary>
DependentCount,
/// <summary>
/// 被引用计数
/// </summary>
DependentUsedCount,
}
public enum AssetType
{
/// <summary> 全选 </summary>
Everything = -1,
/// <summary> 纹理资源 </summary>
Texture = 1,
/// <summary> 文本资源 </summary>
TextAsset = 2,
/// <summary> 音频资源 </summary>
Audio = 4,
/// <summary> C#脚本 </summary>
MonoScript = 8,
/// <summary> Mat材质球 </summary>
Mat = 16,
/// <summary> Prefab资源 </summary>
Prefab = 32,
/// <summary> Scene资源 </summary>
Unity = 64,
/// <summary> Material资源 </summary>
Material = 128,
/// <summary> Meta文件 </summary>
Meta = 256,
/// <summary> 文件夹 </summary>
Folder = 512,
/// <summary> 其他类型 </summary>
Other = 1024,
}
public class Asset
{
/// <summary> 资源路径 </summary>
public string path { get; private set; }
//名称
public string name { get; private set; }
/// <summary> 资源类型 </summary>
public AssetType type { get; private set; } = AssetType.Other;
/// <summary> 资源类型ID </summary>
public int typeNum { get; private set; } = -1;
/// <summary> GUID(唯一标识符) </summary>
public string guid { get; private set; }
/// <summary> 资源MD5吗(用于判断文件是否一致) </summary>
public string md5 { get; private set; }
/// <summary> 缓存图标 </summary>
public Texture cacheIcon { get; private set; }
/// <summary> 资源大小 </summary>
public long size { get; private set; } = 0;
/// <summary> 资源是否被选中 </summary>
public bool select = false;
/// <summary> 依赖的资源路径 </summary>
public List<Asset> dependencies { get; } = new List<Asset>();
/// <summary> 被其他资源引用 </summary>
public List<Asset> dependenciesUsed { get; } = new List<Asset>();
/// <summary> 相同文件列表 </summary>
public List<Asset> sameList { get; } = new List<Asset>();
/// <summary> 内嵌Spirte信息 </summary>
public List<SpriteMetaData> spriteSheet { get; } = new List<SpriteMetaData>();
/// <summary> Texture导入模式 </summary>
public SpriteImportMode spriteImportMode = SpriteImportMode.None;
private string sizeName = null;
public Asset(string path)
{
this.path = path;
this.md5 = AssetUtility.GetFileMD5(path);
this.guid = AssetDatabase.AssetPathToGUID(path);
this.name = AssetDatabase.LoadMainAssetAtPath(path)?.name;
this.cacheIcon = AssetDatabase.GetCachedIcon(path);
//Type
this.type = AssetType.Other;
if (path.EndsWith(".meta"))
this.type = AssetType.Meta;
else if (path.EndsWith(".jpg") || path.EndsWith(".png"))
this.type = AssetType.Texture;
else if (path.EndsWith(".txt") || path.EndsWith(".json"))
this.type = AssetType.TextAsset;
else if (path.EndsWith(".mp3") || path.EndsWith(".wav"))
this.type = AssetType.Audio;
else if (path.EndsWith(".mat") || path.EndsWith(".material"))
this.type = AssetType.Material;
else if (path.EndsWith(".cs"))
this.type = AssetType.MonoScript;
else if (path.EndsWith(".prefab"))
this.type = AssetType.Prefab;
else if (path.EndsWith(".unity"))
this.type = AssetType.Unity;
else if (System.IO.Directory.Exists(path))
this.type = AssetType.Folder;
this.typeNum = Convert.ToInt32(this.type);
//Debug.Log(AssetDatabase.GetMainAssetTypeAtPath(path));
if (System.IO.File.Exists(path))
{
var info = new FileInfo(path);
this.size = info.Length;
}
}
public string GetSizeName()
{
if (sizeName == null)
{
var size = (float)this.size;
sizeName = size.ToString("f0") + "B";
if (size > 1024)
{
size /= 1024;
sizeName = size.ToString("f1") + "KB";
}
if (size > 1024)
{
size /= 1024;
sizeName = size.ToString("f2") + "MB";
}
}
return sizeName;
}
public int GetInstanceID()
{
return AssetDatabase.LoadAssetAtPath<Object>(path).GetInstanceID();
}
public string GetDependencies()
{
var temp = "";
for (int i = 0; i < dependencies.Count; i++)
{
temp += "\n" + (i + 1) + "." + dependencies[i].path;
}
return temp;
}
public string GetDependenciesUsed()
{
var temp = "";
for (int i = 0; i < dependenciesUsed.Count; i++)
{
temp += "\n" + (i + 1) + "." + dependenciesUsed[i].path;
}
return temp;
}
public string GetSameFiles()
{
var temp = "";
for (int i = 0; i < sameList.Count; i++)
{
temp += "\n" + (i + 1) + "." + sameList[i].path;
}
return temp;
}
public string GetSpriteSheet()
{
if (spriteImportMode != SpriteImportMode.None)
{
var temp = "\t" + Enum.GetName(typeof(SpriteImportMode), spriteImportMode);
for (int i = 0; i < spriteSheet.Count; i++)
{
temp += "\n" + (i + 1) + ".Name:" + spriteSheet[i].name + "\tRect:" + spriteSheet[i].rect;
}
return temp;
}
return "";
}
public string GetInfo()
{
string str = @"[信息] <b>Name:</b>{0} <b>GUID:</b>{1}
<b>Path:</b>{2}
<b>Size:</b>{3}({4})
<b>MD5:</b>{5}
<b>依赖:</b>{6}
<b>被依赖:</b>{7}
<b>相同文件:</b>{8}
<b>纹理模式:</b>{9}
";
return string.Format(str, name, guid, path, GetSizeName(), size, md5,
GetDependencies(), GetDependenciesUsed(), GetSameFiles(), GetSpriteSheet());
}
}
//当前按钮状态
private ViewState menuState = ViewState.NONE;
private int viewId = -1;
private bool viewRefresh = true;
//ScrollView 进度条
private Vector2 contentVec2;
//所有资源列表
private Dictionary<string, Asset> assetsMappingGuids = new Dictionary<string, Asset>();
private List<Asset> assets = new List<Asset>();
private List<Asset> assetsAll = new List<Asset>();
//是否获取所有资源信息
private bool completeAllAssets = false;
//是否建立起依赖引用信息
private bool completeDependencies = false;
///是否建立MD5比对信息
private bool completeAllMd5 = false;
//渲染页数
private int page = 1;
private int pageSize = 20;
//选择的资源列表
private List<Asset> selectAssets = new List<Asset>();
//选择删除的资源列表
private List<Asset> selectDelete = new List<Asset>();
//选择合并的资源列表
private List<List<Asset>> selectMerge = new List<List<Asset>>();
//选择的类型
private AssetType selectType = AssetType.Everything;
//排序规则
private OrderType orderType = OrderType.Size;
//是否升序Ascending/降序Descending
private bool ascending = false;
//筛选条件
private string search = null;
//filter 需要过滤的字段
private string filterString;
private string filterDefault = "Editor;Gizmos;Plugins;Resources;StreamingAssets;Editor Default Resources;";
private string[] filter;
[MenuItem("Tools/AssetsManager/Manager")]
static AssetManagerWindow InitWindow()
{
AssetManagerWindow window = (AssetManagerWindow)EditorWindow.GetWindow(typeof(AssetManagerWindow), false, "Manager");
window.Show();
return window;
}
[MenuItem("Assets/Check/Dependencies")]
static void CheckDependencies()
{
var path = Selection.activeObject != null ? AssetDatabase.GetAssetPath(Selection.activeObject) : null;
if (!string.IsNullOrEmpty(path) && File.Exists(path))
{
var dependencies = AssetDatabase.GetDependencies(path);
var temp = "";
for (int i = 0; i < dependencies.Length; i++)
{
temp += "\n" + (i + 1) + "." + dependencies[i];
}
Debug.Log(string.Format("<b>Path:</b>{0} \n<b>依赖:</b>{1}", path, temp));
}
}
[MenuItem("Assets/Check/DependenciesUsed")]
static void CheckDependenciesUsed()
{
var path = Selection.activeObject != null ? AssetDatabase.GetAssetPath(Selection.activeObject) : null;
if (!string.IsNullOrEmpty(path) && File.Exists(path))
{
//Dependencies
var temp1_i = 0;
var temp1 = "";
var dependencies = AssetDatabase.GetDependencies(path);
for (int i = 0; i < dependencies.Length; i++)
{
temp1 += "\n" + (temp1_i + 1) + "." + dependencies[i];
temp1_i++;
}
//DependenciesUsed
var temp2_i = 0;
var temp2 = "";
string[] paths = AssetDatabase.GetAllAssetPaths();
for (int i = 0; i < paths.Length; i++)
{
try
{
var cancel = EditorUtility.DisplayCancelableProgressBar(string.Format("检查依赖中({0}/{1})", i, paths.Length), paths[i], (float)i / paths.Length);
if (cancel)
{
InfoWindow.Log("取消检查:" + path);
EditorUtility.ClearProgressBar();
return;
}
i