using System; using Godot; using Microsoft.Extensions.Logging; using OwofGames.AetherBind; using OwofGames.GodotLume; namespace GodotHostTest.AetherBind; /// /// A node that provides injected services to other nodes. /// [Icon("res://addons/AetherBind/ServiceSource.svg")] public partial class ServiceSource : Node { private static readonly string RootScopeQualifiedName = typeof(RootScope).AssemblyQualifiedName!; /// /// List of nodes that must be injected. This list will be automatically populated with all nodes in this object's /// editor scene that have at least one [Inject] field or method. /// [Export] protected Node?[] InjectedNodes = []; /// /// Name of the scope for the services built by this service source. /// [Export] private string _serviceScope = RootScopeQualifiedName; /// /// Inject the required services in . /// /// The service provider. /// A callback method invoked with this scope's provider, if a scope was created. internal void ResolveInjectedNodes(IProvider provider, Action? onScopeCreated) { var logger = provider.Get>(); // if this service source must also act as a scope, create the scope and use its service provider if (_serviceScope != RootScopeQualifiedName) { // create the scoped provider var serviceScope = ScopeTypesAndNames.GetType(_serviceScope); provider = provider.GetScopedProvider(serviceScope); // invoke onScopeCreated, if present onScopeCreated?.Invoke(provider); // invoke overridden callback OnScopeCreated(provider); } else if (onScopeCreated != null) { logger.LogWarning("onScopeCreated passed during instantiation, but no scoped provider was created."); } // resolve the injected nodes against the chosen service provider foreach (var node in InjectedNodes) { if (node == null) continue; logger.LogTrace("Injecting {Node}.", node.Name); if (node is IInjectable injectable) { injectable.Inject(provider); } } } // TODO: also add source generator to mark methods in derived classes with [OnScopeCreated] and perform parameter injection /// /// This method is invoked as soon as the scope for the services is created, but before the services are injected into /// the . Override this method in derived classes to perform custom initialization steps /// for the services, like setting s. /// /// Lume's service provider. protected virtual void OnScopeCreated(IProvider serviceProvider) { } }