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*.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:
    - Editor script to slice sprites - Questions & Answers - Unity Discussions
    - http://answers.unity3d.com/questions/753664/

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).

3 Answers

3

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 =)

Wow, great, especially those regex... ;)

Is it [\\d]{8}: or [\d]{8}:

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 Mulligan window and you should be able to rename everything at once.

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)

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*;*

names = EditorGUILayout.TextField(s.name, names*);*
* }*

* if (GUILayout.Button(“Rename”))*
* {*
SpriteMetaData[] sprites = selectedTextureImporter.spritesheet;
* for (int i = 0; i < selectedTextureImporter.spritesheet.Length; i++)*
* {*
sprites_.name = names*;
}
selectedTextureImporter.spritesheet = sprites;
EditorUtility.SetDirty(selectedTextureImporter);
selectedTextureImporter.SaveAndReimport();*_

* // Reimport/refresh asset.*
* AssetDatabase.ImportAsset(AssetDatabase.GetAssetPath(selectedTextureImporter), ImportAssetOptions.ForceUpdate);*
* Close();*
* }*
* }*
}