no rename?

5395308--547320--upload_2020-1-21_16-35-47.png
I'm using this to create quick clip, for example i'm using this as a run cycle

1 Like

Unity doesn't permit renaming of SubAssets.

But, if you go to the animation track, then 'Convert To Clip track', select the clip, you can then rename the associated clip in the inspector. Not ideal - but it is a workaround for exactly this limitation.

1 Like

it works but doesn't update the project name immediately, after a few updates i seems

why doesn't unity permit sub asset renaming?

I don't think there is a technical reason for it, I think it's legacy behaviour that likely needs updating. If I'm not mistaken, the main use case for sub-assets were fbx files, where the names were fixed.

It is possible to do it via script (like the inspector does), and I think there are some user-tools out there to do it.

1 Like

Cheers it's fine the way it is, just a habit to get
The name not updating until reload looks like a glitch though, maybe not your team's job

To tack on here - that behavior to allow for renaming would be incredibly convenient for organizational reasons. We have created a system for sub-asset scriptable objects as data. This allows for several conveniences in keeping track of which assets are related. Using a seemingly random editor window or custom tooling is far less intuitive of a workflow for the non-engineers who use the system than simply renaming the asset is.

If there really is no technical reason for it, would it be possible for that option to be made available?

It seems to be a requested editor feature (https://answers.unity.com/questions/1348379/renaming-child-assets-in-project.html), but I haven't found it on a road map anywhere (which doesn't mean it isn't).

The post above works around it using the inspector, which works if you have custom types. The following example code - which is condensed for brevity - is a bit closer to what we use in the animation playable asset inspector to change the recorded clip name.

serializedObject.Update();
var nameProperty = serializedObject.FindProperty("m_Name");
EditorGUI.BeginChangeCheck();
EditorGUILayout.DelayedTextField(nameProperty);
if (EditorGUI.EndChangeCheck())
{
    serializedObject.ApplyModifiedProperties();
    AssetDatabase.SaveAssets();
}

This is mostly fine as a workaround, but the issue as stated above is that the asset won't update immediately. You have to manually go and reimport the asset. Writing in an AssetImport call after SaveAssets doesn't really work either, as it will update the asset but only to the previous (and incorrect) value.

There is a bit of confusion on the developer end as they're forced to trigger the reimport to see the change.

1 Like


Yep. Unity does not refresh asset names in project view using the above.
Bug report coming

Here's my workaround to get it to refresh the name: remove the subasset, save assets, re-add the subasset, save assets. Nuclear, but seems to work!

EditorGUI.BeginChangeCheck();

var newName = EditorGUILayout.DelayedTextField(subAsset.name);

if (EditorGUI.EndChangeCheck())
{
    subAsset.name = newName;
    EditorUtility.SetDirty(subAsset);

    if (AssetDatabase.IsSubAsset(subAsset))
    {
        var path = AssetDatabase.GetAssetPath(subAsset);
        var mainAsset = AssetDatabase.LoadMainAssetAtPath(path);

        if (mainAsset != null)
        {
            // This works, but it doesn't refresh the project window name instantly:
            // https://discussions.unity.com/t/773377
            //EditorUtility.SetDirty(mainAsset);
            //AssetDatabase.SaveAssetIfDirty(mainAsset);
            //AssetDatabase.ImportAsset(path);
            //AssetDatabase.Refresh();

            // This is more nuclear but does work:
            AssetDatabase.RemoveObjectFromAsset(subAsset);
            EditorUtility.SetDirty(mainAsset);
            AssetDatabase.SaveAssetIfDirty(mainAsset);
            AssetDatabase.AddObjectToAsset(subAsset, mainAsset);
            EditorUtility.SetDirty(mainAsset);
            AssetDatabase.SaveAssetIfDirty(mainAsset);
        }
    }
}

Here it is as a standalone utility method that supports renaming both main assets and sub assets:

public static void RenameAsset(UnityEngine.Object asset, string newName)
{
    // Check that asset is not null first using your prefered validation method

    var assetPath = AssetDatabase.GetAssetPath(asset);

    if (AssetDatabase.IsMainAsset(asset))
    {
        AssetDatabase.RenameAsset(assetPath, newName);
    }
    else if (AssetDatabase.IsSubAsset(asset))
    {
        asset.name = newName;
        EditorUtility.SetDirty(asset);
        var mainAsset = AssetDatabase.LoadMainAssetAtPath(assetPath);

        AssetDatabase.RemoveObjectFromAsset(asset);
        EditorUtility.SetDirty(mainAsset);
        AssetDatabase.SaveAssetIfDirty(mainAsset);
        AssetDatabase.AddObjectToAsset(asset, mainAsset);
        EditorUtility.SetDirty(mainAsset);
        AssetDatabase.SaveAssetIfDirty(mainAsset);
    }
    else
    {
        throw new Exception("Object is not an asset.");
    }
}
1 Like

Update: My solution above has a massive issue: by removing and re-adding the sub-asset to the main asset, the fileID for the sub-asset changes in the serialized YAML. The references will appear to be preserved until an assembly reload, but break when the reload occurs.

I dug deeper and figured that the issue was that ProjectBrowser.ResetViews was not getting called after a sub-asset rename, which is because, I think, EditorApplication.projectChanged does not get called on a sub-asset rename.

The better solution thus is to manually refresh the project window using reflection, like so:

public static void RenameAsset(UnityObject asset, string newName)
{
    EnsureArg.IsNotNull(asset);

    if (!AssetDatabase.Contains(asset))
    {
        throw new InvalidOperationException("Object is not an asset.");
    }

    var assetPath = AssetDatabase.GetAssetPath(asset);

    if (AssetDatabase.IsMainAsset(asset))
    {
        AssetDatabase.RenameAsset(assetPath, newName);
    }
    else if (AssetDatabase.IsSubAsset(asset))
    {
        asset.name = newName;
        EditorUtility.SetDirty(asset);

        var mainAsset = AssetDatabase.LoadMainAssetAtPath(assetPath);
        EditorUtility.SetDirty(mainAsset);
        AssetDatabase.SaveAssetIfDirty(mainAsset);

        var projectBrowserType = typeof(Editor).Assembly.GetType("UnityEditor.ProjectBrowser");
        var resetViewsMethod = projectBrowserType.GetMethod("ResetViews", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);

        foreach (var window in Resources.FindObjectsOfTypeAll(projectBrowserType))
        {
            resetViewsMethod.Invoke(window, new object[0]);
        }
    }
}
3 Likes

Thanks @LazloBonin ! I was trying to make a property drawer do this and couldn't figure out why changing property.serializedObject.targetObject.name wasn't working, even though I was setting it as dirty. I was missing the step of setting the parent object as dirty too. This works! I don't think @seant_unity is around anymore, but I also appreciate the DelayedTextField. I didn't know that existed.