moving part of the API into a separate module

This commit is contained in:
Mikhail 2023-05-26 06:18:09 +08:00
parent 32429e5af8
commit 7cc02d00ba
13 changed files with 28 additions and 788 deletions

View File

@ -1,4 +1,5 @@
using System;
using DCFApixels.DragonECS.Utils;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Runtime.CompilerServices;

View File

@ -1,7 +1,8 @@
using System;
using DCFApixels.DragonECS.Internal;
using DCFApixels.DragonECS.Utils;
using System;
using System.Collections.Generic;
using System.Runtime.CompilerServices;
using DCFApixels.DragonECS.Internal;
namespace DCFApixels.DragonECS
{
@ -144,7 +145,7 @@ namespace DCFApixels.DragonECS
}
#endregion
#region Queries
#region Subjects
public TSubject GetSubject<TSubject>() where TSubject : EcsSubject
{
int uniqueID = WorldMetaStorage.GetSubjectId<TSubject>(_worldTypeID);
@ -154,104 +155,45 @@ namespace DCFApixels.DragonECS
_subjects[uniqueID] = EcsSubject.Builder.Build<TSubject>(this);
return (TSubject)_subjects[uniqueID];
}
#region Iterate
public EcsSubjectIterator<TSubject> IterateFor<TSubject>(EcsReadonlyGroup sourceGroup, out TSubject subject) where TSubject : EcsSubject
{
subject = GetSubject<TSubject>();
return subject.GetIteratorFor(sourceGroup);
}
public EcsSubjectIterator<TSubject> IterateFor<TSubject>(EcsReadonlyGroup sourceGroup) where TSubject : EcsSubject
{
return GetSubject<TSubject>().GetIteratorFor(sourceGroup);
}
public EcsSubjectIterator<TSubject> Iterate<TSubject>(out TSubject subject) where TSubject : EcsSubject
{
subject = GetSubject<TSubject>();
return subject.GetIterator();
}
public EcsSubjectIterator<TSubject> Iterate<TSubject>() where TSubject : EcsSubject
{
return GetSubject<TSubject>().GetIterator();
}
#endregion
#region Where
private EcsWhereExecutor<TSubject> GetWhereExecutor<TSubject>() where TSubject : EcsSubject
#region Queries
public TExecutor GetExecutor<TExecutor>(Func<EcsWorld, TExecutor> builder) where TExecutor: EcsQueryExecutor
{
int id = WorldMetaStorage.GetExecutorId<EcsWhereExecutor<TSubject>>(_worldTypeID);
int id = WorldMetaStorage.GetExecutorId<TExecutor>(_worldTypeID);
if (id >= _executors.Length)
Array.Resize(ref _executors, _executors.Length << 1);
if (_executors[id] == null)
_executors[id] = new EcsWhereExecutor<TSubject>(GetSubject<TSubject>());
return (EcsWhereExecutor<TSubject>)_executors[id];
_executors[id] = builder(this);
return (TExecutor)_executors[id];
}
private EcsWhereExecutor<TSubject> EcsWhereExecutorBuilder<TSubject>(EcsWorld world) where TSubject : EcsSubject
{
return new EcsWhereExecutor<TSubject>(world.GetSubject<TSubject>());
}
public EcsWhereResult<TSubject> WhereFor<TSubject>(EcsReadonlyGroup sourceGroup, out TSubject subject) where TSubject : EcsSubject
{
var executor = GetWhereExecutor<TSubject>();
var executor = GetExecutor(EcsWhereExecutorBuilder<TSubject>);
subject = executor.Subject;
return executor.ExecuteFor(sourceGroup);
}
public EcsWhereResult<TSubject> WhereFor<TSubject>(EcsReadonlyGroup sourceGroup) where TSubject : EcsSubject
{
return GetWhereExecutor<TSubject>().ExecuteFor(sourceGroup);
return GetExecutor(EcsWhereExecutorBuilder<TSubject>).ExecuteFor(sourceGroup);
}
public EcsWhereResult<TSubject> Where<TSubject>(out TSubject subject) where TSubject : EcsSubject
{
var executor = GetWhereExecutor<TSubject>();
var executor = GetExecutor(EcsWhereExecutorBuilder<TSubject>);
subject = executor.Subject;
return executor.Execute();
}
public EcsWhereResult<TSubject> Where<TSubject>() where TSubject : EcsSubject
{
return GetWhereExecutor<TSubject>().Execute();
return GetExecutor(EcsWhereExecutorBuilder<TSubject>).Execute();
}
#endregion
#region Join
private EcsJoinAttachExecutor<TSubject, TAttachComponent> GetJoinAttachExecutor<TSubject, TAttachComponent>()
where TSubject : EcsSubject
where TAttachComponent : struct, IEcsAttachComponent
{
int id = WorldMetaStorage.GetExecutorId<EcsJoinAttachExecutor<TSubject, TAttachComponent>>(_worldTypeID);
if (id >= _executors.Length)
Array.Resize(ref _executors, _executors.Length << 1);
if (_executors[id] == null)
_executors[id] = new EcsJoinAttachExecutor<TSubject, TAttachComponent>(GetSubject<TSubject>());
return (EcsJoinAttachExecutor<TSubject, TAttachComponent>)_executors[id];
}
public EcsJoinAttachResult<TSubject, TAttachComponent> JoinFor<TSubject, TAttachComponent>(EcsReadonlyGroup sourceGroup, out TSubject subject)
where TSubject : EcsSubject
where TAttachComponent : struct, IEcsAttachComponent
{
var executor = GetJoinAttachExecutor<TSubject, TAttachComponent>();
subject = executor.Subject;
return executor.ExecuteFor(sourceGroup);
}
public EcsJoinAttachResult<TSubject, TAttachComponent> JoinFor<TSubject, TAttachComponent>(EcsReadonlyGroup sourceGroup)
where TSubject : EcsSubject
where TAttachComponent : struct, IEcsAttachComponent
{
return GetJoinAttachExecutor<TSubject, TAttachComponent>().ExecuteFor(sourceGroup);
}
public EcsJoinAttachResult<TSubject, TAttachComponent> Join<TSubject, TAttachComponent>(out TSubject subject)
where TSubject : EcsSubject
where TAttachComponent : struct, IEcsAttachComponent
{
var executor = GetJoinAttachExecutor<TSubject, TAttachComponent>();
subject = executor.Subject;
return executor.Execute();
}
public EcsJoinAttachResult<TSubject, TAttachComponent> Join<TSubject, TAttachComponent>()
where TSubject : EcsSubject
where TAttachComponent : struct, IEcsAttachComponent
{
return GetJoinAttachExecutor<TSubject, TAttachComponent>().Execute();
}
#endregion
#endregion
#region IsMatchesMask
public bool IsMatchesMask(EcsMask mask, int entityID)
{

View File

@ -1,189 +0,0 @@
using Unity.Profiling;
namespace DCFApixels.DragonECS
{
public sealed class EcsJoinAttachExecutor<TSubject, TAttachComponent> : EcsQueryExecutor
where TSubject : EcsSubject
where TAttachComponent : struct, IEcsAttachComponent
{
private readonly TSubject _subject;
internal readonly EcsGroup _filteredGroup;
private EcsWorld _targetWorld;
private EcsAttachPool<TAttachComponent> _targetPool;
private int _targetWorldCapacity = -1;
private int _targetPoolCapacity = -1;
private int[] _mapping;
private int[] _counts;
private EntityLinkedList _linkedBasket;
private bool _isInitTargetWorld = false;
private ProfilerMarker _executeJoin = new ProfilerMarker("JoinAttachQuery.Join");
private long _executeVersion;
#region Properties
public TSubject Subject => _subject;
internal long ExecuteVersion => _executeVersion;
#endregion
#region Constructors
public EcsJoinAttachExecutor(TSubject subject)
{
_subject = subject;
_filteredGroup = EcsGroup.New(subject.World);
_targetPool = subject.World.GetPool<TAttachComponent>();
}
#endregion
#region Methods
public EcsJoinAttachResult<TSubject, TAttachComponent> Execute() => ExecuteFor(_targetPool.Entities);
public EcsJoinAttachResult<TSubject, TAttachComponent> ExecuteFor(EcsReadonlyGroup sourceGroup)
{
_executeJoin.Begin();
var world = _subject.World;
#if (DEBUG && !DISABLE_DEBUG) || !DISABLE_DRAGONECS_ASSERT_CHEKS
if (sourceGroup.IsNull) throw new System.ArgumentNullException();//TODO составить текст исключения.
#endif
if (!_isInitTargetWorld)
InitTargetWorlds(sourceGroup.World);
#if (DEBUG && !DISABLE_DEBUG) || !DISABLE_DRAGONECS_ASSERT_CHEKS
else
if (_targetWorld != sourceGroup.World) throw new System.ArgumentException();//TODO составить текст исключения. это проверка на то что пользователь использует правильный мир
#endif
//Подготовка массивов
if (_targetWorldCapacity < _targetWorld.Capacity)
{
_targetWorldCapacity = _targetWorld.Capacity;
_mapping = new int[_targetWorldCapacity];
_counts = new int[_targetWorldCapacity];
}
else
{
ArrayUtility.Fill(_counts, 0);
ArrayUtility.Fill(_mapping, 0);
}
if (_targetPoolCapacity < _targetPool.Capacity)
{
_targetPoolCapacity = _targetPool.Capacity;
_linkedBasket.Resize(_targetPoolCapacity);
}
_linkedBasket.Clear();
//Конец подготовки массивов
var iterator = new EcsSubjectIterator<TSubject>(_subject, sourceGroup);
foreach (var attachID in iterator)
{
entlong attachTarget = _targetPool.Read(attachID).Target;
if (!attachTarget.IsAlive)
{
//_targetPool.Del(attachID);
continue;
}
int attachTargetID = attachTarget.id;
//if (!CheckMaskInternal(targetWorldWhereQuery.query.mask, attachTargetID)) continue; //TODO проверить что все работает //исчключить все аттачи, цели которых не входят в targetWorldWhereQuery
ref int nodeIndex = ref _mapping[attachTargetID];
if (nodeIndex <= 0)
nodeIndex = _linkedBasket.Add(attachID);
else
_linkedBasket.Insert(nodeIndex, attachID);
_counts[attachTargetID]++;
}
_executeVersion++;
_executeJoin.End();
return new EcsJoinAttachResult<TSubject, TAttachComponent>(_subject, this , _executeVersion);
}
private void InitTargetWorlds(EcsWorld targetWorld)
{
_targetWorld = targetWorld;
_targetWorldCapacity = _targetWorld.Capacity;
_mapping = new int[_targetWorldCapacity];
_counts = new int[_targetWorldCapacity];
_targetPoolCapacity = _targetPool.Capacity;
_linkedBasket = new EntityLinkedList(_targetPoolCapacity);
_isInitTargetWorld = true;
}
internal sealed override void Destroy()
{
_filteredGroup.Release();
_targetWorld = null;
_mapping = null;
_counts = null;
_linkedBasket = null;
}
#endregion
#region Internal result methods
internal bool Has(int attachedEnttiyID) => _filteredGroup.Has(attachedEnttiyID);
internal EntityLinkedList.EnumerableSpan GetNodes(int entityID) => _linkedBasket.Span(_mapping[entityID], _counts[entityID]);
internal int GetNode(int entityID) => _counts[entityID] > 0 ? _linkedBasket.Get(_mapping[entityID]) : 0;
internal int GetNodesCount(int entityID) => _counts[entityID];
internal bool HasNode(int entityID, int attachedEntityID) => _filteredGroup.Has(attachedEntityID) && _targetPool.Read(attachedEntityID).Target.id == entityID;
#endregion
}
#region JoinAttachExecuter Results
public readonly ref struct EcsJoinAttachResult<TSubject, TAttachComponent>
where TSubject : EcsSubject
where TAttachComponent : struct, IEcsAttachComponent
{
public readonly TSubject s;
private readonly EcsJoinAttachExecutor<TSubject, TAttachComponent> _executer;
private readonly long _verison;
public bool IsRelevant => _verison == _executer.ExecuteVersion;
public EcsJoinAttachResult(TSubject s, EcsJoinAttachExecutor<TSubject, TAttachComponent> executer, long version)
{
this.s = s;
_executer = executer;
_verison = version;
}
public bool Has(int attachedEnttiyID)
{
#if (DEBUG && !DISABLE_DEBUG) || !DISABLE_DRAGONECS_ASSERT_CHEKS
if (!IsRelevant) throw new System.InvalidOperationException();//TODO составить текст исключения.
#endif
return _executer.Has(attachedEnttiyID);
}
public EntityLinkedList.EnumerableSpan GetNodes(int entityID)
{
#if (DEBUG && !DISABLE_DEBUG) || !DISABLE_DRAGONECS_ASSERT_CHEKS
if (!IsRelevant) throw new System.InvalidOperationException();//TODO составить текст исключения.
#endif
return _executer.GetNodes(entityID);
}
public int GetNode(int entityID)
{
#if (DEBUG && !DISABLE_DEBUG) || !DISABLE_DRAGONECS_ASSERT_CHEKS
if (!IsRelevant) throw new System.InvalidOperationException();//TODO составить текст исключения.
#endif
return _executer.GetNode(entityID);
}
public int GetNodesCount(int entityID)
{
#if (DEBUG && !DISABLE_DEBUG) || !DISABLE_DRAGONECS_ASSERT_CHEKS
if (!IsRelevant) throw new System.InvalidOperationException();//TODO составить текст исключения.
#endif
return _executer.GetNodesCount(entityID);
}
public bool HasNode(int entityID, int attachedEntityID)
{
#if (DEBUG && !DISABLE_DEBUG) || !DISABLE_DRAGONECS_ASSERT_CHEKS
if (!IsRelevant) throw new System.InvalidOperationException();//TODO составить текст исключения.
#endif
return _executer.HasNode(entityID, attachedEntityID);
}
}
#endregion
}

View File

@ -1,198 +0,0 @@
using System;
using Unity.Profiling;
namespace DCFApixels.DragonECS
{
public sealed class EcsJoinHierarchyExecutor<TSubject, TAttachComponent> : EcsQueryExecutor
where TSubject : EcsSubject
where TAttachComponent : struct, IEcsAttachComponent
{
private readonly TSubject _subject;
internal readonly EcsGroup _filteredGroup;
private EcsWorld _targetWorld;
private EcsAttachPool<TAttachComponent> _targetPool;
private int _targetWorldCapacity = -1;
private int _targetPoolCapacity = -1;
private int[] _mapping;
private int[] _counts;
private EntityLinkedList _linkedBasket;
private bool _isInitTargetWorld = false;
private ProfilerMarker _executeWhere = new ProfilerMarker("JoinAttachQuery.Where");
private ProfilerMarker _executeJoin = new ProfilerMarker("JoinAttachQuery.Join");
private long _executeVersion;
#region Properties
public TSubject Subject => _subject;
internal long ExecuteVersion => _executeVersion;
#endregion
#region Constructors
public EcsJoinHierarchyExecutor(TSubject subject)
{
_subject = subject;
_filteredGroup = EcsGroup.New(subject.World);
_targetPool = subject.World.GetPool<TAttachComponent>();
}
#endregion
#region Methods
public EcsJoinHierarchyResult<TSubject, TAttachComponent> Execute() => ExecuteFor(_targetPool.Entities);
public EcsJoinHierarchyResult<TSubject, TAttachComponent> ExecuteFor(EcsReadonlyGroup sourceGroup)
{
var world = _subject.World;
_executeJoin.Begin();
#if (DEBUG && !DISABLE_DEBUG) || !DISABLE_DRAGONECS_ASSERT_CHEKS
if (sourceGroup.IsNull) throw new ArgumentNullException();//TODO составить текст исключения.
#endif
if (!_isInitTargetWorld)
InitTargetWorlds(sourceGroup.World);
#if (DEBUG && !DISABLE_DEBUG) || !DISABLE_DRAGONECS_ASSERT_CHEKS
else
if (_targetWorld != sourceGroup.World) throw new ArgumentException();//TODO составить текст исключения. это проверка на то что пользователь использует правильный мир
#endif
//Подготовка массивов
if (_targetWorldCapacity < _targetWorld.Capacity)
{
_targetWorldCapacity = _targetWorld.Capacity;
_mapping = new int[_targetWorldCapacity];
_counts = new int[_targetWorldCapacity];
}
else
{
ArrayUtility.Fill(_counts, 0);
ArrayUtility.Fill(_mapping, 0);
}
if (_targetPoolCapacity < _targetPool.Capacity)
{
_targetPoolCapacity = _targetPool.Capacity;
_linkedBasket.Resize(_targetPoolCapacity);
}
_linkedBasket.Clear();
//Конец подготовки массивов
var iterator = new EcsSubjectIterator<TSubject>(_subject, sourceGroup);
foreach (var attachID in iterator)
{
entlong attachTarget = _targetPool.Read(attachID).Target;
if (!attachTarget.IsAlive)
{
//_targetPool.Del(attachID);
continue;
}
int attachTargetID = attachTarget.id;
//if (!CheckMaskInternal(targetWorldWhereQuery.query.mask, attachTargetID)) continue; //TODO проверить что все работает //исчключить все аттачи, цели которых не входят в targetWorldWhereQuery
ref int nodeIndex = ref _mapping[attachTargetID];
if (nodeIndex <= 0)
nodeIndex = _linkedBasket.Add(attachID);
else
_linkedBasket.Insert(nodeIndex, attachID);
_counts[attachTargetID]++;
}
_executeVersion++;
_executeJoin.End();
return new EcsJoinHierarchyResult<TSubject, TAttachComponent>(_subject, this , _executeVersion);
}
private void InitTargetWorlds(EcsWorld targetWorld)
{
_targetWorld = targetWorld;
_targetWorldCapacity = _targetWorld.Capacity;
_mapping = new int[_targetWorldCapacity];
_counts = new int[_targetWorldCapacity];
_targetPoolCapacity = _targetPool.Capacity;
_linkedBasket = new EntityLinkedList(_targetPoolCapacity);
_isInitTargetWorld = true;
}
internal sealed override void Destroy()
{
_filteredGroup.Release();
_targetWorld = null;
_mapping = null;
_counts = null;
_linkedBasket = null;
}
#endregion
#region Internal result methods
internal bool Has(int attachedEnttiyID) => _filteredGroup.Has(attachedEnttiyID);
internal EntityLinkedList.EnumerableSpan GetNodes(int entityID) => _linkedBasket.Span(_mapping[entityID], _counts[entityID]);
internal int GetNode(int entityID) => _counts[entityID] > 0 ? _linkedBasket.Get(_mapping[entityID]) : 0;
internal int GetNodesCount(int entityID) => _counts[entityID];
internal bool HasNode(int entityID, int attachedEntityID) => _filteredGroup.Has(attachedEntityID) && _targetPool.Read(attachedEntityID).Target.id == entityID;
internal EntityLinkedList.EnumerableSpan GetSubNodes(int entityID) => throw new NotImplementedException();
internal int GetSubNode(int entityID) => throw new NotImplementedException();
internal bool GetSubNodesCount(int entityID, int attachedEntityID) => throw new NotImplementedException();
internal bool HasSubNode(int entityID, int attachedEntityID) => throw new NotImplementedException();
#endregion
}
#region JoinAttachExecuter Results
public readonly ref struct EcsJoinHierarchyResult<TSubject, TAttachComponent>
where TSubject : EcsSubject
where TAttachComponent : struct, IEcsAttachComponent
{
public readonly TSubject s;
private readonly EcsJoinHierarchyExecutor<TSubject, TAttachComponent> _executer;
private readonly long _verison;
public bool IsRelevant => _verison == _executer.ExecuteVersion;
public EcsJoinHierarchyResult(TSubject s, EcsJoinHierarchyExecutor<TSubject, TAttachComponent> executer, long version)
{
this.s = s;
_executer = executer;
_verison = version;
}
public bool Has(int attachedEnttiyID)
{
#if (DEBUG && !DISABLE_DEBUG) || !DISABLE_DRAGONECS_ASSERT_CHEKS
if (!IsRelevant) throw new InvalidOperationException();//TODO составить текст исключения.
#endif
return _executer.Has(attachedEnttiyID);
}
public EntityLinkedList.EnumerableSpan GetNodes(int entityID)
{
#if (DEBUG && !DISABLE_DEBUG) || !DISABLE_DRAGONECS_ASSERT_CHEKS
if (!IsRelevant) throw new InvalidOperationException();//TODO составить текст исключения.
#endif
return _executer.GetNodes(entityID);
}
public int GetNode(int entityID)
{
#if (DEBUG && !DISABLE_DEBUG) || !DISABLE_DRAGONECS_ASSERT_CHEKS
if (!IsRelevant) throw new InvalidOperationException();//TODO составить текст исключения.
#endif
return _executer.GetNode(entityID);
}
public int GetNodesCount(int entityID)
{
#if (DEBUG && !DISABLE_DEBUG) || !DISABLE_DRAGONECS_ASSERT_CHEKS
if (!IsRelevant) throw new InvalidOperationException();//TODO составить текст исключения.
#endif
return _executer.GetNodesCount(entityID);
}
public bool HasNode(int entityID, int attachedEntityID)
{
#if (DEBUG && !DISABLE_DEBUG) || !DISABLE_DRAGONECS_ASSERT_CHEKS
if (!IsRelevant) throw new InvalidOperationException();//TODO составить текст исключения.
#endif
return _executer.HasNode(entityID, attachedEntityID);
}
}
#endregion
}

View File

@ -2,6 +2,7 @@
{
public abstract class EcsQueryExecutor
{
internal abstract void Destroy();
internal void Destroy() => OnDestroy();
protected abstract void OnDestroy();
}
}

View File

@ -37,7 +37,7 @@ namespace DCFApixels.DragonECS
return new EcsWhereResult<TSubject>(this, _filteredGroup.Readonly);
}
}
internal sealed override void Destroy()
protected sealed override void OnDestroy()
{
_filteredGroup.Release();
}

