Wayback Machinekoobas.hobune.stream
May JUN Jul
Previous capture 12 Next capture
2021 2022 2023
1 capture
12 Jun 22 - 12 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
0
Question by androgendo · May 12, 2016 at 06:24 AM · editor-scriptingassetrename

Can imported assets be automatically renamed by script?

I'm trying to eliminate one small step in a process I repeat a lot as I update artwork: deleting old assets before I import replacements. Specifically, I'm importing images as sprites in a 2D project and I frequently reimport artwork to see updates in-game.

The idea was to use AssetPostprocessor.OnPostprocessSprites to look for " 1" in the AssetImporter.assetPath of a newly imported sprite. If present, delete the original with AssetDatabase.DeleteAsset and rename the new without " 1" using AssetDatabase.RenameAsset.

The trouble is RenameAsset can't find the asset at assetPath:

 using UnityEngine;
 using UnityEditor;
 
 public class SpriteRenamer : AssetPostprocessor
 {
     void OnPostprocessSprites(Texture2D texture, Sprite[] sprites)
     {
         TextureImporter importer = (TextureImporter)assetImporter;
         
         //returns "Assets/foo.png"
         Debug.Log(importer.assetPath);
         
         //returns "The source asset could not be found"
         Debug.Log(AssetDatabase.RenameAsset(importer.assetPath, "bar.png"));
     }
 }

Hardcoding the path gave the same result...

 Debug.Log(AssetDatabase.RenameAsset("Assets/foo.png", "bar.png"));

...but helped me discover renaming DOES work if I'm not trying to rename the asset currently being imported / postprocessed.

In other words, the first time I import foo.png, renaming fails, but the second time (when the imported file is actually "foo 1.png") the old foo.png is successfully renamed to bar.png.

OnPostprocessSprites claims to "get a notification when an texture of sprite(s) has completed importing" but it seems to me Unity is not actually done with the asset at that point since AssetDatabase can't see it.

Are there any other ideas to accomplish this goal? Is there anything wrong with the script above?


Final code using the accepted answer to automatically overwrite existing sprites with the same name in the same location:

 void OnPostprocessSprites(Texture2D texture, Sprite[] sprites)
 {
     TextureImporter spriteImporter = (TextureImporter)assetImporter;
     
     //end of directory path, start of file name
     int fileNamePos = spriteImporter.assetPath.LastIndexOf("/");
     //end of file name, start of file extension
     int fileExtPos = spriteImporter.assetPath.LastIndexOf(".");
     
     //parent directory with trailing slash
     string filePath = spriteImporter.assetPath.Substring(0, fileNamePos + 1);
     //isolated file name
     string fileName = spriteImporter.assetPath.Substring(fileNamePos + 1, fileExtPos - filePath.Length);
     //extension with "."
     string fileExt = spriteImporter.assetPath.Substring(fileExtPos);
     
     //check if this asset should replace another ("name 1.ext" should replace "name.ext")
     if(spriteImporter.assetPath.EndsWith(" 1" + fileExt))
     {
         //file name without trailing " 1"
         string fileNameOld = spriteImporter.assetPath.Substring(fileNamePos + 1, (fileExtPos - filePath.Length) - 2);
         
         //move old asset to trash so new asset can have the same name
         AssetDatabase.MoveAssetToTrash(filePath + fileNameOld + fileExt);
         
         //non-empty string indicates failure
         if(AssetDatabase.RenameAsset(spriteImporter.assetPath, fileNameOld) != "")
         {
             //ILogger refreshLogger = ???
             //refreshLogger.logEnabled = false;
             
             //calls OnPostprocessSprites (for the 2nd time)
             AssetDatabase.Refresh();  //prints crash message to console
             
             //refreshLogger.logEnabled = true;
         }
         else //successful RenameAsset calls OnPostprocessSprites (for the 3rd time)
         {
             //clear Refresh's crash message and unfortunately the whole console
             //Debug.ClearDeveloperConsole();
         }
     }
     else
     {
         //finally do post-processing here
         Debug.Log("post-processing: "+spriteImporter.assetPath);
     }
 }

There are a couple ways to deal with AssetDatabase.Refresh's crash message, commented out in the code above. One temporarily disables the logger Refresh uses, but it's not Debug.logger so I'm not sure how to get it. The other idea clears the whole console after Refresh which is probably worse, so for now I'm just dealing with a dirty console.

Comment
Add comment · Show 1
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 Ybotic-Software · May 20, 2019 at 11:15 PM 1
Share

