You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
Driftology/Assets/Plugins/AssetUsageDetector/Editor/AssetUsageDetectorWindow.cs

745 lines
29 KiB
C#

// Asset Usage Detector - by Suleyman Yasir KULA (yasirkula@gmail.com)
using UnityEngine;
using UnityEditor;
using System.Collections.Generic;
using System.Reflection;
using Object = UnityEngine.Object;
#if UNITY_2018_3_OR_NEWER
using PrefabStage = UnityEditor.SceneManagement.PrefabStage;
using PrefabStageUtility = UnityEditor.SceneManagement.PrefabStageUtility;
#endif
namespace AssetUsageDetectorNamespace
{
public enum Phase { Setup, Processing, Complete };
public class AssetUsageDetectorWindow : EditorWindow
{
private const float PLAY_MODE_REFRESH_INTERVAL = 1f; // Interval to refresh the editor window in play mode
private const string PREFS_SEARCH_SCENES = "AUD_SceneSearch";
private const string PREFS_SEARCH_ASSETS = "AUD_AssetsSearch";
private const string PREFS_SEARCH_PROJECT_SETTINGS = "AUD_ProjectSettingsSearch";
private const string PREFS_DONT_SEARCH_SOURCE_ASSETS = "AUD_AssetsExcludeSrc";
private const string PREFS_SEARCH_DEPTH_LIMIT = "AUD_Depth";
private const string PREFS_SEARCH_FIELDS = "AUD_Fields";
private const string PREFS_SEARCH_PROPERTIES = "AUD_Properties";
private const string PREFS_SEARCH_NON_SERIALIZABLES = "AUD_NonSerializables";
private const string PREFS_LAZY_SCENE_SEARCH = "AUD_LazySceneSearch";
private const string PREFS_PATH_DRAWING_MODE = "AUD_PathDrawing";
private const string PREFS_SHOW_PROGRESS = "AUD_Progress";
private const string PREFS_SHOW_TOOLTIPS = "AUD_Tooltips";
private static readonly GUIContent windowTitle = new GUIContent( "Asset Usage Detector" );
private static readonly Vector2 windowMinSize = new Vector2( 325f, 220f );
private AssetUsageDetector core = new AssetUsageDetector();
private SearchResult searchResult; // Overall search results
private List<ObjectToSearch> objectsToSearch = new List<ObjectToSearch>() { new ObjectToSearch( null ) };
private Phase currentPhase = Phase.Setup;
private bool searchInOpenScenes = true; // Scenes currently open in Hierarchy view
private bool searchInScenesInBuild = true; // Scenes in build
private bool searchInScenesInBuildTickedOnly = true; // Scenes in build (ticked only or not)
private bool searchInAllScenes = true; // All scenes (including scenes that are not in build)
private bool searchInAssetsFolder = true; // Assets in Project window
private bool dontSearchInSourceAssets = true; // objectsToSearch won't be searched for internal references
private bool searchInProjectSettings = true; // Player Settings, Graphics Settings etc.
private List<Object> searchInAssetsSubset = new List<Object>() { null }; // If not empty, only these assets are searched for references
private List<Object> excludedAssets = new List<Object>() { null }; // These assets won't be searched for references
private List<Object> excludedScenes = new List<Object>() { null }; // These scenes won't be searched for references
private int searchDepthLimit = 4; // Depth limit for recursively searching variables of objects
private bool restoreInitialSceneSetup = true; // Close the additively loaded scenes that were not part of the initial scene setup
private string errorMessage = string.Empty;
private bool lazySceneSearch = false;
private bool searchNonSerializableVariables = true;
private bool noAssetDatabaseChanges = false;
private bool showDetailedProgressBar = false;
private BindingFlags fieldModifiers, propertyModifiers;
private SearchResultDrawParameters searchResultDrawParameters = new SearchResultDrawParameters( PathDrawingMode.ShortRelevantParts, false, false );
private double nextPlayModeRefreshTime = 0f;
private readonly ObjectToSearchListDrawer objectsToSearchDrawer = new ObjectToSearchListDrawer();
private readonly ObjectListDrawer searchInAssetsSubsetDrawer = new ObjectListDrawer( "Search following asset(s) only:", false );
private readonly ObjectListDrawer excludedAssetsDrawer = new ObjectListDrawer( "Don't search following asset(s):", false );
private readonly ObjectListDrawer excludedScenesDrawer = new ObjectListDrawer( "Don't search in following scene(s):", false );
private readonly GUIContent restoreInitialSceneSetupLabel = new GUIContent( "Restore initial scene setup (Recommended)", "For example, if scene A was open when the search was started and scenes A and B are open after the search is completed, clicking the \"Reset Search\" button will automatically close scene B" );
private readonly GUIContent showTooltipsLabel = new GUIContent( "Show tooltips", "Display nodes' contents in a tooltip when cursor hovers over them" );
private Vector2 scrollPosition = Vector2.zero;
private bool shouldRepositionSelf;
private Rect windowTargetPosition;
private static AssetUsageDetectorWindow mainWindow = null;
// Add "Asset Usage Detector" menu item to the Window menu
[MenuItem( "Window/Asset Usage Detector/Active Window" )]
private static void OpenActiveWindow()
{
if( !mainWindow )
{
mainWindow = GetWindow<AssetUsageDetectorWindow>();
mainWindow.titleContent = windowTitle;
mainWindow.minSize = windowMinSize;
}
mainWindow.Show();
}
[MenuItem( "Window/Asset Usage Detector/New Window" )]
private static void OpenNewWindow()
{
Rect? windowTargetPosition = null;
if( mainWindow )
{
Rect position = mainWindow.position;
position.position += new Vector2( 50f, 50f );
windowTargetPosition = position;
}
mainWindow = CreateInstance<AssetUsageDetectorWindow>();
mainWindow.titleContent = windowTitle;
mainWindow.minSize = windowMinSize;
if( windowTargetPosition.HasValue )
{
mainWindow.shouldRepositionSelf = true;
mainWindow.windowTargetPosition = windowTargetPosition.Value;
}
mainWindow.Show( true );
}
// Quickly initiate search for the selected assets
[MenuItem( "GameObject/Search for References/This Object Only", priority = 49 )]
[MenuItem( "Assets/Search for References", priority = 1000 )]
private static void SearchSelectedAssetReferences( MenuCommand command )
{
// This happens when this button is clicked via hierarchy's right click context menu
// and is called once for each object in the selection. We don't want that, we want
// the function to be called only once
if( command.context )
{
EditorApplication.update -= CallSearchSelectedAssetReferencesOnce;
EditorApplication.update += CallSearchSelectedAssetReferencesOnce;
}
else
ShowAndSearch( Selection.objects );
}
[MenuItem( "GameObject/Search for References/Include Children", priority = 49 )]
private static void SearchSelectedAssetReferencesWithChildren( MenuCommand command )
{
if( command.context )
{
EditorApplication.update -= CallSearchSelectedAssetReferencesWithChildrenOnce;
EditorApplication.update += CallSearchSelectedAssetReferencesWithChildrenOnce;
}
else
ShowAndSearch( Selection.objects, true );
}
// Show the menu item only if there is a selection in the Editor
[MenuItem( "GameObject/Search for References/This Object Only", validate = true )]
[MenuItem( "GameObject/Search for References/Include Children", validate = true )]
[MenuItem( "Assets/Search for References", validate = true )]
private static bool SearchSelectedAssetReferencesValidate( MenuCommand command )
{
return Selection.objects.Length > 0;
}
// Quickly show the AssetUsageDetector window and initiate a search
public static void ShowAndSearch( IEnumerable<Object> searchObjects, bool? shouldSearchChildren = null )
{
ShowAndSearchInternal( searchObjects, null, shouldSearchChildren );
}
// Quickly show the AssetUsageDetector window and initiate a search
public static void ShowAndSearch( AssetUsageDetector.Parameters searchParameters, bool? shouldSearchChildren = null )
{
if( searchParameters == null )
{
Debug.LogError( "searchParameters can't be null!" );
return;
}
ShowAndSearchInternal( searchParameters.objectsToSearch, searchParameters, shouldSearchChildren );
}
private static void CallSearchSelectedAssetReferencesOnce()
{
EditorApplication.update -= CallSearchSelectedAssetReferencesOnce;
SearchSelectedAssetReferences( new MenuCommand( null ) );
}
private static void CallSearchSelectedAssetReferencesWithChildrenOnce()
{
EditorApplication.update -= CallSearchSelectedAssetReferencesWithChildrenOnce;
SearchSelectedAssetReferencesWithChildren( new MenuCommand( null ) );
}
private static void ShowAndSearchInternal( IEnumerable<Object> searchObjects, AssetUsageDetector.Parameters searchParameters, bool? shouldSearchChildren )
{
if( mainWindow != null && !mainWindow.ReturnToSetupPhase( true, true ) )
{
Debug.LogError( "Need to reset the previous search first!" );
return;
}
OpenActiveWindow();
mainWindow.objectsToSearch.Clear();
if( searchObjects != null )
{
foreach( Object obj in searchObjects )
mainWindow.objectsToSearch.Add( new ObjectToSearch( obj, shouldSearchChildren ) );
}
if( searchParameters != null )
{
mainWindow.ParseSceneSearchMode( searchParameters.searchInScenes );
mainWindow.searchInAssetsFolder = searchParameters.searchInAssetsFolder;
mainWindow.dontSearchInSourceAssets = searchParameters.dontSearchInSourceAssets;
mainWindow.searchInProjectSettings = searchParameters.searchInProjectSettings;
mainWindow.searchDepthLimit = searchParameters.searchDepthLimit;
mainWindow.fieldModifiers = searchParameters.fieldModifiers;
mainWindow.propertyModifiers = searchParameters.propertyModifiers;
mainWindow.searchNonSerializableVariables = searchParameters.searchNonSerializableVariables;
mainWindow.lazySceneSearch = searchParameters.lazySceneSearch;
mainWindow.noAssetDatabaseChanges = searchParameters.noAssetDatabaseChanges;
mainWindow.showDetailedProgressBar = searchParameters.showDetailedProgressBar;
mainWindow.searchInAssetsSubset.Clear();
if( searchParameters.searchInAssetsSubset != null )
{
foreach( Object obj in searchParameters.searchInAssetsSubset )
mainWindow.searchInAssetsSubset.Add( obj );
}
mainWindow.excludedAssets.Clear();
if( searchParameters.excludedAssetsFromSearch != null )
{
foreach( Object obj in searchParameters.excludedAssetsFromSearch )
mainWindow.excludedAssets.Add( obj );
}
mainWindow.excludedScenes.Clear();
if( searchParameters.excludedScenesFromSearch != null )
{
foreach( Object obj in searchParameters.excludedScenesFromSearch )
mainWindow.excludedScenes.Add( obj );
}
}
mainWindow.InitiateSearch();
mainWindow.Repaint();
}
private void Awake()
{
LoadPrefs();
}
private void OnEnable()
{
mainWindow = this;
#if UNITY_2018_3_OR_NEWER
PrefabStage.prefabStageClosing -= ReplacePrefabStageObjectsWithAssets;
PrefabStage.prefabStageClosing += ReplacePrefabStageObjectsWithAssets;
#endif
}
private void OnDisable()
{
#if UNITY_2018_3_OR_NEWER
PrefabStage.prefabStageClosing -= ReplacePrefabStageObjectsWithAssets;
#endif
if( mainWindow == this )
mainWindow = null;
}
private void OnDestroy()
{
if( core != null )
core.SaveCache();
SavePrefs();
if( searchResult != null && currentPhase == Phase.Complete )
searchResult.RestoreInitialSceneSetup( true );
}
private void OnFocus()
{
mainWindow = this;
}
private void SavePrefs()
{
EditorPrefs.SetInt( PREFS_SEARCH_SCENES, (int) GetSceneSearchMode( false ) );
EditorPrefs.SetBool( PREFS_SEARCH_ASSETS, searchInAssetsFolder );
EditorPrefs.SetBool( PREFS_DONT_SEARCH_SOURCE_ASSETS, dontSearchInSourceAssets );
EditorPrefs.SetBool( PREFS_SEARCH_PROJECT_SETTINGS, searchInProjectSettings );
EditorPrefs.SetInt( PREFS_SEARCH_DEPTH_LIMIT, searchDepthLimit );
EditorPrefs.SetInt( PREFS_SEARCH_FIELDS, (int) fieldModifiers );
EditorPrefs.SetInt( PREFS_SEARCH_PROPERTIES, (int) propertyModifiers );
EditorPrefs.SetInt( PREFS_PATH_DRAWING_MODE, (int) searchResultDrawParameters.pathDrawingMode );
EditorPrefs.SetBool( PREFS_SEARCH_NON_SERIALIZABLES, searchNonSerializableVariables );
EditorPrefs.SetBool( PREFS_LAZY_SCENE_SEARCH, lazySceneSearch );
EditorPrefs.SetBool( PREFS_SHOW_TOOLTIPS, searchResultDrawParameters.showTooltips );
EditorPrefs.SetBool( PREFS_SHOW_PROGRESS, showDetailedProgressBar );
}
private void LoadPrefs()
{
ParseSceneSearchMode( (SceneSearchMode) EditorPrefs.GetInt( PREFS_SEARCH_SCENES, (int) ( SceneSearchMode.OpenScenes | SceneSearchMode.ScenesInBuildSettingsTickedOnly | SceneSearchMode.AllScenes ) ) );
searchInAssetsFolder = EditorPrefs.GetBool( PREFS_SEARCH_ASSETS, true );
dontSearchInSourceAssets = EditorPrefs.GetBool( PREFS_DONT_SEARCH_SOURCE_ASSETS, true );
searchInProjectSettings = EditorPrefs.GetBool( PREFS_SEARCH_PROJECT_SETTINGS, true );
searchDepthLimit = EditorPrefs.GetInt( PREFS_SEARCH_DEPTH_LIMIT, 4 );
// Fetch public, protected and private non-static fields and properties from objects by default
fieldModifiers = (BindingFlags) EditorPrefs.GetInt( PREFS_SEARCH_FIELDS, (int) ( BindingFlags.Public | BindingFlags.NonPublic ) );
propertyModifiers = (BindingFlags) EditorPrefs.GetInt( PREFS_SEARCH_PROPERTIES, (int) ( BindingFlags.Public | BindingFlags.NonPublic ) );
try
{
searchResultDrawParameters.pathDrawingMode = (PathDrawingMode) EditorPrefs.GetInt( PREFS_PATH_DRAWING_MODE, (int) PathDrawingMode.ShortRelevantParts );
}
catch
{
searchResultDrawParameters.pathDrawingMode = PathDrawingMode.ShortRelevantParts;
}
searchNonSerializableVariables = EditorPrefs.GetBool( PREFS_SEARCH_NON_SERIALIZABLES, true );
lazySceneSearch = EditorPrefs.GetBool( PREFS_LAZY_SCENE_SEARCH, false );
searchResultDrawParameters.showTooltips = EditorPrefs.GetBool( PREFS_SHOW_TOOLTIPS, false );
showDetailedProgressBar = EditorPrefs.GetBool( PREFS_SHOW_PROGRESS, false );
}
private SceneSearchMode GetSceneSearchMode( bool hideOptionsInPlayMode )
{
SceneSearchMode sceneSearchMode = SceneSearchMode.None;
if( searchInOpenScenes )
sceneSearchMode |= SceneSearchMode.OpenScenes;
if( !hideOptionsInPlayMode || !EditorApplication.isPlaying )
{
if( searchInScenesInBuild )
sceneSearchMode |= searchInScenesInBuildTickedOnly ? SceneSearchMode.ScenesInBuildSettingsTickedOnly : SceneSearchMode.ScenesInBuildSettingsAll;
if( searchInAllScenes )
sceneSearchMode |= SceneSearchMode.AllScenes;
}
return sceneSearchMode;
}
private void ParseSceneSearchMode( SceneSearchMode sceneSearchMode )
{
searchInOpenScenes = ( sceneSearchMode & SceneSearchMode.OpenScenes ) == SceneSearchMode.OpenScenes;
searchInScenesInBuild = ( sceneSearchMode & SceneSearchMode.ScenesInBuildSettingsAll ) == SceneSearchMode.ScenesInBuildSettingsAll || ( sceneSearchMode & SceneSearchMode.ScenesInBuildSettingsTickedOnly ) == SceneSearchMode.ScenesInBuildSettingsTickedOnly;
searchInScenesInBuildTickedOnly = ( sceneSearchMode & SceneSearchMode.ScenesInBuildSettingsAll ) != SceneSearchMode.ScenesInBuildSettingsAll;
searchInAllScenes = ( sceneSearchMode & SceneSearchMode.AllScenes ) == SceneSearchMode.AllScenes;
}
private void Update()
{
// Refresh the window at a regular interval in play mode to update the tooltip
if( EditorApplication.isPlaying && currentPhase == Phase.Complete && searchResultDrawParameters.showTooltips && EditorApplication.timeSinceStartup >= nextPlayModeRefreshTime )
{
nextPlayModeRefreshTime = EditorApplication.timeSinceStartup + PLAY_MODE_REFRESH_INTERVAL; ;
Repaint();
}
if( shouldRepositionSelf )
{
shouldRepositionSelf = false;
position = windowTargetPosition;
}
}
private void OnGUI()
{
// Make the window scrollable
scrollPosition = EditorGUILayout.BeginScrollView( scrollPosition, Utilities.GL_EXPAND_WIDTH, Utilities.GL_EXPAND_HEIGHT );
GUILayout.BeginVertical();
GUILayout.Space( 10 );
// Show the error message, if it is not empty
if( errorMessage.Length > 0 )
EditorGUILayout.HelpBox( errorMessage, MessageType.Error );
GUILayout.Space( 10 );
if( currentPhase == Phase.Processing )
{
// If we are stuck at this phase, then we have encountered an exception
GUILayout.Label( ". . . Search in progress or something went wrong (check console) . . ." );
restoreInitialSceneSetup = EditorGUILayout.ToggleLeft( restoreInitialSceneSetupLabel, restoreInitialSceneSetup );
if( GUILayout.Button( "RETURN", Utilities.GL_HEIGHT_30 ) )
ReturnToSetupPhase( restoreInitialSceneSetup, false );
}
else if( currentPhase == Phase.Setup )
{
if( objectsToSearchDrawer.Draw( objectsToSearch ) )
errorMessage = string.Empty;
GUILayout.Space( 10 );
Color c = GUI.backgroundColor;
GUI.backgroundColor = Color.cyan;
GUILayout.Box( "SEARCH IN", Utilities.BoxGUIStyle, Utilities.GL_EXPAND_WIDTH );
GUI.backgroundColor = c;
searchInAssetsFolder = EditorGUILayout.ToggleLeft( "Project window (Assets folder)", searchInAssetsFolder );
if( searchInAssetsFolder )
{
GUILayout.BeginHorizontal();
GUILayout.Space( 35 );
GUILayout.BeginVertical();
searchInAssetsSubsetDrawer.Draw( searchInAssetsSubset );
excludedAssetsDrawer.Draw( excludedAssets );
dontSearchInSourceAssets = EditorGUILayout.ToggleLeft( "Don't search \"Find references of\" themselves for references", dontSearchInSourceAssets );
GUILayout.EndVertical();
GUILayout.EndHorizontal();
}
Utilities.DrawSeparatorLine();
if( searchInAllScenes && !EditorApplication.isPlaying )
GUI.enabled = false;
searchInOpenScenes = EditorGUILayout.ToggleLeft( "Currently open (loaded) scene(s)", searchInOpenScenes );
if( !EditorApplication.isPlaying )
{
searchInScenesInBuild = EditorGUILayout.ToggleLeft( "Scenes in Build Settings", searchInScenesInBuild );
if( searchInScenesInBuild )
{
GUILayout.BeginHorizontal();
GUILayout.Space( 35 );
searchInScenesInBuildTickedOnly = EditorGUILayout.ToggleLeft( "Ticked only", searchInScenesInBuildTickedOnly, Utilities.GL_WIDTH_100 );
searchInScenesInBuildTickedOnly = !EditorGUILayout.ToggleLeft( "All", !searchInScenesInBuildTickedOnly, Utilities.GL_WIDTH_100 );
GUILayout.EndHorizontal();
}
GUI.enabled = true;
searchInAllScenes = EditorGUILayout.ToggleLeft( "All scenes in the project", searchInAllScenes );
}
GUILayout.BeginHorizontal();
GUILayout.Space( 35 );
GUILayout.BeginVertical();
excludedScenesDrawer.Draw( excludedScenes );
GUILayout.EndVertical();
GUILayout.EndHorizontal();
Utilities.DrawSeparatorLine();
searchInProjectSettings = EditorGUILayout.ToggleLeft( "Project Settings (Player Settings, Graphics Settings etc.)", searchInProjectSettings );
GUILayout.Space( 10 );
//GUILayout.Box( "SEARCH SETTINGS", Utilities.BoxGUIStyle, Utilities.GL_EXPAND_WIDTH );
//GUILayout.BeginHorizontal();
//GUILayout.Label( new GUIContent( "> Search depth: " + searchDepthLimit, "Depth limit for recursively searching variables of objects" ), Utilities.GL_WIDTH_250 );
//searchDepthLimit = (int) GUILayout.HorizontalSlider( searchDepthLimit, 0, 4 );
//GUILayout.EndHorizontal();
//GUILayout.Label( "> Search variables:" );
//GUILayout.BeginHorizontal();
//GUILayout.Space( 35 );
//if( EditorGUILayout.ToggleLeft( "Public", ( fieldModifiers & BindingFlags.Public ) == BindingFlags.Public, Utilities.GL_WIDTH_100 ) )
// fieldModifiers |= BindingFlags.Public;
//else
// fieldModifiers &= ~BindingFlags.Public;
//if( EditorGUILayout.ToggleLeft( "Non-public", ( fieldModifiers & BindingFlags.NonPublic ) == BindingFlags.NonPublic, Utilities.GL_WIDTH_100 ) )
// fieldModifiers |= BindingFlags.NonPublic;
//else
// fieldModifiers &= ~BindingFlags.NonPublic;
//GUILayout.EndHorizontal();
//GUILayout.Label( "> Search properties:" );
//GUILayout.BeginHorizontal();
//GUILayout.Space( 35 );
//if( EditorGUILayout.ToggleLeft( "Public", ( propertyModifiers & BindingFlags.Public ) == BindingFlags.Public, Utilities.GL_WIDTH_100 ) )
// propertyModifiers |= BindingFlags.Public;
//else
// propertyModifiers &= ~BindingFlags.Public;
//if( EditorGUILayout.ToggleLeft( "Non-public", ( propertyModifiers & BindingFlags.NonPublic ) == BindingFlags.NonPublic, Utilities.GL_WIDTH_100 ) )
// propertyModifiers |= BindingFlags.NonPublic;
//else
// propertyModifiers &= ~BindingFlags.NonPublic;
//GUILayout.EndHorizontal();
//GUILayout.Space( 10 );
//searchNonSerializableVariables = EditorGUILayout.ToggleLeft( "Search non-serializable fields and properties", searchNonSerializableVariables );
//GUILayout.Space( 10 );
GUI.backgroundColor = Color.cyan;
GUILayout.Box( "SETTINGS", Utilities.BoxGUIStyle, Utilities.GL_EXPAND_WIDTH );
GUI.backgroundColor = c;
lazySceneSearch = EditorGUILayout.ToggleLeft( "Lazy scene search: scenes are searched in detail only when they are manually refreshed (faster search)", lazySceneSearch );
noAssetDatabaseChanges = EditorGUILayout.ToggleLeft( "I haven't modified any assets/scenes since the last search (faster search)", noAssetDatabaseChanges );
showDetailedProgressBar = EditorGUILayout.ToggleLeft( "Show detailed progress bar (slower search)", showDetailedProgressBar );
GUILayout.Space( 10 );
// Don't let the user press the GO button without any valid search location
if( !searchInAllScenes && !searchInOpenScenes && !searchInScenesInBuild && !searchInAssetsFolder && !searchInProjectSettings )
GUI.enabled = false;
if( GUILayout.Button( "GO!", Utilities.GL_HEIGHT_30 ) )
{
InitiateSearch();
GUIUtility.ExitGUI();
}
}
else if( currentPhase == Phase.Complete )
{
// Draw the results of the search
GUI.enabled = false;
objectsToSearchDrawer.Draw( objectsToSearch );
GUILayout.Space( 10 );
GUI.enabled = true;
restoreInitialSceneSetup = EditorGUILayout.ToggleLeft( restoreInitialSceneSetupLabel, restoreInitialSceneSetup );
if( GUILayout.Button( "Reset Search", Utilities.GL_HEIGHT_30 ) )
ReturnToSetupPhase( restoreInitialSceneSetup, false );
if( searchResult == null )
{
EditorGUILayout.HelpBox( "ERROR: searchResult is null", MessageType.Error );
return;
}
else if( !searchResult.SearchCompletedSuccessfully )
EditorGUILayout.HelpBox( "ERROR: search was interrupted, check the logs for more info", MessageType.Error );
Color c = GUI.backgroundColor;
GUI.backgroundColor = Color.green;
GUILayout.Box( "Don't forget to save scene(s) if you made any changes!", Utilities.BoxGUIStyle, Utilities.GL_EXPAND_WIDTH );
GUI.backgroundColor = c;
if( searchResult.NumberOfGroups == 0 )
{
GUILayout.Space( 10 );
GUILayout.Box( "No references found...", Utilities.BoxGUIStyle, Utilities.GL_EXPAND_WIDTH );
}
else
{
//GUILayout.Space( 10 );
//GUILayout.BeginHorizontal();
//// Select all the references after filtering them (select only the GameObject's)
//if( GUILayout.Button( "Select All\n(GameObject-wise)", Utilities.GL_HEIGHT_35 ) )
//{
// GameObject[] objects = searchResult.SelectAllAsGameObjects();
// if( objects != null && objects.Length > 0 )
// Selection.objects = objects;
//}
//// Select all the references without filtering them
//if( GUILayout.Button( "Select All\n(Object-wise)", Utilities.GL_HEIGHT_35 ) )
//{
// Object[] objects = searchResult.SelectAllAsObjects();
// if( objects != null && objects.Length > 0 )
// Selection.objects = objects;
//}
//GUILayout.EndHorizontal();
//GUILayout.Space( 10 );
searchResultDrawParameters.showTooltips = EditorGUILayout.ToggleLeft( showTooltipsLabel, searchResultDrawParameters.showTooltips );
noAssetDatabaseChanges = EditorGUILayout.ToggleLeft( "I haven't modified any assets/scenes since the last search (faster Refresh)", noAssetDatabaseChanges );
searchResultDrawParameters.noAssetDatabaseChanges = noAssetDatabaseChanges;
Utilities.DrawSeparatorLine();
GUILayout.Label( "Path drawing mode:" );
GUILayout.BeginHorizontal();
GUILayout.Space( 35 );
if( EditorGUILayout.ToggleLeft( "Full: Draw the complete paths to the references", searchResultDrawParameters.pathDrawingMode == PathDrawingMode.Full ) )
searchResultDrawParameters.pathDrawingMode = PathDrawingMode.Full;
GUILayout.EndHorizontal();
GUILayout.BeginHorizontal();
GUILayout.Space( 35 );
if( EditorGUILayout.ToggleLeft( "Shorter: Draw only the most relevant parts (that start with a UnityEngine.Object) of the complete paths", searchResultDrawParameters.pathDrawingMode == PathDrawingMode.ShortRelevantParts ) )
searchResultDrawParameters.pathDrawingMode = PathDrawingMode.ShortRelevantParts;
GUILayout.EndHorizontal();
GUILayout.BeginHorizontal();
GUILayout.Space( 35 );
if( EditorGUILayout.ToggleLeft( "Shortest: Draw only the last two nodes of the complete paths", searchResultDrawParameters.pathDrawingMode == PathDrawingMode.Shortest ) )
searchResultDrawParameters.pathDrawingMode = PathDrawingMode.Shortest;
GUILayout.EndHorizontal();
searchResult.DrawOnGUI( searchResultDrawParameters );
}
}
GUILayout.Space( 10 );
GUILayout.EndVertical();
EditorGUILayout.EndScrollView();
}
private void InitiateSearch()
{
if( objectsToSearch.IsEmpty() )
errorMessage = "ADD AN ASSET TO THE LIST FIRST!";
else if( !EditorApplication.isPlaying && !Utilities.AreScenesSaved() )
{
// Don't start the search if at least one scene is currently dirty (not saved)
errorMessage = "SAVE OPEN SCENES FIRST!";
}
else
{
errorMessage = string.Empty;
currentPhase = Phase.Processing;
SavePrefs();
#if UNITY_2018_3_OR_NEWER
ReplacePrefabStageObjectsWithAssets( PrefabStageUtility.GetCurrentPrefabStage() );
#endif
// Start searching
searchResult = core.Run( new AssetUsageDetector.Parameters()
{
objectsToSearch = new ObjectToSearchEnumerator( objectsToSearch ).ToArray(),
searchInScenes = GetSceneSearchMode( true ),
searchInAssetsFolder = searchInAssetsFolder,
searchInAssetsSubset = !searchInAssetsSubset.IsEmpty() ? searchInAssetsSubset.ToArray() : null,
excludedAssetsFromSearch = !excludedAssets.IsEmpty() ? excludedAssets.ToArray() : null,
dontSearchInSourceAssets = dontSearchInSourceAssets,
excludedScenesFromSearch = !excludedScenes.IsEmpty() ? excludedScenes.ToArray() : null,
searchInProjectSettings = searchInProjectSettings,
//fieldModifiers = fieldModifiers,
//propertyModifiers = propertyModifiers,
//searchDepthLimit = searchDepthLimit,
//searchNonSerializableVariables = searchNonSerializableVariables,
lazySceneSearch = lazySceneSearch,
noAssetDatabaseChanges = noAssetDatabaseChanges,
showDetailedProgressBar = showDetailedProgressBar
} );
currentPhase = Phase.Complete;
}
}
#if UNITY_2018_3_OR_NEWER
// Try replacing searched objects who are part of currently open prefab stage with their corresponding prefab assets
public void ReplacePrefabStageObjectsWithAssets( PrefabStage prefabStage )
{
if( prefabStage == null || !prefabStage.stageHandle.IsValid() )
return;
#if UNITY_2020_1_OR_NEWER
GameObject prefabAsset = AssetDatabase.LoadAssetAtPath<GameObject>( prefabStage.assetPath );
#else
GameObject prefabAsset = AssetDatabase.LoadAssetAtPath<GameObject>( prefabStage.prefabAssetPath );
#endif
if( prefabAsset == null || prefabAsset.Equals( null ) )
return;
for( int i = 0; i < objectsToSearch.Count; i++ )
{
Object obj = objectsToSearch[i].obj;
if( obj != null && !obj.Equals( null ) && obj is GameObject && prefabStage.IsPartOfPrefabContents( (GameObject) obj ) )
{
GameObject prefabStageObjectSource = ( (GameObject) obj ).FollowSymmetricHierarchy( prefabStage.prefabContentsRoot, prefabAsset );
if( prefabStageObjectSource != null )
objectsToSearch[i].obj = prefabStageObjectSource;
List<ObjectToSearch.SubAsset> subAssets = objectsToSearch[i].subAssets;
for( int j = 0; j < subAssets.Count; j++ )
{
obj = subAssets[j].subAsset;
if( obj != null && !obj.Equals( null ) && obj is GameObject && prefabStage.IsPartOfPrefabContents( (GameObject) obj ) )
{
prefabStageObjectSource = ( (GameObject) obj ).FollowSymmetricHierarchy( prefabStage.prefabContentsRoot, prefabAsset );
if( prefabStageObjectSource != null )
subAssets[j].subAsset = prefabStageObjectSource;
}
}
}
}
}
#endif
private bool ReturnToSetupPhase( bool restoreInitialSceneSetup, bool sceneSetupRestorationIsOptional )
{
if( searchResult != null && restoreInitialSceneSetup && !EditorApplication.isPlaying && !searchResult.RestoreInitialSceneSetup( sceneSetupRestorationIsOptional ) )
return false;
searchResult = null;
errorMessage = string.Empty;
currentPhase = Phase.Setup;
return true;
}
}
}