Compare commits

..

No commits in common. "main" and "0.9.12" have entirely different histories.
main ... 0.9.12

16 changed files with 158 additions and 326 deletions

1
.gitignore vendored
View File

@ -35,7 +35,6 @@ ExportedObj/
*.csproj *.csproj
*.unityproj *.unityproj
*.sln *.sln
*.sln.meta
*.suo *.suo
*.tmp *.tmp
*.user *.user

View File

@ -1,6 +1,6 @@
MIT License MIT License
Copyright (c) 2023 Mikhail(DCFApixels) Copyright (c) 2023 Mikhail
Permission is hereby granted, free of charge, to any person obtaining a copy Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal of this software and associated documentation files (the "Software"), to deal

View File

@ -11,35 +11,11 @@
# Auto Injections for [DragonECS](https://github.com/DCFApixels/DragonECS) # Auto Injections for [DragonECS](https://github.com/DCFApixels/DragonECS)
<table> | Languages: | [Русский](https://github.com/DCFApixels/DragonECS-AutoInjections/blob/main/README-RU.md) | [English(WIP)](https://github.com/DCFApixels/DragonECS-AutoInjections) |
<tr></tr> | :--- | :--- | :--- |
<tr>
<td colspan="3">Readme Languages:</td>
</tr>
<tr></tr>
<tr>
<td nowrap width="100">
<a href="https://github.com/DCFApixels/DragonECS-AutoInjections/blob/main/README-RU.md">
<img src="https://github.com/user-attachments/assets/3c699094-f8e6-471d-a7c1-6d2e9530e721"></br>
<span>Русский</span>
</a>
</td>
<td nowrap width="100">
<a href="https://github.com/DCFApixels/DragonECS-AutoInjections">
<img src="https://github.com/user-attachments/assets/30528cb5-f38e-49f0-b23e-d001844ae930"></br>
<span>English(WIP)</span>
</a>
</td>
</tr>
</table>
</br>
Расширение призвано сократить объем кода, упростив инъекцию зависимостей, делая их автоматически. Расширение призвано сократить объем кода, упростив инъекцию зависимостей, делая их автоматически.
> **ВАЖНО!** Проект в стадии разработки. API может меняться.
> [!WARNING]
> Проект в стадии разработки. API может меняться.
# Оглавление # Оглавление
- [Установка](#установка) - [Установка](#установка)
- [Интеграция](#интеграция) - [Интеграция](#интеграция)
@ -61,7 +37,7 @@
Опционально: Опционально:
+ Игровые движки с C#: Unity, Godot, MonoGame и т.д. + Игровые движки с C#: Unity, Godot, MonoGame и т.д.
Протестировано: Протестированно:
+ **Unity:** Минимальная версия 2020.1.0; + **Unity:** Минимальная версия 2020.1.0;
## Установка для Unity ## Установка для Unity
@ -70,7 +46,7 @@
``` ```
https://github.com/DCFApixels/DragonECS-AutoInjections.git https://github.com/DCFApixels/DragonECS-AutoInjections.git
``` ```
* ### В виде исходников * ### В виде иходников
Фреймворк так же может быть добавлен в проект в виде исходников. Фреймворк так же может быть добавлен в проект в виде исходников.
</br> </br>
@ -145,7 +121,7 @@ sealed class DoSomethingProcessRunner : EcsRunner<IDoSomethingProcess>, IDoSomet
} }
//... //...
// Если в пайплайн не был добавлен раннер, то GetRunnerAuto автоматически добавит экземпляр DoSomethingProcessRunner. // Если в пайплайн небыл добавлен раннер, то GetRunnerAuto автоматически добавит экземпляр DoSomethingProcessRunner.
_pipeline.GetRunnerAuto<IDoSomethingProcess>().Do(); _pipeline.GetRunnerAuto<IDoSomethingProcess>().Do();
``` ```
@ -214,7 +190,7 @@ class VelocitySystem : IEcsRun, IEcsInject<EcsDefaultWorld>, IEcsInject<TimeServ
# Не null инъекции # Не null инъекции
Чтобы поле помеченное `[EcsInject]` было проинициализированно даже в случае отстувия инъекции, в конструктор атрибута можно передать тип болванку. В примере ниже поле `foo` получит экземпляр класса `Foo` из инъекции или экземпляр `FooDummy : Foo` если инъекции не было. Чтобы поле помеченное `[EcsInject]` было проинициализированно даже в случае отстувия инъекции, в конструктор атрибута можно передать тип болванку. В примере ниже поле `foo` получит экземпляр класса `Foo` из инъекции или экземпляр `FooDummy : Foo` если инъекции небыло.
``` csharp ``` csharp
[EcsInject(typeof(FooDummy))] Foo foo; [EcsInject(typeof(FooDummy))] Foo foo;
``` ```

View File

@ -11,34 +11,11 @@
# Auto Injections for [DragonECS](https://github.com/DCFApixels/DragonECS) # Auto Injections for [DragonECS](https://github.com/DCFApixels/DragonECS)
<table> | Languages: | [Русский](https://github.com/DCFApixels/DragonECS-AutoInjections/blob/main/README-RU.md) | [English(WIP)](https://github.com/DCFApixels/DragonECS-AutoInjections) |
<tr></tr> | :--- | :--- | :--- |
<tr>
<td colspan="3">Readme Languages:</td>
</tr>
<tr></tr>
<tr>
<td nowrap width="100">
<a href="https://github.com/DCFApixels/DragonECS-AutoInjections/blob/main/README-RU.md">
<img src="https://github.com/user-attachments/assets/7bc29394-46d6-44a3-bace-0a3bae65d755"></br>
<span>Русский</span>
</a>
</td>
<td nowrap width="100">
<a href="https://github.com/DCFApixels/DragonECS-AutoInjections">
<img src="https://github.com/user-attachments/assets/3c699094-f8e6-471d-a7c1-6d2e9530e721"></br>
<span>English(WIP)</span>
</a>
</td>
</tr>
</table>
</br>
The extension is designed to reduce the amount of code by simplifying dependency injection by doing injections automatically. The extension is designed to reduce the amount of code by simplifying dependency injection by doing injections automatically.
> [!WARNING] > **NOTICE:** The project is a work in progress, API may change.
> The project is a work in progress, API may change.
>
> While the English version of the README is incomplete, you can view the [Russian version](https://github.com/DCFApixels/DragonECS-AutoInjections/blob/main/README-RU.md). > While the English version of the README is incomplete, you can view the [Russian version](https://github.com/DCFApixels/DragonECS-AutoInjections/blob/main/README-RU.md).
@ -59,12 +36,12 @@ Tested with:
## Unity Installation ## Unity Installation
* ### Unity Package * ### Unity Package
The package can be installed as a Unity package by adding the Git URL [in the PackageManager](https://docs.unity3d.com/2023.2/Documentation/Manual/upm-ui-giturl.html) or manually adding it to `Packages/manifest.json`: The framework can be installed as a Unity package by adding the Git URL [in the PackageManager](https://docs.unity3d.com/2023.2/Documentation/Manual/upm-ui-giturl.html) or manually adding it to `Packages/manifest.json`:
``` ```
https://github.com/DCFApixels/DragonECS-AutoInjections.git https://github.com/DCFApixels/DragonECS-AutoInjections.git
``` ```
* ### Source Code * ### Source Code
The package can also be added to the project as source code. The framework can also be added to the project as source code.
</br> </br>

View File

@ -8,7 +8,7 @@
"displayName": "DragonECS-AutoInjections", "displayName": "DragonECS-AutoInjections",
"description": "Auto Injections for DragonECS", "description": "Auto Injections for DragonECS",
"unity": "2020.3", "unity": "2020.3",
"version": "0.9.18", "version": "0.9.12",
"repository": { "repository": {
"type": "git", "type": "git",
"url": "https://github.com/DCFApixels/DragonECS-AutoInjections.git" "url": "https://github.com/DCFApixels/DragonECS-AutoInjections.git"

View File

@ -1,10 +1,5 @@
#if DISABLE_DEBUG using DCFApixels.DragonECS.AutoInjections.Internal;
#undef DEBUG
#endif
using DCFApixels.DragonECS.AutoInjections.Internal;
using System; using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection; using System.Reflection;
namespace DCFApixels.DragonECS namespace DCFApixels.DragonECS
@ -13,7 +8,7 @@ namespace DCFApixels.DragonECS
{ {
protected sealed override void Init(Builder b) protected sealed override void Init(Builder b)
{ {
//EcsAspectAutoHelper.Fill(this, b); EcsAspectAutoHelper.Fill(this, b);
InitAfterDI(b); InitAfterDI(b);
} }
protected virtual void InitAfterDI(Builder b) { } protected virtual void InitAfterDI(Builder b) { }
@ -21,119 +16,90 @@ namespace DCFApixels.DragonECS
internal static class EcsAspectAutoHelper internal static class EcsAspectAutoHelper
{ {
private static readonly MethodInfo _incluedMethod; public static void Fill(EcsAspect s, EcsAspect.Builder b)
private static readonly MethodInfo _excludeMethod;
private static readonly MethodInfo _optionalMethod;
private static readonly MethodInfo _combineMethod;
private const BindingFlags REFL_FLAGS = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic;
static EcsAspectAutoHelper()
{ {
Type builderType = typeof(EcsAspect.Builder); Type builderType = b.GetType();
MethodInfo incluedMethod = builderType.GetMethod("IncludePool", BindingFlags.Instance | BindingFlags.Public);
MethodInfo excludeMethod = builderType.GetMethod("ExcludePool", BindingFlags.Instance | BindingFlags.Public);
MethodInfo optionalMethod = builderType.GetMethod("OptionalPool", BindingFlags.Instance | BindingFlags.Public);
MethodInfo includeImplicitMethod = builderType.GetMethod("IncludeImplicit", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
MethodInfo excludeImplicitMethod = builderType.GetMethod("ExcludeImplicit", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
MethodInfo combineMethod = builderType.GetMethod("Combine", BindingFlags.Instance | BindingFlags.Public);
_incluedMethod = builderType.GetMethod("IncludePool", REFL_FLAGS); Type aspectType = s.GetType();
_excludeMethod = builderType.GetMethod("ExcludePool", REFL_FLAGS);
_optionalMethod = builderType.GetMethod("OptionalPool", REFL_FLAGS); foreach (var attribute in aspectType.GetCustomAttributes<ImplicitInjectAttribute>())//TODO убрать дублирование кода - вынести в отедльный метод
_combineMethod = builderType.GetMethod("Combine", REFL_FLAGS);
}
public static void FillMaskFields(object aspect, EcsMask mask)
{
foreach (FieldInfo fieldInfo in aspect.GetType().GetFields(REFL_FLAGS))
{ {
if (fieldInfo.GetCustomAttribute<MaskAttribute>() == null) if (attribute is IncImplicitAttribute incImplicit)
{ {
if (incImplicit.isPool)
incluedMethod.MakeGenericMethod(incImplicit.type).Invoke(b, null);
else
includeImplicitMethod.Invoke(b, new object[] { incImplicit.type });
continue; continue;
} }
if (attribute is ExcImplicitAttribute excImplicit)
if (fieldInfo.FieldType == typeof(EcsMask))
{ {
fieldInfo.SetValue(aspect, mask); if (excImplicit.isPool)
excludeMethod.MakeGenericMethod(excImplicit.type).Invoke(b, null);
else
excludeImplicitMethod.Invoke(b, new object[] { excImplicit.type });
continue;
} }
else if (fieldInfo.FieldType == typeof(EcsStaticMask)) }//TODO КОНЕЦ убрать дублирование кода - вынести в отедльный метод
{
fieldInfo.SetValue(aspect, mask.ToStatic());
}
}
}
public static void FillFields(object aspect, EcsAspect.Builder builder)
{
Type aspectType = aspect.GetType();
var implicitInjectAttributes = (IEnumerable<ImplicitInjectAttribute>)aspectType.GetCustomAttributes<ImplicitInjectAttribute>();
FieldInfo[] fieldInfos = aspectType.GetFields(REFL_FLAGS); FieldInfo[] fieldInfos = aspectType.GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
foreach (FieldInfo fieldInfo in fieldInfos) foreach (FieldInfo fieldInfo in fieldInfos)
{ {
Type fieldType = fieldInfo.FieldType; Type fieldType = fieldInfo.FieldType;
implicitInjectAttributes = implicitInjectAttributes.Concat(fieldInfo.GetCustomAttributes<ImplicitInjectAttribute>()); foreach (var attribute in fieldInfo.GetCustomAttributes<ImplicitInjectAttribute>())//TODO убрать дублирование кода - вынести в отедльный метод
{
if (attribute is IncImplicitAttribute incImplicit)
{
if (incImplicit.isPool)
incluedMethod.MakeGenericMethod(incImplicit.type).Invoke(b, null);
else
includeImplicitMethod.Invoke(b, new object[] { incImplicit.type });
continue;
}
if (attribute is ExcImplicitAttribute excImplicit)
{
if (excImplicit.isPool)
excludeMethod.MakeGenericMethod(excImplicit.type).Invoke(b, null);
else
excludeImplicitMethod.Invoke(b, new object[] { excImplicit.type });
continue;
}
}//TODO КОНЕЦ убрать дублирование кода - вынести в отедльный метод
if (fieldInfo.TryGetCustomAttribute(out InjectAspectMemberAttribute injectAttribute) == false) if (!fieldInfo.TryGetCustomAttribute(out InjectAspectMemberAttribute injectAttribute))
{ {
continue; continue;
} }
IEcsPool pool;
switch (injectAttribute)
{
case IncAttribute incAtr:
if (builder.World.TryFindPoolInstance(fieldType, out pool))
{
builder.SetMaskInclude(fieldType);
fieldInfo.SetValue(aspect, pool);
}
else
{
pool = (IEcsPool)_incluedMethod.MakeGenericMethod(fieldType).Invoke(builder, null);
}
fieldInfo.SetValue(aspect, pool);
break;
case ExcAttribute extAtr:
if (builder.World.TryFindPoolInstance(fieldType, out pool))
{
builder.SetMaskExclude(fieldType);
fieldInfo.SetValue(aspect, pool);
}
else
{
pool = (IEcsPool)_excludeMethod.MakeGenericMethod(fieldType).Invoke(builder, null);
}
fieldInfo.SetValue(aspect, pool);
break;
case OptAttribute optAtr:
if (builder.World.TryFindPoolInstance(fieldType, out pool))
{
fieldInfo.SetValue(aspect, pool);
}
else
{
pool = (IEcsPool)_optionalMethod.MakeGenericMethod(fieldType).Invoke(builder, null);
}
fieldInfo.SetValue(aspect, pool);
break;
case CombineAttribute combineAtr:
pool = builder.World.FindPoolInstance(fieldType);
fieldInfo.SetValue(aspect, _combineMethod.MakeGenericMethod(fieldType).Invoke(builder, new object[] { combineAtr.Order }));
break;
default:
break;
}
}
if (injectAttribute is IncAttribute)
foreach (var attribute in implicitInjectAttributes)
{
if (attribute is IncImplicitAttribute incImplicitAtr)
{ {
builder.SetMaskInclude(incImplicitAtr.ComponentType); fieldInfo.SetValue(s, incluedMethod.MakeGenericMethod(fieldType).Invoke(b, null));
continue; continue;
} }
if (attribute is ExcImplicitAttribute excImplicitAtr) if (injectAttribute is ExcAttribute)
{ {
builder.SetMaskExclude(excImplicitAtr.ComponentType); fieldInfo.SetValue(s, excludeMethod.MakeGenericMethod(fieldType).Invoke(b, null));
continue;
}
if (injectAttribute is OptAttribute)
{
fieldInfo.SetValue(s, optionalMethod.MakeGenericMethod(fieldType).Invoke(b, null));
continue;
}
if (injectAttribute is CombineAttribute combAttribute)
{
fieldInfo.SetValue(s, combineMethod.MakeGenericMethod(fieldType).Invoke(b, new object[] { combAttribute.order }));
continue; continue;
} }
} }
} }
} }
} }

View File

@ -1,7 +1,4 @@
#if DISABLE_DEBUG using DCFApixels.DragonECS.PoolsCore;
#undef DEBUG
#endif
using DCFApixels.DragonECS.PoolsCore;
using System; using System;
using System.Linq; using System.Linq;
@ -17,30 +14,32 @@ namespace DCFApixels.DragonECS
[AttributeUsage(AttributeTargets.Field, Inherited = false, AllowMultiple = false)] [AttributeUsage(AttributeTargets.Field, Inherited = false, AllowMultiple = false)]
public sealed class CombineAttribute : InjectAspectMemberAttribute public sealed class CombineAttribute : InjectAspectMemberAttribute
{ {
public readonly int Order = 0; public readonly int order = 0;
public CombineAttribute(int order = 0) { Order = order; } public CombineAttribute(int order = 0) { this.order = order; }
} }
[AttributeUsage(AttributeTargets.Field, Inherited = false, AllowMultiple = false)]
public sealed class MaskAttribute : InjectAspectMemberAttribute { }
public abstract class ImplicitInjectAttribute : Attribute { }
public abstract class ImplicitInjectAttribute : Attribute
{
public readonly Type ComponentType;
public ImplicitInjectAttribute(Type componentType)
{
ComponentType = componentType;
}
}
[AttributeUsage(AttributeTargets.Field | AttributeTargets.Class, Inherited = false, AllowMultiple = true)] [AttributeUsage(AttributeTargets.Field | AttributeTargets.Class, Inherited = false, AllowMultiple = true)]
public sealed class IncImplicitAttribute : ImplicitInjectAttribute public sealed class IncImplicitAttribute : ImplicitInjectAttribute
{ {
public IncImplicitAttribute(Type type) : base(type) { } public readonly Type type;
public readonly bool isPool;
public IncImplicitAttribute(Type type)
{
this.type = type;
isPool = type.GetInterfaces().Any(o => o == typeof(IEcsPoolImplementation));
}
} }
[AttributeUsage(AttributeTargets.Field | AttributeTargets.Class, Inherited = false, AllowMultiple = true)] [AttributeUsage(AttributeTargets.Field | AttributeTargets.Class, Inherited = false, AllowMultiple = true)]
public sealed class ExcImplicitAttribute : ImplicitInjectAttribute public sealed class ExcImplicitAttribute : ImplicitInjectAttribute
{ {
public ExcImplicitAttribute(Type type) : base(type) { } public readonly Type type;
public readonly bool isPool;
public ExcImplicitAttribute(Type type)
{
this.type = type;
isPool = type.GetInterfaces().Any(o => o == typeof(IEcsPoolImplementation));
}
} }
} }

View File

@ -1,29 +1,15 @@
#if DISABLE_DEBUG using System;
#undef DEBUG
#endif
using System;
namespace DCFApixels.DragonECS namespace DCFApixels.DragonECS
{ {
[AttributeUsage(AttributeTargets.Field | AttributeTargets.Property | AttributeTargets.Method, Inherited = false, AllowMultiple = false)] [AttributeUsage(AttributeTargets.Field | AttributeTargets.Property | AttributeTargets.Method, Inherited = false, AllowMultiple = false)]
public class DIAttribute : Attribute public class DIAttribute : Attribute
{ {
public static readonly DIAttribute Dummy = new DIAttribute(); public static readonly DIAttribute Dummy = new DIAttribute(null);
public readonly Type NotNullDummyType = null; public readonly Type notNullDummyType;
public readonly string NamedInjection = string.Empty; public DIAttribute(Type notNullDummyType = null)
public DIAttribute() { }
public DIAttribute(string namedInjection)
{ {
NamedInjection = namedInjection; this.notNullDummyType = notNullDummyType;
}
public DIAttribute(Type notNullDummyType)
{
NotNullDummyType = notNullDummyType;
}
public DIAttribute(string namedInjection, Type notNullDummyType)
{
NamedInjection = namedInjection;
NotNullDummyType = notNullDummyType;
} }
} }

View File

@ -1,6 +1,3 @@
#if DISABLE_DEBUG
#undef DEBUG
#endif
using DCFApixels.DragonECS.AutoInjections; using DCFApixels.DragonECS.AutoInjections;
using DCFApixels.DragonECS.AutoInjections.Internal; using DCFApixels.DragonECS.AutoInjections.Internal;
using System; using System;
@ -13,8 +10,8 @@ namespace DCFApixels.DragonECS
internal class AutoInjectionMap internal class AutoInjectionMap
{ {
private readonly EcsPipeline _source; private readonly EcsPipeline _source;
private Dictionary<Type, List<InjectedPropertyRecord>> _injectedTypeToPropertiesMap = new Dictionary<Type, List<InjectedPropertyRecord>>(); private Dictionary<Type, List<InjectedPropertyRecord>> _systemProperties;
private HashSet<Type> _notInjected = new HashSet<Type>(); private HashSet<Type> _notInjected;
private bool _isDummyInjected = false; private bool _isDummyInjected = false;
private bool _isPreInitInjectionComplete = false; private bool _isPreInitInjectionComplete = false;
@ -23,19 +20,20 @@ namespace DCFApixels.DragonECS
{ {
_source = source; _source = source;
var allsystems = _source.AllSystems; var allsystems = _source.AllSystems;
_systemProperties = new Dictionary<Type, List<InjectedPropertyRecord>>();
_notInjected = new HashSet<Type>();
foreach (var system in allsystems) foreach (var system in allsystems)
{ {
Type systemType = system.GetType(); Type systemType = system.GetType();
if (systemType == typeof(AutoInjectSystem)) { continue; } if (systemType == typeof(AutoInjectSystem)) { continue; }
foreach (var property in GetAllPropertiesFor(systemType, isAgressiveInjection)) foreach (var property in GetAllPropertiesFor(systemType, isAgressiveInjection))
{ {
Type propertType = property.PropertyType; Type propertType = property.PropertyType;
List<InjectedPropertyRecord> list; List<InjectedPropertyRecord> list;
if (_injectedTypeToPropertiesMap.TryGetValue(propertType, out list) == false) if (!_systemProperties.TryGetValue(propertType, out list))
{ {
list = new List<InjectedPropertyRecord>(); list = new List<InjectedPropertyRecord>();
_injectedTypeToPropertiesMap.Add(propertType, list); _systemProperties.Add(propertType, list);
} }
list.Add(new InjectedPropertyRecord(system, property)); list.Add(new InjectedPropertyRecord(system, property));
if (property.GetAutoInjectAttribute() != DIAttribute.Dummy) if (property.GetAutoInjectAttribute() != DIAttribute.Dummy)
@ -44,101 +42,87 @@ namespace DCFApixels.DragonECS
} }
} }
} }
//foreach (var pair in _systemProperties)
//{
// _notInjected.Add(pair.Key);
//}
} }
private static List<IInjectedProperty> GetAllPropertiesFor(Type type, bool isAgressiveInjection)
{
List<IInjectedProperty> result = new List<IInjectedProperty>();
GetAllPropertiesFor(type, isAgressiveInjection, result);
return result;
}
private static void GetAllPropertiesFor(Type type, bool isAgressiveInjection, List<IInjectedProperty> result)
{
const BindingFlags REFL_FLAGS = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic;
result.AddRange(type.GetFields(REFL_FLAGS) //private bool IsInjectTarget(MemberInfo member)
.Where(o => isAgressiveInjection || o.HasAttribute<DIAttribute>()) //{
// return _isAgressiveInjection || member.GetCustomAttribute<EcsInjectAttribute>() != null;
//}
private static void Do(Type type, List<IInjectedProperty> result, bool isAgressiveInjection)
{
const BindingFlags bindingFlags = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic;
result.AddRange(type.GetFields(bindingFlags)
.Where(o => isAgressiveInjection || o.GetCustomAttribute<DIAttribute>() != null)
.Select(o => new InjectedField(o))); .Select(o => new InjectedField(o)));
result.AddRange(type.GetProperties(bindingFlags)
result.AddRange(type.GetProperties(REFL_FLAGS)
.Where(o => .Where(o =>
{ {
if (!isAgressiveInjection && o.HasAttribute<DIAttribute>() == false) if (!isAgressiveInjection && o.GetCustomAttribute<DIAttribute>() == null)
{ {
return false; return false;
} }
#if DEBUG #if (DEBUG && !DISABLE_DEBUG) || ENABLE_DRAGONECS_ASSERT_CHEKS
if (!isAgressiveInjection && o.CanWrite == false) { Throw.PropertyIsCantWrite(o); } if (!isAgressiveInjection && o.CanWrite == false) { Throw.PropertyIsCantWrite(o); }
#endif #endif
return o.CanWrite; return o.CanWrite == false;
}) })
.Select(o => new InjectedProperty(o))); .Select(o => new InjectedProperty(o)));
result.AddRange(type.GetMethods(bindingFlags)
result.AddRange(type.GetMethods(REFL_FLAGS)
.Where(o => .Where(o =>
{ {
if (!isAgressiveInjection && o.HasAttribute<DIAttribute>() == false) if (!isAgressiveInjection && o.GetCustomAttribute<DIAttribute>() == null)
{ {
return false; return false;
} }
var parameters = o.GetParameters(); var parameters = o.GetParameters();
#if (DEBUG && !DISABLE_DEBUG) || ENABLE_DRAGONECS_ASSERT_CHEKS
if (!isAgressiveInjection) if (!isAgressiveInjection)
{ {
#if DEBUG
if (o.IsGenericMethod) { Throw.MethodIsGeneric(o); } if (o.IsGenericMethod) { Throw.MethodIsGeneric(o); }
if (parameters.Length != 1) { Throw.MethodArgumentsGreater1(o); } if (parameters.Length != 1) { Throw.MethodArgumentsGreater1(o); }
#endif
} }
#endif
return o.IsGenericMethod == false && parameters.Length == 1; return o.IsGenericMethod == false && parameters.Length == 1;
}) })
.Select(o => new InjectedMethod(o))); .Select(o => new InjectedMethod(o)));
if (type.BaseType != null) if (type.BaseType != null)
{ {
GetAllPropertiesFor(type.BaseType, isAgressiveInjection, result); Do(type.BaseType, result, isAgressiveInjection);
} }
} }
private Type[] _relatedTypesBuffer; private static List<IInjectedProperty> GetAllPropertiesFor(Type type, bool isAgressiveInjection)
{
List<IInjectedProperty> result = new List<IInjectedProperty>();
Do(type, result, isAgressiveInjection);
return result;
}
public void Inject(Type fieldType, object obj) public void Inject(Type fieldType, object obj)
{ {
if (!_isPreInitInjectionComplete)
if (_relatedTypesBuffer == null || _relatedTypesBuffer.Length < _injectedTypeToPropertiesMap.Count)
{ {
_relatedTypesBuffer = new Type[_injectedTypeToPropertiesMap.Count]; _notInjected.Remove(fieldType);
} }
int relatedTypesCount = 0;
foreach (var pair in _injectedTypeToPropertiesMap) if (_systemProperties.TryGetValue(fieldType, out List<InjectedPropertyRecord> list))
{ {
if (pair.Key == fieldType || pair.Key.IsAssignableFrom(fieldType)) foreach (var item in list)
{ {
_relatedTypesBuffer[relatedTypesCount++] = pair.Key; item.property.Inject(item.target, obj);
} }
} }
foreach (var type in new ReadOnlySpan<Type>(_relatedTypesBuffer, 0, relatedTypesCount))
{
if (_injectedTypeToPropertiesMap.TryGetValue(type, out List<InjectedPropertyRecord> list))
{
string name = string.Empty;
if (obj is INamedMember named)
{
name = named.Name;
}
foreach (var item in list)
{
string propertyName = item.Attribute.NamedInjection;
if (string.IsNullOrEmpty(propertyName) || propertyName == name)
{
if (_isPreInitInjectionComplete == false)
{
_notInjected.Remove(item.property.PropertyType);
}
item.property.Inject(item.target, obj);
}
}
}
}
Type baseType = fieldType.BaseType;
if (baseType != null)
{
Inject(baseType, obj);
}
} }
public void InjectDummy() public void InjectDummy()
@ -148,18 +132,18 @@ namespace DCFApixels.DragonECS
_isDummyInjected = true; _isDummyInjected = true;
foreach (var notInjectedItem in _notInjected) foreach (var notInjectedItem in _notInjected)
{ {
foreach (var systemRecord in _injectedTypeToPropertiesMap[notInjectedItem]) foreach (var systemRecord in _systemProperties[notInjectedItem])
{ {
if (systemRecord.Attribute.NotNullDummyType == null) if (systemRecord.Attribute.notNullDummyType == null)
continue; continue;
if (systemRecord.property.IsInjected) if (systemRecord.property.IsInjected)
continue; continue;
if (systemRecord.property.PropertyType.IsAssignableFrom(systemRecord.Attribute.NotNullDummyType) == false) if (systemRecord.property.PropertyType.IsAssignableFrom(systemRecord.Attribute.notNullDummyType) == false)
{ {
EcsDebug.Print(EcsConsts.DEBUG_ERROR_TAG, $"The {systemRecord.Attribute.NotNullDummyType} dummy cannot be assigned to the {systemRecord.property.PropertyType.Name} field"); EcsDebug.Print(EcsConsts.DEBUG_ERROR_TAG, $"The {systemRecord.Attribute.notNullDummyType} dummy cannot be assigned to the {systemRecord.property.PropertyType.Name} field");
continue; continue;
} }
systemRecord.property.Inject(systemRecord.target, DummyInstance.GetInstance(systemRecord.Attribute.NotNullDummyType)); systemRecord.property.Inject(systemRecord.target, DummyInstance.GetInstance(systemRecord.Attribute.notNullDummyType));
} }
} }
WarningMissedInjections(); WarningMissedInjections();
@ -172,7 +156,7 @@ namespace DCFApixels.DragonECS
#if DEBUG #if DEBUG
foreach (var item in _notInjected) foreach (var item in _notInjected)
{ {
foreach (var systemRecord in _injectedTypeToPropertiesMap[item]) foreach (var systemRecord in _systemProperties[item])
{ {
EcsDebug.PrintWarning($"in system {EcsDebugUtility.GetGenericTypeFullName(systemRecord.target.GetType(), 1)} is missing an injection of {EcsDebugUtility.GetGenericTypeFullName(item, 1)}."); EcsDebug.PrintWarning($"in system {EcsDebugUtility.GetGenericTypeFullName(systemRecord.target.GetType(), 1)} is missing an injection of {EcsDebugUtility.GetGenericTypeFullName(item, 1)}.");
} }
@ -202,33 +186,15 @@ namespace DCFApixels.DragonECS
[MetaColor(MetaColor.Gray)] [MetaColor(MetaColor.Gray)]
[MetaGroup(EcsAutoInjectionsConsts.PACK_GROUP, EcsConsts.DI_GROUP)] [MetaGroup(EcsAutoInjectionsConsts.PACK_GROUP, EcsConsts.DI_GROUP)]
[MetaDescription(EcsConsts.AUTHOR, "The system responsible for the processing of automatic injections. The .AutoInject() method adds an AutoInjectSystem to the systems pipelines.")] [MetaDescription(EcsConsts.AUTHOR, "The system responsible for the processing of automatic injections. The .AutoInject() method adds an AutoInjectSystem to the systems pipelines.")]
public class AutoInjectSystem : IEcsInject<object>, IEcsPipelineMember, IOnInitInjectionComplete, IEcsDefaultAddParams public class AutoInjectSystem : IEcsInject<object>, IEcsPipelineMember, IOnInitInjectionComplete
{ {
public AddParams AddParams => new AddParams(layerName: EcsConsts.PRE_BEGIN_LAYER, isUnique: true);
private EcsPipeline _pipeline; private EcsPipeline _pipeline;
EcsPipeline IEcsPipelineMember.Pipeline { get => _pipeline; set => _pipeline = value; }
private List<object> _delayedInjects = new List<object>(); private List<object> _delayedInjects = new List<object>();
private AutoInjectionMap _autoInjectionMap; private AutoInjectionMap _autoInjectionMap;
private bool _isInitInjectionCompleted; private bool _isInitInjectionCompleted;
private bool _isAgressiveInjection; private bool _isAgressiveInjection;
static AutoInjectSystem()
{
EcsAspect.OnInit -= EcsAspect_OnInit;
EcsAspect.OnInit += EcsAspect_OnInit;
EcsAspect.OnAfterInit -= EcsAspect_OnBuild;
EcsAspect.OnAfterInit += EcsAspect_OnBuild;
}
private static void EcsAspect_OnInit(object aspect, EcsAspect.Builder builder)
{
EcsAspectAutoHelper.FillFields(aspect, builder);
}
private static void EcsAspect_OnBuild(object aspect, EcsMask mask)
{
EcsAspectAutoHelper.FillMaskFields(aspect, mask);
}
public AutoInjectSystem(bool isAgressiveInjection = false) public AutoInjectSystem(bool isAgressiveInjection = false)
{ {
_isAgressiveInjection = isAgressiveInjection; _isAgressiveInjection = isAgressiveInjection;
@ -246,7 +212,6 @@ namespace DCFApixels.DragonECS
} }
} }
public void OnBeforeInitInjection() { }
public void OnInitInjectionComplete() public void OnInitInjectionComplete()
{ {
_autoInjectionMap = new AutoInjectionMap(_pipeline, _isAgressiveInjection); _autoInjectionMap = new AutoInjectionMap(_pipeline, _isAgressiveInjection);
@ -263,8 +228,6 @@ namespace DCFApixels.DragonECS
_delayedInjects = null; _delayedInjects = null;
GC.Collect(0); GC.Collect(0);
} }
EcsPipeline IEcsPipelineMember.Pipeline { get => _pipeline; set => _pipeline = value; }
} }
#region Utils #region Utils

View File

@ -1,23 +1,10 @@
#if DISABLE_DEBUG namespace DCFApixels.DragonECS
#undef DEBUG
#endif
namespace DCFApixels.DragonECS
{ {
public static class AutoInjectSystemExtensions public static class AutoInjectSystemExtensions
{ {
[MetaColor(MetaColor.DragonCyan)]
public class AutoInjectModule : IEcsModule
{
public bool isAgressiveInjection;
public void Import(EcsPipeline.Builder b)
{
b.AddUnique(new AutoInjectSystem(isAgressiveInjection));
}
}
public static EcsPipeline.Builder AutoInject(this EcsPipeline.Builder self, bool isAgressiveInjection = false) public static EcsPipeline.Builder AutoInject(this EcsPipeline.Builder self, bool isAgressiveInjection = false)
{ {
self.AddUnique(new AutoInjectSystem(isAgressiveInjection)); self.Add(new AutoInjectSystem(isAgressiveInjection));
return self; return self;
} }
} }

View File

@ -1,8 +1,4 @@
#if DISABLE_DEBUG using System;
#undef DEBUG
#endif
using System;
[AttributeUsage(AttributeTargets.Interface, Inherited = false, AllowMultiple = false)] [AttributeUsage(AttributeTargets.Interface, Inherited = false, AllowMultiple = false)]
public sealed class BindWithRunnerAttribute : Attribute public sealed class BindWithRunnerAttribute : Attribute
{ {

View File

@ -1,7 +1,4 @@
#if DISABLE_DEBUG using DCFApixels.DragonECS.AutoInjections.Internal;
#undef DEBUG
#endif
using DCFApixels.DragonECS.AutoInjections.Internal;
using System; using System;
using System.Reflection; using System.Reflection;

View File

@ -1,7 +1,4 @@
#if DISABLE_DEBUG using System;
#undef DEBUG
#endif
using System;
using System.Reflection; using System.Reflection;
namespace DCFApixels.DragonECS namespace DCFApixels.DragonECS

View File

@ -1,7 +1,4 @@
#if DISABLE_DEBUG using System;
#undef DEBUG
#endif
using System;
using System.Reflection; using System.Reflection;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;

View File

@ -1,7 +1,4 @@
#if DISABLE_DEBUG using System;
#undef DEBUG
#endif
using System;
using System.Reflection; using System.Reflection;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
@ -21,10 +18,5 @@ namespace DCFApixels.DragonECS.AutoInjections.Internal
attribute = self.GetCustomAttribute<T>(); attribute = self.GetCustomAttribute<T>();
return attribute != null; return attribute != null;
} }
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool HasAttribute<T>(this MemberInfo self) where T : Attribute
{
return self.GetCustomAttribute<T>() != null;
}
} }
} }