diff --git a/Game/GameRootServiceSource.cs b/Game/LevelServiceSource.cs
similarity index 87%
rename from Game/GameRootServiceSource.cs
rename to Game/LevelServiceSource.cs
index 837120d..ed30e05 100644
--- a/Game/GameRootServiceSource.cs
+++ b/Game/LevelServiceSource.cs
@@ -5,7 +5,7 @@ using Microsoft.Extensions.DependencyInjection;
namespace GodotHostTest.Game;
-public partial class GameRootServiceSource : RootServiceSource
+public partial class LevelServiceSource : RootServiceSource
{
[Export] private TargetSpawner _targetSpawner = null!;
diff --git a/Game/GameRootServiceSource.cs.uid b/Game/LevelServiceSource.cs.uid
similarity index 100%
rename from Game/GameRootServiceSource.cs.uid
rename to Game/LevelServiceSource.cs.uid
diff --git a/Interfaces/ILevel.cs b/Interfaces/ILevel.cs
new file mode 100644
index 0000000..7f05d86
--- /dev/null
+++ b/Interfaces/ILevel.cs
@@ -0,0 +1,5 @@
+namespace GodotHostTest.Interfaces;
+
+public interface ILevel
+{
+}
\ No newline at end of file
diff --git a/addons/GodotDI/GodotScriptPathCache.cs b/addons/GodotDI/Editor/GodotScriptPathCache.cs
similarity index 80%
rename from addons/GodotDI/GodotScriptPathCache.cs
rename to addons/GodotDI/Editor/GodotScriptPathCache.cs
index 2465221..d93a620 100644
--- a/addons/GodotDI/GodotScriptPathCache.cs
+++ b/addons/GodotDI/Editor/GodotScriptPathCache.cs
@@ -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;
///
/// 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);
}
-}
\ No newline at end of file
+
+ 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
\ No newline at end of file
diff --git a/addons/GodotDI/GodotScriptPathCache.cs.uid b/addons/GodotDI/Editor/GodotScriptPathCache.cs.uid
similarity index 100%
rename from addons/GodotDI/GodotScriptPathCache.cs.uid
rename to addons/GodotDI/Editor/GodotScriptPathCache.cs.uid
diff --git a/addons/GodotDI/GodotDI.cs.uid b/addons/GodotDI/Editor/Plugin.cs.uid
similarity index 100%
rename from addons/GodotDI/GodotDI.cs.uid
rename to addons/GodotDI/Editor/Plugin.cs.uid
diff --git a/addons/GodotDI/ScopeInspectorPlugin.cs.uid b/addons/GodotDI/Editor/ScopeInspectorPlugin.cs.uid
similarity index 100%
rename from addons/GodotDI/ScopeInspectorPlugin.cs.uid
rename to addons/GodotDI/Editor/ScopeInspectorPlugin.cs.uid
diff --git a/addons/GodotDI/ScopePickerEditor.cs b/addons/GodotDI/Editor/ScopePickerEditor.cs
similarity index 95%
rename from addons/GodotDI/ScopePickerEditor.cs
rename to addons/GodotDI/Editor/ScopePickerEditor.cs
index 5cce9c4..6b56a9d 100644
--- a/addons/GodotDI/ScopePickerEditor.cs
+++ b/addons/GodotDI/Editor/ScopePickerEditor.cs
@@ -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
{
- ///
- /// The "combo box" that picks a choice from the scopes.
- ///
- private OptionButton _optionButton = new();
-
///
/// The currently chosen type.
///
@@ -21,6 +17,11 @@ public partial class ScopePickerEditor : EditorProperty
///
private string[] _fullyQualifiedNames;
+ ///
+ /// The "combo box" that picks a choice from the scopes.
+ ///
+ private OptionButton _optionButton = new();
+
///
/// A guard against internal changes while the property is being updated.
///
@@ -92,4 +93,5 @@ public partial class ScopePickerEditor : EditorProperty
{
_optionButton.Selected = Array.IndexOf(_fullyQualifiedNames, _currentType);
}
-}
\ No newline at end of file
+}
+#endif
\ No newline at end of file
diff --git a/addons/GodotDI/ScopePickerEditor.cs.uid b/addons/GodotDI/Editor/ScopePickerEditor.cs.uid
similarity index 100%
rename from addons/GodotDI/ScopePickerEditor.cs.uid
rename to addons/GodotDI/Editor/ScopePickerEditor.cs.uid
diff --git a/addons/GodotDI/EnumerableExtensions.cs b/addons/GodotDI/EnumerableExtensions.cs
new file mode 100644
index 0000000..bc5af7f
--- /dev/null
+++ b/addons/GodotDI/EnumerableExtensions.cs
@@ -0,0 +1,33 @@
+using System.Collections.Generic;
+
+namespace GodotHostTest.GodotDI;
+
+public static class EnumerableExtensions
+{
+ public enum SingleFailureReason
+ {
+ LessThanOne,
+ MoreThanOne
+ }
+
+ public static T? Single(this IEnumerable 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;
+ }
+}
\ No newline at end of file
diff --git a/addons/GodotDI/RandomIntEditor.cs b/addons/GodotDI/RandomIntEditor.cs
deleted file mode 100644
index c7033ea..0000000
--- a/addons/GodotDI/RandomIntEditor.cs
+++ /dev/null
@@ -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
\ No newline at end of file
diff --git a/addons/GodotDI/RandomIntEditor.cs.uid b/addons/GodotDI/RandomIntEditor.cs.uid
deleted file mode 100644
index 25a0380..0000000
--- a/addons/GodotDI/RandomIntEditor.cs.uid
+++ /dev/null
@@ -1 +0,0 @@
-uid://db526cjmnd4q7
diff --git a/addons/GodotDI/ServiceSource.cs b/addons/GodotDI/ServiceSource.cs
index 232382a..6b16d28 100644
--- a/addons/GodotDI/ServiceSource.cs
+++ b/addons/GodotDI/ServiceSource.cs
@@ -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>();
+ var scopedProvider = serviceProvider.GetRequiredService()
+ .GetScopedProvider(ScopeTypesAndNames.GetType(_serviceScope));
+ serviceProvider = serviceProviderCreator(scopedProvider);
+ // serviceProvider = serviceProvider
+ // .CreateScope()
+ // .ServiceProvider;
}
// resolve the injected nodes against the chosen service provider
diff --git a/addons/GodotDI/plugin.cfg b/addons/GodotDI/plugin.cfg
index 717f7df..8e61c65 100644
--- a/addons/GodotDI/plugin.cfg
+++ b/addons/GodotDI/plugin.cfg
@@ -4,4 +4,4 @@ name="GodotDI"
description=""
author="owof games"
version="0.1"
-script="GodotDI.cs"
+script="Editor/Plugin.cs"
diff --git a/root_scene.tscn b/root_scene.tscn
index ddd7f09..0d089b5 100644
--- a/root_scene.tscn
+++ b/root_scene.tscn
@@ -1,142 +1,10 @@
[gd_scene format=3 uid="uid://vsburk37p4u"]
-[ext_resource type="PackedScene" uid="uid://3v8kq1rfwhmr" path="res://Game/target.tscn" id="2_c77vg"]
-[ext_resource type="Script" uid="uid://cxfrtglku2gfa" path="res://Game/TargetSpawner.cs" id="3_iqet6"]
-[ext_resource type="Script" uid="uid://dk578xnlxjwrr" path="res://Game/GameRootScope.cs" id="3_t2jh2"]
-[ext_resource type="Script" uid="uid://bgrjeadxhgmvi" path="res://Game/Score.cs" id="4_t2jh2"]
-[ext_resource type="Texture2D" uid="uid://y1ros3y7hag2" path="res://icon.svg" id="5_4ty2a"]
-[ext_resource type="Script" uid="uid://ce7gnp1lcrrdv" path="res://Game/Turret.cs" id="6_rckqj"]
-[ext_resource type="PackedScene" uid="uid://brbufibn7hi3o" path="res://Game/projectile.tscn" id="7_rckqj"]
-
-[sub_resource type="Animation" id="Animation_bbjqm"]
-length = 0.001
-tracks/0/type = "value"
-tracks/0/imported = false
-tracks/0/enabled = true
-tracks/0/path = NodePath("Score:offset_transform_position")
-tracks/0/interp = 1
-tracks/0/loop_wrap = true
-tracks/0/keys = {
-"times": PackedFloat32Array(0),
-"transitions": PackedFloat32Array(1),
-"update": 0,
-"values": [Vector2(0, 0)]
-}
-tracks/1/type = "value"
-tracks/1/imported = false
-tracks/1/enabled = true
-tracks/1/path = NodePath("Score:offset_transform_rotation")
-tracks/1/interp = 1
-tracks/1/loop_wrap = true
-tracks/1/keys = {
-"times": PackedFloat32Array(0),
-"transitions": PackedFloat32Array(1),
-"update": 0,
-"values": [0.0]
-}
-
-[sub_resource type="Animation" id="Animation_4ty2a"]
-resource_name = "wiggle"
-length = 0.3
-tracks/0/type = "value"
-tracks/0/imported = false
-tracks/0/enabled = true
-tracks/0/path = NodePath("Score:offset_transform_position")
-tracks/0/interp = 1
-tracks/0/loop_wrap = true
-tracks/0/keys = {
-"times": PackedFloat32Array(0, 0.049999997, 0.099999994, 0.15, 0.2, 0.24999999),
-"transitions": PackedFloat32Array(1, 1, 1, 1, 1, 1),
-"update": 0,
-"values": [Vector2(0, 0), Vector2(10, -10), Vector2(-10, -10), Vector2(10, 10), Vector2(-10, 10), Vector2(0, 0)]
-}
-tracks/1/type = "value"
-tracks/1/imported = false
-tracks/1/enabled = true
-tracks/1/path = NodePath("Score:offset_transform_rotation")
-tracks/1/interp = 1
-tracks/1/loop_wrap = true
-tracks/1/keys = {
-"times": PackedFloat32Array(0, 0.049999997, 0.099999994, 0.15, 0.2, 0.24999999),
-"transitions": PackedFloat32Array(1, 1, 1, 1, 1, 1),
-"update": 0,
-"values": [0.0, 0.08726646, -0.08726646, 0.08726646, -0.08726646, 0.0]
-}
-
-[sub_resource type="AnimationLibrary" id="AnimationLibrary_rckqj"]
-_data = {
-&"RESET": SubResource("Animation_bbjqm"),
-&"wiggle": SubResource("Animation_4ty2a")
-}
+[ext_resource type="Script" uid="uid://bvjvojer872c8" path="res://Game/Root.cs" id="1_iqet6"]
+[ext_resource type="PackedScene" uid="uid://xfd48ep5qi1k" path="res://Game/level.tscn" id="3_bbjqm"]
[node name="Node2D" type="Node2D" unique_id=920849082]
+script = ExtResource("1_iqet6")
+_levelScene = ExtResource("3_bbjqm")
-[node name="RootScope" type="Node" parent="." unique_id=1453141084 node_paths=PackedStringArray("_targetSpawner", "InjectedNodes")]
-script = ExtResource("3_t2jh2")
-_targetSpawner = NodePath("../Spawner")
-InjectedNodes = [NodePath("../Turret"), NodePath("../Target"), NodePath("../Target2"), NodePath("../Target3"), NodePath("../Target4"), NodePath("../Target5"), NodePath("../Target6"), NodePath("../Spawner"), NodePath("../Score")]
-
-[node name="Target" parent="." unique_id=2101558052 instance=ExtResource("2_c77vg")]
-position = Vector2(198, 143)
-TimeOutDurationInSeconds = 2.0
-
-[node name="Target2" parent="." unique_id=1480287846 instance=ExtResource("2_c77vg")]
-position = Vector2(669, 64)
-TimeOutDurationInSeconds = 2.0
-
-[node name="Target3" parent="." unique_id=242951997 instance=ExtResource("2_c77vg")]
-position = Vector2(1060, 263)
-TimeOutDurationInSeconds = 2.0
-
-[node name="Target4" parent="." unique_id=1190782819 instance=ExtResource("2_c77vg")]
-position = Vector2(961, 620)
-TimeOutDurationInSeconds = 2.0
-
-[node name="Target5" parent="." unique_id=1183803617 instance=ExtResource("2_c77vg")]
-position = Vector2(469, 591)
-TimeOutDurationInSeconds = 2.0
-
-[node name="Target6" parent="." unique_id=2017833482 instance=ExtResource("2_c77vg")]
-position = Vector2(53, 417)
-TimeOutDurationInSeconds = 2.0
-
-[node name="Spawner" type="Node2D" parent="." unique_id=1331368036 node_paths=PackedStringArray("Timer")]
-script = ExtResource("3_iqet6")
-TimeBetweenSpawns = 1.5
-Timer = NodePath("Timer")
-
-[node name="Timer" type="Timer" parent="Spawner" unique_id=1142098929]
-
-[node name="Score" type="ColorRect" parent="." unique_id=1990204205 node_paths=PackedStringArray("_animationPlayer", "_label")]
-offset_right = 200.0
-offset_bottom = 40.0
-offset_transform_enabled = true
-color = Color(1, 1, 1, 0.2784314)
-script = ExtResource("4_t2jh2")
-_animationPlayer = NodePath("../AnimationPlayer")
-_label = NodePath("Label")
-
-[node name="Label" type="Label" parent="Score" unique_id=1929317028]
-layout_mode = 1
-anchors_preset = -1
-anchor_right = 1.0
-anchor_bottom = 1.0
-offset_left = 10.0
-offset_right = -10.0
-grow_horizontal = 2
-grow_vertical = 2
-theme_override_colors/font_color = Color(0, 0, 0, 1)
-text = "Score: 0"
-vertical_alignment = 1
-
-[node name="AnimationPlayer" type="AnimationPlayer" parent="." unique_id=1749711689]
-libraries/ = SubResource("AnimationLibrary_rckqj")
-
-[node name="Turret" type="Sprite2D" parent="." unique_id=1932581411]
-modulate = Color(1.92523e-07, 0.88004553, 0.8802661, 1)
-position = Vector2(539, 307)
-texture = ExtResource("5_4ty2a")
-script = ExtResource("6_rckqj")
-_projectilePackedScene = ExtResource("7_rckqj")
-
-[connection signal="timeout" from="Spawner/Timer" to="Spawner" method="OnTimer"]
+[node name="Level" parent="." unique_id=1331632726 instance=ExtResource("3_bbjqm")]