AssetDataFetcher.cs 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263
  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, Queue<string> miscGuids) 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. var allGuids = new Queue<string>(AssetDatabase.FindAssets(""));
  30. var knownGuids = new HashSet<string>();
  31. knownGuids.UnionWith(scriptableObjects);
  32. knownGuids.UnionWith(prefabs);
  33. knownGuids.UnionWith(scriptableObjects);
  34. knownGuids.UnionWith(scenes);
  35. var miscGuids = new Queue<string>(allGuids.Except(knownGuids));
  36. return (scripts, prefabs, scriptableObjects, scenes, miscGuids);
  37. }
  38. /// <summary>
  39. /// Gathers metadata for a single script asset. Its dependencies will be filled in later.
  40. /// </summary>
  41. public static ScriptMetadata PreFetchScriptMetadata(string guid)
  42. {
  43. var assetPath = AssetDatabase.GUIDToAssetPath(guid);
  44. if (string.IsNullOrEmpty(assetPath) || !assetPath.StartsWith("Assets/")) return null;
  45. return new ScriptMetadata { Guid = guid, FullPath = Path.GetFullPath(assetPath).Replace('\\', '/') };
  46. }
  47. /// <summary>
  48. /// Gathers metadata for a single prefab asset, including its direct script dependencies.
  49. /// </summary>
  50. public static PrefabMetadata PreFetchPrefabMetadata(string guid)
  51. {
  52. var assetPath = AssetDatabase.GUIDToAssetPath(guid);
  53. if (string.IsNullOrEmpty(assetPath) || !assetPath.StartsWith("Assets/")) return null;
  54. var go = AssetDatabase.LoadAssetAtPath<GameObject>(assetPath);
  55. if (go == null) return null;
  56. var prefabMetadata = new PrefabMetadata { Guid = guid };
  57. var hash = new HashSet<string>();
  58. // Find all components on the prefab and its children to get their script GUIDs.
  59. var components = go.GetComponentsInChildren<Component>(true);
  60. foreach (var component in components)
  61. {
  62. if (component == null) continue;
  63. var script = MonoScript.FromMonoBehaviour(component as MonoBehaviour);
  64. if (script == null) continue;
  65. var scriptAssetPath = AssetDatabase.GetAssetPath(script);
  66. if (string.IsNullOrEmpty(scriptAssetPath)) continue;
  67. var scriptGuid = AssetDatabase.AssetPathToGUID(scriptAssetPath);
  68. if (!string.IsNullOrEmpty(scriptGuid) && scriptAssetPath.StartsWith("Assets/"))
  69. {
  70. hash.Add(scriptGuid);
  71. }
  72. }
  73. var assetDependencies = AssetDatabase.GetDependencies(assetPath);
  74. foreach (var dependency in assetDependencies)
  75. {
  76. if (string.IsNullOrEmpty(dependency) || !dependency.StartsWith("Assets/") || dependency == assetPath)
  77. {
  78. continue;
  79. }
  80. var dependencyGuid = AssetDatabase.AssetPathToGUID(dependency);
  81. if (!string.IsNullOrEmpty(dependencyGuid))
  82. {
  83. hash.Add(dependencyGuid);
  84. }
  85. }
  86. prefabMetadata.DependencyGuids = hash.ToList();
  87. return prefabMetadata;
  88. }
  89. /// <summary>
  90. /// Gathers metadata for a single ScriptableObject asset, including its direct script dependency.
  91. /// </summary>
  92. public static ScriptableObjectMetadata PreFetchScriptableObjectMetadata(string guid)
  93. {
  94. var assetPath = AssetDatabase.GUIDToAssetPath(guid);
  95. if (string.IsNullOrEmpty(assetPath) || !assetPath.StartsWith("Assets/")) return null;
  96. var so = AssetDatabase.LoadAssetAtPath<ScriptableObject>(assetPath);
  97. if (so == null) return null;
  98. var script = MonoScript.FromScriptableObject(so);
  99. if (script == null) return null;
  100. var scriptAssetPath = AssetDatabase.GetAssetPath(script);
  101. if (string.IsNullOrEmpty(scriptAssetPath)) return null;
  102. var hash = new HashSet<string>();
  103. var scriptGuid = AssetDatabase.AssetPathToGUID(scriptAssetPath);
  104. var soMetadata = new ScriptableObjectMetadata { Guid = guid };
  105. if (!string.IsNullOrEmpty(scriptGuid) && scriptAssetPath.StartsWith("Assets/"))
  106. {
  107. hash.Add(scriptGuid);
  108. }
  109. var assetDependencies = AssetDatabase.GetDependencies(assetPath);
  110. foreach (var dependency in assetDependencies)
  111. {
  112. if (string.IsNullOrEmpty(dependency) || !dependency.StartsWith("Assets/") || dependency == assetPath)
  113. {
  114. continue;
  115. }
  116. var dependencyGuid = AssetDatabase.AssetPathToGUID(dependency);
  117. if (!string.IsNullOrEmpty(dependencyGuid))
  118. {
  119. hash.Add(dependencyGuid);
  120. }
  121. }
  122. soMetadata.DependencyGuids = hash.ToList();
  123. return soMetadata;
  124. }
  125. /// <summary>
  126. /// Gathers all data required to initialize the Roslyn C# analysis.
  127. /// </summary>
  128. public static RoslynSetupData PreFetchRoslynSetupData(List<ScriptMetadata> scriptMetadata)
  129. {
  130. var setupData = new RoslynSetupData
  131. {
  132. SourceFiles = scriptMetadata.Select(s => s.FullPath).ToArray(),
  133. PreprocessorSymbols = EditorUserBuildSettings.activeScriptCompilationDefines
  134. };
  135. var references = new List<string>();
  136. foreach (var assembly in CompilationPipeline.GetAssemblies())
  137. {
  138. references.AddRange(assembly.compiledAssemblyReferences.Select(Path.GetFullPath));
  139. }
  140. setupData.References = references.Distinct().ToArray();
  141. var prefixes = new List<string> { "System", "UnityEngine", "UnityEditor" };
  142. var settings = AnalyzerSettingsCrud.GetOrCreateSettings();
  143. if (settings != null && settings.CustomSystemTypes != null)
  144. {
  145. prefixes.AddRange(settings.CustomSystemTypes.Where(p => !string.IsNullOrEmpty(p) && !prefixes.Contains(p)));
  146. }
  147. setupData.SystemTypePrefixes = prefixes;
  148. setupData.TypeToGuidMap = new Dictionary<string, string>();
  149. var tempAnalyzer = new RoslynTypeDependencyAnalyzer(setupData.SourceFiles, setupData.References, setupData.PreprocessorSymbols, setupData.SystemTypePrefixes);
  150. foreach (var pair in tempAnalyzer.TypeToPathMap)
  151. {
  152. var projectPath = Directory.GetParent(Application.dataPath)?.FullName.Replace('\\', '/');
  153. var relativePath = pair.Value.Replace('\\', '/').Replace(projectPath + "/", "");
  154. var guid = AssetDatabase.AssetPathToGUID(relativePath);
  155. if (!string.IsNullOrEmpty(guid)) { setupData.TypeToGuidMap[pair.Key] = guid; }
  156. }
  157. return setupData;
  158. }
  159. public static MiscAssetMetadata PreFetchMiscAssetMetadata(string guid)
  160. {
  161. var assetPath = AssetDatabase.GUIDToAssetPath(guid);
  162. if (string.IsNullOrEmpty(assetPath) || !assetPath.StartsWith("Assets/")) return null;
  163. var miscMetaData = new MiscAssetMetadata() { Guid = guid };
  164. var hash = new HashSet<string>();
  165. var assetDependencies = AssetDatabase.GetDependencies(assetPath);
  166. foreach (var dependency in assetDependencies)
  167. {
  168. if (string.IsNullOrEmpty(dependency) || !dependency.StartsWith("Assets/") || dependency == assetPath)
  169. {
  170. continue;
  171. }
  172. var dependencyGuid = AssetDatabase.AssetPathToGUID(dependency);
  173. if (!string.IsNullOrEmpty(dependencyGuid))
  174. {
  175. hash.Add(dependencyGuid);
  176. }
  177. }
  178. miscMetaData.DependencyGuids = hash.ToList();
  179. return miscMetaData;
  180. }
  181. public static SceneMetadata PreFetchSceneMetadata(string guid)
  182. {
  183. var assetPath = AssetDatabase.GUIDToAssetPath(guid);
  184. if (string.IsNullOrEmpty(assetPath) || !assetPath.StartsWith("Assets/")) return null;
  185. var scene = EditorSceneManager.OpenScene(assetPath, OpenSceneMode.Single);
  186. var sceneMetaData = new SceneMetadata() { Guid = guid };
  187. var hash = new HashSet<string>();
  188. // Find all components on the scene and its children to get their script GUIDs.
  189. foreach (var root in scene.GetRootGameObjects())
  190. {
  191. var components = root.GetComponentsInChildren<Component>(true);
  192. foreach (var component in components)
  193. {
  194. if (component == null) continue;
  195. var script = MonoScript.FromMonoBehaviour(component as MonoBehaviour);
  196. if (script == null) continue;
  197. var scriptAssetPath = AssetDatabase.GetAssetPath(script);
  198. if (string.IsNullOrEmpty(scriptAssetPath)) continue;
  199. var scriptGuid = AssetDatabase.AssetPathToGUID(scriptAssetPath);
  200. if (!string.IsNullOrEmpty(scriptGuid) && scriptAssetPath.StartsWith("Assets/"))
  201. {
  202. hash.Add(scriptGuid);
  203. }
  204. }
  205. }
  206. var assetDependencies = AssetDatabase.GetDependencies(assetPath);
  207. foreach (var dependency in assetDependencies)
  208. {
  209. if (string.IsNullOrEmpty(dependency) || !dependency.StartsWith("Assets/") || dependency == assetPath)
  210. {
  211. continue;
  212. }
  213. var dependencyGuid = AssetDatabase.AssetPathToGUID(dependency);
  214. if (!string.IsNullOrEmpty(dependencyGuid))
  215. {
  216. hash.Add(dependencyGuid);
  217. }
  218. }
  219. sceneMetaData.DependencyGuids = hash.ToList();
  220. return sceneMetaData;
  221. }
  222. }
  223. }