This tool helps you find usages of the selected asset(s) and/or scene object(s), i.e. lists the objects that refer to them. It is possible to search for references in the Assets folder (Project view) and/or in the scene(s) of your project. You can also search for references while in Play mode!
Yet another update: more information is provided where necessary in the results page; like the referencing variable’s name, material name, shader property name (for textures) etc.
Great asset. does exactly what it says on the tin.
I know it’s extra work, but do you think you will be able to expand it so that it can give you a list of assets that are NOT being used. I’d happily pay a few dollars for that, even if it can;t search a few types.
Here is a script that collects the dependencies of Scenes In Build (ticked) and finds assets that are not in that list. Scripts are excluded from the list as they are not correctly collected by Unity. Also, no special action is taken against Resources or StreamingAssets folders (contents of these folders are always included in build, regardless of whether they are actually used or not).
Also know that there are some paid solutions on Asset Store that use Unity’s build log to generate the list of unused assets. They are probably more accurate than my solution.
But anyways, here is my code snippet (put it in Editor folder):
using UnityEngine;
using UnityEditor;
using System.Collections.Generic;
using System.IO;
public class UnusedAssetDetector : EditorWindow
{
private struct AssetHolder
{
public string name;
public int instanceId;
public AssetHolder( string path, int instanceId )
{
name = Path.GetFileName( path );
this.instanceId = instanceId;
}
}
private const string META_EXTENSION = ".meta";
private List<AssetHolder> unusedAssets = null;
private static GUIStyle m_boxGUIStyle; // GUIStyle used to draw the results of the search
public static GUIStyle boxGUIStyle
{
get
{
if( m_boxGUIStyle == null )
{
m_boxGUIStyle = new GUIStyle( EditorStyles.helpBox );
m_boxGUIStyle.alignment = TextAnchor.MiddleCenter;
m_boxGUIStyle.font = EditorStyles.label.font;
}
return m_boxGUIStyle;
}
}
private Vector2 scrollPosition = Vector2.zero;
[MenuItem( "Util/Unused Asset Detector" )]
static void Init()
{
UnusedAssetDetector window = GetWindow<UnusedAssetDetector>();
window.titleContent = new GUIContent( "Unused Asset Detector" );
window.Show();
}
void OnGUI()
{
if( unusedAssets == null )
{
GUILayout.Box( "Only 'Scenes In Build' in Build Settings are searched for dependencies!", GUILayout.ExpandWidth( true ) );
if( GUILayout.Button( "Find unused assets", GUILayout.Height( 25 ) ) )
{
FindUnusedAssets();
}
}
else
{
GUILayout.BeginVertical();
GUILayout.Box( unusedAssets.Count + " possibly unused asset(s) found", GUILayout.ExpandWidth( true ) );
if( GUILayout.Button( "Search Again", GUILayout.Height( 25 ) ) )
{
FindUnusedAssets();
}
GUILayout.Space( 10 );
scrollPosition = GUILayout.BeginScrollView( scrollPosition );
for( int i = 0; i < unusedAssets.Count; i++ )
{
if( GUILayout.Button( unusedAssets[i].name, boxGUIStyle ) )
{
Selection.activeInstanceID = unusedAssets[i].instanceId;
EditorGUIUtility.PingObject( unusedAssets[i].instanceId );
}
}
GUILayout.EndScrollView();
GUILayout.EndVertical();
}
}
void OnDestroy()
{
unusedAssets = null;
}
void FindUnusedAssets()
{
if( unusedAssets == null )
unusedAssets = new List<AssetHolder>( 128 );
else
unusedAssets.Clear();
// Get all scenes in build settings (ticked)
EditorBuildSettingsScene[] scenesTemp = EditorBuildSettings.scenes;
int targetSceneCount = 0;
for( int i = 0; i < scenesTemp.Length; i++ )
{
if( scenesTemp[i].enabled )
targetSceneCount++;
}
if( targetSceneCount == 0 )
return;
Object[] targetScenes = new Object[targetSceneCount];
for( int i = 0, j = 0; i < scenesTemp.Length; i++ )
{
if( scenesTemp[i].enabled )
targetScenes[j++] = AssetDatabase.LoadAssetAtPath<SceneAsset>( scenesTemp[i].path );
}
Object[] dependencies = EditorUtility.CollectDependencies( targetScenes );
HashSet<string> usedAssets = new HashSet<string>();
for( int i = 0; i < dependencies.Length; i++ )
{
usedAssets.Add( AssetDatabase.AssetPathToGUID( AssetDatabase.GetAssetPath( dependencies[i] ) ) );
}
for( int i = 0; i < targetSceneCount; i++ )
{
usedAssets.Add( AssetDatabase.AssetPathToGUID( AssetDatabase.GetAssetPath( targetScenes[i] ) ) );
}
string projectDir = Directory.GetParent( Application.dataPath ).FullName;
if( projectDir[projectDir.Length - 1] != '/' && projectDir[projectDir.Length - 1] != '\\' )
projectDir += '/';
int substrIndex = projectDir.Length;
string[] files = Directory.GetFiles( Application.dataPath, "*", SearchOption.AllDirectories );
for( int i = 0; i < files.Length; i++ )
{
if( !files[i].EndsWith( META_EXTENSION ) )
{
string relativePath = files[i].Substring( substrIndex );
if( !usedAssets.Contains( AssetDatabase.AssetPathToGUID( relativePath ) ) )
TryAddUnusedAsset( relativePath );
}
}
}
void TryAddUnusedAsset( string path )
{
Object asset = AssetDatabase.LoadAssetAtPath<Object>( path );
if( asset == null )
return;
if( !IsTypeDerivedFrom( asset.GetType(), typeof( MonoScript ) ) )
{
int instanceId = asset.GetInstanceID();
unusedAssets.Add( new AssetHolder( path, instanceId ) );
}
}
// Check if "child" is a subclass of "parent" (or if their types match)
bool IsTypeDerivedFrom( System.Type child, System.Type parent )
{
if( child.IsSubclassOf( parent ) || child == parent )
return true;
return false;
}
}
You can access it from the menu bar: “Util-Unused Asset Detector”.
Hey, thanks for this tool.
I found a problem with it though… it wasn’t finding a reference to a texture I was using on a SpriteRenderer component. https://screencast.com/t/YYmPuDDs
For whatever reason, the same texture on an Image component is found.
You need to include public properties in your search as “Sprite” is a property of “Sprite Renderer”. I’ve now tested it with default settings + public properties selected on a Sprite Renderer and it worked for me. Let me know if the problem persists.
PS, also make sure that “Include sub-assets in search” is selected.