Skip to content

Instantly share code, notes, and snippets.

@PizzaConsole
Created November 13, 2023 22:05
Show Gist options
  • Save PizzaConsole/47b8f4e289cd87e9e61316eab7c68490 to your computer and use it in GitHub Desktop.
Save PizzaConsole/47b8f4e289cd87e9e61316eab7c68490 to your computer and use it in GitHub Desktop.
Dependency Injection in Godot
public class ConstrainedRequestPostProcessor<TRequest, TResponse>
: IRequestPostProcessor<TRequest, TResponse>
where TRequest : class
{
public ConstrainedRequestPostProcessor()
{
}
public Task Process(TRequest request, TResponse response, CancellationToken cancellationToken)
{
return Task.CompletedTask;
}
}
public class DependencyInjectionSystem : Node
{
private static DependencyInjectionSystem _instance;
public static DependencyInjectionSystem Instance
{
get
{
if (_instance == null)
{
_instance = new DependencyInjectionSystem();
}
return _instance;
}
}
private SimpleInjector.Container container;
public override void _EnterTree()
{
base._EnterTree();
container = new SimpleInjector.Container();
var type = typeof(IGlobal); // Get the type of our interface
// Get the assemblies associated with our project
var types = AppDomain.CurrentDomain.GetAssemblies()
.SelectMany(s => s.GetTypes()) // Get all the types
.Where(p => type.IsAssignableFrom(p) && !p.IsInterface); // Filter to find any type that can be assigned to an IModule
foreach (var typ in types)
{
var serviceType = Type.GetType(typ.AssemblyQualifiedName.Replace(typ.Name, $"I{typ.Name}"));
container.RegisterSingleton(typ, typ);
}
// do registrations here
container.RegisterMediator();
//container.Register<InputController>(SimpleInjector.Lifestyle.Singleton);
container.Verify();
}
internal object Resolve(Type fieldType)
{
return container.GetInstance(fieldType);
}
}
public class GenericPipelineBehavior<TRequest, TResponse> : IPipelineBehavior<TRequest, TResponse>
{
public GenericPipelineBehavior()
{
}
public async Task<TResponse> Handle(TRequest request, CancellationToken cancellationToken, RequestHandlerDelegate<TResponse> next)
{
var response = await next();
return response;
}
}
public class GenericRequestPostProcessor<TRequest, TResponse> : IRequestPostProcessor<TRequest, TResponse>
{
public GenericRequestPostProcessor()
{
}
public Task Process(TRequest request, TResponse response, CancellationToken cancellationToken)
{
return Task.CompletedTask;
}
}
public class GenericRequestPreProcessor<TRequest> : IRequestPreProcessor<TRequest>
{
public GenericRequestPreProcessor()
{
}
public Task Process(TRequest request, CancellationToken cancellationToken)
{
return Task.CompletedTask;
}
}
public class InjectAttribute : Attribute
{
}
public static class InjectorExtensions
{
public static void ResolveDependencies(this object node)
{
var dis = DependencyInjectionSystem.Instance;
var at = typeof(InjectAttribute);
var fields = node.GetType()
.GetRuntimeFields()
.Where(f => f.GetCustomAttributes(at, true).Any());
foreach (var field in fields)
{
var obj = dis.Resolve(field.FieldType);
try
{
field.SetValue(node, obj);
}
catch (InvalidCastException)
{
GD.PrintErr($"Error converting value " +
$"{obj} ({obj.GetType()})" +
$" to {field.FieldType}");
throw;
}
}
}
public static void RegisterMediator(this SimpleInjector.Container container)
{
var assemblies = GetAssemblies().ToArray();
container.RegisterSingleton<IMediator, Mediator>();
container.Register(typeof(IRequestHandler<,>), assemblies);
RegisterHandlers(container, typeof(INotificationHandler<>), assemblies);
RegisterHandlers(container, typeof(IRequestExceptionAction<,>), assemblies);
RegisterHandlers(container, typeof(IRequestExceptionHandler<,,>), assemblies);
//Pipeline
container.Collection.Register(typeof(IPipelineBehavior<,>), new[]
{
typeof(RequestExceptionProcessorBehavior<,>),
typeof(RequestExceptionActionProcessorBehavior<,>),
typeof(RequestPreProcessorBehavior<,>),
typeof(RequestPostProcessorBehavior<,>),
typeof(GenericPipelineBehavior<,>)
});
container.Collection.Register(typeof(IRequestPreProcessor<>), new[] { typeof(GenericRequestPreProcessor<>) });
container.Collection.Register(typeof(IRequestPostProcessor<,>), new[] { typeof(GenericRequestPostProcessor<,>), typeof(ConstrainedRequestPostProcessor<,>) });
container.Register(() => new ServiceFactory(container.GetInstance), Lifestyle.Singleton);
}
private static void RegisterHandlers(SimpleInjector.Container container, Type collectionType, Assembly[] assemblies)
{
// we have to do this because by default, generic type definitions (such as the
// Constrained Notification Handler) won't be registered
var handlerTypes = container.GetTypesToRegister(collectionType, assemblies, new TypesToRegisterOptions
{
IncludeGenericTypeDefinitions = true,
IncludeComposites = false,
});
container.Collection.Register(collectionType, handlerTypes);
}
private static IEnumerable<Assembly> GetAssemblies()
{
yield return typeof(IMediator).GetTypeInfo().Assembly;
yield return typeof(DependencyInjectionSystem).GetTypeInfo().Assembly;
}
}
public class DependencyInjectionSystem : Node
{
private static DependencyInjectionSystem _instance;
public static DependencyInjectionSystem Instance
{
get
{
if (_instance == null)
{
_instance = new DependencyInjectionSystem();
}
return _instance;
}
}
private SimpleInjector.Container container;
public override void _EnterTree()
{
base._EnterTree();
container = new SimpleInjector.Container();
var type = typeof(IGlobal); // Get the type of our interface
// Get the assemblies associated with our project
var types = AppDomain.CurrentDomain.GetAssemblies()
.SelectMany(s => s.GetTypes()) // Get all the types
.Where(p => type.IsAssignableFrom(p) && !p.IsInterface); // Filter to find any type that can be assigned to an IModule
foreach (var typ in types)
{
var serviceType = Type.GetType(typ.AssemblyQualifiedName.Replace(typ.Name, $"I{typ.Name}"));
container.RegisterSingleton(typ, typ);
}
// do registrations here
container.RegisterMediator();
//container.Register<InputController>(SimpleInjector.Lifestyle.Singleton);
container.Verify();
}
internal object Resolve(Type fieldType)
{
return container.GetInstance(fieldType);
}
}
public class GameMenu : Control
{
[Inject]
protected GameManager _gameManager;
[Signal]
public delegate void ResetRoom();
// Called when the node enters the scene tree for the first time.
public override void _Ready()
{
this.ResolveDependencies();
//Connect(nameof(ResetRoom), _gameManager, nameof(GameManager.ResetRoom));
}
public void OnResetPressed()
{
EmitSignal(nameof(ResetRoom));
}
//LISTEN for when, Player shouts its controller name and function
private void OpenGameMenu()
{
//Menu.Show()
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment