unity5 关于反向查找物体被引用的方法

这篇博客介绍了如何在Unity5中使用UnityAssetUsageDetector库来反向查找游戏对象或资产被引用的方式。通过遍历对象的字段和属性,找到可能包含引用的变量,并绘制出引用路径,以帮助开发者定位和管理项目中的依赖关系。
摘要由CSDN通过智能技术生成

  
  
  
引用 by https://github.com/yasirkula/UnityAssetUsageDetector/
马克下
using UnityEngine;
using UnityEditor;
using UnityEngine.SceneManagement;
using UnityEditor.SceneManagement;
using System.Collections;
using System.Collections.Generic;
using System.Reflection;
using System;
using Object = UnityEngine.Object;

namespace AssetUsageDetectorNamespace
{
	public enum Phase { Setup, Processing, Complete };

	// Delegate to get the value of a variable (either field or property)
	public delegate object VariableGetVal( object obj );

	#region Helper Classes
	// Custom class to hold the results for a single scene or Assets folder
	public class ReferenceHolder
	{
		// Custom struct to hold a single path to a reference
		public struct ReferencePath
		{
			public readonly ReferenceNode startNode;
			public readonly int[] pathLinksToFollow;

			public ReferencePath( ReferenceNode startNode, int[] pathIndices )
			{
				this.startNode = startNode;
				pathLinksToFollow = pathIndices;
			}
		}

		private string title;
		private bool clickable;
		private List
    
    
     
      references;
		private List
     
     
      
       shortestPathsToReferences;

		public int NumberOfReferences { get { return references.Count; } }

		public ReferenceHolder( string title, bool clickable )
		{
			this.title = title;
			this.clickable = clickable;
			references = new List
      
      
       
       ();
			shortestPathsToReferences = null;
		}

		// Add a reference to the list
		public void AddReference( ReferenceNode node )
		{
			references.Add( node );
		}

		// Add all the Object's in this container to the set
		public void AddObjectsTo( HashSet
       
        objectsSet )
		{
			CalculateShortestPathsToReferences();

			for( int i = 0; i < shortestPathsToReferences.Count; i++ )
			{
				Object obj = shortestPathsToReferences[i].startNode.nodeObject as Object;
				if( obj != null )
					objectsSet.Add( obj );
			}
		}

		// Add all the GameObject's in this container to the set
		public void AddGameObjectsTo( HashSet
        
        
         
          gameObjectsSet )
		{
			CalculateShortestPathsToReferences();

			for( int i = 0; i < shortestPathsToReferences.Count; i++ )
			{
				Object obj = shortestPathsToReferences[i].startNode.nodeObject as Object;
				if( obj != null )
				{
					if( obj is GameObject )
						gameObjectsSet.Add( (GameObject) obj );
					else if( obj is Component )
						gameObjectsSet.Add( ( (Component) obj ).gameObject );
				}
			}
		}

		// Calculate shortest unique paths to the references
		public void CalculateShortestPathsToReferences()
		{
			if( shortestPathsToReferences != null )
				return;

			shortestPathsToReferences = new List
         
         
           ( 32 ); for( int i = 0; i < references.Count; i++ ) references[i].CalculateShortestPaths( shortestPathsToReferences ); } // Draw the results found for this container public void DrawOnGUI( bool drawFullPaths ) { Color c = GUI.color; GUI.color = Color.cyan; if( GUILayout.Button( title, AssetUsageDetector.BoxGUIStyle, AssetUsageDetector.GL_EXPAND_WIDTH, AssetUsageDetector.GL_HEIGHT_40 ) && clickable ) { // If the container (scene, usually) is clicked, highlight it on Project view EditorGUIUtility.PingObject( AssetDatabase.LoadAssetAtPath 
          
            ( title ) ); Selection.activeObject = AssetDatabase.LoadAssetAtPath 
           
