2023-03-11 17:11:40 +08:00
|
|
|
|
using System;
|
2023-03-26 11:19:03 +08:00
|
|
|
|
using System.Collections;
|
2023-03-11 17:11:40 +08:00
|
|
|
|
using System.Collections.Generic;
|
2023-03-26 11:19:03 +08:00
|
|
|
|
using System.Collections.ObjectModel;
|
|
|
|
|
using System.Linq.Expressions;
|
2023-03-11 17:11:40 +08:00
|
|
|
|
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 20:45:18 +08:00
|
|
|
|
|
|
|
|
|
public EcsRunnerFilterAttribute(object filter)
|
|
|
|
|
{
|
|
|
|
|
interfaceType = null;
|
|
|
|
|
this.filter = filter;
|
|
|
|
|
}
|
2023-03-11 17:11:40 +08:00
|
|
|
|
}
|
|
|
|
|
|
2023-03-12 20:45:18 +08:00
|
|
|
|
public interface IEcsSystem { }
|
2023-03-26 11:19:03 +08:00
|
|
|
|
public interface IEcsRunner
|
|
|
|
|
{
|
|
|
|
|
public IList Targets { get; }
|
|
|
|
|
public object Filter { get; }
|
|
|
|
|
public bool IsHasFilter { get; }
|
|
|
|
|
}
|
2023-03-16 01:49:14 +08:00
|
|
|
|
|
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 20:45:18 +08:00
|
|
|
|
public static bool IsRunner(this IEcsSystem 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
|
|
|
|
{
|
2023-03-26 11:19:03 +08:00
|
|
|
|
private static Dictionary<Guid, Type> _runnerHandlerTypes; //interface guid/Runner handler type pairs;
|
2023-03-12 02:02:39 +08:00
|
|
|
|
|
|
|
|
|
static EcsRunnerActivator()
|
|
|
|
|
{
|
|
|
|
|
List<Exception> exceptions = new List<Exception>();
|
|
|
|
|
|
|
|
|
|
Type runnerBaseType = typeof(EcsRunner<>);
|
|
|
|
|
|
2023-03-26 11:19:03 +08:00
|
|
|
|
List<Type> runnerHandlerTypes = new List<Type>();
|
|
|
|
|
runnerHandlerTypes = Assembly.GetAssembly(runnerBaseType)
|
2023-03-12 02:02:39 +08:00
|
|
|
|
.GetTypes()
|
|
|
|
|
.Where(type => type.BaseType != null && type.BaseType.IsGenericType && runnerBaseType == type.BaseType.GetGenericTypeDefinition())
|
|
|
|
|
.ToList();
|
|
|
|
|
|
2023-03-26 11:19:03 +08:00
|
|
|
|
#if DEBUG || !DRAGONECS_NO_SANITIZE_CHECKS
|
|
|
|
|
for (int i = 0; i < runnerHandlerTypes.Count; i++)
|
2023-03-12 02:02:39 +08:00
|
|
|
|
{
|
2023-03-26 11:19:03 +08:00
|
|
|
|
var e = CheckRunnerValide(runnerHandlerTypes[i]);
|
2023-03-12 02:02:39 +08:00
|
|
|
|
if (e != null)
|
|
|
|
|
{
|
2023-03-26 11:19:03 +08:00
|
|
|
|
runnerHandlerTypes.RemoveAt(i--);
|
2023-03-12 02:02:39 +08:00
|
|
|
|
exceptions.Add(e);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
#endif
|
2023-03-26 11:19:03 +08:00
|
|
|
|
_runnerHandlerTypes = new Dictionary<Guid, Type>();
|
|
|
|
|
foreach (var item in runnerHandlerTypes)
|
2023-03-12 02:02:39 +08:00
|
|
|
|
{
|
2023-03-26 11:19:03 +08:00
|
|
|
|
Type interfaceType = item.GetInterfaces().Where(o => o != typeof(IEcsRunner) && o != typeof(IEcsSystem)).First(); //TODO оптимизировать это место
|
|
|
|
|
_runnerHandlerTypes.Add(interfaceType.GUID, item);
|
2023-03-12 02:02:39 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2023-03-11 17:11:40 +08:00
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
2023-03-16 01:49:14 +08:00
|
|
|
|
internal static void InitFor<TInterface>() where TInterface : IEcsSystem
|
2023-03-11 17:11:40 +08:00
|
|
|
|
{
|
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
|
|
|
|
|
2023-03-26 11:19:03 +08:00
|
|
|
|
if (!_runnerHandlerTypes.TryGetValue(interfaceGuid, out Type runnerType))
|
2023-03-12 02:02:39 +08:00
|
|
|
|
{
|
|
|
|
|
throw new Exception();
|
|
|
|
|
}
|
|
|
|
|
if (interfaceType.IsGenericType)
|
2023-03-11 17:11:40 +08:00
|
|
|
|
{
|
2023-03-12 02:02:39 +08:00
|
|
|
|
Type[] genericTypes = interfaceType.GetGenericArguments();
|
|
|
|
|
runnerType = runnerType.MakeGenericType(genericTypes);
|
2023-03-11 17:11:40 +08:00
|
|
|
|
}
|
2023-03-26 11:19:03 +08:00
|
|
|
|
EcsRunner<TInterface>.Register(runnerType);
|
2023-03-11 17:11:40 +08:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2023-03-12 20:45:18 +08:00
|
|
|
|
public abstract class EcsRunner<TInterface> : IEcsSystem, IEcsRunner
|
|
|
|
|
where TInterface : IEcsSystem
|
2023-03-11 17:11:40 +08:00
|
|
|
|
{
|
2023-03-26 11:19:03 +08:00
|
|
|
|
#region Register
|
|
|
|
|
private static Type _subclass;
|
|
|
|
|
internal static void Register(Type subclass)
|
2023-03-11 17:11:40 +08:00
|
|
|
|
{
|
2023-03-16 01:49:14 +08:00
|
|
|
|
#if DEBUG || !DRAGONECS_NO_SANITIZE_CHECKS
|
2023-03-11 17:11:40 +08:00
|
|
|
|
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 20:45:18 +08:00
|
|
|
|
if (interfaces.Length != 1 || interfaces[0] != typeof(IEcsSystem))
|
2023-03-11 17:11:40 +08:00
|
|
|
|
{
|
2023-03-12 20:45:18 +08:00
|
|
|
|
throw new ArgumentException($"{typeof(TInterface).FullName} does not directly inherit the {nameof(IEcsSystem)} interface");
|
2023-03-11 17:11:40 +08:00
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
_subclass = subclass;
|
|
|
|
|
}
|
2023-03-26 11:19:03 +08:00
|
|
|
|
#endregion
|
2023-03-11 17:11:40 +08:00
|
|
|
|
|
2023-03-26 11:19:03 +08:00
|
|
|
|
#region FilterSystems
|
|
|
|
|
private static TInterface[] FilterSystems(IEnumerable<IEcsSystem> targets)
|
|
|
|
|
{
|
|
|
|
|
return targets.Where(o => o is TInterface).Select(o => (TInterface)o).ToArray();
|
|
|
|
|
}
|
|
|
|
|
private static TInterface[] FilterSystems(IEnumerable<IEcsSystem> targets, object filter)
|
2023-03-11 17:11:40 +08:00
|
|
|
|
{
|
|
|
|
|
Type interfaceType = typeof(TInterface);
|
|
|
|
|
|
2023-03-12 20:45:18 +08:00
|
|
|
|
IEnumerable<IEcsSystem> newTargets;
|
2023-03-11 17:11:40 +08:00
|
|
|
|
|
|
|
|
|
if (filter != null)
|
|
|
|
|
{
|
2023-03-12 02:02:39 +08:00
|
|
|
|
newTargets = targets.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 02:02:39 +08:00
|
|
|
|
newTargets = targets.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-26 11:19:03 +08:00
|
|
|
|
return newTargets.Select(o => (TInterface)o).ToArray();
|
2023-03-11 17:11:40 +08:00
|
|
|
|
}
|
2023-03-26 11:19:03 +08:00
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
|
#region Instantiate
|
|
|
|
|
private static TInterface Instantiate(TInterface[] targets, bool isHasFilter, object filter)
|
2023-03-11 17:11:40 +08:00
|
|
|
|
{
|
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);
|
2023-03-26 11:19:03 +08:00
|
|
|
|
return (TInterface)(IEcsSystem)instance.Set(targets, isHasFilter, filter);
|
2023-03-11 17:11:40 +08:00
|
|
|
|
}
|
2023-03-26 11:19:03 +08:00
|
|
|
|
public static TInterface Instantiate(IEnumerable<IEcsSystem> targets)
|
|
|
|
|
{
|
|
|
|
|
return Instantiate(FilterSystems(targets), false, null);
|
|
|
|
|
}
|
|
|
|
|
public static TInterface Instantiate(IEnumerable<IEcsSystem> targets, object filter)
|
|
|
|
|
{
|
|
|
|
|
return Instantiate(FilterSystems(targets, filter), true, filter);
|
|
|
|
|
}
|
|
|
|
|
#endregion
|
2023-03-12 02:02:39 +08:00
|
|
|
|
|
2023-03-11 17:11:40 +08:00
|
|
|
|
protected TInterface[] targets;
|
2023-03-26 11:19:03 +08:00
|
|
|
|
private ReadOnlyCollection<TInterface> _targetsSealed;
|
|
|
|
|
private object _filter;
|
|
|
|
|
private bool _isHasFilter;
|
|
|
|
|
|
|
|
|
|
public IList Targets => _targetsSealed;
|
|
|
|
|
public object Filter => _filter;
|
|
|
|
|
public bool IsHasFilter => _isHasFilter;
|
|
|
|
|
private EcsRunner<TInterface> Set(TInterface[] targets, bool isHasFilter, object filter)
|
2023-03-11 17:11:40 +08:00
|
|
|
|
{
|
|
|
|
|
this.targets = targets;
|
2023-03-26 11:19:03 +08:00
|
|
|
|
_targetsSealed = new ReadOnlyCollection<TInterface>(targets);
|
|
|
|
|
_filter = filter;
|
|
|
|
|
_isHasFilter = isHasFilter;
|
2023-03-11 17:11:40 +08:00
|
|
|
|
return this;
|
|
|
|
|
}
|
2023-03-26 11:19:03 +08:00
|
|
|
|
|
|
|
|
|
internal void Rebuild(IEnumerable<IEcsSystem> targets)
|
|
|
|
|
{
|
|
|
|
|
if(_isHasFilter)
|
|
|
|
|
Set(FilterSystems(targets), _isHasFilter, _filter);
|
|
|
|
|
else
|
|
|
|
|
Set(FilterSystems(targets, _filter), _isHasFilter, _filter);
|
|
|
|
|
}
|
2023-03-11 17:11:40 +08:00
|
|
|
|
}
|
|
|
|
|
}
|