DragonECS/src/React/EcsRunner.cs

192 lines
6.6 KiB
C#
Raw Normal View History

using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
namespace DCFApixels.DragonECS
{
[AttributeUsage(AttributeTargets.Class, Inherited = false, AllowMultiple = true)]
2023-03-12 01:33:48 +08:00
sealed class EcsRunnerFilterAttribute : Attribute
{
public readonly Type interfaceType;
public readonly object filter;
2023-03-12 01:33:48 +08:00
public EcsRunnerFilterAttribute(Type interfaceType, object filter)
{
this.interfaceType = interfaceType;
this.filter = filter;
}
}
2023-03-12 01:33:48 +08:00
public interface IEcsProcessor { }
2023-03-12 01:33:48 +08:00
public static class IEcsProcessorExtensions
{
2023-03-12 01:33:48 +08:00
public static bool IsRunner(this IEcsProcessor self)
{
2023-03-12 01:33:48 +08:00
return self is IEcsRunner;
}
}
2023-03-12 02:02:39 +08:00
2023-03-12 01:33:48 +08:00
internal static class EcsRunnerActivator
{
2023-03-12 02:02:39 +08:00
private static Dictionary<Guid, Type> _runnerTypes; //interface guid/ Runner type pairs;
static EcsRunnerActivator()
{
List<Exception> exceptions = new List<Exception>();
Type runnerBaseType = typeof(EcsRunner<>);
List<Type> newRunnerTypes = new List<Type>();
newRunnerTypes = Assembly.GetAssembly(runnerBaseType)
.GetTypes()
.Where(type => type.BaseType != null && type.BaseType.IsGenericType && runnerBaseType == type.BaseType.GetGenericTypeDefinition())
.ToList();
#if DEBUG
for (int i = 0; i < newRunnerTypes.Count; i++)
{
var e = CheckRunnerValide(newRunnerTypes[i]);
if (e != null)
{
newRunnerTypes.RemoveAt(i--);
exceptions.Add(e);
}
}
#endif
_runnerTypes = new Dictionary<Guid, Type>();
foreach (var item in newRunnerTypes)
{
2023-03-12 02:48:51 +08:00
Type intrf = item.GetInterfaces().Where(o => o != typeof(IEcsRunner) && o != typeof(IEcsProcessor)).First(); //TODO оптимизировать это место
2023-03-12 02:02:39 +08:00
_runnerTypes.Add(intrf.GUID, item);
}
if (exceptions.Count > 0)
{
foreach (var item in exceptions) throw item;
}
}
private static Exception CheckRunnerValide(Type type) //TODO доработать проверку валидности реалиазации ранера
{
if (type.ReflectedType != null)
return new Exception($"{type.FullName}.ReflectedType must be Null, but equal to {type.ReflectedType.FullName}");
//var interfaces = type.GetInterfaces();
//if (interfaces.Length != 1 || interfaces[0].GUID != typeof())
//{
//}
return null;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
2023-03-12 02:02:39 +08:00
public static void InitFor<TInterface>() where TInterface : IEcsProcessor
{
2023-03-12 02:02:39 +08:00
Type interfaceType = typeof(TInterface);
2023-03-12 02:48:51 +08:00
Type nonGenericInterfaceType = interfaceType;
if (nonGenericInterfaceType.IsGenericType)
{
nonGenericInterfaceType = nonGenericInterfaceType.GetGenericTypeDefinition();
}
Guid interfaceGuid = nonGenericInterfaceType.GUID;
2023-03-12 02:02:39 +08:00
if (!_runnerTypes.TryGetValue(interfaceGuid, out Type runnerType))
{
throw new Exception();
}
if (interfaceType.IsGenericType)
{
2023-03-12 02:02:39 +08:00
Type[] genericTypes = interfaceType.GetGenericArguments();
runnerType = runnerType.MakeGenericType(genericTypes);
}
2023-03-12 02:02:39 +08:00
EcsRunner<TInterface>.Init(runnerType);
}
}
2023-03-12 01:33:48 +08:00
public interface IEcsRunner { }
public abstract class EcsRunner<TInterface> : IEcsProcessor, IEcsRunner
where TInterface : IEcsProcessor
{
internal static void Init(Type subclass)
{
#if DEBUG || DCFAECS_NO_SANITIZE_CHECKS
if (_subclass != null)
{
throw new ArgumentException($"The Runner<{typeof(TInterface).FullName}> can only have one subclass");
}
Type interfaceType = typeof(TInterface);
var interfaces = interfaceType.GetInterfaces();
if (interfaceType.IsInterface == false)
{
throw new ArgumentException($"{typeof(TInterface).FullName} is not interface");
}
2023-03-12 01:33:48 +08:00
if (interfaces.Length != 1 || interfaces[0] != typeof(IEcsProcessor))
{
2023-03-12 01:33:48 +08:00
throw new ArgumentException($"{typeof(TInterface).FullName} does not directly inherit the {nameof(IEcsProcessor)} interface");
}
#endif
_subclass = subclass;
}
2023-03-12 01:33:48 +08:00
public static TInterface Instantiate(IEnumerable<IEcsProcessor> targets, object filter)
{
Type interfaceType = typeof(TInterface);
2023-03-12 02:02:39 +08:00
IEnumerable<IEcsProcessor> newTargets;
if (filter != null)
{
2023-03-12 02:02:39 +08:00
newTargets = targets.Where(o =>
{
if (o is TInterface == false) return false;
2023-03-12 01:33:48 +08:00
var atr = o.GetType().GetCustomAttribute<EcsRunnerFilterAttribute>();
return atr != null && atr.interfaceType == interfaceType && atr.filter.Equals(filter);
});
}
else
{
2023-03-12 02:02:39 +08:00
newTargets = targets.Where(o =>
{
if (o is TInterface == false) return false;
2023-03-12 01:33:48 +08:00
var atr = o.GetType().GetCustomAttribute<EcsRunnerFilterAttribute>();
return atr == null || atr.interfaceType == interfaceType && atr.filter == null;
});
}
2023-03-12 02:02:39 +08:00
return Instantiate(newTargets.Select(o => (TInterface)o).ToArray());
}
2023-03-12 01:33:48 +08:00
public static TInterface Instantiate(IEnumerable<IEcsProcessor> targets)
{
2023-03-12 02:02:39 +08:00
return Instantiate(targets.Where(o => o is TInterface).Select(o => (TInterface)o).ToArray());
}
internal static TInterface Instantiate(TInterface[] targets)
{
2023-03-12 02:02:39 +08:00
if (_subclass == null)
EcsRunnerActivator.InitFor<TInterface>();
2023-03-12 01:33:48 +08:00
var instance = (EcsRunner<TInterface>)Activator.CreateInstance(_subclass);
return (TInterface)(IEcsProcessor)instance.Set(targets);
}
private static Type _subclass;
2023-03-12 02:02:39 +08:00
protected static void SetSublcass(Type type) => _subclass = type;
protected TInterface[] targets;
2023-03-12 01:33:48 +08:00
private EcsRunner<TInterface> Set(TInterface[] targets)
{
this.targets = targets;
return this;
}
}
}