Compare commits

..

2 Commits

Author SHA1 Message Date
DCFApixels
6a3b78026d Update AutoInjectSystem.cs 2025-03-13 20:48:22 +08:00
DCFApixels
1b2cf99a68 update the aspect auto-build 2025-03-13 13:38:58 +08:00
3 changed files with 134 additions and 86 deletions

View File

@ -1,5 +1,7 @@
using DCFApixels.DragonECS.AutoInjections.Internal;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
namespace DCFApixels.DragonECS
@ -8,7 +10,7 @@ namespace DCFApixels.DragonECS
{
protected sealed override void Init(Builder b)
{
EcsAspectAutoHelper.Fill(this, b);
//EcsAspectAutoHelper.Fill(this, b);
InitAfterDI(b);
}
protected virtual void InitAfterDI(Builder b) { }
@ -16,90 +18,117 @@ namespace DCFApixels.DragonECS
internal static class EcsAspectAutoHelper
{
public static void Fill(EcsAspect s, EcsAspect.Builder b)
private static readonly MethodInfo _incluedMethod;
private static readonly MethodInfo _excludeMethod;
private static readonly MethodInfo _optionalMethod;
private static readonly MethodInfo _includeImplicitMethod;
private static readonly MethodInfo _excludeImplicitMethod;
private static readonly MethodInfo _combineMethod;
static EcsAspectAutoHelper()
{
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);
const BindingFlags REFL_FLAGS = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic;
Type aspectType = s.GetType();
Type builderType = typeof(EcsAspect.Builder);
foreach (var attribute in aspectType.GetCustomAttributes<ImplicitInjectAttribute>())//TODO убрать дублирование кода - вынести в отедльный метод
_incluedMethod = builderType.GetMethod("IncludePool", REFL_FLAGS);
_excludeMethod = builderType.GetMethod("ExcludePool", REFL_FLAGS);
_optionalMethod = builderType.GetMethod("OptionalPool", REFL_FLAGS);
_includeImplicitMethod = builderType.GetMethod("IncludeImplicit", REFL_FLAGS);
_excludeImplicitMethod = builderType.GetMethod("ExcludeImplicit", REFL_FLAGS);
_combineMethod = builderType.GetMethod("Combine", REFL_FLAGS);
}
public static void FillMaskFields(object aspect, EcsMask mask)
{
const BindingFlags REFL_FLAGS = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic;
foreach (FieldInfo fieldInfo in aspect.GetType().GetFields(REFL_FLAGS))
{
if (attribute is IncImplicitAttribute incImplicit)
if (fieldInfo.GetCustomAttribute<MaskAttribute>() == null)
{
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 (fieldInfo.FieldType == typeof(EcsMask))
{
if (excImplicit.isPool)
excludeMethod.MakeGenericMethod(excImplicit.type).Invoke(b, null);
else
excludeImplicitMethod.Invoke(b, new object[] { excImplicit.type });
continue;
fieldInfo.SetValue(aspect, mask);
}
}//TODO КОНЕЦ убрать дублирование кода - вынести в отедльный метод
else if (fieldInfo.FieldType == typeof(EcsStaticMask))
{
fieldInfo.SetValue(aspect, mask.ToStatic());
}
}
}
public static void FillFields(object aspect, EcsAspect.Builder builder)
{
const BindingFlags REFL_FLAGS = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic;
FieldInfo[] fieldInfos = aspectType.GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
Type aspectType = aspect.GetType();
var implicitInjectAttributes = (IEnumerable<ImplicitInjectAttribute>)aspectType.GetCustomAttributes<ImplicitInjectAttribute>();
FieldInfo[] fieldInfos = aspectType.GetFields(REFL_FLAGS);
foreach (FieldInfo fieldInfo in fieldInfos)
{
Type fieldType = fieldInfo.FieldType;
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 КОНЕЦ убрать дублирование кода - вынести в отедльный метод
implicitInjectAttributes = implicitInjectAttributes.Concat(fieldInfo.GetCustomAttributes<ImplicitInjectAttribute>());
if (!fieldInfo.TryGetCustomAttribute(out InjectAspectMemberAttribute injectAttribute))
if (fieldInfo.TryGetCustomAttribute(out InjectAspectMemberAttribute injectAttribute) == false)
{
continue;
}
if (injectAttribute is IncAttribute)
switch (injectAttribute)
{
fieldInfo.SetValue(s, incluedMethod.MakeGenericMethod(fieldType).Invoke(b, null));
case IncAttribute atr:
var x1 = _incluedMethod;
fieldInfo.SetValue(aspect, _incluedMethod.MakeGenericMethod(fieldType).Invoke(builder, null));
break;
case ExcAttribute atr:
var x2 = _excludeMethod;
fieldInfo.SetValue(aspect, _excludeMethod.MakeGenericMethod(fieldType).Invoke(builder, null));
break;
case OptAttribute atr:
var x3 = _optionalMethod;
fieldInfo.SetValue(aspect, _optionalMethod.MakeGenericMethod(fieldType).Invoke(builder, null));
break;
case CombineAttribute atr:
var x4 = _combineMethod;
fieldInfo.SetValue(aspect, _combineMethod.MakeGenericMethod(fieldType).Invoke(builder, new object[] { atr.Order }));
break;
default:
break;
}
}
void Inject(ImplicitInjectAttribute atr_, MethodInfo method_, MethodInfo implicitMethod_)
{
if (atr_.IsPool)
{
method_.MakeGenericMethod(atr_.Type).Invoke(builder, null);
}
else
{
implicitMethod_.Invoke(builder, new object[] { atr_.Type });
}
}
foreach (var attribute in implicitInjectAttributes)
{
if (attribute is IncImplicitAttribute incImplicit)
{
Inject(incImplicit, _incluedMethod, _includeImplicitMethod);
continue;
}
if (injectAttribute is ExcAttribute)
if (attribute is ExcImplicitAttribute excImplicit)
{
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 }));
Inject(excImplicit, _excludeMethod, _excludeImplicitMethod);
continue;
}
}
}
}
}

