feat: aetherbind, first source generator
This commit is contained in:
+1
-1
@@ -3,7 +3,7 @@
|
|||||||
<CLASSES />
|
<CLASSES />
|
||||||
<JAVADOC />
|
<JAVADOC />
|
||||||
<SOURCES>
|
<SOURCES>
|
||||||
<root url="file://$APPLICATION_PLUGINS_DIR$/GdScript/extracted/Master" />
|
<root url="file://$APPLICATION_PLUGINS_DIR$/Godot/extracted/4.7" />
|
||||||
</SOURCES>
|
</SOURCES>
|
||||||
</library>
|
</library>
|
||||||
</component>
|
</component>
|
||||||
@@ -1,21 +0,0 @@
|
|||||||
using Godot;
|
|
||||||
using GodotHostTest.GodotDI;
|
|
||||||
using GodotHostTest.Interfaces;
|
|
||||||
using OwofGames.GodotLume;
|
|
||||||
|
|
||||||
namespace GodotHostTest.Game;
|
|
||||||
|
|
||||||
public partial class GameServiceSource : RootServiceSource
|
|
||||||
{
|
|
||||||
[Export] private LevelsData _levelsData = null!;
|
|
||||||
|
|
||||||
protected override void Configure(Builder builder)
|
|
||||||
{
|
|
||||||
builder
|
|
||||||
.AddSingleton<ICurrentLevel, CurrentLevel>()
|
|
||||||
.AddInstance<ILevelDataProvider, LevelsData>(_levelsData)
|
|
||||||
.AddValueProvider<ILevel, RootScope, LevelScope>()
|
|
||||||
.AddValueProvider<ITargetCollector, LevelScope>()
|
|
||||||
.AddValueProvider<ITargetSpawner, LevelScope>();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
using GodotHostTest.Interfaces;
|
using GodotHostTest.Interfaces;
|
||||||
|
|
||||||
namespace GodotHostTest.Game;
|
namespace GodotHostTest.Game.Level;
|
||||||
|
|
||||||
public class CurrentLevel : ICurrentLevel
|
public class CurrentLevel : ICurrentLevel
|
||||||
{
|
{
|
||||||
@@ -2,7 +2,7 @@ using System;
|
|||||||
using Godot;
|
using Godot;
|
||||||
using GodotHostTest.Interfaces;
|
using GodotHostTest.Interfaces;
|
||||||
|
|
||||||
namespace GodotHostTest.Game;
|
namespace GodotHostTest.Game.Level;
|
||||||
|
|
||||||
[GlobalClass]
|
[GlobalClass]
|
||||||
public partial class LevelData : Resource, ILevel
|
public partial class LevelData : Resource, ILevel
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
using OwofGames.GodotLume;
|
||||||
|
|
||||||
|
namespace GodotHostTest.Game.Level;
|
||||||
|
|
||||||
|
public class LevelScope : RootScope;
|
||||||
@@ -1,9 +1,11 @@
|
|||||||
using Godot;
|
using Godot;
|
||||||
using GodotHostTest.GodotDI;
|
using GodotHostTest.AetherBind;
|
||||||
|
using GodotHostTest.Game.Target;
|
||||||
using GodotHostTest.Interfaces;
|
using GodotHostTest.Interfaces;
|
||||||
using OwofGames.GodotLume;
|
using OwofGames.GodotLume;
|
||||||
|
using ServiceSource = GodotHostTest.AetherBind.ServiceSource;
|
||||||
|
|
||||||
namespace GodotHostTest.Game;
|
namespace GodotHostTest.Game.Level;
|
||||||
|
|
||||||
public partial class LevelServiceSource : ServiceSource
|
public partial class LevelServiceSource : ServiceSource
|
||||||
{
|
{
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
using GodotHostTest.AetherBind;
|
||||||
|
using GodotHostTest.Interfaces;
|
||||||
|
using OwofGames.GodotLume;
|
||||||
|
|
||||||
|
namespace GodotHostTest.Game.Level;
|
||||||
|
|
||||||
|
public static class LevelServices
|
||||||
|
{
|
||||||
|
public static void AddLevelServices(this Builder builder, LevelsData levelsData)
|
||||||
|
{
|
||||||
|
builder
|
||||||
|
// current level / level data management
|
||||||
|
.AddSingleton<ICurrentLevel, CurrentLevel>()
|
||||||
|
.AddInstance<ILevelDataProvider, LevelsData>(levelsData)
|
||||||
|
// value providers to send data into level scope
|
||||||
|
.AddValueProvider<ILevel, RootScope, LevelScope>()
|
||||||
|
// value provider for level scope setup
|
||||||
|
.AddValueProvider<ITargetCollector, LevelScope>()
|
||||||
|
.AddValueProvider<ITargetSpawner, LevelScope>();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
using Godot;
|
using Godot;
|
||||||
using GodotHostTest.Interfaces;
|
using GodotHostTest.Interfaces;
|
||||||
|
|
||||||
namespace GodotHostTest.Game;
|
namespace GodotHostTest.Game.Level;
|
||||||
|
|
||||||
[GlobalClass]
|
[GlobalClass]
|
||||||
public partial class LevelsData : Resource, ILevelDataProvider
|
public partial class LevelsData : Resource, ILevelDataProvider
|
||||||
@@ -1,5 +0,0 @@
|
|||||||
using OwofGames.GodotLume;
|
|
||||||
|
|
||||||
namespace GodotHostTest.Game;
|
|
||||||
|
|
||||||
public class LevelScope : RootScope;
|
|
||||||
@@ -1,16 +1,18 @@
|
|||||||
using Godot;
|
using Godot;
|
||||||
using GodotHostTest.GodotDI;
|
using GodotHostTest.AetherBind;
|
||||||
using GodotHostTest.Helpers;
|
using GodotHostTest.Helpers;
|
||||||
using GodotHostTest.Interfaces;
|
using GodotHostTest.Interfaces;
|
||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
|
using OwofGames.AetherBind;
|
||||||
using R3;
|
using R3;
|
||||||
|
|
||||||
namespace GodotHostTest.Game;
|
namespace GodotHostTest.Game.Projectile;
|
||||||
|
|
||||||
|
[Injected]
|
||||||
public partial class Projectile : Node2D
|
public partial class Projectile : Node2D
|
||||||
{
|
{
|
||||||
[Inject] private readonly ILogger<Projectile> _logger = null!;
|
[Inject] private ILogger<Projectile> _logger = null!;
|
||||||
[Inject] private readonly IValueGetter<ITargetSpawner> _targetSpawner = null!;
|
[Inject] private IValueGetter<ITargetSpawner> _targetSpawner = null!;
|
||||||
|
|
||||||
// Called when the node enters the scene tree for the first time.
|
// Called when the node enters the scene tree for the first time.
|
||||||
public override void _Ready()
|
public override void _Ready()
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
using Godot;
|
||||||
|
using GodotHostTest.Game.Level;
|
||||||
|
using OwofGames.GodotLume;
|
||||||
|
using RootServiceSource = GodotHostTest.AetherBind.RootServiceSource;
|
||||||
|
|
||||||
|
namespace GodotHostTest.Game.Root;
|
||||||
|
|
||||||
|
public partial class GameServiceSource : RootServiceSource
|
||||||
|
{
|
||||||
|
[Export] private LevelsData _levelsData = null!;
|
||||||
|
|
||||||
|
protected override void Configure(Builder builder)
|
||||||
|
{
|
||||||
|
builder.AddLevelServices(_levelsData);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,15 +1,17 @@
|
|||||||
using Godot;
|
using Godot;
|
||||||
using GodotHostTest.GodotDI;
|
using GodotHostTest.AetherBind;
|
||||||
using GodotHostTest.Interfaces;
|
using GodotHostTest.Interfaces;
|
||||||
|
using OwofGames.AetherBind;
|
||||||
|
|
||||||
namespace GodotHostTest.Game;
|
namespace GodotHostTest.Game.Root;
|
||||||
|
|
||||||
|
[Injected]
|
||||||
public partial class Root : Node2D
|
public partial class Root : Node2D
|
||||||
{
|
{
|
||||||
[Inject] private readonly ICurrentLevel _currentLevel = null!;
|
[Inject] private ICurrentLevel _currentLevel = null!;
|
||||||
[Inject] private readonly ILevelDataProvider _levelDataProvider = null!;
|
[Inject] private ILevelDataProvider _levelDataProvider = null!;
|
||||||
[Inject] private readonly ISceneInstantiator _sceneInstantiator = null!;
|
|
||||||
[Export] private PackedScene _levelScene = null!;
|
[Export] private PackedScene _levelScene = null!;
|
||||||
|
[Inject] private ISceneInstantiator _sceneInstantiator = null!;
|
||||||
|
|
||||||
public override void _Ready()
|
public override void _Ready()
|
||||||
{
|
{
|
||||||
@@ -1,18 +1,20 @@
|
|||||||
using Godot;
|
using Godot;
|
||||||
using GodotHostTest.GodotDI;
|
using GodotHostTest.AetherBind;
|
||||||
using GodotHostTest.Helpers;
|
using GodotHostTest.Helpers;
|
||||||
using GodotHostTest.Interfaces;
|
using GodotHostTest.Interfaces;
|
||||||
|
using OwofGames.AetherBind;
|
||||||
using R3;
|
using R3;
|
||||||
|
|
||||||
namespace GodotHostTest.Game;
|
namespace GodotHostTest.Game.Score;
|
||||||
|
|
||||||
|
[Injected]
|
||||||
public partial class Score : Control, IScore
|
public partial class Score : Control, IScore
|
||||||
{
|
{
|
||||||
[Inject] private readonly IValueGetter<ITargetSpawner> _targetSpawner = null!;
|
|
||||||
[Export] private AnimationPlayer _animationPlayer = null!;
|
[Export] private AnimationPlayer _animationPlayer = null!;
|
||||||
[Export] private Label _label = null!;
|
[Export] private Label _label = null!;
|
||||||
|
|
||||||
private int _score;
|
private int _score;
|
||||||
|
[Inject] private IValueGetter<ITargetSpawner> _targetSpawner = null!;
|
||||||
|
|
||||||
int IScore.Score => _score;
|
int IScore.Score => _score;
|
||||||
|
|
||||||
@@ -1,22 +1,24 @@
|
|||||||
using Godot;
|
using Godot;
|
||||||
using GodotHostTest.GodotDI;
|
using GodotHostTest.AetherBind;
|
||||||
using GodotHostTest.Interfaces;
|
using GodotHostTest.Interfaces;
|
||||||
|
using OwofGames.AetherBind;
|
||||||
using R3;
|
using R3;
|
||||||
|
|
||||||
namespace GodotHostTest.Game;
|
namespace GodotHostTest.Game.Target;
|
||||||
|
|
||||||
|
[Injected]
|
||||||
public partial class Target : Node2D, ITarget
|
public partial class Target : Node2D, ITarget
|
||||||
{
|
{
|
||||||
private readonly Subject<Unit> _hit = new();
|
private readonly Subject<Unit> _hit = new();
|
||||||
|
|
||||||
[Inject] private readonly IValueGetter<ITargetCollector> _targetCollector = null!;
|
|
||||||
|
|
||||||
private readonly Subject<Unit> _timedOut = new();
|
private readonly Subject<Unit> _timedOut = new();
|
||||||
[Export] public required Area2D CollisionArea;
|
[Export] public required Area2D CollisionArea;
|
||||||
[Export] public required Sprite2D Image;
|
[Export] public required Sprite2D Image;
|
||||||
[Export] public double TimeOutDurationInSeconds;
|
[Export] public double TimeOutDurationInSeconds;
|
||||||
[Export] public required Timer TimeOutTimer;
|
[Export] public required Timer TimeOutTimer;
|
||||||
|
|
||||||
|
[Inject] private IValueGetter<ITargetCollector> _targetCollector = null!;
|
||||||
|
|
||||||
public Observable<Unit> TimedOut => _timedOut.AsObservable();
|
public Observable<Unit> TimedOut => _timedOut.AsObservable();
|
||||||
|
|
||||||
public Observable<Unit> Hit => _hit.AsObservable();
|
public Observable<Unit> Hit => _hit.AsObservable();
|
||||||
@@ -4,15 +4,24 @@ using GodotHostTest.Helpers;
|
|||||||
using GodotHostTest.Interfaces;
|
using GodotHostTest.Interfaces;
|
||||||
using R3;
|
using R3;
|
||||||
|
|
||||||
namespace GodotHostTest.Game;
|
namespace GodotHostTest.Game.Target;
|
||||||
|
|
||||||
public partial class TargetSpawner : Node2D, ITargetCollector, ITargetSpawner
|
public partial class TargetSpawner : Node2D, ITargetCollector, ITargetSpawner
|
||||||
{
|
{
|
||||||
|
private readonly List<ITarget> _availableTargets = [];
|
||||||
|
|
||||||
|
private readonly Subject<ITarget> _targetSpawned = new();
|
||||||
[Export] public double TimeBetweenSpawns;
|
[Export] public double TimeBetweenSpawns;
|
||||||
|
|
||||||
[Export] public required Timer Timer;
|
[Export] public required Timer Timer;
|
||||||
|
|
||||||
private readonly List<ITarget> _availableTargets = [];
|
public void NewTarget(ITarget target)
|
||||||
|
{
|
||||||
|
_availableTargets.Add(target);
|
||||||
|
target.Hit.Merge(target.TimedOut).Select(_ => target).Subscribe(MakeTargetAvailable).AddTo(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Observable<ITarget> TargetSpawned => _targetSpawned.AsObservable();
|
||||||
|
|
||||||
public override void _Ready()
|
public override void _Ready()
|
||||||
{
|
{
|
||||||
@@ -44,18 +53,9 @@ public partial class TargetSpawner : Node2D, ITargetCollector, ITargetSpawner
|
|||||||
_targetSpawned.OnNext(target);
|
_targetSpawned.OnNext(target);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void NewTarget(ITarget target)
|
|
||||||
{
|
|
||||||
_availableTargets.Add(target);
|
|
||||||
target.Hit.Merge(target.TimedOut).Select(_ => target).Subscribe(MakeTargetAvailable).AddTo(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override void Dispose(bool disposing)
|
protected override void Dispose(bool disposing)
|
||||||
{
|
{
|
||||||
base.Dispose(disposing);
|
base.Dispose(disposing);
|
||||||
_targetSpawned.Dispose();
|
_targetSpawned.Dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
private readonly Subject<ITarget> _targetSpawned = new();
|
|
||||||
public Observable<ITarget> TargetSpawned => _targetSpawned.AsObservable();
|
|
||||||
}
|
}
|
||||||
@@ -1,12 +1,14 @@
|
|||||||
using Godot;
|
using Godot;
|
||||||
using GodotHostTest.GodotDI;
|
using GodotHostTest.AetherBind;
|
||||||
|
using OwofGames.AetherBind;
|
||||||
|
|
||||||
namespace GodotHostTest.Game;
|
namespace GodotHostTest.Game.Turret;
|
||||||
|
|
||||||
|
[Injected]
|
||||||
public partial class Turret : Sprite2D
|
public partial class Turret : Sprite2D
|
||||||
{
|
{
|
||||||
[Inject] private readonly ISceneInstantiator _sceneInstantiator = null!;
|
|
||||||
[Export] private PackedScene _projectilePackedScene = null!;
|
[Export] private PackedScene _projectilePackedScene = null!;
|
||||||
|
[Inject] private ISceneInstantiator _sceneInstantiator = null!;
|
||||||
|
|
||||||
public override void _Ready()
|
public override void _Ready()
|
||||||
{
|
{
|
||||||
+5
-5
@@ -1,11 +1,11 @@
|
|||||||
[gd_scene format=3 uid="uid://xfd48ep5qi1k"]
|
[gd_scene format=3 uid="uid://xfd48ep5qi1k"]
|
||||||
|
|
||||||
[ext_resource type="Script" uid="uid://dk578xnlxjwrr" path="res://Game/LevelServiceSource.cs" id="1_5saw1"]
|
[ext_resource type="Script" uid="uid://dk578xnlxjwrr" path="res://Game/Level/LevelServiceSource.cs" id="1_5saw1"]
|
||||||
[ext_resource type="PackedScene" uid="uid://3v8kq1rfwhmr" path="res://Game/target.tscn" id="1_y7rhs"]
|
[ext_resource type="PackedScene" uid="uid://3v8kq1rfwhmr" path="res://Game/target.tscn" id="1_y7rhs"]
|
||||||
[ext_resource type="Script" uid="uid://cxfrtglku2gfa" path="res://Game/TargetSpawner.cs" id="2_5saw1"]
|
[ext_resource type="Script" uid="uid://cxfrtglku2gfa" path="res://Game/Target/TargetSpawner.cs" id="2_5saw1"]
|
||||||
[ext_resource type="Script" uid="uid://bgrjeadxhgmvi" path="res://Game/Score.cs" id="3_spj1u"]
|
[ext_resource type="Script" uid="uid://bgrjeadxhgmvi" path="res://Game/Score/Score.cs" id="3_spj1u"]
|
||||||
[ext_resource type="Texture2D" uid="uid://y1ros3y7hag2" path="res://icon.svg" id="4_esqs7"]
|
[ext_resource type="Texture2D" uid="uid://y1ros3y7hag2" path="res://icon.svg" id="4_esqs7"]
|
||||||
[ext_resource type="Script" uid="uid://ce7gnp1lcrrdv" path="res://Game/Turret.cs" id="5_himod"]
|
[ext_resource type="Script" uid="uid://ce7gnp1lcrrdv" path="res://Game/Turret/Turret.cs" id="5_himod"]
|
||||||
[ext_resource type="PackedScene" uid="uid://brbufibn7hi3o" path="res://Game/projectile.tscn" id="6_sin03"]
|
[ext_resource type="PackedScene" uid="uid://brbufibn7hi3o" path="res://Game/projectile.tscn" id="6_sin03"]
|
||||||
|
|
||||||
[sub_resource type="Animation" id="Animation_bbjqm"]
|
[sub_resource type="Animation" id="Animation_bbjqm"]
|
||||||
@@ -74,7 +74,7 @@ _data = {
|
|||||||
[node name="LevelScope" type="Node" parent="." unique_id=1267156771 node_paths=PackedStringArray("_targetSpawner", "InjectedNodes")]
|
[node name="LevelScope" type="Node" parent="." unique_id=1267156771 node_paths=PackedStringArray("_targetSpawner", "InjectedNodes")]
|
||||||
script = ExtResource("1_5saw1")
|
script = ExtResource("1_5saw1")
|
||||||
_targetSpawner = NodePath("../Spawner")
|
_targetSpawner = NodePath("../Spawner")
|
||||||
_serviceScope = "GodotHostTest.Game.LevelScope, godot-host-test, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null"
|
_serviceScope = "GodotHostTest.Game.Level.LevelScope, godot-host-test, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null"
|
||||||
InjectedNodes = [NodePath("../Target"), NodePath("../Target2"), NodePath("../Target3"), NodePath("../Target4"), NodePath("../Target5"), NodePath("../Target6"), NodePath("../Score"), NodePath("../Turret")]
|
InjectedNodes = [NodePath("../Target"), NodePath("../Target2"), NodePath("../Target3"), NodePath("../Target4"), NodePath("../Target5"), NodePath("../Target6"), NodePath("../Score"), NodePath("../Turret")]
|
||||||
|
|
||||||
[node name="Target" parent="." unique_id=2101558052 instance=ExtResource("1_y7rhs")]
|
[node name="Target" parent="." unique_id=2101558052 instance=ExtResource("1_y7rhs")]
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
[gd_resource type="Resource" script_class="LevelsData" format=3 uid="uid://c4ym7vrpgk4e6"]
|
[gd_resource type="Resource" script_class="LevelsData" format=3 uid="uid://c4ym7vrpgk4e6"]
|
||||||
|
|
||||||
[ext_resource type="Script" uid="uid://ywe7vkywrdvk" path="res://Game/LevelData.cs" id="1_bkfnq"]
|
[ext_resource type="Script" uid="uid://ywe7vkywrdvk" path="res://Game/Level/LevelData.cs" id="1_bkfnq"]
|
||||||
[ext_resource type="Script" uid="uid://cl200m5rnkboq" path="res://Game/LevelsData.cs" id="1_e2ehm"]
|
[ext_resource type="Script" uid="uid://cl200m5rnkboq" path="res://Game/Level/LevelsData.cs" id="1_e2ehm"]
|
||||||
|
|
||||||
[sub_resource type="Resource" id="Resource_bbjqm"]
|
[sub_resource type="Resource" id="Resource_bbjqm"]
|
||||||
script = ExtResource("1_bkfnq")
|
script = ExtResource("1_bkfnq")
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
using OwofGames.GodotLume;
|
using OwofGames.GodotLume;
|
||||||
|
|
||||||
namespace GodotHostTest.GodotDI;
|
namespace GodotHostTest.AetherBind;
|
||||||
|
|
||||||
public static class BuilderExtensions
|
public static class BuilderExtensions
|
||||||
{
|
{
|
||||||
+1
-1
@@ -7,7 +7,7 @@ using System.Reflection;
|
|||||||
using System.Runtime.Loader;
|
using System.Runtime.Loader;
|
||||||
using Godot;
|
using Godot;
|
||||||
|
|
||||||
namespace GodotHostTest.GodotDI.Editor;
|
namespace GodotHostTest.AetherBind.Editor;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Taken from https://github.com/godotengine/godot-proposals/issues/12294
|
/// Taken from https://github.com/godotengine/godot-proposals/issues/12294
|
||||||
@@ -2,9 +2,10 @@
|
|||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using Godot;
|
using Godot;
|
||||||
|
using OwofGames.AetherBind;
|
||||||
using Array = Godot.Collections.Array;
|
using Array = Godot.Collections.Array;
|
||||||
|
|
||||||
namespace GodotHostTest.GodotDI.Editor;
|
namespace GodotHostTest.AetherBind.Editor;
|
||||||
|
|
||||||
[Tool]
|
[Tool]
|
||||||
public partial class Plugin : EditorPlugin
|
public partial class Plugin : EditorPlugin
|
||||||
+1
-1
@@ -1,7 +1,7 @@
|
|||||||
#if TOOLS
|
#if TOOLS
|
||||||
using Godot;
|
using Godot;
|
||||||
|
|
||||||
namespace GodotHostTest.GodotDI.Editor;
|
namespace GodotHostTest.AetherBind.Editor;
|
||||||
|
|
||||||
// it's inside ServiceSource so that it can safely access nameof(_serviceScope)
|
// it's inside ServiceSource so that it can safely access nameof(_serviceScope)
|
||||||
public partial class ScopeInspectorPlugin : EditorInspectorPlugin
|
public partial class ScopeInspectorPlugin : EditorInspectorPlugin
|
||||||
+1
-1
@@ -3,7 +3,7 @@ using System;
|
|||||||
using System.Linq;
|
using System.Linq;
|
||||||
using Godot;
|
using Godot;
|
||||||
|
|
||||||
namespace GodotHostTest.GodotDI.Editor;
|
namespace GodotHostTest.AetherBind.Editor;
|
||||||
|
|
||||||
public partial class ScopePickerEditor : EditorProperty
|
public partial class ScopePickerEditor : EditorProperty
|
||||||
{
|
{
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
|
||||||
namespace GodotHostTest.GodotDI;
|
namespace GodotHostTest.AetherBind;
|
||||||
|
|
||||||
public static class EnumerableExtensions
|
public static class EnumerableExtensions
|
||||||
{
|
{
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
using System;
|
using System;
|
||||||
using Godot;
|
using Godot;
|
||||||
|
|
||||||
namespace GodotHostTest.GodotDI;
|
namespace GodotHostTest.AetherBind;
|
||||||
|
|
||||||
public interface ISceneInstantiator
|
public interface ISceneInstantiator
|
||||||
{
|
{
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
namespace GodotHostTest.GodotDI;
|
namespace GodotHostTest.AetherBind;
|
||||||
|
|
||||||
public interface IValueGetter<out T>
|
public interface IValueGetter<out T>
|
||||||
{
|
{
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
namespace GodotHostTest.GodotDI;
|
namespace GodotHostTest.AetherBind;
|
||||||
|
|
||||||
public interface IValueSetter<in T>
|
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;
|
||||||
using OwofGames.GodotLume.Microsoft.DependencyInjection;
|
using OwofGames.GodotLume.Microsoft.DependencyInjection;
|
||||||
|
|
||||||
namespace GodotHostTest.GodotDI;
|
namespace GodotHostTest.AetherBind;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The base class for a root scope. Implement this class and its abstract methods to kick off the DI system.
|
/// 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 Microsoft.Extensions.Logging;
|
||||||
using OwofGames.GodotLume;
|
using OwofGames.GodotLume;
|
||||||
|
|
||||||
namespace GodotHostTest.GodotDI;
|
namespace GodotHostTest.AetherBind;
|
||||||
|
|
||||||
internal class SceneInstantiator(IProvider provider) : ISceneInstantiator
|
internal class SceneInstantiator(IProvider provider) : ISceneInstantiator
|
||||||
{
|
{
|
||||||
+1
-1
@@ -1,7 +1,7 @@
|
|||||||
using System;
|
using System;
|
||||||
using Godot;
|
using Godot;
|
||||||
|
|
||||||
namespace GodotHostTest.GodotDI;
|
namespace GodotHostTest.AetherBind;
|
||||||
|
|
||||||
public static class SceneInstantiatorExtensions
|
public static class SceneInstantiatorExtensions
|
||||||
{
|
{
|
||||||
@@ -7,7 +7,7 @@ using System.Runtime.Loader;
|
|||||||
using Godot;
|
using Godot;
|
||||||
using OwofGames.GodotLume;
|
using OwofGames.GodotLume;
|
||||||
|
|
||||||
namespace GodotHostTest.GodotDI;
|
namespace GodotHostTest.AetherBind;
|
||||||
|
|
||||||
public static class ScopeTypesAndNames
|
public static class ScopeTypesAndNames
|
||||||
{
|
{
|
||||||
@@ -1,18 +1,18 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Reflection;
|
|
||||||
using Godot;
|
using Godot;
|
||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
|
using OwofGames.AetherBind;
|
||||||
using OwofGames.GodotLume;
|
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
|
public partial class ServiceSource : Node
|
||||||
{
|
{
|
||||||
private static readonly string RootScopeQualifiedName = typeof(RootScope).AssemblyQualifiedName!;
|
private static readonly string RootScopeQualifiedName = typeof(RootScope).AssemblyQualifiedName!;
|
||||||
[Export] private string _serviceScope = RootScopeQualifiedName;
|
|
||||||
[Export] protected Node?[] InjectedNodes = [];
|
[Export] protected Node?[] InjectedNodes = [];
|
||||||
|
[Export] private string _serviceScope = RootScopeQualifiedName;
|
||||||
|
|
||||||
internal void ResolveInjectedNodes(IProvider provider, Delegate? onScopeCreated)
|
internal void ResolveInjectedNodes(IProvider provider, Delegate? onScopeCreated)
|
||||||
{
|
{
|
||||||
@@ -25,7 +25,7 @@ public partial class ServiceSource : Node
|
|||||||
var serviceScope = ScopeTypesAndNames.GetType(_serviceScope);
|
var serviceScope = ScopeTypesAndNames.GetType(_serviceScope);
|
||||||
provider = provider.GetScopedProvider(serviceScope);
|
provider = provider.GetScopedProvider(serviceScope);
|
||||||
// invoke onScopeCreated, if present
|
// 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)
|
if (onScopeCreated != null)
|
||||||
{
|
{
|
||||||
var parameters = onScopeCreated.Method
|
var parameters = onScopeCreated.Method
|
||||||
@@ -43,37 +43,42 @@ public partial class ServiceSource : Node
|
|||||||
}
|
}
|
||||||
|
|
||||||
// resolve the injected nodes against the chosen service provider
|
// 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)
|
foreach (var node in InjectedNodes)
|
||||||
{
|
{
|
||||||
if (node == null) continue;
|
if (node == null) continue;
|
||||||
logger.LogTrace("Injecting {Node}.", node.Name);
|
logger.LogTrace("Injecting {Node}.", node.Name);
|
||||||
var nodeType = node.GetType();
|
|
||||||
foreach (var field in nodeType
|
if (node is IInjectable injectable)
|
||||||
.GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic))
|
|
||||||
{
|
{
|
||||||
if (field.GetCustomAttribute<InjectAttribute>() == null) continue;
|
injectable.Inject(provider);
|
||||||
var fieldType = field.FieldType;
|
|
||||||
var service = provider.Get(fieldType);
|
|
||||||
field.SetValue(node, service);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach (var method in nodeType.GetMethods(BindingFlags.Instance | BindingFlags.Public |
|
// var nodeType = node.GetType();
|
||||||
BindingFlags.NonPublic))
|
// foreach (var field in nodeType
|
||||||
{
|
// .GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic))
|
||||||
if (method.GetCustomAttribute<InjectAttribute>() == null) continue;
|
// {
|
||||||
var parameters = method.GetParameters();
|
// if (field.GetCustomAttribute<InjectAttribute>() == null) continue;
|
||||||
var values = new object?[parameters.Length];
|
// var fieldType = field.FieldType;
|
||||||
var i = 0;
|
// var service = provider.Get(fieldType);
|
||||||
foreach (var parameter in parameters)
|
// field.SetValue(node, service);
|
||||||
{
|
// }
|
||||||
var parameterType = parameter.ParameterType;
|
//
|
||||||
var service = provider.Get(parameterType);
|
// foreach (var method in nodeType.GetMethods(BindingFlags.Instance | BindingFlags.Public |
|
||||||
values[i++] = service;
|
// BindingFlags.NonPublic))
|
||||||
}
|
// {
|
||||||
|
// if (method.GetCustomAttribute<InjectAttribute>() == null) continue;
|
||||||
method.Invoke(node, values);
|
// 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"
|
importer="texture"
|
||||||
type="CompressedTexture2D"
|
type="CompressedTexture2D"
|
||||||
uid="uid://ce5hi46doaiv8"
|
uid="uid://ce5hi46doaiv8"
|
||||||
path="res://.godot/imported/ServiceSource.svg-ca2976082d4f895e226f23d45377b764.ctex"
|
path="res://.godot/imported/ServiceSource.svg-22939ab8c3bebd4d414fabd470fcc1cf.ctex"
|
||||||
metadata={
|
metadata={
|
||||||
"vram_texture": false
|
"vram_texture": false
|
||||||
}
|
}
|
||||||
|
|
||||||
[deps]
|
[deps]
|
||||||
|
|
||||||
source_file="res://addons/GodotDI/ServiceSource.svg"
|
source_file="res://addons/AetherBind/ServiceSource.svg"
|
||||||
dest_files=["res://.godot/imported/ServiceSource.svg-ca2976082d4f895e226f23d45377b764.ctex"]
|
dest_files=["res://.godot/imported/ServiceSource.svg-22939ab8c3bebd4d414fabd470fcc1cf.ctex"]
|
||||||
|
|
||||||
[params]
|
[params]
|
||||||
|
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
using System;
|
using System;
|
||||||
|
|
||||||
namespace GodotHostTest.GodotDI;
|
namespace GodotHostTest.AetherBind;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// An object that allows communication through scopes, by providing a couple getter/setter that can be injected in
|
/// An object that allows communication through scopes, by providing a couple getter/setter that can be injected in
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
[plugin]
|
[plugin]
|
||||||
|
|
||||||
name="GodotDI"
|
name="AetherBind"
|
||||||
description=""
|
description=""
|
||||||
author="owof games"
|
author="owof games"
|
||||||
version="0.1"
|
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
|
|
||||||
@@ -7,7 +7,7 @@
|
|||||||
<Nullable>enable</Nullable>
|
<Nullable>enable</Nullable>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="R3" Version="1.3.1" />
|
<PackageReference Include="R3" Version="1.3.1"/>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Reference Include="OwofGames.GodotHost">
|
<Reference Include="OwofGames.GodotHost">
|
||||||
@@ -31,4 +31,10 @@
|
|||||||
<HintPath>..\OwofGames.Godot\OwofGames.GodotLume.Microsoft.DependencyInjection\bin\Debug\net8.0\OwofGames.GodotLume.Microsoft.DependencyInjection.dll</HintPath>
|
<HintPath>..\OwofGames.Godot\OwofGames.GodotLume.Microsoft.DependencyInjection\bin\Debug\net8.0\OwofGames.GodotLume.Microsoft.DependencyInjection.dll</HintPath>
|
||||||
</Reference>
|
</Reference>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<Content Include="addons\AetherBind\README.md"/>
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<Analyzer Include="..\OwofGames.Godot\OwofGames.AetherBind.SourceGenerators\bin\Debug\netstandard2.0\OwofGames.AetherBind.SourceGenerators.dll"/>
|
||||||
|
</ItemGroup>
|
||||||
</Project>
|
</Project>
|
||||||
@@ -1,9 +1,12 @@
|
|||||||
<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
|
<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
|
||||||
|
<s:Boolean x:Key="/Default/AddReferences/RecentPaths/=_002Fhome_002Fredglow_002Fsources_002FOwofGames_002EGodot_002FOwofGames_002EAetherBind_002ESourceGenerators_002Fbin_002FDebug_002Fnetstandard2_002E0_002FOwofGames_002EAetherBind_002ESourceGenerators_002Edll/@EntryIndexedValue">True</s:Boolean>
|
||||||
|
<s:Boolean x:Key="/Default/AddReferences/RecentPaths/=_002Fhome_002Fredglow_002Fsources_002FOwofGames_002EGodot_002FOwofGames_002EAetherBind_002Fbin_002FDebug_002Fnet8_002E0_002FOwofGames_002EAetherBind_002Edll/@EntryIndexedValue">True</s:Boolean>
|
||||||
<s:Boolean x:Key="/Default/AddReferences/RecentPaths/=_002Fhome_002Fredglow_002Fsources_002FOwofGames_002EGodot_002FOwofGames_002EGodotHost_002Fbin_002FDebug_002Fnet8_002E0_002FOwofGames_002EGodotHost_002Edll/@EntryIndexedValue">True</s:Boolean>
|
<s:Boolean x:Key="/Default/AddReferences/RecentPaths/=_002Fhome_002Fredglow_002Fsources_002FOwofGames_002EGodot_002FOwofGames_002EGodotHost_002Fbin_002FDebug_002Fnet8_002E0_002FOwofGames_002EGodotHost_002Edll/@EntryIndexedValue">True</s:Boolean>
|
||||||
<s:Boolean x:Key="/Default/AddReferences/RecentPaths/=_002Fhome_002Fredglow_002Fsources_002FOwofGames_002EGodot_002FOwofGames_002EGodotHost_002Fbin_002FDebug_002Fnet8_002E0_002FOwofGames_002EGodotLogger_002Edll/@EntryIndexedValue">True</s:Boolean>
|
<s:Boolean x:Key="/Default/AddReferences/RecentPaths/=_002Fhome_002Fredglow_002Fsources_002FOwofGames_002EGodot_002FOwofGames_002EGodotHost_002Fbin_002FDebug_002Fnet8_002E0_002FOwofGames_002EGodotLogger_002Edll/@EntryIndexedValue">True</s:Boolean>
|
||||||
<s:Boolean x:Key="/Default/AddReferences/RecentPaths/=_002Fhome_002Fredglow_002Fsources_002FOwofGames_002EGodot_002FOwofGames_002EGodotLume_002EMicrosoft_002EDependencyInjection_002Fbin_002FDebug_002Fnet8_002E0_002FOwofGames_002EGodotLume_002EMicrosoft_002EDependencyInjection_002Edll/@EntryIndexedValue">True</s:Boolean>
|
<s:Boolean x:Key="/Default/AddReferences/RecentPaths/=_002Fhome_002Fredglow_002Fsources_002FOwofGames_002EGodot_002FOwofGames_002EGodotLume_002EMicrosoft_002EDependencyInjection_002Fbin_002FDebug_002Fnet8_002E0_002FOwofGames_002EGodotLume_002EMicrosoft_002EDependencyInjection_002Edll/@EntryIndexedValue">True</s:Boolean>
|
||||||
<s:Boolean x:Key="/Default/AddReferences/RecentPaths/=_002Fhome_002Fredglow_002Fsources_002FOwofGames_002EGodot_002FOwofGames_002EGodotLume_002Fbin_002FDebug_002Fnet8_002E0_002FOwofGames_002EGodotLume_002Edll/@EntryIndexedValue">True</s:Boolean>
|
<s:Boolean x:Key="/Default/AddReferences/RecentPaths/=_002Fhome_002Fredglow_002Fsources_002FOwofGames_002EGodot_002FOwofGames_002EGodotLume_002Fbin_002FDebug_002Fnet8_002E0_002FOwofGames_002EGodotLume_002Edll/@EntryIndexedValue">True</s:Boolean>
|
||||||
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AEnumerable_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002Econfig_003FJetBrains_003FRider2026_002E1_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003F71c28e8d0d254cb69b7b78690e099f6183800_003Fa8_003F2e82b19d_003FEnumerable_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AEnumerable_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002Econfig_003FJetBrains_003FRider2026_002E1_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003F71c28e8d0d254cb69b7b78690e099f6183800_003Fa8_003F2e82b19d_003FEnumerable_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
||||||
|
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AGodotObject_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002Econfig_003FJetBrains_003FRider2026_002E2_003Fresharper_002Dhost_003FSourcesCache_003F4b3cf0d6385fc1f8b61f68a3e1df5132e355f1c63b49372b4c670e76f3_003FGodotObject_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
||||||
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003ARuntimeType_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002Econfig_003FJetBrains_003FRider2026_002E1_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003F6cc9b871557b441baa469ce23b255f41dbb200_003F5e_003F88e82907_003FRuntimeType_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003ARuntimeType_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002Econfig_003FJetBrains_003FRider2026_002E1_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003F6cc9b871557b441baa469ce23b255f41dbb200_003F5e_003F88e82907_003FRuntimeType_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
||||||
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AThrowHelpers_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002Econfig_003FJetBrains_003FRider2026_002E1_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003F6cc9b871557b441baa469ce23b255f41dbb200_003F8e_003Fc3f51c26_003FThrowHelpers_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AThrowHelpers_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002Econfig_003FJetBrains_003FRider2026_002E1_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003F6cc9b871557b441baa469ce23b255f41dbb200_003F8e_003Fc3f51c26_003FThrowHelpers_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
||||||
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AThrowHelper_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002Econfig_003FJetBrains_003FRider2026_002E1_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003F6cc9b871557b441baa469ce23b255f41dbb200_003F71_003F4ef26ee8_003FThrowHelper_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AThrowHelper_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002Econfig_003FJetBrains_003FRider2026_002E1_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003F6cc9b871557b441baa469ce23b255f41dbb200_003F71_003F4ef26ee8_003FThrowHelper_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
||||||
|
|||||||
+1
-1
@@ -26,7 +26,7 @@ project/assembly_name="godot-host-test"
|
|||||||
|
|
||||||
[editor_plugins]
|
[editor_plugins]
|
||||||
|
|
||||||
enabled=PackedStringArray("res://addons/GodotDI/plugin.cfg")
|
enabled=PackedStringArray("res://addons/AetherBind/plugin.cfg")
|
||||||
|
|
||||||
[physics]
|
[physics]
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user