2023-03-11 17:11:40 +08:00
|
|
|
|
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
|
2023-03-11 17:11:40 +08:00
|
|
|
|
{
|
|
|
|
|
public readonly Type interfaceType;
|
|
|
|
|
public readonly object filter;
|
2023-03-12 01:33:48 +08:00
|
|
|
|
public EcsRunnerFilterAttribute(Type interfaceType, object filter)
|
2023-03-11 17:11:40 +08:00
|
|
|
|
{
|
|
|
|
|
this.interfaceType = interfaceType;
|
|
|
|
|
this.filter = filter;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2023-03-12 01:33:48 +08:00
|
|
|
|
public interface IEcsProcessor { }
|
2023-03-11 17:11:40 +08:00
|
|
|
|
|
2023-03-12 01:33:48 +08:00
|
|
|
|
public static class IEcsProcessorExtensions
|
2023-03-11 17:11:40 +08:00
|
|
|
|
{
|
2023-03-12 01:33:48 +08:00
|
|
|
|
public static bool IsRunner(this IEcsProcessor self)
|
2023-03-11 17:11:40 +08:00
|
|
|
|
{
|
2023-03-12 01:33:48 +08:00
|
|
|
|
return self is IEcsRunner;
|
2023-03-11 17:11:40 +08:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2023-03-12 01:33:48 +08:00
|
|
|
|
internal static class EcsRunnerActivator
|
2023-03-11 17:11:40 +08:00
|
|
|
|
{
|
|
|
|
|
private static bool _isInit = false;
|
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
|
|
|
public static void Init()
|
|
|
|
|
{
|
|
|
|
|
if (_isInit) return;
|
2023-03-12 01:33:48 +08:00
|
|
|
|
Type targetType = typeof(EcsRunner<>);
|
2023-03-11 17:11:40 +08:00
|
|
|
|
var subclasses = Assembly.GetAssembly(targetType).GetTypes().Where(type => type.BaseType != null && type.BaseType.IsGenericType && targetType == type.BaseType.GetGenericTypeDefinition());
|
|
|
|
|
foreach (var item in subclasses)
|
|
|
|
|
{
|
|
|
|
|
item.BaseType.GetMethod("Init", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static).Invoke(null, new object[] { item });
|
|
|
|
|
}
|
|
|
|
|
_isInit = true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2023-03-12 01:33:48 +08:00
|
|
|
|
public interface IEcsRunner { }
|
|
|
|
|
|
|
|
|
|
public abstract class EcsRunner<TInterface> : IEcsProcessor, IEcsRunner
|
|
|
|
|
where TInterface : IEcsProcessor
|
2023-03-11 17:11:40 +08:00
|
|
|
|
{
|
|
|
|
|
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-11 17:11:40 +08:00
|
|
|
|
{
|
2023-03-12 01:33:48 +08:00
|
|
|
|
throw new ArgumentException($"{typeof(TInterface).FullName} does not directly inherit the {nameof(IEcsProcessor)} interface");
|
2023-03-11 17:11:40 +08:00
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
_subclass = subclass;
|
|
|
|
|
}
|
|
|
|
|
|
2023-03-12 01:33:48 +08:00
|
|
|
|
public static TInterface Instantiate(IEnumerable<IEcsProcessor> targets, object filter)
|
2023-03-11 17:11:40 +08:00
|
|
|
|
{
|
|
|
|
|
Type interfaceType = typeof(TInterface);
|
|
|
|
|
|
2023-03-12 01:33:48 +08:00
|
|
|
|
IEnumerable<TInterface> newTargets = targets.OfType<TInterface>();
|
2023-03-11 17:11:40 +08:00
|
|
|
|
|
|
|
|
|
if (filter != null)
|
|
|
|
|
{
|
2023-03-12 01:33:48 +08:00
|
|
|
|
newTargets = newTargets.Where(o =>
|
2023-03-11 17:11:40 +08:00
|
|
|
|
{
|
|
|
|
|
if (o is TInterface == false) return false;
|
2023-03-12 01:33:48 +08:00
|
|
|
|
var atr = o.GetType().GetCustomAttribute<EcsRunnerFilterAttribute>();
|
2023-03-11 17:11:40 +08:00
|
|
|
|
return atr != null && atr.interfaceType == interfaceType && atr.filter.Equals(filter);
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2023-03-12 01:33:48 +08:00
|
|
|
|
newTargets = newTargets.Where(o =>
|
2023-03-11 17:11:40 +08:00
|
|
|
|
{
|
|
|
|
|
if (o is TInterface == false) return false;
|
2023-03-12 01:33:48 +08:00
|
|
|
|
var atr = o.GetType().GetCustomAttribute<EcsRunnerFilterAttribute>();
|
2023-03-11 17:11:40 +08:00
|
|
|
|
return atr == null || atr.interfaceType == interfaceType && atr.filter == null;
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
2023-03-12 01:33:48 +08:00
|
|
|
|
return Instantiate(newTargets.ToArray());
|
2023-03-11 17:11:40 +08:00
|
|
|
|
}
|
2023-03-12 01:33:48 +08:00
|
|
|
|
public static TInterface Instantiate(IEnumerable<IEcsProcessor> targets)
|
2023-03-11 17:11:40 +08:00
|
|
|
|
{
|
2023-03-12 01:33:48 +08:00
|
|
|
|
return Instantiate(targets.OfType<TInterface>().ToArray());
|
2023-03-11 17:11:40 +08:00
|
|
|
|
}
|
|
|
|
|
internal static TInterface Instantiate(TInterface[] targets)
|
|
|
|
|
{
|
2023-03-12 01:33:48 +08:00
|
|
|
|
EcsRunnerActivator.Init();
|
|
|
|
|
var instance = (EcsRunner<TInterface>)Activator.CreateInstance(_subclass);
|
|
|
|
|
return (TInterface)(IEcsProcessor)instance.Set(targets);
|
2023-03-11 17:11:40 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private static Type _subclass;
|
|
|
|
|
protected TInterface[] targets;
|
|
|
|
|
|
2023-03-12 01:33:48 +08:00
|
|
|
|
private EcsRunner<TInterface> Set(TInterface[] targets)
|
2023-03-11 17:11:40 +08:00
|
|
|
|
{
|
|
|
|
|
this.targets = targets;
|
|
|
|
|
return this;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|