feat: automatic injection of elements in scene.
This commit is contained in:
+22
-3
@@ -1,11 +1,13 @@
|
||||
#if TOOLS
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Runtime.Loader;
|
||||
using Godot;
|
||||
|
||||
namespace GodotHostTest.addons.godot_di;
|
||||
namespace GodotHostTest.GodotDI.Editor;
|
||||
|
||||
/// <summary>
|
||||
/// Taken from https://github.com/godotengine/godot-proposals/issues/12294
|
||||
@@ -23,7 +25,7 @@ public static class GodotScriptPathCache
|
||||
{
|
||||
if (_assemblyLoadEventHandler != null) return;
|
||||
Initialize();
|
||||
System.Runtime.Loader.AssemblyLoadContext.GetLoadContext(Assembly.GetExecutingAssembly())!
|
||||
AssemblyLoadContext.GetLoadContext(Assembly.GetExecutingAssembly())!
|
||||
.Unloading += _ => { Deinitialize(); };
|
||||
}
|
||||
|
||||
@@ -87,4 +89,21 @@ public static class GodotScriptPathCache
|
||||
InitializeIfNeeded();
|
||||
return PathToType.TryGetValue(path, out type);
|
||||
}
|
||||
}
|
||||
|
||||
public static Type? GetCSharpScriptType(this GodotObject node)
|
||||
{
|
||||
if (node.GetScript().AsGodotObject() is CSharpScript script &&
|
||||
TryGetTypeFromPath(script.ResourcePath, out var type))
|
||||
return type;
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public static bool IsServiceSource(this GodotObject node)
|
||||
{
|
||||
return node.GetScript().AsGodotObject() is CSharpScript script &&
|
||||
TryGetTypeFromPath(script.ResourcePath, out var type) &&
|
||||
type.IsAssignableTo(typeof(ServiceSource));
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -1,16 +1,12 @@
|
||||
#if TOOLS
|
||||
using System;
|
||||
using System.Linq;
|
||||
using Godot;
|
||||
|
||||
namespace GodotHostTest.GodotDI;
|
||||
namespace GodotHostTest.GodotDI.Editor;
|
||||
|
||||
public partial class ScopePickerEditor : EditorProperty
|
||||
{
|
||||
/// <summary>
|
||||
/// The "combo box" that picks a choice from the scopes.
|
||||
/// </summary>
|
||||
private OptionButton _optionButton = new();
|
||||
|
||||
/// <summary>
|
||||
/// The currently chosen type.
|
||||
/// </summary>
|
||||
@@ -21,6 +17,11 @@ public partial class ScopePickerEditor : EditorProperty
|
||||
/// </summary>
|
||||
private string[] _fullyQualifiedNames;
|
||||
|
||||
/// <summary>
|
||||
/// The "combo box" that picks a choice from the scopes.
|
||||
/// </summary>
|
||||
private OptionButton _optionButton = new();
|
||||
|
||||
/// <summary>
|
||||
/// A guard against internal changes while the property is being updated.
|
||||
/// </summary>
|
||||
@@ -92,4 +93,5 @@ public partial class ScopePickerEditor : EditorProperty
|
||||
{
|
||||
_optionButton.Selected = Array.IndexOf(_fullyQualifiedNames, _currentType);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,33 @@
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace GodotHostTest.GodotDI;
|
||||
|
||||
public static class EnumerableExtensions
|
||||
{
|
||||
public enum SingleFailureReason
|
||||
{
|
||||
LessThanOne,
|
||||
MoreThanOne
|
||||
}
|
||||
|
||||
public static T? Single<T>(this IEnumerable<T> enumerable, out SingleFailureReason? failureReason)
|
||||
where T : class
|
||||
{
|
||||
using var enumerator = enumerable.GetEnumerator();
|
||||
if (!enumerator.MoveNext())
|
||||
{
|
||||
failureReason = SingleFailureReason.LessThanOne;
|
||||
return null;
|
||||
}
|
||||
|
||||
var value = enumerator.Current;
|
||||
if (enumerator.MoveNext())
|
||||
{
|
||||
failureReason = SingleFailureReason.MoreThanOne;
|
||||
return null;
|
||||
}
|
||||
|
||||
failureReason = null;
|
||||
return value;
|
||||
}
|
||||
}
|
||||
@@ -1,64 +0,0 @@
|
||||
namespace GodotHostTest.addons.godot_di;
|
||||
|
||||
// RandomIntEditor.cs
|
||||
#if TOOLS
|
||||
using Godot;
|
||||
|
||||
public partial class RandomIntEditor : EditorProperty
|
||||
{
|
||||
// The main control for editing the property.
|
||||
private Button _propertyControl = new Button();
|
||||
|
||||
// An internal value of the property.
|
||||
private int _currentValue = 0;
|
||||
|
||||
// A guard against internal changes when the property is updated.
|
||||
private bool _updating = false;
|
||||
|
||||
public RandomIntEditor()
|
||||
{
|
||||
// Add the control as a direct child of EditorProperty node.
|
||||
AddChild(_propertyControl);
|
||||
// Make sure the control is able to retain the focus.
|
||||
AddFocusable(_propertyControl);
|
||||
// Setup the initial state and connect to the signal to track changes.
|
||||
RefreshControlText();
|
||||
_propertyControl.Pressed += OnButtonPressed;
|
||||
}
|
||||
|
||||
private void OnButtonPressed()
|
||||
{
|
||||
// Ignore the signal if the property is currently being updated.
|
||||
if (_updating)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Generate a new random integer between 0 and 99.
|
||||
_currentValue = (int)GD.Randi() % 100;
|
||||
RefreshControlText();
|
||||
EmitChanged(GetEditedProperty(), _currentValue);
|
||||
}
|
||||
|
||||
public override void _UpdateProperty()
|
||||
{
|
||||
// Read the current value from the property.
|
||||
var newValue = (int)GetEditedObject().Get(GetEditedProperty());
|
||||
if (newValue == _currentValue)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Update the control with the new value.
|
||||
_updating = true;
|
||||
_currentValue = newValue;
|
||||
RefreshControlText();
|
||||
_updating = false;
|
||||
}
|
||||
|
||||
private void RefreshControlText()
|
||||
{
|
||||
_propertyControl.Text = $"Value: {_currentValue}";
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -1 +0,0 @@
|
||||
uid://db526cjmnd4q7
|
||||
@@ -9,17 +9,22 @@ namespace GodotHostTest.GodotDI;
|
||||
[Icon("res://addons/GodotDI/ServiceSource.svg")]
|
||||
public partial class ServiceSource : Node
|
||||
{
|
||||
[Export] private string _serviceScope = typeof(RootScope).AssemblyQualifiedName!;
|
||||
private static readonly string RootScopeQualifiedName = typeof(RootScope).AssemblyQualifiedName!;
|
||||
[Export] private string _serviceScope = RootScopeQualifiedName;
|
||||
[Export] protected Node?[] InjectedNodes = [];
|
||||
|
||||
internal void ResolveInjectedNodes(IServiceProvider serviceProvider)
|
||||
{
|
||||
// if this service source must also act as a scope, create the scope and use its service provider
|
||||
if (_serviceScope != "")
|
||||
if (_serviceScope != RootScopeQualifiedName)
|
||||
{
|
||||
serviceProvider = serviceProvider
|
||||
.CreateScope()
|
||||
.ServiceProvider;
|
||||
var serviceProviderCreator = serviceProvider.GetRequiredService<Func<IProvider, IServiceProvider>>();
|
||||
var scopedProvider = serviceProvider.GetRequiredService<IProvider>()
|
||||
.GetScopedProvider(ScopeTypesAndNames.GetType(_serviceScope));
|
||||
serviceProvider = serviceProviderCreator(scopedProvider);
|
||||
// serviceProvider = serviceProvider
|
||||
// .CreateScope()
|
||||
// .ServiceProvider;
|
||||
}
|
||||
|
||||
// resolve the injected nodes against the chosen service provider
|
||||
|
||||
@@ -4,4 +4,4 @@ name="GodotDI"
|
||||
description=""
|
||||
author="owof games"
|
||||
version="0.1"
|
||||
script="GodotDI.cs"
|
||||
script="Editor/Plugin.cs"
|
||||
|
||||
Reference in New Issue
Block a user