private ReferenceNode SearchAnimatorStateMachine( Object unityObject ) { AnimatorStateMachine animatorStateMachine = (AnimatorStateMachine) unityObject; ReferenceNode referenceNode = PopReferenceNode( animatorStateMachine ); ChildAnimatorStateMachine[] stateMachines = animatorStateMachine.stateMachines; for( int i = 0; i < stateMachines.Length; i++ ) referenceNode.AddLinkTo( SearchObject( stateMachines[i].stateMachine ), "Child State Machine" ); ChildAnimatorState[] states = animatorStateMachine.states; for( int i = 0; i < states.Length; i++ ) referenceNode.AddLinkTo( SearchObject( states[i].state ) ); if( searchMonoBehavioursForScript ) { StateMachineBehaviour[] behaviours = animatorStateMachine.behaviours; for( int i = 0; i < behaviours.Length; i++ ) { MonoScript script = MonoScript.FromScriptableObject( behaviours[i] ); if( objectsToSearchSet.Contains( script ) ) referenceNode.AddLinkTo( GetReferenceNode( script ) ); } } return referenceNode; }
private ReferenceNode SearchMaterial( Object unityObject ) { Material material = (Material) unityObject; ReferenceNode referenceNode = PopReferenceNode( material ); if( searchMaterialsForShader && objectsToSearchSet.Contains( material.shader ) ) referenceNode.AddLinkTo( GetReferenceNode( material.shader ), "Shader" ); if( searchMaterialsForTexture ) { // Search through all the textures attached to this material // Credit: http://answers.unity3d.com/answers/1116025/view.html Shader shader = material.shader; int shaderPropertyCount = ShaderUtil.GetPropertyCount( shader ); for( int i = 0; i < shaderPropertyCount; i++ ) { if( ShaderUtil.GetPropertyType( shader, i ) == ShaderUtil.ShaderPropertyType.TexEnv ) { string propertyName = ShaderUtil.GetPropertyName( shader, i ); Texture assignedTexture = material.GetTexture( propertyName ); if( objectsToSearchSet.Contains( assignedTexture ) ) referenceNode.AddLinkTo( GetReferenceNode( assignedTexture ), "Shader property: " + propertyName ); } } } return referenceNode; }
private ReferenceNode SearchAnimatorController( Object unityObject ) { RuntimeAnimatorController controller = (RuntimeAnimatorController) unityObject; ReferenceNode referenceNode = PopReferenceNode( controller ); if( controller is AnimatorController ) { AnimatorControllerLayer[] layers = ( (AnimatorController) controller ).layers; for( int i = 0; i < layers.Length; i++ ) { if( objectsToSearchSet.Contains( layers[i].avatarMask ) ) referenceNode.AddLinkTo( GetReferenceNode( layers[i].avatarMask ), layers[i].name + " Mask" ); referenceNode.AddLinkTo( SearchObject( layers[i].stateMachine ) ); } } else { AnimationClip[] animClips = controller.animationClips; for( int i = 0; i < animClips.Length; i++ ) referenceNode.AddLinkTo( SearchObject( animClips[i] ) ); } return referenceNode; }
private ReferenceNode SearchGameObject( Object unityObject ) { GameObject go = (GameObject) unityObject; ReferenceNode referenceNode = PopReferenceNode( go ); // Check if this GameObject's prefab is one of the selected assets if( searchPrefabConnections ) { #if UNITY_2018_3_OR_NEWER Object prefab = PrefabUtility.GetCorrespondingObjectFromSource( go ); if( objectsToSearchSet.Contains( prefab ) && go == PrefabUtility.GetNearestPrefabInstanceRoot( go ) ) #else Object prefab = PrefabUtility.GetPrefabParent( go ); if( objectsToSearchSet.Contains( prefab ) && go == PrefabUtility.FindRootGameObjectWithSameParentPrefab( go ) ) #endif referenceNode.AddLinkTo( GetReferenceNode( prefab ), "Prefab object" ); } // Search through all the components of the object Component[] components = go.GetComponents<Component>(); for( int i = 0; i < components.Length; i++ ) referenceNode.AddLinkTo( SearchObject( components[i] ) ); return referenceNode; }
// Search through field and properties of an object for references private void SearchFieldsAndPropertiesOf( ReferenceNode referenceNode ) { // Get filtered variables for this object VariableGetterHolder[] variables = GetFilteredVariablesForType( referenceNode.nodeObject.GetType() ); for( int i = 0; i < variables.Length; i++ ) { // When possible, don't search non-serializable variables if( searchSerializableVariablesOnly && !variables[i].isSerializable ) continue; try { object variableValue = variables[i].Get( referenceNode.nodeObject ); if( variableValue == null ) continue; if( !( variableValue is IEnumerable ) || variableValue is Transform ) referenceNode.AddLinkTo( SearchObject( variableValue ), ( variables[i].isProperty ? "Property: " : "Variable: " ) + variables[i].name ); else { // If the field is IEnumerable (possibly an array or collection), search through members of it // Note that Transform IEnumerable (children of the transform) is not iterated foreach( object arrayItem in (IEnumerable) variableValue ) referenceNode.AddLinkTo( SearchObject( arrayItem ), ( variables[i].isProperty ? "Property (IEnumerable): " : "Variable (IEnumerable): " ) + variables[i].name ); } } catch( UnassignedReferenceException ) { } catch( MissingReferenceException ) { } } }
private ReferenceNode SearchSpriteAtlas( Object unityObject ) { SpriteAtlas spriteAtlas = (SpriteAtlas) unityObject; ReferenceNode referenceNode = PopReferenceNode( spriteAtlas ); SerializedObject spriteAtlasSO = new SerializedObject( spriteAtlas ); if( spriteAtlas.isVariant ) { Object masterAtlas = spriteAtlasSO.FindProperty( "m_MasterAtlas" ).objectReferenceValue; if( objectsToSearchSet.Contains( masterAtlas ) ) referenceNode.AddLinkTo( SearchObject( masterAtlas ), "Master Atlas" ); } #if UNITY_2018_2_OR_NEWER Object[] packables = spriteAtlas.GetPackables(); if( packables != null ) { for( int i = 0; i < packables.Length; i++ ) referenceNode.AddLinkTo( SearchObject( packables[i] ), "Packed Texture" ); } #else SerializedProperty packables = spriteAtlasSO.FindProperty( "m_EditorData.packables" ); if( packables != null ) { for( int i = 0, length = packables.arraySize; i < length; i++ ) referenceNode.AddLinkTo( SearchObject( packables.GetArrayElementAtIndex( i ).objectReferenceValue ), "Packed Texture" ); } #endif return referenceNode; }
private ReferenceNode SearchBlendTree( Object unityObject ) { BlendTree blendTree = (BlendTree) unityObject; ReferenceNode referenceNode = PopReferenceNode( blendTree ); ChildMotion[] children = blendTree.children; for( int i = 0; i < children.Length; i++ ) referenceNode.AddLinkTo( SearchObject( children[i].motion ), "Motion" ); return referenceNode; }
private ReferenceNode SearchAnimationClip( Object unityObject ) { AnimationClip clip = (AnimationClip) unityObject; ReferenceNode referenceNode = PopReferenceNode( clip ); // Get all curves from animation clip EditorCurveBinding[] objectCurves = AnimationUtility.GetObjectReferenceCurveBindings( clip ); for( int i = 0; i < objectCurves.Length; i++ ) { // Search through all the keyframes in this curve ObjectReferenceKeyframe[] keyframes = AnimationUtility.GetObjectReferenceCurve( clip, objectCurves[i] ); for( int j = 0; j < keyframes.Length; j++ ) referenceNode.AddLinkTo( SearchObject( keyframes[j].value ), "Keyframe: " + keyframes[j].time ); } // Get all events from animation clip AnimationEvent[] events = AnimationUtility.GetAnimationEvents( clip ); for( int i = 0; i < events.Length; i++ ) referenceNode.AddLinkTo( SearchObject( events[i].objectReferenceParameter ), "AnimationEvent: " + events[i].time ); return referenceNode; }
private ReferenceNode SearchComponent( Object unityObject ) { Component component = (Component) unityObject; // Ignore Transform component (no object field to search for) if( component is Transform ) return null; ReferenceNode referenceNode = PopReferenceNode( component ); if( searchMonoBehavioursForScript && component is MonoBehaviour ) { // If a searched asset is script, check if this component is an instance of it MonoScript script = MonoScript.FromMonoBehaviour( (MonoBehaviour) component ); if( objectsToSearchSet.Contains( script ) ) referenceNode.AddLinkTo( GetReferenceNode( script ) ); } else if( searchRenderers && component is Renderer ) { // If an asset is a shader, texture or material, and this component is a Renderer, // search it for references Material[] materials = ( (Renderer) component ).sharedMaterials; for( int i = 0; i < materials.Length; i++ ) referenceNode.AddLinkTo( SearchObject( materials[i] ) ); } else if( component is Animation ) { // If this component is an Animation, search its animation clips for references foreach( AnimationState anim in (Animation) component ) referenceNode.AddLinkTo( SearchObject( anim.clip ) ); } else if( component is Animator ) { // If this component is an Animator, search its animation clips for references referenceNode.AddLinkTo( SearchObject( ( (Animator) component ).runtimeAnimatorController ) ); } #if UNITY_2017_2_OR_NEWER else if( component is Tilemap ) { // If this component is a Tilemap, search its tiles for references TileBase[] tiles = new TileBase[( (Tilemap) component ).GetUsedTilesCount()]; ( (Tilemap) component ).GetUsedTilesNonAlloc( tiles ); if( tiles != null ) { for( int i = 0; i < tiles.Length; i++ ) referenceNode.AddLinkTo( SearchObject( tiles[i] ), "Tile" ); } } #endif #if UNITY_2017_1_OR_NEWER else if( component is PlayableDirector ) { // If this component is a PlayableDirectory, search its PlayableAsset's scene bindings for references PlayableAsset playableAsset = ( (PlayableDirector) component ).playableAsset; if( playableAsset != null && !playableAsset.Equals( null ) ) { foreach( PlayableBinding binding in playableAsset.outputs ) referenceNode.AddLinkTo( SearchObject( ( (PlayableDirector) component ).GetGenericBinding( binding.sourceObject ) ), "Binding: " + binding.streamName ); } } #endif SearchFieldsAndPropertiesOf( referenceNode ); return referenceNode; }
// Initializes commonly used variables of the nodes public void InitializeNodes(Func <object, ReferenceNode> nodeGetter) { // Remove root nodes that don't have any outgoing links or have null node objects (somehow) for (int i = references.Count - 1; i >= 0; i--) { if (references[i].NumberOfOutgoingLinks == 0) { references.RemoveAtFast(i); } else { object nodeObject = references[i].nodeObject; if (nodeObject == null || nodeObject.Equals(null)) { references.RemoveAtFast(i); } } } // For simplicity's sake, get rid of root nodes that are already part of another node's hierarchy for (int i = references.Count - 1; i >= 0; i--) { if (IsRootNodePartOfAnotherRootNode(i)) { references.RemoveAtFast(i); } } // For clarity, a reference path shouldn't start with a sub-asset but instead with its corresponding main asset for (int i = references.Count - 1; i >= 0; i--) { object nodeObject = references[i].nodeObject; if (nodeObject.IsAsset() && !AssetDatabase.IsMainAsset((Object)nodeObject)) { string assetPath = AssetDatabase.GetAssetPath((Object)nodeObject); if (string.IsNullOrEmpty(assetPath)) { continue; } Object mainAsset = AssetDatabase.LoadMainAssetAtPath(assetPath); if (mainAsset == null || mainAsset.Equals(null)) { continue; } if (nodeObject is Component && ((Component)nodeObject).gameObject == mainAsset) { continue; } // Get a ReferenceNode for the main asset, add a link to the sub-asset's node and change the root node ReferenceNode newRootNode = nodeGetter(mainAsset); newRootNode.AddLinkTo(references[i], (nodeObject is Component || nodeObject is GameObject) ? "Child object" : "Sub-asset"); references[i] = newRootNode; // Make sure that the new root node isn't already a part of another node's hierarchy if (IsRootNodePartOfAnotherRootNode(i)) { references.RemoveAtFast(i); } } } for (int i = references.Count - 1; i >= 0; i--) { references[i].InitializeRecursively(); } }