using System; using System.Collections.Generic; using System.Linq; using System.Reflection; using EcsRx.Extensions; using EcsRx.Infrastructure.Dependencies; using EcsRx.Systems; namespace EcsRx.Infrastructure.Extensions { public static class IEcsRxApplicationExtensions { /// /// This will bind any ISystem implementations that are found within the assembly provided /// /// /// This can save you time but is not advised in most cases /// /// The application to act on /// The assemblies to scan for systems public static void BindAllSystemsInAssemblies(this IEcsRxApplication application, params Assembly[] assemblies) { var systemType = typeof(ISystem); var applicableSystems = assemblies.SelectMany(x => x.GetTypes()) .Where(x => { if(x.IsInterface || x.IsAbstract) { return false; } return systemType.IsAssignableFrom(x); }) .ToList(); if(!applicableSystems.Any()) { return; } foreach (var applicableSystemType in applicableSystems) { var bindingConfiguration = new BindingConfiguration { AsSingleton = true, WithName = applicableSystemType.Name }; application.Container.Bind(systemType, applicableSystemType, bindingConfiguration); } } /// /// This will bind any ISystem implementations that are found within the namespaces provided /// /// /// It is also advised you wrap this method with your own conventions like BindAllSystemsWithinApplicationScope does. /// /// The application to act on /// The namespaces to be scanned for implementations public static void BindAllSystemsInNamespaces(this IEcsRxApplication application, params string[] namespaces) { var applicationAssemblies = AppDomain.CurrentDomain.GetAssemblies(); var systemType = typeof(ISystem); var applicableSystems = applicationAssemblies.SelectMany(x => x.GetTypes()) .Where(x => { if(x.IsInterface || x.IsAbstract) { return false; } if(string.IsNullOrEmpty(x.Namespace)) { return false; } if(!systemType.IsAssignableFrom(x)) { return false; } return namespaces.Any(namespaceToVerify => x.Namespace.Contains(namespaceToVerify)); }) .ToList(); if(!applicableSystems.Any()) { return; } foreach (var applicableSystemType in applicableSystems) { var bindingConfiguration = new BindingConfiguration { AsSingleton = true, WithName = applicableSystemType.Name }; application.Container.Bind(systemType, applicableSystemType, bindingConfiguration); } } /// /// This will bind any ISystem implementations found within Systems, ViewResolvers folders which are located /// in a child namespace of the application. /// /// /// This is a conventional based binding that expects the application file to sit in the root of a directory, /// and then have systems in folders within same directory,if you need other conventions then look at wrapping /// BindAnySystemsInNamespace /// /// The application to act on public static void BindAllSystemsWithinApplicationScope(this IEcsRxApplication application) { var applicationNamespace = application.GetType().Namespace; var namespaces = new[] { $"{applicationNamespace}.Systems", $"{applicationNamespace}.ViewResolvers" }; application.BindAllSystemsInNamespaces(namespaces); } /// /// This will bind the given system type (T) to the DI container against `ISystem` /// and will then immediately register the system with the SystemExecutor. /// /// The application to act on /// The implementation of ISystem to bind/register /// This is really for runtime usage, in mose cases you will want to bind in starting and register in started public static void BindAndStartSystem(this IEcsRxApplication application) where T : ISystem { application.Container.Bind(x => x.WithName(typeof(T).Name)); StartSystem(application); } /// /// This will resolve the given type (T) from the DI container then register it /// with the SystemExecutor. /// /// The application to act on /// The implementation of ISystem to register public static void StartSystem(this IEcsRxApplication application) where T : ISystem { ISystem system; if(application.Container.HasBinding(typeof(T).Name)) { system = application.Container.Resolve(typeof(T).Name); } else { system = application.Container.Resolve(); } application.SystemExecutor.AddSystem(system); } /// /// Resolve all systems which have been bound in the order they should be registered /// /// The application to act on /// This ordering will be purely by priority public static IEnumerable GetAllBoundSystems(this IEcsRxApplication application) { var allSystems = application.Container.ResolveAll(); return allSystems.OrderByPriority(); } /// /// Resolve all systems which have been bound and register them in order with the systems executor /// /// The application to act on /// Will be purely public static void StartAllBoundSystems(this IEcsRxApplication application) { var allSystems = GetAllBoundSystems(application); allSystems.ForEachRun(application.SystemExecutor.AddSystem); } } }