feat: automatic injection of elements in scene.
This commit is contained in:
@@ -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!;
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
namespace GodotHostTest.Interfaces;
|
||||
|
||||
public interface ILevel
|
||||
{
|
||||
}
|
||||
+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"
|
||||
|
||||
+5
-137
@@ -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")]
|
||||
|
||||
Reference in New Issue
Block a user