2023-05-07 00:50:02 +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 ;
2023-05-26 04:25:09 +08:00
using static DCFApixels . DragonECS . EcsDebugUtility ;
2023-03-11 17:11:40 +08:00
namespace DCFApixels.DragonECS
{
2023-05-07 00:50:02 +08:00
using RunnersCore ;
using System.ComponentModel ;
2023-03-11 17:11:40 +08:00
[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-16 01:49:14 +08:00
2023-04-23 17:55:01 +08:00
namespace RunnersCore
2023-03-11 17:11:40 +08:00
{
2023-05-07 00:50:02 +08:00
[EditorBrowsable(EditorBrowsableState.Never)]
2023-04-23 17:55:01 +08:00
public interface IEcsRunner
{
2023-05-26 04:25:09 +08:00
EcsPipeline Source { get ; }
Type Interface { get ; }
IList Targets { get ; }
object Filter { get ; }
bool IsHasFilter { get ; }
bool IsDestroyed { get ; }
bool IsEmpty { get ; }
void Destroy ( ) ;
2023-04-23 17:55:01 +08:00
}
2023-03-12 02:02:39 +08:00
2023-04-23 17:55:01 +08:00
internal static class EcsRunnerActivator
2023-03-12 02:02:39 +08:00
{
2023-05-23 01:47:28 +08:00
private static Dictionary < Type , Type > _runnerHandlerTypes ; //interface base type/Runner handler type pairs;
2023-04-23 17:55:01 +08:00
static EcsRunnerActivator ( )
2023-03-29 19:40:18 +08:00
{
2023-04-23 17:55:01 +08:00
List < Exception > delayedExceptions = new List < Exception > ( ) ;
Type runnerBaseType = typeof ( EcsRunner < > ) ;
List < Type > runnerHandlerTypes = new List < Type > ( ) ;
foreach ( var assembly in AppDomain . CurrentDomain . GetAssemblies ( ) )
{
runnerHandlerTypes . AddRange ( assembly . GetTypes ( )
. Where ( type = > type . BaseType ! = null & & type . BaseType . IsGenericType & & runnerBaseType = = type . BaseType . GetGenericTypeDefinition ( ) ) ) ;
}
2023-03-12 02:02:39 +08:00
2023-05-07 00:50:02 +08:00
#if ( DEBUG & & ! DISABLE_DEBUG ) | | ! DRAGONECS_NO_SANITIZE_CHECKS
2023-05-26 04:25:09 +08:00
for ( int i = 0 ; i < runnerHandlerTypes . Count ; i + + )
2023-03-12 02:02:39 +08:00
{
2023-05-26 04:25:09 +08:00
var e = CheckRunnerValide ( runnerHandlerTypes [ i ] ) ;
if ( e ! = null )
{
runnerHandlerTypes . RemoveAt ( i - - ) ;
delayedExceptions . Add ( e ) ;
}
2023-03-12 02:02:39 +08:00
}
#endif
2023-05-23 01:47:28 +08:00
_runnerHandlerTypes = new Dictionary < Type , Type > ( ) ;
2023-04-23 17:55:01 +08:00
foreach ( var item in runnerHandlerTypes )
{
Type interfaceType = item . BaseType . GenericTypeArguments [ 0 ] ;
2023-05-26 04:25:09 +08:00
_runnerHandlerTypes . Add ( interfaceType . IsGenericType ? interfaceType . GetGenericTypeDefinition ( ) : interfaceType , item ) ;
2023-04-23 17:55:01 +08:00
}
if ( delayedExceptions . Count > 0 )
{
foreach ( var item in delayedExceptions ) EcsDebug . Print ( EcsConsts . DEBUG_ERROR_TAG , item . Message ) ;
throw delayedExceptions [ 0 ] ;
}
2023-03-12 02:02:39 +08:00
}
2023-04-23 17:55:01 +08:00
private static Exception CheckRunnerValide ( Type type ) //TODO доработать проверку валидности реалиазации ранера
2023-03-12 02:02:39 +08:00
{
2023-04-23 17:55:01 +08:00
Type baseType = type . BaseType ;
Type baseTypeArgument = baseType . GenericTypeArguments [ 0 ] ;
2023-03-12 02:02:39 +08:00
2023-04-23 17:55:01 +08:00
if ( type . ReflectedType ! = null )
{
2023-05-26 04:25:09 +08:00
return new EcsRunnerImplementationException ( $"{GetGenericTypeFullName(type, 1)}.ReflectedType must be Null, but equal to {GetGenericTypeFullName(type.ReflectedType, 1)}." ) ;
2023-04-23 17:55:01 +08:00
}
if ( ! baseTypeArgument . IsInterface )
{
2023-05-26 04:25:09 +08:00
return new EcsRunnerImplementationException ( $"Argument T of class EcsRunner<T>, can only be an inetrface. The {GetGenericTypeFullName(baseTypeArgument, 1)} type is not an interface." ) ;
2023-04-23 17:55:01 +08:00
}
2023-03-29 23:34:19 +08:00
2023-04-23 17:55:01 +08:00
var interfaces = type . GetInterfaces ( ) ;
2023-03-29 23:34:19 +08:00
2023-04-23 17:55:01 +08:00
if ( ! interfaces . Any ( o = > o = = baseTypeArgument ) )
{
2023-05-26 04:25:09 +08:00
return new EcsRunnerImplementationException ( $"Runner {GetGenericTypeFullName(type, 1)} does not implement interface {GetGenericTypeFullName(baseTypeArgument, 1)}." ) ;
2023-04-23 17:55:01 +08:00
}
2023-03-12 02:02:39 +08:00
2023-04-23 17:55:01 +08:00
return null ;
2023-03-29 23:34:19 +08:00
}
2023-03-12 02:02:39 +08:00
2023-04-23 17:55:01 +08:00
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal static void InitFor < TInterface > ( ) where TInterface : IEcsSystem
2023-03-12 02:48:51 +08:00
{
2023-04-23 17:55:01 +08:00
Type interfaceType = typeof ( TInterface ) ;
2023-03-12 02:02:39 +08:00
2023-05-23 01:47:28 +08:00
if ( ! _runnerHandlerTypes . TryGetValue ( interfaceType . IsGenericType ? interfaceType . GetGenericTypeDefinition ( ) : interfaceType , out Type runnerType ) )
2023-04-23 17:55:01 +08:00
{
2023-05-26 04:25:09 +08:00
throw new EcsRunnerImplementationException ( $"There is no implementation of a runner for the {GetGenericTypeFullName<TInterface>(1)} interface." ) ;
2023-04-23 17:55:01 +08:00
}
if ( interfaceType . IsGenericType )
{
Type [ ] genericTypes = interfaceType . GetGenericArguments ( ) ;
runnerType = runnerType . MakeGenericType ( genericTypes ) ;
}
EcsRunner < TInterface > . Register ( runnerType ) ;
2023-03-11 17:11:40 +08:00
}
}
2023-05-07 00:50:02 +08:00
[EditorBrowsable(EditorBrowsableState.Never)]
2023-04-23 17:55:01 +08:00
public abstract class EcsRunner < TInterface > : IEcsSystem , IEcsRunner
where TInterface : IEcsSystem
2023-03-11 17:11:40 +08:00
{
2023-04-23 17:55:01 +08:00
#region Register
private static Type _subclass ;
internal static void Register ( Type subclass )
{
2023-05-07 00:50:02 +08:00
#if ( DEBUG & & ! DISABLE_DEBUG ) | | ! DRAGONECS_NO_SANITIZE_CHECKS
2023-05-26 04:25:09 +08:00
if ( _subclass ! = null )
{
throw new EcsRunnerImplementationException ( $"The Runner<{typeof(TInterface).FullName}> can have only one implementing subclass" ) ;
}
2023-03-11 17:11:40 +08:00
2023-05-26 04:25:09 +08:00
Type interfaceType = typeof ( TInterface ) ;
2023-03-11 17:11:40 +08:00
2023-05-26 04:25:09 +08:00
var interfaces = interfaceType . GetInterfaces ( ) ;
if ( interfaceType . IsInterface = = false )
{
throw new ArgumentException ( $"{typeof(TInterface).FullName} is not interface" ) ;
}
if ( interfaces . Length ! = 1 | | interfaces [ 0 ] ! = typeof ( IEcsSystem ) )
{
throw new ArgumentException ( $"{typeof(TInterface).FullName} does not directly inherit the {nameof(IEcsSystem)} interface" ) ;
}
2023-03-11 17:11:40 +08:00
#endif
2023-04-23 17:55:01 +08:00
_subclass = subclass ;
}
#endregion
2023-03-11 17:11:40 +08:00
2023-04-23 17:55:01 +08:00
#region FilterSystems
private static TInterface [ ] FilterSystems ( IEnumerable < IEcsSystem > targets )
2023-03-11 17:11:40 +08:00
{
2023-04-23 17:55:01 +08:00
return targets . Where ( o = > o is TInterface ) . Select ( o = > ( TInterface ) o ) . ToArray ( ) ;
2023-03-11 17:11:40 +08:00
}
2023-04-23 17:55:01 +08:00
private static TInterface [ ] FilterSystems ( IEnumerable < IEcsSystem > targets , object filter )
2023-03-11 17:11:40 +08:00
{
2023-04-23 17:55:01 +08:00
Type interfaceType = typeof ( TInterface ) ;
IEnumerable < IEcsSystem > newTargets ;
if ( filter ! = null )
{
newTargets = targets . Where ( o = >
{
if ( o is TInterface = = false ) return false ;
var atr = o . GetType ( ) . GetCustomAttribute < EcsRunnerFilterAttribute > ( ) ;
return atr ! = null & & atr . interfaceType = = interfaceType & & atr . filter . Equals ( filter ) ;
} ) ;
}
else
2023-03-11 17:11:40 +08:00
{
2023-04-23 17:55:01 +08:00
newTargets = targets . Where ( o = >
{
if ( o is TInterface = = false ) return false ;
var atr = o . GetType ( ) . GetCustomAttribute < EcsRunnerFilterAttribute > ( ) ;
return atr = = null | | atr . interfaceType = = interfaceType & & atr . filter = = null ;
} ) ;
}
return newTargets . Select ( o = > ( TInterface ) o ) . ToArray ( ) ;
2023-03-11 17:11:40 +08:00
}
2023-04-23 17:55:01 +08:00
#endregion
2023-03-26 11:19:03 +08:00
2023-04-23 17:55:01 +08:00
#region Instantiate
private static TInterface Instantiate ( EcsPipeline source , TInterface [ ] targets , bool isHasFilter , object filter )
{
2023-05-26 04:25:09 +08:00
if ( _subclass = = null ) EcsRunnerActivator . InitFor < TInterface > ( ) ;
2023-04-23 17:55:01 +08:00
var instance = ( EcsRunner < TInterface > ) Activator . CreateInstance ( _subclass ) ;
return ( TInterface ) ( IEcsSystem ) instance . Set ( source , targets , isHasFilter , filter ) ;
}
public static TInterface Instantiate ( EcsPipeline source )
{
return Instantiate ( source , FilterSystems ( source . AllSystems ) , false , null ) ;
}
public static TInterface Instantiate ( EcsPipeline source , object filter )
{
return Instantiate ( source , FilterSystems ( source . AllSystems , filter ) , true , filter ) ;
}
#endregion
2023-03-12 02:02:39 +08:00
2023-04-23 17:55:01 +08:00
private EcsPipeline _source ;
protected TInterface [ ] targets ;
private ReadOnlyCollection < TInterface > _targetsSealed ;
private object _filter ;
private bool _isHasFilter ;
private bool _isDestroyed ;
2023-03-26 11:19:03 +08:00
2023-04-23 17:55:01 +08:00
#region Properties
public EcsPipeline Source = > _source ;
public Type Interface = > typeof ( TInterface ) ;
public IList Targets = > _targetsSealed ;
public object Filter = > _filter ;
public bool IsHasFilter = > _isHasFilter ;
public bool IsDestroyed = > _isDestroyed ;
public bool IsEmpty = > targets = = null | | targets . Length < = 0 ;
#endregion
2023-03-27 17:34:12 +08:00
2023-04-23 17:55:01 +08:00
private EcsRunner < TInterface > Set ( EcsPipeline source , TInterface [ ] targets , bool isHasFilter , object filter )
{
_source = source ;
this . targets = targets ;
_targetsSealed = new ReadOnlyCollection < TInterface > ( targets ) ;
_filter = filter ;
_isHasFilter = isHasFilter ;
OnSetup ( ) ;
return this ;
}
internal void Rebuild ( )
{
if ( _isHasFilter )
Set ( _source , FilterSystems ( _source . AllSystems ) , _isHasFilter , _filter ) ;
else
Set ( _source , FilterSystems ( _source . AllSystems , _filter ) , _isHasFilter , _filter ) ;
}
public void Destroy ( )
{
_isDestroyed = true ;
_source . OnRunnerDestroy ( this ) ;
_source = null ;
targets = null ;
_targetsSealed = null ;
_filter = null ;
OnDestroy ( ) ;
}
protected virtual void OnSetup ( ) { }
protected virtual void OnDestroy ( ) { }
}
2023-03-11 17:11:40 +08:00
}
2023-05-26 04:25:09 +08:00
2023-03-30 01:57:10 +08:00
#region Extensions
2023-04-23 17:55:01 +08:00
public static class EcsRunner
{
public static void Destroy ( IEcsSystem runner ) = > ( ( IEcsRunner ) runner ) . Destroy ( ) ;
}
2023-03-30 01:57:10 +08:00
public static class IEcsSystemExtensions
{
public static bool IsRunner ( this IEcsSystem self )
{
return self is IEcsRunner ;
}
}
#endregion
2023-03-11 17:11:40 +08:00
}