// Search a scene for references
		private void SearchScene( string scenePath, List<SearchResultGroup> searchResult, SceneSetup[] initialSceneSetup )
		{
			Scene scene = EditorSceneManager.GetSceneByPath( scenePath );
			if( EditorApplication.isPlaying && !scene.isLoaded )
				return;

			bool canContainSceneObjectReference = scene.isLoaded && ( !EditorSceneManager.preventCrossSceneReferences || sceneObjectsToSearchScenesSet.Contains( scenePath ) );
			if( !canContainSceneObjectReference )
			{
				bool canContainAssetReference = assetsToSearchSet.Count > 0 && ( EditorApplication.isPlaying || AssetHasAnyReference( scenePath ) );
				if( !canContainAssetReference )
					return;
			}

			if( !EditorApplication.isPlaying )
				scene = EditorSceneManager.OpenScene( scenePath, OpenSceneMode.Additive );

			currentSearchResultGroup = new SearchResultGroup( scenePath, true );

			// Search through all the GameObjects in the scene
			GameObject[] rootGameObjects = scene.GetRootGameObjects();
			for( int i = 0; i < rootGameObjects.Length; i++ )
				SearchGameObjectRecursively( rootGameObjects[i] );

			// If no references are found in the scene and if the scene is not part of the initial scene setup, close it
			if( currentSearchResultGroup.NumberOfReferences == 0 )
			{
				if( !EditorApplication.isPlaying )
				{
					bool sceneIsOneOfInitials = false;
					for( int i = 0; i < initialSceneSetup.Length; i++ )
					{
						if( initialSceneSetup[i].path == scenePath )
						{
							if( !initialSceneSetup[i].isLoaded )
								EditorSceneManager.CloseScene( scene, false );

							sceneIsOneOfInitials = true;
							break;
						}
					}

					if( !sceneIsOneOfInitials )
						EditorSceneManager.CloseScene( scene, true );
				}
			}
			else
			{
				// Some references are found in this scene, save the results
				searchResult.Add( currentSearchResultGroup );
			}
		}
		private string CachePath { get { return Application.dataPath + "/../Library/AssetUsageDetector.cache"; } } // Path of the cache file

		// Search for references!
		public SearchResult Run( Parameters searchParameters )
		{
			if( searchParameters.objectsToSearch == null )
			{
				Debug.LogError( "objectsToSearch list is empty" );
				return new SearchResult( false, null, null );
			}

			List<SearchResultGroup> searchResult = null;

			// Get the scenes that are open right now
			SceneSetup[] initialSceneSetup = !EditorApplication.isPlaying ? EditorSceneManager.GetSceneManagerSetup() : null;

			// Make sure the AssetDatabase is up-to-date
			AssetDatabase.SaveAssets();

			try
			{
				currentDepth = 0;
				searchedObjectsCount = 0;
				searchStartTime = EditorApplication.timeSinceStartup;

				this.fieldModifiers = searchParameters.fieldModifiers | BindingFlags.Instance | BindingFlags.DeclaredOnly;
				this.propertyModifiers = searchParameters.propertyModifiers | BindingFlags.Instance | BindingFlags.DeclaredOnly;
				this.searchDepthLimit = searchParameters.searchDepthLimit;

				// Initialize commonly used variables
				searchResult = new List<SearchResultGroup>(); // Overall search results

				if( typeToVariables == null )
					typeToVariables = new Dictionary<Type, VariableGetterHolder[]>( 4096 );
				else if( prevFieldModifiers != fieldModifiers || prevPropertyModifiers != propertyModifiers )
					typeToVariables.Clear();

				if( searchedObjects == null )
					searchedObjects = new Dictionary<string, ReferenceNode>( 32768 );
				else
					searchedObjects.Clear();

				if( callStack == null )
					callStack = new List<object>( 64 );
				else
					callStack.Clear();

				if( objectsToSearchSet == null )
					objectsToSearchSet = new HashSet<Object>();
				else
					objectsToSearchSet.Clear();

				if( sceneObjectsToSearchSet == null )
					sceneObjectsToSearchSet = new HashSet<Object>();
				else
					sceneObjectsToSearchSet.Clear();

				if( sceneObjectsToSearchScenesSet == null )
					sceneObjectsToSearchScenesSet = new HashSet<string>();
				else
					sceneObjectsToSearchScenesSet.Clear();

				if( assetsToSearchSet == null )
					assetsToSearchSet = new HashSet<Object>();
				else
					assetsToSearchSet.Clear();

				if( assetsToSearchPathsSet == null )
					assetsToSearchPathsSet = new HashSet<string>();
				else
					assetsToSearchPathsSet.Clear();

				if( assetDependencyCache == null )
				{
					LoadCache();
					searchStartTime = EditorApplication.timeSinceStartup;
				}
				else if( !searchParameters.noAssetDatabaseChanges )
				{
					foreach( var cacheEntry in assetDependencyCache.Values )
						cacheEntry.verified = false;
				}

				foreach( var cacheEntry in assetDependencyCache.Values )
					cacheEntry.searchResult = CacheEntry.Result.Unknown;

				if( typeToSearchFunction == null )
				{
					typeToSearchFunction = new Dictionary<Type, Func<Object, ReferenceNode>>()
					{
						{ typeof( GameObject ), SearchGameObject },
						{ typeof( Material ), SearchMaterial },
						{ typeof( RuntimeAnimatorController ), SearchAnimatorController },
						{ typeof( AnimatorOverrideController ), SearchAnimatorController },
						{ typeof( AnimatorController ), SearchAnimatorController },
						{ typeof( AnimatorStateMachine ), SearchAnimatorStateMachine },
						{ typeof( AnimatorState ), SearchAnimatorState },
						{ typeof( AnimatorStateTransition ), SearchAnimatorStateTransition },
						{ typeof( BlendTree ), SearchBlendTree },
						{ typeof( AnimationClip ), SearchAnimationClip },
#if UNITY_2017_1_OR_NEWER
						{ typeof( SpriteAtlas ), SearchSpriteAtlas },
#endif
					};
				}

				prevFieldModifiers = fieldModifiers;
				prevPropertyModifiers = propertyModifiers;

				searchPrefabConnections = false;
				searchMonoBehavioursForScript = false;
				searchRenderers = false;
				searchMaterialsForShader = false;
				searchMaterialsForTexture = false;

				// Store the searched objects(s) in HashSets
				HashSet<string> folderContentsSet = new HashSet<string>();
				foreach( Object obj in searchParameters.objectsToSearch )
				{
					if( obj == null || obj.Equals( null ) )
						continue;

					if( obj.IsFolder() )
						folderContentsSet.UnionWith( Utilities.EnumerateFolderContents( obj ) );
					else
						AddSearchedObjectToFilteredSets( obj );
				}

				foreach( string filePath in folderContentsSet )
				{
					// Skip scene assets
					if( filePath.EndsWith( ".unity" ) )
						continue;

					Object[] assets = AssetDatabase.LoadAllAssetsAtPath( filePath );
					if( assets == null || assets.Length == 0 )
						continue;

					for( int i = 0; i < assets.Length; i++ )
						AddSearchedObjectToFilteredSets( assets[i] );
				}

				foreach( Object obj in objectsToSearchSet )
				{
					if( obj is Texture )
					{
						searchRenderers = true;
						searchMaterialsForTexture = true;
					}
					else if( obj is Material )
					{
						searchRenderers = true;
					}
					else if( obj is MonoScript )
					{
						searchMonoBehavioursForScript = true;
					}
					else if( obj is Shader )
					{
						searchRenderers = true;
						searchMaterialsForShader = true;
					}
					else if( obj is GameObject )
					{
						searchPrefabConnections = true;
					}
				}

				// Find the scenes to search for references
				HashSet<string> openScenes = null;
				if( EditorApplication.isPlaying )
				{
					// In Play mode, only open scenes can be searched
					openScenes = new HashSet<string>();
					for( int i = 0; i < EditorSceneManager.loadedSceneCount; i++ )
					{
						Scene scene = EditorSceneManager.GetSceneAt( i );
						if( scene.IsValid() )
							openScenes.Add( scene.path );
					}
				}

				HashSet<string> scenesToSearch = new HashSet<string>();
				if( ( searchParameters.searchInScenes & SceneSearchMode.AllScenes ) == SceneSearchMode.AllScenes )
				{
					// Get all scenes from the Assets folder
					string[] sceneGuids = AssetDatabase.FindAssets( "t:SceneAsset" );
					for( int i = 0; i < sceneGuids.Length; i++ )
					{
						string scenePath = AssetDatabase.GUIDToAssetPath( sceneGuids[i] );
						if( !EditorApplication.isPlaying || openScenes.Contains( scenePath ) )
							scenesToSearch.Add( scenePath );
					}
				}
				else
				{
					if( ( searchParameters.searchInScenes & SceneSearchMode.OpenScenes ) == SceneSearchMode.OpenScenes )
					{
						// Get all open (and loaded) scenes
						for( int i = 0; i < EditorSceneManager.loadedSceneCount; i++ )
						{
							Scene scene = EditorSceneManager.GetSceneAt( i );
							if( scene.IsValid() )
								scenesToSearch.Add( scene.path );
						}
					}

					bool searchInScenesInBuildTickedAll = ( searchParameters.searchInScenes & SceneSearchMode.ScenesInBuildSettingsAll ) == SceneSearchMode.ScenesInBuildSettingsAll;
					if( searchInScenesInBuildTickedAll || ( searchParameters.searchInScenes & SceneSearchMode.ScenesInBuildSettingsTickedOnly ) == SceneSearchMode.ScenesInBuildSettingsTickedOnly )
					{
						// Get all scenes in build settings
						EditorBuildSettingsScene[] scenesTemp = EditorBuildSettings.scenes;
						for( int i = 0; i < scenesTemp.Length; i++ )
						{
							if( ( searchInScenesInBuildTickedAll || scenesTemp[i].enabled ) && ( !EditorApplication.isPlaying || openScenes.Contains( scenesTemp[i].path ) ) )
								scenesToSearch.Add( scenesTemp[i].path );
						}
					}
				}

				// By default, search only serializable variables for references
				searchSerializableVariablesOnly = !searchParameters.searchNonSerializableVariables;

				// Initialize the nodes of searched asset(s)
				foreach( Object obj in objectsToSearchSet )
				{
					BeginSearchObject( obj );

					string objHash = obj.Hash();
					ReferenceNode referenceNode;
					if( !searchedObjects.TryGetValue( objHash, out referenceNode ) || referenceNode == null )
						searchedObjects[objHash] = PopReferenceNode( obj );
				}

				// Progressbar values
				int searchProgress = 0;
				int searchTotalProgress = scenesToSearch.Count;
				if( EditorApplication.isPlaying )
					searchTotalProgress++; // DontDestroyOnLoad scene

				// Don't search assets if searched object(s) are all scene objects as assets can't hold references to scene objects
				if( searchParameters.searchInAssetsFolder && assetsToSearchSet.Count > 0 )
				{
					currentSearchResultGroup = new SearchResultGroup( "Project View (Assets)", false );

					// Get the paths of all assets that are to be searched
					IEnumerable<string> assetPaths;
					if( searchParameters.searchInAssetsSubset == null )
					{
						string[] allAssetPaths = AssetDatabase.GetAllAssetPaths();
						searchTotalProgress += allAssetPaths.Length;
						assetPaths = allAssetPaths;
					}
					else
					{
						folderContentsSet.Clear();

						foreach( Object obj in searchParameters.searchInAssetsSubset )
						{
							if( obj == null || obj.Equals( null ) )
								continue;

							if( !obj.IsAsset() )
								continue;

							if( obj.IsFolder() )
								folderContentsSet.UnionWith( Utilities.EnumerateFolderContents( obj ) );
							else
								folderContentsSet.Add( AssetDatabase.GetAssetPath( obj ) );
						}

						searchTotalProgress += folderContentsSet.Count;
						assetPaths = folderContentsSet;
					}

					// Calculate the path(s) of the assets that won't be searched for references
					HashSet<string> excludedAssetsPathsSet = new HashSet<string>();
					if( searchParameters.excludedAssetsFromSearch != null )
					{
						foreach( Object obj in searchParameters.excludedAssetsFromSearch )
						{
							if( obj == null || obj.Equals( null ) )
								continue;

							if( !obj.IsAsset() )
								continue;

							if( obj.IsFolder() )
								excludedAssetsPathsSet.UnionWith( Utilities.EnumerateFolderContents( obj ) );
							else
								excludedAssetsPathsSet.Add( AssetDatabase.GetAssetPath( obj ) );
						}
					}

					if( searchParameters.dontSearchInSourceAssets )
						excludedAssetsPathsSet.UnionWith( assetsToSearchPathsSet );

					foreach( string path in assetPaths )
					{
						if( searchParameters.showProgressBar && ++searchProgress % 30 == 1 && EditorUtility.DisplayCancelableProgressBar( "Please wait...", "Searching assets", (float) searchProgress / searchTotalProgress ) )
							throw new Exception( "Search aborted" );

						if( excludedAssetsPathsSet.Contains( path ) )
							continue;

						// If asset resides inside the Assets directory and is not a scene asset
						if( path.StartsWith( "Assets/" ) && !path.EndsWith( ".unity" ) )
						{
							if( !AssetHasAnyReference( path ) )
								continue;

							Object[] assets = AssetDatabase.LoadAllAssetsAtPath( path );
							if( assets == null || assets.Length == 0 )
								continue;

							for( int i = 0; i < assets.Length; i++ )
							{
								// Components are already searched while searching the GameObject
								if( assets[i] is Component )
									continue;

								BeginSearchObject( assets[i] );
							}
						}
					}

					// If a reference is found in the Project view, save the results
					if( currentSearchResultGroup.NumberOfReferences > 0 )
						searchResult.Add( currentSearchResultGroup );
				}

				// Search non-serializable variables for references only if we are currently searching a scene and the editor is in play mode
				if( EditorApplication.isPlaying )
					searchSerializableVariablesOnly = false;

				if( scenesToSearch.Count > 0 )
				{
					// Calculate the path(s) of the scenes that won't be searched for references
					HashSet<string> excludedScenesPathsSet = new HashSet<string>();
					if( searchParameters.excludedScenesFromSearch != null )
					{
						foreach( Object obj in searchParameters.excludedScenesFromSearch )
						{
							if( obj == null || obj.Equals( null ) )
								continue;

							if( !obj.IsAsset() )
								continue;

							if( obj.IsFolder() )
							{
								string[] folderContents = AssetDatabase.FindAssets( "t:SceneAsset", new string[] { AssetDatabase.GetAssetPath( obj ) } );
								if( folderContents == null )
									continue;

								for( int i = 0; i < folderContents.Length; i++ )
									excludedScenesPathsSet.Add( AssetDatabase.GUIDToAssetPath( folderContents[i] ) );
							}
							else if( obj is SceneAsset )
								excludedScenesPathsSet.Add( AssetDatabase.GetAssetPath( obj ) );
						}
					}

					foreach( string scenePath in scenesToSearch )
					{
						if( searchParameters.showProgressBar && EditorUtility.DisplayCancelableProgressBar( "Please wait...", "Searching scene: " + scenePath, (float) ++searchProgress / searchTotalProgress ) )
							throw new Exception( "Search aborted" );

						// Search scene for references
						if( string.IsNullOrEmpty( scenePath ) )
							continue;

						if( excludedScenesPathsSet.Contains( scenePath ) )
							continue;

						SearchScene( scenePath, searchResult, initialSceneSetup );
					}
				}

				// Search through all the GameObjects under the DontDestroyOnLoad scene (if exists)
				if( EditorApplication.isPlaying )
				{
					if( searchParameters.showProgressBar && EditorUtility.DisplayCancelableProgressBar( "Please wait...", "Searching scene: DontDestroyOnLoad", 1f ) )
						throw new Exception( "Search aborted" );

					currentSearchResultGroup = new SearchResultGroup( "DontDestroyOnLoad", false );

					GameObject[] rootGameObjects = GetDontDestroyOnLoadObjects();
					for( int i = 0; i < rootGameObjects.Length; i++ )
						SearchGameObjectRecursively( rootGameObjects[i] );

					if( currentSearchResultGroup.NumberOfReferences > 0 )
						searchResult.Add( currentSearchResultGroup );
				}

				InitializeSearchResultNodes( searchResult );

				// Log some c00l stuff to console
				Debug.Log( "Searched " + searchedObjectsCount + " objects in " + ( EditorApplication.timeSinceStartup - searchStartTime ).ToString( "F2" ) + " seconds" );

				return new SearchResult( true, searchResult, initialSceneSetup );
			}
			catch( Exception e )
			{
				Debug.LogException( e );

				try
				{
					InitializeSearchResultNodes( searchResult );
				}
				catch
				{ }

				return new SearchResult( false, searchResult, initialSceneSetup );
			}
			finally
			{
				currentSearchResultGroup = null;
				currentObject = null;

				EditorUtility.ClearProgressBar();
			}
		}
        public void RefreshSearchResultGroup(SearchResultGroup searchResultGroup, bool noAssetDatabaseChanges)
        {
            if (searchResultGroup == null)
            {
                Debug.LogError("SearchResultGroup is null!");
                return;
            }

            int searchResultGroupIndex = -1;

            for (int i = 0; i < result.Count; i++)
            {
                if (result[i] == searchResultGroup)
                {
                    searchResultGroupIndex = i;
                    break;
                }
            }

            if (searchResultGroupIndex < 0)
            {
                Debug.LogError("SearchResultGroup is not a part of SearchResult!");
                return;
            }

            if (searchResultGroup.Type == SearchResultGroup.GroupType.Scene && EditorApplication.isPlaying && !EditorSceneManager.GetSceneByPath(searchResultGroup.Title).isLoaded)
            {
                Debug.LogError("Can't search unloaded scene while in Play Mode!");
                return;
            }

            if (searchHandler == null)
            {
                searchHandler = new AssetUsageDetector();
            }

            SceneSearchMode searchInScenes = m_searchParameters.searchInScenes;

            Object[] searchInScenesSubset = m_searchParameters.searchInScenesSubset;
            bool     searchInAssetsFolder = m_searchParameters.searchInAssetsFolder;

            Object[] searchInAssetsSubset = m_searchParameters.searchInAssetsSubset;

            try
            {
                if (searchResultGroup.Type == SearchResultGroup.GroupType.Assets)
                {
                    m_searchParameters.searchInScenes       = SceneSearchMode.None;
                    m_searchParameters.searchInScenesSubset = null;
                }
                else if (searchResultGroup.Type == SearchResultGroup.GroupType.Scene)
                {
                    m_searchParameters.searchInScenes       = SceneSearchMode.None;
                    m_searchParameters.searchInScenesSubset = new Object[1] {
                        AssetDatabase.LoadAssetAtPath <SceneAsset>(searchResultGroup.Title)
                    };
                    m_searchParameters.searchInAssetsFolder = false;
                    m_searchParameters.searchInAssetsSubset = null;
                }
                else
                {
                    m_searchParameters.searchInScenes       = (SceneSearchMode)1024;                // A unique value to search only the DontDestroyOnLoad scene
                    m_searchParameters.searchInScenesSubset = null;
                    m_searchParameters.searchInAssetsFolder = false;
                    m_searchParameters.searchInAssetsSubset = null;
                }

                m_searchParameters.lazySceneSearch        = false;
                m_searchParameters.noAssetDatabaseChanges = noAssetDatabaseChanges;

                // Make sure the AssetDatabase is up-to-date
                AssetDatabase.SaveAssets();

                List <SearchResultGroup> searchResult = searchHandler.Run(m_searchParameters).result;
                if (searchResult != null)
                {
                    int newSearchResultGroupIndex = -1;
                    for (int i = 0; i < searchResult.Count; i++)
                    {
                        if (searchResultGroup.Title == searchResult[i].Title)
                        {
                            newSearchResultGroupIndex = i;
                            break;
                        }
                    }

                    if (newSearchResultGroupIndex >= 0)
                    {
                        result[searchResultGroupIndex] = searchResult[newSearchResultGroupIndex];
                    }
                    else
                    {
                        searchResultGroup.Clear();
                    }
                }
            }
            finally
            {
                m_searchParameters.searchInScenes       = searchInScenes;
                m_searchParameters.searchInScenesSubset = searchInScenesSubset;
                m_searchParameters.searchInAssetsFolder = searchInAssetsFolder;
                m_searchParameters.searchInAssetsSubset = searchInAssetsSubset;
            }
        }