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 ;
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-30 01:57:10 +08:00
public EcsRunnerFilterAttribute ( object filter ) : this ( null , 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
{
2023-03-29 23:34:19 +08:00
public EcsSystems Source { get ; }
2023-03-26 11:19:03 +08:00
public IList Targets { get ; }
public object Filter { get ; }
public bool IsHasFilter { get ; }
}
2023-03-16 01:49:14 +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 ( )
{
2023-03-30 01:57:10 +08:00
List < Exception > delayedExceptions = new List < Exception > ( ) ;
2023-03-12 02:02:39 +08:00
Type runnerBaseType = typeof ( EcsRunner < > ) ;
2023-03-26 11:19:03 +08:00
List < Type > runnerHandlerTypes = new List < Type > ( ) ;
2023-03-29 19:40:18 +08:00
foreach ( var assembly in AppDomain . CurrentDomain . GetAssemblies ( ) )
{
2023-03-30 01:57:10 +08:00
runnerHandlerTypes . AddRange ( assembly . GetTypes ( )
2023-03-29 19:40:18 +08:00
. Where ( type = > type . BaseType ! = null & & type . BaseType . IsGenericType & & runnerBaseType = = type . BaseType . GetGenericTypeDefinition ( ) ) ) ;
}
2023-03-12 02:02:39 +08:00
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-30 01:57:10 +08:00
delayedExceptions . Add ( e ) ;
2023-03-12 02:02:39 +08:00
}
}
#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-29 23:34:19 +08:00
Type interfaceType = item . BaseType . GenericTypeArguments [ 0 ] ;
2023-03-26 11:19:03 +08:00
_runnerHandlerTypes . Add ( interfaceType . GUID , item ) ;
2023-03-12 02:02:39 +08:00
}
2023-03-30 01:57:10 +08:00
if ( delayedExceptions . Count > 0 )
2023-03-12 02:02:39 +08:00
{
2023-03-30 01:57:10 +08:00
foreach ( var item in delayedExceptions ) EcsDebug . Print ( EcsConsts . DEBUG_ERROR_TAG , item . Message ) ;
throw delayedExceptions [ 0 ] ;
2023-03-12 02:02:39 +08:00
}
}
private static Exception CheckRunnerValide ( Type type ) //TODO доработать проверку валидности реалиазации ранера
{
2023-03-29 23:34:19 +08:00
Type baseType = type . BaseType ;
Type baseTypeArgument = baseType . GenericTypeArguments [ 0 ] ;
2023-03-12 02:02:39 +08:00
if ( type . ReflectedType ! = null )
2023-03-29 23:34:19 +08:00
{
2023-03-30 01:57:10 +08:00
return new EcsRunnerImplementationException ( $"{type.FullName}.ReflectedType must be Null, but equal to {type.ReflectedType.FullName}." ) ;
2023-03-29 23:34:19 +08:00
}
if ( ! baseTypeArgument . IsInterface )
{
2023-03-30 01:57:10 +08:00
return new EcsRunnerImplementationException ( $"Argument T of class EcsRunner<T>, can only be an inetrface.The {baseTypeArgument.FullName} type is not an interface." ) ;
2023-03-29 23:34:19 +08:00
}
var interfaces = type . GetInterfaces ( ) ;
2023-03-12 02:02:39 +08:00
2023-03-29 23:34:19 +08:00
if ( ! interfaces . Any ( o = > o = = baseTypeArgument ) )
{
2023-03-30 01:57:10 +08:00
return new EcsRunnerImplementationException ( $"Runner {type.FullName} does not implement interface {baseTypeArgument.FullName}." ) ;
2023-03-29 23:34:19 +08:00
}
2023-03-12 02:02:39 +08:00
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 )
{
2023-03-30 01:57:10 +08:00
throw new EcsRunnerImplementationException ( $"The Runner<{typeof(TInterface).FullName}> can have only one implementing subclass" ) ;
2023-03-11 17:11:40 +08:00
}
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
2023-03-29 15:09:00 +08:00
private static TInterface Instantiate ( EcsSystems source , 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-29 15:09:00 +08:00
return ( TInterface ) ( IEcsSystem ) instance . Set ( source , targets , isHasFilter , filter ) ;
2023-03-11 17:11:40 +08:00
}
2023-03-29 15:09:00 +08:00
public static TInterface Instantiate ( EcsSystems source )
2023-03-26 11:19:03 +08:00
{
2023-03-29 15:09:00 +08:00
return Instantiate ( source , FilterSystems ( source . AllSystems ) , false , null ) ;
2023-03-26 11:19:03 +08:00
}
2023-03-29 15:09:00 +08:00
public static TInterface Instantiate ( EcsSystems source , object filter )
2023-03-26 11:19:03 +08:00
{
2023-03-29 15:09:00 +08:00
return Instantiate ( source , FilterSystems ( source . AllSystems , filter ) , true , filter ) ;
2023-03-26 11:19:03 +08:00
}
#endregion
2023-03-12 02:02:39 +08:00
2023-03-29 15:09:00 +08:00
private EcsSystems _source ;
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 ;
2023-03-30 01:57:10 +08:00
#region Properties
2023-03-29 15:09:00 +08:00
public EcsSystems Source = > _source ;
2023-03-26 11:19:03 +08:00
public IList Targets = > _targetsSealed ;
public object Filter = > _filter ;
public bool IsHasFilter = > _isHasFilter ;
2023-03-30 01:57:10 +08:00
#endregion
2023-03-27 17:34:12 +08:00
2023-03-29 15:09:00 +08:00
private EcsRunner < TInterface > Set ( EcsSystems source , TInterface [ ] targets , bool isHasFilter , object filter )
2023-03-11 17:11:40 +08:00
{
2023-03-29 15:09:00 +08:00
_source = source ;
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-27 17:34:12 +08:00
OnSetup ( ) ;
2023-03-11 17:11:40 +08:00
return this ;
}
2023-03-26 11:19:03 +08:00
2023-03-27 17:34:12 +08:00
protected virtual void OnSetup ( ) { }
2023-03-29 15:09:00 +08:00
internal void Rebuild ( )
2023-03-26 11:19:03 +08:00
{
if ( _isHasFilter )
2023-03-29 15:09:00 +08:00
Set ( _source , FilterSystems ( _source . AllSystems ) , _isHasFilter , _filter ) ;
2023-03-26 11:19:03 +08:00
else
2023-03-29 15:09:00 +08:00
Set ( _source , FilterSystems ( _source . AllSystems , _filter ) , _isHasFilter , _filter ) ;
2023-03-26 11:19:03 +08:00
}
2023-03-11 17:11:40 +08:00
}
2023-03-30 01:57:10 +08:00
#region Extensions
public static class IEcsSystemExtensions
{
public static bool IsRunner ( this IEcsSystem self )
{
return self is IEcsRunner ;
}
}
#endregion
2023-03-11 17:11:40 +08:00
}