using System.Collections;
using System.Collections.Generic;
using UnityEditor;
using UnityEditor.U2D;
using UnityEngine;
using UnityEngine.U2D;
using UnityEngine.UI;
/// <summary>
/// UI预制体检查
///
/// 1.使用图集的数量
/// 2.不在图集中的图片
/// 3.使用的大图资源
/// 4.引用丢失
///
/// </summary>
public class UIPrefabChecker
{
enum CheckType
{
UsingAtlas,
ImageNotInAtals,
LargeImge,
MissRef,
}
private static Dictionary<CheckType, string> m_checkDesDict = new Dictionary<CheckType, string>()
{
{ CheckType.UsingAtlas,"using atlas count is"},
{ CheckType.ImageNotInAtals,"these image not in atlas"},
{ CheckType.LargeImge,"consider change to texture or scale image"},
{ CheckType.MissRef,"miss ref"},
};
[MenuItem(ToolDes.UI_CheckUIPrefab)]
public static void DeepCheck()
{
var objs = CollectResUtility.SelectObjs();
if (objs.Length > 0)
{
CollectAtlasSprite();
}
int index = 0;
List<string> report = new List<string>();
foreach (var obj in objs)
{
index++;
var path = AssetDatabase.GetAssetPath(obj);
if (path.Contains(".prefab"))
{
var log = DeepCheck(obj);
if (log != null)
report.Add(log);
EditorUtility.DisplayProgressBar("ui prefab checking", "current is " + path, (float)index / (float)objs.Length);
}
}
if (report.Count > 0)
{
FileUtil.Export(Application.dataPath + "/UIPrefabCheckReport.txt", report);
AssetDatabase.Refresh();
}
EditorUtility.ClearProgressBar();
}
private static string DeepCheck(Object obj)
{
var go = obj as GameObject;
if (go == null)
return null;
string path = AssetDatabase.GetAssetPath(obj);
List<string> usingAtlas = new List<string>();
List<string> imageNotInAtlas = new List<string>();
List<string> largeImage = new List<string>();
CheckImage(go, usingAtlas, imageNotInAtlas, largeImage);
List<string> missRef = new List<string>();
CheckObj(go, missRef);
return ToLog(path, usingAtlas, imageNotInAtlas, largeImage, missRef);
}
private static void CheckImage(GameObject go, List<string> usingAtlas, List<string> imageNotInAtlas, List<string> largeImage)
{
Image[] images = go.transform.GetComponentsInChildren<Image>(true);
for (int i = 0; i < images.Length; i++)
{
var img = images[i];
var imgPath = GetComponentPath(img);
var mat = img.material;
var sprite = img.sprite;
//排除特效所用的资源
if (sprite != null && mat.name == "Default UI Material")
{
var asset_path = AssetDatabase.GetAssetPath(sprite);
var atlasPath = GetAtalsPathByImage(asset_path);
if (atlasPath == null)
{
var guid = AssetDatabase.AssetPathToGUID(asset_path);
if (guid != "0000000000000000f000000000000000")
{
imageNotInAtlas.Add("path:" + imgPath + " res:" + asset_path);
}
}
else
{
if (!usingAtlas.Contains(atlasPath))
usingAtlas.Add(atlasPath);
}
if (sprite.rect.width >= 512 || sprite.rect.height >= 512)
{
largeImage.Add("path:" + imgPath + " res:" + asset_path);
}
}
}
}
private static void CheckObj(GameObject go, List<string> componentPaths)
{
if (go.transform.childCount <= 0)
{
return;
}
else
{
for (int i = 0; i < go.transform.childCount; i++)
{
var trans = go.transform.GetChild(i);
var paths = CheckTrans(trans);
componentPaths.AddRange(paths);
CheckObj(trans.gameObject, componentPaths);
}
}
}
private static List<string> CheckTrans(Transform trans)
{
List<string> componentPaths = new List<string>();
var components = trans.GetComponentsInChildren<Component>(true);
foreach (var component in components)
{
var path = CheckRef(trans, component);
if (path != null)
{
componentPaths.Add(path);
}
}
return componentPaths;
}
private static string CheckRef(Transform trans, Component component)
{
if (component != null)
{
SerializedObject so = new SerializedObject(component);
var iter = so.GetIterator();
while (iter.NextVisible(true))
{
if (iter.propertyType == SerializedPropertyType.ObjectReference)
{
if (iter.objectReferenceValue == null && iter.objectReferenceInstanceIDValue != 0)
{
return GetComponentPath(trans);
}
}
}
}
else
{
return GetComponentPath(trans);
}
return null;
}
private static string ToLog(string path, List<string> usingAtlas, List<string> imageNotInAtlas, List<string> largeImage, List<string> missRef)
{
string logFormat = "[" + path + "]" + "\r\n";
string usingAtlasFormat = GetLogByCheckType(CheckType.UsingAtlas, usingAtlas);
if (usingAtlasFormat != null)
logFormat += usingAtlasFormat;
string imageNotInAtlasFormat = GetLogByCheckType(CheckType.ImageNotInAtals, imageNotInAtlas);
if (imageNotInAtlasFormat != null)
logFormat += imageNotInAtlasFormat;
string largeImageFormat = GetLogByCheckType(CheckType.LargeImge, largeImage);
if (largeImageFormat != null)
logFormat += largeImageFormat;
string missRefFormat = GetLogByCheckType(CheckType.MissRef, missRef);
if (missRefFormat != null)
logFormat += missRefFormat;
return logFormat;
}
private static string GetLogByCheckType(CheckType type, List<string> checkResult)
{
if (checkResult.Count == 0)
return null;
var des = m_checkDesDict[type];
if (type == CheckType.UsingAtlas)
des += " " + checkResult.Count + "\r\n";
else
des += " " + "\r\n";
foreach (var item in checkResult)
{
des += " " + item + "\r\n";
}
return des;
}
private static string GetComponentPath(Component component)
{
string str = component.name + ":" + component.GetType().Name;
var trans = component.transform;
while (trans.parent != null)
{
var name = trans.parent.name;
str = name + "/" + str;
trans = trans.parent;
}
return str;
}
#region CollectAtlasInfo
private static Dictionary<string, string> m_spriteDicts = new Dictionary<string, string>();
public static void CollectAtlasSprite()
{
var atalsGuid = AssetDatabase.FindAssets("t:" + typeof(SpriteAtlas).Name);
foreach (var guid in atalsGuid)
{
var atlasPath = AssetDatabase.GUIDToAssetPath(guid);
SpriteAtlas atlas = AssetDatabase.LoadAssetAtPath<SpriteAtlas>(atlasPath) as SpriteAtlas;
if (atlas != null)
{
var assets = GetSpritesInAtlas(atlas);
foreach (var asset in assets)
{
if (!m_spriteDicts.ContainsKey(asset))
{
m_spriteDicts.Add(asset, atlasPath);
}
}
}
}
}
private static List<string> GetSpritesInAtlas(SpriteAtlas atlas)
{
List<string> spirtes_path = new List<string>();
UnityEngine.Object[] sprites = SpriteAtlasExtensions.GetPackables(atlas);
foreach (var sprite in sprites)
{
var path = AssetDatabase.GetAssetPath(sprite);
var sprite_guids = AssetDatabase.FindAssets("t:" + typeof(Sprite).Name, new string[] { path });
foreach (var guid in sprite_guids)
{
var certain_path = AssetDatabase.GUIDToAssetPath(guid);
if (!spirtes_path.Contains(certain_path))
{
spirtes_path.Add(certain_path);
}
}
}
return spirtes_path;
}
private static string GetAtalsPathByImage(string iamgePath)
{
string path = null;
if (m_spriteDicts.TryGetValue(iamgePath, out path))
{
return path;
}
return null;
}
#endregion
}