how to get currently selected folder for putting new Asset into?

When you create an asset in the Project tab, the default/built-in assets are created inside whatever folder is selected or was last selected in the Project tab. It’s probably there but I’m not finding how to replicate this in the documentation. In other words, right now I have

AssetDatabase.CreateAsset(asset, 
AssetDatabase.GenerateUniqueAssetPath("Assets/New MyAsset.asset"));

Is there any way to do something like

AssetDatabase.CreateAsset(asset, 
AssetDatabase.GenerateUniqueAssetPath(SomeElusiveClass.TheCurrentlySelectedAssetFolderPath + "New Myasset.asset"));

?

bump?

Is this what your looking for?

EditorUtility.GetAssetPath(Selection.activeObject)

2 Likes

thanks for the heads up. it takes a little more work to get the behavior right for all cases, the following code seems to be working great:

string path = AssetDatabase.GetAssetPath (Selection.activeObject);
if (path == "")
{
	path = "Assets";
}
else if (Path.GetExtension(path) != "")
{
	path = path.Replace(Path.GetFileName (AssetDatabase.GetAssetPath (Selection.activeObject)), "");
}
AssetDatabase.CreateAsset (asset, AssetDatabase.GenerateUniqueAssetPath (path + "/New MyAsset.asset"));

you’ll also have to include the System.IO namespace.

2 Likes

great I needed it and it worked smoothly

This will do the same thing, but is a little simpler and doesn’t rely on files having extensions and directories not having them:

        string path = "Assets";
        foreach (UnityEngine.Object obj in Selection.GetFiltered(typeof(UnityEngine.Object), SelectionMode.Assets))
        {
            path = AssetDatabase.GetAssetPath(obj);
            if (File.Exists(path))
            {
                path = Path.GetDirectoryName(path);
            }
            break;
        }
7 Likes

I found the following implementation to work quite good as well. https://gist.github.com/JvetS/5208916
I had some issues with the proposed solution, but I didn’t bother to debug further and came up with this solution.

Might break somewhere down the road though due to it being private.

1 Like

Thanks for posting that JvetS, it’s really useful.

Path.GetDirectoryName() in yoyo’s reply doesn’t seem to work because it normalizes the path (“Assets/” → “assets/”, which may be fine for the Windows, but I guess Unity is case sensitive).

A small comment for those who are reading this thread.
Yoyo’s solution was the best for me.
While other solutions are not selecting folder or are complicated, the Selection.GetFiltered(typeof(UnityEngine.Object), SelectionMode.Assets) select both folders or objects and is simple to use.

AFAIK, using AssetDatabase.GetAssetPath with Selection never returns a folder, instead of that always returns the last asset file you have clicked on (the one being shown in the inspector).
Here is my try, in case you needed full path (but it would be easy to modify it to return a relative path):

private static string GetClickedDirFullPath()
{
    string clickedAssetGuid = Selection.assetGUIDs[0];
    string clickedPath          = AssetDatabase.GUIDToAssetPath(clickedAssetGuid);
    string clickedPathFull     = Path.Combine(Directory.GetCurrentDirectory(), clickedPath);

    FileAttributes attr = File.GetAttributes(clickedPathFull);
    return attr.HasFlag(FileAttributes.Directory) ? clickedPathFull : Path.GetDirectoryName(clickedPathFull);
}
2 Likes

If you want to create an asset just like it is done in the Project window, then ProjectWindowUtil.CreateAsset() is the right way to do it. It will start the asset creation and prompt the user to input an asset name. A default asset name is passed as an argument and shows up as a suggestion to the user.

If you don’t want the user to be able to rename the asset, it can only be done through Reflection. The methods described above use Selection in different ways, but if the currently open folder is empty, none of them will work because no asset will be selected in the Project window.

MethodInfo getActiveFolderPath = typeof(ProjectWindowUtil).GetMethod(
    "GetActiveFolderPath",
    BindingFlags.Static | BindingFlags.NonPublic);

string folderPath = (string) getActiveFolderPath.Invoke(null, null);
7 Likes

And this is why no-one should post off-site links in forums :(. (it’s 404, deleted, gone, vanished).

(which reminds me of this XKCD:

2 Likes

[Off-topic, sorry]

I like to create a GitHub gist for a snippet if it is bigger than a couple of lines. The issue here is not posting a third-party link but the fact that the user decided to remove a gist that they posted on a forum (this is evil, never do this). When a snippet is posted on the forum, there are multiple replies like “I fixed this”, “I made it work in the new Unity version”, etc., and each user posts a copy of the snippet with only one or two different lines. On the other hand, a gist can be updated, and you will always find the latest version at the link without scrolling through a long thread of snippets.

For Unity forums, the multiple replies with small changes actually works great, better than a gist. Most of the time it’s more useful to see all the different versions, and respond to different individual people about what THEY changed and why.

For other platforms/languages/types of problem a gist can work better, but in Unity usually everyone’s doing slghtly different things. AND Uinty keeps breaking stuff between versions - so you often NEED to see the old version, not the new version (which is possible with a gist, but a lot more effport than simply seeing it directly in the thread).

It seems that AssetDatabase.GetAssetPath provides a path when selecting a folder in right view of the Project panel, but not from the hierarchical list on the left.

I guess I need to look into the ProjectWindowUtil

Here’s mine. Doesn’t use reflection, just available public API.
Ironically, that function is just a few lines below the one that other person grabbed with reflection.

var asset = ScriptableObject.CreateInstance<MyAssetType>();

const string fileName = "Unnamed Asset.asset";
ProjectWindowUtil.CreateAsset(asset, fileName);