Files
2026-07-29 09:38:54 +02:00

78 lines
3.0 KiB
C#

using System;
using Godot;
using Microsoft.Extensions.Logging;
using OwofGames.AetherBind;
using OwofGames.GodotLume;
namespace GodotHostTest.AetherBind;
/// <summary>
/// A node that provides injected services to other nodes.
/// </summary>
[Icon("res://addons/AetherBind/ServiceSource.svg")]
public partial class ServiceSource : Node
{
private static readonly string RootScopeQualifiedName = typeof(RootScope).AssemblyQualifiedName!;
/// <summary>
/// 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.
/// </summary>
[Export] protected Node?[] InjectedNodes = [];
/// <summary>
/// Name of the scope for the services built by this service source.
/// </summary>
[Export] private string _serviceScope = RootScopeQualifiedName;
/// <summary>
/// Inject the required services in <see cref="InjectedNodes" />.
/// </summary>
/// <param name="provider">The service provider.</param>
/// <param name="onScopeCreated">A callback method invoked with this scope's provider, if a scope was created.</param>
internal void ResolveInjectedNodes(IProvider provider, Action<IProvider>? onScopeCreated)
{
var logger = provider.Get<ILogger<ServiceSource>>();
// 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
/// <summary>
/// This method is invoked as soon as the scope for the services is created, but before the services are injected into
/// the <see cref="InjectedNodes" />. Override this method in derived classes to perform custom initialization steps
/// for the services, like setting <see cref="ValueProvider{T}" />s.
/// </summary>
/// <param name="serviceProvider">Lume's service provider.</param>
protected virtual void OnScopeCreated(IProvider serviceProvider)
{
}
}