Skip to content

Commit

Permalink
0.1-beta
Browse files Browse the repository at this point in the history
  • Loading branch information
decembrist-revolt authored and decembrist-revolt committed Apr 19, 2021
0 parents commit be9b32c
Show file tree
Hide file tree
Showing 45 changed files with 1,220 additions and 0 deletions.
51 changes: 51 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
/.idea/

### Godot ###

# Godot-specific ignores
.import/
export.cfg
export_presets.cfg

# Imported translations (automatically generated from CSV files)
*.translation

# Mono-specific ignores
.mono/
data_*/

### Csharp ###
## Ignore Visual Studio temporary files, build results, and
## files generated by popular Visual Studio add-ons.
##
## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore

# User-specific files
*.rsuser
*.suo
*.user
*.userosscache
*.sln.docstates

# User-specific files (MonoDevelop/Xamarin Studio)
*.userprefs

# Mono auto generated files
mono_crash.*

# Build results
[Dd]ebug/
[Dd]ebugPublic/
[Rr]elease/
[Rr]eleases/
x64/
x86/
[Ww][Ii][Nn]32/
[Aa][Rr][Mm]/
[Aa][Rr][Mm]64/
bld/
[Bb]in/
[Oo]bj/
[Ll]og/
[Ll]ogs/