             ( title ); } GUI.color = Color.yellow; if( drawFullPaths ) { for( int i = 0; i < references.Count; i++ ) { if( references[i].nodeObject == null ) continue; GUILayout.Space( 5 ); references[i].DrawOnGUIRecursively(); } } else { if( shortestPathsToReferences == null ) CalculateShortestPathsToReferences(); for( int i = 0; i < shortestPathsToReferences.Count; i++ ) { ReferencePath path = shortestPathsToReferences[i]; if( path.startNode.nodeObject == null ) continue; GUILayout.Space( 5 ); GUILayout.BeginHorizontal(); path.startNode.DrawOnGUI( null ); ReferenceNode currentNode = path.startNode; for( int j = 0; j < path.pathLinksToFollow.Length; j++ ) { ReferenceNode.Link link = currentNode[path.pathLinksToFollow[j]]; link.targetNode.DrawOnGUI( link.description ); currentNode = link.targetNode; } GUILayout.EndHorizontal(); } } GUI.color = c; GUILayout.Space( 10 ); } } // Custom class to hold an object in the path to a reference as a node public class ReferenceNode { public struct Link { public readonly ReferenceNode targetNode; public readonly string description; public Link( ReferenceNode targetNode, string description ) { this.targetNode = targetNode; this.description = description; } } public object nodeObject; private readonly List 
            
      links; public int NumberOfOutgoingLinks { get { return links.Count; } } public Link this[int index] { get { return links[index]; } } public ReferenceNode() { links = new List 
            
     ( 2 ); } public ReferenceNode( object obj ) : this() { nodeObject = obj; } // Add a one-way connection to another node public void AddLinkTo( ReferenceNode nextNode, string description = null ) { if( nextNode != null ) { if( !string.IsNullOrEmpty( description ) ) description = "[" + description + "]"; links.Add( new Link( nextNode, description ) ); } } // Clear this node so that it can be reused later public void Clear() { nodeObject = null; links.Clear(); } // Calculate shortest unique paths that start with this node public void CalculateShortestPaths( List 
            
              currentPaths ) { CalculateShortestPaths( currentPaths, new List 
             
               ( 8 ), new List 
              
                ( 8 ) { -1 }, 0 ); } // Just some boring calculations to find the shortest unique paths recursively private void CalculateShortestPaths( List 
               
                 shortestPaths, List 
                
                  currentPath, List 
                 
                   currentPathIndices, int latestObjectIndexInPath ) { if( nodeObject == null ) return; int currentIndex = currentPath.Count; currentPath.Add( this ); if( links.Count == 0 ) { // Check if the path to the reference is unique (not discovered so far) bool isUnique = true; for( int i = 0; i < shortestPaths.Count; i++ ) { if( shortestPaths[i].startNode == currentPath[latestObjectIndexInPath] && shortestPaths[i].pathLinksToFollow.Length == currentPathIndices.Count - latestObjectIndexInPath - 1 ) { int j = latestObjectIndexInPath + 1; for( int k = 0; j < currentPathIndices.Count; j++, k++ ) { if( shortestPaths[i].pathLinksToFollow[k] != currentPathIndices[j] ) break; } if( j == currentPathIndices.Count ) { isUnique = false; break; } } } // Don't allow duplicate shortest paths if( isUnique ) { int[] pathIndices = new int[currentPathIndices.Count - latestObjectIndexInPath - 1]; for( int i = latestObjectIndexInPath + 1, j = 0; i < currentPathIndices.Count; i++, j++ ) pathIndices[j] = currentPathIndices[i]; shortestPaths.Add( new ReferenceHolder.ReferencePath( currentPath[latestObjectIndexInPath], pathIndices ) ); } } else { if( nodeObject is Object ) latestObjectIndexInPath = currentIndex; for( int i = 0; i < links.Count; i++ ) { currentPathIndices.Add( i ); links[i].targetNode.CalculateShortestPaths( shortestPaths, currentPath, currentPathIndices, latestObjectIndexInPath ); currentPathIndices.RemoveAt( currentIndex + 1 ); } } currentPath.RemoveAt( currentIndex ); } // Draw all the paths that start with this node on GUI recursively public void DrawOnGUIRecursively( string linkToPrevNodeDescription = null ) { GUILayout.BeginHorizontal(); DrawOnGUI( linkToPrevNodeDescription ); if( links.Count > 0 ) { GUILayout.BeginVertical(); for( int i = 0; i < links.Count; i++ ) { ReferenceNode next = links[i].targetNode; if( next.nodeObject != null ) next.DrawOnGUIRecursively( links[i].description ); } GUILayout.EndVertical(); } GUILayout.EndHorizontal(); } // Draw only this node on GUI public void DrawOnGUI( string linkToPrevNodeDescription ) { string label = GetNodeContent( linkToPrevNodeDescription ); if( GUILayout.Button( label, AssetUsageDetector.BoxGUIStyle, AssetUsageDetector.GL_EXPAND_HEIGHT ) ) { // If a reference is clicked, highlight it (either on Hierarchy view or Project view) Object unityObject = nodeObject as Object; if( unityObject != null ) { EditorGUIUtility.PingObject( unityObject ); Selection.activeObject = unityObject; } } if( AssetUsageDetector.showTooltips && Event.current.type == EventType.Repaint && GUILayoutUtility.GetLastRect().Contains( Event.current.mousePosition ) ) AssetUsageDetector.tooltip = label; } // Get the string representation of this node private string GetNodeContent( string linkToPrevNodeDescription = null ) { string result = string.Empty; if( !string.IsNullOrEmpty( linkToPrevNodeDescription ) ) result = linkToPrevNodeDescription + "\n"; Object unityObject = nodeObject as Object; if( unityObject != null ) result += unityObject.name + " (" + unityObject.GetType() + ")"; else result += nodeObject.GetType() + " object"; return result; } } // Custom struct to hold a variable, its important properties and its getter function public struct VariableGetterHolder { public readonly string name; public readonly bool isProperty; public readonly bool isSerializable; private readonly VariableGetVal getter; public VariableGetterHolder( FieldInfo fieldInfo, VariableGetVal getter, bool isSerializable ) { name = fieldInfo.Name; isProperty = false; this.isSerializable = isSerializable; this.getter = getter; } public VariableGetterHolder( PropertyInfo propertyInfo, VariableGetVal getter, bool isSerializable ) { name = propertyInfo.Name; isProperty = true; this.isSerializable = isSerializable; this.getter = getter; } public object Get( object obj ) { return getter( obj ); } } // Credit: http://stackoverflow.com/questions/724143/how-do-i-create-a-delegate-for-a-net-property public interface IPropertyAccessor { object GetValue( object source ); } // A wrapper class for properties to get their values more efficiently public class PropertyWrapper 
                  
                    : IPropertyAccessor where TObject : class { private readonly Func 
                   
                     getter; public PropertyWrapper( MethodInfo getterMethod ) { getter = (Func 
                    
                      ) Delegate.CreateDelegate( typeof( Func 
                     
                       ), getterMethod ); } public object GetValue( object obj ) { try { return getter( (TObject) obj ); } catch { // Property getters may return various kinds of exceptions // if their backing fields are not initialized (yet) return null; } } } #endregion #region Extension Functions public static class AssetUsageDetectorExtensions { // Get a unique-ish string hash code for an object public static string Hash( this object obj ) { if( obj is Object ) return obj.GetHashCode() + obj.GetType().Name + ( (Object) obj ).name; return obj.GetHashCode() + obj.GetType().Name; } // Check if object depends on any of the references public static bool HasAnyReferenceTo( this Object obj, HashSet 
                       references ) { Object[] dependencies = EditorUtility.CollectDependencies( new Object[] { obj } ); for( int i = 0; i < dependencies.Length; i++ ) { if( references.Contains( dependencies[i] ) ) return true; } return false; } // Check if the field is serializable public static bool IsSerializable( this FieldInfo fieldInfo ) { // see Serialization Rules: https://docs.unity3d.com/Manual/script-Serialization.html Type fieldType = fieldInfo.FieldType; if( fieldType.IsDerivedFrom( typeof( Object ) ) ) return true; if( fieldType.IsArray ) { if( fieldType.GetArrayRank() != 1 ) return false; fieldType = fieldType.GetElementType(); } else if( fieldType.IsGenericType ) { if( fieldType.GetGenericTypeDefinition() != typeof( List<> ) ) return false; fieldType = fieldType.GetGenericArguments()[0]; } if( fieldType.IsGenericType || fieldInfo.IsInitOnly || ( ( !fieldInfo.IsPublic || fieldInfo.IsNotSerialized ) && !Attribute.IsDefined( fieldInfo, typeof( SerializeField ) ) ) ) return false; if( Attribute.IsDefined( fieldType, typeof( SerializableAttribute ), false ) ) return true; return false; } // Check if the type is a common Unity type (let's call them primitives) public static bool IsPrimitiveUnityType( this Type type ) { return type.IsPrimitive || type == typeof( string ) || type == typeof( Vector3 ) || type =
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值