AssetDataFetcher.cs 9.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228
  1. using System.IO;
  2. using System.Linq;
  3. using UnityEditor;
  4. using UnityEngine;
  5. using UnityEditor.Compilation;
  6. using System.Collections.Generic;
  7. using IntelligentProjectAnalyzer.Analyzer;
  8. using UnityEditor.SceneManagement;
  9. // All using statements now refer to the new data-only class
  10. using static IntelligentProjectAnalyzer.Editor.DependencyBuilderData;
  11. namespace IntelligentProjectAnalyzer.Editor
  12. {
  13. /// <summary>
  14. /// Handles all communication with the Unity API that must occur on the main thread
  15. /// to gather data for the dependency analysis.
  16. /// </summary>
  17. public static class AssetDataFetcher
  18. {
  19. /// <summary>
  20. /// Finds all relevant asset GUIDs for scripts, prefabs, and ScriptableObjects.
  21. /// </summary>
  22. /// <returns>A tuple containing queues of GUIDs for each asset type.</returns>
  23. public static (Queue<string> scriptGuids, Queue<string> prefabGuids, Queue<string> soGuids, Queue<string> sceneGuids) FindAssetGuids()
  24. {
  25. var scripts = new Queue<string>(AssetDatabase.FindAssets("t:MonoScript"));
  26. var prefabs = new Queue<string>(AssetDatabase.FindAssets("t:Prefab"));
  27. var scriptableObjects = new Queue<string>(AssetDatabase.FindAssets("t:ScriptableObject"));
  28. var scenes = new Queue<string>(AssetDatabase.FindAssets("t:Scene"));
  29. return (scripts, prefabs, scriptableObjects, scenes);
  30. }
  31. /// <summary>
  32. /// Gathers metadata for a single script asset. Its dependencies will be filled in later.
  33. /// </summary>
  34. public static ScriptMetadata PreFetchScriptMetadata(string guid)
  35. {
  36. var assetPath = AssetDatabase.GUIDToAssetPath(guid);
  37. if (string.IsNullOrEmpty(assetPath) || !assetPath.StartsWith("Assets/")) return null;
  38. return new ScriptMetadata { Guid = guid, FullPath = Path.GetFullPath(assetPath).Replace('\\', '/') };
  39. }
  40. /// <summary>
  41. /// Gathers metadata for a single prefab asset, including its direct script dependencies.
  42. /// </summary>
  43. public static PrefabMetadata PreFetchPrefabMetadata(string guid)
  44. {
  45. var assetPath = AssetDatabase.GUIDToAssetPath(guid);
  46. if (string.IsNullOrEmpty(assetPath) || !assetPath.StartsWith("Assets/")) return null;
  47. var go = AssetDatabase.LoadAssetAtPath<GameObject>(assetPath);
  48. if (go == null) return null;
  49. var prefabMetadata = new PrefabMetadata { Guid = guid };
  50. var hash = new HashSet<string>();
  51. // Find all components on the prefab and its children to get their script GUIDs.
  52. var components = go.GetComponentsInChildren<Component>(true);
  53. foreach (var component in components)
  54. {
  55. if (component == null) continue;
  56. var script = MonoScript.FromMonoBehaviour(component as MonoBehaviour);
  57. if (script == null) continue;
  58. var scriptAssetPath = AssetDatabase.GetAssetPath(script);
  59. if (string.IsNullOrEmpty(scriptAssetPath)) continue;
  60. var scriptGuid = AssetDatabase.AssetPathToGUID(scriptAssetPath);
  61. if (!string.IsNullOrEmpty(scriptGuid) && scriptAssetPath.StartsWith("Assets/"))
  62. {
  63. hash.Add(scriptGuid);
  64. }
  65. }
  66. var assetDependencies = AssetDatabase.GetDependencies(assetPath);
  67. foreach (var dependency in assetDependencies)
  68. {
  69. if (string.IsNullOrEmpty(dependency) || !dependency.StartsWith("Assets/") || dependency == assetPath)
  70. {
  71. continue;
  72. }
  73. var dependencyGuid = AssetDatabase.AssetPathToGUID(dependency);
  74. if (!string.IsNullOrEmpty(dependencyGuid))
  75. {
  76. hash.Add(dependencyGuid);
  77. }
  78. }
  79. prefabMetadata.DependencyGuids = hash.ToList();
  80. return prefabMetadata;
  81. }
  82. /// <summary>
  83. /// Gathers metadata for a single ScriptableObject asset, including its direct script dependency.
  84. /// </summary>
  85. public static ScriptableObjectMetadata PreFetchScriptableObjectMetadata(string guid)
  86. {
  87. var assetPath = AssetDatabase.GUIDToAssetPath(guid);
  88. if (string.IsNullOrEmpty(assetPath) || !assetPath.StartsWith("Assets/")) return null;
  89. var so = AssetDatabase.LoadAssetAtPath<ScriptableObject>(assetPath);
  90. if (so == null) return null;
  91. var script = MonoScript.FromScriptableObject(so);
  92. if (script == null) return null;
  93. var scriptAssetPath = AssetDatabase.GetAssetPath(script);
  94. if (string.IsNullOrEmpty(scriptAssetPath)) return null;
  95. var hash = new HashSet<string>();
  96. var scriptGuid = AssetDatabase.AssetPathToGUID(scriptAssetPath);
  97. var soMetadata = new ScriptableObjectMetadata { Guid = guid };
  98. if (!string.IsNullOrEmpty(scriptGuid) && scriptAssetPath.StartsWith("Assets/"))
  99. {
  100. hash.Add(scriptGuid);
  101. }
  102. var assetDependencies = AssetDatabase.GetDependencies(assetPath);
  103. foreach (var dependency in assetDependencies)
  104. {
  105. if (string.IsNullOrEmpty(dependency) || !dependency.StartsWith("Assets/") || dependency == assetPath)
  106. {
  107. continue;
  108. }
  109. var dependencyGuid = AssetDatabase.AssetPathToGUID(dependency);
  110. if (!string.IsNullOrEmpty(dependencyGuid))
  111. {
  112. hash.Add(dependencyGuid);
  113. }
  114. }
  115. soMetadata.DependencyGuids = hash.ToList();
  116. return soMetadata;
  117. }
  118. /// <summary>
  119. /// Gathers all data required to initialize the Roslyn C# analysis.
  120. /// </summary>
  121. public static RoslynSetupData PreFetchRoslynSetupData(List<ScriptMetadata> scriptMetadata)
  122. {
  123. var setupData = new RoslynSetupData
  124. {
  125. SourceFiles = scriptMetadata.Select(s => s.FullPath).ToArray(),
  126. PreprocessorSymbols = EditorUserBuildSettings.activeScriptCompilationDefines
  127. };
  128. var references = new List<string>();
  129. foreach (var assembly in CompilationPipeline.GetAssemblies())
  130. {
  131. references.AddRange(assembly.compiledAssemblyReferences.Select(Path.GetFullPath));
  132. }
  133. setupData.References = references.Distinct().ToArray();
  134. var prefixes = new List<string> { "System", "UnityEngine", "UnityEditor" };
  135. var settings = AnalyzerSettingsCrud.GetOrCreateSettings();
  136. if (settings != null && settings.CustomSystemTypes != null)
  137. {
  138. prefixes.AddRange(settings.CustomSystemTypes.Where(p => !string.IsNullOrEmpty(p) && !prefixes.Contains(p)));
  139. }
  140. setupData.SystemTypePrefixes = prefixes;
  141. setupData.TypeToGuidMap = new Dictionary<string, string>();
  142. var tempAnalyzer = new RoslynTypeDependencyAnalyzer(setupData.SourceFiles, setupData.References, setupData.PreprocessorSymbols, setupData.SystemTypePrefixes);
  143. foreach (var pair in tempAnalyzer.TypeToPathMap)
  144. {
  145. var projectPath = Directory.GetParent(Application.dataPath)?.FullName.Replace('\\', '/');
  146. var relativePath = pair.Value.Replace('\\', '/').Replace(projectPath + "/", "");
  147. var guid = AssetDatabase.AssetPathToGUID(relativePath);
  148. if (!string.IsNullOrEmpty(guid)) { setupData.TypeToGuidMap[pair.Key] = guid; }
  149. }
  150. return setupData;
  151. }
  152. public static SceneMetadata PreFetchSceneMetadata(string guid)
  153. {
  154. var assetPath = AssetDatabase.GUIDToAssetPath(guid);
  155. if (string.IsNullOrEmpty(assetPath) || !assetPath.StartsWith("Assets/")) return null;
  156. var scene = EditorSceneManager.OpenScene(assetPath, OpenSceneMode.Single);
  157. var sceneMetaData = new SceneMetadata() { Guid = guid };
  158. var hash = new HashSet<string>();
  159. // Find all components on the prefab and its children to get their script GUIDs.
  160. foreach (var root in scene.GetRootGameObjects())
  161. {
  162. var components = root.GetComponentsInChildren<Component>(true);
  163. foreach (var component in components)
  164. {
  165. if (component == null) continue;
  166. var script = MonoScript.FromMonoBehaviour(component as MonoBehaviour);
  167. if (script == null) continue;
  168. var scriptAssetPath = AssetDatabase.GetAssetPath(script);
  169. if (string.IsNullOrEmpty(scriptAssetPath)) continue;
  170. var scriptGuid = AssetDatabase.AssetPathToGUID(scriptAssetPath);
  171. if (!string.IsNullOrEmpty(scriptGuid) && scriptAssetPath.StartsWith("Assets/"))
  172. {
  173. hash.Add(scriptGuid);
  174. }
  175. }
  176. }
  177. var assetDependencies = AssetDatabase.GetDependencies(assetPath);
  178. foreach (var dependency in assetDependencies)
  179. {
  180. if (string.IsNullOrEmpty(dependency) || !dependency.StartsWith("Assets/") || dependency == assetPath)
  181. {
  182. continue;
  183. }
  184. var dependencyGuid = AssetDatabase.AssetPathToGUID(dependency);
  185. if (!string.IsNullOrEmpty(dependencyGuid))
  186. {
  187. hash.Add(dependencyGuid);
  188. }
  189. }
  190. sceneMetaData.DependencyGuids = hash.ToList();
  191. return sceneMetaData;
  192. }
  193. }
  194. }