View File

@ -14,32 +14,32 @@ namespace DCFApixels.DragonECS
[AttributeUsage(AttributeTargets.Field, Inherited = false, AllowMultiple = false)]
public sealed class CombineAttribute : InjectAspectMemberAttribute
{
public readonly int order = 0;
public CombineAttribute(int order = 0) { this.order = order; }
public readonly int Order = 0;
public CombineAttribute(int order = 0) { 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 Type;
public readonly bool IsPool;
public ImplicitInjectAttribute(Type type)
{
Type = type;
IsPool = type.GetInterfaces().Any(o => o == typeof(IEcsPoolImplementation));
}
}
[AttributeUsage(AttributeTargets.Field | AttributeTargets.Class, Inherited = false, AllowMultiple = true)]
public sealed class IncImplicitAttribute : ImplicitInjectAttribute
{
public readonly Type type;
public readonly bool isPool;
public IncImplicitAttribute(Type type)
{
this.type = type;
isPool = type.GetInterfaces().Any(o => o == typeof(IEcsPoolImplementation));
}
public IncImplicitAttribute(Type type) : base(type) { }
}
[AttributeUsage(AttributeTargets.Field | AttributeTargets.Class, Inherited = false, AllowMultiple = true)]
public sealed class ExcImplicitAttribute : ImplicitInjectAttribute
{
public readonly Type type;
public readonly bool isPool;
public ExcImplicitAttribute(Type type)
{
this.type = type;
isPool = type.GetInterfaces().Any(o => o == typeof(IEcsPoolImplementation));
}
public ExcImplicitAttribute(Type type) : base(type) { }
}
}

View File

