feat: aetherbind, first source generator
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
using OwofGames.GodotLume;
|
||||
|
||||
namespace GodotHostTest.GodotDI;
|
||||
namespace GodotHostTest.AetherBind;
|
||||
|
||||
public static class BuilderExtensions
|
||||
{
|
||||
+1
-1
@@ -7,7 +7,7 @@ using System.Reflection;
|
||||
using System.Runtime.Loader;
|
||||
using Godot;
|
||||
|
||||
namespace GodotHostTest.GodotDI.Editor;
|
||||
namespace GodotHostTest.AetherBind.Editor;
|
||||
|
||||
/// <summary>
|
||||
/// Taken from https://github.com/godotengine/godot-proposals/issues/12294
|
||||
@@ -2,9 +2,10 @@
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using Godot;
|
||||
using OwofGames.AetherBind;
|
||||
using Array = Godot.Collections.Array;
|
||||
|
||||
namespace GodotHostTest.GodotDI.Editor;
|
||||
namespace GodotHostTest.AetherBind.Editor;
|
||||
|
||||
[Tool]
|
||||
public partial class Plugin : EditorPlugin
|
||||
+1
-1
@@ -1,7 +1,7 @@
|
||||
#if TOOLS
|
||||
using Godot;
|
||||
|
||||
namespace GodotHostTest.GodotDI.Editor;
|
||||
namespace GodotHostTest.AetherBind.Editor;
|
||||
|
||||
// it's inside ServiceSource so that it can safely access nameof(_serviceScope)
|
||||
public partial class ScopeInspectorPlugin : EditorInspectorPlugin
|
||||
+1
-1
@@ -3,7 +3,7 @@ using System;
|
||||
using System.Linq;
|
||||
using Godot;
|
||||
|
||||
namespace GodotHostTest.GodotDI.Editor;
|
||||
namespace GodotHostTest.AetherBind.Editor;
|
||||
|
||||
public partial class ScopePickerEditor : EditorProperty
|
||||
{
|
||||
@@ -1,6 +1,6 @@
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace GodotHostTest.GodotDI;
|
||||
namespace GodotHostTest.AetherBind;
|
||||
|
||||
public static class EnumerableExtensions
|
||||
{
|
||||
@@ -1,7 +1,7 @@
|
||||
using System;
|
||||
using Godot;
|
||||
|
||||
namespace GodotHostTest.GodotDI;
|
||||
namespace GodotHostTest.AetherBind;
|
||||
|
||||
public interface ISceneInstantiator
|
||||
{
|
||||
@@ -1,4 +1,4 @@
|
||||
namespace GodotHostTest.GodotDI;
|
||||
namespace GodotHostTest.AetherBind;
|
||||
|
||||
public interface IValueGetter<out T>
|
||||
{
|
||||
@@ -1,4 +1,4 @@
|
||||
namespace GodotHostTest.GodotDI;
|
||||
namespace GodotHostTest.AetherBind;
|
||||
|
||||
public interface IValueSetter<in T>
|
||||
{
|
||||
@@ -0,0 +1,18 @@
|
||||
TOC:
|
||||
|
||||
- what GodotDI offers (in short):
|
||||
- logging
|
||||
- configuration
|
||||
- possibility to attach extra DI-based services like telemetry)
|
||||
- minimal description of what problems DI tackles
|
||||
- minimal example with logging, configuration, decoupling of components
|
||||
- how to install
|
||||
- creation of the root service source
|
||||
- example
|
||||
- scopes
|
||||
- why
|
||||
- definition
|
||||
- deep dive into why it's all done at composition root
|
||||
- using extension methods to split the code as necessary
|
||||
- sending data into a scope
|
||||
- initializing data in the scope
|
||||
@@ -5,7 +5,7 @@ using OwofGames.GodotHost;
|
||||
using OwofGames.GodotLume;
|
||||
using OwofGames.GodotLume.Microsoft.DependencyInjection;
|
||||
|
||||
namespace GodotHostTest.GodotDI;
|
||||
namespace GodotHostTest.AetherBind;
|
||||
|
||||
/// <summary>
|
||||
/// The base class for a root scope. Implement this class and its abstract methods to kick off the DI system.
|
||||
@@ -4,7 +4,7 @@ using Godot;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using OwofGames.GodotLume;
|
||||
|
||||
namespace GodotHostTest.GodotDI;
|
||||
namespace GodotHostTest.AetherBind;
|
||||
|
||||
internal class SceneInstantiator(IProvider provider) : ISceneInstantiator
|
||||
{
|
||||
+1
-1
@@ -1,7 +1,7 @@
|
||||
using System;
|
||||
using Godot;
|
||||
|
||||
namespace GodotHostTest.GodotDI;
|
||||
namespace GodotHostTest.AetherBind;
|
||||
|
||||
public static class SceneInstantiatorExtensions
|
||||
{
|
||||
@@ -7,7 +7,7 @@ using System.Runtime.Loader;
|
||||
using Godot;
|
||||
using OwofGames.GodotLume;
|
||||
|
||||
namespace GodotHostTest.GodotDI;
|
||||
namespace GodotHostTest.AetherBind;
|
||||
|
||||
public static class ScopeTypesAndNames
|
||||
{
|
||||
@@ -1,18 +1,18 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using Godot;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using OwofGames.AetherBind;
|
||||
using OwofGames.GodotLume;
|
||||
|
||||
namespace GodotHostTest.GodotDI;
|
||||
namespace GodotHostTest.AetherBind;
|
||||
|
||||
[Icon("res://addons/GodotDI/ServiceSource.svg")]
|
||||
[Icon("res://addons/AetherBind/ServiceSource.svg")]
|
||||
public partial class ServiceSource : Node
|
||||
{
|
||||
private static readonly string RootScopeQualifiedName = typeof(RootScope).AssemblyQualifiedName!;
|
||||
[Export] private string _serviceScope = RootScopeQualifiedName;
|
||||
[Export] protected Node?[] InjectedNodes = [];
|
||||
[Export] private string _serviceScope = RootScopeQualifiedName;
|
||||
|
||||
internal void ResolveInjectedNodes(IProvider provider, Delegate? onScopeCreated)
|
||||
{
|
||||
@@ -25,7 +25,7 @@ public partial class ServiceSource : Node
|
||||
var serviceScope = ScopeTypesAndNames.GetType(_serviceScope);
|
||||
provider = provider.GetScopedProvider(serviceScope);
|
||||
// invoke onScopeCreated, if present
|
||||
// TODO: replace with a source code generation by turning this method private partial with Action<IProvider> argument, and every invocation site calls the necessary provider.Get<...> to build the argument list
|
||||
// TODO: replace with a source code generation by turning this method private with Action<IProvider> argument, and every invocation site calls the necessary provider.Get<...> to build the argument list
|
||||
if (onScopeCreated != null)
|
||||
{
|
||||
var parameters = onScopeCreated.Method
|
||||
@@ -43,37 +43,42 @@ public partial class ServiceSource : Node
|
||||
}
|
||||
|
||||
// resolve the injected nodes against the chosen service provider
|
||||
// TODO: move to source generator, make it the only way for injection
|
||||
foreach (var node in InjectedNodes)
|
||||
{
|
||||
if (node == null) continue;
|
||||
logger.LogTrace("Injecting {Node}.", node.Name);
|
||||
var nodeType = node.GetType();
|
||||
foreach (var field in nodeType
|
||||
.GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic))
|
||||
|
||||
if (node is IInjectable injectable)
|
||||
{
|
||||
if (field.GetCustomAttribute<InjectAttribute>() == null) continue;
|
||||
var fieldType = field.FieldType;
|
||||
var service = provider.Get(fieldType);
|
||||
field.SetValue(node, service);
|
||||
injectable.Inject(provider);
|
||||
}
|
||||
|
||||
foreach (var method in nodeType.GetMethods(BindingFlags.Instance | BindingFlags.Public |
|
||||
BindingFlags.NonPublic))
|
||||
{
|
||||
if (method.GetCustomAttribute<InjectAttribute>() == null) continue;
|
||||
var parameters = method.GetParameters();
|
||||
var values = new object?[parameters.Length];
|
||||
var i = 0;
|
||||
foreach (var parameter in parameters)
|
||||
{
|
||||
var parameterType = parameter.ParameterType;
|
||||
var service = provider.Get(parameterType);
|
||||
values[i++] = service;
|
||||
}
|
||||
|
||||
method.Invoke(node, values);
|
||||
}
|
||||
// var nodeType = node.GetType();
|
||||
// foreach (var field in nodeType
|
||||
// .GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic))
|
||||
// {
|
||||
// if (field.GetCustomAttribute<InjectAttribute>() == null) continue;
|
||||
// var fieldType = field.FieldType;
|
||||
// var service = provider.Get(fieldType);
|
||||
// field.SetValue(node, service);
|
||||
// }
|
||||
//
|
||||
// foreach (var method in nodeType.GetMethods(BindingFlags.Instance | BindingFlags.Public |
|
||||
// BindingFlags.NonPublic))
|
||||
// {
|
||||
// if (method.GetCustomAttribute<InjectAttribute>() == null) continue;
|
||||
// var parameters = method.GetParameters();
|
||||
// var values = new object?[parameters.Length];
|
||||
// var i = 0;
|
||||
// foreach (var parameter in parameters)
|
||||
// {
|
||||
// var parameterType = parameter.ParameterType;
|
||||
// var service = provider.Get(parameterType);
|
||||
// values[i++] = service;
|
||||
// }
|
||||
//
|
||||
// method.Invoke(node, values);
|
||||
// }
|
||||
}
|
||||
}
|
||||
|
||||
|
Before Width: | Height: | Size: 259 B After Width: | Height: | Size: 259 B |
+3
-3
@@ -3,15 +3,15 @@
|
||||
importer="texture"
|
||||
type="CompressedTexture2D"
|
||||
uid="uid://ce5hi46doaiv8"
|
||||
path="res://.godot/imported/ServiceSource.svg-ca2976082d4f895e226f23d45377b764.ctex"
|
||||
path="res://.godot/imported/ServiceSource.svg-22939ab8c3bebd4d414fabd470fcc1cf.ctex"
|
||||
metadata={
|
||||
"vram_texture": false
|
||||
}
|
||||
|
||||
[deps]
|
||||
|
||||
source_file="res://addons/GodotDI/ServiceSource.svg"
|
||||
dest_files=["res://.godot/imported/ServiceSource.svg-ca2976082d4f895e226f23d45377b764.ctex"]
|
||||
source_file="res://addons/AetherBind/ServiceSource.svg"
|
||||
dest_files=["res://.godot/imported/ServiceSource.svg-22939ab8c3bebd4d414fabd470fcc1cf.ctex"]
|
||||
|
||||
[params]
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
using System;
|
||||
|
||||
namespace GodotHostTest.GodotDI;
|
||||
namespace GodotHostTest.AetherBind;
|
||||
|
||||
/// <summary>
|
||||
/// An object that allows communication through scopes, by providing a couple getter/setter that can be injected in
|
||||
@@ -1,6 +1,6 @@
|
||||
[plugin]
|
||||
|
||||
name="GodotDI"
|
||||
name="AetherBind"
|
||||
description=""
|
||||
author="owof games"
|
||||
version="0.1"
|
||||
@@ -1,6 +0,0 @@
|
||||
using System;
|
||||
|
||||
namespace GodotHostTest.GodotDI;
|
||||
|
||||
[AttributeUsage(AttributeTargets.Field | AttributeTargets.Method)]
|
||||
public class InjectAttribute: Attribute;
|
||||
@@ -1 +0,0 @@
|
||||
uid://mshffj1jlgi7
|
||||
Reference in New Issue
Block a user