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