@ -10,7 +10,7 @@ namespace DCFApixels.DragonECS
internal class AutoInjectionMap
{
private readonly EcsPipeline _source;
private Dictionary<Type, List<InjectedPropertyRecord>> _systemProperties = new Dictionary<Type, List<InjectedPropertyRecord>>();
private Dictionary<Type, List<InjectedPropertyRecord>> _injectedTypeToPropertiesMap = new Dictionary<Type, List<InjectedPropertyRecord>>();
private HashSet<Type> _notInjected = new HashSet<Type>();
private bool _isDummyInjected = false;
@ -29,10 +29,10 @@ namespace DCFApixels.DragonECS
{
Type propertType = property.PropertyType;
List<InjectedPropertyRecord> list;
if (_systemProperties.TryGetValue(propertType, out list) == false)
if (_injectedTypeToPropertiesMap.TryGetValue(propertType, out list) == false)
{
list = new List<InjectedPropertyRecord>();
_systemProperties.Add(propertType, list);
_injectedTypeToPropertiesMap.Add(propertType, list);
}
list.Add(new InjectedPropertyRecord(system, property));
if (property.GetAutoInjectAttribute() != DIAttribute.Dummy)
@ -102,12 +102,12 @@ namespace DCFApixels.DragonECS
{
_notInjected.Remove(fieldType);
}
if (_relatedTypesBuffer == null || _relatedTypesBuffer.Length < _systemProperties.Count)
if (_relatedTypesBuffer == null || _relatedTypesBuffer.Length < _injectedTypeToPropertiesMap.Count)
{
_relatedTypesBuffer = new Type[_systemProperties.Count];
_relatedTypesBuffer = new Type[_injectedTypeToPropertiesMap.Count];
}
int relatedTypesCount = 0;
foreach (var pair in _systemProperties)
foreach (var pair in _injectedTypeToPropertiesMap)
{
if (pair.Key == fieldType || pair.Key.IsAssignableFrom(fieldType))
{
@ -117,7 +117,7 @@ namespace DCFApixels.DragonECS
foreach (var type in new ReadOnlySpan<Type>(_relatedTypesBuffer, 0, relatedTypesCount))
{
if (_systemProperties.TryGetValue(type, out List<InjectedPropertyRecord> list))
if (_injectedTypeToPropertiesMap.TryGetValue(type, out List<InjectedPropertyRecord> list))
{
string name = string.Empty;
if (obj is INamedMember named)
@ -144,7 +144,7 @@ namespace DCFApixels.DragonECS
_isDummyInjected = true;
foreach (var notInjectedItem in _notInjected)
{
foreach (var systemRecord in _systemProperties[notInjectedItem])
foreach (var systemRecord in _injectedTypeToPropertiesMap[notInjectedItem])
{
if (systemRecord.Attribute.NotNullDummyType == null)
continue;
@ -168,7 +168,7 @@ namespace DCFApixels.DragonECS
#if DEBUG
foreach (var item in _notInjected)
{
foreach (var systemRecord in _systemProperties[item])
foreach (var systemRecord in _injectedTypeToPropertiesMap[item])
{
EcsDebug.PrintWarning($"in system {EcsDebugUtility.GetGenericTypeFullName(systemRecord.target.GetType(), 1)} is missing an injection of {EcsDebugUtility.GetGenericTypeFullName(item, 1)}.");
}
@ -198,15 +198,31 @@ namespace DCFApixels.DragonECS
[MetaColor(MetaColor.Gray)]
[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.")]
public class AutoInjectSystem : IEcsInject<object>, IEcsPipelineMember, IOnInitInjectionComplete
public class AutoInjectSystem : IEcsInject<object>, IEcsPipelineMember, IOnInitInjectionComplete, IEcsDefaultAddParams
{
public AddParams AddParams => new AddParams(layerName: EcsConsts.PRE_BEGIN_LAYER, isUnique: true);
private EcsPipeline _pipeline;
EcsPipeline IEcsPipelineMember.Pipeline { get => _pipeline; set => _pipeline = value; }
private List<object> _delayedInjects = new List<object>();
private AutoInjectionMap _autoInjectionMap;
private bool _isInitInjectionCompleted;
private bool _isAgressiveInjection;
static AutoInjectSystem()
{
EcsAspect.OnInit += EcsAspect_OnInit;
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)
{
_isAgressiveInjection = isAgressiveInjection;
@ -224,6 +240,7 @@ namespace DCFApixels.DragonECS
}
}
public void OnBeforeInitInjection() { }
public void OnInitInjectionComplete()
{
_autoInjectionMap = new AutoInjectionMap(_pipeline, _isAgressiveInjection);
@ -240,6 +257,8 @@ namespace DCFApixels.DragonECS
_delayedInjects = null;
GC.Collect(0);
}
EcsPipeline IEcsPipelineMember.Pipeline { get => _pipeline; set => _pipeline = value; }
}
#region Utils