@androgendo just an fyi to save you a metric ton of time - use System.Path ins$$anonymous$$d of string functions.

 var fileNameWithoutExtension = System.Path.GetFileNameWithoutExtension(this.assetPath);
 var directoryPath = System.Path.GetDirectoryName(this.assetPath)

and there's many more functions which all work perfectly with Unity (at-least in Editor classes).

1 Reply

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

Answer by Naphier · May 12, 2016 at 07:17 AM

You might need to do AssetDatabase.Refresh or maybe AssetDatabase.ImportAsset (similarly textureImporter.SaveAndReimport).

Comment
Add comment · Show 5 · 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 androgendo · May 12, 2016 at 08:39 AM 0
Share

I appreciate the suggestion - I had not tried those. Unfortunately they didn't help or I'm not using them properly. I tried each just before the RenameAsset() line. For ImportAsset() I used importer.assetPath.

Refresh may have given a clue though. It prints this to the console: "A default asset was created for 'Assets/foo.png' because the asset importer crashed on it last time."

avatar image androgendo · May 14, 2016 at 01:01 AM 0
Share

Along the same lines, I just tried AssetDatabase.SaveAssets, but there was no improvement.

avatar image Naphier · May 14, 2016 at 04:43 AM 0
Share

Just tried it out and I got it to work, but it's not great. One thing to note before I dive in is that you don't actually want to put ".png" on the end. Just put in the new name.

So your script works just fine if the asset is already imported and you reimport. So that's telling me that the asset database hasn't finished all it needs to do. If I put in AssetDatabase.Refresh() it works just fine, but I get a message: A default asset was created for 'Assets/renamed.png' because the asset importer crashed on it last time. You can select the asset and use the 'Assets -> Reimport' menu command to try importing it again, or you can replace the asset and it will auto import again.

Ugly.... but if you can live with that message then this it the way to do it:

     void OnPostprocessSprites(Texture2D texture, Sprite[] sprites)
     {
         Debug.Log("texture: " + texture.name);
         foreach (var item in sprites)
         {
             Debug.Log("sprite: " + item.name);
             
         }
 
         TextureImporter textureImporter = (TextureImporter)assetImporter;
         Debug.Log("assetPath: " + textureImporter.assetPath);
         AssetDatabase.Refresh();
         
         
         string result = AssetDatabase.RenameAsset(textureImporter.assetPath, "renamed2");
         Debug.Log("result: " + result);
     }

Using textureImporter.SaveAndReimport() is apparently a horrible idea here (sorry!) as I think it just creates an infinite loop.

An alternative would be to write a menu script like this:

 using UnityEngine;
 using UnityEditor;
 
 public class RenameSprites : Editor
 {
     [$$anonymous$$enuItem("Tools/$$anonymous$$yTool/$$anonymous$$yEditorScript")]
     static void DoIt()
     {
         string[] sprites = AssetDatabase.FindAssets("t:sprite");
         for (int i = 0; i < sprites.Length; i++)
         {
             AssetDatabase.RenameAsset(AssetDatabase.GUIDToAssetPath(sprites[i]), "sprite" + i);
         }
 
         AssetDatabase.SaveAssets();
     }
 }

I'm not sure why OnPostprocessSprite throws that message when changing the name. It's apparently not the place to rename an imported asset. I'm not sure when a better time would be, but it seems it is interrupting the import process, which seems like it should have finished by the time OnPostprocess gets called...

avatar image androgendo · May 14, 2016 at 06:03 PM 0
Share

I don't know what I did wrong when I tried before, but you're right, AssetDatabase.Refresh does the trick! And good point, I shouldn't include a file extension in the newName of AssetDatabase.RenameAsset.

I'll add the final code to the end of my original question for prettier formatting.

The Refresh message is ugly as you say, but it gets the job done. In the final code above I commented out a couple ideas to deal with that message.

avatar image Naphier androgendo · May 14, 2016 at 07:18 PM 0
Share

Cool. I was hoping you could do Debug.logger.logEnabled = false, but that doesn't seem to work. I usually do asset database work in custom menus, but I understand why you're doing it in post process.

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

5 People are following this question.

avatar image avatar image avatar image avatar image avatar image

Related Questions

Importing .png via script 1 Answer

How to assign variables like Texture2D, TextAsset, Transform, etc. using code? 1 Answer

Editor prompt asset name 2 Answers

Permanently linking import settings presets 0 Answers

[Editor scripting] How to save a script generated mesh as an asset/FBX? 4 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