Update YooAsset
parent
2e902b701c
commit
fbef706388
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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>
|
||||
|
|
|
@ -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>
|
||||
|
|
Loading…
Reference in New Issue