Rework filters & pooling / optimization

This commit is contained in:
Mikhail 2023-04-07 05:08:48 +08:00
parent 467f2e07c7
commit 05aa578b96
7 changed files with 333 additions and 387 deletions

108
src/EcsEntityArchetype.cs Normal file
View File

@ -0,0 +1,108 @@
using DCFApixels.DragonECS;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Threading.Tasks;
namespace DCFApixels.DragonECS
{
public abstract class EcsEntityArchetypeBuilder
{
public abstract inc<TComponent> Include<TComponent>() where TComponent : struct;
public abstract exc<TComponent> Exclude<TComponent>() where TComponent : struct;
public abstract opt<TComponent> Optional<TComponent>() where TComponent : struct;
}
public interface IEcsEntityArchetype
{
internal void AddEntity(int entityID);
internal void RemoveEntity(int entityID);
}
public class EcsEntityArchetype<TWorldArchetype> : IEcsEntityArchetype
where TWorldArchetype : EcsWorld<TWorldArchetype>
{
private int _id;
internal EcsGroup group;
public int ID => _id;
public EcsReadonlyGroup entities
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get => group.Readonly;
}
public EcsEntityArchetype(Builder b)
{
}
public EcsGroup.Enumerator GetEnumerator() => group.GetEnumerator();
[MethodImpl(MethodImplOptions.AggressiveInlining)]
void IEcsEntityArchetype.AddEntity(int entityID) => group.Add(entityID);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
void IEcsEntityArchetype.RemoveEntity(int entityID) => group.Remove(entityID);
#region Builder
public sealed class Builder : EcsEntityArchetypeBuilder
{
private IEcsWorld _world;
private List<int> _inc;
private List<int> _exc;
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal Builder(IEcsWorld world)
{
_world = world;
_inc = new List<int>(8);
_exc = new List<int>(4);
}
public override inc<TComponent> Include<TComponent>() where TComponent : struct
{
_inc.Add(_world.GetComponentID<TComponent>());
return new inc<TComponent>(_world.GetPool<TComponent>());
}
public override exc<TComponent> Exclude<TComponent>() where TComponent : struct
{
_exc.Add(_world.GetComponentID<TComponent>());
return new exc<TComponent>(_world.GetPool<TComponent>());
}
public override opt<TComponent> Optional<TComponent>() where TComponent : struct
{
return new opt<TComponent>(_world.GetPool<TComponent>());
}
internal void End(out EcsEntityArhetypeMask mask)
{
_inc.Sort();
_exc.Sort();
mask = new EcsEntityArhetypeMask(_world.ArchetypeType, _inc.ToArray(), _exc.ToArray());
_world = null;
_inc.Clear();
_inc = null;
_exc.Clear();
_exc = null;
}
}
#endregion
}
public class EcsEntityArhetypeMask
{
internal readonly Type WorldArchetypeType;
internal readonly int[] Inc;
internal readonly int[] Exc;
public int IncCount => Inc.Length;
public int ExcCount => Exc.Length;
public EcsEntityArhetypeMask(Type worldArchetypeType, int[] inc, int[] exc)
{
WorldArchetypeType = worldArchetypeType;
Inc = inc;
Exc = exc;
}
}
}

82
src/EcsFields.cs Normal file
View File

@ -0,0 +1,82 @@
using System;
using System.Collections.Generic;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
namespace DCFApixels.DragonECS
{
public interface IEcsFiled<TComponent>
where TComponent : struct
{
public ref TComponent Write(int entityID);
public ref readonly TComponent Read(int entityID);
public bool Has(int entityID);
public void Del(int entityID);
}
[StructLayout(LayoutKind.Sequential, Pack = 8, Size = 8)]
public readonly struct inc<TComponent> : IEcsFiled<TComponent>
where TComponent : struct
{
private readonly EcsPool<TComponent> _pool;
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal inc(EcsPool<TComponent> pool) => _pool = pool;
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public ref TComponent Write(int entityID) => ref _pool.Write(entityID);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public ref readonly TComponent Read(int entityID) => ref _pool.Read(entityID);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool Has(int entityID) => _pool.Has(entityID);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void Del(int entityID) => _pool.Del(entityID);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public override string ToString() => $"{(_pool == null ? "NULL" : _pool.World.ArchetypeType.Name)}inc<{typeof(TComponent).Name}>";
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static implicit operator inc<TComponent>(EcsEntityArchetypeBuilder buider) => buider.Include<TComponent>();
}
[StructLayout(LayoutKind.Sequential, Pack = 8, Size = 8)]
public readonly struct exc<TComponent> : IEcsFiled<TComponent>
where TComponent : struct
{
private readonly EcsPool<TComponent> _pool;
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal exc(EcsPool<TComponent> pool) => _pool = pool;
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public ref TComponent Write(int entityID) => ref _pool.Write(entityID);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public ref readonly TComponent Read(int entityID) => ref _pool.Read(entityID);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool Has(int entityID) => _pool.Has(entityID);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void Del(int entityID) => _pool.Del(entityID);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public override string ToString() => $"{(_pool == null ? "NULL" : _pool.World.ArchetypeType.Name)}exc<{typeof(TComponent).Name}>";
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static implicit operator exc<TComponent>(EcsEntityArchetypeBuilder buider) => buider.Exclude<TComponent>();
}
[StructLayout(LayoutKind.Sequential, Pack = 8, Size = 8)]
public readonly struct opt<TComponent> : IEcsFiled<TComponent>
where TComponent : struct
{
private readonly EcsPool<TComponent> _pool;
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal opt(EcsPool<TComponent> pool) => _pool = pool;
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public ref TComponent Write(int entityID) => ref _pool.Write(entityID);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public ref readonly TComponent Read(int entityID) => ref _pool.Read(entityID);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool Has(int entityID) => _pool.Has(entityID);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void Del(int entityID) => _pool.Del(entityID);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public override string ToString() => $"{(_pool == null ? "NULL" : _pool.World.ArchetypeType.Name)}opt<{typeof(TComponent).Name}>";
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static implicit operator opt<TComponent>(EcsEntityArchetypeBuilder buider) => buider.Optional<TComponent>();
}
}

View File

@ -10,8 +10,8 @@ namespace DCFApixels.DragonECS
public EcsFilter Relations<TComponent>() where TComponent : struct;
rr
}
public sealed class EcsRelationTable<TArchetype> : IEcsRealationTable
where TArchetype : EcsRelationTableArchetypeBase
public sealed class EcsRelationTable<TWorldArchetype> : IEcsRealationTable
where TWorldArchetype : EcsRelationTableArchetypeBase
{
public readonly IEcsWorld leftWorld;
public readonly IEcsWorld rightWorld;
@ -26,7 +26,7 @@ namespace DCFApixels.DragonECS
private EcsNullPool _nullPool;
#region Properties
public Type ArchetypeType => typeof(TArchetype);
public Type ArchetypeType => typeof(TWorldArchetype);
public int EntitesCount => _relationsCount;
public int EntitesCapacity => _relations.Length;
#endregion

View File

@ -1,265 +0,0 @@
using DCFApixels.DragonECS;
/*using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Http.Headers;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
using UnityEngine.WSA;
using static UnityEditor.Experimental.GraphView.Port;
namespace DCFApixels.Assets.DragonECS.src
{
public struct Pose { }
public struct Health { }
public struct Mana { }
public struct EnemyTag { }
public class TestArhetype : EcsEntityArhetype<EcsDefaultWrold>
{
public inc<Pose> pose;
public inc<Health> health;
public opt<Mana> mana;
public exc<EnemyTag> enemyTag;
public TestArhetype(Builder b) : base(b)
{
pose = b.Include<Pose>();
health = b.Include<Health>();
mana = b.Optional<Mana>();
enemyTag = b.Exclude<EnemyTag>();
}
}
public class TestSystem : IEcsRunSystem
{
private TestArhetype test;
public void Run(EcsPipeline pipeline)
{
foreach (var e in test)
{
test.health.Read(e.id);
test.pose.Write(e.id) = new Pose();
}
}
}
public abstract class EcsWorldArhetype
{
public EcsWorldArhetype(IEcsWorld world) { }
}
public interface IFakeWorld { }
public class FakeWorld<TWorldArhetype> : IFakeWorld
where TWorldArhetype : EcsWorldArhetype
{
public readonly TWorldArhetype data;
private EcsEntityArhetype<TWorldArhetype>[] _arhetypes;
public FakeWorld()
{
_arhetypes = new EcsEntityArhetype<TWorldArhetype>[ArhetypeID.capacity];
}
public TArhetype Arhetype<TArhetype>() where TArhetype : EcsEntityArhetype<TWorldArhetype>
{
int id = ArhetypeID<IEcsEntityArhetype>.id;
if (_arhetypes.Length < ArhetypeID.capacity)
Array.Resize(ref _arhetypes, ArhetypeID.capacity);
if (_arhetypes[id] == null)
{
EcsEntityArhetype<TWorldArhetype>.Builder builder = new EcsEntityArhetype<TWorldArhetype>.Builder(this);
_arhetypes[id] = (TArhetype)Activator.CreateInstance(typeof(TArhetype), builder);
builder.End();
}
return (TArhetype)_arhetypes[id];
}
#region ArhetypeID
private static class ArhetypeID
{
public static int count = 0;
public static int capacity = 128;
}
private static class ArhetypeID<TArhetype>
{
public static int id;
static ArhetypeID()
{
id = ArhetypeID.count++;
if (ArhetypeID.count > ArhetypeID.capacity)
ArhetypeID.capacity <<= 1;
}
}
#endregion
}
public interface IEcsEntityArhetype
{
internal void AddEntity(int entityID);
internal void RemoveEntity(int entityID);
}
public class EcsEntityArhetype<TWorldArhetype> : IEcsEntityArhetype
where TWorldArhetype : EcsWorldArhetype
{
private int _id;
private EcsGroup _group;
public int ID => _id;
public EcsReadonlyGroup entities
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get => _group.Readonly;
}
public EcsEntityArhetype(Builder b) { }
public EcsGroup.Enumerator GetEnumerator() => _group.GetEnumerator();
[MethodImpl(MethodImplOptions.AggressiveInlining)]
void IEcsEntityArhetype.AddEntity(int entityID) => _group.Add(entityID);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
void IEcsEntityArhetype.RemoveEntity(int entityID) => _group.Remove(entityID);
#region Builder
public class Builder
{
private IFakeWorld _world;
private List<int> _inc;
private List<int> _exc;
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal Builder(IFakeWorld world)
{
_world = world;
}
public inc<TComponent> Include<TComponent>() where TComponent : struct
{
_inc.Add(_world.GetComponentID<TComponent>());
return new inc<TComponent>(_world.GetPool<TComponent>());
}
public exc<TComponent> Exclude<TComponent>() where TComponent : struct
{
_exc.Add(_world.GetComponentID<TComponent>());
return new exc<TComponent>(_world.GetPool<TComponent>());
}
public opt<TComponent> Optional<TComponent>() where TComponent : struct
{
return new opt<TComponent>(_world.GetPool<TComponent>());
}
internal void End(out EcsEntityArhetypeMask mask)
{
_inc.Sort();
_exc.Sort();
mask = new EcsEntityArhetypeMask(_world.ArchetypeType, _inc.ToArray(), _exc.ToArray());
_world = null;
_inc.Clear();
_inc = null;
_exc.Clear();
_exc = null;
}
}
#endregion
}
public interface IEcsFiled<TComponent>
where TComponent : struct
{
public ref TComponent Write(int entityID);
public ref readonly TComponent Read(int entityID);
public bool Has(int entityID);
public void Del(int entityID);
}
[StructLayout(LayoutKind.Sequential, Pack = 8, Size = 8)]
public readonly struct inc<TComponent> : IEcsFiled<TComponent>
where TComponent : struct
{
private readonly EcsPool<TComponent> _pool;
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal inc(EcsPool<TComponent> pool) => _pool = pool;
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public ref TComponent Write(int entityID) => ref _pool.Write(entityID);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public ref readonly TComponent Read(int entityID) => ref _pool.Read(entityID);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool Has(int entityID) => _pool.Has(entityID);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void Del(int entityID) => _pool.Del(entityID);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public override string ToString() => $"{(_pool == null ? "NULL" : _pool.World.ArchetypeType.Name)}inc<{typeof(TComponent).Name}>";
}
[StructLayout(LayoutKind.Sequential, Pack = 8, Size = 8)]
public readonly struct exc<TComponent> : IEcsFiled<TComponent>
where TComponent : struct
{
private readonly EcsPool<TComponent> _pool;
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal exc(EcsPool<TComponent> pool) => _pool = pool;
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public ref TComponent Write(int entityID) => ref _pool.Write(entityID);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public ref readonly TComponent Read(int entityID) => ref _pool.Read(entityID);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool Has(int entityID) => _pool.Has(entityID);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void Del(int entityID) => _pool.Del(entityID);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public override string ToString() => $"{(_pool == null ? "NULL" : _pool.World.ArchetypeType.Name)}exc<{typeof(TComponent).Name}>";
}
[StructLayout(LayoutKind.Sequential, Pack = 8, Size = 8)]
public readonly struct opt<TComponent> : IEcsFiled<TComponent>
where TComponent : struct
{
private readonly EcsPool<TComponent> _pool;
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal opt(EcsPool<TComponent> pool) => _pool = pool;
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public ref TComponent Write(int entityID) => ref _pool.Write(entityID);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public ref readonly TComponent Read(int entityID) => ref _pool.Read(entityID);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool Has(int entityID) => _pool.Has(entityID);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void Del(int entityID) => _pool.Del(entityID);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public override string ToString() => $"{(_pool == null ? "NULL" : _pool.World.ArchetypeType.Name)}opt<{typeof(TComponent).Name}>";
}
public class EcsEntityArhetypeMask
{
internal readonly Type WorldArchetypeType;
internal readonly int[] Inc;
internal readonly int[] Exc;
public EcsEntityArhetypeMask(Type worldArchetypeType, int[] inc, int[] exc)
{
WorldArchetypeType = worldArchetypeType;
Inc = inc;
Exc = exc;
}
}
}
*/

View File

@ -17,7 +17,7 @@ namespace DCFApixels.DragonECS
#endregion
#region Entities
public EcsFilter Entities<TComponent>() where TComponent : struct;
public TArhetype Entities<TArhetype>(out TArhetype entities) where TArhetype : IEcsEntityArchetype;
public ent NewEntity();
public void DelEntity(ent entity);
@ -56,8 +56,8 @@ namespace DCFApixels.DragonECS
}
}
public abstract class EcsWorld<TArchetype> : EcsWorld, IEcsWorld
where TArchetype : EcsWorld<TArchetype>
public abstract class EcsWorld<TWorldArchetype> : EcsWorld, IEcsWorld
where TWorldArchetype : EcsWorld<TWorldArchetype>
{
private IntDispenser _entityDispenser;
private int[] _denseEntities;
@ -69,10 +69,10 @@ namespace DCFApixels.DragonECS
private IEcsPool[] _pools;
private EcsNullPool _nullPool;
private List<EcsFilter>[] _filtersByIncludedComponents;
private List<EcsFilter>[] _filtersByExcludedComponents;
private List<EcsGroup>[] _filtersByIncludedComponents;
private List<EcsGroup>[] _filtersByExcludedComponents;
private EcsFilter[] _filters;
private IEcsEntityArchetype[] _archetypes;
private EcsPipeline _pipeline;
@ -96,7 +96,7 @@ namespace DCFApixels.DragonECS
#endregion
#region Properties
public Type ArchetypeType => typeof(TArchetype);
public Type ArchetypeType => typeof(TWorldArchetype);
public int ID => id;
public EcsPipeline Pipeline => _pipeline;
@ -115,18 +115,18 @@ namespace DCFApixels.DragonECS
FillArray(_pools, _nullPool);
_gens = new short[512];
_filters = new EcsFilter[64];
_archetypes = new EcsEntityArchetype<TWorldArchetype>[EntityArhetype.capacity];
_groups = new List<EcsGroup>(128);
_denseEntities = new int[512];
_filtersByIncludedComponents = new List<EcsFilter>[16];
_filtersByExcludedComponents = new List<EcsFilter>[16];
_filtersByIncludedComponents = new List<EcsGroup>[16];
_filtersByExcludedComponents = new List<EcsGroup>[16];
_poolRunnres = new PoolRunnres(_pipeline);
_entityCreate = _pipeline.GetRunner<IEcsEntityCreate>();
_entityDestry = _pipeline.GetRunner<IEcsEntityDestroy>();
_pipeline.GetRunner<IEcsInject<TArchetype>>().Inject((TArchetype)this);
_pipeline.GetRunner<IEcsInject<TWorldArchetype>>().Inject((TWorldArchetype)this);
_pipeline.GetRunner<IEcsInject<IEcsWorld>>().Inject(this);
_pipeline.GetRunner<IEcsWorldCreate>().OnWorldCreate(this);
}
@ -159,61 +159,70 @@ namespace DCFApixels.DragonECS
}
#endregion
#region GetFilter
public EcsFilter Entities<TComponent>() where TComponent : struct => Filter<Inc<TComponent>, Exc>();
public EcsFilter Filter<TInc>() where TInc : struct, IInc => Filter<TInc, Exc>();
public EcsFilter Filter<TInc, TExc>() where TInc : struct, IInc where TExc : struct, IExc
#region Entities
public TEntityArhetype Entities<TEntityArhetype>(out TEntityArhetype entities) where TEntityArhetype : IEcsEntityArchetype
{
var mask = EcsMaskMap<TArchetype>.GetMask<TInc, TExc>();
int uniqueID = EntityArhetype<TEntityArhetype>.uniqueID;
if (_archetypes.Length < EntityArhetype.capacity)
Array.Resize(ref _archetypes, EntityArhetype.capacity);
if (_filters.Length <= EcsMaskMap<TArchetype>.Capacity)
if (_archetypes[uniqueID] == null)
{
Array.Resize(ref _filters, EcsMaskMap<TArchetype>.Capacity);
}
EcsEntityArchetype<TWorldArchetype>.Builder builder = new EcsEntityArchetype<TWorldArchetype>.Builder(this);
_archetypes[uniqueID] = (TEntityArhetype)Activator.CreateInstance(typeof(TEntityArhetype), builder);
builder.End(out EcsEntityArhetypeMask mask);
if (_filters[mask.UniqueID] == null)
{
_filters[mask.UniqueID] = NewFilter(mask);
var filter = new EcsGroup(this);
((EcsEntityArchetype<TWorldArchetype>)_archetypes[uniqueID]).group = filter;
for (int i = 0; i < mask.IncCount; i++)
{
int componentID = mask.Inc[i];
var list = _filtersByIncludedComponents[componentID];
if (list == null)
{
list = new List<EcsGroup>(8);
_filtersByIncludedComponents[componentID] = list;
}
list.Add(filter);
}
for (int i = 0; i < mask.ExcCount; i++)
{
int componentID = mask.Exc[i];
var list = _filtersByExcludedComponents[componentID];
if (list == null)
{
list = new List<EcsGroup>(8);
_filtersByExcludedComponents[componentID] = list;
}
list.Add(filter);
}
// scan exist entities for compatibility with new filter.
for (int i = 0; i < _entitiesCount && _entitiesCount <= _denseEntities.Length; i++)
{
int entity = _denseEntities[i];
if (IsMaskCompatible(mask.Inc, mask.Exc, entity))
filter.Add(entity);
}
}
return _filters[mask.UniqueID];
entities = (TEntityArhetype)_archetypes[uniqueID];
return entities;
}
private EcsFilter NewFilter(EcsMask mask, int capacirty = 512)
private bool IsMaskCompatible(int[] inc, int[] exc, int entity)
{
var filter = new EcsFilter(this, mask, capacirty);
for (int i = 0; i < mask.IncCount; i++)
for (int i = 0, iMax = inc.Length; i < iMax; i++)
{
int componentID = mask.Inc[i];
var list = _filtersByIncludedComponents[componentID];
if (list == null)
{
list = new List<EcsFilter>(8);
_filtersByIncludedComponents[componentID] = list;
}
list.Add(filter);
if (!_pools[inc[i]].Has(entity))
return false;
}
for (int i = 0; i < mask.ExcCount; i++)
for (int i = 0, iMax = exc.Length; i < iMax; i++)
{
int componentID = mask.Exc[i];
var list = _filtersByExcludedComponents[componentID];
if (list == null)
{
list = new List<EcsFilter>(8);
_filtersByExcludedComponents[componentID] = list;
}
list.Add(filter);
if (_pools[exc[i]].Has(entity))
return false;
}
// scan exist entities for compatibility with new filter.
for (int i = 0; i < _entitiesCount && _entitiesCount <= _denseEntities.Length; i++)
{
int entity = _denseEntities[i];
if (IsMaskCompatible(mask, entity))
filter.Add(entity);
}
return filter;
return true;
}
#endregion
@ -221,19 +230,19 @@ namespace DCFApixels.DragonECS
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool IsMaskCompatible<TInc>(int entityID) where TInc : struct, IInc
{
return IsMaskCompatible(EcsMaskMap<TArchetype>.GetMask<TInc, Exc>(), entityID);
return IsMaskCompatible(EcsMaskMap<TWorldArchetype>.GetMask<TInc, Exc>(), entityID);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool IsMaskCompatible<TInc, TExc>(int entityID) where TInc : struct, IInc where TExc : struct, IExc
{
return IsMaskCompatible(EcsMaskMap<TArchetype>.GetMask<TInc, TExc>(), entityID);
return IsMaskCompatible(EcsMaskMap<TWorldArchetype>.GetMask<TInc, TExc>(), entityID);
}
public bool IsMaskCompatible(EcsMask mask, int entity)
{
#if (DEBUG && !DISABLE_DRAGONECS_DEBUG) || !DRAGONECS_NO_SANITIZE_CHECKS
if (mask.WorldArchetypeType != typeof(TArchetype))
throw new EcsFrameworkException("mask.WorldArchetypeType != typeof(TArchetype)");
if (mask.WorldArchetypeType != typeof(TWorldArchetype))
throw new EcsFrameworkException("mask.WorldArchetypeType != typeof(TWorldArchetype)");
#endif
for (int i = 0, iMax = mask.IncCount; i < iMax; i++)
{
@ -251,8 +260,8 @@ namespace DCFApixels.DragonECS
public bool IsMaskCompatibleWithout(EcsMask mask, int entity, int otherComponentID)
{
#if (DEBUG && !DISABLE_DRAGONECS_DEBUG) || !DRAGONECS_NO_SANITIZE_CHECKS
if (mask.WorldArchetypeType != typeof(TArchetype))
throw new EcsFrameworkException("mask.WorldArchetypeType != typeof(TArchetype)");
if (mask.WorldArchetypeType != typeof(TWorldArchetype))
throw new EcsFrameworkException("mask.WorldArchetypeType != typeof(TWorldArchetype)");
#endif
for (int i = 0, iMax = mask.IncCount; i < iMax; i++)
{
@ -277,30 +286,30 @@ namespace DCFApixels.DragonECS
var includeList = _filtersByIncludedComponents[componentID];
var excludeList = _filtersByExcludedComponents[componentID];
if (includeList != null)
{
foreach (var filter in includeList)
{
if (IsMaskCompatible(filter.Mask, entityID))
{
filter.entities.UncheckedAdd(entityID);
}
}
}
if (excludeList != null)
{
foreach (var filter in excludeList)
{
if (IsMaskCompatibleWithout(filter.Mask, entityID, componentID))
{
filter.entities.UncheckedRemove(entityID);
}
}
}
// if (includeList != null)
// {
// foreach (var filter in includeList)
// {
// if (IsMaskCompatible(filter.Mask, entityID))
// {
// filter.entities.UncheckedAdd(entityID);
// }
// }
// }
// if (excludeList != null)
// {
// foreach (var filter in excludeList)
// {
// if (IsMaskCompatibleWithout(filter.Mask, entityID, componentID))
// {
// filter.entities.UncheckedRemove(entityID);
// }
// }
// }
//TODO провести стресс тест для варианта выши и закоментированного ниже
// if (includeList != null) foreach (var filter in includeList) filter.entities.Add(entityID);
// if (excludeList != null) foreach (var filter in excludeList) filter.entities.Remove(entityID);
if (includeList != null) foreach (var filter in includeList) filter.Add(entityID);
if (excludeList != null) foreach (var filter in excludeList) filter.Remove(entityID);
}
void IEcsReadonlyTable.OnEntityComponentRemoved(int entityID, int componentID)
@ -308,30 +317,30 @@ namespace DCFApixels.DragonECS
var includeList = _filtersByIncludedComponents[componentID];
var excludeList = _filtersByExcludedComponents[componentID];
if (includeList != null)
{
foreach (var filter in includeList)
{
if (IsMaskCompatible(filter.Mask, entityID))
{
filter.entities.UncheckedRemove(entityID);
}
}
}
if (excludeList != null)
{
foreach (var filter in excludeList)
{
if (IsMaskCompatibleWithout(filter.Mask, entityID, componentID))
{
filter.entities.UncheckedAdd(entityID);
}
}
}
// if (includeList != null)
// {
// foreach (var filter in includeList)
// {
// if (IsMaskCompatible(filter.Mask, entityID))
// {
// filter.entities.UncheckedRemove(entityID);
// }
// }
// }
// if (excludeList != null)
// {
// foreach (var filter in excludeList)
// {
// if (IsMaskCompatibleWithout(filter.Mask, entityID, componentID))
// {
// filter.entities.UncheckedAdd(entityID);
// }
// }
// }
//TODO провести стресс тест для варианта выши и закоментированного ниже
// if (includeList != null) foreach (var filter in includeList) filter.entities.Remove(entityID);
// if (excludeList != null) foreach (var filter in excludeList) filter.entities.Add(entityID);
if (includeList != null) foreach (var filter in includeList) filter.Remove(entityID);
if (excludeList != null) foreach (var filter in excludeList) filter.Add(entityID);
}
#endregion
@ -386,7 +395,7 @@ namespace DCFApixels.DragonECS
_nullPool = null;
_filtersByIncludedComponents = null;
_filtersByExcludedComponents = null;
_filters = null;
_archetypes = null;
Realeze();
}
public void DestryWithPipeline()
@ -396,7 +405,29 @@ namespace DCFApixels.DragonECS
}
#endregion
#region Other
void IEcsReadonlyTable.RegisterGroup(EcsGroup group)
{
_groups.Add(group);
}
#endregion
#region Utils
internal static class EntityArhetype
{
public static int increment = 0;
public static int capacity = 128;
}
internal static class EntityArhetype<TArhetype>
{
public static int uniqueID;
static EntityArhetype()
{
uniqueID = EntityArhetype.increment++;
if (EntityArhetype.increment > EntityArhetype.capacity)
EntityArhetype.capacity <<= 1;
}
}
internal static class ComponentType
{
internal static int increment = 1;
@ -416,7 +447,7 @@ namespace DCFApixels.DragonECS
#if (DEBUG && !DISABLE_DRAGONECS_DEBUG) || !DRAGONECS_NO_SANITIZE_CHECKS
if (ComponentType.increment + 1 > ushort.MaxValue)
{
throw new EcsFrameworkException($"No more room for new component for this {typeof(TArchetype).FullName} IWorldArchetype");
throw new EcsFrameworkException($"No more room for new component for this {typeof(TWorldArchetype).FullName} IWorldArchetype");
}
#endif
if (uniqueID >= ComponentType.types.Length)
@ -443,13 +474,6 @@ namespace DCFApixels.DragonECS
}
}
#endregion
#region Other
void IEcsReadonlyTable.RegisterGroup(EcsGroup group)
{
_groups.Add(group);
}
#endregion
}
[StructLayout(LayoutKind.Sequential, Pack = 8, Size = 24)]

View File

@ -20,9 +20,6 @@ namespace DCFApixels.DragonECS
public EcsPool<T> GetPool<T>() where T : struct;
public EcsPool<T> UncheckedGetPool<T>() where T : struct;
public EcsFilter Filter<TInc>() where TInc : struct, IInc;
public EcsFilter Filter<TInc, TExc>() where TInc : struct, IInc where TExc : struct, IExc;
public bool IsMaskCompatible<TInc>(int entity) where TInc : struct, IInc;
public bool IsMaskCompatible<TInc, TExc>(int entity) where TInc : struct, IInc where TExc : struct, IExc;
public bool IsMaskCompatible(EcsMask mask, int entity);

View File

@ -12,7 +12,7 @@ namespace DCFApixels.DragonECS
public short Gen { get; }
public short World { get; }
}
// id - 32 bits
// uniqueID - 32 bits
// gen - 16 bits
// world - 16 bits
[StructLayout(LayoutKind.Explicit, Pack = 2, Size = 8)]
@ -71,7 +71,7 @@ namespace DCFApixels.DragonECS
#region ToString
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public override string ToString() => $"ent(id:{id} gen:{gen} world:{world})";
public override string ToString() => $"ent(uniqueID:{id} gen:{gen} world:{world})";
#endregion
#region operators