-
-
Save ZimM-LostPolygon/7e2f8a3e5a1be183ac19 to your computer and use it in GitHub Desktop.
| // Drop into Assets/Editor, use "Tools/Regenerate asset GUIDs" | |
| using System; | |
| using System.Collections.Generic; | |
| using System.Diagnostics; | |
| using System.IO; | |
| using UnityEditor; | |
| namespace UnityGuidRegenerator { | |
| public class UnityGuidRegeneratorMenu { | |
| [MenuItem("Tools/Regenerate asset GUIDs")] | |
| public static void RegenerateGuids() { | |
| if (EditorUtility.DisplayDialog("GUIDs regeneration", | |
| "You are going to start the process of GUID regeneration. This may have unexpected results. \n\nMAKE A PROJECT BACKUP BEFORE PROCEEDING!", | |
| "Regenerate GUIDs", "Cancel")) { | |
| try { | |
| AssetDatabase.StartAssetEditing(); | |
| string path = Path.GetFullPath(".") + Path.DirectorySeparatorChar + "Assets"; | |
| UnityGuidRegenerator regenerator = new UnityGuidRegenerator(path); | |
| regenerator.RegenerateGuids(); | |
| } | |
| finally { | |
| AssetDatabase.StopAssetEditing(); | |
| EditorUtility.ClearProgressBar(); | |
| AssetDatabase.Refresh(); | |
| } | |
| } | |
| } | |
| } | |
| internal class UnityGuidRegenerator { | |
| private static readonly string[] kDefaultFileExtensions = { | |
| "*.meta", | |
| "*.mat", | |
| "*.anim", | |
| "*.prefab", | |
| "*.unity", | |
| "*.asset", | |
| "*.guiskin", | |
| "*.fontsettings", | |
| "*.controller", | |
| }; | |
| private readonly string _assetsPath; | |
| public UnityGuidRegenerator(string assetsPath) { | |
| _assetsPath = assetsPath; | |
| } | |
| public void RegenerateGuids(string[] regeneratedExtensions = null) { | |
| if (regeneratedExtensions == null) { | |
| regeneratedExtensions = kDefaultFileExtensions; | |
| } | |
| // Get list of working files | |
| List<string> filesPaths = new List<string>(); | |
| foreach (string extension in regeneratedExtensions) { | |
| filesPaths.AddRange( | |
| Directory.GetFiles(_assetsPath, extension, SearchOption.AllDirectories) | |
| ); | |
| } | |
| // Create dictionary to hold old-to-new GUID map | |
| Dictionary<string, string> guidOldToNewMap = new Dictionary<string, string>(); | |
| Dictionary<string, List<string>> guidsInFileMap = new Dictionary<string, List<string>>(); | |
| // We must only replace GUIDs for Resources present in Assets. | |
| // Otherwise built-in resources (shader, meshes etc) get overwritten. | |
| HashSet<string> ownGuids = new HashSet<string>(); | |
| // Traverse all files, remember which GUIDs are in which files and generate new GUIDs | |
| int counter = 0; | |
| foreach (string filePath in filesPaths) { | |
| if (!EditorUtility.DisplayCancelableProgressBar("Scanning Assets folder", MakeRelativePath(_assetsPath, filePath), | |
| counter / (float) filesPaths.Count)) { | |
| string contents = File.ReadAllText(filePath); | |
| IEnumerable<string> guids = GetGuids(contents); | |
| bool isFirstGuid = true; | |
| foreach (string oldGuid in guids) { | |
| // First GUID in .meta file is always the GUID of the asset itself | |
| if (isFirstGuid && Path.GetExtension(filePath) == ".meta") { | |
| ownGuids.Add(oldGuid); | |
| isFirstGuid = false; | |
| } | |
| // Generate and save new GUID if we haven't added it before | |
| if (!guidOldToNewMap.ContainsKey(oldGuid)) { | |
| string newGuid = Guid.NewGuid().ToString("N"); | |
| guidOldToNewMap.Add(oldGuid, newGuid); | |
| } | |
| if (!guidsInFileMap.ContainsKey(filePath)) | |
| guidsInFileMap[filePath] = new List<string>(); | |
| if (!guidsInFileMap[filePath].Contains(oldGuid)) { | |
| guidsInFileMap[filePath].Add(oldGuid); | |
| } | |
| } | |
| counter++; | |
| } else { | |
| UnityEngine.Debug.LogWarning("GUID regeneration canceled"); | |
| return; | |
| } | |
| } | |
| // Traverse the files again and replace the old GUIDs | |
| counter = -1; | |
| int guidsInFileMapKeysCount = guidsInFileMap.Keys.Count; | |
| foreach (string filePath in guidsInFileMap.Keys) { | |
| EditorUtility.DisplayProgressBar("Regenerating GUIDs", MakeRelativePath(_assetsPath, filePath), counter / (float) guidsInFileMapKeysCount); | |
| counter++; | |
| string contents = File.ReadAllText(filePath); | |
| foreach (string oldGuid in guidsInFileMap[filePath]) { | |
| if (!ownGuids.Contains(oldGuid)) | |
| continue; | |
| string newGuid = guidOldToNewMap[oldGuid]; | |
| if (string.IsNullOrEmpty(newGuid)) | |
| throw new NullReferenceException("newGuid == null"); | |
| contents = contents.Replace("guid: " + oldGuid, "guid: " + newGuid); | |
| } | |
| File.WriteAllText(filePath, contents); | |
| } | |
| EditorUtility.ClearProgressBar(); | |
| } | |
| private static IEnumerable<string> GetGuids(string text) { | |
| const string guidStart = "guid: "; | |
| const int guidLength = 32; | |
| int textLength = text.Length; | |
| int guidStartLength = guidStart.Length; | |
| List<string> guids = new List<string>(); | |
| int index = 0; | |
| while (index + guidStartLength + guidLength < textLength) { | |
| index = text.IndexOf(guidStart, index, StringComparison.Ordinal); | |
| if (index == -1) | |
| break; | |
| index += guidStartLength; | |
| string guid = text.Substring(index, guidLength); | |
| index += guidLength; | |
| if (IsGuid(guid)) { | |
| guids.Add(guid); | |
| } | |
| } | |
| return guids; | |
| } | |
| private static bool IsGuid(string text) { | |
| for (int i = 0; i < text.Length; i++) { | |
| char c = text[i]; | |
| if ( | |
| !((c >= '0' && c <= '9') || | |
| (c >= 'a' && c <= 'z')) | |
| ) | |
| return false; | |
| } | |
| return true; | |
| } | |
| private static string MakeRelativePath(string fromPath, string toPath) { | |
| Uri fromUri = new Uri(fromPath); | |
| Uri toUri = new Uri(toPath); | |
| Uri relativeUri = fromUri.MakeRelativeUri(toUri); | |
| string relativePath = Uri.UnescapeDataString(relativeUri.ToString()); | |
| return relativePath; | |
| } | |
| } | |
| } |
I'm facing an issue where after running this script, Unity scenes complain that their scripts cannot be found.
Hi, my projects do not have the route Assets/Editor, where it is supposed to be copied this script into my project?
Hi, my projects do not have the route Assets/Editor, where it is supposed to be copied this script into my project?
You just create the folder if it does not exist and then put it in there. Right-click in the project => Create new folder => name it Editor.
I found my unity project at 2019.4.0f1 Guid didn't have alphabet characters bigger and equal to 'g'.
Maybe it doesn't have to check Guid character from g to z, in the function of IsGuid(string text).
From
private static bool IsGuid(string text)
{
for (int i = 0; i < text.Length; i++)
{
char c = text[i];
if (
!((c >= '0' && c <= '9') ||
(c >= 'a' && c <= 'z'))
)
return false;
}
return true;
}
to
private static bool IsGuid(string text)
{
for (int i = 0; i < text.Length; i++)
{
char c = text[i];
if (
!((c >= '0' && c <= '9') ||
(c >= 'a' && c <= 'f'))
)
return false;
}
return true;
}
need assembly definition implementation. asmdef didn't be replaced to new guid
THAAAAAAAAAAAAAAAAAAANKKSSSSSSSSSSSSSSSSSSSSSSSSSS !!!!!!!!!!!!!!!!!!!
Still works as expected in Unity 2021 👍
I'm facing an issue where after running this script, Unity scenes complain that their scripts cannot be found . Unity version 2021.3.11f
Perfect!! It worked for me. Thanks a lot!
Thanks for sharing this.
@ZimM-LostPolygon, thanks for sharing this wonderful and helpful script.
@geolands, I faced this same issue and using FileStream solved it. Thanks a ton for sharing the issue and the solution along with it. :)