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-09 21:10:12 +08:00
public readonly struct Singleton < T > where T : struct
{
public readonly short WorldID ;
public Singleton ( short worldID )
{
WorldID = worldID ;
EcsWorld . GetData < T > ( worldID ) ;
}
public EcsWorld World
{
get { return EcsWorld . GetWorld ( WorldID ) ; }
}
public ref T Value
{
get { return ref EcsWorld . GetDataUnchecked < T > ( WorldID ) ; }
}
public static implicit operator Singleton < T > ( SingletonMarker a ) { return new Singleton < T > ( a . Builder . World . ID ) ; }
}
2025-03-10 13:00:30 +08:00
public interface IEcsAspect
{
EcsMask Mask { get ; set ; }
}
#region IEcsAspectExtensions tmp
// public static class IEcsAspectExtensions
// {
// public static void Apply(this IEcsAspect aspect, short worldID, int entityID)
// {
// EcsWorld world = EcsWorld.GetWorld(worldID);
// EcsMask mask = aspect.Mask;
// foreach (var incTypeID in mask._incs)
// {
// var pool = world.FindPoolInstance(incTypeID);
// if (pool != null)
// {
// if (pool.Has(entityID) == false)
// {
// pool.AddEmpty(entityID);
// }
// }
//#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
public static partial class API
{
public static IncludeMarker Inc
{
get { return EcsAspect . CurrentBuilder . Inc ; }
}
public static ExcludeMarker Exc
{
get { return EcsAspect . CurrentBuilder . Exc ; }
}
public static OptionalMarker Opt
{
get { return EcsAspect . CurrentBuilder . Opt ; }
}
}
public abstract class EcsAspect : IEcsAspect , 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-11-09 21:10:12 +08:00
protected static Builder B
2024-07-05 22:13:17 +08:00
{
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
}
}
2025-03-10 13:00:30 +08:00
public static Builder CurrentBuilder
2024-11-09 21:10:12 +08:00
{
get { return B ; }
}
2024-03-26 16:06:03 +08:00
protected static IncludeMarker Inc
{
2024-11-09 21:10:12 +08:00
get { return B . Inc ; }
2024-03-26 16:06:03 +08:00
}
protected static ExcludeMarker Exc
{
2024-11-09 21:10:12 +08:00
get { return B . Exc ; }
2024-03-26 16:06:03 +08:00
}
protected static OptionalMarker Opt
{
2024-11-09 21:10:12 +08:00
get { return B . Opt ; }
}
protected static SingletonMarker Singleton
{
get { return B . Singleton ; }
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-06 13:46:20 +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 ; }
2025-03-10 13:00:30 +08:00
set { }
2024-03-02 21:45:09 +08:00
}
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-06 13:46:20 +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-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-11-09 21:10:12 +08:00
public SingletonMarker Singleton
{
get { return new SingletonMarker ( 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 ( ) { }
2025-03-10 13:00:30 +08:00
internal static unsafe ( TAspect aspect , EcsMask mask ) New < TAspect > ( EcsWorld world ) where TAspect : 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 ( ) ;
2025-03-10 13:00:30 +08:00
EcsAspect builtinAspect = newAspect as EcsAspect ;
if ( builtinAspect ! = null )
{
builtinAspect . _source = world ;
builtinAspect . 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 ;
2025-03-10 13:00:30 +08:00
if ( builtinAspect = = null | | builtinAspect . IsStaticInitialization )
2024-11-01 12:41:10 +08:00
{
_staticMaskCache . Add ( typeof ( TAspect ) , staticMask ) ;
}
}
2025-03-10 13:00:30 +08:00
EcsMask mask = staticMask . ToMask ( world ) ;
if ( builtinAspect ! = null )
{
builtinAspect . _mask = mask ;
//var pools = new IEcsPool[builder._poolsBufferCount];
//Array.Copy(builder._poolsBuffer, pools, pools.Length);
builtinAspect . _isBuilt = true ;
}
2024-01-07 18:52:54 +08:00
2024-11-01 12:41:10 +08:00
_constructorBuildersStackIndex - - ;
2025-03-10 13:00:30 +08:00
return ( newAspect , mask ) ;
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-11-09 21:10:12 +08:00
public Singleton < T > Get < T > ( ) where T : struct
{
return new Singleton < T > ( _world . ID ) ;
}
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 > ( ) ;
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 )
{
2024-11-12 16:36:37 +08:00
pool . AddEmpty ( entityID ) ;
2024-11-01 12:41:10 +08:00
}
}
#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-12-04 16:10:09 +08:00
#region EcsAspect . Builder . Extensions
public static class EcsAspectBuilderExtensions
{
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 ;
}
}
2024-08-26 11:08:42 +08:00
#endregion
2025-03-10 13:00:30 +08:00
}
namespace DCFApixels.DragonECS.Core
{
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-11-09 21:10:12 +08:00
public readonly ref struct SingletonMarker
{
public readonly EcsAspect . Builder Builder ;
public SingletonMarker ( EcsAspect . Builder builder )
{
Builder = builder ;
}
public T Get < T > ( ) where T : struct
{
return Builder . World . Get < T > ( ) ;
}
}
2024-08-23 22:31:43 +08:00
#endregion
}