2023-05-27 23:02:32 +08:00
using DCFApixels.DragonECS.RunnersCore ;
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-11-08 15:15:10 +08:00
using System.Text.RegularExpressions ;
2023-05-26 04:25:09 +08:00
using static DCFApixels . DragonECS . EcsDebugUtility ;
2023-03-11 17:11:40 +08:00
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-05-30 18:27:30 +08:00
public interface IEcsProcess { }
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-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-06-02 01:20:46 +08:00
#if ( DEBUG & & ! DISABLE_DEBUG ) | | ENABLE_DRAGONECS_ASSERT_CHEKS
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
}
2023-10-31 03:03:13 +08:00
2023-04-23 17:55:01 +08:00
if ( delayedExceptions . Count > 0 )
{
2023-06-26 01:57:50 +08:00
throw new AggregateException ( delayedExceptions ) ;
2023-04-23 17:55:01 +08:00
}
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)]
2023-05-30 18:27:30 +08:00
internal static void InitFor < TInterface > ( ) where TInterface : IEcsProcess
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-28 05:53:08 +08:00
#if UNITY_2020_3_OR_NEWER
[UnityEngine.Scripting.RequireDerived, UnityEngine.Scripting.Preserve]
#endif
2023-05-30 18:30:10 +08:00
public abstract class EcsRunner < TInterface > : IEcsProcess , IEcsRunner
2023-05-30 18:27:30 +08:00
where TInterface : IEcsProcess
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-06-02 01:20:46 +08:00
#if ( DEBUG & & ! DISABLE_DEBUG ) | | ENABLE_DRAGONECS_ASSERT_CHEKS
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" ) ;
}
2023-05-30 18:27:30 +08:00
if ( interfaces . Length ! = 1 | | interfaces [ 0 ] ! = typeof ( IEcsProcess ) )
2023-05-26 04:25:09 +08:00
{
2023-05-30 18:27:30 +08:00
throw new ArgumentException ( $"{typeof(TInterface).FullName} does not directly inherit the {nameof(IEcsProcess)} interface" ) ;
2023-05-26 04:25:09 +08:00
}
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
2023-05-30 18:27:30 +08:00
private static TInterface [ ] FilterSystems ( IEnumerable < IEcsProcess > 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-05-30 18:27:30 +08:00
private static TInterface [ ] FilterSystems ( IEnumerable < IEcsProcess > targets , object filter )
2023-03-11 17:11:40 +08:00
{
2023-04-23 17:55:01 +08:00
Type interfaceType = typeof ( TInterface ) ;
2023-05-30 18:27:30 +08:00
IEnumerable < IEcsProcess > newTargets ;
2023-04-23 17:55:01 +08:00
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 ) ;
2023-05-30 18:27:30 +08:00
return ( TInterface ) ( IEcsProcess ) instance . Set ( source , targets , isHasFilter , filter ) ;
2023-04-23 17:55:01 +08:00
}
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
{
2023-05-30 18:27:30 +08:00
public static void Destroy ( IEcsProcess runner ) = > ( ( IEcsRunner ) runner ) . Destroy ( ) ;
2023-04-23 17:55:01 +08:00
}
2023-03-30 01:57:10 +08:00
public static class IEcsSystemExtensions
{
2023-05-30 18:27:30 +08:00
public static bool IsRunner ( this IEcsProcess self )
2023-03-30 01:57:10 +08:00
{
return self is IEcsRunner ;
}
}
#endregion
2023-11-08 15:15:10 +08:00
public static class EcsProcessUtility
{
private struct ProcessInterface
{
public Type interfaceType ;
public string processName ;
public ProcessInterface ( Type interfaceType , string processName )
{
this . interfaceType = interfaceType ;
this . processName = processName ;
}
}
private static Dictionary < Type , ProcessInterface > _processes = new Dictionary < Type , ProcessInterface > ( ) ;
private static HashSet < Type > _systems = new HashSet < Type > ( ) ;
static EcsProcessUtility ( )
{
Type processBasicInterface = typeof ( IEcsProcess ) ;
foreach ( var assembly in AppDomain . CurrentDomain . GetAssemblies ( ) )
{
var types = assembly . GetTypes ( ) ;
foreach ( var type in types )
{
if ( type . GetInterface ( nameof ( IEcsProcess ) ) ! = null | | type = = processBasicInterface )
{
if ( type . IsInterface )
{
string name = type . Name ;
if ( name [ 0 ] = = 'I' & & name . Length > 1 & & char . IsUpper ( name [ 1 ] ) )
name = name . Substring ( 1 ) ;
name = Regex . Replace ( name , @"\bEcs|Process\b" , "" ) ;
if ( Regex . IsMatch ( name , "`\\w{1,}$" ) )
{
var s = name . Split ( "`" ) ;
name = s [ 0 ] + $"<{s[1]}>" ;
}
_processes . Add ( type , new ProcessInterface ( type , name ) ) ;
}
else
{
_systems . Add ( type ) ;
}
}
}
}
}
#region Systems
public static bool IsSystem ( Type type ) = > _systems . Contains ( type ) ;
public static bool IsEcsSystem ( this Type type ) = > _systems . Contains ( type ) ;
#endregion
#region Process
public static bool IsProcessInterface ( Type type )
{
if ( type . IsGenericType ) type = type . GetGenericTypeDefinition ( ) ;
return _processes . ContainsKey ( type ) ;
}
public static bool IsEcsProcessInterface ( this Type type ) = > IsProcessInterface ( type ) ;
public static string GetProcessInterfaceName ( Type type )
{
if ( type . IsGenericType ) type = type . GetGenericTypeDefinition ( ) ;
return _processes [ type ] . processName ;
}
public static bool TryGetProcessInterfaceName ( Type type , out string name )
{
if ( type . IsGenericType ) type = type . GetGenericTypeDefinition ( ) ;
bool result = _processes . TryGetValue ( type , out ProcessInterface data ) ;
name = data . processName ;
return result ;
}
public static IEnumerable < Type > GetEcsProcessInterfaces ( this Type self )
{
return self . GetInterfaces ( ) . Where ( o = > o . IsEcsProcessInterface ( ) ) ;
}
#endregion
}
2023-03-11 17:11:40 +08:00
}