DragonECS-AutoInjections/src/AutoInjectSystem.cs

177 lines
6.3 KiB
C#
Raw Normal View History

2023-03-29 16:43:06 +08:00
using System;
using System.Collections.Generic;
using System.Reflection;
namespace DCFApixels.DragonECS
{
2023-04-05 09:14:42 +08:00
internal static class DummyInstance<T>
{
public static T intsance = (T)Activator.CreateInstance(typeof(T));
}
2023-03-29 16:43:06 +08:00
internal class AutoInjectionMap
{
2023-03-30 05:33:55 +08:00
private readonly EcsPipeline _source;
2023-05-30 02:17:09 +08:00
private Dictionary<Type, List<FieldRecord>> _systems;
2023-04-05 09:14:42 +08:00
private HashSet<Type> _notInjected;
2023-05-27 15:59:57 +08:00
private Type _dummyInstance = typeof(DummyInstance<>);
2023-04-05 09:14:42 +08:00
private bool _isDummyInjected = false;
2023-03-29 16:43:06 +08:00
2023-03-30 05:33:55 +08:00
public AutoInjectionMap(EcsPipeline source)
2023-03-29 16:43:06 +08:00
{
_source = source;
var allsystems = _source.AllSystems;
2023-05-30 02:17:09 +08:00
_systems = new Dictionary<Type, List<FieldRecord>>();
2023-04-05 09:14:42 +08:00
_notInjected = new HashSet<Type>();
2023-03-29 16:43:06 +08:00
foreach (var system in allsystems)
{
Type systemType = system.GetType();
2023-05-26 23:32:29 +08:00
foreach (var field in GetAllFieldsFor(systemType))
2023-03-29 16:43:06 +08:00
{
2023-05-07 00:50:23 +08:00
EcsInjectAttribute autoInjectAttribute = field.GetCustomAttribute<EcsInjectAttribute>();
2023-04-05 09:14:42 +08:00
if (autoInjectAttribute != null)
2023-03-29 16:43:06 +08:00
{
Type fieldType = field.FieldType;
2023-05-30 02:17:09 +08:00
List<FieldRecord> list;
2023-03-29 16:43:06 +08:00
if (!_systems.TryGetValue(fieldType, out list))
{
2023-05-30 02:17:09 +08:00
list = new List<FieldRecord>();
2023-03-29 16:43:06 +08:00
_systems.Add(fieldType, list);
}
2023-05-30 02:17:09 +08:00
list.Add(new FieldRecord(system, field, autoInjectAttribute));
2023-03-29 16:43:06 +08:00
}
}
}
2023-04-05 09:14:42 +08:00
foreach (var item in _systems.Keys)
_notInjected.Add(item);
2023-03-29 16:43:06 +08:00
}
2023-05-26 23:32:29 +08:00
private static List<FieldInfo> GetAllFieldsFor(Type type)
{
List<FieldInfo> result = new List<FieldInfo>();
Do(type, result);
2023-05-30 02:17:09 +08:00
static void Do(Type type, List<FieldInfo> result)
2023-05-26 23:32:29 +08:00
{
result.AddRange(type.GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic));
if (type.BaseType != null)
Do(type.BaseType, result);
}
return result;
}
2023-05-30 02:17:09 +08:00
public void Inject(Type fieldType, object obj)
2023-03-29 16:43:06 +08:00
{
2023-04-05 09:14:42 +08:00
_notInjected.Remove(obj.GetType());
2023-05-30 02:17:09 +08:00
Type baseType = fieldType.BaseType;
if (baseType != null)
Inject(baseType, obj);
if (_systems.TryGetValue(fieldType, out List<FieldRecord> list))
2023-03-29 16:43:06 +08:00
{
foreach (var item in list)
item.field.SetValue(item.target, obj);
}
}
2023-04-05 09:14:42 +08:00
public void InjectDummy()
{
if (_isDummyInjected)
return;
_isDummyInjected = true;
foreach (var notInjectedItem in _notInjected)
{
foreach (var systemRecord in _systems[notInjectedItem])
{
if (systemRecord.attribute.notNullDummyType == null)
continue;
if (systemRecord.field.GetValue(systemRecord.target) != null)
continue;
if (systemRecord.field.FieldType.IsAssignableFrom(systemRecord.attribute.notNullDummyType) == false)
{
EcsDebug.Print(EcsConsts.DEBUG_ERROR_TAG, $"The {systemRecord.attribute.notNullDummyType} dummy cannot be assigned to the {systemRecord.field.FieldType.Name} field");
continue;
}
systemRecord.field.SetValue(systemRecord.target,
2023-05-27 15:59:57 +08:00
_dummyInstance.MakeGenericType(systemRecord.attribute.notNullDummyType).GetField("intsance", BindingFlags.Static | BindingFlags.Public).GetValue(null));
2023-04-05 09:14:42 +08:00
}
}
2023-05-27 15:59:57 +08:00
WarningMissedInjections();
2023-04-05 09:14:42 +08:00
_notInjected.Clear();
_notInjected= null;
}
2023-05-27 15:59:57 +08:00
private void WarningMissedInjections()
{
2023-05-28 05:53:37 +08:00
#if DEBUG
2023-05-27 15:59:57 +08:00
foreach (var item in _notInjected)
{
foreach (var systemRecord in _systems[item])
{
EcsDebug.PrintWarning($"in system {EcsDebugUtility.GetGenericTypeFullName(systemRecord.target.GetType(), 1)} is missing an injection of {EcsDebugUtility.GetGenericTypeFullName(item, 1)}.");
}
}
2023-05-28 05:53:37 +08:00
#endif
2023-05-27 15:59:57 +08:00
}
2023-05-30 02:17:09 +08:00
private readonly struct FieldRecord
2023-03-29 16:43:06 +08:00
{
public readonly IEcsSystem target;
public readonly FieldInfo field;
2023-05-07 00:50:23 +08:00
public readonly EcsInjectAttribute attribute;
2023-05-30 02:17:09 +08:00
public FieldRecord(IEcsSystem target, FieldInfo field, EcsInjectAttribute attribute)
2023-03-29 16:43:06 +08:00
{
this.target = target;
this.field = field;
2023-04-05 09:14:42 +08:00
this.attribute = attribute;
2023-03-29 16:43:06 +08:00
}
}
}
[DebugHide, DebugColor(DebugColor.Gray)]
2023-05-07 00:50:23 +08:00
public class AutoInjectSystem : IEcsPreInitProcess, IEcsPreInject, IEcsPreInitInjectProcess
2023-03-29 16:43:06 +08:00
{
2023-03-30 05:33:55 +08:00
private EcsPipeline _pipeline;
2023-03-29 16:43:06 +08:00
private List<object> _injectQueue = new List<object>();
private AutoInjectionMap _autoInjectionMap;
2023-04-05 09:14:42 +08:00
private bool _isPreInjectionComplete = false;
2023-03-29 16:43:06 +08:00
public void PreInject(object obj)
{
2023-03-30 05:33:55 +08:00
if(_pipeline == null)
2023-03-29 16:43:06 +08:00
{
_injectQueue.Add(obj);
return;
}
AutoInject(obj);
}
2023-03-30 05:33:55 +08:00
public void PreInit(EcsPipeline pipeline)
2023-03-29 16:43:06 +08:00
{
2023-03-30 05:33:55 +08:00
_pipeline = pipeline;
_autoInjectionMap = new AutoInjectionMap(_pipeline);
2023-03-29 16:43:06 +08:00
foreach (var obj in _injectQueue)
{
AutoInject(obj);
}
_injectQueue.Clear();
_injectQueue = null;
2023-04-05 09:14:42 +08:00
if (_isPreInjectionComplete)
{
_autoInjectionMap.InjectDummy();
}
2023-03-29 16:43:06 +08:00
}
private void AutoInject(object obj)
{
2023-05-30 02:17:09 +08:00
_autoInjectionMap.Inject(obj.GetType(), obj);
2023-03-29 16:43:06 +08:00
}
2023-04-05 09:14:42 +08:00
public void OnPreInitInjectionBefore() { }
public void OnPreInitInjectionAfter()
{
_isPreInjectionComplete = true;
if (_autoInjectionMap != null)
{
_autoInjectionMap.InjectDummy();
}
}
2023-03-29 16:43:06 +08:00
}
}