7 changes: 7 additions & 0 deletions Decembrist Plugin.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
<Project Sdk="Godot.NET.Sdk/3.2.3">
<PropertyGroup>
<LangVersion>8</LangVersion>
<TargetFramework>netcoreapp3.1</TargetFramework>
<RootNamespace>Decembrist</RootNamespace>
</PropertyGroup>
</Project>
4 changes: 4 additions & 0 deletions Decembrist Plugin.csproj.DotSettings
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
<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/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=addons/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=addons_005Cdecembrist_005Fplugin/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=addons_005Cspring_005Fframework/@EntryIndexedValue">True</s:Boolean></wpf:ResourceDictionary>
19 changes: 19 additions & 0 deletions Decembrist Plugin.sln
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 2012
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Decembrist Plugin", "Decembrist Plugin.csproj", "{009F4AE3-B7A3-406D-8521-76DE42F276CC}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
ExportDebug|Any CPU = ExportDebug|Any CPU
ExportRelease|Any CPU = ExportRelease|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{009F4AE3-B7A3-406D-8521-76DE42F276CC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{009F4AE3-B7A3-406D-8521-76DE42F276CC}.Debug|Any CPU.Build.0 = Debug|Any CPU
{009F4AE3-B7A3-406D-8521-76DE42F276CC}.ExportDebug|Any CPU.ActiveCfg = ExportDebug|Any CPU
{009F4AE3-B7A3-406D-8521-76DE42F276CC}.ExportDebug|Any CPU.Build.0 = ExportDebug|Any CPU
{009F4AE3-B7A3-406D-8521-76DE42F276CC}.ExportRelease|Any CPU.ActiveCfg = ExportRelease|Any CPU
{009F4AE3-B7A3-406D-8521-76DE42F276CC}.ExportRelease|Any CPU.Build.0 = ExportRelease|Any CPU
EndGlobalSection
EndGlobal
15 changes: 15 additions & 0 deletions Example/DecembristConfiguration.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
using Decembrist.Di;
using Decembrist.Example.Service;

namespace Decembrist.Example
{
public class DecembristConfiguration: IDecembristConfiguration
{
public ContainerBuilder ConfigDi(ContainerBuilder builder)
{
builder.Register<SomeService2, IService>();
builder.Register<SomeService1>();
return builder;
}
}
}
7 changes: 7 additions & 0 deletions Example/Service/IService.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
namespace Decembrist.Example.Service
{
public interface IService
{
public void Run();
}
}
9 changes: 9 additions & 0 deletions Example/Service/SomeService1.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
using Godot;

namespace Decembrist.Example.Service
{
public class SomeService1
{
public void SayHello() => GD.Print("Hello");
}
}
14 changes: 14 additions & 0 deletions Example/Service/SomeService2.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
namespace Decembrist.Example.Service
{
public class SomeService2: IService
{
private readonly SomeService1 _service1;

public SomeService2(SomeService1 service1)
{
_service1 = service1;
}

public void Run() => _service1.SayHello();
}
}
20 changes: 20 additions & 0 deletions Example/TestScene.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
using Godot;
using Decembrist.Di;
using Decembrist.Example.Service;
using Decembrist.Utils;

namespace Decembrist.Example
{
public class TestScene : Node2D
{
[Inject]
private IService service;

public override void _Ready()
{
this.InjectAll();
service.Run();
}

}
}
6 changes: 6 additions & 0 deletions Example/TestScene.tscn
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
[gd_scene load_steps=2 format=2]

[ext_resource path="res://Example/TestScene.cs" type="Script" id=1]

[node name="Node2D" type="Node2D"]
script = ExtResource( 1 )
77 changes: 77 additions & 0 deletions addons/decembrist_plugin/Autoload/DiService.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
#nullable enable
using System;
using System.Reflection;
using Godot;
using Decembrist.Di;
using Decembrist.Service;
using DiContainer = Decembrist.Di.Container;

namespace Decembrist.Autoload
{
public class DiService : Node2D
{
public DiContainer Container;

public override void _Ready()
{
}

public DiService()
{
var builder = new ContainerBuilder();
builder.RegisterInstance(new ConfigService());
builder = InstantiateConfig()?.ConfigDi(builder) ?? builder;
Container = builder.Build();
}

public T? ResolveOrNull<T>() where T : class
{
return Container.ResolveOrNull(typeof(T)) as T;
}

public void InjectAll(object instance)
{
var type = instance.GetType();
var fields = type.GetFields(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);
foreach (var field in fields)
{
if (field.GetCustomAttribute(typeof(Inject)) != null)
{
var serviceType = field.FieldType;
var service = Container.ResolveOrNull(serviceType);
if (service != null)
{
field.SetValue(instance, service);
}
else
{
GD.PrintErr($"No such type registered in container: {serviceType} for class {type}");
}
}
}
}

private IDecembristConfiguration? InstantiateConfig()
{
if (!(ProjectSettings.GetSetting("decembrist/config_class") is string configClass))
{
return null;
}
var configType = Type.GetType(configClass);
if (configType == null)
{
return null;
}

var noArgConstructor = configType?.GetConstructor(new Type[0]);
var config = noArgConstructor?.Invoke(null) ??
throw new Exception($"Decembrist config {configType} has no default constructor");
if (config is IDecembristConfiguration decembristConfiguration)
{
return decembristConfiguration;
}

return null;
}
}
}
28 changes: 28 additions & 0 deletions addons/decembrist_plugin/DecembristPlugin.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
#if TOOLS
using Godot;

[Tool]
public class DecembristPlugin : EditorPlugin
{
public override void EnablePlugin()
{
AddAutoloadSingleton("DI", "res://addons/decembrist_plugin/Autoload/DiService.cs");
CheckSetting("decembrist/config_class", "DecembristConfiguration");
}

public override void DisablePlugin()
{
RemoveAutoloadSingleton("DI");
}

private void CheckSetting(string name, object @default)
{
var setting = ProjectSettings.GetSetting(name);
if (setting == null)
{
ProjectSettings.SetSetting(name, @default);
}
}
}

#endif
115 changes: 115 additions & 0 deletions addons/decembrist_plugin/Di/Container.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
#nullable enable
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using Decembrist.Service;

namespace Decembrist.Di
{
public class Container
{
private readonly Dictionary<Type, object> _instanceMap;

public Container(Dictionary<Type, object> instanceMap, Dictionary<Type, Type> typeMap)
{
_instanceMap = instanceMap;
InstantiateTypes(typeMap);
}

public object? ResolveOrNull(Type type)
{
return _instanceMap.ContainsKey(type) ? _instanceMap[type] : null;
}

private void InstantiateTypes(Dictionary<Type, Type> typeMap)
{
var iteration = typeMap.Count;
while (typeMap.Count > 0 && iteration == typeMap.Count)
{
var toRemove = new List<Type>();
foreach (var (type, asType) in typeMap)
{
// Instantiate through no arg constructor
var instance = type.GetConstructor(new Type[0])?.Invoke(null);
if (instance == null)
{
var ctr = type.GetConstructors().First();
instance = InstantiateTypes(ctr);
}

if (instance != null)
{
_instanceMap[asType] = instance;
toRemove.Add(type);
}
}
foreach (var type in toRemove)
{
typeMap.Remove(type);
}

iteration--;
}

if (typeMap.Count != 0)
{
var typesArr = typeMap.Values.Select(type => type.ToString()).ToArray();
throw new Exception($"Unsatisfied dependencies {string.Join("", typesArr)}");
}
}

private object? InstantiateTypes(ConstructorInfo ctr)
{
var parameters = ctr.GetParameters();
var paramArgs = new List<object>(parameters.Length);
foreach (var parameter in parameters)
{
var paramType = parameter.ParameterType;
if (_instanceMap.ContainsKey(paramType))
{
paramArgs.Add(_instanceMap[paramType]);
}
else
{
break;
}

}

object? result = null;
if (parameters.Length == paramArgs.Count)
{
result = ctr.Invoke(paramArgs.ToArray());
}

return result;
}
}

public class ContainerBuilder
{
private readonly Dictionary<Type, object> _instanceMap = new Dictionary<Type, object>();
private readonly Dictionary<Type, Type> _typeMap = new Dictionary<Type, Type>();

public ContainerBuilder RegisterInstance<T>(T instance)
{
if (instance == null) throw new Exception("Null instance registration");

_instanceMap[typeof(T)] = instance;
return this;
}

public void Register<T>()
{
_typeMap[typeof(T)] = typeof(T);
}

public void Register<TYpe, TYpeAs>()
{
_typeMap[typeof(TYpe)] = typeof(TYpeAs);
}

public Container Build() => new Container(_instanceMap, _typeMap);
}
}
Loading

0 comments on commit be9b32c

Please sign in to comment.