using System; using System.IO; using UnityEngine; using System.Collections.Generic; using IntelligentProjectAnalyzer.Helper; using static IntelligentProjectAnalyzer.Editor.DependencyBuilderData; namespace IntelligentProjectAnalyzer.Editor.DependencyViewer { /// /// Loads, parses, and organizes dependency data from the cache into a queryable graph. /// This version reads the unified AssetMetadata structure. /// public class DependencyGraph { // Maps an asset's GUID to a list of GUIDs it depends. private readonly Dictionary> _dependencies = new(); // Maps an asset's GUID to a list of GUIDs that reference it. private readonly Dictionary> _references = new(); private readonly HashSet _allKnownGuids = new(); /// /// Initializes a new instance of the DependencyGraph class and builds it from the cache. /// public DependencyGraph() { BuildGraph(); } /// /// Gets the list of assets that the specified asset depends on. /// public List GetDependencies(string guid) { return _dependencies.TryGetValue(guid, out var dependencies) ? dependencies : new List(); } /// /// Gets the list of assets that reference the specified asset. /// public List GetReferences(string guid) { return _references.TryGetValue(guid, out var refs) ? refs : new List(); } /// /// Checks if the graph contains any data related to the given asset GUID. /// public bool AssetExists(string guid) { return _allKnownGuids.Contains(guid); } /// /// Clears and rebuilds the entire dependency graph by reading from the cache. /// public void BuildGraph() { _dependencies.Clear(); _references.Clear(); _allKnownGuids.Clear(); var cachePath = DependencyCacheManager.GetCachePath(); if (!Directory.Exists(cachePath)) { Debug.LogWarning("Cache directory does not exist. Skipping dependency graph build."); return; } var files = Directory.GetFiles(cachePath, "*.json"); foreach (var file in files) { try { // First, deserialize the outer wrapper object. var wrapper = JsonFileSystem.Read(file); if (wrapper == null || string.IsNullOrEmpty(wrapper.JsonData)) { continue; } // Dynamically get the concrete type from the stored index using our helper. var concreteType = MetadataTypeHelper.GetTypeFromIndex(wrapper.AssetTypeIndex); if (concreteType == null) { Debug.LogWarning($"Could not find a registered type for index '{wrapper.AssetTypeIndex}' during deserialization. Skipping file: {Path.GetFileName(file)}"); continue; } // Now, deserialize the nested JSON data into the correct concrete type. var metadata = JsonFileSystem.Read(wrapper.JsonData, concreteType) as AssetMetadata; if (metadata?.DependencyGuids == null) continue; _dependencies[metadata.Guid] = metadata.DependencyGuids; _allKnownGuids.Add(metadata.Guid); foreach(var depGuid in metadata.DependencyGuids) { _allKnownGuids.Add(depGuid); } } catch (Exception e) { Debug.LogError($"Failed to parse dependency file {Path.GetFileName(file)}. Error: {e.Message}"); } } // Now, build the inverse map (the references). foreach (var (referrerGuid, dependencies) in _dependencies) { foreach (var dependencyGuid in dependencies) { if (!_references.ContainsKey(dependencyGuid)) { _references[dependencyGuid] = new List(); } _references[dependencyGuid].Add(referrerGuid); } } } } }