2023-12-20 23:16:57 +08:00
using DCFApixels.DragonECS.RunnersCore ;
2023-05-27 23:02:32 +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 ;
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-12-06 20:34:33 +08:00
#if UNITY_2020_3_OR_NEWER
[UnityEngine.Scripting.RequireDerived, UnityEngine.Scripting.Preserve]
#endif
[AttributeUsage(AttributeTargets.Interface, Inherited = false, AllowMultiple = false)]
2023-12-06 20:38:00 +08:00
public sealed class BindWithEcsRunnerAttribute : Attribute
2023-12-06 20:34:33 +08:00
{
2023-12-06 20:38:00 +08:00
private static readonly Type _baseType = typeof ( EcsRunner < > ) ;
2023-12-06 20:34:33 +08:00
public readonly Type runnerType ;
2023-12-06 20:38:00 +08:00
public BindWithEcsRunnerAttribute ( Type runnerType )
2023-12-06 20:34:33 +08:00
{
if ( runnerType = = null )
throw new ArgumentNullException ( ) ;
2023-12-06 21:15:35 +08:00
if ( ! CheckSubclass ( runnerType ) )
2023-12-06 20:34:33 +08:00
throw new ArgumentException ( ) ;
this . runnerType = runnerType ;
}
2023-12-06 21:15:35 +08:00
private bool CheckSubclass ( Type type )
2023-12-06 20:34:33 +08:00
{
2023-12-06 20:38:00 +08:00
if ( type . IsGenericType & & type . GetGenericTypeDefinition ( ) = = _baseType )
2023-12-06 20:34:33 +08:00
return true ;
if ( type . BaseType ! = null )
2023-12-06 21:15:35 +08:00
return CheckSubclass ( type . BaseType ) ;
2023-12-06 20:34:33 +08:00
return false ;
}
}
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-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
2023-12-06 21:15:35 +08:00
private static void CheckRunnerValide ( Type type ) //TODO доработать проверку валидности реалиазации ранера
{
Type targetInterface = typeof ( TInterface ) ;
if ( type . IsAbstract )
{
throw new Exception ( ) ;
}
Type GetRunnerBaseType ( Type type )
{
if ( type . IsGenericType & & type . GetGenericTypeDefinition ( ) = = typeof ( EcsRunner < > ) )
return type ;
if ( type . BaseType ! = null )
return GetRunnerBaseType ( type . BaseType ) ;
return null ;
}
Type baseType = GetRunnerBaseType ( type ) ;
Type baseTypeArgument = baseType . GenericTypeArguments [ 0 ] ;
if ( baseTypeArgument ! = targetInterface )
{
throw new Exception ( ) ;
}
if ( ! type . GetInterfaces ( ) . Any ( o = > o = = targetInterface ) )
{
throw new EcsRunnerImplementationException ( $"Runner {GetGenericTypeFullName(type, 1)} does not implement interface {GetGenericTypeFullName(baseTypeArgument, 1)}." ) ;
}
}
2023-04-23 17:55:01 +08:00
private static TInterface Instantiate ( EcsPipeline source , TInterface [ ] targets , bool isHasFilter , object filter )
{
2023-12-20 23:21:10 +08:00
if ( _subclass = = null )
2023-12-06 20:34:33 +08:00
{
Type interfaceType = typeof ( TInterface ) ;
2023-12-20 23:16:57 +08:00
if ( interfaceType . TryGetCustomAttribute ( out BindWithEcsRunnerAttribute atr ) )
2023-12-06 20:34:33 +08:00
{
Type runnerType = atr . runnerType ;
if ( interfaceType . IsGenericType )
{
Type [ ] genericTypes = interfaceType . GetGenericArguments ( ) ;
runnerType = runnerType . MakeGenericType ( genericTypes ) ;
}
2023-12-06 21:15:35 +08:00
CheckRunnerValide ( runnerType ) ;
2023-12-06 20:34:33 +08:00
_subclass = runnerType ;
}
else
{
2023-12-06 21:15:35 +08:00
throw new EcsFrameworkException ( "Процесс не связан с раннером, используйте атрибуут BindWithEcsRunner(Type runnerType)" ) ;
2023-12-06 20:34:33 +08:00
}
}
2023-12-20 23:21:10 +08:00
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-12-20 23:21:10 +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 ( ) ;
}
2023-12-24 15:40:19 +08:00
protected virtual void OnSetup ( ) { } //rename to OnInitialize
2023-04-23 17:55:01 +08:00
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 )
{
2023-12-20 23:21:10 +08:00
return self . GetInterfaces ( ) . Where ( o = > o . IsEcsProcessInterface ( ) ) ;
2023-11-08 15:15:10 +08:00
}
#endregion
}
2023-03-11 17:11:40 +08:00
}