Wayback Machinekoobas.hobune.stream
May JUN Jul
Previous capture 13 Next capture
2021 2022 2023
1 capture
13 Jun 22 - 13 Jun 22
sparklines
Close Help
  • Products
  • Solutions
  • Made with Unity
  • Learning
  • Support & Services
  • Community
  • Asset Store
  • Get Unity

UNITY ACCOUNT

You need a Unity Account to shop in the Online and Asset Stores, participate in the Unity Community and manage your license portfolio. Login Create account
  • Blog
  • Forums
  • Answers
  • Evangelists
  • User Groups
  • Beta Program
  • Advisory Panel

Navigation

  • Home
  • Products
  • Solutions
  • Made with Unity
  • Learning
  • Support & Services
  • Community
    • Blog
    • Forums
    • Answers
    • Evangelists
    • User Groups
    • Beta Program
    • Advisory Panel

Unity account

You need a Unity Account to shop in the Online and Asset Stores, participate in the Unity Community and manage your license portfolio. Login Create account

Language

  • Chinese
  • Spanish
  • Japanese
  • Korean
  • Portuguese
  • Ask a question
  • Spaces
    • Default
    • Help Room
    • META
    • Moderators
    • Topics
    • Questions
    • Users
    • Badges
  • Home /
avatar image
2
Question by graslany · Nov 26, 2014 at 07:48 AM · editorassetdatabasefolderonpostprocessallassets

How to move an asset to a newly created directory in the AssetDatabase ?

Hello community

I'm developing an asset postprocessor script that monitors the creation of text files containing dialog lines. When such a text file is created in (or moved to) specific places in the project hirerarchy a companion dialog asset is also created (using the AssetPostprocessor::OnPostprocessAllAssets callback). This companion asset is created in a subfolder and contains a parsed and structured version of the text file's contents.

When the source text file is deleted or moved, its companion asset must be moved in another folder (either to a subfolder of the text file's new location or a special orphans fodler). When the destination folder does not exist I create it before moving the asset.

My problem is that when I create a new asset, I can create the folder (using AssetDatabase::CreateFolder) and then create the asset (ScriptableObject::Instantiate + AssetDatabase::CreateAsset) and everything works fine. But when I try to move an existing asset to a new folder (AssetDatabase::CreateFolder + AssetDatabase::MoveAsset), the file moving fails ! The returned error message is as follows : Parent directory is not in asset database - So my question is : how can I move an existing asset to a newly created folder ?

I found one old page from last year related to this issue, but it was never marked as solved. Nevertheless I tried to apply the proposed solution using EditorApplication.delayedCall (which seems to have been replaced with EditorApplication.update since then) and put my asset moving operations there (while the folder creations stayed in OnPostprocessAllAssets to be performed before). The asset moving operation still fails, although this time no error message is returned.

Here is the code I'm using to do that (things that are relevant to my project only were stripped for clarity) :

 static private void OnPostprocessAllAssets (
         string[] importedAssets,
         string[] deletedAssets,
         string[] movedAssets,
         string[] movedFromAssetPaths)
     { 
     // The processing of created and deleted asset is stripped in this snippet.
   
     // This is the stripped version of the asset moving code.
         for (int i=0; i<movedAssets.Length; i++) {
             string newTextfilePath = movedAssets[i];
             string oldTextfilePath = movedFromAssetPaths[i];
             if (SomeConditionOnPaths()) {
         // TextfilePathToDialogPath computes a subfolder name where the dialog asset to move must go.
                 string newDialogPath = TextfilePathToDialogPath(newTextfilePath, false);
                 Util.CreateDirectories(newDialogPath, false);
                 string res = AssetDatabase.ValidateMoveAsset(oldAssetPath, newDialogPath);
 
                 if (res.IsNullOrEmpty()) {
                             AssetDatabase.MoveAsset(oldAssetPath, newDialogPath);
                 } else {
                             GDebug.LogError(string.Format("Unable to move a dialog asset between directories from '{0}' to '{1}': {2}.", oldAssetPath, newDialogPath, res));
                 }
       }
     }
     }
 
   // The rest of the class is stripped
   
 }


Comment
Add comment
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users

3 Replies

· Add your reply
  • Sort: 
avatar image
1
Best Answer

Answer by graslany · Nov 27, 2014 at 09:58 AM

I'll be answering my own question here, but after sleeping a bit on the problem a solution came to my mind today. The problem is apparently that when I create a new folder using AssetDatabase::CreateFolder, the folder is not available right away in the database. Instead it's queued for a later import.

