using System.Reflection; namespace Ghost.SparseEntities.Systems; internal class SystemDependencyBuilder { private readonly Dictionary> _dependencies = new(); private readonly List _systemTypes; public SystemDependencyBuilder(List allSystemTypes) { _systemTypes = allSystemTypes; } /// /// Builds a dependency graph for all system types that implement the interface. /// /// This method analyzes all system types and their dependencies, as defined by the . It validates that each system type is a concrete implementation of and constructs a mapping of each system type to its direct dependencies. /// Thrown if a type in allSystemTypes is not a concrete implementation of . public void BuildDependencyGraph() { foreach (var systemType in _systemTypes) { if (!typeof(ISystem).IsAssignableFrom(systemType) || systemType.IsAbstract || systemType.IsInterface) { throw new ArgumentException($"{systemType.Name} is not a concrete ISystem type."); } var directDependencies = new List(); var dependsOnAttributes = systemType.GetCustomAttributes(false); foreach (var attr in dependsOnAttributes) { directDependencies.AddRange(attr.Prerequisites); } _dependencies[systemType] = directDependencies; } } private void Visit(Type systemType, HashSet visited, HashSet permanentMark, List executionOrder) { if (permanentMark.Contains(systemType)) { return; } if (visited.Contains(systemType)) { throw new InvalidOperationException($"Circular dependency detected involving system: {systemType.Name}"); } visited.Add(systemType); // Mark as currently visiting if (_dependencies.TryGetValue(systemType, out var directDependencies)) { foreach (var dependencyType in directDependencies) { // Ensure the dependency is a registered system type if (!_systemTypes.Contains(dependencyType)) { throw new InvalidOperationException($"System {systemType.Name} depends on unregistered system {dependencyType.Name}."); } Visit(dependencyType, visited, permanentMark, executionOrder); } } visited.Remove(systemType); // Done visiting this node in the current path permanentMark.Add(systemType); // Mark as permanently processed executionOrder.Add(systemType); // Add to the sorted list (this will be reversed later for correct order) } /// /// Builds the topological order of systems. /// /// A list of system types in the order they should be executed. /// Thrown if a circular dependency is detected." public List BuildExecutionOrder() { var executionOrder = new List(_systemTypes.Count); var visited = new HashSet(); // Tracks visited nodes in the current DFS path (for cycle detection) var permanentMark = new HashSet(); // Tracks nodes whose dependencies have been fully resolved // Initialize dependencies for all registered systems, even those without explicit attributes foreach (var sysType in _systemTypes) { if (!_dependencies.ContainsKey(sysType)) { _dependencies[sysType] = new(); } } foreach (var systemType in _systemTypes) { if (!permanentMark.Contains(systemType)) { Visit(systemType, visited, permanentMark, executionOrder); } } return executionOrder; } }