Update YooAsset

pull/4/head
hevinci 2022-03-10 16:54:56 +08:00
parent 2e902b701c
commit fbef706388
5 changed files with 119 additions and 329 deletions

View File

@ -53,7 +53,7 @@ namespace YooAsset.Editor
foreach (string assetPath in findAssets)
{
AnimatorController animator= AssetDatabase.LoadAssetAtPath<AnimatorController>(assetPath);
if (EditorTools.FindRedundantAnimationState(animator))
if (FindRedundantAnimationState(animator))
{
findCount++;
Debug.LogWarning($"发现冗余的动画控制器:{assetPath}");
@ -83,7 +83,7 @@ namespace YooAsset.Editor
foreach (string assetPath in findAssets)
{
Material mat = AssetDatabase.LoadAssetAtPath<Material>(assetPath);
if (EditorTools.ClearMaterialUnusedProperty(mat))
if (ClearMaterialUnusedProperty(mat))
{
removedCount++;
Debug.LogWarning($"材质球已被处理:{assetPath}");
@ -97,5 +97,119 @@ namespace YooAsset.Editor
else
AssetDatabase.SaveAssets();
}
/// <summary>
/// 清理无用的材质球属性
/// </summary>
private static bool ClearMaterialUnusedProperty(Material mat)
{
bool removeUnused = false;
SerializedObject so = new SerializedObject(mat);
SerializedProperty sp = so.FindProperty("m_SavedProperties");
sp.Next(true);
do
{
if (sp.isArray == false)
continue;
for (int i = sp.arraySize - 1; i >= 0; --i)
{
var p1 = sp.GetArrayElementAtIndex(i);
if (p1.isArray)
{
for (int ii = p1.arraySize - 1; ii >= 0; --ii)
{
var p2 = p1.GetArrayElementAtIndex(ii);
var val = p2.FindPropertyRelative("first");
if (mat.HasProperty(val.stringValue) == false)
{
Debug.Log($"Material {mat.name} remove unused property : {val.stringValue}");
p1.DeleteArrayElementAtIndex(ii);
removeUnused = true;
}
}
}
else
{
var val = p1.FindPropertyRelative("first");
if (mat.HasProperty(val.stringValue) == false)
{
Debug.Log($"Material {mat.name} remove unused property : {val.stringValue}");
sp.DeleteArrayElementAtIndex(i);
removeUnused = true;
}
}
}
}
while (sp.Next(false));
so.ApplyModifiedProperties();
return removeUnused;
}
/// <summary>
/// 查找动画控制器里冗余的动画状态机
/// </summary>
private static bool FindRedundantAnimationState(AnimatorController animatorController)
{
if (animatorController == null)
return false;
string assetPath = AssetDatabase.GetAssetPath(animatorController);
// 查找使用的状态机名称
List<string> usedStateNames = new List<string>();
foreach (var layer in animatorController.layers)
{
foreach (var state in layer.stateMachine.states)
{
usedStateNames.Add(state.state.name);
}
}
List<string> allLines = new List<string>();
List<int> stateIndexList = new List<int>();
using (StreamReader reader = File.OpenText(assetPath))
{
string content;
while (null != (content = reader.ReadLine()))
{
allLines.Add(content);
if (content.StartsWith("AnimatorState:"))
{
stateIndexList.Add(allLines.Count - 1);
}
}
}
List<string> allStateNames = new List<string>();
foreach (var index in stateIndexList)
{
for (int i = index; i < allLines.Count; i++)
{
string content = allLines[i];
content = content.Trim();
if (content.StartsWith("m_Name"))
{
string[] splits = content.Split(':');
string name = splits[1].TrimStart(' '); //移除前面的空格
allStateNames.Add(name);
break;
}
}
}
bool foundRedundantState = false;
foreach (var stateName in allStateNames)
{
if (usedStateNames.Contains(stateName) == false)
{
Debug.LogWarning($"发现冗余的动画文件:{assetPath}={stateName}");
foundRedundantState = true;
}
}
return foundRedundantState;
}
}
}

View File

@ -16,52 +16,6 @@ namespace YooAsset.Editor
/// </summary>
public static class EditorTools
{
#region NGUI
/// <summary>
/// Draw a distinctly different looking header label
/// </summary>
public static bool DrawHeader(string text)
{
return DrawHeader(text, text, false, true);
}
public static bool DrawHeader(string text, string key, bool forceOn, bool minimalistic)
{
bool state = EditorPrefs.GetBool(key, true);
if (!minimalistic) GUILayout.Space(3f);
if (!forceOn && !state) GUI.backgroundColor = new Color(0.8f, 0.8f, 0.8f);
GUILayout.BeginHorizontal();
GUI.changed = false;
if (minimalistic)
{
if (state) text = "\u25BC" + (char)0x200a + text;
else text = "\u25BA" + (char)0x200a + text;
GUILayout.BeginHorizontal();
GUI.contentColor = EditorGUIUtility.isProSkin ? new Color(1f, 1f, 1f, 0.7f) : new Color(0f, 0f, 0f, 0.7f);
if (!GUILayout.Toggle(true, text, "PreToolbar2", GUILayout.MinWidth(20f))) state = !state;
GUI.contentColor = Color.white;
GUILayout.EndHorizontal();
}
else
{
text = "<b><size=11>" + text + "</size></b>";
if (state) text = "\u25BC " + text;
else text = "\u25BA " + text;
if (!GUILayout.Toggle(true, text, "dragtab", GUILayout.MinWidth(20f))) state = !state;
}
if (GUI.changed) EditorPrefs.SetBool(key, state);
if (!minimalistic) GUILayout.Space(2f);
GUILayout.EndHorizontal();
GUI.backgroundColor = Color.white;
if (!forceOn && !state) GUILayout.Space(3f);
return state;
}
#endregion
#region Assembly
/// <summary>
/// 调用私有的静态方法
@ -205,7 +159,7 @@ namespace YooAsset.Editor
}
#endregion
#region 编辑器窗口
#region EditorWindow
public static void FocusUnitySceneWindow()
{
EditorWindow.FocusWindowIfItsOpen<SceneView>();
@ -237,261 +191,6 @@ namespace YooAsset.Editor
}
#endregion
#region 引用关系
/// <summary>
/// 获取场景里的克隆预制体
/// </summary>
public static GameObject GetClonePrefabInScene(GameObject sourcePrefab)
{
GameObject[] findObjects = GameObject.FindObjectsOfType<GameObject>();
if (findObjects.Length == 0)
return null;
for (int i = 0; i < findObjects.Length; i++)
{
GameObject findObject = findObjects[i];
#if UNITY_2017_4
// 判断对象是否为一个预制体的引用
if (PrefabUtility.GetPrefabType(findObject) == PrefabType.PrefabInstance)
{
// 判断是否为同一个预制体
Object source = PrefabUtility.GetPrefabParent(findObject);
if (source.GetInstanceID() == sourcePrefab.GetInstanceID())
return findObject;
}
#else
// 判断对象是否为一个预制体的引用
if (PrefabUtility.GetPrefabInstanceStatus(findObject) == PrefabInstanceStatus.Connected)
{
// 判断是否为同一个预制体
Object source = PrefabUtility.GetCorrespondingObjectFromSource(findObject);
if (source.GetInstanceID() == sourcePrefab.GetInstanceID())
return findObject;
}
#endif
}
return null; //没有找到合适的对象
}
/// <summary>
/// 查找场景里的引用对象
/// </summary>
public static void FindReferencesInScene(UnityEngine.Object to)
{
var referencedBy = new List<Object>();
GameObject[] findObjects = GameObject.FindObjectsOfType<GameObject>(); //注意只能获取激活的GameObject
for (int j = 0; j < findObjects.Length; j++)
{
GameObject findObject = findObjects[j];
#if UNITY_2017_4
// 如果Prefab匹配
if (PrefabUtility.GetPrefabType(findObject) == PrefabType.PrefabInstance)
{
if (PrefabUtility.GetPrefabParent(findObject) == to)
referencedBy.Add(findObject);
}
#else
// 如果Prefab匹配
if (PrefabUtility.GetPrefabInstanceStatus(findObject) == PrefabInstanceStatus.Connected)
{
if (PrefabUtility.GetCorrespondingObjectFromSource(findObject) == to)
referencedBy.Add(findObject);
}
#endif
// 如果组件匹配
Component[] components = findObject.GetComponents<Component>();
for (int i = 0; i < components.Length; i++)
{
Component c = components[i];
if (!c) continue;
SerializedObject so = new SerializedObject(c);
SerializedProperty sp = so.GetIterator();
while (sp.NextVisible(true))
{
if (sp.propertyType == SerializedPropertyType.ObjectReference)
{
if (sp.objectReferenceValue != null && sp.objectReferenceValue == to)
referencedBy.Add(c.gameObject);
}
}
}
}
if (referencedBy.Any())
Selection.objects = referencedBy.ToArray();
}
/// <summary>
/// 查找场景里的引用对象
/// </summary>
public static void FindReferencesInPrefabs(UnityEngine.Object to, GameObject[] sourcePrefabs)
{
var referencedBy = new List<Object>();
for (int j = 0; j < sourcePrefabs.Length; j++)
{
GameObject clonePrefab = GetClonePrefabInScene(sourcePrefabs[j]);
if (clonePrefab == null)
continue;
#if UNITY_2017_4
// 如果Prefab匹配
if (PrefabUtility.GetPrefabParent(clonePrefab) == to)
referencedBy.Add(clonePrefab);
#else
// 如果Prefab匹配
if (PrefabUtility.GetCorrespondingObjectFromSource(clonePrefab) == to)
referencedBy.Add(clonePrefab);
#endif
// 如果组件匹配
Component[] components = clonePrefab.GetComponentsInChildren<Component>(true); //GetComponents<Component>();
for (int i = 0; i < components.Length; i++)
{
Component c = components[i];
if (!c) continue;
SerializedObject so = new SerializedObject(c);
SerializedProperty sp = so.GetIterator();
while (sp.NextVisible(true))
{
if (sp.propertyType == SerializedPropertyType.ObjectReference)
{
if (sp.objectReferenceValue != null && sp.objectReferenceValue == to)
referencedBy.Add(c.gameObject);
}
}
}
}
if (referencedBy.Any())
Selection.objects = referencedBy.ToArray();
}
#endregion
#region 材质球
/// <summary>
/// 清理无用的材质球属性
/// </summary>
public static bool ClearMaterialUnusedProperty(Material mat)
{
bool removeUnused = false;
SerializedObject so = new SerializedObject(mat);
SerializedProperty sp = so.FindProperty("m_SavedProperties");
sp.Next(true);
do
{
if (sp.isArray == false)
continue;
for (int i = sp.arraySize - 1; i >= 0; --i)
{
var p1 = sp.GetArrayElementAtIndex(i);
if (p1.isArray)
{
for (int ii = p1.arraySize - 1; ii >= 0; --ii)
{
var p2 = p1.GetArrayElementAtIndex(ii);
var val = p2.FindPropertyRelative("first");
if (mat.HasProperty(val.stringValue) == false)
{
Debug.Log($"Material {mat.name} remove unused property : {val.stringValue}");
p1.DeleteArrayElementAtIndex(ii);
removeUnused = true;
}
}
}
else
{
var val = p1.FindPropertyRelative("first");
if (mat.HasProperty(val.stringValue) == false)
{
Debug.Log($"Material {mat.name} remove unused property : {val.stringValue}");
sp.DeleteArrayElementAtIndex(i);
removeUnused = true;
}
}
}
}
while (sp.Next(false));
so.ApplyModifiedProperties();
return removeUnused;
}
#endregion
#region 动画控制器
/// <summary>
/// 查找动画控制器里冗余的动画状态机
/// </summary>
public static bool FindRedundantAnimationState(AnimatorController animatorController)
{
if (animatorController == null)
return false;
string assetPath = AssetDatabase.GetAssetPath(animatorController);
// 查找使用的状态机名称
List<string> usedStateNames = new List<string>();
foreach (var layer in animatorController.layers)
{
foreach (var state in layer.stateMachine.states)
{
usedStateNames.Add(state.state.name);
}
}
List<string> allLines = new List<string>();
List<int> stateIndexList = new List<int>();
using (StreamReader reader = File.OpenText(assetPath))
{
string content;
while (null != (content = reader.ReadLine()))
{
allLines.Add(content);
if (content.StartsWith("AnimatorState:"))
{
stateIndexList.Add(allLines.Count - 1);
}
}
}
List<string> allStateNames = new List<string>();
foreach (var index in stateIndexList)
{
for (int i = index; i < allLines.Count; i++)
{
string content = allLines[i];
content = content.Trim();
if (content.StartsWith("m_Name"))
{
string[] splits = content.Split(':');
string name = splits[1].TrimStart(' '); //移除前面的空格
allStateNames.Add(name);
break;
}
}
}
bool foundRedundantState = false;
foreach (var stateName in allStateNames)
{
if (usedStateNames.Contains(stateName) == false)
{
Debug.LogWarning($"发现冗余的动画文件:{assetPath}={stateName}");
foundRedundantState = true;
}
}
return foundRedundantState;
}
#endregion
#region 控制台
private static MethodInfo _clearConsoleMethod;
private static MethodInfo ClearConsoleMethod
@ -518,28 +217,6 @@ namespace YooAsset.Editor
#endregion
#region 文件
/// <summary>
/// 测试写入权限
/// </summary>
public static bool HasWriteAccess(string directoryPath)
{
try
{
string tmpFilePath = Path.Combine(directoryPath, Path.GetRandomFileName());
using (FileStream fs = new FileStream(tmpFilePath, FileMode.CreateNew, FileAccess.ReadWrite, FileShare.ReadWrite))
{
StreamWriter writer = new StreamWriter(fs);
writer.Write(0);
}
File.Delete(tmpFilePath);
return true;
}
catch
{
return false;
}
}
/// <summary>
/// 创建文件所在的目录
/// </summary>

View File

@ -194,8 +194,8 @@ namespace YooAsset
/// 向网络端请求并更新补丁清单
/// </summary>
/// <param name="updateResourceVersion">更新的资源版本号</param>
/// <param name="timeout">超时时间</param>
public static UpdateManifestOperation UpdateManifestAsync(int updateResourceVersion, int timeout)
/// <param name="timeout">超时时间默认值60秒</param>
public static UpdateManifestOperation UpdateManifestAsync(int updateResourceVersion, int timeout = 60)
{
if (_playMode == EPlayMode.EditorPlayMode)
{
@ -221,7 +221,6 @@ namespace YooAsset
}
}
/// <summary>
/// 获取资源版本号
/// </summary>