So what I do now is to try moving my asset as I did before, but if it fails, I put the move operation on hold for a while, by storing the source and destination paths in a list somewhere. Then in my OnPostProcessAllAssets callback, on monitor not only the assets I'm actually interested in processing, but also the folders that I created in previous calls. When the folder I created before is actually imported and gets through OnPostprocessAllAssets, I finally perform the pending moves which involve it. Here's how it looks :

 static private List<KeyValuePair<string, string>> delayedMoves = new List<KeyValuePair<string, string>>();
 
 static private void OnPostprocessAllAssets (
     string[] importedAssets,
     string[] deletedAssets,
     string[] movedAssets,
     string[] movedFromAssetPaths)
 {
     // The processing of deleted asset is stripped in this snippet.
 
     foreach (string newPath in importedAssets) {
         // The part related to delayed move operations
         if (delayedMoves.Count > 0) {
             MaybePerformDelayedMoves(newPath);
         }
         // The part related to what I really want to do to assets
         if (IsValidTextfilePath(newPath)) {
             newOrUpdatedTextfiles.Add(newPath);
         }
     }
 
     // This is the stripped version of the asset moving code.
     for (int i=0; i<movedAssets.Length; i++) {
         string newTextfilePath = movedAssets[i];
         string oldTextfilePath = movedFromAssetPaths[i];
         if (SomeConditionOnPaths()) {
             // TextfilePathToDialogPath computes a subfolder name where the dialog asset to move must go.
             string newDialogPath = TextfilePathToDialogPath(newTextfilePath, false);
             Util.CreateDirectories(newDialogPath, false);
             // Nicely ask the database for permission to perform the move right away
             string res = AssetDatabase.ValidateMoveAsset(oldAssetPath, newDialogPath);
             
             if (res.IsNullOrEmpty()) {
                 // It's okay, we can move right away
                 AssetDatabase.MoveAsset(oldAssetPath, newDialogPath);
             } else {
                 // A move fail may be a temporary error, if the destination directory
                 // was just created and is not imported yet. Try later.
                 MoveAssetLater(oldAssetPath, newDialogPath);
             }
         }
     }
 }
 
 static private void MoveAssetLater(string from, string to) {
     delayedMoves.Add(new KeyValuePair<string, string>(from, to));
 }
 
 static private void MaybePerformDelayedMoves(string newAssetName) {
     int nMoves = delayedMoves.Count;
     
     // The list is parsed in reverse order to remove elements easily.
     for (int i = nMoves-1; i>=0; i--) {
         KeyValuePair<string, string> dm = delayedMoves[i];
         string destinationAssetPath = dm.Value;
         string destinationFolder = Util.DirectoryFromPath(destinationAssetPath);
         if(destinationFolder == newAssetName) {
             // Perform move operation and delete origin directory if it is empty.
             string originAssetPath = dm.Key;
             string res = AssetDatabase.ValidateMoveAsset(originAssetPath, destinationAssetPath);
             if (res.IsNullOrEmpty()) {
                 string originFolder = Util.DirectoryFromPath(originAssetPath);
                 AssetDatabase.MoveAsset(originAssetPath, destinationAssetPath);
             } else {
                 GDebug.LogError(string.Format("Unable to move {0} to {1} even after waiting for the destination folder to be imported.", originAssetPath, destinationAssetPath));
             }
             delayedMoves.RemoveAt(i);
         }
     }
 }
 
 // The rest of the class is stripped
 }
Comment
Add comment · Share
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image
0

Answer by mmvlad · Nov 16, 2016 at 04:46 PM

Had the same problem. I believe found a more simple solution - just create the directory in OnPreprocess call. It will be ready for use in OnPostprocessAllAssets* .

Comment
Add comment · Share
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image
0

Answer by dCalle · Sep 14, 2020 at 07:54 PM

Six years later and it's still the same problem...

Comment
Add comment · Share
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users

Your answer

Hint: You can notify a user about this post by typing @username

Up to 2 attachments (including images) can be used with a maximum of 524.3 kB each and 1.0 MB total.

Follow this Question

Answers Answers and Comments

28 People are following this question.

avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image

Related Questions

How do I print out which folder in the projects tab is currently selected ? 1 Answer

Using Hidden folders for editor stuff? 1 Answer

Seperating editor and runtime data with ScriptableObjects 1 Answer

Is there a way to create a folder hierarchy view in the editor? 1 Answer

Detecting Asset Types 3 Answers


Enterprise
Social Q&A

Social
Subscribe on YouTube social-youtube Follow on LinkedIn social-linkedin Follow on Twitter social-twitter Follow on Facebook social-facebook Follow on Instagram social-instagram

Footer

  • Purchase
    • Products
    • Subscription
    • Asset Store
    • Unity Gear
    • Resellers
  • Education
    • Students
    • Educators
    • Certification
    • Learn
    • Center of Excellence
  • Download
    • Unity
    • Beta Program
  • Unity Labs
    • Labs
    • Publications
  • Resources
    • Learn platform
    • Community
    • Documentation
    • Unity QA
    • FAQ
    • Services Status
    • Connect
  • About Unity
    • About Us
    • Blog
    • Events
    • Careers
    • Contact
    • Press
    • Partners
    • Affiliates
    • Security
Copyright © 2020 Unity Technologies
  • Legal
  • Privacy Policy
  • Cookies
  • Do Not Sell My Personal Information
  • Cookies Settings
"Unity", Unity logos, and other Unity trademarks are trademarks or registered trademarks of Unity Technologies or its affiliates in the U.S. and elsewhere (more info here). Other names or brands are trademarks of their respective owners.
  • Anonymous
  • Sign in
  • Create
  • Ask a question
  • Spaces
  • Default
  • Help Room
  • META
  • Moderators
  • Explore
  • Topics
  • Questions
  • Users
  • Badges