2024-11-01 12:41:10 +08:00
using DCFApixels.DragonECS.Core ;
using DCFApixels.DragonECS.Internal ;
2024-04-30 16:09:57 +08:00
using DCFApixels.DragonECS.PoolsCore ;
2023-06-26 02:53:55 +08:00
using System ;
2024-11-01 12:41:10 +08:00
using System.Collections.Generic ;
2023-05-07 00:50:02 +08:00
namespace DCFApixels.DragonECS
{
2024-11-01 12:41:10 +08:00
public abstract class EcsAspect : ITemplateNode , IComponentMask
2023-05-07 00:50:02 +08:00
{
2024-08-23 22:31:43 +08:00
#region Initialization Halpers
2024-03-26 16:06:03 +08:00
[ThreadStatic]
2024-10-31 14:46:21 +08:00
private static Builder [ ] _constructorBuildersStack ;
[ThreadStatic]
private static int _constructorBuildersStackIndex ;
2024-07-05 22:13:17 +08:00
protected static Builder CurrentBuilder
{
get
{
2024-10-31 14:46:21 +08:00
if ( _constructorBuildersStack = = null | | _constructorBuildersStackIndex < 0 )
2024-07-05 22:13:17 +08:00
{
Throw . Aspect_CanOnlyBeUsedDuringInitialization ( nameof ( CurrentBuilder ) ) ;
}
2024-10-31 14:46:21 +08:00
return _constructorBuildersStack [ _constructorBuildersStackIndex ] ;
2024-07-05 22:13:17 +08:00
}
}
2024-03-26 16:06:03 +08:00
protected static IncludeMarker Inc
{
2024-10-31 14:46:21 +08:00
get { return CurrentBuilder . Inc ; }
2024-03-26 16:06:03 +08:00
}
protected static ExcludeMarker Exc
{
2024-10-31 14:46:21 +08:00
get { return CurrentBuilder . Exc ; }
2024-03-26 16:06:03 +08:00
}
protected static OptionalMarker Opt
{
2024-10-31 14:46:21 +08:00
get { return CurrentBuilder . Opt ; }
2024-03-26 16:06:03 +08:00
}
2024-08-23 22:31:43 +08:00
#endregion
2024-01-07 18:52:54 +08:00
2024-11-03 19:02:07 +08:00
//Инициализация аспектов проходит в синхронизированном состоянии, поэтому использование _staticMaskCache потоко безопасно.
private static Dictionary < Type , EcsStaticMask > _staticMaskCache = new Dictionary < Type , EcsStaticMask > ( ) ;
2024-08-23 22:31:43 +08:00
internal EcsWorld _source ;
internal EcsMask _mask ;
private bool _isBuilt = false ;
2024-11-03 19:02:07 +08:00
private IEcsPool [ ] _pools ;
2024-11-01 12:41:10 +08:00
2023-05-07 00:50:02 +08:00
#region Properties
2024-03-02 21:45:09 +08:00
public EcsMask Mask
{
get { return _mask ; }
}
public EcsWorld World
{
get { return _source ; }
}
public bool IsInit
{
2024-03-26 16:06:03 +08:00
get { return _isBuilt ; }
2024-03-02 21:45:09 +08:00
}
2024-11-03 19:02:07 +08:00
public ReadOnlySpan < IEcsPool > Pools
{
get { return _pools ; }
}
2024-11-01 12:41:10 +08:00
/// <summary>
/// Статическая инициализация означет что каждый новый эекземпляр идентичен другому, инициализация стандартным путем создает идентичные экземпляры, поэтому значение по умолчанию true.
/// </summary>
protected virtual bool IsStaticInitialization
{
get { return true ; }
}
2023-05-07 00:50:02 +08:00
#endregion
#region Methods
2024-02-13 21:00:01 +08:00
public bool IsMatches ( int entityID )
{
return _source . IsMatchesMask ( _mask , entityID ) ;
}
2023-05-07 00:50:02 +08:00
#endregion
#region Builder
protected virtual void Init ( Builder b ) { }
2024-02-11 01:28:18 +08:00
public sealed class Builder
2023-05-07 00:50:02 +08:00
{
private EcsWorld _world ;
2024-10-31 14:46:21 +08:00
private EcsStaticMask . Builder _maskBuilder ;
2024-07-05 22:13:17 +08:00
2024-11-03 19:02:07 +08:00
private IEcsPool [ ] _poolsBuffer = new IEcsPool [ 8 ] ;
private int _poolsBufferCount ;
2024-08-26 11:08:42 +08:00
#region Properties
2024-03-08 20:40:19 +08:00
public IncludeMarker Inc
{
get { return new IncludeMarker ( this ) ; }
}
public ExcludeMarker Exc
{
get { return new ExcludeMarker ( this ) ; }
}
public OptionalMarker Opt
{
get { return new OptionalMarker ( this ) ; }
}
2024-08-26 11:08:42 +08:00
public EcsWorld World
{
get { return _world ; }
}
#endregion
2024-03-08 20:40:19 +08:00
2024-08-26 11:08:42 +08:00
#region Constructors / New
2024-10-31 14:46:21 +08:00
private Builder ( ) { }
2024-07-05 22:13:17 +08:00
internal static unsafe TAspect New < TAspect > ( EcsWorld world ) where TAspect : EcsAspect , new ( )
2023-05-07 00:50:02 +08:00
{
2024-11-01 12:41:10 +08:00
//Get Builder
2024-10-31 14:46:21 +08:00
if ( _constructorBuildersStack = = null )
{
_constructorBuildersStack = new Builder [ 4 ] ;
_constructorBuildersStackIndex = - 1 ;
}
_constructorBuildersStackIndex + + ;
if ( _constructorBuildersStackIndex > = _constructorBuildersStack . Length )
{
Array . Resize ( ref _constructorBuildersStack , _constructorBuildersStack . Length < < 1 ) ;
}
Builder builder = _constructorBuildersStack [ _constructorBuildersStackIndex ] ;
if ( builder = = null )
{
builder = new Builder ( ) ;
_constructorBuildersStack [ _constructorBuildersStackIndex ] = builder ;
}
2024-06-27 00:26:05 +08:00
2024-11-01 12:41:10 +08:00
//Setup Builder
EcsStaticMask staticMask = null ;
if ( _staticMaskCache . TryGetValue ( typeof ( TAspect ) , out staticMask ) = = false )
{
builder . _maskBuilder = EcsStaticMask . New ( ) ;
}
builder . _world = world ;
//Building
2024-10-31 14:46:21 +08:00
TAspect newAspect = new TAspect ( ) ;
2024-11-01 12:41:10 +08:00
newAspect . _source = world ;
2024-03-26 18:09:13 +08:00
newAspect . Init ( builder ) ;
2024-08-26 11:08:42 +08:00
2024-11-01 12:41:10 +08:00
//Build Mask
if ( staticMask = = null )
{
staticMask = builder . _maskBuilder . Build ( ) ;
builder . _maskBuilder = default ;
if ( newAspect . IsStaticInitialization )
{
_staticMaskCache . Add ( typeof ( TAspect ) , staticMask ) ;
}
}
newAspect . _mask = staticMask . ToMask ( world ) ;
2024-11-03 19:02:07 +08:00
var pools = new IEcsPool [ builder . _poolsBufferCount ] ;
Array . Copy ( builder . _poolsBuffer , pools , pools . Length ) ;
2024-03-26 16:06:03 +08:00
newAspect . _isBuilt = true ;
2024-01-07 18:52:54 +08:00
2024-11-01 12:41:10 +08:00
_constructorBuildersStackIndex - - ;
2024-10-31 14:46:21 +08:00
return newAspect ;
2023-05-07 00:50:02 +08:00
}
2024-08-26 11:08:42 +08:00
#endregion
2023-05-07 00:50:02 +08:00
2024-04-18 22:14:50 +08:00
#region Include / Exclude / Optional / Combine / Except
2024-03-07 03:40:06 +08:00
public TPool IncludePool < TPool > ( ) where TPool : IEcsPoolImplementation , new ( )
2023-05-07 00:50:02 +08:00
{
2024-11-03 19:02:07 +08:00
var pool = CachePool < TPool > ( ) ;
2024-02-23 18:34:40 +08:00
IncludeImplicit ( pool . ComponentType ) ;
return pool ;
2023-05-07 00:50:02 +08:00
}
2024-03-07 03:40:06 +08:00
public TPool ExcludePool < TPool > ( ) where TPool : IEcsPoolImplementation , new ( )
2023-05-07 00:50:02 +08:00
{
2024-11-03 19:02:07 +08:00
var pool = CachePool < TPool > ( ) ;
2024-02-23 18:34:40 +08:00
ExcludeImplicit ( pool . ComponentType ) ;
return pool ;
2023-05-07 00:50:02 +08:00
}
2024-03-07 03:40:06 +08:00
public TPool OptionalPool < TPool > ( ) where TPool : IEcsPoolImplementation , new ( )
2023-05-07 00:50:02 +08:00
{
2024-11-03 19:02:07 +08:00
return CachePool < TPool > ( ) ;
2023-05-07 00:50:02 +08:00
}
2024-10-05 10:19:52 +08:00
2024-11-03 19:02:07 +08:00
private TPool CachePool < TPool > ( ) where TPool : IEcsPoolImplementation , new ( )
{
var pool = _world . GetPoolInstance < TPool > ( ) ;
2024-11-05 15:50:03 +08:00
if ( _poolsBufferCount > = _poolsBuffer . Length )
2024-11-03 19:02:07 +08:00
{
2024-11-03 19:03:57 +08:00
Array . Resize ( ref _poolsBuffer , _poolsBuffer . Length < < 1 ) ;
2024-11-03 19:02:07 +08:00
}
_poolsBuffer [ _poolsBufferCount + + ] = pool ;
return pool ;
}
2023-06-04 18:32:05 +08:00
private void IncludeImplicit ( Type type )
2023-05-07 00:50:02 +08:00
{
2024-11-01 12:41:10 +08:00
if ( _maskBuilder . IsNull = = false )
{
_maskBuilder . Inc ( type ) ;
}
2023-05-07 00:50:02 +08:00
}
2023-06-04 18:32:05 +08:00
private void ExcludeImplicit ( Type type )
2023-05-07 00:50:02 +08:00
{
2024-11-01 12:41:10 +08:00
if ( _maskBuilder . IsNull = = false )
{
_maskBuilder . Exc ( type ) ;
}
2023-05-07 00:50:02 +08:00
}
2024-07-05 22:13:17 +08:00
public TOtherAspect Combine < TOtherAspect > ( int order = 0 ) where TOtherAspect : EcsAspect , new ( )
2023-06-03 01:58:54 +08:00
{
2023-06-22 14:31:13 +08:00
var result = _world . GetAspect < TOtherAspect > ( ) ;
2024-11-01 12:41:10 +08:00
if ( _maskBuilder . IsNull = = false )
{
_maskBuilder . Combine ( result . Mask . _staticMask ) ;
}
2023-06-03 01:58:54 +08:00
return result ;
}
2024-07-05 22:13:17 +08:00
public TOtherAspect Except < TOtherAspect > ( int order = 0 ) where TOtherAspect : EcsAspect , new ( )
2024-04-18 22:14:50 +08:00
{
var result = _world . GetAspect < TOtherAspect > ( ) ;
2024-11-01 12:41:10 +08:00
if ( _maskBuilder . IsNull = = false )
{
_maskBuilder . Except ( result . Mask . _staticMask ) ;
}
2024-04-18 22:14:50 +08:00
return result ;
}
2023-06-03 01:58:54 +08:00
#endregion
2023-05-28 05:53:08 +08:00
#region SupportReflectionHack
#if UNITY_2020_3_OR_NEWER
[UnityEngine.Scripting.Preserve]
#endif
2023-06-04 18:32:05 +08:00
private void SupportReflectionHack < TPool > ( ) where TPool : IEcsPoolImplementation , new ( )
2023-05-28 05:53:08 +08:00
{
2024-03-07 03:40:06 +08:00
IncludePool < TPool > ( ) ;
ExcludePool < TPool > ( ) ;
OptionalPool < TPool > ( ) ;
2023-06-04 18:32:05 +08:00
IncludeImplicit ( null ) ;
ExcludeImplicit ( null ) ;
2023-05-28 05:53:08 +08:00
}
#endregion
2023-05-07 00:50:02 +08:00
}
#endregion
2024-01-07 18:52:54 +08:00
#region Combined
2023-06-25 23:13:51 +08:00
private readonly struct Combined
2023-06-05 22:09:34 +08:00
{
2023-06-25 23:13:51 +08:00
public readonly EcsAspect aspect ;
public readonly int order ;
2023-06-22 14:31:13 +08:00
public Combined ( EcsAspect aspect , int order )
2023-06-05 22:09:34 +08:00
{
2023-06-22 14:31:13 +08:00
this . aspect = aspect ;
2023-06-05 22:09:34 +08:00
this . order = order ;
}
}
2024-01-07 18:52:54 +08:00
#endregion
2023-05-07 00:50:02 +08:00
2024-11-01 12:41:10 +08:00
#region Template
public virtual void Apply ( short worldID , int entityID )
{
EcsWorld world = EcsWorld . GetWorld ( worldID ) ;
foreach ( var incTypeID in _mask . _incs )
{
var pool = world . FindPoolInstance ( incTypeID ) ;
if ( pool ! = null )
{
if ( pool . Has ( entityID ) = = false )
{
pool . AddRaw ( entityID , null ) ;
}
}
#if DEBUG
else
{
EcsDebug . PrintWarning ( "Component has not been added because the pool has not been initialized yet." ) ;
}
#endif
}
foreach ( var excTypeID in _mask . _excs )
{
var pool = world . FindPoolInstance ( excTypeID ) ;
if ( pool ! = null & & pool . Has ( entityID ) )
{
pool . Del ( entityID ) ;
}
}
}
#endregion
#region Other
EcsMask IComponentMask . ToMask ( EcsWorld world ) { return _mask ; }
#endregion
#region Obsolete
2024-08-24 12:29:58 +08:00
[Obsolete("Use EcsMask.GetIterator()")]
public Iterator GetIterator ( )
{
return new Iterator ( Mask . GetIterator ( ) , _source . Entities ) ;
}
[Obsolete("Use EcsMask.GetIterator().Iterate(span)")]
public Iterator GetIteratorFor ( EcsSpan span )
{
return new Iterator ( Mask . GetIterator ( ) , span ) ;
}
[Obsolete("Use EcsMaskIterator")]
2024-02-11 01:14:54 +08:00
public ref struct Iterator
2023-12-24 15:40:19 +08:00
{
2024-04-16 12:46:09 +08:00
public readonly short worldID ;
2024-08-24 12:29:58 +08:00
public readonly EcsMaskIterator . Enumerable iterator ;
2024-02-11 01:14:54 +08:00
private EcsSpan _span ;
2024-08-24 12:29:58 +08:00
public Iterator ( EcsMaskIterator iterator , EcsSpan span )
2023-12-24 15:40:19 +08:00
{
2024-10-31 16:27:53 +08:00
worldID = iterator . World . ID ;
2024-02-11 01:14:54 +08:00
_span = span ;
2024-08-24 12:29:58 +08:00
this . iterator = iterator . Iterate ( span ) ;
}
#region CopyTo
public void CopyTo ( EcsGroup group )
{
iterator . CopyTo ( group ) ;
}
public int CopyTo ( ref int [ ] array )
{
return iterator . CopyTo ( ref array ) ;
}
public EcsSpan CopyToSpan ( ref int [ ] array )
{
2024-10-10 19:57:19 +08:00
int count = CopyTo ( ref array ) ;
return new EcsSpan ( worldID , array , count ) ;
2024-08-24 12:29:58 +08:00
}
#endregion
public EcsMaskIterator . Enumerable . Enumerator GetEnumerator ( )
{
return iterator . GetEnumerator ( ) ;
2023-12-24 15:40:19 +08:00
}
2023-05-07 00:50:02 +08:00
}
2023-06-02 04:00:08 +08:00
#endregion
2023-05-07 00:50:02 +08:00
}
2024-08-23 22:31:43 +08:00
2024-08-26 11:08:42 +08:00
#region EcsAspectExtensions
//public static class EcsAspectExtensions
//{
// public static EcsAspect.Builder Inc<TPool>(this EcsAspect.Builder self, ref TPool pool) where TPool : IEcsPoolImplementation, new()
// {
// pool = self.IncludePool<TPool>();
// return self;
// }
// public static EcsAspect.Builder Exc<TPool>(this EcsAspect.Builder self, ref TPool pool) where TPool : IEcsPoolImplementation, new()
// {
// pool = self.ExcludePool<TPool>();
// return self;
// }
// public static EcsAspect.Builder Opt<TPool>(this EcsAspect.Builder self, ref TPool pool) where TPool : IEcsPoolImplementation, new()
// {
// pool = self.OptionalPool<TPool>();
// return self;
// }
//}
#endregion
2024-08-23 22:31:43 +08:00
#region Constraint Markers
2024-03-08 20:40:19 +08:00
public readonly ref struct IncludeMarker
{
private readonly EcsAspect . Builder _builder ;
public IncludeMarker ( EcsAspect . Builder builder )
{
_builder = builder ;
}
2024-08-23 22:31:43 +08:00
public T GetInstance < T > ( ) where T : IEcsPoolImplementation , new ( )
2024-03-08 20:40:19 +08:00
{
return _builder . IncludePool < T > ( ) ;
}
}
public readonly ref struct ExcludeMarker
{
private readonly EcsAspect . Builder _builder ;
public ExcludeMarker ( EcsAspect . Builder builder )
{
_builder = builder ;
}
2024-08-23 22:31:43 +08:00
public T GetInstance < T > ( ) where T : IEcsPoolImplementation , new ( )
2024-03-08 20:40:19 +08:00
{
return _builder . ExcludePool < T > ( ) ;
}
}
public readonly ref struct OptionalMarker
{
private readonly EcsAspect . Builder _builder ;
public OptionalMarker ( EcsAspect . Builder builder )
{
_builder = builder ;
}
2024-08-23 22:31:43 +08:00
public T GetInstance < T > ( ) where T : IEcsPoolImplementation , new ( )
2024-03-08 20:40:19 +08:00
{
return _builder . OptionalPool < T > ( ) ;
}
}
2024-08-23 22:31:43 +08:00
#endregion
}