Skip to content

Instantly share code, notes, and snippets.

@Mikilo
Created February 3, 2022 15:37
Show Gist options
  • Save Mikilo/bbeda90ed7125a35a11cbcaab6aa6e39 to your computer and use it in GitHub Desktop.
Save Mikilo/bbeda90ed7125a35a11cbcaab6aa6e39 to your computer and use it in GitHub Desktop.
using System;
using System.Collections.Generic;
using UnityEditor;
namespace NGToolsEditor.NGMissingScriptRecovery
{
using UnityEngine;
public static class MonoScriptCache
{
private static Dictionary<Type, MonoScriptIdentity> cache = new Dictionary<Type, MonoScriptIdentity>();
public static MonoScriptIdentity Get(Type type)
{
MonoScriptIdentity result;
if (MonoScriptCache.cache.TryGetValue(type, out result) == false)
{
result = new MonoScriptIdentity();
MonoScript monoScript;
if (typeof(ScriptableObject).IsAssignableFrom(type) == true)
{
ScriptableObject temp = ScriptableObject.CreateInstance(type);
monoScript = MonoScript.FromScriptableObject(temp);
Object.DestroyImmediate(temp, true);
}
else
{
GameObject temp = new GameObject("TEMP_RECOVERY", type);
monoScript = MonoScript.FromMonoBehaviour(temp.GetComponent(type) as MonoBehaviour);
Object.DestroyImmediate(temp, true);
}
if (monoScript == null)
return result;
#if UNITY_2018_2_OR_NEWER
// Modern technique, fastest & safest.
AssetDatabase.TryGetGUIDAndLocalFileIdentifier(monoScript.GetInstanceID(), out result.guid, out result.localID);
#endif
// First fallback, quick, can fix a Type from a DLL.
if (result.guid == null || result.guid.Length != 32 || result.localID == 0)
{
using (SerializedObject serializedScript = new SerializedObject(monoScript))
{
BrokenObject.inspectorModeProperty.SetValue(serializedScript, InspectorMode.Debug);
result.localID = serializedScript.FindProperty("m_LocalIdentfierInFile").intValue;
}
string projectPath = System.IO.Path.GetFullPath(Application.dataPath);
if (type.Assembly.Location.StartsWith(projectPath) == true)
result.guid = AssetDatabase.AssetPathToGUID(type.Assembly.Location.Substring(projectPath.Length - "Assets".Length).Replace('\\', '/'));
else
result.guid = AssetDatabase.AssetPathToGUID(type.Assembly.Location);
}
// Second fallback, slower, works as long as the Type's name matches the C# filename in the project.
if (result.guid == null || result.guid.Length != 32 || result.localID == 0)
{
string[] files = AssetDatabase.FindAssets(type.Name + " t:MonoScript");
for (int i = 0, max = files.Length; i < max; ++i)
{
string path = AssetDatabase.GUIDToAssetPath(files[i]);
if (path.EndsWith("/" + type.Name + ".cs") == true)
{
MonoScript ms = AssetDatabase.LoadAssetAtPath<MonoScript>(path);
if (result.guid == null || result.guid.Length != 32)
result.guid = files[i];
if (result.localID == 0)
result.localID = long.Parse(Utility.GetLocalIdentifierFromObject(ms));
break;
}
}
}
Debug.AssertFormat(result.guid != null && result.guid.Length == 32 && result.localID != 0, "MonoScript identity for \"{0}\" could not be retrieve properly.", type);
MonoScriptCache.cache.Add(type, result);
}
return result;
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment