mirror of
https://github.com/DCFApixels/DragonECS.git
synced 2025-09-18 01:44:35 +08:00
update queries
This commit is contained in:
parent
cb25943b55
commit
24849ab619
@ -31,10 +31,10 @@ namespace DCFApixels.DragonECS
|
||||
public void PreInit(EcsPipeline pipeline)
|
||||
{
|
||||
#if DEBUG && !DISABLE_DEBUG
|
||||
for (int i = 0; i < Targets.Length && Targets.Length <= _markers.Length; i++)
|
||||
for (int i = 0; i < targets.Length && targets.Length <= _markers.Length; i++)
|
||||
{
|
||||
using (_markers[i].Auto())
|
||||
Targets[i].PreInit(pipeline);
|
||||
targets[i].PreInit(pipeline);
|
||||
}
|
||||
#else
|
||||
foreach (var item in targets) item.PreInit(pipeline);
|
||||
@ -44,10 +44,10 @@ namespace DCFApixels.DragonECS
|
||||
#if DEBUG && !DISABLE_DEBUG
|
||||
protected override void OnSetup()
|
||||
{
|
||||
_markers = new EcsProfilerMarker[Targets.Length];
|
||||
for (int i = 0; i < Targets.Length; i++)
|
||||
_markers = new EcsProfilerMarker[targets.Length];
|
||||
for (int i = 0; i < targets.Length; i++)
|
||||
{
|
||||
_markers[i] = new EcsProfilerMarker(EcsDebug.RegisterMark($"EcsRunner.{Targets[i].GetType().Name}.{nameof(PreInit)}"));
|
||||
_markers[i] = new EcsProfilerMarker(EcsDebug.RegisterMark($"EcsRunner.{targets[i].GetType().Name}.{nameof(PreInit)}"));
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@ -61,10 +61,10 @@ namespace DCFApixels.DragonECS
|
||||
public void Init(EcsPipeline pipeline)
|
||||
{
|
||||
#if DEBUG && !DISABLE_DEBUG
|
||||
for (int i = 0; i < Targets.Length && Targets.Length <= _markers.Length; i++)
|
||||
for (int i = 0; i < targets.Length && targets.Length <= _markers.Length; i++)
|
||||
{
|
||||
using (_markers[i].Auto())
|
||||
Targets[i].Init(pipeline);
|
||||
targets[i].Init(pipeline);
|
||||
}
|
||||
#else
|
||||
foreach (var item in targets) item.Init(pipeline);
|
||||
@ -74,10 +74,10 @@ namespace DCFApixels.DragonECS
|
||||
#if DEBUG && !DISABLE_DEBUG
|
||||
protected override void OnSetup()
|
||||
{
|
||||
_markers = new EcsProfilerMarker[Targets.Length];
|
||||
for (int i = 0; i < Targets.Length; i++)
|
||||
_markers = new EcsProfilerMarker[targets.Length];
|
||||
for (int i = 0; i < targets.Length; i++)
|
||||
{
|
||||
_markers[i] = new EcsProfilerMarker(EcsDebug.RegisterMark($"EcsRunner.{Targets[i].GetType().Name}.{nameof(Init)}"));
|
||||
_markers[i] = new EcsProfilerMarker(EcsDebug.RegisterMark($"EcsRunner.{targets[i].GetType().Name}.{nameof(Init)}"));
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@ -91,10 +91,10 @@ namespace DCFApixels.DragonECS
|
||||
public void Run(EcsPipeline pipeline)
|
||||
{
|
||||
#if DEBUG && !DISABLE_DEBUG
|
||||
for (int i = 0; i < Targets.Length && Targets.Length <= _markers.Length; i++)
|
||||
for (int i = 0; i < targets.Length && targets.Length <= _markers.Length; i++)
|
||||
{
|
||||
using (_markers[i].Auto())
|
||||
Targets[i].Run(pipeline);
|
||||
targets[i].Run(pipeline);
|
||||
|
||||
}
|
||||
#else
|
||||
@ -105,10 +105,10 @@ namespace DCFApixels.DragonECS
|
||||
#if DEBUG && !DISABLE_DEBUG
|
||||
protected override void OnSetup()
|
||||
{
|
||||
_markers = new EcsProfilerMarker[Targets.Length];
|
||||
for (int i = 0; i < Targets.Length; i++)
|
||||
_markers = new EcsProfilerMarker[targets.Length];
|
||||
for (int i = 0; i < targets.Length; i++)
|
||||
{
|
||||
_markers[i] = new EcsProfilerMarker(EcsDebug.RegisterMark($"EcsRunner.{Targets[i].GetType().Name}.{nameof(Run)}"));
|
||||
_markers[i] = new EcsProfilerMarker(EcsDebug.RegisterMark($"EcsRunner.{targets[i].GetType().Name}.{nameof(Run)}"));
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@ -122,10 +122,10 @@ namespace DCFApixels.DragonECS
|
||||
public void Destroy(EcsPipeline pipeline)
|
||||
{
|
||||
#if DEBUG && !DISABLE_DEBUG
|
||||
for (int i = 0; i < Targets.Length && Targets.Length <= _markers.Length; i++)
|
||||
for (int i = 0; i < targets.Length && targets.Length <= _markers.Length; i++)
|
||||
{
|
||||
using (_markers[i].Auto())
|
||||
Targets[i].Destroy(pipeline);
|
||||
targets[i].Destroy(pipeline);
|
||||
}
|
||||
#else
|
||||
foreach (var item in targets) item.Destroy(pipeline);
|
||||
@ -135,10 +135,10 @@ namespace DCFApixels.DragonECS
|
||||
#if DEBUG && !DISABLE_DEBUG
|
||||
protected override void OnSetup()
|
||||
{
|
||||
_markers = new EcsProfilerMarker[Targets.Length];
|
||||
for (int i = 0; i < Targets.Length; i++)
|
||||
_markers = new EcsProfilerMarker[targets.Length];
|
||||
for (int i = 0; i < targets.Length; i++)
|
||||
{
|
||||
_markers[i] = new EcsProfilerMarker(EcsDebug.RegisterMark($"EcsRunner.{Targets[i].GetType().Name}.{nameof(Destroy)}"));
|
||||
_markers[i] = new EcsProfilerMarker(EcsDebug.RegisterMark($"EcsRunner.{targets[i].GetType().Name}.{nameof(Destroy)}"));
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
@ -4,6 +4,11 @@ using System.Linq;
|
||||
|
||||
namespace DCFApixels.DragonECS
|
||||
{
|
||||
//TODO развить идею инжектов
|
||||
//1) добавить расширенный метод инжекта, с 2 джинерик-аргументами, первый базовый тип и второй инжектируемый тип.
|
||||
//напримере это будет работать так Inject<object, Foo> делает инжект объекта типа Foo для систем с IEcsInject<object> или с IEcsInject<Foo>
|
||||
//2) добавить контейнер, который автоматически создается, собирает в себя все пре-инжекты и авто-инжектится во все системы.
|
||||
//но это спорная идея
|
||||
namespace Internal
|
||||
{
|
||||
internal class PreInitInjectController
|
||||
|
29
src/Builtin/Queries.cs
Normal file
29
src/Builtin/Queries.cs
Normal file
@ -0,0 +1,29 @@
|
||||
namespace DCFApixels.DragonECS
|
||||
{
|
||||
|
||||
public sealed class EmptyQuery : EcsQueryBase
|
||||
{
|
||||
private long _whereVersion;
|
||||
|
||||
public override long WhereVersion => _whereVersion;
|
||||
|
||||
public EmptyQuery(Builder b) { }
|
||||
|
||||
public sealed override WhereResult Where()
|
||||
{
|
||||
groupFilter = source.Entities.GetGroupInternal();
|
||||
return new WhereResult(this, ++_whereVersion);
|
||||
}
|
||||
|
||||
protected sealed override void OnBuild(Builder b) { }
|
||||
}
|
||||
public static partial class EcsWorldExtensions
|
||||
{
|
||||
public static WhereResult WhereAll(this EcsWorld self) => self.Select<EmptyQuery>().Where();
|
||||
}
|
||||
|
||||
public sealed class HierarchyQuery : EcsJoinAttachQuery<Parent>
|
||||
{
|
||||
public HierarchyQuery(Builder b) { }
|
||||
}
|
||||
}
|
@ -46,7 +46,7 @@ namespace DCFApixels.DragonECS
|
||||
|
||||
#region Methods
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public bool Contains(int entityID) => _source.Contains(entityID);
|
||||
public bool Contains(int entityID) => _source.Has(entityID);
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public EcsGroup.Enumerator GetEnumerator() => _source.GetEnumerator();
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
@ -152,16 +152,17 @@ namespace DCFApixels.DragonECS
|
||||
|
||||
//защита от криворукости
|
||||
//перед сборкой мусора снова создает сильную ссылку и возвращает в пул
|
||||
//TODO переделат ьиил удалить, так как сборщик мусора просыпается только после 12к и более экземпляров, только тогда и вызывается финализатор, слишком жирно
|
||||
//TODO переделат или удалить, так как сборщик мусора просыпается только после 12к и более экземпляров, только тогда и вызывается финализатор, слишком жирно
|
||||
~EcsGroup()
|
||||
{
|
||||
Release();
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Contains
|
||||
#region Has
|
||||
//TODO переименовать в Has
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public bool Contains(int entityID)
|
||||
public bool Has(int entityID)
|
||||
{
|
||||
return _sparse[entityID] > 0;
|
||||
}
|
||||
@ -179,7 +180,7 @@ namespace DCFApixels.DragonECS
|
||||
public void UncheckedAdd(int entityID) => AddInternal(entityID);
|
||||
public void Add(int entityID)
|
||||
{
|
||||
if (Contains(entityID)) return;
|
||||
if (Has(entityID)) return;
|
||||
AddInternal(entityID);
|
||||
}
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
@ -204,7 +205,7 @@ namespace DCFApixels.DragonECS
|
||||
public void UncheckedRemove(int entityID) => RemoveInternal(entityID);
|
||||
public void Remove(int entityID)
|
||||
{
|
||||
if (!Contains(entityID)) return;
|
||||
if (!Has(entityID)) return;
|
||||
RemoveInternal(entityID);
|
||||
}
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
@ -234,6 +235,15 @@ namespace DCFApixels.DragonECS
|
||||
}
|
||||
_delayedOps[_delayedOpsCount++] = entityID | isAddBitFlag; // delayedOp = entityID add isAddBitFlag
|
||||
}
|
||||
|
||||
public void RemoveUnusedEntityIDs()
|
||||
{
|
||||
foreach (var e in this)
|
||||
{
|
||||
if (!_source.IsUsed(e))
|
||||
AggressiveRemove(e);
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Sort/Clear
|
||||
@ -290,7 +300,7 @@ namespace DCFApixels.DragonECS
|
||||
if (_source != group.World) throw new ArgumentException("WorldIndex != groupFilter.WorldIndex");
|
||||
#endif
|
||||
foreach (var item in group)
|
||||
if (!Contains(item))
|
||||
if (!Has(item))
|
||||
AggressiveAdd(item);
|
||||
}
|
||||
|
||||
@ -304,7 +314,7 @@ namespace DCFApixels.DragonECS
|
||||
if (_source != group.World) throw new ArgumentException("WorldIndex != groupFilter.WorldIndex");
|
||||
#endif
|
||||
foreach (var item in this)
|
||||
if (group.Contains(item))
|
||||
if (group.Has(item))
|
||||
AggressiveRemove(item);
|
||||
}
|
||||
|
||||
@ -318,7 +328,7 @@ namespace DCFApixels.DragonECS
|
||||
if (World != group.World) throw new ArgumentException("WorldIndex != groupFilter.WorldIndex");
|
||||
#endif
|
||||
foreach (var item in this)
|
||||
if (!group.Contains(item))
|
||||
if (!group.Has(item))
|
||||
AggressiveRemove(item);
|
||||
}
|
||||
|
||||
@ -332,7 +342,7 @@ namespace DCFApixels.DragonECS
|
||||
if (_source != group.World) throw new ArgumentException("WorldIndex != groupFilter.WorldIndex");
|
||||
#endif
|
||||
foreach (var item in group)
|
||||
if (Contains(item))
|
||||
if (Has(item))
|
||||
AggressiveRemove(item);
|
||||
else
|
||||
AggressiveAdd(item);
|
||||
@ -349,7 +359,7 @@ namespace DCFApixels.DragonECS
|
||||
#endif
|
||||
EcsGroup result = a._source.GetGroupFromPool();
|
||||
foreach (var item in a)
|
||||
if (!b.Contains(item))
|
||||
if (!b.Has(item))
|
||||
result.AggressiveAdd(item);
|
||||
a._source.ReleaseGroup(a);
|
||||
return result;
|
||||
@ -363,7 +373,7 @@ namespace DCFApixels.DragonECS
|
||||
#endif
|
||||
EcsGroup result = a._source.GetGroupFromPool();
|
||||
foreach (var item in a)
|
||||
if (b.Contains(item))
|
||||
if (b.Has(item))
|
||||
result.AggressiveAdd(item);
|
||||
a._source.ReleaseGroup(a);
|
||||
return result;
|
||||
@ -456,7 +466,7 @@ namespace DCFApixels.DragonECS
|
||||
if (other.Count != Count)
|
||||
return false;
|
||||
foreach (var item in other)
|
||||
if (!Contains(item))
|
||||
if (!Has(item))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
@ -1,13 +1,17 @@
|
||||
using Unity.Profiling;
|
||||
using System;
|
||||
using System.Xml.Schema;
|
||||
using Unity.Profiling;
|
||||
using UnityEditor.Search;
|
||||
using UnityEngine;
|
||||
|
||||
namespace DCFApixels.DragonECS
|
||||
{
|
||||
public abstract class EcsJoinQueryBase : EcsQueryBase
|
||||
public abstract class EcsJoinAttachQueryBase : EcsQueryBase
|
||||
{
|
||||
public abstract void ExecuteJoin();
|
||||
public abstract void Join(WhereResult targetWorldWhereQuery);
|
||||
}
|
||||
public abstract class EcsJoinAttachQuery<TAttachComponent> : EcsJoinQueryBase
|
||||
where TAttachComponent : struct, IEcsAttachComponent
|
||||
public abstract class EcsJoinAttachQuery<TAttachComponent> : EcsJoinAttachQueryBase
|
||||
where TAttachComponent : struct, IEcsAttachComponent
|
||||
{
|
||||
private EcsWorld _targetWorld;
|
||||
private EcsAttachPool<TAttachComponent> _targetPool;
|
||||
@ -19,39 +23,49 @@ namespace DCFApixels.DragonECS
|
||||
private int[] _counts;
|
||||
private EntityLinkedList _linkedBasket;
|
||||
|
||||
private bool _isJoinExecuted = false;
|
||||
private bool _isInitTargetWorld = false;
|
||||
|
||||
private bool _isInitTargetWorlds = false;
|
||||
private long _executeWhereVersion = 0;
|
||||
private long _executeJoinVersion = 0;
|
||||
|
||||
private ProfilerMarker _execute = new ProfilerMarker("Query.ExecuteJoin");
|
||||
private ProfilerMarker _executeWhere = new ProfilerMarker("JoinAttachQuery.Where");
|
||||
private ProfilerMarker _executeJoin = new ProfilerMarker("JoinAttachQuery.Join");
|
||||
|
||||
#region Properties
|
||||
public EcsWorld AttachWorld => _targetWorld;
|
||||
public EcsAttachPool<TAttachComponent> Attach => _targetPool;
|
||||
public bool IsJoinExecuted => _isJoinExecuted;
|
||||
|
||||
public sealed override long WhereVersion => _executeWhereVersion;
|
||||
public long JoinVersion => _executeJoinVersion;
|
||||
#endregion
|
||||
|
||||
protected sealed override void OnBuild(Builder b)
|
||||
{
|
||||
_targetPool = b.Include<TAttachComponent>();
|
||||
}
|
||||
public sealed override void ExecuteWhere()
|
||||
public sealed override WhereResult Where()
|
||||
{
|
||||
//ExecuteWhere(_targetPool.Entities, groupFilter);
|
||||
ExecuteWhere(World.Entities, groupFilter);
|
||||
using (_executeWhere.Auto())
|
||||
{
|
||||
_executeWhereVersion++;
|
||||
ExecuteWhere(_targetPool.Entities, groupFilter);
|
||||
return new WhereResult(this, WhereVersion);
|
||||
}
|
||||
}
|
||||
|
||||
public sealed override void ExecuteJoin()
|
||||
public sealed override void Join(WhereResult targetWorldWhereQuery)
|
||||
{
|
||||
_execute.Begin();
|
||||
|
||||
_isJoinExecuted = false;
|
||||
if (_isInitTargetWorlds == false)
|
||||
{
|
||||
InitTargetWorlds();
|
||||
if (_isInitTargetWorlds == false)
|
||||
return;
|
||||
}
|
||||
_executeJoin.Begin();
|
||||
#if (DEBUG && !DISABLE_DEBUG) || !DRAGONECS_NO_SANITIZE_CHECKS
|
||||
if (targetWorldWhereQuery.IsNull)
|
||||
throw new ArgumentNullException();//TODO составить текст исключения.
|
||||
#endif
|
||||
if (!_isInitTargetWorld)
|
||||
InitTargetWorlds(targetWorldWhereQuery.World);
|
||||
#if (DEBUG && !DISABLE_DEBUG) || !DRAGONECS_NO_SANITIZE_CHECKS
|
||||
else
|
||||
if (_targetWorld != targetWorldWhereQuery.World) throw new ArgumentException();//TODO составить текст исключения. это проверка на то что пользователь использует правильный мир
|
||||
#endif
|
||||
|
||||
//Подготовка массивов
|
||||
if (_targetWorldCapacity < _targetWorld.Capacity)
|
||||
@ -73,19 +87,137 @@ namespace DCFApixels.DragonECS
|
||||
_linkedBasket.Clear();
|
||||
//Конец подготовки массивов
|
||||
|
||||
ExecuteWhere();
|
||||
Where();
|
||||
foreach (var attachID in groupFilter)
|
||||
{
|
||||
EcsEntity attachTarget = _targetPool.Read(attachID).Target;
|
||||
if (!attachTarget.IsAlive)//TODO пофиксить IsAlive
|
||||
if (!attachTarget.IsAlive)
|
||||
{
|
||||
//_targetPool.Del(attachID);
|
||||
continue;
|
||||
}
|
||||
int attachTargetID = attachTarget.id;
|
||||
|
||||
ref int nodeIndex = ref _mapping[attachTargetID];
|
||||
if(nodeIndex <= 0)
|
||||
ref int nodeIndex = ref _mapping[attachTargetID];
|
||||
if (nodeIndex <= 0)
|
||||
nodeIndex = _linkedBasket.Add(attachID);
|
||||
else
|
||||
_linkedBasket.Insert(nodeIndex, attachID);
|
||||
_counts[attachTargetID]++;
|
||||
}
|
||||
|
||||
_executeJoinVersion++;
|
||||
_executeJoin.End();
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
public bool Has(int attachedEnttiyID) => groupFilter.Has(attachedEnttiyID);
|
||||
public EntityLinkedList.EnumerableSpan GetNodes(int entityID) => _linkedBasket.Span(_mapping[entityID], _counts[entityID]);
|
||||
public int GetNode(int entityID) => _counts[entityID] > 0 ? _linkedBasket.Get(_mapping[entityID]) : 0;
|
||||
public int GetNodesCount(int entityID) => _counts[entityID];
|
||||
public bool HasNode(int entityID, int attachedEntityID) => groupFilter.Has(attachedEntityID) && _targetPool.Read(attachedEntityID).Target.id == entityID;
|
||||
}
|
||||
/*
|
||||
public abstract class EcsJoinRelationQuery<TRelationComponent> : EcsQueryBase
|
||||
where TRelationComponent : struct, IEcsRelationComponent
|
||||
{
|
||||
private EcsWorld _firstWorld;
|
||||
private EcsWorld _secondWorld;
|
||||
private EcsRelationPool<TRelationComponent> _targetPool;
|
||||
|
||||
internal int _targetPoolCapacity = -1;
|
||||
|
||||
private bool _isInitTargetWorlds = false;
|
||||
private bool _isJoinExecuted = false;
|
||||
|
||||
private long _executeWhereVersion = 0;
|
||||
private long _executeJoinVersion = 0;
|
||||
|
||||
public readonly Orientation ToSecond = new Orientation();
|
||||
public readonly Orientation ToFirst = new Orientation();
|
||||
|
||||
private ProfilerMarker _executeWhere = new ProfilerMarker("JoinRelationQuery.Where");
|
||||
private ProfilerMarker _executeJoin = new ProfilerMarker("JoinRelationQuery.Join");
|
||||
|
||||
#region Properties
|
||||
public EcsWorld RelationFirstWorld => _firstWorld;
|
||||
public EcsWorld RelationSecondWorld => _secondWorld;
|
||||
public EcsRelationPool<TRelationComponent> Relation => _targetPool;
|
||||
public bool IsMonoWorldRelation => _firstWorld == _secondWorld;
|
||||
|
||||
public sealed override long WhereVersion => _executeWhereVersion;
|
||||
public long JoinVersion => _executeJoinVersion;
|
||||
#endregion
|
||||
|
||||
protected sealed override void OnBuild(Builder b)
|
||||
{
|
||||
_targetPool = b.Include<TRelationComponent>();
|
||||
}
|
||||
public sealed override WhereResult Where()
|
||||
{
|
||||
using (_executeWhere.Auto())
|
||||
{
|
||||
_executeWhereVersion++;
|
||||
ExecuteWhere(_targetPool.Entities, groupFilter);
|
||||
return new WhereResult(this, WhereVersion);
|
||||
}
|
||||
}
|
||||
|
||||
public void Join(WhereResult firstWorldWhereQuery, WhereResult secondWorldWhereQuery)
|
||||
{
|
||||
_executeJoin.Begin();
|
||||
_isJoinExecuted = false;
|
||||
if (_isInitTargetWorlds == false)
|
||||
{
|
||||
InitTargetWorlds();
|
||||
if (_isInitTargetWorlds == false)
|
||||
return;
|
||||
};
|
||||
|
||||
// //Подготовка массивов
|
||||
// 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();
|
||||
// //Конец подготовки массивов
|
||||
|
||||
Where();
|
||||
foreach (var attachID in groupFilter)
|
||||
{
|
||||
EcsEntity attachTarget = _targetPool.Read(attachID).First;
|
||||
if (!attachTarget.IsAlive)
|
||||
{
|
||||
//_targetPool.Del(attachID);
|
||||
continue;
|
||||
}
|
||||
int attachTargetID = attachTarget.id;
|
||||
|
||||
ref int nodeIndex = ref _mapping[attachTargetID];
|
||||
if (nodeIndex <= 0)
|
||||
nodeIndex = _linkedBasket.Add(attachID);
|
||||
else
|
||||
_linkedBasket.Insert(nodeIndex, attachID);
|
||||
@ -93,66 +225,12 @@ namespace DCFApixels.DragonECS
|
||||
}
|
||||
|
||||
_isJoinExecuted = true;
|
||||
_execute.End();
|
||||
}
|
||||
private void InitTargetWorlds()
|
||||
{
|
||||
foreach (var e in _targetPool.Entities)
|
||||
{
|
||||
ref readonly var rel = ref _targetPool.Read(e);
|
||||
//if (rel.Target.IsNotNull)
|
||||
_targetWorld = EcsWorld.Worlds[rel.Target.world];
|
||||
_executeJoinVersion++;
|
||||
_executeJoin.End();
|
||||
|
||||
if (_targetWorld != null)
|
||||
{
|
||||
_isInitTargetWorlds = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (_isInitTargetWorlds)
|
||||
{
|
||||
_targetWorldCapacity = _targetWorld.Capacity;
|
||||
_mapping = new int[_targetWorldCapacity];
|
||||
_counts = new int[_targetWorldCapacity];
|
||||
|
||||
_targetPoolCapacity = _targetPool.Capacity;
|
||||
//_entites = new int[_targetPoolCapacity];
|
||||
_linkedBasket = new EntityLinkedList(_targetPoolCapacity);
|
||||
}
|
||||
}
|
||||
public EcsGroup.Enumerator GetEnumerator()
|
||||
{
|
||||
return groupFilter.GetEnumerator();
|
||||
}
|
||||
public EntityLinkedList.EnumerableSpan GetNodes(int entityID) => _linkedBasket.Span(_mapping[entityID], _counts[entityID]);
|
||||
}
|
||||
public abstract class EcsJoinRelationQuery<TRelationComponent> : EcsJoinQueryBase
|
||||
where TRelationComponent : struct, IEcsRelationComponent
|
||||
{
|
||||
private EcsWorld _firstWorld;
|
||||
private EcsWorld _secondWorld;
|
||||
private EcsRelationPool<TRelationComponent> _targetPool;
|
||||
private bool _isInitTargetWorlds = false;
|
||||
|
||||
#region Properties
|
||||
public EcsWorld RelationFirstWorld => _firstWorld;
|
||||
public EcsWorld RelationSecondWorld => _secondWorld;
|
||||
public EcsRelationPool<TRelationComponent> Relation => _targetPool;
|
||||
public bool IsMonoWorldRelation => _firstWorld == _secondWorld;
|
||||
#endregion
|
||||
|
||||
protected sealed override void OnBuild(Builder b)
|
||||
{
|
||||
_targetPool = b.Include<TRelationComponent>();
|
||||
}
|
||||
public sealed override void ExecuteWhere()
|
||||
{
|
||||
ExecuteWhere(_targetPool.Entites, groupFilter);
|
||||
}
|
||||
public sealed override void ExecuteJoin()
|
||||
{
|
||||
if (_isInitTargetWorlds == false) InitTargetWorlds();
|
||||
_executeJoinVersion++;
|
||||
_isJoinExecuted = true;
|
||||
_executeJoin.End();
|
||||
}
|
||||
|
||||
private void InitTargetWorlds()
|
||||
@ -170,10 +248,78 @@ namespace DCFApixels.DragonECS
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (_isInitTargetWorlds)
|
||||
{
|
||||
_targetWorldCapacity = _targetWorld.Capacity;
|
||||
_mapping = new int[_targetWorldCapacity];
|
||||
_counts = new int[_targetWorldCapacity];
|
||||
|
||||
_targetPoolCapacity = _targetPool.Capacity;
|
||||
_linkedBasket = new EntityLinkedList(_targetPoolCapacity);
|
||||
}
|
||||
}
|
||||
public EcsGroup.Enumerator GetEnumerator()
|
||||
|
||||
|
||||
public bool Has(int relationEntityID) => groupFilter.Has(relationEntityID);
|
||||
|
||||
|
||||
public class Orientation
|
||||
{
|
||||
return groupFilter.GetEnumerator();
|
||||
internal int targetWorldCapacity = -1;
|
||||
|
||||
internal int[] mapping;
|
||||
internal int[] counts;
|
||||
internal EntityLinkedList linkedBasket;
|
||||
|
||||
public bool HasRelation(int fromEntityID, int toEntityID)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
public bool HasNode(int fromEntityID, int toEntityID)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
public EntityLinkedList.EnumerableSpan GetRelations(int fromEntityID) => linkedBasket.Span(mapping[fromEntityID], counts[fromEntityID]);
|
||||
public int GetRelation(int fromEntityID) => counts[fromEntityID] > 0 ? linkedBasket.Get(mapping[fromEntityID]) : 0;
|
||||
public int GetRelationsCount(int fromEntityID) => counts[fromEntityID];
|
||||
}
|
||||
}*/
|
||||
|
||||
#region Extensions
|
||||
public static class EcsJoinQueryBaseExtensions
|
||||
{
|
||||
public static void Join(this EcsJoinAttachQueryBase self, EcsWorld targetWorld)
|
||||
{
|
||||
self.Join(targetWorld.Where<EmptyQuery>());
|
||||
}
|
||||
|
||||
public static TQuery Join<TQuery>(this EcsWorld self, EcsWorld targetWorld, out TQuery query) where TQuery : EcsJoinAttachQueryBase
|
||||
{
|
||||
return self.Join(targetWorld.WhereAll(), out query);
|
||||
}
|
||||
public static TQuery Join<TQuery>(this EcsWorld self, EcsWorld targetWorld) where TQuery : EcsJoinAttachQueryBase
|
||||
{
|
||||
return self.Join<TQuery>(targetWorld.WhereAll());
|
||||
}
|
||||
/* public static class EcsJoinRelationQueryExtensions
|
||||
{
|
||||
public static void Join<TRelationComponent>(this EcsJoinRelationQuery<TRelationComponent> self, EcsWorld firstWorld, EcsWorld secondWorld)
|
||||
where TRelationComponent : struct, IEcsRelationComponent
|
||||
{
|
||||
self.Join(firstWorld.Where<EmptyQuery>(), secondWorld.Where<EmptyQuery>());
|
||||
}
|
||||
public static void Join<TRelationComponent>(this EcsJoinRelationQuery<TRelationComponent> self, EcsWorld firstWorld, WhereResult secondWorldWhereQuery)
|
||||
where TRelationComponent : struct, IEcsRelationComponent
|
||||
{
|
||||
self.Join(firstWorld.Where<EmptyQuery>(), secondWorldWhereQuery);
|
||||
}
|
||||
public static void Join<TRelationComponent>(this EcsJoinRelationQuery<TRelationComponent> self, WhereResult firstWorldWhereQuery, EcsWorld secondWorld)
|
||||
where TRelationComponent : struct, IEcsRelationComponent
|
||||
{
|
||||
self.Join(firstWorldWhereQuery, secondWorld.Where<EmptyQuery>());
|
||||
}
|
||||
}*/
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
|
@ -1,6 +1,9 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using System.Reflection;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
using Unity.Profiling;
|
||||
|
||||
namespace DCFApixels.DragonECS
|
||||
@ -11,15 +14,19 @@ namespace DCFApixels.DragonECS
|
||||
internal EcsGroup groupFilter;
|
||||
internal EcsQueryMask mask;
|
||||
|
||||
private bool _isInit;
|
||||
|
||||
#region Properties
|
||||
internal EcsQueryMask Mask => mask;
|
||||
public EcsQueryMask Mask => mask;
|
||||
public EcsWorld World => source;
|
||||
public bool IsInit => _isInit;
|
||||
|
||||
public abstract long WhereVersion { get; }
|
||||
#endregion
|
||||
|
||||
#region Builder
|
||||
protected virtual void Init(Builder b) { }
|
||||
protected abstract void OnBuild(Builder b);
|
||||
public abstract void ExecuteWhere();
|
||||
public sealed class Builder : EcsQueryBuilderBase
|
||||
{
|
||||
private EcsWorld _world;
|
||||
@ -53,6 +60,7 @@ namespace DCFApixels.DragonECS
|
||||
newQuery.source = world;
|
||||
newQuery.OnBuild(builder);
|
||||
builder.End(out newQuery.mask);
|
||||
newQuery._isInit = true;
|
||||
return (TQuery)(object)newQuery;
|
||||
}
|
||||
|
||||
@ -82,10 +90,11 @@ namespace DCFApixels.DragonECS
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
public abstract WhereResult Where();
|
||||
|
||||
protected void ExecuteWhere(EcsReadonlyGroup group, EcsGroup result)
|
||||
{
|
||||
var pools = World.Pools;
|
||||
var pools = World.pools;
|
||||
result.Clear();
|
||||
foreach (var e in group)
|
||||
{
|
||||
@ -103,6 +112,7 @@ namespace DCFApixels.DragonECS
|
||||
next: continue;
|
||||
}
|
||||
}
|
||||
//protected void IsMaskCompatible
|
||||
protected void ExecuteWhereAndSort(EcsReadonlyGroup group, EcsGroup result)
|
||||
{
|
||||
ExecuteWhere(group, result);
|
||||
@ -110,20 +120,38 @@ namespace DCFApixels.DragonECS
|
||||
}
|
||||
}
|
||||
|
||||
//TODO есть идея проверки того что запросбылвыполнен путем создания ref struct которыйсодержит результат выполнения заапроса и существует только в стеке.
|
||||
//таким образом для каждой системы он будет выполняться единожды, без холостых перезапусков, скорее всего эта система будет работать лучше чем "Версии запросов"
|
||||
public abstract class EcsQuery : EcsQueryBase
|
||||
{
|
||||
private ProfilerMarker _execute = new ProfilerMarker("EcsQuery.ExecuteWhere");
|
||||
private ProfilerMarker _execute = new ProfilerMarker("EcsQuery.Where");
|
||||
|
||||
private long _executeWhereVersion = 0;
|
||||
|
||||
#region Properties
|
||||
//на данный момент бесполное свойство, основная идея, реализовать все методы запроса с аргументом (..., ref long version),
|
||||
//далее в теле метододов сравнивать с текущей версией, и если они отличаются, выполнять запрос и перезаписывать значение version
|
||||
//таким образом можно добиться сокращение "холостых" выполнений запроса, тоесть в рамках одной системы запрос всегда будет выполняться один раз
|
||||
//даже при повторном вызове.
|
||||
//Но нужно добавить метод для принудительного повторения запроса без сравнения вресий.
|
||||
//TODO реализовать описанное выше поведение
|
||||
//TODO проверить что лучше подходит int или long. long делает этот механизм очень надежным, но возможно его использование будет существенно влиять на производительность.
|
||||
public sealed override long WhereVersion => _executeWhereVersion;
|
||||
#endregion
|
||||
|
||||
protected sealed override void OnBuild(Builder b) { }
|
||||
public sealed override void ExecuteWhere()
|
||||
public sealed override WhereResult Where()
|
||||
{
|
||||
using (_execute.Auto())
|
||||
{
|
||||
ExecuteWhereAndSort(World.Entities, groupFilter);
|
||||
return new WhereResult(this, ++_executeWhereVersion);
|
||||
}
|
||||
}
|
||||
public EcsGroup.Enumerator GetEnumerator()
|
||||
|
||||
public bool Has(int entityID)
|
||||
{
|
||||
return groupFilter.GetEnumerator();
|
||||
return groupFilter.Has(entityID);
|
||||
}
|
||||
}
|
||||
|
||||
@ -142,4 +170,26 @@ namespace DCFApixels.DragonECS
|
||||
public abstract TPool Exclude<TComponent, TPool>() where TComponent : struct where TPool : EcsPoolBase<TComponent>, new();
|
||||
public abstract TPool Optional<TComponent, TPool>() where TComponent : struct where TPool : EcsPoolBase<TComponent>, new();
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 8, Size = 16)]
|
||||
public readonly ref struct WhereResult
|
||||
{
|
||||
public readonly EcsQueryBase query; //ref = 8 byte
|
||||
public readonly long version; //long = 8 byte
|
||||
|
||||
#region Properties
|
||||
public bool IsNull => query == null;
|
||||
public EcsWorld World => query.World;
|
||||
public bool IsActual => query.WhereVersion == version;
|
||||
#endregion
|
||||
|
||||
public WhereResult(EcsQueryBase query, long version)
|
||||
{
|
||||
this.query = query;
|
||||
this.version = version;
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public EcsGroup.Enumerator GetEnumerator() => query.groupFilter.GetEnumerator();
|
||||
}
|
||||
}
|
||||
|
101
src/EcsWorld.cs
101
src/EcsWorld.cs
@ -9,12 +9,12 @@ namespace DCFApixels.DragonECS
|
||||
{
|
||||
private const short GEN_BITS = 0x7fff;
|
||||
private const short DEATH_GEN_BIT = short.MinValue;
|
||||
private const int DEL_ENT_BUFFER_SIZE_OFFSET = 2;
|
||||
|
||||
public static EcsWorld[] Worlds = new EcsWorld[8];
|
||||
private static IntDispenser _worldIdDispenser = new IntDispenser(0);
|
||||
public readonly short uniqueID;
|
||||
|
||||
private const int DEL_ENT_BUFFER_SIZE_OFFSET = 2;
|
||||
private int _worldArchetypeID;
|
||||
|
||||
private IntDispenser _entityDispenser;
|
||||
@ -30,7 +30,7 @@ namespace DCFApixels.DragonECS
|
||||
private int[] _delEntBuffer;
|
||||
private int _delEntBufferCount;
|
||||
|
||||
private EcsPoolBase[] _pools;
|
||||
internal EcsPoolBase[] pools;
|
||||
private EcsNullPool _nullPool;
|
||||
|
||||
private EcsQueryBase[] _queries;
|
||||
@ -43,12 +43,6 @@ namespace DCFApixels.DragonECS
|
||||
private IEcsEntityCreate _entityCreate;
|
||||
private IEcsEntityDestroy _entityDestry;
|
||||
|
||||
#region GetterMethods
|
||||
public ReadOnlySpan<EcsPoolBase> GetAllPools() => new ReadOnlySpan<EcsPoolBase>(_pools);
|
||||
public int GetComponentID<T>() => WorldMetaStorage.GetComponentId<T>(_worldArchetypeID);////ComponentType<TWorldArchetype>.uniqueID;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Properties
|
||||
public abstract Type Archetype { get; }
|
||||
public int UniqueID => uniqueID;
|
||||
@ -56,14 +50,7 @@ namespace DCFApixels.DragonECS
|
||||
public int Capacity => _entitesCapacity; //_denseEntities.Length;
|
||||
public EcsPipeline Pipeline => _pipeline;
|
||||
public EcsReadonlyGroup Entities => _allEntites.Readonly;
|
||||
#endregion
|
||||
|
||||
#region Internal Properties
|
||||
internal EcsPoolBase[] Pools
|
||||
{
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
get => _pools;
|
||||
}
|
||||
public ReadOnlySpan<EcsPoolBase> AllPools => pools;
|
||||
#endregion
|
||||
|
||||
#region Constructors/Destroy
|
||||
@ -82,8 +69,8 @@ namespace DCFApixels.DragonECS
|
||||
if (!_pipeline.IsInit) pipline.Init();
|
||||
_entityDispenser = new IntDispenser(0);
|
||||
_nullPool = EcsNullPool.instance;
|
||||
_pools = new EcsPoolBase[512];
|
||||
ArrayUtility.Fill(_pools, _nullPool);
|
||||
pools = new EcsPoolBase[512];
|
||||
ArrayUtility.Fill(pools, _nullPool);
|
||||
|
||||
_gens = new short[_entitesCapacity];
|
||||
ArrayUtility.Fill(_gens, DEATH_GEN_BIT);
|
||||
@ -105,7 +92,7 @@ namespace DCFApixels.DragonECS
|
||||
_entityDispenser = null;
|
||||
//_denseEntities = null;
|
||||
_gens = null;
|
||||
_pools = null;
|
||||
pools = null;
|
||||
_nullPool = null;
|
||||
_queries = null;
|
||||
|
||||
@ -119,38 +106,37 @@ namespace DCFApixels.DragonECS
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region GetComponentID
|
||||
public int GetComponentID<T>() => WorldMetaStorage.GetComponentId<T>(_worldArchetypeID);////ComponentType<TWorldArchetype>.uniqueID;
|
||||
|
||||
#endregion
|
||||
|
||||
#region GetPool
|
||||
public TPool GetPool<TComponent, TPool>() where TComponent : struct where TPool : EcsPoolBase<TComponent>, new()
|
||||
{
|
||||
int uniqueID = WorldMetaStorage.GetComponentId<TComponent>(_worldArchetypeID);
|
||||
|
||||
if (uniqueID >= _pools.Length)
|
||||
if (uniqueID >= pools.Length)
|
||||
{
|
||||
int oldCapacity = _pools.Length;
|
||||
Array.Resize(ref _pools, _pools.Length << 1);
|
||||
ArrayUtility.Fill(_pools, _nullPool, oldCapacity, oldCapacity - _pools.Length);
|
||||
int oldCapacity = pools.Length;
|
||||
Array.Resize(ref pools, pools.Length << 1);
|
||||
ArrayUtility.Fill(pools, _nullPool, oldCapacity, oldCapacity - pools.Length);
|
||||
}
|
||||
|
||||
if (_pools[uniqueID] == _nullPool)
|
||||
if (pools[uniqueID] == _nullPool)
|
||||
{
|
||||
var pool = new TPool();
|
||||
_pools[uniqueID] = pool;
|
||||
pools[uniqueID] = pool;
|
||||
pool.InvokeInit(this);
|
||||
|
||||
//EcsDebug.Print(pool.GetType().FullName);
|
||||
}
|
||||
|
||||
return (TPool)_pools[uniqueID];
|
||||
return (TPool)pools[uniqueID];
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Queries
|
||||
public TQuery Where<TQuery>(out TQuery query) where TQuery : EcsQuery
|
||||
{
|
||||
query = Select<TQuery>();
|
||||
query.ExecuteWhere();
|
||||
return query;
|
||||
}
|
||||
public TQuery Select<TQuery>() where TQuery : EcsQueryBase
|
||||
{
|
||||
int uniqueID = WorldMetaStorage.GetQueryId<TQuery>(_worldArchetypeID);
|
||||
@ -160,6 +146,28 @@ namespace DCFApixels.DragonECS
|
||||
_queries[uniqueID] = EcsQueryBase.Builder.Build<TQuery>(this);
|
||||
return (TQuery)_queries[uniqueID];
|
||||
}
|
||||
public WhereResult Where<TQuery>(out TQuery query) where TQuery : EcsQueryBase
|
||||
{
|
||||
query = Select<TQuery>();
|
||||
return query.Where();
|
||||
}
|
||||
public WhereResult Where<TQuery>() where TQuery : EcsQueryBase
|
||||
{
|
||||
return Select<TQuery>().Where();
|
||||
}
|
||||
|
||||
public TQuery Join<TQuery>(WhereResult targetWorldWhereQuery, out TQuery query) where TQuery : EcsJoinAttachQueryBase
|
||||
{
|
||||
query = Select<TQuery>();
|
||||
query.Join(targetWorldWhereQuery);
|
||||
return query;
|
||||
}
|
||||
public TQuery Join<TQuery>(WhereResult targetWorldWhereQuery) where TQuery : EcsJoinAttachQueryBase
|
||||
{
|
||||
TQuery query = Select<TQuery>();
|
||||
query.Join(targetWorldWhereQuery);
|
||||
return query;
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region IsMaskCompatible
|
||||
@ -171,12 +179,12 @@ namespace DCFApixels.DragonECS
|
||||
#endif
|
||||
for (int i = 0, iMax = mask.Inc.Length; i < iMax; i++)
|
||||
{
|
||||
if (!_pools[mask.Inc[i]].Has(entityID))
|
||||
if (!pools[mask.Inc[i]].Has(entityID))
|
||||
return false;
|
||||
}
|
||||
for (int i = 0, iMax = mask.Exc.Length; i < iMax; i++)
|
||||
{
|
||||
if (_pools[mask.Exc[i]].Has(entityID))
|
||||
if (pools[mask.Exc[i]].Has(entityID))
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
@ -208,12 +216,11 @@ namespace DCFApixels.DragonECS
|
||||
_groups.RemoveAt(last);
|
||||
}
|
||||
}
|
||||
foreach (var item in _pools)
|
||||
foreach (var item in pools)
|
||||
item.InvokeOnWorldResize(_gens.Length);
|
||||
}
|
||||
_gens[entityID] &= GEN_BITS;
|
||||
EcsEntity entity = new EcsEntity(entityID, ++_gens[entityID], uniqueID);
|
||||
// UnityEngine.Debug.Log($"{entityID} {_gens[entityID]} {uniqueID}");
|
||||
_entityCreate.OnEntityCreate(entity);
|
||||
_allEntites.Add(entityID);
|
||||
return entity;
|
||||
@ -227,26 +234,20 @@ namespace DCFApixels.DragonECS
|
||||
_entityDestry.OnEntityDestroy(entity);
|
||||
|
||||
if (_delEntBufferCount >= _delEntBuffer.Length)
|
||||
ReleaseDelEntBuffer();
|
||||
ReleaseDelEntityBuffer();
|
||||
}
|
||||
|
||||
private void ReleaseDelEntBuffer()//TODO проверить что буфер удаления работает нормально
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public EcsEntity GetEcsEntity(int entityID) => new EcsEntity(entityID, _gens[entityID], uniqueID); //TODO придумать получше имя метода
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public bool IsAlive(int entityID, short gen) => _gens[entityID] == gen;
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public bool IsUsed(int entityID) => (_gens[entityID] | DEATH_GEN_BIT) == 0;
|
||||
public void ReleaseDelEntityBuffer()
|
||||
{
|
||||
for (int i = 0; i < _delEntBufferCount; i++)
|
||||
_entityDispenser.Release(_delEntBuffer[i]);
|
||||
_delEntBufferCount = 0;
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public EcsEntity GetEcsEntity(int entityID)
|
||||
{
|
||||
return new EcsEntity(entityID, _gens[entityID], uniqueID);
|
||||
}
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public bool EntityIsAlive(int entityID, short gen) //TODO пофиксить EntityIsAlive
|
||||
{
|
||||
return _gens[entityID] == gen;
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Groups
|
||||
|
@ -8,7 +8,7 @@ namespace DCFApixels.DragonECS
|
||||
// gen - 16 bits
|
||||
// world - 16 bits
|
||||
/// <summary>Strong identifier/Permanent entity identifier</summary>
|
||||
[StructLayout(LayoutKind.Explicit, Pack =2, Size = 8)]
|
||||
[StructLayout(LayoutKind.Explicit, Pack = 2, Size = 8)]
|
||||
public readonly partial struct EcsEntity : IEquatable<long>, IEquatable<EcsEntity>
|
||||
{
|
||||
public static readonly EcsEntity NULL = default;
|
||||
@ -22,9 +22,9 @@ namespace DCFApixels.DragonECS
|
||||
public readonly short world;
|
||||
|
||||
//[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
//public ent ToEnt() => EcsWorld.Worlds[world].EntityIsAlive(id, gen) ? new ent(id) : default;
|
||||
//public ent ToEnt() => EcsWorld.Worlds[world].IsAlive(id, gen) ? new ent(id) : default;
|
||||
|
||||
public bool IsAlive => EcsWorld.Worlds[world].EntityIsAlive(id, gen);
|
||||
public bool IsAlive => EcsWorld.Worlds[world].IsAlive(id, gen);
|
||||
|
||||
#region Constructors
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
@ -104,7 +104,7 @@ namespace DCFApixels.DragonECS
|
||||
// {
|
||||
// //using (_IsAliveMarker.Auto())
|
||||
// //{
|
||||
// bool result = EcsWorld.Worlds[self.world].EntityIsAlive(self.id, self.gen);
|
||||
// bool result = EcsWorld.Worlds[self.world].IsAlive(self.id, self.gen);
|
||||
// if (!result) self = EcsEntity.NULL;
|
||||
// return result;
|
||||
// //}
|
||||
|
@ -15,7 +15,14 @@ namespace DCFApixels.DragonECS
|
||||
private PoolRunners _poolRunners;
|
||||
|
||||
private EcsGroup _entities;
|
||||
public EcsReadonlyGroup Entities => _entities.Readonly;
|
||||
public EcsReadonlyGroup Entities
|
||||
{
|
||||
get
|
||||
{
|
||||
_entities.RemoveUnusedEntityIDs();
|
||||
return _entities.Readonly;
|
||||
}
|
||||
}
|
||||
|
||||
#if (DEBUG && !DISABLE_DEBUG) || !DRAGONECS_NO_SANITIZE_CHECKS
|
||||
private short _sanitizeTargetWorld = -1;
|
||||
|
143
src/Pools/EcsReadonlyPool.cs
Normal file
143
src/Pools/EcsReadonlyPool.cs
Normal file
@ -0,0 +1,143 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Runtime.CompilerServices;
|
||||
using Unity.Profiling;
|
||||
|
||||
namespace DCFApixels.DragonECS
|
||||
{
|
||||
public sealed class EcsReadonlyPool<T> : EcsPoolBase<T>
|
||||
where T : struct, IEcsReadonlyComponent
|
||||
{
|
||||
public static string name = typeof(T).Name;
|
||||
|
||||
private EcsWorld _source;
|
||||
|
||||
private int[] _mapping;// index = entityID / value = itemIndex;/ value = 0 = no entityID
|
||||
private T[] _items; //dense
|
||||
private int _itemsCount;
|
||||
private int[] _recycledItems;
|
||||
private int _recycledItemsCount;
|
||||
|
||||
private IEcsComponentReset<T> _componentResetHandler;
|
||||
private PoolRunners _poolRunners;
|
||||
|
||||
#region Properites
|
||||
public int Count => _itemsCount;
|
||||
public int Capacity => _items.Length;
|
||||
public sealed override EcsWorld World => _source;
|
||||
#endregion
|
||||
|
||||
#region Init
|
||||
protected override void Init(EcsWorld world)
|
||||
{
|
||||
const int capacity = 512;
|
||||
_source = world;
|
||||
|
||||
_mapping = new int[world.Capacity];
|
||||
_recycledItems = new int[128];
|
||||
_recycledItemsCount = 0;
|
||||
_items = new T[capacity];
|
||||
_itemsCount = 0;
|
||||
|
||||
_componentResetHandler = EcsComponentResetHandler<T>.instance;
|
||||
_poolRunners = new PoolRunners(world.Pipeline);
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Write/Read/Has/Del
|
||||
private ProfilerMarker _addMark = new ProfilerMarker("EcsPoo.Add");
|
||||
private ProfilerMarker _writeMark = new ProfilerMarker("EcsPoo.Write");
|
||||
private ProfilerMarker _readMark = new ProfilerMarker("EcsPoo.Read");
|
||||
private ProfilerMarker _hasMark = new ProfilerMarker("EcsPoo.Has");
|
||||
private ProfilerMarker _delMark = new ProfilerMarker("EcsPoo.Del");
|
||||
public ref T Add(int entityID)
|
||||
{
|
||||
// using (_addMark.Auto())
|
||||
// {
|
||||
ref int itemIndex = ref _mapping[entityID];
|
||||
if (itemIndex <= 0)
|
||||
{
|
||||
if (_recycledItemsCount > 0)
|
||||
{
|
||||
itemIndex = _recycledItems[--_recycledItemsCount];
|
||||
_itemsCount++;
|
||||
}
|
||||
else
|
||||
{
|
||||
itemIndex = ++_itemsCount;
|
||||
if (itemIndex >= _items.Length)
|
||||
Array.Resize(ref _items, _items.Length << 1);
|
||||
}
|
||||
|
||||
//_mapping[entityID] = itemIndex; TODO проверить что это лишнее дейсвие
|
||||
_poolRunners.add.OnComponentAdd<T>(entityID);
|
||||
}
|
||||
else
|
||||
{
|
||||
_componentResetHandler.Reset(ref _items[itemIndex]);
|
||||
}
|
||||
_poolRunners.write.OnComponentWrite<T>(entityID);
|
||||
return ref _items[itemIndex];
|
||||
// }
|
||||
}
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public ref readonly T Read(int entityID)
|
||||
{
|
||||
// using (_readMark.Auto())
|
||||
return ref _items[_mapping[entityID]];
|
||||
}
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public sealed override bool Has(int entityID)
|
||||
{
|
||||
// using (_hasMark.Auto())
|
||||
return _mapping[entityID] > 0;
|
||||
}
|
||||
public void Del(int entityID)
|
||||
{
|
||||
// using (_delMark.Auto())
|
||||
// {
|
||||
ref int itemIndex = ref _mapping[entityID];
|
||||
_componentResetHandler.Reset(ref _items[itemIndex]);
|
||||
if (_recycledItemsCount >= _recycledItems.Length)
|
||||
Array.Resize(ref _recycledItems, _recycledItems.Length << 1);
|
||||
_recycledItems[_recycledItemsCount++] = itemIndex;
|
||||
itemIndex = 0;
|
||||
_itemsCount--;
|
||||
_poolRunners.del.OnComponentDel<T>(entityID);
|
||||
// }
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region WorldCallbacks
|
||||
protected override void OnWorldResize(int newSize)
|
||||
{
|
||||
Array.Resize(ref _mapping, newSize);
|
||||
}
|
||||
protected override void OnDestroy() { }
|
||||
|
||||
#endregion
|
||||
}
|
||||
|
||||
public interface IEcsReadonlyComponent { }
|
||||
public static class EcsReadonlyPoolExt
|
||||
{
|
||||
public static EcsReadonlyPool<TReadolnyComponent> GetPool<TReadolnyComponent>(this EcsWorld self) where TReadolnyComponent : struct, IEcsReadonlyComponent
|
||||
{
|
||||
return self.GetPool<TReadolnyComponent, EcsReadonlyPool<TReadolnyComponent>>();
|
||||
}
|
||||
|
||||
public static EcsReadonlyPool<TReadolnyComponent> Include<TReadolnyComponent>(this EcsQueryBuilderBase self) where TReadolnyComponent : struct, IEcsReadonlyComponent
|
||||
{
|
||||
return self.Include<TReadolnyComponent, EcsReadonlyPool<TReadolnyComponent>>();
|
||||
}
|
||||
public static EcsReadonlyPool<TReadolnyComponent> Exclude<TReadolnyComponent>(this EcsQueryBuilderBase self) where TReadolnyComponent : struct, IEcsReadonlyComponent
|
||||
{
|
||||
return self.Exclude<TReadolnyComponent, EcsReadonlyPool<TReadolnyComponent>>();
|
||||
}
|
||||
public static EcsReadonlyPool<TReadolnyComponent> Optional<TReadolnyComponent>(this EcsQueryBuilderBase self) where TReadolnyComponent : struct, IEcsReadonlyComponent
|
||||
{
|
||||
return self.Optional<TReadolnyComponent, EcsReadonlyPool<TReadolnyComponent>>();
|
||||
}
|
||||
}
|
||||
}
|
@ -15,7 +15,7 @@ namespace DCFApixels.DragonECS
|
||||
private PoolRunners _poolRunners;
|
||||
|
||||
private EcsGroup _entities;
|
||||
public EcsReadonlyGroup Entites => _entities.Readonly;
|
||||
public EcsReadonlyGroup Entities => _entities.Readonly;
|
||||
|
||||
#if (DEBUG && !DISABLE_DEBUG) || !DRAGONECS_NO_SANITIZE_CHECKS
|
||||
private short _sanitizeFirstWorld = -1;
|
||||
|
@ -21,6 +21,11 @@ namespace DCFApixels.DragonECS
|
||||
private PoolRunners _poolRunners;
|
||||
|
||||
#region Properites
|
||||
public ref T Instance
|
||||
{
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
get => ref _component;
|
||||
}
|
||||
public int Count => _count;
|
||||
public sealed override EcsWorld World => _source;
|
||||
#endregion
|
||||
@ -53,6 +58,7 @@ namespace DCFApixels.DragonECS
|
||||
return ref _component;
|
||||
// }
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public ref T Write(int entityID)
|
||||
{
|
||||
@ -91,7 +97,7 @@ namespace DCFApixels.DragonECS
|
||||
protected override void OnDestroy() { }
|
||||
#endregion
|
||||
}
|
||||
|
||||
/// <summary> Singleton component </summary>
|
||||
public interface IEcsSingleComponent { }
|
||||
public static class EcsSinglePoolExt
|
||||
{
|
||||
|
@ -39,10 +39,8 @@ namespace DCFApixels.DragonECS
|
||||
_count = 0;
|
||||
}
|
||||
|
||||
public void Set(int nodeIndex, int entityID)
|
||||
{
|
||||
_nodes[nodeIndex].entityID = entityID;
|
||||
}
|
||||
public void Set(int nodeIndex, int entityID) => _nodes[nodeIndex].entityID = entityID;
|
||||
public int Get(int nodeIndex) => _nodes[nodeIndex].entityID;
|
||||
|
||||
/// <summary> Insert after</summary>
|
||||
/// <returns> new node index</returns>
|
||||
|
Loading…
Reference in New Issue
Block a user