AssetDataFetcher.cs 7.6 KB

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