View File

@ -1,140 +0,0 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Runtime.CompilerServices;
namespace DCFApixels.DragonECS
{
//íå âëèÿåò íà ñ÷åò÷èê êîìïîíåíòîâ íà ñóùíîñòè
/// <summary>Pool for IEcsNotNullComponent components</summary>
public sealed class EcsNotNullPool<T> : IEcsPoolImplementation<T>, IEnumerable<T> //IntelliSense hack
where T : struct, IEcsNotNullComponent
{
private EcsWorld _source;
private int _id;
private T[] _items; //sparse
private int _count;
private IEcsComponentReset<T> _componentResetHandler;
private IEcsComponentCopy<T> _componentCopyHandler;
private List<IEcsPoolEventListener> _listeners;
#region Properites
public int Count => _count;
public int Capacity => _items.Length;
public int ComponentID => _id;
public Type ComponentType => typeof(T);
public EcsWorld World => _source;
#endregion
#region Init
void IEcsPoolImplementation.OnInit(EcsWorld world, int componentID)
{
_source = world;
_id = componentID;
_items = new T[world.Capacity];
_count = 0;
_listeners = new List<IEcsPoolEventListener>();
_componentResetHandler = EcsComponentResetHandler<T>.instance;
_componentCopyHandler = EcsComponentCopyHandler<T>.instance;
}
#endregion
#region Methods
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public ref T Write(int entityID)
{
_listeners.InvokeOnWrite(entityID);
return ref _items[entityID];
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public ref readonly T Read(int entityID)
{
return ref _items[entityID];
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool Has(int entityID)
{
return true;
}
public void Copy(int fromEntityID, int toEntityID)
{
_componentCopyHandler.Copy(ref Write(fromEntityID), ref Write(toEntityID));
}
public void Copy(int fromEntityID, EcsWorld toWorld, int toEntityID)
{
_componentCopyHandler.Copy(ref Write(fromEntityID), ref toWorld.GetPool<T>().Write(toEntityID));
}
#endregion
#region Callbacks
void IEcsPoolImplementation.OnWorldResize(int newSize)
{
Array.Resize(ref _items, newSize);
}
void IEcsPoolImplementation.OnWorldDestroy() { }
void IEcsPoolImplementation.OnReleaseDelEntityBuffer(ReadOnlySpan<int> buffer)
{
foreach (var entityID in buffer)
_componentResetHandler.Reset(ref _items[entityID]);
}
#endregion
#region Other
ref T IEcsPool<T>.Add(int entityID) => ref Write(entityID);
ref readonly T IEcsPool<T>.Read(int entityID) => ref Read(entityID);
ref T IEcsPool<T>.Write(int entityID) => ref Write(entityID);
void IEcsPool.Del(int entityID) { }
void IEcsPool.AddRaw(int entityID, object dataRaw) => Write(entityID) = (T)dataRaw;
object IEcsPool.GetRaw(int entityID) => Write(entityID);
void IEcsPool.SetRaw(int entityID, object dataRaw) => Write(entityID) = (T)dataRaw;
#endregion
#region Listeners
public void AddListener(IEcsPoolEventListener listener)
{
if (listener == null) { throw new ArgumentNullException("listener is null"); }
_listeners.Add(listener);
}
public void RemoveListener(IEcsPoolEventListener listener)
{
if (listener == null) { throw new ArgumentNullException("listener is null"); }
_listeners.Remove(listener);
}
#endregion
#region IEnumerator - IntelliSense hack
IEnumerator<T> IEnumerable<T>.GetEnumerator() => throw new NotImplementedException();
IEnumerator IEnumerable.GetEnumerator() => throw new NotImplementedException();
#endregion
}
/// <summary>
/// Not null component. Is present on all entities, without explicit addition and cannot be deleted
/// </summary>
public interface IEcsNotNullComponent { }
public static class EcsNotNullPoolExt
{
public static EcsNotNullPool<TNotNullComponent> GetPool<TNotNullComponent>(this EcsWorld self) where TNotNullComponent : struct, IEcsNotNullComponent
{
return self.GetPool<TNotNullComponent, EcsNotNullPool<TNotNullComponent>>();
}
public static EcsNotNullPool<TNotNullComponent> Include<TNotNullComponent>(this EcsSubjectBuilderBase self) where TNotNullComponent : struct, IEcsNotNullComponent
{
return self.Include<TNotNullComponent, EcsNotNullPool<TNotNullComponent>>();
}
public static EcsNotNullPool<TNotNullComponent> Exclude<TNotNullComponent>(this EcsSubjectBuilderBase self) where TNotNullComponent : struct, IEcsNotNullComponent
{
return self.Exclude<TNotNullComponent, EcsNotNullPool<TNotNullComponent>>();
}
public static EcsNotNullPool<TNotNullComponent> Optional<TNotNullComponent>(this EcsSubjectBuilderBase self) where TNotNullComponent : struct, IEcsNotNullComponent
{
return self.Optional<TNotNullComponent, EcsNotNullPool<TNotNullComponent>>();
}
}
}

View File

@ -1,177 +0,0 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Runtime.CompilerServices;
namespace DCFApixels.DragonECS
{
using static EcsPoolThrowHalper;
public sealed class EcsSinglePool<T> : IEcsPoolImplementation<T>, IEnumerable<T> //IntelliSense hack
where T : struct, IEcsSingleComponent
{
private EcsWorld _source;
private int _id;
private int[] _mapping;
private int _count;
private T _component;
private List<IEcsPoolEventListener> _listeners;
#region Properites
public ref T Instance
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get => ref _component;
}
public int Count => _count;
int IEcsPool.Capacity => -1;
public int ComponentID => _id;
public Type ComponentType => typeof(T);
public EcsWorld World => _source;
#endregion
#region Init
void IEcsPoolImplementation.OnInit(EcsWorld world, int componentID)
{
_source = world;
_id = componentID;
_mapping = new int[world.Capacity];
_count = 0;
_listeners = new List<IEcsPoolEventListener>();
}
#endregion
#region Methods
public ref T Add(int entityID)
{
#if (DEBUG && !DISABLE_DEBUG) || !DISABLE_DRAGONECS_ASSERT_CHEKS
if (Has(entityID)) ThrowAlreadyHasComponent<T>(entityID);
#endif
_mapping[entityID] = ++_count;
this.IncrementEntityComponentCount(entityID);
_listeners.InvokeOnAddAndWrite(entityID);
return ref _component;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public ref T Write(int entityID)
{
#if (DEBUG && !DISABLE_DEBUG) || !DISABLE_DRAGONECS_ASSERT_CHEKS
if (!Has(entityID)) ThrowNotHaveComponent<T>(entityID);
#endif
_listeners.InvokeOnWrite(entityID);
return ref _component;
}
public ref T TryAddOrWrite(int entityID)
{
if (!Has(entityID))
return ref Add(entityID);
return ref Write(entityID);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public ref readonly T Read(int entityID)
{
#if (DEBUG && !DISABLE_DEBUG) || !DISABLE_DRAGONECS_ASSERT_CHEKS
if (!Has(entityID)) ThrowNotHaveComponent<T>(entityID);
#endif
return ref _component;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool Has(int entityID)
{
return _mapping[entityID] > 0;
}
public void Del(int entityID)
{
#if (DEBUG && !DISABLE_DEBUG) || !DISABLE_DRAGONECS_ASSERT_CHEKS
if (!Has(entityID)) ThrowNotHaveComponent<T>(entityID);
#endif
_mapping[entityID] = 0;
_count--;
this.DecrementEntityComponentCount(entityID);
_listeners.InvokeOnDel(entityID);
}
public void TryDel(int entityID)
{
if (Has(entityID)) Del(entityID);
}
public void Copy(int fromEntityID, int toEntityID)
{
#if (DEBUG && !DISABLE_DEBUG) || !DISABLE_DRAGONECS_ASSERT_CHEKS
if (!Has(fromEntityID)) ThrowNotHaveComponent<T>(fromEntityID);
#endif
TryAddOrWrite(toEntityID);
}
public void Copy(int fromEntityID, EcsWorld toWorld, int toEntityID)
{
#if (DEBUG && !DISABLE_DEBUG) || !DISABLE_DRAGONECS_ASSERT_CHEKS
if (!Has(fromEntityID)) ThrowNotHaveComponent<T>(fromEntityID);
#endif
toWorld.GetPool<T>().TryAddOrWrite(toEntityID);
}
#endregion
#region Callbacks
void IEcsPoolImplementation.OnWorldResize(int newSize)
{
Array.Resize(ref _mapping, newSize);
}
void IEcsPoolImplementation.OnWorldDestroy() { }
void IEcsPoolImplementation.OnReleaseDelEntityBuffer(ReadOnlySpan<int> buffer)
{
foreach (var entityID in buffer)
TryDel(entityID);
}
#endregion
#region Other
void IEcsPool.AddRaw(int entityID, object dataRaw) => Instance = (T)dataRaw;
object IEcsPool.GetRaw(int entityID) => Instance;
void IEcsPool.SetRaw(int entityID, object dataRaw) => Instance = (T)dataRaw;
#endregion
#region Listeners
public void AddListener(IEcsPoolEventListener listener)
{
if (listener == null) { throw new ArgumentNullException("listener is null"); }
_listeners.Add(listener);
}
public void RemoveListener(IEcsPoolEventListener listener)
{
if (listener == null) { throw new ArgumentNullException("listener is null"); }
_listeners.Remove(listener);
}
#endregion
#region IEnumerator - IntelliSense hack
IEnumerator<T> IEnumerable<T>.GetEnumerator() => throw new NotImplementedException();
IEnumerator IEnumerable.GetEnumerator() => throw new NotImplementedException();
#endregion
}
/// <summary>Singleton component</summary>
public interface IEcsSingleComponent { }
public static class EcsSinglePoolExt
{
public static EcsSinglePool<TSingleComponent> GetPool<TSingleComponent>(this EcsWorld self)
where TSingleComponent : struct, IEcsSingleComponent
{
return self.GetPool<TSingleComponent, EcsSinglePool<TSingleComponent>>();
}
public static EcsSinglePool<TSingleComponent> Include<TSingleComponent>(this EcsSubjectBuilderBase self) where TSingleComponent : struct, IEcsSingleComponent
{
return self.Include<TSingleComponent, EcsSinglePool<TSingleComponent>>();
}
public static EcsSinglePool<TSingleComponent> Exclude<TSingleComponent>(this EcsSubjectBuilderBase self) where TSingleComponent : struct, IEcsSingleComponent
{
return self.Exclude<TSingleComponent, EcsSinglePool<TSingleComponent>>();
}
public static EcsSinglePool<TSingleComponent> Optional<TSingleComponent>(this EcsSubjectBuilderBase self) where TSingleComponent : struct, IEcsSingleComponent
{
return self.Optional<TSingleComponent, EcsSinglePool<TSingleComponent>>();
}
}
}

View File

@ -1,7 +1,7 @@
using System;
using System.Runtime.InteropServices;
namespace DCFApixels.DragonECS
namespace DCFApixels.DragonECS.Utils
{
internal static class ArrayUtility
{

View File

@ -1,7 +1,7 @@
using System.Collections.Concurrent;
using System.Threading;
namespace DCFApixels.DragonECS
namespace DCFApixels.DragonECS.Utils
{
internal sealed class IntDispenser
{

View File

@ -1,6 +1,6 @@
namespace DCFApixels.DragonECS
{
public static class Extensions
public static class IntExtensions
{
public static entlong ToEntityLong(this int self, EcsWorld world)
{

View File

@ -6,7 +6,7 @@ using System.Diagnostics.Contracts;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
namespace DCFApixels.DragonECS
namespace DCFApixels.DragonECS.Utils
{
public class SparseArray<TValue>
{

View File

@ -4,7 +4,7 @@ using System.Collections.Generic;
using System.Runtime.CompilerServices;
using System.Text;
namespace DCFApixels.DragonECS
namespace DCFApixels.DragonECS.Utils
{
public class SparseSet : IEnumerable<int>, ICollection<int>, IReadOnlyCollection<int>
{