- Home /
How to Rename Sprite Slices in Script Without Breaking References
I've been trying to write a quick script to rename sprite slices without breaking references to the sprites in sprite renderers or animations. I thought it would be simple since you can do this manually through the Sprite Editor without any issues, but I have run into a difficult snag.
The script I currently have seems to work fine, except that my references break ("Missing Sprite").
I've tried using different methods for importing the asset, as I find that pretty unclear from the Unity documentation. I've used both AssetImporter.SaveAndReimport (), and AssetDatabase.ReimportAsset (path, ImportAssetOptions.ForceUpdate), (both seeming to require calling EditorUtility.SetDirty() on my import settings), but both have the same results.
In examining the meta files before and after my script, I see the renamed file has a few references to the old files in the "fileIDToRecycleName" section, and I'm wondering if that might be the issue. For example:
Original file:
fileIDToRecycleName:
21300000: UI_Buttons_0
21300002: UI_Buttons_1
21300004: UI_Buttons_2
21300006: UI_Buttons_3
Renamed File:
fileIDToRecycleName:
21300000: UI_Buttons_0
21300002: UI_Buttons_1
21300004: UI_Buttons_2
21300006: UI_Buttons_3
21300008: RenamedSprite_0
21300010: RenamedSprite_1
21300012: RenamedSprite_2
21300014: RenamedSprite_3
If I rename the slices manually they will keep the original fileID.
Has anyone solved this issue? Can anyone tell me how to rewrite Texture Import Settings on slices without regenerating their meta data?
Code:
using UnityEngine;
using UnityEditor;
public class SpritesheetRename : MonoBehaviour
{
[MenuItem ("Assets/Rename Spritesheet")]
public static void RenameSpritesheet ()
{
RenameSelectedTexture ();
}
static void RenameSelectedTexture ()
{
// Validation
var selectedObject = Selection.activeObject;
if (!AssetDatabase.Contains (selectedObject)) {
Debug.LogError ("Selected object not found in Asset Database.");
return;
}
string path = AssetDatabase.GetAssetPath (selectedObject);
var importer = AssetImporter.GetAtPath (path) as TextureImporter;
if (importer == null) {
Debug.LogError ("Selected object not found in Asset Database.");
return;
}
// Rename the slices
SpriteMetaData[] spritesheet = importer.spritesheet;
bool textureHasSpritesheet = spritesheet != null && spritesheet.Length > 0;
if (textureHasSpritesheet)
{
for (int i = 0; i < spritesheet.Length; i++) {
spritesheet[i].name = "RenamedSprite_" + i;
}
importer.spritesheet = spritesheet;
// Reimport the asset
EditorUtility.SetDirty (importer); // Flag dirty for SaveAndReimport to find it
importer.SaveAndReimport ();
// Don't need to do this since settings were already reimported via SaveAndReimport
//AssetDatabase.ImportAsset (path, ImportAssetOptions.ForceUpdate);
}
// TODO: Rename the asset as well once slice renaming is working
//AssetDatabase.RenameAsset (path, "Renamed.png");
//AssetDatabase.Refresh ();
}
[MenuItem ("Assets/Rename Spritesheet", true)]
public static bool IsValidTargetForPalette ()
{
if (Selection.activeObject == null) {
return false;
}
if (Selection.objects.Length > 1) {
return false;
}
return Selection.activeObject.GetType () == typeof(Texture2D);
}
}
I've based my script off of similar questions I've found here:
I've been looking a bit more into this and it seems SpriteRenderer must use the sprite's name as part of its reference. Still need to dig into this some.
There's a "RenameAsset" method in the AssetDatabase class, have you tried it? I've never used it, but it looks like the proper way to rename an asset.
Thanks Diego - I have tried it. I couldn't get it to do what I want since it only takes an Asset path but all sprites share the same path (which is that of their Texture asset).
Have you managed to solve your problem? I actually encountered the same one.
No, unfortunately not. I've been digging some more and definitely think the fileIDToRecycleName is basically like a GUID for the sprite, and the issue is related to the extra IDs ins$$anonymous$$d of rena$$anonymous$$g the existing names. The extra IDs are probably added when I assign the new spritesheet to the importer on line 36. It probably compares the new sprite names against the RecycleNames and if it doesn't find it it creates a new ID. I'm thinking it's basically a Unity bug since there's no way to force it to also rename the RecycleName.
A workaround (that might have issues - I have no idea) is to edit the .meta file manually (assu$$anonymous$$g you have it forced to text). You can replace each sprite name with whatever you want, and it seems to keep references in the editor in tact. Just be sure to edit both the fileIDToRecycleName (if there is any) and the Sprite$$anonymous$$etaData.
Answer by edwardrowe · Nov 20, 2015 at 04:56 PM
I created a workaround script for this, after discussions with @artwen
This script renames the texture and its auto-sliced sprites while maintaining references by modifying the .meta data file. Use it at your own risk =)
Yeah I love regex. Should need the \\d to escape the "\". Using "[\d]" won't compile (unrecognized escape character)
Answer by JohnGamingStudio · Jul 22, 2019 at 02:18 AM
Hello @edwardrowe , I have been going through both scripts you made. It seems this script would sort of be what I am looking for (I am looking for a script that has a tab on the main menu, that uses a list format such as spriteslice1=renamed1, spriteslice2=renamed2 etc.) Your second working script uses prefixes, and seems to only change the spritesheet name itself. I am going to try to blend together a bunch of scripts until I have what I am looking for, but I am quite new to C# and wondering if you have any insight on the topic.
Thanks,
I've expanded on this script greatly since this answer - made a rename tool that does what you want, I think: https://github.com/redbluegames/unity-mulligan-renamer
Install that Custom Package through Releases. Drag and drop your sprites into the $$anonymous$$ulligan window and you should be able to rename everything at once.
A singular find and replace wouldn't due exactly what I needed. I am replacing the current unity generated names with their original directional and action names such as attacke0001. I couldn't have a simple replace all "Sprite" with attack, because they are all doing different things and different directions. What I am looking for is to be able to set 500+ unity generated names into the original names as they are both I the same order. (Sprite1 replace to attacke0001, Sprite to attacke002 etc. ) For example, in python I made a multi variable find and replace script using csv (row1 is matched left column is find, right column is replace) and was able to stack up all of them. I tried to replace the file back into unity, but broke all the references and such.
I'll check it out, i want to double check with you first, is their a way to mass rename the sprites to each a unique name that it originally came with? What I find is autogenerated or prefix changing name changers, I just want to switch each one back to their original pre spritescriptname. (Ie a multi value find and replace tool that changes the name)
I'm not 100% sure I'm understanding the question but you can do a find a replace using this tool.
Ex: SpritesheetXYZ with sprites $$anonymous$$ySprite1, $$anonymous$$ySprite2, $$anonymous$$ySprite3
You can replace "$$anonymous$$ySprite" with "Hero" and "SpritesheetXYZ" with "HeroSheet", so you'd have:
HeroSheet with sprites Hero1, Hero2, Hero3
Answer by K0ST4S · Aug 23, 2020 at 03:16 PM
using UnityEngine;
using UnityEditor;
public class RenameSpritesheet : EditorWindow
{
static string[] names = new string[20];
static TextureImporter selectedTextureImporter
{
get
{
var selectedObject = Selection.activeObject;
if (!AssetDatabase.Contains(selectedObject))
{
Debug.LogError("Selected object not found in Asset Database.");
return null;
}
return (TextureImporter)AssetImporter.GetAtPath(AssetDatabase.GetAssetPath(selectedObject));
}
}
[MenuItem("Assets/Rename Spritesheet")]
public static void ShowRenameSpritesheetWindow()
{
EditorWindow.GetWindow<RenameSpritesheet>(true, "Rename Texture", true);
}
[MenuItem("Assets/Rename Spritesheet", true)]
public static bool IsSelectionSprite()
{
if (Selection.activeObject == null)
{
return false;
}
if (Selection.objects.Length > 1)
{
return false;
}
return Selection.activeObject.GetType() == typeof(Texture2D);
}
void OnGUI()
{
EditorGUILayout.HelpBox("This SpritesheetRename tool is used to rename a texture that's been autosliced. It replaces " +
"all instances of the old prefix with a new one, and renames the Texture to match.", MessageType.None);
for (int i = 0; i < selectedTextureImporter.spritesheet.Length; i++)
{
SpriteMetaData s = selectedTextureImporter.spritesheet[i];
names[i] = EditorGUILayout.TextField(s.name, names[i]);
}
if (GUILayout.Button("Rename"))
{
SpriteMetaData[] sprites = selectedTextureImporter.spritesheet;
for (int i = 0; i < selectedTextureImporter.spritesheet.Length; i++)
{
sprites[i].name = names[i];
}
selectedTextureImporter.spritesheet = sprites;
EditorUtility.SetDirty(selectedTextureImporter);
selectedTextureImporter.SaveAndReimport();
// Reimport/refresh asset.
AssetDatabase.ImportAsset(AssetDatabase.GetAssetPath(selectedTextureImporter), ImportAssetOptions.ForceUpdate);
Close();
}
}
}
Your answer
Follow this Question
Related Questions
Editor script to slice sprites 4 Answers
Editor class "Texture Importer" question (applying settings to multiple texture assets). 2 Answers
Texture mipmap distance 1 Answer
How does sprite extrude edges work? 1 Answer
Sprite resized to whole screen 3 Answers