using System.IO;
using System.Linq;
using UnityEditor;
using UnityEngine;
using UnityEditor.Compilation;
using System.Collections.Generic;
using IntelligentProjectAnalyzer.Analyzer;
using UnityEditor.SceneManagement;
// All using statements now refer to the new data-only class
using static IntelligentProjectAnalyzer.Editor.DependencyBuilderData;
namespace IntelligentProjectAnalyzer.Editor
{
///
/// Handles all communication with the Unity API that must occur on the main thread
/// to gather data for the dependency analysis.
///
public static class AssetDataFetcher
{
///
/// Finds all relevant asset GUIDs for scripts, prefabs, and ScriptableObjects.
///
/// A tuple containing queues of GUIDs for each asset type.
public static (Queue scriptGuids, Queue prefabGuids, Queue soGuids, Queue sceneGuids, Queue miscGuids) FindAssetGuids()
{
var scripts = new Queue(AssetDatabase.FindAssets("t:MonoScript"));
var prefabs = new Queue(AssetDatabase.FindAssets("t:Prefab"));
var scriptableObjects = new Queue(AssetDatabase.FindAssets("t:ScriptableObject"));
var scenes = new Queue(AssetDatabase.FindAssets("t:Scene"));
var allGuids = new Queue(AssetDatabase.FindAssets(""));
var knownGuids = new HashSet();
knownGuids.UnionWith(scriptableObjects);
knownGuids.UnionWith(prefabs);
knownGuids.UnionWith(scripts);
knownGuids.UnionWith(scenes);
var miscGuids = new Queue(allGuids.Except(knownGuids));
return (scripts, prefabs, scriptableObjects, scenes, miscGuids);
}
///
/// Gathers metadata for a single script asset. Its dependencies will be filled in later.
///
public static ScriptMetadata PreFetchScriptMetadata(string guid)
{
var assetPath = AssetDatabase.GUIDToAssetPath(guid);
if (string.IsNullOrEmpty(assetPath) || !assetPath.StartsWith("Assets/")) return null;
return new ScriptMetadata { Guid = guid, FullPath = Path.GetFullPath(assetPath).Replace('\\', '/') };
}
///
/// Gathers metadata for a single prefab asset, including its direct script dependencies.
///
public static PrefabMetadata PreFetchPrefabMetadata(string guid)
{
var assetPath = AssetDatabase.GUIDToAssetPath(guid);
if (string.IsNullOrEmpty(assetPath) || !assetPath.StartsWith("Assets/")) return null;
var go = AssetDatabase.LoadAssetAtPath(assetPath);
if (go == null) return null;
var prefabMetadata = new PrefabMetadata { Guid = guid };
var hash = new HashSet();
// Find all components on the prefab and its children to get their script GUIDs.
var components = go.GetComponentsInChildren(true);
foreach (var component in components)
{
if (component == null) continue;
var script = MonoScript.FromMonoBehaviour(component as MonoBehaviour);
if (script == null) continue;
var scriptAssetPath = AssetDatabase.GetAssetPath(script);
if (string.IsNullOrEmpty(scriptAssetPath)) continue;
var scriptGuid = AssetDatabase.AssetPathToGUID(scriptAssetPath);
if (!string.IsNullOrEmpty(scriptGuid) && scriptAssetPath.StartsWith("Assets/"))
{
hash.Add(scriptGuid);
}
}
var assetDependencies = AssetDatabase.GetDependencies(assetPath);
foreach (var dependency in assetDependencies)
{
if (string.IsNullOrEmpty(dependency) || !dependency.StartsWith("Assets/") || dependency == assetPath)
{
continue;
}
var dependencyGuid = AssetDatabase.AssetPathToGUID(dependency);
if (!string.IsNullOrEmpty(dependencyGuid))
{
hash.Add(dependencyGuid);
}
}
prefabMetadata.DependencyGuids = hash.ToList();
return prefabMetadata;
}
///
/// Gathers metadata for a single ScriptableObject asset, including its direct script dependency.
///
public static ScriptableObjectMetadata PreFetchScriptableObjectMetadata(string guid)
{
var assetPath = AssetDatabase.GUIDToAssetPath(guid);
if (string.IsNullOrEmpty(assetPath) || !assetPath.StartsWith("Assets/")) return null;
var so = AssetDatabase.LoadAssetAtPath(assetPath);
if (so == null) return null;
var script = MonoScript.FromScriptableObject(so);
if (script == null) return null;
var scriptAssetPath = AssetDatabase.GetAssetPath(script);
if (string.IsNullOrEmpty(scriptAssetPath)) return null;
var hash = new HashSet();
var scriptGuid = AssetDatabase.AssetPathToGUID(scriptAssetPath);
var soMetadata = new ScriptableObjectMetadata { Guid = guid };
if (!string.IsNullOrEmpty(scriptGuid) && scriptAssetPath.StartsWith("Assets/"))
{
hash.Add(scriptGuid);
}
var assetDependencies = AssetDatabase.GetDependencies(assetPath);
foreach (var dependency in assetDependencies)
{
if (string.IsNullOrEmpty(dependency) || !dependency.StartsWith("Assets/") || dependency == assetPath)
{
continue;
}
var dependencyGuid = AssetDatabase.AssetPathToGUID(dependency);
if (!string.IsNullOrEmpty(dependencyGuid))
{
hash.Add(dependencyGuid);
}
}
soMetadata.DependencyGuids = hash.ToList();
return soMetadata;
}
///
/// Gathers all data required to initialize the Roslyn C# analysis.
///
public static RoslynSetupData PreFetchRoslynSetupData(List scriptMetadata)
{
var setupData = new RoslynSetupData
{
SourceFiles = scriptMetadata.Select(s => s.FullPath).ToArray(),
PreprocessorSymbols = EditorUserBuildSettings.activeScriptCompilationDefines
};
var references = new List();
foreach (var assembly in CompilationPipeline.GetAssemblies())
{
references.AddRange(assembly.compiledAssemblyReferences.Select(Path.GetFullPath));
}
setupData.References = references.Distinct().ToArray();
var prefixes = new List { "System", "UnityEngine", "UnityEditor" };
var settings = AnalyzerSettingsCrud.GetOrCreateSettings();
if (settings != null && settings.CustomSystemTypes != null)
{
prefixes.AddRange(settings.CustomSystemTypes.Where(p => !string.IsNullOrEmpty(p) && !prefixes.Contains(p)));
}
setupData.SystemTypePrefixes = prefixes;
setupData.TypeToGuidMap = new Dictionary();
var tempAnalyzer = new RoslynTypeDependencyAnalyzer(setupData.SourceFiles, setupData.References, setupData.PreprocessorSymbols, setupData.SystemTypePrefixes);
foreach (var pair in tempAnalyzer.TypeToPathMap)
{
var projectPath = Directory.GetParent(Application.dataPath)?.FullName.Replace('\\', '/');
var relativePath = pair.Value.Replace('\\', '/').Replace(projectPath + "/", "");
var guid = AssetDatabase.AssetPathToGUID(relativePath);
if (!string.IsNullOrEmpty(guid)) { setupData.TypeToGuidMap[pair.Key] = guid; }
}
return setupData;
}
public static MiscAssetMetadata PreFetchMiscAssetMetadata(string guid)
{
var assetPath = AssetDatabase.GUIDToAssetPath(guid);
if (string.IsNullOrEmpty(assetPath) || !assetPath.StartsWith("Assets/")) return null;
var miscMetaData = new MiscAssetMetadata() { Guid = guid };
var hash = new HashSet();
var assetDependencies = AssetDatabase.GetDependencies(assetPath);
foreach (var dependency in assetDependencies)
{
if (string.IsNullOrEmpty(dependency) || !dependency.StartsWith("Assets/") || dependency == assetPath)
{
continue;
}
var dependencyGuid = AssetDatabase.AssetPathToGUID(dependency);
if (!string.IsNullOrEmpty(dependencyGuid))
{
hash.Add(dependencyGuid);
}
}
miscMetaData.DependencyGuids = hash.ToList();
return miscMetaData;
}
public static SceneMetadata PreFetchSceneMetadata(string guid)
{
var assetPath = AssetDatabase.GUIDToAssetPath(guid);
if (string.IsNullOrEmpty(assetPath) || !assetPath.StartsWith("Assets/")) return null;
var scene = EditorSceneManager.OpenScene(assetPath, OpenSceneMode.Single);
var sceneMetaData = new SceneMetadata() { Guid = guid };
var hash = new HashSet();
// Find all components on the scene and its children to get their script GUIDs.
foreach (var root in scene.GetRootGameObjects())
{
var components = root.GetComponentsInChildren(true);
foreach (var component in components)
{
if (component == null) continue;
var script = MonoScript.FromMonoBehaviour(component as MonoBehaviour);
if (script == null) continue;
var scriptAssetPath = AssetDatabase.GetAssetPath(script);
if (string.IsNullOrEmpty(scriptAssetPath)) continue;
var scriptGuid = AssetDatabase.AssetPathToGUID(scriptAssetPath);
if (!string.IsNullOrEmpty(scriptGuid) && scriptAssetPath.StartsWith("Assets/"))
{
hash.Add(scriptGuid);
}
}
}
var assetDependencies = AssetDatabase.GetDependencies(assetPath);
foreach (var dependency in assetDependencies)
{
if (string.IsNullOrEmpty(dependency) || !dependency.StartsWith("Assets/") || dependency == assetPath)
{
continue;
}
var dependencyGuid = AssetDatabase.AssetPathToGUID(dependency);
if (!string.IsNullOrEmpty(dependencyGuid))
{
hash.Add(dependencyGuid);
}
}
sceneMetaData.DependencyGuids = hash.ToList();
return sceneMetaData;
}
}
}